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/。

