uname
unameコマンドはシステム情報の表示をします。私の環境では以下の通りです。
ip_auto_config_setup()で:をデリミタとする以下の最大6つの項目のaddrsから、ネットワーク設定値を取得し、このホスト名がnodenameに設定されます。
addrs=ローカルアドレス:サーバアドレス:ゲートウエイ:ネットマスク:ホスト名:デバイス名:プロトコル名
(プロトコル名はon/any/dhcp/bootp/rarp/bothのいずれか。ただしコンパイルオプションによる。)
推測ですが、__setup("ip=", ip_auto_config_setup);としてのコールは、カーネル起動時、/etc/sysconfig/networkの内容をip=:::::と編集してコールされるのではと思います。
[root@localhost test]# uname -a Linux localhost.localdomain 3.3.8-1.fc16.i686 #1 SMP Mon Jun 4 21:30:50 UTC 2012 i686 i686 i386 GNU/Linuxunameコマンドはシステムコールの122(ただし、i386の場合で他のシステムは異なっています。それ故下記サンプルが動作しなくて悩みました。)また、システムの応じて3つのフォーマットを有しています。
struct oldold_utsname { char sysname[9]; char nodename[9]; char release[9]; char version[9]; char machine[9]; }; #define __NEW_UTS_LEN 64 struct old_utsname { char sysname[65]; char nodename[65]; char release[65]; char version[65]; char machine[65]; }; struct new_utsname { char sysname[65]; char nodename[65]; char release[65]; char version[65]; char machine[65]; char domainname[65]; }; asmlinkage int sys_uname(struct old_utsname __user * name) { int err; if (!name) return -EFAULT; down_read(&uts_sem); err=copy_to_user(name, &system_utsname, sizeof (*name)); up_read(&uts_sem); return err?-EFAULT:0; }sys_uname()は、system_utsnameを返すだけでが、unameコマンドはglibを介しての処理で、下記サンプルは、直接システムコールを通しての私の環境での結果です。
#include <stdio.h> struct new_utsname { char sysname[65]; char nodename[65]; char release[65]; char version[65]; char machine[65]; char domainname[65]; } ; void main() { struct new_utsname *tmp, utsname; tmp = &utsname; __asm__("movl $122, %%eax;\n\t" "int $0x80" : :"b"(tmp) );:q printf("sysname :%s\n", utsname.sysname); printf("nodename :%s\n", utsname.nodename); printf("release :%s\n", utsname.release); printf("version :%s\n", utsname.version); printf("machine :%s\n", utsname.machine); printf("domainname:%s\n", utsname.domainname); } [root@localhost test]# ./a.out sysname :Linux nodename :localhost.localdomain release :3.3.8-1.fc16.i686 version :#1 SMP Mon Jun 4 21:30:50 UTC 2012 machine :i686 domainname:(none)system_utsnameは以下のマクロで初期化されています。UTS_RELEASEはカーネルのMakefileのVERSION+PATCHLEVEL+SUBLEVEL+EXTRAVERSION、またUTS_MACHINEもmakefie下で定義されてます。そしてUTS_VERSIONは/usr/src/linux/include/generated/utsrelease.h(カーネルコンパイル時に生成される。)で設定されます。カーネルモジュールのマジック番号(その1)参照
#ifndef UTS_SYSNAME #define UTS_SYSNAME "Linux" #endif #ifndef UTS_NODENAME #define UTS_NODENAME "(none)" /* set by sethostname() */ #endif #ifndef UTS_DOMAINNAME #define UTS_DOMAINNAME "(none)" /* set by setdomainname() */ #endif struct new_utsname system_utsname = { .sysname = UTS_SYSNAME .nodename = UTS_NODENAME .release = UTS_RELEASE .version = UTS_VERSION .machine = UTS_MACHINE .domainname = UTS_DOMAINNAME };.nodename/.domainnameはIPアドレスの設定時に設定されるようです。IPアドレス設定時にコールされるip_auto_config_setup()で、設定されるようです。なおnfsaddrs_config_setup()からも、ip_auto_config_setup()をコールしていますが、これはnfsをルートファイルシステムとするケースだと思います。
ip_auto_config_setup()で:をデリミタとする以下の最大6つの項目のaddrsから、ネットワーク設定値を取得し、このホスト名がnodenameに設定されます。
addrs=ローカルアドレス:サーバアドレス:ゲートウエイ:ネットマスク:ホスト名:デバイス名:プロトコル名
(プロトコル名はon/any/dhcp/bootp/rarp/bothのいずれか。ただしコンパイルオプションによる。)
static int __init ip_auto_config_setup(char *addrs) { char *cp, *ip, *dp; int num = 0; ic_set_manually = 1; ic_enable = (*addrs && (strcmp(addrs, "off") != 0) && (strcmp(addrs, "none") != 0)); if (!ic_enable) return 1; if (ic_proto_name(addrs)) return 1; /* Parse the whole string */ ip = addrs; while (ip && *ip) { if ((cp = strchr(ip, ':'))) *cp++ = '\0'; if (strlen(ip) > 0) { DBG(("IP-Config: Parameter #%d: `%s'\n", num, ip)); switch (num) { case 0: if ((ic_myaddr = in_aton(ip)) == INADDR_ANY) ic_myaddr = INADDR_NONE; break; case 1: if ((ic_servaddr = in_aton(ip)) == INADDR_ANY) ic_servaddr = INADDR_NONE; break; case 2: if ((ic_gateway = in_aton(ip)) == INADDR_ANY) ic_gateway = INADDR_NONE; break; case 3: if ((ic_netmask = in_aton(ip)) == INADDR_ANY) ic_netmask = INADDR_NONE; break; case 4: if ((dp = strchr(ip, '.'))) { *dp++ = '\0'; strlcpy(system_utsname.domainname, dp, sizeof(system_utsname.domainname)); } strlcpy(system_utsname.nodename, ip, sizeof(system_utsname.nodename)); ic_host_name_set = 1; break; case 5: strlcpy(user_dev_name, ip, sizeof(user_dev_name)); break; case 6: ic_proto_name(ip); break; } } ip = cp; num++; } return 1; } static int __init nfsaddrs_config_setup(char *addrs) { return ip_auto_config_setup(addrs); } __setup("ip=", ip_auto_config_setup); __setup("nfsaddrs=", nfsaddrs_config_setup);__setupマクロは以下の様に定義され、
struct obs_kernel_param { const char *str; int (*setup_func)(char *); } #define __init __attribute__ ((__section__ (".text.init"))) #define __setup(str, fn) \ static char __setup_str_##fn[] __initdata = str; \ static struct obs_kernel_param __setup_##fn \ __attribute_used__ \ __attribute__((__section__(".init.setup"))) \ = { __setup_str_##fn, fn } #define module_init(initfn) \ static inline initcall_t __inittest(void) \ { return initfn; } \ int init_module(void) __attribute__((alias(#initfn))); [root@localhost test]# cat hogehoge.c static int __init hogehoge(void) { } __setup("ip=", hogehoge); [root@localhost test]# gcc -E hogehoge.c # 1 "hogehoge.c" # 1 "<組み込み>" # 1 "<コマンドライン>" # 1 "hogehoge.c" typedef int (*initcall_t)(void); # 18 "hogehoge.c" static int __attribute__ ((__section__ (".text.init"))) hogehoge(void) { } static char __setup_str_hogehoge[] __initdata = "ip="; static struct obs_kernel_param __setup_hogehoge __attribute_used__ __attribute__((__section__(".init.setup"))) = { __setup_str_hogehoge, hogehoge };.init.setupセクションに、struct obs_kernel_param構造体として、__setup_str_hogehoge/hogehogeが配置されます。__setup_str_hogehogeは引数の"ip="で、hogehogeが関数となるわけです。
補足
sysnameはデフォルトのLinux以外に、SunOS/HP-UXがあるようです。推測ですが、__setup("ip=", ip_auto_config_setup);としてのコールは、カーネル起動時、/etc/sysconfig/networkの内容をip=:::::と編集してコールされるのではと思います。