sethostname系统调用及示例

我们来深入学习 sethostname 系统调用,在 Linux 系统(以及大多数 Unix-like 系统)中,每台计算机都有一个唯一的标识符,叫做 主机名 (hostname)。这个主机名用于在网络中识别这台机器。例如,当你在命令行输入 hostname 时,它会显示当前机器的主机名。sethostname 系统调用的作用就是设置这台运行着 Linux 内核的计算机的 主机名。这是一个系统级别的设置,会影响整个机器,而不仅仅是调用它的那个进程。

1. 函数介绍

在 Linux 系统(以及大多数 Unix-like 系统)中,每台计算机都有一个唯一的标识符,叫做 主机名 (hostname)。这个主机名用于在网络中识别这台机器。例如,当你在命令行输入 hostname 时,它会显示当前机器的主机名。sethostname 系统调用的作用就是设置这台运行着 Linux 内核的计算机的 主机名。这是一个系统级别的设置,会影响整个机器,而不仅仅是调用它的那个进程。

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

简单来说,sethostname 就是让你用程序来给你的 Linux 电脑“改名字”。

重要提示:

需要权限:修改主机名是一个特权操作,通常只有 root 用户(超级用户)才有权限执行 sethostname。普通用户尝试调用它会失败。

影响范围:主机名是系统全局的属性。一旦通过 sethostname 修改,系统中所有查询主机名的地方(如 gethostname, uname 命令)都会返回新的名字。

持久性:通过 sethostname 设置的主机名是临时的。它只在当前的系统运行会话(直到关机或重启)中有效。系统重启后,主机会从配置文件(如 /etc/hostname)中读取并恢复原来的主机名。

2. 函数原型

1
2
3
4
5
#include <unistd.h>      // 包含系统调用声明
#include <sys/utsname.h> // 有时也需要,包含主机名长度常量

int sethostname(const char *name, size_t len);

3. 功能

设置内核维护的主机名。这个主机名可以通过 gethostname 系统调用或 uname 系统调用来查询。

4. 参数

name:

  • const char * 类型。

  • 一个指向以 null 结尾的字符串的指针,该字符串包含了新的主机名。

len:

  • size_t 类型。

  • 指定 name 字符串中实际包含的字符数(不包括末尾的 null 终止符 \0)。通常使用 strlen(name) 来获取这个长度。

5. 返回值

  • 成功: 返回 0。

  • 失败: 返回 -1,并设置全局变量 errno 来指示具体的错误原因。

6. 错误码 (errno)

  • EFAULT: name 指向了调用进程无法访问的内存地址。

  • EINVAL: len 超过了系统允许的最大主机名长度(通常是 MAXHOSTNAMELEN,在 <sys/utsname.h> 或 <limits.h> 中定义,常见值是 64 或 256)。

  • EPERM: 调用进程没有权限(不是 root 用户)来更改主机名。

7. 相似函数或关联函数

  • gethostname: 用于获取当前的主机名。

  • uname: 系统调用,可以获取包括主机名在内的系统信息(系统名、版本、机器类型等)。对应的命令行工具也叫 uname。

  • hostname: 命令行工具,用于显示或设置系统的主机名。它在底层就是调用 sethostname 和 gethostname。

  • /etc/hostname: 在许多 Linux 发行版中,系统启动时会从这个文件读取主机名并使用 sethostname 设置。

8. 示例代码

下面的示例演示了如何使用 sethostname 来修改主机名,以及如何使用 gethostname 来查询它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#define _GNU_SOURCE // 启用 GNU 扩展
#include <stdio.h>
#include <unistd.h>
#include <sys/utsname.h> // 包含 gethostname, uname, MAXHOSTNAMELEN
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#define HOST_NAME_BUFFER_SIZE MAXHOSTNAMELEN // 通常定义在 <sys/utsname.h> 或 <limits.h>

void print_current_hostname(const char* context) {
char hostname&#91;HOST_NAME_BUFFER_SIZE];
if (gethostname(hostname, sizeof(hostname)) == 0) {
printf("&#91;%s] Current hostname is: '%s'\n", context, hostname);
} else {
perror("gethostname");
}
}

int main(int argc, char *argv&#91;]) {
char new_hostname&#91;HOST_NAME_BUFFER_SIZE];
struct utsname uname_info; // 用于 uname 系统调用

printf("--- Demonstrating sethostname ---\n");

// 1. 显示当前主机名
print_current_hostname("Initial");

// 2. 使用 uname 系统调用获取更详细的系统信息
if (uname(&uname_info) == 0) {
printf("&#91;uname] System name: %s\n", uname_info.sysname);
printf("&#91;uname] Node name (hostname): %s\n", uname_info.nodename);
printf("&#91;uname] Release: %s\n", uname_info.release);
printf("&#91;uname] Version: %s\n", uname_info.version);
printf("&#91;uname] Machine: %s\n", uname_info.machine);
} else {
perror("uname");
}

// 3. 检查命令行参数
if (argc != 2) {
printf("Usage: %s <new_hostname>\n", argv&#91;0]);
printf("Note: You need to run this program as root to change the hostname.\n");
exit(EXIT_FAILURE);
}

strncpy(new_hostname, argv&#91;1], sizeof(new_hostname) - 1);
new_hostname&#91;sizeof(new_hostname) - 1] = '\0'; // 确保 null 终止

printf("\nAttempting to change hostname to: '%s'\n", new_hostname);

// 4. 调用 sethostname
// 注意:这需要 root 权限
if (sethostname(new_hostname, strlen(new_hostname)) == -1) {
perror("sethostname");
if (errno == EPERM) {
printf("Error: Permission denied. You must run this program as root (e.g., using sudo).\n");
}
exit(EXIT_FAILURE);
}

printf("sethostname('%s') succeeded.\n", new_hostname);

// 5. 再次显示主机名以验证更改
print_current_hostname("After sethostname");

// 6. 再次使用 uname 验证
if (uname(&uname_info) == 0) {
printf("&#91;uname after change] Node name (hostname): %s\n", uname_info.nodename);
}

printf("\n--- Important Notes ---\n");
printf("1. The hostname change is TEMPORARY and only lasts until the system is rebooted.\n");
printf("2. To make the change persistent, you need to update configuration files like /etc/hostname.\n");
printf("3. You need ROOT privileges to call sethostname.\n");

return 0;
}

编译和运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 假设代码保存在 sethostname_example.c 中
gcc -o sethostname_example sethostname_example.c

# 1. 不带参数运行 (会报错)
./sethostname_example

# 2. 带一个参数运行,但没有 root 权限 (会失败)
./sethostname_example MyNewTempHostname

# 3. 带一个参数运行,并使用 sudo 获取 root 权限 (应该成功)
# 注意:请将 MyNewTempHostname 替换为你想要的主机名
sudo ./sethostname_example MyNewTempHostname

# 4. 验证更改
hostname
uname -n

预期输出 (使用 sudo 运行):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 假设原始主机名是 'old-hostname'
$ sudo ./sethostname_example NewTempName
--- Demonstrating sethostname ---
&#91;Initial] Current hostname is: 'old-hostname'
&#91;uname] System name: Linux
&#91;uname] Node name (hostname): old-hostname
&#91;uname] Release: 5.4.0-XX-generic
&#91;uname] Version: #XX-Ubuntu SMP ...
&#91;uname] Machine: x86_64

Attempting to change hostname to: 'NewTempName'
sethostname('NewTempName') succeeded.
&#91;After sethostname] Current hostname is: 'NewTempName'
&#91;uname after change] Node name (hostname): NewTempName

--- Important Notes ---
1. The hostname change is TEMPORARY and only lasts until the system is rebooted.
2. To make the change persistent, you need to update configuration files like /etc/hostname.
3. You need ROOT privileges to call sethostname.

# 验证命令
$ hostname
NewTempName
$ uname -n
NewTempName

重启后:如果你重启系统,主机会名会恢复到 /etc/hostname 文件中配置的名称。

总结:sethostname 是一个用于修改系统全局主机名的系统调用。它需要 root 权限,并且修改是临时的。理解它有助于你编写需要动态管理主机名的系统管理工具。在日常使用中,hostname 命令是更常见的设置主机名的方式。

https://www.calcguide.tech/2025/08/23/sethostname系统调用及示例-2/

FL:https://blog.csdn.net/timberwolf007/article/details/150643034?sharetype=blogdetail&sharerId=150643034&sharerefer=PC&sharesource=zidier215&spm=1011.2480.3001.8118

data-ad-format="auto" data-full-width-responsive="true">