ホスト名とsetns
本内容は、SETNSについてです。
newuts.cは、CLONE_NEWUTSで、親プロセスと異なるネームスペースの子プロセスを作成し、この子プロセスにsethostname()でホスト名(コマンド引数)を設定する事で、デフォルトの親プロセスのホスト名(localhost.localdomain)と子プロセスのホスト名(babakaka)のホスト名を有する環境となります。
シェルから起動されたプロセスは、ネームスペースの変更がない限り、親シェルのネームスペースのlocalhost.localdomainを継承しますが、このシェル下でbabakakaのプロセスのネームスペースをsetns()で更新後、execしたbashは、localhost.localdomaiでなくbabakakaとなります。
newuts.c
setns.c
newuts.cは、CLONE_NEWUTSで、親プロセスと異なるネームスペースの子プロセスを作成し、この子プロセスにsethostname()でホスト名(コマンド引数)を設定する事で、デフォルトの親プロセスのホスト名(localhost.localdomain)と子プロセスのホスト名(babakaka)のホスト名を有する環境となります。
シェルから起動されたプロセスは、ネームスペースの変更がない限り、親シェルのネームスペースのlocalhost.localdomainを継承しますが、このシェル下でbabakakaのプロセスのネームスペースをsetns()で更新後、execしたbashは、localhost.localdomaiでなくbabakakaとなります。
newuts.c
#define _GNU_SOURCE #include <sys/wait.h> #include <sys/utsname.h> #include <sched.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) static int childFunc(void *arg) { struct utsname uts; if (sethostname(arg, strlen(arg)) == -1) errExit("sethostname"); if (uname(&uts) == -1) errExit("uname"); printf("uts.nodename in child: %s\n", uts.nodename); sleep(200); return 0; } #define STACK_SIZE (1024 * 1024) /* clone される子プロセスのスタックサイズ */ int main(int argc, char *argv[]) { char *stack; char *stackTop; pid_t pid; struct utsname uts; if (argc < 2) { fprintf(stderr, "Usage: %s <child-hostname>\n", argv[0]); exit(EXIT_SUCCESS); } stack = malloc(STACK_SIZE); if (stack == NULL) errExit("malloc"); stackTop = stack + STACK_SIZE; pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]); if (pid == -1) errExit("clone"); printf("clone() returned %ld\n", (long) pid); sleep(1); if (uname(&uts) == -1) errExit("uname"); printf("uts.nodename in parent: %s\n", uts.nodename); if (waitpid(pid, NULL, 0) == -1) errExit("waitpid"); printf("child has terminated\n"); exit(EXIT_SUCCESS); }
setns.c
#define _GNU_SOURCE #include <fcntl.h> #include <sched.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) int main(int argc, char *argv[]) { int fd; if (argc < 3) { fprintf(stderr, "%s /proc/PID/ns/FILE cmd args...\n", argv[0]); exit(EXIT_FAILURE); } fd = open(argv[1], O_RDONLY); /* 名前空間のディスクリプターを取得 */ if (fd == -1) errExit("open"); if (setns(fd, 0) == -1) /* 名前空間に参加 */ errExit("setns"); execvp(argv[2], &argv[2]); /* 名前空間内でコマンドを実行 */ errExit("execvp"); }
実効結果
子プロセスIDは2270でホスト名はbabakakaで、シェルとする親プロセスIDは2269でホスト名はlocalhost.localdomainです。[root@localhost test]# ./newuts babakaka & [1] 2269 [root@localhost test]# clone() returned 2270 uts.nodename in child: babakaka uts.nodename in parent: localhost.localdomain [root@localhost test]# uname -n localhost.localdomain [root@localhost test]# ./setns /proc/2270/ns/uts /bin/bash [root@babakaka test]# uname -n babakaka [root@localhost test]# ./setns /proc/2269/ns/uts /bin/bash [root@babakaka test]# uname -n localhost.localdomain [root@localhost test]# exit exit [root@babakaka test]# uname -n babakaka [root@babakaka test]# exit exit [root@localhost test]# uname -n localhost.localdomain