Woher bezieht uname seine Informationen?


40

Woher bezieht uname wirklich seine Informationen?

Ich denke, das ist etwas, das einfach sein sollte. Leider kann ich keinen Header finden, der nur diese Informationen enthält.

Angenommen, jemand wollte die Grundausgabe von uname/ uname -s von Linuxauf etwas anderes ändern (im Wesentlichen den Kernel umbenennen).

Wie würde er / sie vorgehen, um das richtig zu machen (dh die Quelle zu ändern)?

Antworten:


26

Das unameDienstprogramm bezieht seine Informationen aus dem uname()Systemaufruf. Es füllt eine Struktur wie diese aus (siehe 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
       };

Dies kommt direkt aus dem laufenden Kernel. Ich würde davon ausgehen , alle Informationen , ist hartcodiert in sie, außer vielleicht domainname(und wie sich herausstellt, auch nodename, machineund release, siehe Kommentar). Der Release-String von uname -rkann während der Kompilierung über die Konfiguration festgelegt werden, aber ich bezweifle sehr, dass das Feld sysname dies kann - es ist der Linux-Kernel und es gibt keinen vorstellbaren Grund, etwas anderes zu verwenden.

Da es sich jedoch um Open Source handelt, können Sie den Quellcode ändern und den Kernel neu kompilieren, um den gewünschten Systemnamen zu verwenden.


2
Das domainnameFeld wird vom domainnameBefehl mithilfe des setdomainnameSystemaufrufs festgelegt. In ähnlicher Weise wird das nodenameFeld durch den hostnameBefehl unter Verwendung des sethostnameSystemaufrufs festgelegt. (Der Wert nodename/ hostnamekann in gespeichert werden /etc/nodename.)
Scott

2
Dies ist irrelevant - die Frage, wo dies geändert werden soll. Ja, der unameBefehl bezieht seine Informationen aus einem Systemaufruf. Und woher bezieht der Systemaufruf seine Informationen? (Antwort, bereitgestellt durch andere Poster hier: Es ist zur Kompilierungszeit im Kernel fest codiert.)
Gilles 'SO - hör auf, böse zu sein',

@ Gilles: Was ist irrelevent? Wenn die Antwort lautet "Von anderen Postern hier bereitgestellt: Es ist fest im Kernel codiert ...", dann habe ich genau dasselbe gesagt: "Dies kommt direkt vom laufenden Kernel. Ich würde annehmen, dass alle Informationen hart sind -coded in es ... da es Open Source ist, können Sie den Quellcode ändern und den Kernel neu kompilieren, um jeden gewünschten Sysnamen zu verwenden . Es ist keine Konfigurationsoption.
Goldilocks

2
@goldilocks Warum sollte sich das machineändern? Es wird möglicherweise nicht fest in den Kernel codiert, da es sich möglicherweise an die Hardware anpasst. Dann wird es jedoch beim Booten festgelegt und wird sich danach nicht mehr ändern. Aber nein: Sie kann pro Prozess festgelegt werden (z. B. um i686auf x86_64 verarbeitete 32-Bit-Daten zu melden ). Übrigens releasekann auch pro Prozess einigermaßen angepasst werden (try setarch i686 --uname-2.6 uname -a).
Gilles 'SO - hör auf, böse zu sein'

1
@ Gilles habe ich bearbeitet machine, nodenameund releasein die Frage mit einem Verweis auf die Kommentare. Auch hier ging es nicht wirklich um all diese Bereiche.
Goldlöckchen

26

Die Daten sind in init / version.c gespeichert:

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);

Die Zeichenfolgen selbst befinden sich in include / generated / compile.h:

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

und in include / generated / utsrelease.h:

#define UTS_RELEASE "3.14.0-v2-v"

UTS_SYSNAME kann in include / linux / uts.h definiert werden

#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif

oder als #define in makefiles

Schließlich können der Hostname und der Domainname von / proc / sys / kernel / {Hostname, Domainname} gesteuert werden. Dies sind pro UTS-Namespace:

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

Dies ist im Allgemeinen eine gute und vollständige Antwort, aber es kann sich lohnen, die Frage des Posters direkt zu beantworten. Ich glaube das würde bedeuten - den entsprechenden Eintrag in der entsprechenden Datei zu ändern und neu zu kompilieren. Sie haben "oder als #define in makefiles" geschrieben. Können Sie näher darauf eingehen?
Faheem Mitha

+1 für unshare. Irgendwie habe ich diesen Befehl bis heute verpasst. Vielen Dank!
Tino

Und include/generated/compile.hwird generiert von scripts/mkcompile_h: unix.stackexchange.com/a/485962/32558
Ciro Santilli am

8

Mithilfe eines Linux- Querverweises und Ihrer Erwähnung von habe /proc/sys/kernel/ostypeich nachverfolgt ostype, dass / linux / sysctl.h hinzugefügt wird , wobei in einem Kommentar angegeben wird, dass Namen durch Aufrufen hinzugefügt werden register_sysctl_table.

Also , wo ist die genannte aus ? Ein Ort ist kernel / utsname_sysctl.c , zu dem include / linux / uts.h gehört. Dort finden wir:

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

Also, wie die Kernel-Dokumentation besagt:

Die einzige Möglichkeit, diese Werte zu optimieren, besteht darin, den Kernel neu zu erstellen

:-)


6

Wie an anderer Stelle erwähnt, werden die Informationen mit dem unameSyscall geliefert, der im laufenden Kernel fest codiert ist.

Der Versionsteil wird normalerweise beim Kompilieren eines neuen Kernels durch das Makefile festgelegt :

VERSION = 3
PATCHLEVEL = 15
SUBLEVEL = 0
EXTRAVERSION =

Als ich Zeit zum Kompilieren meiner Kernel hatte, habe ich dort in EXTRAVERSION Dinge hinzugefügt. das gab dir uname -r mit dingen wie 3.4.1-mytestkernel.

Ich verstehe es nicht ganz, aber ich denke, dass der Rest der Informationen in der Makefileebenfalls umliegenden Zeile 944 eingerichtet ist:

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

# 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

Für den Rest der Daten wird der sys_unameSystemaufruf mithilfe von Makros generiert (auf eine ziemlich verschlungene Weise). Wenn Sie sich abenteuerlustig fühlen , können Sie von hier aus beginnen.

Der wahrscheinlich beste Weg, solche Informationen zu ändern, ist das Schreiben eines Kernel-Moduls, um den unameSyscall zu überschreiben . Ich habe das nie gemacht, aber Sie finden Informationen auf dieser Seite in Abschnitt 4.2 (Entschuldigung, kein direkter Link). Beachten Sie jedoch, dass sich dieser Code auf einen ziemlich alten Kernel bezieht (jetzt hat der Linux-Kernel utsNamespaces, was auch immer sie bedeuten), so dass Sie ihn wahrscheinlich sehr oft ändern müssen.


Vielen Dank an alle. Ich wusste schon, dass es etwas mit Uname zu tun hat. Was ich jedoch nicht verstehen kann, ist, wie und wo in der Quelle der String "Linux" definiert ist. Ich weiß nur, wo ich diese Informationen zur Laufzeit finden kann (sie sind in / proc / sys / kernel / ostype enthalten). Es wäre interessanter, herauszufinden, wie genau der Kernel selbst den richtigen Namen kennt, würde ich sagen.
user237251

@ user237251 Wie viele Instanzen des Wortes "Linux" kommen in der Kernelquelle in String-Kontexten vor? Wenn es nicht so viele sind, können Sie einfach die Ergebnisse einer Textsuche untersuchen und sehen, wohin Sie das führt.
JAB

@JAB Viel zu viele. Zum Glück hat mir jemand auf kernelnewbies.org geholfen, das "Rätsel" zu lösen. Linux erhält seinen sys-Namen von /include/Linux/uts.h. Siehe hier: lxr.free-electrons.com/source/include/linux/uts.h?v=3.10
user237251

2

Obwohl ich nichts in der Quelle finden konnte, das dies anzeigt, glaube ich, dass der uname syscall verwendet wird.

man 2 uname

sollte dir mehr darüber erzählen. Wenn dies der Fall ist, werden die Informationen direkt vom Kernel abgerufen, und das Ändern erfordert wahrscheinlich eine Neukompilierung.

Sie können die Binärdatei ändern, damit Sie uname tun können, was Sie wollen. Schreiben Sie einfach mit einem Programm darüber, das Sie möchten. Der Nachteil einiger Skripte ist, dass sie von dieser Ausgabe abhängen.


3
In strace unamediesem Fall wird bestätigt, dass der unameSystemaufruf verwendet wird.
Graeme

1

Die richtige Möglichkeit, uname zu ändern, besteht darin, die Compile-Header zu ändern und neu zu kompilieren, wie von anderen vorgeschlagen. Aber ich bin nicht sicher, warum Sie so viel Ärger machen wollen, wenn Sie etwas tun können,

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

oder auch

alias uname 'echo whatever'

0

Rmano ‚s Antwort hat mich leicht an , aber die wirkliche Magie einfacher , indem man das entdeckt wird Q=Option in Ihrem makeKommandozeile im Kernel - Quellverzeichnis. es können Sie die Details sehen, von denen ein Anruf an ein Skript ist: echo "4.4.19$(/bin/sh ./scripts/setlocalversion .)". Wenn Sie dasselbe Snippet ausführen, erhalten Sie die Versionsnummer des Kernels 4.4.19-00010-ge5dddbf. Wenn Sie sich das Skript ansehen, ermittelt es die Nummer aus dem Versionsverwaltungssystem, und wenn Sie es mit bash -xausführen, wird der genaue Prozess angezeigt:

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

Das zeigt mir, dass ich, wenn ich ein Kernelmodul für meinen laufenden Kernel erstellen möchte, die Version mit dem falschen Tag und das falsche Commit habe. Ich muss das beheben und mindestens die DTBs ( make dtbs) erstellen, um die generierten Dateien mit der richtigen Versionsnummer zu erstellen.


stellt sich heraus, auch das war nicht genug. Ich musste eine ersetzen scripts/setlocalversion, die einfach tut:

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

Erstellen Sie dann die automatisch generierten Dateien neu:

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

dann konnte ich Derek Molloys Beispieltreiber bauen und konnte insmodes erfolgreich. anscheinend spielte die Warnung, Module.symversnicht anwesend zu sein, keine Rolle. Alles, was Linux benutzte, um festzustellen, ob das Modul funktionieren würde, war diese localversion-Zeichenfolge.


0

scripts/mkcompile_h

In Version 4.19 ist dies die Datei, die Folgendes generiert include/generated/compile.hund enthält /proc/version: https://github.com/torvalds/linux/blob/v4.19/scripts/mkcompile_h

  • Der #<version>Teil stammt aus der .versionDatei im Build-Baum, die bei jedem Verbindungsaufbau (erfordert Datei- / Konfigurationsänderungen) um erhöht wird scripts/link-vmlinux.sh.

    Sie kann von der KBUILD_BUILD_VERSIONUmgebungsvariablen überschrieben werden :

    if [ -z "$KBUILD_BUILD_VERSION" ]; then
        VERSION=$(cat .version 2>/dev/null || echo 1)
    else
        VERSION=$KBUILD_BUILD_VERSION
    fi
    
  • Das Datum ist nur ein kurzer dateAnruf:

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

    und in ähnlicher Weise kommt der Benutzername von whoami( KBUILD_BUILD_USER) und der Hostname von hostname( KBUILD_BUILD_HOST)

  • Die Compilerversion stammt von gcc -vund kann anscheinend nicht gesteuert werden.

Hier ist eine Anleitung zum Ändern der Stuff-Version der Frage: https://stackoverflow.com/questions/23424174/how-to-customize-or-remove-extra-linux-kernel-version-details-shown-at-boot

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.