Dari mana uname mendapatkan informasinya?

40

Dari mana uname benar-benar mendapatkan informasinya?

Saya pikir ini adalah sesuatu yang harus jelas. Sayangnya, saya tidak dapat menemukan header yang berisi informasi itu saja.

Katakanlah seseorang ingin mengubah output dasar dari uname/ uname -s dari Linuxke yang lain (pada dasarnya, mengganti nama kernel).

Bagaimana dia akan melakukan itu dengan cara yang tepat (yaitu, mengubah sumber)?

pengguna237251
sumber

Jawaban:

26

The unameutilitas mendapat informasinya dari uname()system call. Ini mengisi struct seperti ini (lihat man 2 uname):

       struct utsname {
           char sysname[];    /* Operating system name (e.g., "Linux") */
           char nodename[];   /* Name within "some implementation-defined
                                 network" */
           char release[];    /* Operating system release (e.g., "2.6.28") */
           char version[];    /* Operating system version */
           char machine[];    /* Hardware identifier */
       #ifdef _GNU_SOURCE
           char domainname[]; /* NIS or YP domain name */
       #endif
       };

Ini datang langsung dari kernel yang sedang berjalan. Saya akan menganggap semua informasi yang sulit-kode ke dalamnya, kecuali mungkin domainname(dan ternyata, juga nodename, machinedan release, lihat komentar). Rilis string, dari uname -r, dapat diatur melalui konfigurasi pada waktu kompilasi, tapi saya sangat meragukan bidang sysname bisa - itu adalah kernel Linux dan tidak ada alasan yang memungkinkan untuk menggunakan hal lain.

Namun, karena ini adalah open source, Anda dapat mengubah kode sumber dan mengkompilasi ulang kernel untuk menggunakan sysname apa pun yang Anda inginkan.

goldilocks
sumber
2
The domainnamelapangan set oleh domainnameperintah, menggunakan setdomainnamesystem call. Demikian pula, nodenamebidang diatur oleh hostnameperintah, menggunakan sethostnamesystem call. (Nilai nodename/ hostnamedapat disimpan dalam /etc/nodename.)
Scott
2
Ini tidak relevan - pertanyaan yang diajukan kemana harus mengubah ini. Jadi ya, unameperintah mendapatkan informasinya dari panggilan sistem. Dan dari mana panggilan sistem mendapatkan informasinya? (Jawab, disediakan oleh poster-poster lain di sini: hard-coded di kernel pada waktu kompilasi.)
Gilles 'SO-stop being evil'
@Gilles: Apa itu irrelevent? Jika jawabannya adalah "disediakan oleh poster lain di sini: hard-coded ke dalam kernel ..." perhatikan saya sudah mengatakan hal yang persis sama: "Ini datang langsung dari kernel yang sedang berjalan. Saya akan menganggap semua informasi sulit -dikodekan ke dalamnya ... karena ini adalah open source, Anda dapat mengubah kode sumber dan mengkompilasi ulang kernel untuk menggunakan sysname apa pun yang Anda inginkan . Ini bukan opsi konfigurasi.
goldilocks
2
@goldilocks Mengapa akan machinepernah berubah? Ini mungkin tidak di-hardcode ke dalam kernel karena mungkin beradaptasi dengan perangkat keras, tetapi pasti itu akan diatur pada saat boot dan tidak akan berubah setelah itu. Tapi tidak: itu bisa disetel per proses (misalnya untuk melapor i686ke 32-bit yang diproses pada x86_64). Ngomong-ngomong, releasebisa juga dikustomisasi per proses sampai batas tertentu (coba setarch i686 --uname-2.6 uname -a).
Gilles 'SANGAT berhenti menjadi jahat'
1
@Gilles Saya sudah mengedit machine,, nodenamedan releaseke pertanyaan dengan referensi ke komentar. Sekali lagi, pertanyaannya sebenarnya bukan tentang semua bidang itu.
goldilocks
26

Data disimpan di init / version.c:

struct uts_namespace init_uts_ns = {
        .kref = {
                .refcount       = ATOMIC_INIT(2),
        },
        .name = {
                .sysname        = UTS_SYSNAME,
                .nodename       = UTS_NODENAME,
                .release        = UTS_RELEASE,
                .version        = UTS_VERSION,
                .machine        = UTS_MACHINE,
                .domainname     = UTS_DOMAINNAME,
        },
        .user_ns = &init_user_ns,
        .proc_inum = PROC_UTS_INIT_INO,
};
EXPORT_SYMBOL_GPL(init_uts_ns);

String-nya sendiri di include / generate / compile.h:

#define UTS_MACHINE "x86_64"
#define UTS_VERSION "#30 SMP Fri Apr 11 00:24:23 BST 2014"

dan di include / generate / utsrelease.h:

#define UTS_RELEASE "3.14.0-v2-v"

UTS_SYSNAME dapat didefinisikan di include / linux / uts.h

#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif

atau sebagai #define di makefiles

Akhirnya, nama host dan nama domain dapat dikontrol oleh / proc / sys / kernel / {hostname, domainname}. Ini adalah per namespace UTS:

# hostname
hell
# unshare --uts /bin/bash
# echo test > /proc/sys/kernel/hostname 
# hostname
test
# exit
# hostname
hell
V13
sumber
Ini umumnya merupakan jawaban yang baik dan lengkap, tetapi mungkin layak saat menjawab pertanyaan langsung dari poster. Saya yakin ini sama dengan - mengubah entri yang relevan di file yang relevan dan mengkompilasi ulang. Anda menulis "atau sebagai #define dalam makefiles". Bisakah Anda menguraikan?
Faheem Mitha
+1 untuk unshare. Entah bagaimana saya berhasil melewatkan perintah ini sampai hari ini. Terima kasih!
Tino
Dan include/generated/compile.hdihasilkan oleh scripts/mkcompile_h: unix.stackexchange.com/a/485962/32558
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
8

Dengan bantuan Linux Cross Reference dan penyebutan Anda /proc/sys/kernel/ostype, saya melacak ostypeuntuk memasukkan / linux / sysctl.h , di mana komentar mengatakan bahwa nama ditambahkan dengan memanggil register_sysctl_table.

Jadi dari mana asalnya ? Satu tempat adalah kernel / utsname_sysctl.c , yang meliputi include / linux / uts.h , tempat kami menemukan:

/*
 * Defines for what uname() should return 
 */
#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif

Jadi, sebagaimana dinyatakan oleh dokumentasi kernel :

Satu-satunya cara untuk menyetel nilai-nilai ini adalah membangun kembali kernel

:-)

deltab
sumber
6

Seperti dikomentari di tempat lain, informasi tersebut datang dengan unamesyscall, yang informasinya di-hard-coded di kernel yang sedang berjalan.

Bagian versi biasanya diatur ketika mengkompilasi kernel baru oleh Makefile :

VERSION = 3
PATCHLEVEL = 15
SUBLEVEL = 0
EXTRAVERSION =

ketika saya punya waktu untuk bermain mengkompilasi kernel saya, saya biasa menambahkan hal-hal di sana dalam EXTRAVERSION; yang memberi Anda uname -r hal-hal seperti 3.4.1-mytestkernel.

Saya tidak sepenuhnya memahaminya, tetapi saya berpikir bahwa sisa informasi tersebut diatur dalam Makefilejuga sekitar baris 944:

# ---------------------------------------------------------------------------

# KERNELRELEASE can change from a few different places, meaning version.h
# needs to be updated, so this check is forced on all builds

uts_len := 64
define filechk_utsrelease.h
    if [ `echo -n "$(KERNELRELEASE)" | wc -c ` -gt $(uts_len) ]; then \
      echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2;    \
      exit 1;                                                         \
    fi;                                                               \
    (echo \#define UTS_RELEASE \"$(KERNELRELEASE)\";)
endef

define filechk_version.h
    (echo \#define LINUX_VERSION_CODE $(shell                         \
    expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \
    echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';)
endef

$(version_h): $(srctree)/Makefile FORCE
    $(call filechk,version.h)

include/generated/utsrelease.h: include/config/kernel.release FORCE
    $(call filechk,utsrelease.h)

PHONY += headerdep
headerdep:
    $(Q)find $(srctree)/include/ -name '*.h' | xargs --max-args 1 \
    $(srctree)/scripts/headerdep.pl -I$(srctree)/include

Untuk sisa data, sys_unamesyscall dihasilkan menggunakan makro (dengan cara yang cukup berbelit-belit), Anda bisa mulai dari sini jika Anda ingin bertualang.

Mungkin cara terbaik untuk mengubah informasi tersebut adalah menulis modul kernel untuk mengganti unamesyscall; Saya tidak pernah melakukan itu tetapi Anda dapat menemukan info di halaman ini di bagian 4.2 (maaf, tidak ada tautan langsung). Namun perhatikan bahwa kode tersebut merujuk ke kernel yang cukup lama (sekarang kernel Linux memiliki utsruang nama, apa pun artinya) sehingga Anda harus sering mengubahnya.

Rmano
sumber
Terimakasih semuanya. Saya sudah tahu itu ada hubungannya dengan uname. Namun, apa yang saya tidak dapat mengerti adalah bagaimana dan di mana di dalam sumber string "Linux" didefinisikan. Yang saya tahu adalah di mana saya dapat menemukan informasi itu selama runtime (itu terkandung di dalam / proc / sys / kernel / ostype). Mencari tahu bagaimana tepatnya kernel itu sendiri tahu itu nama yang tepat akan menjadi salah satu hal yang lebih menarik, saya katakan.
user237251
@ user237251 berapa banyak contoh kata "Linux" terjadi di sumber kernel dalam konteks string? Jika tidak banyak, Anda bisa memeriksa hasil pencarian tekstual dan melihat ke mana arahnya.
JAB
@ JAB Terlalu banyak. Untungnya, seseorang di kernelnewbies.org membantu saya memecahkan "misteri". Linux mendapatkan nama sistemnya dari /include/Linux/uts.h. Lihat di sini: lxr.free-electrons.com/source/include/linux/uts.h?v=3.10
user237251
2

Meskipun saya tidak dapat menemukan apa pun di sumber untuk menunjukkan ini, saya percaya itu menggunakan syscall yang tidak sama.

man 2 uname

harus memberi tahu Anda lebih banyak tentang hal itu. Jika itu masalahnya, ia mendapatkan informasi langsung dari kernel dan mengubahnya mungkin memerlukan kompilasi ulang.

Anda dapat mengubah biner agar Anda tidak dapat melakukan apa pun yang Anda inginkan, cukup tulis saja dengan program w / e yang Anda inginkan. Kelemahannya adalah beberapa skrip mengandalkan output itu.

Hidup kembali
sumber
3
Jika Anda melakukannya strace uname, itu akan mengkonfirmasi bahwa unamepanggilan sistem digunakan.
Graeme
1

Cara yang tepat untuk mengubah uname adalah dengan mengubah header kompilasi dan mengkompilasi ulang seperti yang disarankan orang lain. Tapi saya tidak yakin mengapa Anda ingin melalui banyak masalah ketika Anda bisa melakukan sesuatu seperti,

alias uname 'uname \\!* | sed s/2.6.13/2.6.52/'

atau bahkan

alias uname 'echo whatever'
Saurabh
sumber
0

Jawaban Rmano membuat saya setengah jalan, tetapi keajaiban sebenarnya lebih mudah ditemukan dengan melewatkan Q=opsi di makecommandline Anda di direktori source kernel. itu memungkinkan Anda melihat rincian, salah satunya adalah panggilan untuk script: echo "4.4.19$(/bin/sh ./scripts/setlocalversion .)". mengeksekusi snippet yang sama memberikan nomor rilis kernel 4.4.19-00010-ge5dddbf,. jika Anda melihat skrip, ia menentukan angka dari sistem versi, dan menjalankannya dengan bash -xmenunjukkan proses yang tepat:

+++ git rev-parse --verify --short HEAD
++ head=e5dddbf
+++ git describe --exact-match
++ '[' -z '' ']'
++ false
+++ git describe
++ atag=release/A530_os_1.0.0-10-ge5dddbf
++ echo release/A530_os_1.0.0-10-ge5dddbf
++ awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
++ git config --get svn-remote.svn.url
++ git diff-index --name-only HEAD
++ grep -qv '^scripts/package'
++ return
+ res=-00010-ge5dddbf
+ echo -00010-ge5dddbf
-00010-ge5dddbf

Ini menunjukkan kepada saya bahwa jika saya ingin membangun modul kernel untuk bekerja dengan kernel saya yang sedang berjalan, saya berada pada rilis yang salah ditandai dan komit yang salah. Saya perlu memperbaikinya, dan membangun setidaknya DTB ( make dtbs) untuk membuat file yang dihasilkan dengan nomor versi yang tepat.


Ternyata, bahkan itu tidak cukup. Saya harus mengganti scripts/setlocalversiondengan yang sederhana:

#!/bin/sh
echo -0710GC0F-44F-01QA

lalu buat kembali file yang di-autogenerasi:

make Q= ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs

maka saya bisa membangun driver sampel Derek Molloy dan insmodberhasil. rupanya peringatan tentang Module.symverstidak hadir tidak masalah. semua Linux menggunakan untuk menentukan apakah modul akan bekerja adalah string versi lokal itu.

jcomeau_ictx
sumber
0

scripts/mkcompile_h

Di v4.19, ini adalah file yang menghasilkan include/generated/compile.h, dan berisi beberapa bagian menarik /proc/version: https://github.com/torvalds/linux/blob/v4.19/scripts/mkcompile_h

  • yang #<version>bagian berasal dari .versionfile di pohon membangun, yang akan bertambah setiap kali link yang terjadi (membutuhkan file / config perubahan) oleh scripts/link-vmlinux.sh.

    Itu dapat ditimpa oleh KBUILD_BUILD_VERSIONvariabel lingkungan:

    if [ -z "$KBUILD_BUILD_VERSION" ]; then
        VERSION=$(cat .version 2>/dev/null || echo 1)
    else
        VERSION=$KBUILD_BUILD_VERSION
    fi
    
  • tanggalnya hanyalah datepanggilan biasa:

    if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then
        TIMESTAMP=`date`
    else
        TIMESTAMP=$KBUILD_BUILD_TIMESTAMP
    fi
    

    dan juga nama pengguna berasal dari whoami( KBUILD_BUILD_USER) dan nama host dari hostname( KBUILD_BUILD_HOST)

  • Versi kompiler berasal dari gcc -v, dan sepertinya tidak bisa dikontrol.

Berikut adalah cara mengubah versi barang dari pertanyaan: https://stackoverflow.com/questions/23424174/how-to-customize-or-remove-extra-linux-kernel-version-details-shown-at-boot

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
sumber