我注意到您询问的是 mknodeat
,但这个函数在标准的 Linux 系统调用中并不存在。您可能想问的是以下几种情况之一:
- mknodat - 创建特殊文件的系统调用
- mknod - 传统的创建特殊文件函数
- mkdirat - 创建目录的系统调用(我在前面已经详细介绍过)
让我为您提供最可能相关的 mknodat
函数详解:
mknodat 函数详解 見出しへのリンク
1. 函数介绍 見出しへのリンク
mknodat
是 Linux 系统中用于创建特殊文件(设备文件、命名管道、符号链接等)的系统调用,它是 mknod
函数的增强版本,支持相对路径创建。可以把 mknodat
想象成"特殊文件创建工厂"——它能够根据指定的类型和参数创建各种系统特殊文件。
2. 函数原型 見出しへのリンク
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sysmacros.h>
int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
3. 功能 見出しへのリンク
mknodat
函数用于创建特殊文件,包括设备文件(字符设备、块设备)、命名管道(FIFO)等。如果 pathname
是相对路径,它相对于 dirfd
指定的目录来解释。
4. 参数 見出しへのリンク
- dirfd: 目录文件描述符,作为路径解析的起始点
- 如果是有效的文件描述符,则
pathname
相对于该目录解释 - 如果是
AT_FDCWD
,则pathname
相对于当前工作目录解释
- 如果是有效的文件描述符,则
- pathname: 要创建的特殊文件路径名
- mode: 文件类型和权限模式
- dev: 设备号(对于设备文件)
5. 文件类型和权限模式 見出しへのリンク
文件类型(mode 的高 4 位) 見出しへのリンク
类型 | 值 | 说明 |
---|---|---|
S_IFREG | 0100000 | 普通文件 |
S_IFDIR | 0040000 | 目录 |
S_IFCHR | 0020000 | 字符设备 |
S_IFBLK | 0060000 | 块设备 |
S_IFIFO | 0010000 | 命名管道 |
S_IFSOCK | 0140000 | 套接字 |
S_IFLNK | 0120000 | 符号链接 |
权限模式(mode 的低 12 位) 見出しへのリンク
权限 | 值 | 说明 |
---|---|---|
S_IRWXU | 0700 | 所有者读写执行 |
S_IRUSR | 0400 | 所有者读 |
S_IWUSR | 0200 | 所有者写 |
S_IXUSR | 0100 | 所有者执行 |
S_IRWXG | 0070 | 组读写执行 |
S_IRGRP | 0040 | 组读 |
S_IWGRP | 0020 | 组写 |
S_IXGRP | 0010 | 组执行 |
S_IRWXO | 0007 | 其他用户读写执行 |
S_IROTH | 0004 | 其他用户读 |
S_IWOTH | 0002 | 其他用户写 |
S_IXOTH | 0001 | 其他用户执行 |
6. 设备号(dev 参数) 見出しへのリンク
对于字符设备和块设备,需要指定设备号:
- 主设备号: 标识设备类型
- 次设备号: 标识同一类型中的具体设备
使用 makedev()
宏创建设备号:
dev_t dev = makedev(major, minor);
7. 返回值 見出しへのリンク
- 成功: 返回 0
- 失败: 返回 -1,并设置相应的 errno 错误码
8. 常见错误码 見出しへのリンク
EACCES
: 权限不足EEXIST
: 文件已存在EFAULT
: pathname 指针无效EINVAL
: 参数无效ELOOP
: 符号链接循环ENAMETOOLONG
: 路径名过长ENOENT
: 路径前缀不存在ENOMEM
: 内存不足ENOSPC
: 设备空间不足ENOTDIR
: dirfd 不是目录EPERM
: 权限不足(创建设备文件通常需要 root 权限)EROFS
: 文件系统只读
9. 相似函数或关联函数 見出しへのリンク
- mknod: 传统的创建特殊文件函数
- mkdirat: 创建目录
- openat: 相对路径打开文件
- mkfifo: 创建命名管道
- creat: 创建普通文件
10. 示例代码 見出しへのリンク
示例1:基础用法 - 创建各种特殊文件 見出しへのリンク
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sysmacros.h>
#include <errno.h>
#include <string.h>
// 显示文件信息
void show_file_info(const char *path) {
struct stat file_stat;
if (stat(path, &file_stat) == -1) {
printf(" 无法获取文件信息: %s\n", strerror(errno));
return;
}
printf(" 路径: %s\n", path);
printf(" Inode: %ld\n", (long)file_stat.st_ino);
printf(" 权限: %o", file_stat.st_mode & 07777);
// 显示文件类型
printf(" (");
switch (file_stat.st_mode & S_IFMT) {
case S_IFREG: printf("普通文件"); break;
case S_IFDIR: printf("目录"); break;
case S_IFCHR: printf("字符设备"); break;
case S_IFBLK: printf("块设备"); break;
case S_IFIFO: printf("命名管道"); break;
case S_IFSOCK: printf("套接字"); break;
case S_IFLNK: printf("符号链接"); break;
default: printf("未知类型"); break;
}
printf(")\n");
// 如果是设备文件,显示设备号
if (S_ISCHR(file_stat.st_mode) || S_ISBLK(file_stat.st_mode)) {
printf(" 主设备号: %d\n", major(file_stat.st_rdev));
printf(" 次设备号: %d\n", minor(file_stat.st_rdev));
}
printf(" 所有者: UID=%d, GID=%d\n",
file_stat.st_uid, file_stat.st_gid);
printf("\n");
}
int main() {
printf("=== mknodat 基础示例 ===\n\n");
// 1. 创建命名管道 (FIFO)
printf("1. 创建命名管道:\n");
if (mknodat(AT_FDCWD, "test_fifo", S_IFIFO | 0666, 0) == 0) {
printf(" ✓ 成功创建命名管道 test_fifo\n");
show_file_info("test_fifo");
} else {
if (errno == EACCES) {
printf(" ⚠ 权限不足,需要适当权限才能创建 FIFO\n");
} else {
printf(" ✗ 创建命名管道失败: %s\n", strerror(errno));
}
}
// 2. 创建普通文件(不推荐,应使用 open())
printf("2. 创建普通文件:\n");
if (mknodat(AT_FDCWD, "test_file", S_IFREG | 0644, 0) == 0) {
printf(" ✓ 成功创建普通文件 test_file\n");
show_file_info("test_file");
} else {
printf(" ✗ 创建普通文件失败: %s\n", strerror(errno));
}
// 3. 尝试创建字符设备(需要 root 权限)
printf("3. 创建字符设备 (需要 root 权限):\n");
dev_t null_dev = makedev(1, 3); // /dev/null 的设备号
if (mknodat(AT_FDCWD, "test_char_dev", S_IFCHR | 0666, null_dev) == 0) {
printf(" ✓ 成功创建字符设备 test_char_dev\n");
show_file_info("test_char_dev");
} else {
if (errno == EPERM) {
printf(" ⚠ 权限不足: 创建设备文件需要 root 权限\n");
} else {
printf(" ✗ 创建字符设备失败: %s\n", strerror(errno));
}
}
// 4. 尝试创建已存在的文件
printf("4. 尝试创建已存在的文件:\n");
if (mknodat(AT_FDCWD, "test_fifo", S_IFIFO | 0666, 0) == -1) {
if (errno == EEXIST) {
printf(" ✓ 正确: 文件已存在 (EEXIST)\n");
} else {
printf(" ✗ 意外错误: %s\n", strerror(errno));
}
}
// 清理创建的文件
printf("\n清理测试文件:\n");
if (unlink("test_fifo") == 0) {
printf(" ✓ 删除 test_fifo\n");
}
if (unlink("test_file") == 0) {
printf(" ✓ 删除 test_file\n");
}
if (access("test_char_dev", F_OK) == 0 && unlink("test_char_dev") == 0) {
printf(" ✓ 删除 test_char_dev\n");
}
return 0;
}
示例2:使用目录文件描述符 見出しへのリンク
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sysmacros.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
// 创建特殊文件并显示信息
int create_and_show_special_file(int dirfd, const char *pathname,
mode_t mode, dev_t dev, const char *description) {
printf("=== %s ===\n", description);
if (mknodat(dirfd, pathname, mode, dev) == 0) {
printf(" ✓ 成功创建: %s\n", pathname);
// 显示文件信息
struct stat file_stat;
if (fstatat(dirfd, pathname, &file_stat, 0) == 0) {
printf(" 类型: ");
switch (file_stat.st_mode & S_IFMT) {
case S_IFIFO: printf("命名管道"); break;
case S_IFCHR: printf("字符设备"); break;
case S_IFBLK: printf("块设备"); break;
case S_IFREG: printf("普通文件"); break;
default: printf("其他类型"); break;
}
printf("\n");
printf(" 权限: %o\n", file_stat.st_mode & 0777);
printf(" Inode: %ld\n", (long)file_stat.st_ino);
if (S_ISCHR(file_stat.st_mode) || S_ISBLK(file_stat.st_mode)) {
printf(" 设备号: %d,%d\n",
major(file_stat.st_rdev), minor(file_stat.st_rdev));
}
}
return 0;
} else {
printf(" ✗ 创建失败: %s\n", strerror(errno));
return -1;
}
}
int main() {
printf("=== mknodat 目录文件描述符示例 ===\n\n");
// 创建基础目录结构
printf("创建测试环境:\n");
if (mkdir("base_dir", 0755) == -1 && errno != EEXIST) {
perror("创建 base_dir 失败");
return 1;
}
printf(" ✓ 创建 base_dir\n");
// 打开目录获取文件描述符
int base_dirfd = open("base_dir", O_RDONLY);
if (base_dirfd == -1) {
perror("打开 base_dir 失败");
rmdir("base_dir");
return 1;
}
printf(" ✓ 打开 base_dir,fd=%d\n\n", base_dirfd);
// 1. 使用目录文件描述符创建相对路径文件
printf("1. 使用目录文件描述符创建相对路径文件:\n");
if (create_and_show_special_file(base_dirfd, "relative_fifo",
S_IFIFO | 0666, 0,
"在 base_dir 中创建 relative_fifo") == 0) {
// 显示目录内容
DIR *dir = opendir("base_dir");
if (dir) {
printf(" base_dir 内容:\n");
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
printf(" %s\n", entry->d_name);
}
}
closedir(dir);
}
printf("\n");
}
// 2. 创建多层嵌套目录中的特殊文件
printf("2. 创建嵌套目录中的特殊文件:\n");
if (mkdirat(base_dirfd, "subdir", 0755) == 0) {
printf(" ✓ 创建子目录 subdir\n");
// 在子目录中创建 FIFO
int subdir_fd = openat(base_dirfd, "subdir", O_RDONLY);
if (subdir_fd != -1) {
if (create_and_show_special_file(subdir_fd, "nested_fifo",
S_IFIFO | 0644, 0,
"在 subdir 中创建 nested_fifo") == 0) {
// 显示嵌套目录内容
DIR *subdir = opendir("base_dir/subdir");
if (subdir) {
printf(" subdir 内容:\n");
struct dirent *entry;
while ((entry = readdir(subdir)) != NULL) {
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
printf(" %s\n", entry->d_name);
}
}
closedir(subdir);
}
}
close(subdir_fd);
}
}
printf("\n");
// 3. 使用 AT_FDCWD 创建文件
printf("3. 使用 AT_FDCWD 创建文件:\n");
if (create_and_show_special_file(AT_FDCWD, "at_fdcwd_fifo",
S_IFIFO | 0666, 0,
"使用 AT_FDCWD 创建文件") == 0) {
show_file_info("at_fdcwd_fifo");
}
// 4. 使用绝对路径(忽略 dirfd)
printf("4. 使用绝对路径创建文件:\n");
char abs_path[512];
char *cwd = getcwd(NULL, 0);
if (cwd) {
snprintf(abs_path, sizeof(abs_path), "%s/absolute_fifo", cwd);
free(cwd);
if (create_and_show_special_file(base_dirfd, abs_path,
S_IFIFO | 0666, 0,
"使用绝对路径创建文件") == 0) {
show_file_info("absolute_fifo");
}
}
// 清理资源
printf("清理测试文件:\n");
close(base_dirfd);
// 递归删除目录
unlink("base_dir/subdir/nested_fifo");
rmdir("base_dir/subdir");
rmdir("base_dir");
unlink("at_fdcwd_fifo");
unlink("absolute_fifo");
printf(" ✓ 清理完成\n");
return 0;
}
示例3:完整的特殊文件管理工具 見出しへのリンク
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sysmacros.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>
#include <libgen.h>
// 全局配置结构
struct mknod_config {
int file_type; // 文件类型
mode_t file_mode; // 文件权限模式
int major; // 主设备号
int minor; // 次设备号
int verbose; // 详细输出模式
int ignore_exist; // 忽略已存在错误
char *base_dir; // 基础目录路径
};
// 创建特殊文件
int create_special_file(int base_dirfd, const char *pathname,
const struct mknod_config *config) {
mode_t mode = config->file_mode;
dev_t dev = 0;
// 设置文件类型
switch (config->file_type) {
case 'p': // FIFO
mode |= S_IFIFO;
break;
case 'c': // 字符设备
mode |= S_IFCHR;
dev = makedev(config->major, config->minor);
break;
case 'b': // 块设备
mode |= S_IFBLK;
dev = makedev(config->major, config->minor);
break;
case 'f': // 普通文件
mode |= S_IFREG;
break;
default:
fprintf(stderr, "未知文件类型: %c\n", config->file_type);
return -1;
}
// 创建特殊文件
int result = mknodat(base_dirfd, pathname, mode, dev);
if (result == 0) {
if (config->verbose) {
printf("创建文件: %s", pathname);
switch (config->file_type) {
case 'p': printf(" (FIFO)"); break;
case 'c': printf(" (字符设备 %d,%d)", config->major, config->minor); break;
case 'b': printf(" (块设备 %d,%d)", config->major, config->minor); break;
case 'f': printf(" (普通文件)"); break;
}
printf(" 权限 %o\n", config->file_mode);
}
} else {
if (errno == EEXIST) {
if (config->ignore_exist) {
if (config->verbose) {
printf("文件已存在: %s\n", pathname);
}
return 0; // 视为成功
} else {
fprintf(stderr, "文件已存在: %s\n", pathname);
return -1;
}
} else if (errno == EPERM) {
fprintf(stderr, "权限不足: 创建设备文件需要 root 权限\n");
return -1;
} else {
fprintf(stderr, "创建文件失败 '%s': %s\n", pathname, strerror(errno));
return -1;
}
}
return result;
}
// 显示文件信息
void show_file_details(int base_dirfd, const char *pathname) {
struct stat st;
if (fstatat(base_dirfd, pathname, &st, 0) == 0) {
printf("文件详细信息:\n");
printf(" 路径: %s\n", pathname);
printf(" 类型: ");
switch (st.st_mode & S_IFMT) {
case S_IFIFO: printf("命名管道 (FIFO)\n"); break;
case S_IFCHR: printf("字符设备\n"); break;
case S_IFBLK: printf("块设备\n"); break;
case S_IFREG: printf("普通文件\n"); break;
case S_IFDIR: printf("目录\n"); break;
case S_IFLNK: printf("符号链接\n"); break;
case S_IFSOCK: printf("套接字\n"); break;
default: printf("未知类型\n"); break;
}
printf(" 权限: %o\n", st.st_mode & 0777);
printf(" Inode: %ld\n", (long)st.st_ino);
printf(" 所有者: UID=%d, GID=%d\n", st.st_uid, st.st_gid);
if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
printf(" 设备号: %d,%d (主:%d, 次:%d)\n",
major(st.st_rdev), minor(st.st_rdev),
major(st.st_rdev), minor(st.st_rdev));
}
}
}
// 显示帮助信息
void show_help(const char *program_name) {
printf("用法: %s [选项] 文件...\n", program_name);
printf("\n选项:\n");
printf(" -t, --type=TYPE 文件类型 (p=FIFO, c=字符设备, b=块设备, f=普通文件)\n");
printf(" -m, --mode=MODE 设置文件权限模式\n");
printf(" --major=MAJOR 主设备号 (字符/块设备)\n");
printf(" --minor=MINOR 次设备号 (字符/块设备)\n");
printf(" -v, --verbose 显示详细信息\n");
printf(" -i, --ignore-exist 忽略已存在的文件\n");
printf(" -b, --base-dir=DIR 指定基础目录\n");
printf(" -h, --help 显示此帮助信息\n");
printf("\n示例:\n");
printf(" %s -t p pipe1 pipe2 # 创建命名管道\n", program_name);
printf(" %s -t c --major=1 --minor=3 null # 创建字符设备\n", program_name);
printf(" %s -t b --major=8 --minor=0 sda # 创建块设备\n", program_name);
printf(" %s -t f -m 644 regular_file # 创建普通文件\n", program_name);
printf(" %s -b /tmp -t p relative_pipe # 在指定目录创建\n", program_name);
}
int main(int argc, char *argv[]) {
struct mknod_config config = {
.file_type = 'p', // 默认创建 FIFO
.file_mode = 0666, // 默认权限
.major = 0,
.minor = 0,
.verbose = 0,
.ignore_exist = 0,
.base_dir = NULL
};
printf("=== 特殊文件创建工具 ===\n\n");
// 解析命令行参数
static struct option long_options[] = {
{"type", required_argument, 0, 't'},
{"mode", required_argument, 0, 'm'},
{"major", required_argument, 0, 1000},
{"minor", required_argument, 0, 1001},
{"verbose", no_argument, 0, 'v'},
{"ignore-exist", no_argument, 0, 'i'},
{"base-dir", required_argument, 0, 'b'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
int opt;
while ((opt = getopt_long(argc, argv, "t:m:vi:b:h", long_options, NULL)) != -1) {
switch (opt) {
case 't':
if (strlen(optarg) == 1) {
config.file_type = optarg[0];
} else {
fprintf(stderr, "文件类型应为单个字符\n");
return 1;
}
break;
case 'm': {
char *endptr;
config.file_mode = strtol(optarg, &endptr, 8);
if (*endptr != '\0') {
fprintf(stderr, "无效的权限模式: %s\n", optarg);
return 1;
}
break;
}
case 1000: // --major
config.major = atoi(optarg);
break;
case 1001: // --minor
config.minor = atoi(optarg);
break;
case 'v':
config.verbose = 1;
break;
case 'i':
config.ignore_exist = 1;
break;
case 'b':
config.base_dir = optarg;
break;
case 'h':
show_help(argv[0]);
return 0;
default:
fprintf(stderr, "使用 '%s --help' 查看帮助信息\n", argv[0]);
return 1;
}
}
// 检查文件参数
if (optind >= argc) {
fprintf(stderr, "错误: 请指定至少一个文件名\n");
fprintf(stderr, "使用 '%s --help' 查看帮助信息\n", argv[0]);
return 1;
}
// 验证参数
if ((config.file_type == 'c' || config.file_type == 'b') &&
(config.major == 0 && config.minor == 0)) {
fprintf(stderr, "创建设备文件需要指定主设备号和次设备号\n");
return 1;
}
// 打开基础目录
int base_dirfd = AT_FDCWD;
if (config.base_dir) {
base_dirfd = open(config.base_dir, O_RDONLY);
if (base_dirfd == -1) {
fprintf(stderr, "无法打开基础目录 '%s': %s\n",
config.base_dir, strerror(errno));
return 1;
}
if (config.verbose) {
printf("使用基础目录: %s (fd=%d)\n", config.base_dir, base_dirfd);
}
}
// 创建所有指定的文件
int success_count = 0;
int error_count = 0;
if (config.verbose) {
printf("配置信息:\n");
printf(" 文件类型: ");
switch (config.file_type) {
case 'p': printf("命名管道 (FIFO)\n"); break;
case 'c': printf("字符设备\n"); break;
case 'b': printf("块设备\n"); break;
case 'f': printf("普通文件\n"); break;
default: printf("未知\n"); break;
}
printf(" 权限模式: %o\n", config.file_mode);
if (config.file_type == 'c' || config.file_type == 'b') {
printf(" 设备号: %d,%d\n", config.major, config.minor);
}
printf(" 忽略已存在: %s\n", config.ignore_exist ? "是" : "否");
printf("\n");
}
for (int i = optind; i < argc; i++) {
const char *filename = argv[i];
if (create_special_file(base_dirfd, filename, &config) == 0) {
success_count++;
if (config.verbose) {
show_file_details(base_dirfd, filename);
printf("\n");
}
} else {
error_count++;
}
}
// 显示统计信息
printf("\n=== 操作统计 ===\n");
printf("成功: %d 个文件\n", success_count);
printf("失败: %d 个文件\n", error_count);
// 清理资源
if (config.base_dir && base_dirfd != AT_FDCWD) {
close(base_dirfd);
}
return (error_count > 0) ? 1 : 0;
}
编译和运行说明 見出しへのリンク
# 编译示例程序
gcc -o mknodat_example1 example1.c
gcc -o mknodat_example2 example2.c
gcc -o mknodat_example3 example3.c
# 运行示例
./mknodat_example1
./mknodat_example2
./mknodat_example3 --help
./mknodat_example3 -t p test_pipe
./mknodat_example3 -t f -m 644 test_file
sudo ./mknodat_example3 -t c --major=1 --minor=3 test_char_dev
系统要求检查 見出しへのリンク
# 检查系统调用支持
grep -w mknodat /usr/include/asm/unistd_64.h
# 检查设备文件权限
ls -l /dev/null /dev/zero
# 检查当前用户权限
id
重要注意事项 見出しへのリンク
- 权限要求: 创建设备文件通常需要 root 权限
- 路径解析: 相对路径相对于 dirfd 解析
- 权限掩码: 实际权限受 umask 影响
- 设备号: 字符设备和块设备需要正确的设备号
- 错误处理: 始终检查返回值和 errno
实际应用场景 見出しへのリンク
- 系统管理: 创建设备文件和特殊文件
- 进程间通信: 创建命名管道
- 设备驱动: 开发和测试设备文件
- 容器技术: 在容器中创建特殊文件
- 系统初始化: 系统启动时创建必要的特殊文件
与相关函数的区别 見出しへのリンク
// mknod - 传统的特殊文件创建
mknod("path", mode, dev); // 相对于当前目录
// mknodat - 增强版特殊文件创建
mknodat(AT_FDCWD, "path", mode, dev); // 相对于当前目录
mknodat(dirfd, "relative_path", mode, dev); // 相对于指定目录
mknodat(dirfd, "/absolute_path", mode, dev); // 绝对路径,忽略 dirfd
// 其他相关函数
mkfifo("path", mode); // 创建命名管道
open("path", O_CREAT, mode); // 创建普通文件
最佳实践 見出しへのリンク
// 安全的特殊文件创建函数
int safe_mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev) {
// 验证参数
if (!pathname) {
errno = EINVAL;
return -1;
}
// 检查文件类型
mode_t file_type = mode & S_IFMT;
if (file_type != S_IFIFO && file_type != S_IFCHR &&
file_type != S_IFBLK && file_type != S_IFREG) {
errno = EINVAL;
return -1;
}
// 检查设备文件权限
if ((file_type == S_IFCHR || file_type == S_IFBLK) && geteuid() != 0) {
errno = EPERM;
return -1;
}
// 创建特殊文件
int result = mknodat(dirfd, pathname, mode, dev);
// 处理常见情况
if (result == -1) {
switch (errno) {
case EEXIST:
// 检查文件类型是否匹配
struct stat st;
if (fstatat(dirfd, pathname, &st, 0) == 0) {
if ((st.st_mode & S_IFMT) == file_type) {
return 0; // 文件已存在且类型匹配,视为成功
}
}
break;
}
}
return result;
}
// 创建设备文件的辅助函数
int create_device_file(int dirfd, const char *pathname,
int is_char_device, int major, int minor, mode_t mode) {
mode_t file_type = is_char_device ? S_IFCHR : S_IFBLK;
dev_t dev = makedev(major, minor);
return mknodat(dirfd, pathname, file_type | mode, dev);
}
这些示例展示了 mknodat
函数的各种使用方法,从基础的特殊文件创建到完整的管理工具,帮助你全面掌握 Linux 系统中的特殊文件创建机制。