¿De dónde saca uname su información?

¿De dónde uname realmente obtiene su información?

Me imagino que esto es algo que debería ser sencillo. Lamentablemente, no puedo encontrar ningún encabezado que contenga solo esa información.

Digamos que alguien quería cambiar el resultado básico de uname / uname -s de Linux a otra cosa (esencialmente, renombrar el kernel).

¿Cómo haría eso de la manera correcta (es decir, cambiando la fuente)?

Solutions Collecting From Web of "¿De dónde saca uname su información?"

La utilidad uname obtiene su información de la llamada al sistema uname() . Rellena una estructura como esta (ver man 2 uname ):

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

Esto viene directamente del kernel en ejecución. Asumiría que toda la información está codificada en ella, excepto tal vez el domainname (y, como resulta, también el nombre, la machine y la release , vea los comentarios). La cadena de publicación, desde uname -r , se puede establecer a través de la configuration en time de compilation, pero dudo mucho de que el campo de nombre de sistema pueda: es el kernel de Linux y no hay razón concebible para que use otra cosa.

Sin embargo, dado que es de código abierto, puede cambiar el código fuente y volver a comstackr el kernel para usar el nombre de sistema que desee.

Los datos se almacenan en 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); 

Las cadenas en sí mismas están en include / generated / compile.h:

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

y en include / generated / utsrelease.h:

 #define UTS_RELEASE "3.14.0-v2-v" 

UTS_SYSNAME se puede definir en include / linux / uts.h

 #ifndef UTS_SYSNAME #define UTS_SYSNAME "Linux" #endif 

o como un #define en makefiles

Finalmente, el nombre de host y el nombre de dominio pueden ser controlados por / proc / sys / kernel / {hostname, domainname}. Estos son por espacio de nombres UTS:

 # hostname hell # unshare --uts /bin/bash # echo test > /proc/sys/kernel/hostname # hostname test # exit # hostname hell 

Con la ayuda de una reference cruzada de Linux y su mención de /proc/sys/kernel/ostype , /proc/sys/kernel/ostype ostype para include / linux / sysctl.h , donde un comentario dice que los nombres se agregan llamando a register_sysctl_table .

Entonces, ¿de dónde es llamado ? Un lugar es kernel / utsname_sysctl.c , que incluye include / linux / uts.h , donde encontramos:

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

Entonces, como dice la documentation del kernel :

La única forma de ajustar estos valores es rebuild el kernel 🙂

Como se comentó en otro lugar, la información viene con la llamada única, cuya información está codificada en el kernel en ejecución.

La parte de la versión normalmente se establece al comstackr un nuevo kernel por el Makefile :

 VERSION = 3 PATCHLEVEL = 15 SUBLEVEL = 0 EXTRAVERSION = 

cuando tuve time de jugar comstackndo mis kernels, solía agregar cosas allí en EXTRAVERSIÓN; eso te dio uname -r con cosas como 3.4.1-mytestkernel .

No lo entiendo completamente, pero creo que el rest de la información está configurada en el Makefile también alnetworkingedor de la línea 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 

Para el rest de los datos, sys_uname syscall se genera utilizando macros (de una manera bastante intrincada), puede comenzar desde aquí si se siente aventurero.

Probablemente, la mejor manera de cambiar dicha información es escribir un module kernel para anular el uniche syscall; Nunca lo hice, pero puede encontrar información en esta página en la sección 4.2 (lo siento, no hay enlace directo). Sin embargo, tenga en count que ese código se refiere a un kernel bastante antiguo (ahora el kernel de Linux tiene espacios de nombres uts , lo que sea que signifiquen), por lo que tendrá que cambiarlo probablemente mucho.

Si bien no pude encontrar nada en la fuente para indicar esto, creo que utiliza la llamada de uname.

man 2 uname

debería decirte más al respecto. Si ese es el caso, es get la información directamente del kernel y cambiarla probablemente requeriría una recompilation.

Puede cambiar el binary para que usted no pueda hacer lo que quiera, solo escríbalo con el progtwig w / e que desee. La desventaja es que algunos scripts se basan en esa salida.

La forma correcta de cambiar uname sería cambiar los encabezados de compilation y volver a comstackr como otros sugirieron. Pero no estoy seguro de por qué querrías pasar por tantos problemas cuando puedes hacer algo como,

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

o incluso

 alias uname 'echo whatever' 

La respuesta de Rmano me llevó a la mitad, pero la verdadera magia se descubre más fácilmente al pasar la opción Q= en la línea de command make en el directory fuente del kernel. le permite ver los detalles, uno de los cuales es una llamada a un script: echo "4.4.19$(/bin/sh ./scripts/setlocalversion .)" . al ejecutar ese mismo fragment se obtiene el número de versión del kernel, 4.4.19-00010-ge5dddbf . Si observa el script, determina el número del sistema de control de versiones, y al ejecutarlo con bash -x muestra el process exacto:

 +++ 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 

Lo que esto me muestra es que si quiero build un module kernel para que funcione con mi kernel en ejecución, estoy en la versión labelda incorrecta y en la confirmación incorrecta. Necesito arreglar eso, y build al less los DTB ( make dtbs ) para crear los files generados con el número de versión correcto.


resulta, incluso eso no fue suficiente. Tuve que replace scripts/setlocalversion por uno que simplemente hace:

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

luego rebuild los files autogenerados:

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

entonces podría build el controller de muestra de Derek Molloy y pude insmod con éxito. aparentemente, la advertencia de que Module.symvers no estaba presente no importaba. todo lo que Linux estaba usando para determinar si el module funcionaría era esa cadena de conversión local.