From 98f4c2e4de4a78d31117f703fb9b35e4e220e34c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 26 Jan 2012 15:28:00 +0400 Subject: [PATCH] ns: Support UTS namespace Only two fields are modifiable -- hostname and domainname. So read them on dump and write on restore. File format is simple -- u32 magic u32 length of nodename u8[] nodename string u32 length of domainname u8[] domainname string For OpenVZ we can write the release at the end, but this is later. Signed-off-by: Pavel Emelyanov Signed-off-by: Cyrill Gorcunov --- cr-restore.c | 2 +- cr-show.c | 3 + crtools.c | 6 ++ include/crtools.h | 4 ++ include/image.h | 1 + include/namespaces.h | 1 + include/syscall.h | 4 ++ namespaces.c | 154 ++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 173 insertions(+), 2 deletions(-) diff --git a/cr-restore.c b/cr-restore.c index 2529ff17f..4a08da315 100644 --- a/cr-restore.c +++ b/cr-restore.c @@ -1435,7 +1435,7 @@ static int restore_root_task(int fd, struct cr_options *opts) */ if (opts->with_namespaces) - ns_clone_flags = 0; + ns_clone_flags = CLONE_NEWUTS; else ns_clone_flags = 0; diff --git a/cr-show.c b/cr-show.c index 456f814f6..c35a4a202 100644 --- a/cr-show.c +++ b/cr-show.c @@ -474,6 +474,9 @@ static int cr_parse_file(struct cr_options *opts) case ITIMERS_MAGIC: show_itimers(fd); break; + case UTSNS_MAGIC: + show_utsns(fd); + break; default: pr_err("Unknown magic %x on %s\n", magic, opts->show_dump_file); goto err; diff --git a/crtools.c b/crtools.c index 815413649..964bc1fd7 100644 --- a/crtools.c +++ b/crtools.c @@ -97,6 +97,12 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = { .fmt = FMT_FNAME_ITIMERS, .magic = ITIMERS_MAGIC, }, + + /* UTS namespace */ + [CR_FD_UTSNS] = { + .fmt = FMT_FNAME_UTSNS, + .magic = UTSNS_MAGIC, + }, }; static struct cr_fdset *alloc_cr_fdset(void) diff --git a/include/crtools.h b/include/crtools.h index 4028d8f24..75e5d10f2 100644 --- a/include/crtools.h +++ b/include/crtools.h @@ -35,6 +35,7 @@ enum { */ CR_FD_PSTREE, + CR_FD_UTSNS, CR_FD_MAX }; @@ -75,6 +76,7 @@ extern struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX]; #define FMT_FNAME_UNIXSK "unixsk-%d.img" #define FMT_FNAME_INETSK "inetsk-%d.img" #define FMT_FNAME_ITIMERS "itimers-%d.img" +#define FMT_FNAME_UTSNS "utsns-%d.img" extern int get_image_path(char *path, int size, const char *fmt, int pid); @@ -103,6 +105,8 @@ struct cr_fdset { CR_FD_DESC_USE(CR_FD_UNIXSK) |\ CR_FD_DESC_USE(CR_FD_INETSK) |\ CR_FD_DESC_USE(CR_FD_ITIMERS) ) +#define CR_FD_DESC_NS (\ + CR_FD_DESC_USE(CR_FD_UTSNS) ) #define CR_FD_DESC_NONE (0) int cr_dump_tasks(pid_t pid, struct cr_options *opts); diff --git a/include/image.h b/include/image.h index e683619b8..1d563120b 100644 --- a/include/image.h +++ b/include/image.h @@ -15,6 +15,7 @@ #define UNIXSK_MAGIC 0x07070707 #define INETSK_MAGIC 0x08080808 #define ITIMERS_MAGIC 0x99009900 +#define UTSNS_MAGIC 0xA00A0AA0 #define FDINFO_FD 1 #define FDINFO_MAP 2 diff --git a/include/namespaces.h b/include/namespaces.h index ee4aad60c..518855f60 100644 --- a/include/namespaces.h +++ b/include/namespaces.h @@ -3,4 +3,5 @@ int dump_namespaces(int pid); int prepare_namespace(int pid, unsigned long clone_flags); int try_show_namespaces(int pid); +void show_utsns(int fd); #endif diff --git a/include/syscall.h b/include/syscall.h index 382b31d02..15657e0d3 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -313,6 +313,10 @@ static long always_inline sys_setns(int fd, int nstype) return syscall2(__NR_setns, (long)fd, (long)nstype); } +#ifndef CLONE_NEWUTS +#define CLONE_NEWUTS 0x04000000 +#endif + #define setns sys_setns #else /* CONFIG_X86_64 */ diff --git a/namespaces.c b/namespaces.c index fa1969c94..6370bc287 100644 --- a/namespaces.c +++ b/namespaces.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "util.h" #include "crtools.h" #include "syscall.h" @@ -27,9 +28,57 @@ out: return ret; } +static int dump_uts_string(int fd, char *str) +{ + int ret; + u32 len; + + len = strlen(str); + ret = write_img(fd, &len); + if (ret == 0) + ret = write_img_buf(fd, str, len); + + return ret; +} + +static int dump_uts_ns(int ns_pid, struct cr_fdset *fdset) +{ + int fd, ret; + struct utsname ubuf; + + ret = switch_ns(ns_pid, CLONE_NEWUTS, "uts"); + if (ret < 0) + return ret; + + ret = uname(&ubuf); + if (ret < 0) { + pr_perror("Error calling uname\n"); + return ret; + } + + fd = fdset->fds[CR_FD_UTSNS]; + + ret = dump_uts_string(fd, ubuf.nodename); + if (!ret) + ret = dump_uts_string(fd, ubuf.domainname); + + return ret; +} + static int do_dump_namespaces(int ns_pid) { - return 0; + struct cr_fdset *fdset; + int ret; + + fdset = cr_fdset_open(ns_pid, CR_FD_DESC_NS, NULL); + if (fdset == NULL) + return -1; + + ret = dump_uts_ns(ns_pid, fdset); + + close_cr_fdset(&fdset); + return ret; + } int dump_namespaces(int ns_pid) @@ -75,6 +124,67 @@ int dump_namespaces(int ns_pid) return 0; } +static int prepare_uts_str(int fd, char *n) +{ + int ret; + u32 len; + char str[65], path[128]; + + ret = read_img(fd, &len); + if (ret > 0) { + if (len >= 65) { + pr_err("Corrupted %s\n", n); + return -1; + } + + ret = read_img_buf(fd, str, len); + if (ret < 0) + return -1; + + str[len] = '\0'; + + snprintf(path, sizeof(path), + "/proc/sys/kernel/%s", n); + fd = open(path, O_WRONLY); + if (fd < 0) { + pr_perror("Can't open %s\n", path); + return -1; + } + + pr_info("Restoging %s to [%s]\n", n, str); + + ret = write(fd, str, len); + close(fd); + if (ret != len) { + pr_perror("Can't write %s to %s\n", + str, path); + return -1; + } + + ret = 0; + } + + return ret; +} + +static int prepare_utsns(int pid) +{ + int fd, ret; + u32 len; + char str[65]; + + fd = open_image_ro(CR_FD_UTSNS, pid); + if (fd < 0) + return -1; + + ret = prepare_uts_str(fd, "hostname"); + if (!ret) + ret = prepare_uts_str(fd, "domainname"); + + close(fd); + return ret; +} + int prepare_namespace(int pid, unsigned long clone_flags) { int ret = 0; @@ -82,10 +192,52 @@ int prepare_namespace(int pid, unsigned long clone_flags) pr_info("Restoring namespaces %d flags %lx\n", pid, clone_flags); + if (clone_flags & CLONE_NEWUTS) + ret = prepare_utsns(pid); + return ret; } +static void show_uts_string(int fd, char *n) +{ + int ret; + u32 len; + char str[65]; + + ret = read_img(fd, &len); + if (ret > 0) { + if (len >= 65) { + pr_err("Corrupted hostname\n"); + return; + } + + ret = read_img_buf(fd, str, len); + if (ret < 0) + return; + + str[len] = '\0'; + pr_info("%s: [%s]\n", n, str); + } +} + +void show_utsns(int fd) +{ + pr_img_head(CR_FD_UTSNS); + show_uts_string(fd, "hostname"); + show_uts_string(fd, "domainname"); + pr_img_tail(CR_FD_UTSNS); +} + int try_show_namespaces(int ns_pid) { + struct cr_fdset *fdset; + + fdset = prep_cr_fdset_for_restore(ns_pid, CR_FD_DESC_NS); + if (!fdset) + return -1; + + show_utsns(fdset->fds[CR_FD_UTSNS]); + + close_cr_fdset(&fdset); return 0; }