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)?
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é.
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
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
:-)
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.
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.
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'
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.