X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fnspawn%2Fnspawn.c;h=646c6c02f387063e03e91c664ada0abe6331b27d;hp=f0e7b0619fd6eb44958e8f4c0605e4f0fba86f48;hb=82adf6af7c72b852449346835f33184a841b4796;hpb=486e99a387adec15738c2822c2df5c813955f433 diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index f0e7b0619..646c6c02f 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -41,6 +41,9 @@ #include #include #include +#ifdef HAVE_SELINUX +#include +#endif #include "sd-daemon.h" #include "sd-bus.h" @@ -77,6 +80,8 @@ static char *arg_directory = NULL; static char *arg_user = NULL; static sd_id128_t arg_uuid = {}; static char *arg_machine = NULL; +static char *arg_selinux_context = NULL; +static char *arg_selinux_apifs_context = NULL; static const char *arg_slice = NULL; static bool arg_private_network = false; static bool arg_read_only = false; @@ -112,30 +117,38 @@ static uint64_t arg_retain = static char **arg_bind = NULL; static char **arg_bind_ro = NULL; static char **arg_setenv = NULL; +static bool arg_quiet = false; static int help(void) { printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n" "Spawn a minimal namespace container for debugging, testing and building.\n\n" - " -h --help Show this help\n" - " --version Print version string\n" - " -D --directory=NAME Root directory for the container\n" - " -b --boot Boot up full system (i.e. invoke init)\n" - " -u --user=USER Run the command under specified user or uid\n" - " --uuid=UUID Set a specific machine UUID for the container\n" - " -M --machine=NAME Set the machine name for the container\n" - " -S --slice=SLICE Place the container in the specified slice\n" - " --private-network Disable network in container\n" - " --read-only Mount the root directory read-only\n" - " --capability=CAP In addition to the default, retain specified\n" - " capability\n" - " --drop-capability=CAP Drop the specified capability from the default set\n" - " --link-journal=MODE Link up guest journal, one of no, auto, guest, host\n" - " -j Equivalent to --link-journal=host\n" - " --bind=PATH[:PATH] Bind mount a file or directory from the host into\n" - " the container\n" - " --bind-ro=PATH[:PATH] Similar, but creates a read-only bind mount\n" - " --setenv=NAME=VALUE Pass an environment variable to PID 1\n", + " -h --help Show this help\n" + " --version Print version string\n" + " -D --directory=NAME Root directory for the container\n" + " -b --boot Boot up full system (i.e. invoke init)\n" + " -u --user=USER Run the command under specified user or uid\n" + " --uuid=UUID Set a specific machine UUID for the container\n" + " -M --machine=NAME Set the machine name for the container\n" + " -S --slice=SLICE Place the container in the specified slice\n" + " -Z --selinux-context=SECLABEL\n" + " Set the SELinux security context to be used by\n" + " processes in the container\n" + " -L --selinux-apifs-context=SECLABEL\n" + " Set the SELinux security context to be used by\n" + " API/tmpfs file systems in the container\n" + " --private-network Disable network in container\n" + " --read-only Mount the root directory read-only\n" + " --capability=CAP In addition to the default, retain specified\n" + " capability\n" + " --drop-capability=CAP Drop the specified capability from the default set\n" + " --link-journal=MODE Link up guest journal, one of no, auto, guest, host\n" + " -j Equivalent to --link-journal=host\n" + " --bind=PATH[:PATH] Bind mount a file or directory from the host into\n" + " the container\n" + " --bind-ro=PATH[:PATH] Similar, but creates a read-only bind mount\n" + " --setenv=NAME=VALUE Pass an environment variable to PID 1\n" + " -q --quiet Do not show status information\n", program_invocation_short_name); return 0; @@ -157,22 +170,25 @@ static int parse_argv(int argc, char *argv[]) { }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "directory", required_argument, NULL, 'D' }, - { "user", required_argument, NULL, 'u' }, - { "private-network", no_argument, NULL, ARG_PRIVATE_NETWORK }, - { "boot", no_argument, NULL, 'b' }, - { "uuid", required_argument, NULL, ARG_UUID }, - { "read-only", no_argument, NULL, ARG_READ_ONLY }, - { "capability", required_argument, NULL, ARG_CAPABILITY }, - { "drop-capability", required_argument, NULL, ARG_DROP_CAPABILITY }, - { "link-journal", required_argument, NULL, ARG_LINK_JOURNAL }, - { "bind", required_argument, NULL, ARG_BIND }, - { "bind-ro", required_argument, NULL, ARG_BIND_RO }, - { "machine", required_argument, NULL, 'M' }, - { "slice", required_argument, NULL, 'S' }, - { "setenv", required_argument, NULL, ARG_SETENV }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "directory", required_argument, NULL, 'D' }, + { "user", required_argument, NULL, 'u' }, + { "private-network", no_argument, NULL, ARG_PRIVATE_NETWORK }, + { "boot", no_argument, NULL, 'b' }, + { "uuid", required_argument, NULL, ARG_UUID }, + { "read-only", no_argument, NULL, ARG_READ_ONLY }, + { "capability", required_argument, NULL, ARG_CAPABILITY }, + { "drop-capability", required_argument, NULL, ARG_DROP_CAPABILITY }, + { "link-journal", required_argument, NULL, ARG_LINK_JOURNAL }, + { "bind", required_argument, NULL, ARG_BIND }, + { "bind-ro", required_argument, NULL, ARG_BIND_RO }, + { "machine", required_argument, NULL, 'M' }, + { "slice", required_argument, NULL, 'S' }, + { "setenv", required_argument, NULL, ARG_SETENV }, + { "selinux-context", required_argument, NULL, 'Z' }, + { "selinux-apifs-context", required_argument, NULL, 'L' }, + { "quiet", no_argument, NULL, 'q' }, {} }; @@ -181,7 +197,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "+hD:u:bM:jS:", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "+hD:u:bL:M:jS:Z:q", options, NULL)) >= 0) { switch (c) { @@ -247,6 +263,14 @@ static int parse_argv(int argc, char *argv[]) { break; + case 'Z': + arg_selinux_context = optarg; + break; + + case 'L': + arg_selinux_apifs_context = optarg; + break; + case ARG_READ_ONLY: arg_read_only = true; break; @@ -354,6 +378,10 @@ static int parse_argv(int argc, char *argv[]) { break; } + case 'q': + arg_quiet = true; + break; + case '?': return -EINVAL; @@ -396,6 +424,10 @@ static int mount_all(const char *dest) { for (k = 0; k < ELEMENTSOF(mount_table); k++) { _cleanup_free_ char *where = NULL; +#ifdef HAVE_SELINUX + _cleanup_free_ char *options = NULL; +#endif + const char *o; int t; where = strjoin(dest, "/", mount_table[k].where, NULL); @@ -418,11 +450,24 @@ static int mount_all(const char *dest) { mkdir_p(where, 0755); +#ifdef HAVE_SELINUX + if (arg_selinux_apifs_context && + (streq_ptr(mount_table[k].what, "tmpfs") || streq_ptr(mount_table[k].what, "devpts"))) { + options = strjoin(mount_table[k].options, ",context=\"", arg_selinux_apifs_context, "\"", NULL); + if (!options) + return log_oom(); + + o = options; + } else +#endif + o = mount_table[k].options; + + if (mount(mount_table[k].what, where, mount_table[k].type, mount_table[k].flags, - mount_table[k].options) < 0 && + o) < 0 && mount_table[k].fatal) { log_error("mount(%s) failed: %m", where); @@ -990,7 +1035,7 @@ static int register_machine(pid_t pid) { _cleanup_bus_unref_ sd_bus *bus = NULL; int r; - r = sd_bus_open_system(&bus); + r = sd_bus_default_system(&bus); if (r < 0) { log_error("Failed to open system bus: %s", strerror(-r)); return r; @@ -1158,7 +1203,7 @@ int main(int argc, char *argv[]) { goto finish; } - if (path_is_os_tree(arg_directory) <= 0) { + if (arg_boot && path_is_os_tree(arg_directory) <= 0) { log_error("Directory %s doesn't look like an OS root directory (/etc/os-release is missing). Refusing.", arg_directory); goto finish; } @@ -1187,7 +1232,8 @@ int main(int argc, char *argv[]) { goto finish; } - log_info("Spawning container %s on %s. Press ^] three times within 1s to abort execution.", arg_machine, arg_directory); + if (!arg_quiet) + log_info("Spawning container %s on %s. Press ^] three times within 1s to abort execution.", arg_machine, arg_directory); if (unlockpt(master) < 0) { log_error("Failed to unlock tty: %m"); @@ -1491,6 +1537,11 @@ int main(int argc, char *argv[]) { } else env_use = (char**) envp; +#ifdef HAVE_SELINUX + if (arg_selinux_context) + if (setexeccon(arg_selinux_context) < 0) + log_error("setexeccon(\"%s\") failed: %m", arg_selinux_context); +#endif if (arg_boot) { char **a; size_t l; @@ -1539,7 +1590,8 @@ int main(int argc, char *argv[]) { break; } - putc('\n', stdout); + if (!arg_quiet) + putc('\n', stdout); /* Kill if it is not dead yet anyway */ terminate_machine(pid); @@ -1562,16 +1614,21 @@ int main(int argc, char *argv[]) { break; } - log_debug("Container %s exited successfully.", arg_machine); + if (!arg_quiet) + log_debug("Container %s exited successfully.", arg_machine); break; } else if (status.si_code == CLD_KILLED && status.si_status == SIGINT) { - log_info("Container %s has been shut down.", arg_machine); + + if (!arg_quiet) + log_info("Container %s has been shut down.", arg_machine); r = 0; break; } else if (status.si_code == CLD_KILLED && status.si_status == SIGHUP) { - log_info("Container %s is being rebooted.", arg_machine); + + if (!arg_quiet) + log_info("Container %s is being rebooted.", arg_machine); continue; } else if (status.si_code == CLD_KILLED || status.si_code == CLD_DUMPED) {