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=:::::と編集してコールされるのではと思います。





