From 023a4f67011f24d4b085995a4a3a02661c4794a2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Aug 2015 13:14:04 +0200 Subject: core: optionally create LOGIN_PROCESS or USER_PROCESS utmp entries When generating utmp/wtmp entries, optionally add both LOGIN_PROCESS and INIT_PROCESS entries or even all three of LOGIN_PROCESS, INIT_PROCESS and USER_PROCESS entries, instead of just a single INIT_PROCESS entry. With this change systemd may be used to not only invoke a getty directly in a SysV-compliant way but alternatively also a login(1) implementation or even forego getty and login entirely, and invoke arbitrary shells in a way that they appear in who(1) or w(1). This is preparation for a later commit that adds a "machinectl shell" operation to invoke a shell in a container, in a way that is compatible with who(1) and w(1). --- man/systemd.exec.xml | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) (limited to 'man') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 8fd75d274e..cb11199ad3 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1,3 +1,4 @@ + @@ -911,10 +912,16 @@ UtmpIdentifier= Takes a four character identifier string for - an utmp/wtmp entry for this service. This should only be set - for services such as getty implementations + an utmp5 + and wtmp entry for this service. This should only be + set for services such as getty + implementations (such as agetty8) where utmp/wtmp entries must be created and cleared before and - after execution. If the configured string is longer than four + after execution, or for services that shall be executed as if + they were run by a getty process (see + below). If the configured string is longer than four characters, it is truncated and the terminal four characters are used. This setting interprets %I style string replacements. This setting is unset by default, i.e. no @@ -922,6 +929,34 @@ service. + + UtmpMode= + + Takes one of init, + login or user. If + UtmpIdentifier= is set, controls which + type of utmp5/wtmp + entries for this service are generated. This setting has no + effect unless UtmpIdentifier= is set + too. If init is set, only an + INIT_PROCESS entry is generated and the + invoked process must implement a getty + compatible utmp/wtmp logic. If login is + set, first an INIT_PROCESS entry, + followed by an LOGIN_PROCESS entry is + generated. In this case the invoked process must implement a + login1-compatible + utmp/wtmp logic. If user is set, first an + INIT_PROCESS entry, then a + LOGIN_PROCESS entry and finally an + USER_PROCESS entry is generated. In this + case the invoked process may be any process that is suitable + to be run as session leader. Defaults to + init. + + SELinuxContext= -- cgit v1.2.3-54-g00ecf From c454426c54c9beb274f415a80c64a4f1580700e7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Aug 2015 13:24:10 +0200 Subject: machinectl: add new "machinectl shell" command This makes use of machined's new OpenShell() command and allows opening a new interactive shell in any container. --- man/machinectl.xml | 44 ++++++++++- src/machine/machinectl.c | 185 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 194 insertions(+), 35 deletions(-) (limited to 'man') diff --git a/man/machinectl.xml b/man/machinectl.xml index a5eb3f08e4..43dcbbdb18 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -1,4 +1,4 @@ - + @@ -137,6 +137,30 @@ SIGTERM. + + + + When used with the shell + command, chooses the user ID to open the interactive shell + session as. If this switch is not specified, defaults to + root. Note that this switch is not + supported for the login command (see + below). + + + + + + When used with the shell + command, sets an environment variable to pass to the executed + shell. Takes a pair of environment variable name and value, + separated by = as argument. This switch + may be used multiple times to set multiple environment + variables. Note that this switch is not supported for the + login command (see + below). + + @@ -145,7 +169,6 @@ mount. - @@ -318,7 +341,7 @@ login NAME - Open an interactive terminal login session to + Open an interactive terminal login session in a container. This will create a TTY connection to a specific container and asks for the execution of a getty on it. Note that this is only supported for containers running @@ -327,12 +350,27 @@ This command will open a full login prompt on the container, which then asks for username and password. Use + shell (see below) or systemd-run1 with the switch to invoke a single command, either interactively or in the background within a local container. + + shell NAME [PATH [ARGUMENTS...]] + + Open an interactive shell session in a + container. This works similar to login but + immediately invokes a user process. Invokes the specified + executable with the specified arguments, or + /bin/sh if none is specified. By default + opens a root shell, but using + a different user may be selected. Use + to set environment variables for + the executed process. + + enable NAME... disable NAME... diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 66ed41087c..8e75508444 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -55,6 +55,7 @@ #include "process-util.h" #include "terminal-util.h" #include "signal-util.h" +#include "env-util.h" static char **arg_property = NULL; static bool arg_all = false; @@ -75,6 +76,8 @@ static bool arg_force = false; static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE; static const char* arg_dkr_index_url = NULL; static const char* arg_format = NULL; +static const char *arg_uid = NULL; +static char **arg_setenv = NULL; static void pager_open_if_enabled(void) { @@ -1170,20 +1173,67 @@ static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *r return 0; } +static int process_forward(sd_event *event, PTYForward **forward, int master, bool ignore_vhangup, const char *name) { + char last_char = 0; + bool machine_died; + int ret = 0, r; + + assert(event); + assert(master >= 0); + assert(name); + + assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0); + + log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", name); + + sd_event_add_signal(event, NULL, SIGINT, NULL, NULL); + sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL); + + r = pty_forward_new(event, master, ignore_vhangup, false, forward); + if (r < 0) + return log_error_errno(r, "Failed to create PTY forwarder: %m"); + + r = sd_event_loop(event); + if (r < 0) + return log_error_errno(r, "Failed to run event loop: %m"); + + pty_forward_get_last_char(*forward, &last_char); + + machine_died = + ignore_vhangup && + pty_forward_get_ignore_vhangup(*forward) == 0; + + *forward = pty_forward_free(*forward); + + if (last_char != '\n') + fputc('\n', stdout); + + if (machine_died) + log_info("Machine %s terminated.", name); + else + log_info("Connection to machine %s terminated.", name); + + sd_event_get_exit_code(event, &ret); + return ret; +} + static int login_machine(int argc, char *argv[], void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL; _cleanup_(pty_forward_freep) PTYForward *forward = NULL; + _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL; _cleanup_event_unref_ sd_event *event = NULL; - int master = -1, r, ret = 0; + int master = -1, r; sd_bus *bus = userdata; const char *pty, *match; - char last_char = 0; - bool machine_died; assert(bus); + if (!strv_isempty(arg_setenv) || arg_uid) { + log_error("--setenv= and --uid= are not supported for 'login'. Use 'shell' instead."); + return -EINVAL; + } + if (arg_transport != BUS_TRANSPORT_LOCAL && arg_transport != BUS_TRANSPORT_MACHINE) { log_error("Login only supported on local machines."); @@ -1201,13 +1251,13 @@ static int login_machine(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to attach bus to event loop: %m"); match = strjoina("type='signal'," - "sender='org.freedesktop.machine1'," - "path='/org/freedesktop/machine1',", - "interface='org.freedesktop.machine1.Manager'," - "member='MachineRemoved'," - "arg0='", - argv[1], - "'"); + "sender='org.freedesktop.machine1'," + "path='/org/freedesktop/machine1',", + "interface='org.freedesktop.machine1.Manager'," + "member='MachineRemoved'," + "arg0='", + argv[1], + "'"); r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward); if (r < 0) @@ -1223,7 +1273,7 @@ static int login_machine(int argc, char *argv[], void *userdata) { &reply, "s", argv[1]); if (r < 0) { - log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r)); + log_error("Failed to get login PTY: %s", bus_error_message(&error, -r)); return r; } @@ -1231,36 +1281,83 @@ static int login_machine(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0); + return process_forward(event, &forward, master, true, argv[1]); +} - log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", argv[1]); +static int shell_machine(int argc, char *argv[], void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(pty_forward_freep) PTYForward *forward = NULL; + _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL; + _cleanup_event_unref_ sd_event *event = NULL; + int master = -1, r; + sd_bus *bus = userdata; + const char *pty, *match; - sd_event_add_signal(event, NULL, SIGINT, NULL, NULL); - sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL); + assert(bus); + + if (arg_transport != BUS_TRANSPORT_LOCAL && + arg_transport != BUS_TRANSPORT_MACHINE) { + log_error("Shell only supported on local machines."); + return -EOPNOTSUPP; + } + + polkit_agent_open_if_enabled(); - r = pty_forward_new(event, master, true, false, &forward); + r = sd_event_default(&event); if (r < 0) - return log_error_errno(r, "Failed to create PTY forwarder: %m"); + return log_error_errno(r, "Failed to get event loop: %m"); - r = sd_event_loop(event); + r = sd_bus_attach_event(bus, event, 0); if (r < 0) - return log_error_errno(r, "Failed to run event loop: %m"); + return log_error_errno(r, "Failed to attach bus to event loop: %m"); - pty_forward_get_last_char(forward, &last_char); - machine_died = pty_forward_get_ignore_vhangup(forward) == 0; + match = strjoina("type='signal'," + "sender='org.freedesktop.machine1'," + "path='/org/freedesktop/machine1',", + "interface='org.freedesktop.machine1.Manager'," + "member='MachineRemoved'," + "arg0='", + argv[1], + "'"); - forward = pty_forward_free(forward); + r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward); + if (r < 0) + return log_error_errno(r, "Failed to add machine removal match: %m"); - if (last_char != '\n') - fputc('\n', stdout); + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "OpenMachineShell"); + if (r < 0) + return bus_log_create_error(r); - if (machine_died) - log_info("Machine %s terminated.", argv[1]); - else - log_info("Connection to machine %s terminated.", argv[1]); + r = sd_bus_message_append(m, "sss", argv[1], arg_uid, argv[2]); + if (r < 0) + return bus_log_create_error(r); - sd_event_get_exit_code(event, &ret); - return ret; + r = sd_bus_message_append_strv(m, strv_length(argv + 2) <= 1 ? NULL : argv + 2); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, arg_setenv); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, &error, &reply); + if (r < 0) { + log_error("Failed to get shell PTY: %s", bus_error_message(&error, -r)); + return r; + } + + r = sd_bus_message_read(reply, "hs", &master, &pty); + if (r < 0) + return bus_log_parse_error(r); + + return process_forward(event, &forward, master, false, argv[1]); } static int remove_image(int argc, char *argv[], void *userdata) { @@ -2314,6 +2411,8 @@ static int help(int argc, char *argv[], void *userdata) { " -l --full Do not ellipsize output\n" " --kill-who=WHO Who to send signal to\n" " -s --signal=SIGNAL Which signal to send\n" + " --uid=USER Specify user ID to invoke shell as\n" + " --setenv=VAR=VALUE Add an environment variable for shell\n" " --read-only Create read-only bind mount\n" " --mkdir Create directory before bind mounting, if missing\n" " -n --lines=INTEGER Number of journal entries to show\n" @@ -2331,6 +2430,7 @@ static int help(int argc, char *argv[], void *userdata) { " show NAME... Show properties of one or more VMs/containers\n" " start NAME... Start container as a service\n" " login NAME Get a login prompt on a container\n" + " shell NAME [COMMAND...] Invoke a shell (or other command) in a container\n" " enable NAME... Enable automatic container start at boot\n" " disable NAME... Disable automatic container start at boot\n" " poweroff NAME... Power off one or more containers\n" @@ -2378,6 +2478,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_FORCE, ARG_DKR_INDEX_URL, ARG_FORMAT, + ARG_UID, + ARG_SETENV, }; static const struct option options[] = { @@ -2402,6 +2504,8 @@ static int parse_argv(int argc, char *argv[]) { { "force", no_argument, NULL, ARG_FORCE }, { "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL }, { "format", required_argument, NULL, ARG_FORMAT }, + { "uid", required_argument, NULL, ARG_UID }, + { "setenv", required_argument, NULL, ARG_SETENV }, {} }; @@ -2532,6 +2636,21 @@ static int parse_argv(int argc, char *argv[]) { arg_format = optarg; break; + case ARG_UID: + arg_uid = optarg; + break; + + case ARG_SETENV: + if (!env_assignment_is_valid(optarg)) { + log_error("Environment assignment invalid: %s", optarg); + return -EINVAL; + } + + r = strv_extend(&arg_setenv, optarg); + if (r < 0) + return log_oom(); + break; + case '?': return -EINVAL; @@ -2557,6 +2676,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { { "poweroff", 2, VERB_ANY, 0, poweroff_machine }, { "kill", 2, VERB_ANY, 0, kill_machine }, { "login", 2, 2, 0, login_machine }, + { "shell", 2, VERB_ANY, 0, shell_machine }, { "bind", 3, 4, 0, bind_mount }, { "copy-to", 3, 4, 0, copy_files }, { "copy-from", 3, 4, 0, copy_files }, @@ -2610,6 +2730,7 @@ finish: polkit_agent_close(); strv_free(arg_property); + strv_free(arg_setenv); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } -- cgit v1.2.3-54-g00ecf From 91913f584af38b29a816cca959ba648acd60ac9f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 24 Aug 2015 22:17:52 +0200 Subject: machinectl: make machine name parameters for "shell" and "login" optional If no machine name is specified, imply that we connect to ".host", i.e. the local host. --- man/machinectl.xml | 123 +++++++++++++++++++++++++++++++++++++++-------- src/machine/machinectl.c | 51 ++++++++++++-------- 2 files changed, 134 insertions(+), 40 deletions(-) (limited to 'man') diff --git a/man/machinectl.xml b/man/machinectl.xml index 43dcbbdb18..2f68f91b93 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -65,6 +65,43 @@ systemd1 virtual machine and container registration manager systemd-machined.service8. + + machinectl may be used to execute + operations on machines and images. Machines in this sense are + considered running instances of: + + + Virtual Machines (VMs) that virtualize hardware + to run full operating system (OS) instances (including their kernels) + in a virtualized environment on top of the host OS. + + Containers that share the hardware and + OS kernel with the host OS, in order to run + OS userspace instances on top the host OS. + + The host system itself + + + Machines are identified by names that follow the same rules + as UNIX and DNS host names, for details see below. Machines are + instantiated from disk or file system images, that frequently but not + necessarily carry the same name as machines running from + them. Images in this sense are considered: + + + Directory trees containing an OS, including its + top-level directories /usr, + /etc, and so on. + + btrfs subvolumes containing OS trees, similar to + normal directory trees. + + Binary "raw" disk images containing MBR or GPT + partition tables and Linux file system partitions. + + The file system tree of the host OS itself. + + @@ -270,9 +307,11 @@ list List currently running (online) virtual - machines and containers. To enumerate container images that - can be started, use list-images (see - below). + machines and containers. To enumerate machine images that can + be started, use list-images (see + below). Note that this command hides the special + .host machine by default. Use the + switch to show it. @@ -290,7 +329,7 @@ - show NAME... + show [NAME...] Show properties of one or more registered virtual machines or containers or the manager itself. If no @@ -339,31 +378,42 @@ - login NAME + login [NAME] Open an interactive terminal login session in - a container. This will create a TTY connection to a specific - container and asks for the execution of a getty on it. Note - that this is only supported for containers running + a container or on the local host. If an argument is supplied + it refers to the container machine to connect to. If none is + specified, or the container name is specified as the empty + string, or the special machine name .host + (see below) is specified, the connection is made to the local + host instead. This will create a TTY connection to a specific + container or the local host and asks for the execution of a + getty on it. Note that this is only supported for containers + running systemd1 as init system. This command will open a full login prompt on the - container, which then asks for username and password. Use - shell (see below) or + container or the local host, which then asks for username and + password. Use shell (see below) or systemd-run1 - with the switch to invoke a single - command, either interactively or in the background within a - local container. + with the switch to directly invoke + a single command, either interactively or in the + background. - shell NAME [PATH [ARGUMENTS...]] + shell [NAME [PATH [ARGUMENTS...]]] Open an interactive shell session in a - container. This works similar to login but - immediately invokes a user process. Invokes the specified - executable with the specified arguments, or + container or on the local host. The first argument refers to + the container machine to connect to. If none is specified, or + the machine name is specified as the empty string, or the + special machine name .host (see below) is + specified, the connection is made to the local host + instead. This works similar to login but + immediately invokes a user process. This command runs the + specified executable with the specified arguments, or /bin/sh if none is specified. By default opens a root shell, but using a different user may be selected. Use @@ -491,7 +541,7 @@ - image-status NAME... + image-status [NAME...] Show terse status information about one or more container or VM images. This function is intended to @@ -501,7 +551,7 @@ - show-image NAME... + show-image [NAME...] Show properties of one or more registered virtual machine or container images, or the manager itself. If @@ -803,6 +853,41 @@ + + Machine and Image Names + + The machinectl tool operates on machines + and images, whose names must be chosen following strict + rules. Machine names must be suitable for use as host names + following a conservative subset of DNS and UNIX/Linux + semantics. Specifically, they must consist of one or more + non-empty label strings, separated by dots. No leading or trailing + dots are allowed. No sequences of multiple dots are allowed. The + label strings may only consists of alphanumeric characters as well + as the dash and underscore. The maximum length of a machine name + is 64 characters. + + A special machine with the name .host + refers to the running host system itself. This is useful for execution + operations or inspecting the host system as well. Not that + machinectl list will not show this special + machine unless the switch is specified. + + Requirements on image names are less strict, however must be + valid UTF-8, must be suitable as file names (hence not be the + single or double dot, and not include a slash), and may not + contain control characters. Since many operations search for an + image by the name of a requested machine it is recommended to name + images in the same strict fashion as machines. + + A special image with the name .host + refers to the image of the running host system. It is hence + conceptually maps to the special .host machine + name described above. Note that machinectl + list-images won't show this special image either, unless + is specified. + + Files and Directories diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 0f9e732ada..08a2d3fe4d 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -1186,7 +1186,10 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, bo assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0); - log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", name); + if (streq(name, ".host")) + log_info("Connected to the local host. Press ^] three times within 1s to exit session."); + else + log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", name); sd_event_add_signal(event, NULL, SIGINT, NULL, NULL); sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL); @@ -1212,6 +1215,8 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, bo if (machine_died) log_info("Machine %s terminated.", name); + else if (streq(name, ".host")) + log_info("Connection to the local host terminated."); else log_info("Connection to machine %s terminated.", name); @@ -1227,7 +1232,7 @@ static int login_machine(int argc, char *argv[], void *userdata) { _cleanup_event_unref_ sd_event *event = NULL; int master = -1, r; sd_bus *bus = userdata; - const char *pty, *match; + const char *pty, *match, *machine; assert(bus); @@ -1252,14 +1257,14 @@ static int login_machine(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to attach bus to event loop: %m"); + machine = argc < 2 || isempty(argv[1]) ? ".host" : argv[1]; + match = strjoina("type='signal'," "sender='org.freedesktop.machine1'," "path='/org/freedesktop/machine1',", "interface='org.freedesktop.machine1.Manager'," "member='MachineRemoved'," - "arg0='", - argv[1], - "'"); + "arg0='", machine, "'"); r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward); if (r < 0) @@ -1273,7 +1278,7 @@ static int login_machine(int argc, char *argv[], void *userdata) { "OpenMachineLogin", &error, &reply, - "s", argv[1]); + "s", machine); if (r < 0) { log_error("Failed to get login PTY: %s", bus_error_message(&error, -r)); return r; @@ -1283,7 +1288,7 @@ static int login_machine(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); - return process_forward(event, &forward, master, true, argv[1]); + return process_forward(event, &forward, master, true, machine); } static int shell_machine(int argc, char *argv[], void *userdata) { @@ -1294,7 +1299,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) { _cleanup_event_unref_ sd_event *event = NULL; int master = -1, r; sd_bus *bus = userdata; - const char *pty, *match; + const char *pty, *match, *machine, *path; assert(bus); @@ -1314,14 +1319,14 @@ static int shell_machine(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to attach bus to event loop: %m"); + machine = argc < 2 || isempty(argv[1]) ? ".host" : argv[1]; + match = strjoina("type='signal'," "sender='org.freedesktop.machine1'," "path='/org/freedesktop/machine1',", "interface='org.freedesktop.machine1.Manager'," "member='MachineRemoved'," - "arg0='", - argv[1], - "'"); + "arg0='", machine, "'"); r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward); if (r < 0) @@ -1337,11 +1342,13 @@ static int shell_machine(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_create_error(r); - r = sd_bus_message_append(m, "sss", argv[1], arg_uid, argv[2]); + path = argc < 3 || isempty(argv[2]) ? NULL : argv[2]; + + r = sd_bus_message_append(m, "sss", machine, arg_uid, path); if (r < 0) return bus_log_create_error(r); - r = sd_bus_message_append_strv(m, strv_length(argv + 2) <= 1 ? NULL : argv + 2); + r = sd_bus_message_append_strv(m, strv_length(argv) <= 3 ? NULL : argv + 2); if (r < 0) return bus_log_create_error(r); @@ -1359,7 +1366,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); - return process_forward(event, &forward, master, false, argv[1]); + return process_forward(event, &forward, master, false, machine); } static int remove_image(int argc, char *argv[], void *userdata) { @@ -2429,10 +2436,12 @@ static int help(int argc, char *argv[], void *userdata) { "Machine Commands:\n" " list List running VMs and containers\n" " status NAME... Show VM/container details\n" - " show NAME... Show properties of one or more VMs/containers\n" + " show [NAME...] Show properties of one or more VMs/containers\n" " start NAME... Start container as a service\n" - " login NAME Get a login prompt on a container\n" - " shell NAME [COMMAND...] Invoke a shell (or other command) in a container\n" + " login [NAME] Get a login prompt in a container or on the\n" + " local host\n" + " shell [NAME] [COMMAND...] Invoke a shell (or other command) in a container\n" + " or the local host\n" " enable NAME... Enable automatic container start at boot\n" " disable NAME... Disable automatic container start at boot\n" " poweroff NAME... Power off one or more containers\n" @@ -2444,8 +2453,8 @@ static int help(int argc, char *argv[], void *userdata) { " bind NAME PATH [PATH] Bind mount a path from the host into a container\n\n" "Image Commands:\n" " list-images Show available container and VM images\n" - " image-status NAME... Show image details\n" - " show-image NAME... Show properties of image\n" + " image-status [NAME...] Show image details\n" + " show-image [NAME...] Show properties of image\n" " clone NAME NAME Clone an image\n" " rename NAME NAME Rename an image\n" " read-only NAME [BOOL] Mark or unmark image read-only\n" @@ -2677,8 +2686,8 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { { "reboot", 2, VERB_ANY, 0, reboot_machine }, { "poweroff", 2, VERB_ANY, 0, poweroff_machine }, { "kill", 2, VERB_ANY, 0, kill_machine }, - { "login", 2, 2, 0, login_machine }, - { "shell", 2, VERB_ANY, 0, shell_machine }, + { "login", VERB_ANY, 2, 0, login_machine }, + { "shell", VERB_ANY, VERB_ANY, 0, shell_machine }, { "bind", 3, 4, 0, bind_mount }, { "copy-to", 3, 4, 0, copy_files }, { "copy-from", 3, 4, 0, copy_files }, -- cgit v1.2.3-54-g00ecf From ef3100e9637adda26fa19e7ee8606788320dcde3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 24 Aug 2015 22:44:54 +0200 Subject: machinectl: extend the "shell" syntax to take user@container names In order to make "machinectl shell" more similar to ssh, allow the following syntax to connect to a container under a specific username: machinectl shell lennart@fedora Also beefs up related man page documentation. --- man/machinectl.xml | 40 +++++++++++++++++++++++++++++++++++----- src/machine/machinectl.c | 26 +++++++++++++++++++++----- 2 files changed, 56 insertions(+), 10 deletions(-) (limited to 'man') diff --git a/man/machinectl.xml b/man/machinectl.xml index 2f68f91b93..6cf405ed29 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -403,7 +403,7 @@ - shell [NAME [PATH [ARGUMENTS...]]] + shell [[NAME@]NAME [PATH [ARGUMENTS...]]] Open an interactive shell session in a container or on the local host. The first argument refers to @@ -415,10 +415,29 @@ immediately invokes a user process. This command runs the specified executable with the specified arguments, or /bin/sh if none is specified. By default - opens a root shell, but using - a different user may be selected. Use - to set environment variables for - the executed process. + opens a root shell, but by using + , or by prefixing the machine name with + a username and an @ character, a different + user may be selected. Use to set + environment variables for the executed process. + + When using the shell command without + arguments (thus invoking the executed shell or command on the + local host) it is similar in many ways to a su1 + session, but unlike su completely isolates + the new session from the originating session, so that it + shares no process or session properties, and is in a clean and + well-defined state. It will be tracked in a new utmp, login, + audit and keyring session, and will not inherit an environment + variables or resource limits, among other properties. + + Note that the + systemd-run1 + may be used in place of the shell command, + and allows more detailed, low-level configuration of the + invoked unit. However, it is frequently more privileged than + the shell command. @@ -995,6 +1014,17 @@ current directory. + + Create a new shell session + + # machinectl shell --uid=lennart + + This creates a new shell session on the local host, for + the user ID lennart, in a su1-like + fashion. + + diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 08a2d3fe4d..6b29e61642 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -1299,7 +1299,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) { _cleanup_event_unref_ sd_event *event = NULL; int master = -1, r; sd_bus *bus = userdata; - const char *pty, *match, *machine, *path; + const char *pty, *match, *machine, *path, *uid = NULL; assert(bus); @@ -1319,7 +1319,22 @@ static int shell_machine(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to attach bus to event loop: %m"); - machine = argc < 2 || isempty(argv[1]) ? ".host" : argv[1]; + machine = argc < 2 || isempty(argv[1]) ? NULL : argv[1]; + + if (arg_uid) + uid = arg_uid; + else if (machine) { + const char *at; + + at = strchr(machine, '@'); + if (at) { + uid = strndupa(machine, at - machine); + machine = at + 1; + } + } + + if (isempty(machine)) + machine = ".host"; match = strjoina("type='signal'," "sender='org.freedesktop.machine1'," @@ -1344,7 +1359,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) { path = argc < 3 || isempty(argv[2]) ? NULL : argv[2]; - r = sd_bus_message_append(m, "sss", machine, arg_uid, path); + r = sd_bus_message_append(m, "sss", machine, uid, path); if (r < 0) return bus_log_create_error(r); @@ -2440,8 +2455,9 @@ static int help(int argc, char *argv[], void *userdata) { " start NAME... Start container as a service\n" " login [NAME] Get a login prompt in a container or on the\n" " local host\n" - " shell [NAME] [COMMAND...] Invoke a shell (or other command) in a container\n" - " or the local host\n" + " shell [[USER@]NAME [COMMAND...]]\n" + " Invoke a shell (or other command) in a container\n" + " or on the local host\n" " enable NAME... Enable automatic container start at boot\n" " disable NAME... Disable automatic container start at boot\n" " poweroff NAME... Power off one or more containers\n" -- cgit v1.2.3-54-g00ecf