D'où uname tire-t-il ses informations?


40

D'où uname trouve-t-il vraiment ses informations?

Je pense que c'est quelque chose qui devrait être simple. Malheureusement, je ne trouve aucun en-tête contenant uniquement ces informations.

Supposons que quelqu'un veuille changer la sortie basique de uname/ uname -s de Linuxen quelque chose d'autre (essentiellement, renommer le noyau).

Comment s'y prendrait-il pour le faire de la bonne manière (c'est-à-dire changer la source)?

Réponses:


26

L' unameutilitaire tire ses informations de l' uname()appel système. Il remplit une structure comme celle-ci (voir 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
       };

Cela vient directement du noyau en cours d'exécution. Je suppose que toutes les informations sont codées en dur en elle, sauf peut - être domainname(et il se trouve, aussi nodename, machineet release, voir les commentaires). La chaîne de publication, à partir de uname -r, peut être définie via la configuration lors de la compilation, mais je doute fort que le champ sysname le puisse - il s’agit du noyau Linux et il n’ya aucune raison concevable d’utiliser autre chose.

Cependant, comme il est open source, vous pouvez changer le code source et recompiler le noyau pour utiliser le sysname de votre choix.


2
Le domainnamechamp est défini par la domainnamecommande, à l'aide de l' setdomainnameappel système. De même, le nodenamechamp est défini par la hostnamecommande, à l'aide de l' sethostnameappel système. (La nodename/ hostnamevaleur peut être stockée dans /etc/nodename.)
Scott

2
Cela n'a aucune importance - la question posée était de savoir comment changer cela. Alors oui, la unamecommande tire ses informations d'un appel système. Et où l'appel système obtient-il ses informations? (Réponse, fournie par d'autres affiches ici: c'est codé en dur dans le noyau au moment de la compilation.)
Gilles 'SO, arrête d'être méchant'

@ Gilles: Qu'est-ce qui n'est pas pertinent? Si la réponse est "fournie par d'autres affiches ici: c'est codé en dur dans le noyau ...", note j'ai dit exactement la même chose: "Cela vient directement du noyau en cours d'exécution. Je suppose que toutes les informations sont difficiles -codé dedans ... puisqu'il est open source, vous pouvez changer le code source et recompiler le noyau pour utiliser le sysname que vous voulez . Ce n'est pas une option de configuration.
goldilocks

2
@goldilocks Pourquoi changerait-il machinejamais? Il se peut qu'il ne soit pas codé en dur dans le noyau, car il s'adapte au matériel, mais il sera sûrement défini au moment du démarrage et ne changera pas par la suite. Mais non: il peut être défini par processus (par exemple, pour générer un rapport i686sur 32 bits traité sur x86_64). Par ailleurs, releasepeut également être personnalisé par processus dans une certaine mesure (essayer setarch i686 --uname-2.6 uname -a).
Gilles 'SO- arrête d'être méchant'

1
@ Gilles j'ai édité machine, nodenameet releasedans la question avec une référence aux commentaires. Encore une fois, la question ne concernait pas tous ces domaines.
goldilocks

26

Les données sont stockées dans 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);

Les chaînes elles-mêmes sont dans include / created / compile.h:

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

et dans include / généré / utsrelease.h:

#define UTS_RELEASE "3.14.0-v2-v"

UTS_SYSNAME peut être défini dans include / linux / uts.h

#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif

ou en tant que #define dans les makefiles

Enfin, le nom d’hôte et le nom de domaine peuvent être contrôlés par / proc / sys / kernel / {nom d’hôte, nom de domaine}. Ce sont par espace de noms UTS:

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

C’est généralement une bonne et complète réponse, mais il peut être intéressant de répondre directement à la question de l’affiche. Je pense que cela reviendrait à - modifier l’entrée correspondante dans le fichier approprié et à la recompiler. Vous avez écrit "ou en tant que #define dans les makefiles". Peux-tu élaborer?
Faheem Mitha

+1 pour unshare. D'une manière ou d'une autre, j'ai réussi à rater cette commande jusqu'à aujourd'hui. Merci!
Tino

Et include/generated/compile.hest généré par scripts/mkcompile_h: unix.stackexchange.com/a/485962/32558
Ciro Santilli新疆改造中心法轮功六四事件

8

Avec l’aide d’une référence croisée Linux et de votre mention /proc/sys/kernel/ostype, j’ai choisi ostyped’ inclure / linux / sysctl.h , où un commentaire indique que les noms sont ajoutés par appel register_sysctl_table.

Alors, d'où est-ce que cela s'appelle ? Le noyau / utsname_sysctl.c , qui inclut include / linux / uts.h , est l’un des emplacements suivants:

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

Ainsi, comme l' indique la documentation du noyau :

Le seul moyen d’ajuster ces valeurs est de reconstruire le noyau

:-)


6

Comme indiqué ailleurs, les informations sont fournies avec l' unameappel système, lequel est codé en dur dans le noyau en cours d'exécution.

La partie version est normalement définie lors de la compilation d’un nouveau noyau par le Makefile :

VERSION = 3
PATCHLEVEL = 15
SUBLEVEL = 0
EXTRAVERSION =

quand j'avais le temps de jouer à la compilation de mes noyaux, j'y ajoutais des choses là-bas dans EXTRAVERSION; cela vous a donné des uname -r choses comme 3.4.1-mytestkernel.

Je ne comprends pas tout à fait cela, mais je pense que le reste de l’information se trouve Makefileégalement dans la ligne 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

Pour le reste des données, l' sys_unameappel système est généré à l'aide de macros (d'une manière assez compliquée), vous pouvez commencer à partir d' ici si vous vous sentez aventureux.

Le meilleur moyen de modifier de telles informations consiste probablement à écrire un module de noyau pour remplacer le unamesyscall. Je n'ai jamais fait cela, mais vous pouvez trouver des informations sur cette page à la section 4.2 (désolé, pas de lien direct). Notez cependant que ce code fait référence à un noyau assez ancien (maintenant le noyau Linux a des utsespaces de noms, peu importe leur signification), vous devrez donc probablement le modifier beaucoup.


Merci tout le monde. Je savais déjà que cela avait quelque chose à voir avec uname. Cependant, je ne peux pas comprendre comment et où à l'intérieur de la source la chaîne "Linux" est définie. Tout ce que je sais, c'est où je peux trouver ces informations pendant l'exécution (elles sont contenues dans / proc / sys / kernel / ostype). L'une des choses les plus intéressantes, à mon avis, consiste à savoir comment le noyau sait exactement que son propre nom est exact.
user237251

@ user237251 combien d'instances du mot "Linux" se produisent-elles dans la source du noyau dans des contextes de chaîne? Si ce n'est pas beaucoup, vous pouvez simplement examiner les résultats d'une recherche textuelle et voir où cela vous mène.
JAB

@JAB Beaucoup trop. Heureusement, quelqu'un sur kernelnewbies.org m'a aidé à résoudre le "mystère". Linux tire son nom de sys de /include/Linux/uts.h. Voir ici: lxr.free-electrons.com/source/include/linux/uts.h?v=3.10
user237251

2

Bien que je n’aie rien trouvé dans la source qui indique cela, je pense qu’il utilise le syscall uname.

man 2 uname

devrait vous en dire plus à ce sujet. Si tel est le cas, obtenir les informations directement du noyau et les modifier nécessiteraient probablement une recompilation.

Vous pouvez changer le fichier binaire pour que vous puissiez faire ce que vous voulez, écrivez dessus avec le programme qui vous convient. L'inconvénient étant que certains scripts reposent sur cette sortie.


3
Si vous le faites strace uname, cela confirmera que l' unameappel système est utilisé.
Graeme

1

Une façon correcte de changer uname serait de changer les en-têtes de compilation et de les recompiler comme le suggèrent les autres. Mais je ne suis pas sûr de savoir pourquoi vous voudriez traverser autant de problèmes quand vous pouvez faire quelque chose comme:

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

ou même

alias uname 'echo whatever'

0

La réponse de Rmano m'a convaincu, mais la vraie magie est plus facile à découvrir en passant l' Q=option dans votre makeligne de commande dans le répertoire source du noyau. il vous permet de voir les détails, dont l'un est un appel à un script: echo "4.4.19$(/bin/sh ./scripts/setlocalversion .)". l' exécution de ce même extrait donne le numéro de version du noyau, 4.4.19-00010-ge5dddbf. si vous regardez le script, il détermine le numéro à partir du système de gestion de versions, et son exécution avec bash -xindique le processus exact:

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

Cela me montre que si je veux construire un module de noyau pour fonctionner avec mon noyau en cours d’exécution, je ne suis pas sur la bonne version étiquetée ni sur la validation. Je dois résoudre ce problème et créer au moins les DTB ( make dtbs) afin de créer les fichiers générés avec le bon numéro de version.


s'avère que même cela ne suffisait pas. Je devais remplacer scripts/setlocalversionà celui qui fait simplement:

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

puis reconstruisez les fichiers générés automatiquement:

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

alors je pouvais construire le pilote exemple de Derek Molloy et je pouvais le faire insmodavec succès. apparemment, l'avertissement de Module.symversne pas être présent importait peu. tout ce que Linux utilisait pour déterminer si le module fonctionnerait était cette chaîne de version locale.


0

scripts/mkcompile_h

Dans la v4.19, il s’agit du fichier qui génère include/generated/compile.het contient plusieurs parties intéressantes de /proc/version: https://github.com/torvalds/linux/blob/v4.19/scripts/mkcompile_h

  • la #<version>partie provient du .versionfichier sur l'arbre de construction, qui est incrémenté chaque fois qu'un lien se produit (nécessite des modifications de fichier / config) de scripts/link-vmlinux.sh.

    Il peut être remplacé par la KBUILD_BUILD_VERSIONvariable d'environnement:

    if [ -z "$KBUILD_BUILD_VERSION" ]; then
        VERSION=$(cat .version 2>/dev/null || echo 1)
    else
        VERSION=$KBUILD_BUILD_VERSION
    fi
    
  • la date est juste un dateappel brut :

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

    et de même le nom d'utilisateur vient de whoami( KBUILD_BUILD_USER) et le nom d'hôte de hostname( KBUILD_BUILD_HOST)

  • La version du compilateur provient de gcc -v, et ne semble pas pouvoir être contrôlée.

Voici comment changer la version de la question: https://stackoverflow.com/questions/23424174/how-to-customize-or-remove-extra-linux-kernel-version-details-shown-at-boot

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.