unameはどこから情報を取得しますか?


40

unameは実際にどこから情報を取得しますか?

これは簡単なことだと思います。残念ながら、その情報だけを含むヘッダーは見つかりません。

セイは、誰かがの基本的な出力変更したいuname/をuname -s からLinux(カーネルの名前を変更し、基本的に)何か他のものに。

彼/彼女はそれを適切な方法(つまり、ソースの変更)でどのように実行しますか?

回答:


26

unameユーティリティからその情報を取得するuname()システムコール。次のような構造体を作成します(「参考文献」を参照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
       };

これは、実行中のカーネルから直接取得されます。私は、おそらく除いて、すべての情報がそれにハードコーディングされているとしますdomainname(また、それは結局のところ、およびnodenamemachine、およびrelease、コメントを参照してください)。リリース文字列fromはuname -r、構成時にコンパイル時に設定できますが、sysnameフィールドができることは非常に疑問です。Linuxカーネルであり、他のものを使用する理由は考えられません。

ただし、オープンソースなので、ソースコードを変更し、必要なsysnameを使用するようにカーネルを再コンパイルできます。


2
domainnameフィールドがで設定されているdomainname使用して、コマンドsetdomainnameシステムコールを。同様に、nodenameフィールドはシステムコールhostnameを使用してコマンドによって設定されsethostnameます。(nodename/ hostname値に格納されてもよい/etc/nodename。)
スコット

2
これは無関係です。どこで変更するかという質問です。そのため、unameコマンドはシステムコールから情報を取得します。そして、システムコールはどこで情報を取得しますか?(ここで他のポスターから提供された回答:コンパイル時にカーネルにハードコードされています。)
ジル 'SO-悪であるのをやめなさい'

@Gilles:関係ないものは何ですか?その答えは、「ここに他のポスターが提供する:それはカーネルにハードコーディングされています...」されている場合は、ノートのIましたが、まったく同じことを言った:「これは、実行中のカーネルから直接来る。私はすべての情報がハードであると仮定しますそれはオープンソースですので、あなたがソースコードを変更し、あなたが望むものは何でもSYSNAME使用にカーネルを再コンパイルでき...それに-codedそれはある。ない設定オプション。
ゴルディロックス

2
@goldilocksなぜmachine変わるのでしょうか?ハードウェアに適応する可能性があるため、カーネルにハードコーディングされていない可能性がありますが、確実にブート時に設定され、その後は変更されません。ただし、プロセスごとに設定できます(i686x86_64で処理された32ビットにレポートするなど)。ところで、releaseプロセスごとにある程度カスタマイズすることもできます(試してみてくださいsetarch i686 --uname-2.6 uname -a)。
ジル 'SO-悪であるのをやめる' 14年

1
@Gilles私が編集したmachinenodenamereleaseのコメントを参照して、質問に。繰り返しますが、質問は実際にはそれらすべてのフィールドに関するものではありませんでした。
goldilocks 14年

26

データは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);

文字列自体はinclude / generated / compile.hにあります。

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

そしてinclude / generated / utsrelease.hで:

#define UTS_RELEASE "3.14.0-v2-v"

UTS_SYSNAMEはinclude / linux / uts.hで定義できます

#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif

またはメイクファイルの#defineとして

最後に、ホスト名とドメイン名は/ proc / sys / kernel / {hostname、domainname}で制御できます。これらはUTS名前空間ごとです。

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

これは一般に良い完全な回答ですが、ポスターの質問に直接答える価値があるかもしれません。これは、関連するファイルの関連エントリを変更して再コンパイルすることになると思います。「またはmakefileの#defineとして」と書きました。詳しく説明してもらえますか?
ファヒムミタ

+1 unshare。どういうわけか私は今日までこのコマンドを見逃していました。ありがとう!
ティノ

そして、include/generated/compile.hによって生成されるscripts/mkcompile_hunix.stackexchange.com/a/485962/32558
チロSantilli新疆改造中心法轮功六四事件

8

助けを借りてLinuxのクロスリファレンスとのあなたの言及/proc/sys/kernel/ostype、私が追跡ostypeするために/ linuxの/ sysctl.h含まコメントは名前を呼び出すことによって追加されたことを述べている場合は、register_sysctl_table

それはどこから呼び出されるのですか?1つの場所はkernel / utsname_sysctl.cでinclude / linux / uts.hが含まています。

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

したがって、カーネルのドキュメントには次のように記載されています

これらの値を調整する唯一の方法は、カーネルを再構築することです

:-)


6

他の場所でコメントされているように、情報unameは実行中のカーネルにハードコードされているsyscallに付属しています。

Makefileで新しいカーネルをコンパイルするとき、バージョン部分は通常設定されます

VERSION = 3
PATCHLEVEL = 15
SUBLEVEL = 0
EXTRAVERSION =

カーネルのコンパイルをする時間があったとき、EXTRAVERSIONでそこに物を追加していました。それはのuname -r ようなものを与えた3.4.1-mytestkernel

私はそれを完全には理解していませんが、残りの情報はMakefile944行目付近にも設定されていると思います。

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

# 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

残りのデータについては、sys_unameマクロを使用して(かなり複雑な方法で)syscallが生成されます 。冒険心があれば、ここから開始できます。

おそらく、そのような情報を変更する最良の方法は、unamesyscall をオーバーライドするカーネルモジュールを作成することです。私はそれをやったことはありませんが、このページのセクション4.2で情報見つけることができます(申し訳ありませんが、直接リンクはありません)。ただし、そのコードは非常に古いカーネルを参照していることに注意してください(現在のLinuxカーネルにはuts名前空間があります)。


みんな、ありがとう。すでにウナメと関係があることは知っていました。ただし、ソース内の「Linux」という文字列がどのように、どこで定義されているのかを推測することはできません。私が知っているのは、実行時にその情報をどこで見つけることができるかです(/ proc / sys / kernel / ostypeに含まれています)。カーネル自体が適切な名前であることを正確に認識する方法を見つけることは、もっと興味深いことの1つです。
user237251 14年

@ user237251文字列コンテキストのカーネルソースで「Linux」という単語のインスタンスがいくつ発生しますか?それほど多くない場合は、テキスト検索の結果を調べて、それがあなたをどこに導くかを確認することができます。
JAB

@JABが多すぎます。幸いなことに、kernelnewbies.orgの誰かが「謎」の解決を助けてくれました。Linuxは/include/Linux/uts.hからsys名を取得します。こちらをご覧ください:lxr.free-electrons.com/source/include/linux/uts.h
v

2

ソースにこれを示すものは見つかりませんでしたが、uname syscallを使用していると思います。

man 2 uname

それについてもっと教えてください。その場合は、カーネルから情報を直接取得し、変更するにはおそらく再コンパイルが必要になります。

あなたが好きなことをするためにあなたのためにバイナリを変更することもできますが、w / eプログラムでそれを上書きしてください。一部のスクリプトの欠点は、その出力に依存しています。


3
実行strace unameすると、unameシステムコールが使用されていることが確認されます。
グレアム

1

unameを変更する適切な方法は、コンパイルヘッダーを変更し、他の人が提案したように再コンパイルすることです。しかし、私はあなたが何かのようなことをすることができるのになぜそんなに多くのトラブルを経験したいのか分かりません。

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

あるいは

alias uname 'echo whatever'

0

Rmanoの答えは途中で得られましたが、本当の魔法はカーネルソースディレクトリのコマンドラインでQ=オプションを渡すことで簡単に発見できますmake。詳細を確認できます。詳細の1つは、スクリプトの呼び出しですecho "4.4.19$(/bin/sh ./scripts/setlocalversion .)"。同じスニペットを実行すると、カーネルのリリース番号が得られます4.4.19-00010-ge5dddbf。スクリプトを見ると、バージョン管理システムから番号を判別し、それを実行するとbash -x正確なプロセスが表示されます。

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

これが私に示しているのは、実行中のカーネルで動作するカーネルモジュールを構築したい場合、間違ったタグ付きリリースと間違ったコミットをしているということです。make dtbs適切なバージョン番号で生成されたファイルを作成するために、それを修正し、少なくともDTB()をビルドする必要があります。


でも、それでも十分ではありませんでした。私はscripts/setlocalversion単にするものに置き換える必要がありました:

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

次に、自動生成されたファイルを再構築します。

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

その後、Derek Molloyのサンプルドライバーを構築でき、insmod正常に実行できました。どうやらModule.symvers存在しないという警告は重要ではなかったようです。モジュールが動作するかどうかを判断するためにLinuxが使用していたのは、そのlocalversion文字列のみでした。


0

scripts/mkcompile_h

v4.19では、これはを生成するファイルでありinclude/generated/compile.hhttps/proc/version//github.com/torvalds/linux/blob/v4.19/scripts/mkcompile_hの興味深い部分がいくつか含まれています

  • #<version>一部はから来ている.versionリンクはで(ファイル/設定の変更が必要となる)が起こるたびにインクリメントされますビルドツリー、上のファイルscripts/link-vmlinux.sh

    KBUILD_BUILD_VERSION環境変数で上書きできます:

    if [ -z "$KBUILD_BUILD_VERSION" ]; then
        VERSION=$(cat .version 2>/dev/null || echo 1)
    else
        VERSION=$KBUILD_BUILD_VERSION
    fi
    
  • 日付は単なる生のdate呼び出しです。

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

    同様に、ユーザー名はwhoamiKBUILD_BUILD_USER)から、ホスト名はhostnameKBUILD_BUILD_HOST)から

  • コンパイラのバージョンはに由来しgcc -v、制御できないようです。

質問のスタッフバージョンを変更する方法は次のとおりです

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.