Use of UTS namespaces requires a kernel that is configured with the
.B CONFIG_UTS_NS
option.
+.\"
+.\" ============================================================
+.\"
+.SS Introspecting namespace relationships
+Since Linux 4.9,
+.\" commit bcac25a58bfc6bd79191ac5d7afb49bea96da8c9
+.\" commit 6786741dbf99e44fb0c0ed85a37582b8a26f1c3b
+.\" commit a7306ed8d94af729ecef8b6e37506a1c6fc14788
+.\" commit 6ad92bf63e45f97e306da48cd1cbce6e4fef1e5d
+two
+.BR ioctl (2)
+operations are provided to allow introspection of namespace relationships
+(see
+.BR user_namespaces (7)
+and
+.BR pid_namespaces (7)).
+The form of the calls is:
+
+ ioctl(fd, request);
+
+In each case,
+.I fd
+refers to a
+.IR /proc/[pid]/ns/*
+file.
+.TP
+.BR NS_GET_USERNS
+Returns a file descriptor that refers to the owning user namespace
+for the namespace referred to by
+.IR fd .
+.TP
+.BR NS_GET_PARENT
+Returns a file descriptor that refers to the parent namespace of
+the namespace referred to by
+.IR fd .
+This operation is valid only for hierarchical namespaces
+(i.e., PID and user namespaces).
+For user namespaces,
+.BR NS_GET_PARENT
+is synonymous with
+.BR NS_GET_USERNS .
+.PP
+In each case, the returned file descriptor is opened with
+.BR O_RDONLY
+and
+.BR O_CLOEXEC
+(close-on-exec).
+.PP
+By applying
+.BR fstat (2)
+to the returned file descriptor, one obtains a
+.I stat
+structure whose
+.I st_ino
+(inode number) field identifies the owning/parent namespace.
+This inode number can be matched with the inode number of another
+.IR /proc/[pid]/ns/{pid,user}
+file to determine whether that is the owning/parent namespace.
+
+Either of these
+.BR ioctl (2)
+operations can fail with the following error:
+.TP
+.B EPERM
+The requested namespace is outside of the caller's namespace scope.
+This error can occur if, for example, the owning user namespace is an
+ancestor of the caller's current user namespace.
+It can also occur on attempts to obtain the parent of the initial
+user or PID namespace.
+.PP
+Additionally, the
+.B NS_GET_PARENT
+operation can fail with the following error:
+.TP
+.B EINVAL
+.I fd
+refers to a nonhierarchical namespace.
+.PP
+See the EXAMPLE section for an example of the use of these operations.
.SH CONFORMING TO
Namespaces are a Linux-specific feature.
.SH EXAMPLE
-See
+For one example,
.BR user_namespaces (7).
+
+The example shown below uses the
+.BR ioctl (2)
+operations described above to perform simple
+introspection of namespace relationships.
+The following shell sessions show various examples of the use
+of this program.
+
+Trying to get the parent of the initial user namespace fails,
+for the reasons explained earlier:
+
+.nf
+.in +4n
+$ \fB./ns_introspect /proc/self/ns/user p\fP
+The parent namespace is outside your namespace scope
+.in
+.fi
+
+Create a process running
+.BR sleep (1)
+that resides in new user and UTS namespaces,
+and show that new UTS namespace is associated with the new user namespace:
+
+.nf
+.in +4n
+$ \fBunshare \-Uu sleep 1000 &\fP
+[1] 23235
+$ \fB./ns_introspect /proc/23235/ns/uts\fP
+Inode number of owning user namespace is: 4026532448
+$ \fBreadlink /proc/23235/ns/user \fP
+user:[4026532448]
+.in
+.fi
+
+Then show that the parent of the new user namespace in the preceding
+example is the initial user namespace:
+
+.nf
+.in +4n
+$ \fBreadlink /proc/self/ns/user\fP
+user:[4026531837]
+$ \fB./ns_introspect /proc/23235/ns/user\fP
+Inode number of owning user namespace is: 4026531837
+.in
+.fi
+
+Start a shell in a new user namespace, and show that from within
+this shell, the parent user namespace can't be discovered.
+Similarly, the UTS namespace
+(which is associated with the initial user namespace)
+can't be discovered.
+
+.nf
+.in +4n
+$ PS1="sh2$ " unshare \-U bash
+sh2$ \fB./ns_introspect /proc/self/ns/user p\fP
+The parent namespace is outside your namespace scope
+sh2$ \fB./ns_introspect /proc/self/ns/uts u\fP
+The owning user namespace is outside your namespace scope
+.in
+.fi
+.SS Program source
+\&
+.nf
+/* ns_introspect.c
+
+ Licensed under GNU General Public License v2 or later
+*/
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <errno.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 "
+ "\(aqp\(aq nor \(aqu\(aq is specified,\\n"
+ "NS_GET_USERNS is the default.\\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Obtain a file descriptor for the \(aqns\(aq 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], \(aqu\(aq)) {
+ 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("Inode number of owning user namespace is: %ld\\n",
+ (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], \(aqp\(aq)) {
+ parent_fd = ioctl(fd, NS_GET_PARENT);
+
+ if (parent_fd == \-1) {
+ if (errno == EINVAL)
+ printf("Can\(aq 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("Inode number of parent namespace is: %ld\\n",
+ (long) sb.st_ino);
+
+ close(parent_fd);
+ }
+
+ exit(EXIT_SUCCESS);
+}
+.fi
.SH SEE ALSO
.BR nsenter (1),
.BR readlink (1),