IOCTL_NS - Linux手册页

时间:2019-08-20 17:58:54  来源:igfitidea点击:

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);
}

另外参见

fstat(2),ioctl(2),proc(5),名称空间(7)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/