IOCTL_NS - Linux手册页
Linux程序员手册 第2部分
更新日期: 2020-06-09
名称
ioctl_ns-Linux名称空间的ioctl()操作
说明
Discovering namespace relationships
提供了以下ioctl(2)操作以允许发现名称空间关系(请参阅user_namespaces(7)和pid_namespaces(7))。调用的形式为:
new_fd = ioctl(fd, request);
在每种情况下,fd均指/ proc / [pid] / ns / *文件。两项操作均成功返回一个新的文件描述符。
- NS_GET_USERNS(since Linux 4.9)
- 返回一个文件描述符,该文件描述符引用fd引用的名称空间的所属用户名称空间。
- NS_GET_PARENT(since Linux 4.9)
- 返回一个文件描述符,该文件描述符引用fd引用的名称空间的父名称空间。此操作仅对分层名称空间(即PID和用户名称空间)有效。对于用户名称空间,NS_GET_PARENT与NS_GET_USERNS是同义词。
这些操作返回的新文件描述符使用O_RDONLY和O_CLOEXEC(close-on-exec;请参阅fcntl(2))标志打开。
通过将fstat(2)应用于返回的文件描述符,可以获得一个stat结构,其st_dev(驻留设备)和st_ino(inode编号)字段共同标识拥有/父命名空间。可以将此索引节点编号与另一个/ proc / [pid] / ns / {pid,user}文件的索引节点编号相匹配,以确定它是否是拥有/父命名空间。
这些ioctl(2)操作中的任何一个都可能失败,并出现以下错误:
- EPERM
- 请求的名称空间超出了调用者的名称空间范围。例如,如果拥有的用户名称空间是调用者当前用户名称空间的祖先,则会发生此错误。尝试获取初始用户或PID名称空间的父代时,也可能发生这种情况。
- ENOTTY
- 此内核版本不支持该操作。
此外,NS_GET_PARENT操作可能因以下错误而失败:
- EINVAL
- fd指的是非分层名称空间。
有关使用这些操作的示例,请参见示例部分。
Discovering the namespace type
NS_GET_NSTYPE操作(从Linux 4.11开始可用)可用于发现文件描述符fd所引用的名称空间的类型:
nstype = ioctl(fd, NS_GET_NSTYPE);
fd指的是/ proc / [pid] / ns / *文件。
返回值是CLONE_NEW *值之一,可以将其指定给clone(2)或unshare(2)以便创建名称空间。
Discovering the owner of a user namespace
NS_GET_OWNER_UID操作(从Linux 4.11开始可用)可用于发现用户名称空间的所有者用户ID(即,创建用户名称空间的进程的有效用户ID)。呼叫的形式为:
uid_t uid; ioctl(fd, NS_GET_OWNER_UID, &uid);
fd指的是/ proc / [pid] / ns / user文件。
所有者用户ID在第三个参数所指向的uid_t中返回。
此操作可能失败,并出现以下错误:
- EINVAL
- fd不引用用户名称空间。
错误说明
上述任何ioctl()操作都可以返回以下错误:
- ENOTTY
- fd不引用/ proc / [pid] / ns / *文件。
遵循规范
本页上描述的命名空间和操作是特定于Linux的。
示例
下面显示的示例使用上述ioctl(2)操作执行名称空间关系的简单发现。以下shell会话显示了使用此程序的各种示例。
尝试获取初始用户名称空间的父级失败,因为它没有父级:
$ ./ns_show /proc/self/ns/user p The parent namespace is outside your namespace scope
创建一个运行sleep(1)的进程,该进程驻留在新的用户和UTS命名空间中,并显示新的UTS命名空间与新的用户命名空间相关联:
$ unshare -Uu sleep 1000 & [1] 23235 $ ./ns_show /proc/23235/ns/uts u Device/Inode of owning user namespace is: [0,3] / 4026532448 $ readlink /proc/23235/ns/user user:[4026532448]
然后显示前面示例中新用户名称空间的父级是初始用户名称空间:
$ readlink /proc/self/ns/user user:[4026531837] $ ./ns_show /proc/23235/ns/user p Device/Inode of parent namespace is: [0,3] / 4026531837
在新的用户名称空间中启动外壳程序,并显示从该外壳程序中找不到父用户名称空间。同样,无法发现UTS名称空间(与初始用户名称空间相关联)。
$ PS1="sh2$ " unshare -U bash sh2$ ./ns_show /proc/self/ns/user p The parent namespace is outside your namespace scope sh2$ ./ns_show /proc/self/ns/uts u The owning user namespace is outside your namespace scope
Program source
/* ns_show.c Licensed under the GNU General Public License v2 or later. */ #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <string.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <errno.h> #include <sys/sysmacros.h> #ifndef NS_GET_USERNS #define NSIO 0xb7 #define NS_GET_USERNS _IO(NSIO, 0x1) #define NS_GET_PARENT _IO(NSIO, 0x2) #endif int main(int argc, char *argv[]) { int fd, userns_fd, parent_fd; struct stat sb; if (argc < 2) { fprintf(stderr, "Usage: %s /proc/[pid]/ns/[file] [p|u]\n", argv[0]); fprintf(stderr, "\nDisplay the result of one or both " "of NS_GET_USERNS (u) or NS_GET_PARENT (p)\n" "for the specified /proc/[pid]/ns/[file]. If neither " "aqpaq nor aquaq is specified,\n" "NS_GET_USERNS is the default.\n"); exit(EXIT_FAILURE); } /* Obtain a file descriptor for the aqnsaq file specified in argv[1] */ fd = open(argv[1], O_RDONLY); if (fd == -1) { perror("open"); exit(EXIT_FAILURE); } /* Obtain a file descriptor for the owning user namespace and then obtain and display the inode number of that namespace */ if (argc < 3 || strchr(argv[2], aquaq)) { userns_fd = ioctl(fd, NS_GET_USERNS); if (userns_fd == -1) { if (errno == EPERM) printf("The owning user namespace is outside " "your namespace scope\n"); else perror("ioctl-NS_GET_USERNS"); exit(EXIT_FAILURE); } if (fstat(userns_fd, &sb) == -1) { perror("fstat-userns"); exit(EXIT_FAILURE); } printf("Device/Inode of owning user namespace is: " "[%lx,%lx] / %ld\n", (long) major(sb.st_dev), (long) minor(sb.st_dev), (long) sb.st_ino); close(userns_fd); } /* Obtain a file descriptor for the parent namespace and then obtain and display the inode number of that namespace */ if (argc > 2 && strchr(argv[2], aqpaq)) { parent_fd = ioctl(fd, NS_GET_PARENT); if (parent_fd == -1) { if (errno == EINVAL) printf("Canaq get parent namespace of a " "nonhierarchical namespace\n"); else if (errno == EPERM) printf("The parent namespace is outside " "your namespace scope\n"); else perror("ioctl-NS_GET_PARENT"); exit(EXIT_FAILURE); } if (fstat(parent_fd, &sb) == -1) { perror("fstat-parentns"); exit(EXIT_FAILURE); } printf("Device/Inode of parent namespace is: [%lx,%lx] / %ld\n", (long) major(sb.st_dev), (long) minor(sb.st_dev), (long) sb.st_ino); close(parent_fd); } exit(EXIT_SUCCESS); }
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。