我们来深入学习 sethostname
系统调用及示例
1. 函数介绍
sethostname
系统调用的作用就是设置这台运行着 Linux 内核的计算机的 主机名。这是一个系统级别的设置,会影响整个机器,而不仅仅是调用它的那个进程。
简单来说,sethostname
就是让你用程序来给你的 Linux 电脑“改名字”。
2. 函数原型
#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
来查询它。
#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[HOST_NAME_BUFFER_SIZE];
if (gethostname(hostname, sizeof(hostname)) == 0) {
printf("[%s] Current hostname is: '%s'\n", context, hostname);
} else {
perror("gethostname");
}
}
int main(int argc, char *argv[]) {
char new_hostname[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("[uname] System name: %s\n", uname_info.sysname);
printf("[uname] Node name (hostname): %s\n", uname_info.nodename);
printf("[uname] Release: %s\n", uname_info.release);
printf("[uname] Version: %s\n", uname_info.version);
printf("[uname] Machine: %s\n", uname_info.machine);
} else {
perror("uname");
}
// 3. 检查命令行参数
if (argc != 2) {
printf("Usage: %s <new_hostname>\n", argv[0]);
printf("Note: You need to run this program as root to change the hostname.\n");
exit(EXIT_FAILURE);
}
strncpy(new_hostname, argv[1], sizeof(new_hostname) - 1);
new_hostname[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("[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;
}
编译和运行:
# 假设代码保存在 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
运行):
# 假设原始主机名是 'old-hostname'
$ sudo ./sethostname_example NewTempName
--- Demonstrating sethostname ---
[Initial] Current hostname is: 'old-hostname'
[uname] System name: Linux
[uname] Node name (hostname): old-hostname
[uname] Release: 5.4.0-XX-generic
[uname] Version: #XX-Ubuntu SMP ...
[uname] Machine: x86_64
Attempting to change hostname to: 'NewTempName'
sethostname('NewTempName') succeeded.
[After sethostname] Current hostname is: 'NewTempName'
[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
命令是更常见的设置主机名的方式。