web-dev-qa-db-fra.com

D'où uname obtient-elle ses informations?

D'où uname obtient-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 de base de uname/uname -s de Linux vers autre chose (essentiellement, renommer le noyau).

Comment procéderait-il de la bonne façon (c'est-à-dire en changeant la source)?

42
user237251

L'utilitaire uname obtient ses informations de l'appel système uname(). 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, sauf peut-être domainname (et comme il s'avère, également nodename, machine et release, voir les commentaires). La chaîne de version, de uname -r, peut être défini via la configuration au moment de la compilation, mais je doute fort que le champ sysname le puisse - c'est le noyau Linux et il n'y a aucune raison concevable pour qu'il utilise autre chose.

Cependant, comme il est open source, vous pouvez modifier le code source et recompiler le noyau pour utiliser le nom de système souhaité.

26
goldilocks

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 se trouvent dans include/generated/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/{hostname, domainname}. Ce sont par espace de noms UTS:

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

Avec l'aide d'un Linux Cross Reference et votre mention de /proc/sys/kernel/ostype, J'ai suivi ostype pour inclure/linux/sysctl.h , où un commentaire indique que des noms sont ajoutés en appelant register_sysctl_table.

Alors, d'où vient depuis ? Un endroit est kernel/utsname_sysctl.c , qui comprend include/linux/uts.h , où l'on trouve:

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

Ainsi, comme l'indique la documentation du noyau :

La seule façon de régler ces valeurs est de reconstruire le noyau

:-)

8
deltab

Comme indiqué ailleurs, les informations sont fournies avec le syscall uname, qui 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'avais l'habitude d'ajouter des choses là-bas dans EXTRAVERSION; cela vous a donné uname -r avec des choses comme 3.4.1-mytestkernel.

Je ne le comprends pas complètement, mais je pense que le reste des informations est configuré dans le Makefile également autour de 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, le sys_uname syscall est généré à l'aide de macros (d'une manière assez compliquée), vous pouvez commencer à partir de ici si vous vous sentez aventureux.

La meilleure façon de changer ces informations est probablement d'écrire un module du noyau pour remplacer l'appel système uname; Je n'ai jamais fait ça mais vous pouvez trouver des informations dans 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 espaces de noms uts, quoi qu'ils signifient), vous devrez donc le changer probablement beaucoup.

7
Rmano

Bien que je n'aie rien trouvé dans la source pour l'indiquer, je pense qu'il utilise le syscall uname.

man 2 uname

devrait vous en dire plus. Si c'est le cas, obtenir les informations directement du noyau et les modifier nécessiterait probablement une recompilation.

Vous pouvez changer le binaire pour que vous ne fassiez pas ce que vous voulez, mais écrivez dessus avec le programme w/e qui vous plaît. L'inconvénient de certains scripts repose sur cette sortie.

2
Livinglifeback

Une bonne façon de changer uname serait de changer les en-têtes de compilation et de recompiler comme d'autres l'ont suggéré. Mais je ne sais pas pourquoi vous voudriez avoir autant d'ennuis 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'
1
Saurabh

scripts/mkcompile_h

Dans la v4.19, c'est le fichier qui génère include/generated/compile.h, et contient plusieurs parties intéressantes de /proc/version: https://github.com/torvalds/linux/blob/v4.19/scripts/mkcompile_h

  • le #<version> une partie provient du .version fichier sur l'arborescence de construction, qui est incrémenté chaque fois que le lien se produit (nécessite des modifications de fichier/configuration) par scripts/link-vmlinux.sh.

    Il peut être remplacé par le KBUILD_BUILD_VERSION variable 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 appel brut de date:

    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 peut pas être contrôlé semble-t-il.

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

Rmano la réponse m'a fait du chemin, mais la vraie magie est plus facile à découvrir en passant l'option Q= Dans votre ligne de commande make 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 des versions et l'exécuter avec bash -x montre 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

ce que cela me montre, c'est que si je veux construire un module de noyau pour travailler avec mon noyau en cours d'exécution, je suis sur la mauvaise version balisée et le mauvais commit. 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.


se révèle, même cela ne suffisait pas. J'ai dû remplacer scripts/setlocalversion Par un autre 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 j'ai pu construire pilote d'exemple de Derek Molloy et j'ai pu insmod le réussir. apparemment, l'avertissement concernant la non-présence de Module.symvers n'avait pas d'importance. tout ce que Linux utilisait pour déterminer si le module fonctionnerait était cette chaîne de version locale.

0
jcomeau_ictx