1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-25 18:50:18 +03:00

Merge pull request #1496 from poettering/stdin-fd

allow passing in fds for stdin/stdout/stderr for transient services
This commit is contained in:
Daniel Mack 2015-10-08 16:09:09 +02:00
commit ad86c1335a
25 changed files with 511 additions and 254 deletions

View File

@ -342,3 +342,7 @@
- To determine the length of a constant string "foo", don't bother
with sizeof("foo")-1, please use strlen("foo") directly. gcc knows
strlen() anyway and turns it into a constant expression if possible.
- If you want to concatenate two or more strings, consider using
strjoin() rather than asprintf(), as the latter is a lot
slower. This matters particularly in inner loops.

View File

@ -26,7 +26,7 @@ __contains_word() {
__get_machines() {
local a b
(machinectl list-images --no-legend --no-pager; machinectl list --no-legend --no-pager) | \
(machinectl list-images --no-legend --no-pager; machinectl list --no-legend --no-pager; echo ".host") | \
{ while read a b; do echo " $a"; done; } | sort -u;
}
@ -41,7 +41,7 @@ _machinectl() {
local -A VERBS=(
[STANDALONE]='list list-images pull-tar pull-raw pull-dkr import-tar import-raw export-tar export-raw list-transfers cancel-transfer'
[MACHINES]='status show start login enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit'
[MACHINES]='status show start login shell enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit'
)
_init_completion || return

View File

@ -480,10 +480,6 @@ int acquire_terminal(
safe_close(notify);
r = reset_terminal_fd(fd, true);
if (r < 0)
log_warning_errno(r, "Failed to reset terminal: %m");
return fd;
fail:
@ -539,8 +535,9 @@ int terminal_vhangup(const char *name) {
}
int vt_disallocate(const char *name) {
int fd, r;
_cleanup_close_ int fd = -1;
unsigned u;
int r;
/* Deallocate the VT if possible. If not possible
* (i.e. because it is the active one), at least clear it
@ -562,8 +559,6 @@ int vt_disallocate(const char *name) {
"\033[H" /* move home */
"\033[2J", /* clear screen */
10, false);
safe_close(fd);
return 0;
}
@ -583,7 +578,7 @@ int vt_disallocate(const char *name) {
return fd;
r = ioctl(fd, VT_DISALLOCATE, u);
safe_close(fd);
fd = safe_close(fd);
if (r >= 0)
return 0;
@ -602,8 +597,6 @@ int vt_disallocate(const char *name) {
"\033[H" /* move home */
"\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
10, false);
safe_close(fd);
return 0;
}
@ -616,6 +609,10 @@ int make_console_stdio(void) {
if (fd < 0)
return log_error_errno(fd, "Failed to acquire terminal: %m");
r = reset_terminal_fd(fd, true);
if (r < 0)
log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
r = make_stdio(fd);
if (r < 0)
return log_error_errno(r, "Failed to duplicate terminal fd: %m");
@ -1054,6 +1051,33 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
return 0;
}
int ptsname_malloc(int fd, char **ret) {
size_t l = 100;
assert(fd >= 0);
assert(ret);
for (;;) {
char *c;
c = new(char, l);
if (!c)
return -ENOMEM;
if (ptsname_r(fd, c, l) == 0) {
*ret = c;
return 0;
}
if (errno != ERANGE) {
free(c);
return -errno;
}
free(c);
l *= 2;
}
}
int ptsname_namespace(int pty, char **ret) {
int no = -1, r;
@ -1072,3 +1096,104 @@ int ptsname_namespace(int pty, char **ret) {
return 0;
}
int openpt_in_namespace(pid_t pid, int flags) {
_cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
_cleanup_close_pair_ int pair[2] = { -1, -1 };
siginfo_t si;
pid_t child;
int r;
assert(pid > 0);
r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
if (r < 0)
return r;
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
return -errno;
child = fork();
if (child < 0)
return -errno;
if (child == 0) {
int master;
pair[0] = safe_close(pair[0]);
r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
if (r < 0)
_exit(EXIT_FAILURE);
master = posix_openpt(flags|O_NOCTTY|O_CLOEXEC);
if (master < 0)
_exit(EXIT_FAILURE);
if (unlockpt(master) < 0)
_exit(EXIT_FAILURE);
if (send_one_fd(pair[1], master, 0) < 0)
_exit(EXIT_FAILURE);
_exit(EXIT_SUCCESS);
}
pair[1] = safe_close(pair[1]);
r = wait_for_terminate(child, &si);
if (r < 0)
return r;
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
return -EIO;
return receive_one_fd(pair[0], 0);
}
int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
_cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
_cleanup_close_pair_ int pair[2] = { -1, -1 };
siginfo_t si;
pid_t child;
int r;
r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
if (r < 0)
return r;
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
return -errno;
child = fork();
if (child < 0)
return -errno;
if (child == 0) {
int master;
pair[0] = safe_close(pair[0]);
r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
if (r < 0)
_exit(EXIT_FAILURE);
master = open_terminal(name, mode|O_NOCTTY|O_CLOEXEC);
if (master < 0)
_exit(EXIT_FAILURE);
if (send_one_fd(pair[1], master, 0) < 0)
_exit(EXIT_FAILURE);
_exit(EXIT_SUCCESS);
}
pair[1] = safe_close(pair[1]);
r = wait_for_terminate(child, &si);
if (r < 0)
return r;
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
return -EIO;
return receive_one_fd(pair[0], 0);
}

View File

@ -120,4 +120,8 @@ int get_ctty(pid_t, dev_t *_devnr, char **r);
int getttyname_malloc(int fd, char **r);
int getttyname_harder(int fd, char **r);
int ptsname_malloc(int fd, char **ret);
int ptsname_namespace(int pty, char **ret);
int openpt_in_namespace(pid_t pid, int flags);
int open_terminal_in_namespace(pid_t pid, const char *name, int mode);

View File

@ -6087,86 +6087,6 @@ int free_and_strdup(char **p, const char *s) {
return 1;
}
int ptsname_malloc(int fd, char **ret) {
size_t l = 100;
assert(fd >= 0);
assert(ret);
for (;;) {
char *c;
c = new(char, l);
if (!c)
return -ENOMEM;
if (ptsname_r(fd, c, l) == 0) {
*ret = c;
return 0;
}
if (errno != ERANGE) {
free(c);
return -errno;
}
free(c);
l *= 2;
}
}
int openpt_in_namespace(pid_t pid, int flags) {
_cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
_cleanup_close_pair_ int pair[2] = { -1, -1 };
siginfo_t si;
pid_t child;
int r;
assert(pid > 0);
r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
if (r < 0)
return r;
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
return -errno;
child = fork();
if (child < 0)
return -errno;
if (child == 0) {
int master;
pair[0] = safe_close(pair[0]);
r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
if (r < 0)
_exit(EXIT_FAILURE);
master = posix_openpt(flags|O_NOCTTY|O_CLOEXEC);
if (master < 0)
_exit(EXIT_FAILURE);
if (unlockpt(master) < 0)
_exit(EXIT_FAILURE);
if (send_one_fd(pair[1], master, 0) < 0)
_exit(EXIT_FAILURE);
_exit(EXIT_SUCCESS);
}
pair[1] = safe_close(pair[1]);
r = wait_for_terminate(child, &si);
if (r < 0)
return r;
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
return -EIO;
return receive_one_fd(pair[0], 0);
}
ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
_cleanup_close_ int fd = -1;

View File

@ -891,10 +891,6 @@ union inotify_event_buffer {
#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW)
int ptsname_malloc(int fd, char **ret);
int openpt_in_namespace(pid_t pid, int flags);
ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags);
int fd_setcrtime(int fd, usec_t usec);

View File

@ -774,8 +774,9 @@ static int automount_stop(Unit *u) {
static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
Automount *a = AUTOMOUNT(u);
void *p;
Iterator i;
void *p;
int r;
assert(a);
assert(f);
@ -790,15 +791,9 @@ static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
SET_FOREACH(p, a->expire_tokens, i)
unit_serialize_item_format(u, f, "expire-token", "%u", PTR_TO_UINT(p));
if (a->pipe_fd >= 0) {
int copy;
copy = fdset_put_dup(fds, a->pipe_fd);
if (copy < 0)
return copy;
unit_serialize_item_format(u, f, "pipe-fd", "%i", copy);
}
r = unit_serialize_item_fd(u, f, fds, "pipe-fd", a->pipe_fd);
if (r < 0)
return r;
return 0;
}

View File

@ -656,6 +656,7 @@ static int busname_stop(Unit *u) {
static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
BusName *n = BUSNAME(u);
int r;
assert(n);
assert(f);
@ -667,15 +668,9 @@ static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
if (n->control_pid > 0)
unit_serialize_item_format(u, f, "control-pid", PID_FMT, n->control_pid);
if (n->starter_fd >= 0) {
int copy;
copy = fdset_put_dup(fds, n->starter_fd);
if (copy < 0)
return copy;
unit_serialize_item_format(u, f, "starter-fd", "%i", copy);
}
r = unit_serialize_item_fd(u, f, fds, "starter-fd", n->starter_fd);
if (r < 0)
return r;
return 0;
}

View File

@ -19,6 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "async.h"
#include "strv.h"
#include "path-util.h"
#include "unit.h"
@ -120,6 +121,37 @@ static int bus_service_set_transient_property(
return 1;
} else if (STR_IN_SET(name,
"StandardInputFileDescriptor",
"StandardOutputFileDescriptor",
"StandardErrorFileDescriptor")) {
int fd;
r = sd_bus_message_read(message, "h", &fd);
if (r < 0)
return r;
if (mode != UNIT_CHECK) {
int copy;
copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (copy < 0)
return -errno;
if (streq(name, "StandardInputFileDescriptor")) {
asynchronous_close(s->stdin_fd);
s->stdin_fd = copy;
} else if (streq(name, "StandardOutputFileDescriptor")) {
asynchronous_close(s->stdout_fd);
s->stdout_fd = copy;
} else {
asynchronous_close(s->stderr_fd);
s->stderr_fd = copy;
}
}
return 1;
} else if (streq(name, "ExecStart")) {
unsigned n = 0;

View File

@ -359,12 +359,28 @@ static int fixup_output(ExecOutput std_output, int socket_fd) {
return std_output;
}
static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
static int setup_input(
const ExecContext *context,
const ExecParameters *params,
int socket_fd) {
ExecInput i;
assert(context);
assert(params);
i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
if (params->stdin_fd >= 0) {
if (dup2(params->stdin_fd, STDIN_FILENO) < 0)
return -errno;
/* Try to make this the controlling tty, if it is a tty, and reset it */
(void) ioctl(STDIN_FILENO, TIOCSCTTY, context->std_input == EXEC_INPUT_TTY_FORCE);
(void) reset_terminal_fd(STDIN_FILENO, true);
return STDIN_FILENO;
}
i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
switch (i) {
@ -401,16 +417,40 @@ static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty
}
}
static int setup_output(Unit *unit, const ExecContext *context, int fileno, int socket_fd, const char *ident, bool apply_tty_stdin, uid_t uid, gid_t gid) {
static int setup_output(
Unit *unit,
const ExecContext *context,
const ExecParameters *params,
int fileno,
int socket_fd,
const char *ident,
uid_t uid, gid_t gid) {
ExecOutput o;
ExecInput i;
int r;
assert(unit);
assert(context);
assert(params);
assert(ident);
i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
if (fileno == STDOUT_FILENO && params->stdout_fd >= 0) {
if (dup2(params->stdout_fd, STDOUT_FILENO) < 0)
return -errno;
return STDOUT_FILENO;
}
if (fileno == STDERR_FILENO && params->stderr_fd >= 0) {
if (dup2(params->stderr_fd, STDERR_FILENO) < 0)
return -errno;
return STDERR_FILENO;
}
i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
o = fixup_output(context->std_output, socket_fd);
if (fileno == STDERR_FILENO) {
@ -503,9 +543,9 @@ static int chown_terminal(int fd, uid_t uid) {
return 0;
}
static int setup_confirm_stdio(int *_saved_stdin,
int *_saved_stdout) {
int fd = -1, saved_stdin, saved_stdout = -1, r;
static int setup_confirm_stdio(int *_saved_stdin, int *_saved_stdout) {
_cleanup_close_ int fd = -1, saved_stdin = -1, saved_stdout = -1;
int r;
assert(_saved_stdin);
assert(_saved_stdout);
@ -515,10 +555,8 @@ static int setup_confirm_stdio(int *_saved_stdin,
return -errno;
saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3);
if (saved_stdout < 0) {
r = errno;
goto fail;
}
if (saved_stdout < 0)
return -errno;
fd = acquire_terminal(
"/dev/console",
@ -526,39 +564,33 @@ static int setup_confirm_stdio(int *_saved_stdin,
false,
false,
DEFAULT_CONFIRM_USEC);
if (fd < 0) {
r = fd;
goto fail;
}
if (fd < 0)
return fd;
r = chown_terminal(fd, getuid());
if (r < 0)
goto fail;
return r;
if (dup2(fd, STDIN_FILENO) < 0) {
r = -errno;
goto fail;
}
r = reset_terminal_fd(fd, true);
if (r < 0)
return r;
if (dup2(fd, STDOUT_FILENO) < 0) {
r = -errno;
goto fail;
}
if (dup2(fd, STDIN_FILENO) < 0)
return -errno;
if (dup2(fd, STDOUT_FILENO) < 0)
return -errno;
if (fd >= 2)
safe_close(fd);
fd = -1;
*_saved_stdin = saved_stdin;
*_saved_stdout = saved_stdout;
saved_stdin = saved_stdout = -1;
return 0;
fail:
safe_close(saved_stdout);
safe_close(saved_stdin);
safe_close(fd);
return r;
}
_printf_(1, 2) static int write_confirm_message(const char *format, ...) {
@ -578,9 +610,7 @@ _printf_(1, 2) static int write_confirm_message(const char *format, ...) {
return 0;
}
static int restore_confirm_stdio(int *saved_stdin,
int *saved_stdout) {
static int restore_confirm_stdio(int *saved_stdin, int *saved_stdout) {
int r = 0;
assert(saved_stdin);
@ -596,8 +626,8 @@ static int restore_confirm_stdio(int *saved_stdin,
if (dup2(*saved_stdout, STDOUT_FILENO) < 0)
r = -errno;
safe_close(*saved_stdin);
safe_close(*saved_stdout);
*saved_stdin = safe_close(*saved_stdin);
*saved_stdout = safe_close(*saved_stdout);
return r;
}
@ -1324,6 +1354,44 @@ static bool exec_needs_mount_namespace(
return false;
}
static int close_remaining_fds(
const ExecParameters *params,
ExecRuntime *runtime,
int socket_fd,
int *fds, unsigned n_fds) {
unsigned n_dont_close = 0;
int dont_close[n_fds + 7];
assert(params);
if (params->stdin_fd >= 0)
dont_close[n_dont_close++] = params->stdin_fd;
if (params->stdout_fd >= 0)
dont_close[n_dont_close++] = params->stdout_fd;
if (params->stderr_fd >= 0)
dont_close[n_dont_close++] = params->stderr_fd;
if (socket_fd >= 0)
dont_close[n_dont_close++] = socket_fd;
if (n_fds > 0) {
memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
n_dont_close += n_fds;
}
if (params->bus_endpoint_fd >= 0)
dont_close[n_dont_close++] = params->bus_endpoint_fd;
if (runtime) {
if (runtime->netns_storage_socket[0] >= 0)
dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
if (runtime->netns_storage_socket[1] >= 0)
dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
}
return close_all_fds(dont_close, n_dont_close);
}
static int exec_child(
Unit *unit,
ExecCommand *command,
@ -1339,8 +1407,6 @@ static int exec_child(
_cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
_cleanup_free_ char *mac_selinux_context_net = NULL;
const char *username = NULL, *home = NULL, *shell = NULL, *wd;
unsigned n_dont_close = 0;
int dont_close[n_fds + 4];
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
int i, r;
@ -1380,22 +1446,7 @@ static int exec_child(
log_forget_fds();
if (socket_fd >= 0)
dont_close[n_dont_close++] = socket_fd;
if (n_fds > 0) {
memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
n_dont_close += n_fds;
}
if (params->bus_endpoint_fd >= 0)
dont_close[n_dont_close++] = params->bus_endpoint_fd;
if (runtime) {
if (runtime->netns_storage_socket[0] >= 0)
dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
if (runtime->netns_storage_socket[1] >= 0)
dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
}
r = close_all_fds(dont_close, n_dont_close);
r = close_remaining_fds(params, runtime, socket_fd, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_FDS;
return r;
@ -1451,21 +1502,21 @@ static int exec_child(
/* If a socket is connected to STDIN/STDOUT/STDERR, we
* must sure to drop O_NONBLOCK */
if (socket_fd >= 0)
fd_nonblock(socket_fd, false);
(void) fd_nonblock(socket_fd, false);
r = setup_input(context, socket_fd, params->apply_tty_stdin);
r = setup_input(context, params, socket_fd);
if (r < 0) {
*exit_status = EXIT_STDIN;
return r;
}
r = setup_output(unit, context, STDOUT_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid);
if (r < 0) {
*exit_status = EXIT_STDOUT;
return r;
}
r = setup_output(unit, context, STDERR_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid);
if (r < 0) {
*exit_status = EXIT_STDERR;
return r;

View File

@ -208,23 +208,22 @@ struct ExecContext {
struct ExecParameters {
char **argv;
char **environment;
int *fds;
char **fd_names;
unsigned n_fds;
char **environment;
bool apply_permissions:1;
bool apply_chroot:1;
bool apply_tty_stdin:1;
bool apply_permissions;
bool apply_chroot;
bool apply_tty_stdin;
bool confirm_spawn;
bool selinux_context_net;
bool confirm_spawn:1;
bool selinux_context_net:1;
bool cgroup_delegate:1;
CGroupMask cgroup_supported;
const char *cgroup_path;
bool cgroup_delegate;
const char *runtime_prefix;
@ -234,6 +233,10 @@ struct ExecParameters {
char *bus_endpoint_path;
int bus_endpoint_fd;
int stdin_fd;
int stdout_fd;
int stderr_fd;
};
int exec_spawn(Unit *unit,

View File

@ -694,6 +694,9 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
.apply_chroot = true,
.apply_tty_stdin = true,
.bus_endpoint_fd = -1,
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
};
assert(m);

View File

@ -108,6 +108,7 @@ static void service_init(Unit *u) {
s->type = _SERVICE_TYPE_INVALID;
s->socket_fd = -1;
s->bus_endpoint_fd = -1;
s->stdin_fd = s->stdout_fd = s->stderr_fd = -1;
s->guess_main_pid = true;
RATELIMIT_INIT(s->start_limit, u->manager->default_start_limit_interval, u->manager->default_start_limit_burst);
@ -271,11 +272,15 @@ static void service_release_resources(Unit *u) {
assert(s);
if (!s->fd_store)
if (!s->fd_store && s->stdin_fd < 0 && s->stdout_fd < 0 && s->stderr_fd < 0)
return;
log_unit_debug(u, "Releasing all resources.");
s->stdin_fd = safe_close(s->stdin_fd);
s->stdout_fd = safe_close(s->stdout_fd);
s->stderr_fd = safe_close(s->stderr_fd);
while (s->fd_store)
service_fd_store_unlink(s->fd_store);
@ -1090,11 +1095,13 @@ static int service_spawn(
pid_t pid;
ExecParameters exec_params = {
.apply_permissions = apply_permissions,
.apply_chroot = apply_chroot,
.apply_tty_stdin = apply_tty_stdin,
.bus_endpoint_fd = -1,
.selinux_context_net = s->socket_fd_selinux_context_net
.apply_permissions = apply_permissions,
.apply_chroot = apply_chroot,
.apply_tty_stdin = apply_tty_stdin,
.bus_endpoint_fd = -1,
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
};
int r;
@ -1236,8 +1243,12 @@ static int service_spawn(
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
exec_params.watchdog_usec = s->watchdog_usec;
exec_params.bus_endpoint_path = bus_endpoint_path;
exec_params.selinux_context_net = s->socket_fd_selinux_context_net;
if (s->type == SERVICE_IDLE)
exec_params.idle_pipe = UNIT(s)->manager->idle_pipe;
exec_params.stdin_fd = s->stdin_fd;
exec_params.stdout_fd = s->stdout_fd;
exec_params.stderr_fd = s->stderr_fd;
r = exec_spawn(UNIT(s),
c,
@ -2038,6 +2049,7 @@ _pure_ static bool service_can_reload(Unit *u) {
static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
Service *s = SERVICE(u);
ServiceFDStore *fs;
int r;
assert(u);
assert(f);
@ -2056,12 +2068,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good));
if (s->status_text) {
_cleanup_free_ char *c = NULL;
c = cescape(s->status_text);
unit_serialize_item(u, f, "status-text", strempty(c));
}
r = unit_serialize_item_escaped(u, f, "status-text", s->status_text);
if (r < 0)
return r;
/* FIXME: There's a minor uncleanliness here: if there are
* multiple commands attached here, we will start from the
@ -2069,25 +2078,22 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (s->control_command_id >= 0)
unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id));
if (s->socket_fd >= 0) {
int copy;
r = unit_serialize_item_fd(u, f, fds, "stdin-fd", s->stdin_fd);
if (r < 0)
return r;
r = unit_serialize_item_fd(u, f, fds, "stdout-fd", s->stdout_fd);
if (r < 0)
return r;
r = unit_serialize_item_fd(u, f, fds, "stderr-fd", s->stderr_fd);
if (r < 0)
return r;
copy = fdset_put_dup(fds, s->socket_fd);
if (copy < 0)
return copy;
unit_serialize_item_format(u, f, "socket-fd", "%i", copy);
}
if (s->bus_endpoint_fd >= 0) {
int copy;
copy = fdset_put_dup(fds, s->bus_endpoint_fd);
if (copy < 0)
return copy;
unit_serialize_item_format(u, f, "endpoint-fd", "%i", copy);
}
r = unit_serialize_item_fd(u, f, fds, "socket-fd", s->socket_fd);
if (r < 0)
return r;
r = unit_serialize_item_fd(u, f, fds, "endpoint-fd", s->bus_endpoint_fd);
if (r < 0)
return r;
LIST_FOREACH(fd_store, fs, s->fd_store) {
_cleanup_free_ char *c = NULL;
@ -2116,8 +2122,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (dual_timestamp_is_set(&s->watchdog_timestamp))
dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp);
if (s->forbid_restart)
unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
return 0;
}
@ -2288,6 +2293,33 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
log_unit_debug(u, "Failed to parse forbid-restart value: %s", value);
else
s->forbid_restart = b;
} else if (streq(key, "stdin-fd")) {
int fd;
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
log_unit_debug(u, "Failed to parse stdin-fd value: %s", value);
else {
asynchronous_close(s->stdin_fd);
s->stdin_fd = fdset_remove(fds, fd);
}
} else if (streq(key, "stdout-fd")) {
int fd;
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
log_unit_debug(u, "Failed to parse stdout-fd value: %s", value);
else {
asynchronous_close(s->stdout_fd);
s->stdout_fd = fdset_remove(fds, fd);
}
} else if (streq(key, "stderr-fd")) {
int fd;
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
log_unit_debug(u, "Failed to parse stderr-fd value: %s", value);
else {
asynchronous_close(s->stderr_fd);
s->stderr_fd = fdset_remove(fds, fd);
}
} else
log_unit_debug(u, "Unknown serialization key: %s", key);

View File

@ -195,6 +195,10 @@ struct Service {
char *usb_function_descriptors;
char *usb_function_strings;
int stdin_fd;
int stdout_fd;
int stderr_fd;
};
extern const UnitVTable service_vtable;

View File

@ -1505,6 +1505,9 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
.apply_chroot = true,
.apply_tty_stdin = true,
.bus_endpoint_fd = -1,
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
};
assert(s);

View File

@ -597,6 +597,9 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
.apply_chroot = true,
.apply_tty_stdin = true,
.bus_endpoint_fd = -1,
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
};
assert(s);

View File

@ -2624,6 +2624,62 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
return 0;
}
int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
assert(u);
assert(f);
assert(key);
if (!value)
return 0;
fputs(key, f);
fputc('=', f);
fputs(value, f);
fputc('\n', f);
return 1;
}
int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value) {
_cleanup_free_ char *c = NULL;
assert(u);
assert(f);
assert(key);
if (!value)
return 0;
c = cescape(value);
if (!c)
return -ENOMEM;
fputs(key, f);
fputc('=', f);
fputs(c, f);
fputc('\n', f);
return 1;
}
int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd) {
int copy;
assert(u);
assert(f);
assert(key);
if (fd < 0)
return 0;
copy = fdset_put_dup(fds, fd);
if (copy < 0)
return copy;
fprintf(f, "%s=%i\n", key, copy);
return 1;
}
void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) {
va_list ap;
@ -2642,15 +2698,6 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *f
fputc('\n', f);
}
void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
assert(u);
assert(f);
assert(key);
assert(value);
fprintf(f, "%s=%s\n", key, value);
}
int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
ExecRuntime **rt = NULL;
size_t offset;

View File

@ -533,11 +533,15 @@ char *unit_dbus_path(Unit *u);
int unit_load_related_unit(Unit *u, const char *type, Unit **_found);
bool unit_can_serialize(Unit *u) _pure_;
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value);
int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd);
void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
int unit_add_node_link(Unit *u, const char *what, bool wants);
int unit_coldplug(Unit *u);

View File

@ -639,7 +639,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
_cleanup_free_ char *pty_name = NULL;
_cleanup_bus_flush_close_unref_ sd_bus *allocated_bus = NULL;
sd_bus *container_bus = NULL;
_cleanup_close_ int master = -1;
_cleanup_close_ int master = -1, slave = -1;
_cleanup_strv_free_ char **env = NULL, **args = NULL;
Machine *m = userdata;
const char *p, *unit, *user, *path, *description, *utmp_id;
@ -700,8 +700,11 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
return r;
p = path_startswith(pty_name, "/dev/pts/");
if (!p)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
assert(p);
slave = machine_open_terminal(m, pty_name, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (slave < 0)
return slave;
utmp_id = path_startswith(pty_name, "/dev/");
assert(utmp_id);
@ -735,16 +738,14 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
description = strjoina("Shell for User ", isempty(user) ? "root" : user);
r = sd_bus_message_append(tm,
"(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
"(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
"Description", "s", description,
"StandardInput", "s", "tty",
"StandardOutput", "s", "tty",
"StandardError", "s", "tty",
"TTYPath", "s", pty_name,
"StandardInputFileDescriptor", "h", slave,
"StandardOutputFileDescriptor", "h", slave,
"StandardErrorFileDescriptor", "h", slave,
"SendSIGHUP", "b", true,
"IgnoreSIGPIPE", "b", false,
"KillMode", "s", "mixed",
"TTYVHangup", "b", true,
"TTYReset", "b", true,
"UtmpIdentifier", "s", utmp_id,
"UtmpMode", "s", "user",
@ -845,6 +846,8 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
if (r < 0)
return r;
slave = safe_close(slave);
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
return r;

View File

@ -23,6 +23,8 @@
#include "sd-bus.h"
#include "machine.h"
extern const sd_bus_vtable machine_vtable[];
char *machine_bus_path(Machine *s);

View File

@ -19,23 +19,24 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "sd-messages.h"
#include "util.h"
#include "mkdir.h"
#include "hashmap.h"
#include "fileio.h"
#include "special.h"
#include "unit-name.h"
#include "bus-util.h"
#include "bus-error.h"
#include "machine.h"
#include "machine-dbus.h"
#include "bus-util.h"
#include "fileio.h"
#include "formats-util.h"
#include "hashmap.h"
#include "mkdir.h"
#include "special.h"
#include "terminal-util.h"
#include "unit-name.h"
#include "util.h"
#include "machine-dbus.h"
#include "machine.h"
Machine* machine_new(Manager *manager, MachineClass class, const char *name) {
Machine *m;
@ -571,6 +572,25 @@ int machine_openpt(Machine *m, int flags) {
}
}
int machine_open_terminal(Machine *m, const char *path, int mode) {
assert(m);
switch (m->class) {
case MACHINE_HOST:
return open_terminal(path, mode);
case MACHINE_CONTAINER:
if (m->leader <= 0)
return -EINVAL;
return open_terminal_in_namespace(m->leader, path, mode);
default:
return -EOPNOTSUPP;
}
}
MachineOperation *machine_operation_unref(MachineOperation *o) {
if (!o)
return NULL;

View File

@ -123,3 +123,4 @@ const char *kill_who_to_string(KillWho k) _const_;
KillWho kill_who_from_string(const char *s) _pure_;
int machine_openpt(Machine *m, int flags);
int machine_open_terminal(Machine *m, const char *path, int mode);

View File

@ -1390,7 +1390,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, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, machine);
return process_forward(event, &forward, master, 0, machine);
}
static int remove_image(int argc, char *argv[], void *userdata) {

View File

@ -36,6 +36,7 @@
#include "signal-util.h"
#include "spawn-polkit-agent.h"
#include "strv.h"
#include "terminal-util.h"
#include "unit-name.h"
static bool arg_ask_password = true;
@ -62,7 +63,7 @@ static usec_t arg_on_boot = 0;
static usec_t arg_on_startup = 0;
static usec_t arg_on_unit_active = 0;
static usec_t arg_on_unit_inactive = 0;
static char *arg_on_calendar = NULL;
static const char *arg_on_calendar = NULL;
static char **arg_timer_property = NULL;
static bool arg_quiet = false;
@ -181,7 +182,6 @@ static int parse_argv(int argc, char *argv[]) {
};
int r, c;
CalendarSpec *spec = NULL;
assert(argc >= 0);
assert(argv);
@ -335,16 +335,19 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_ON_CALENDAR:
case ARG_ON_CALENDAR: {
CalendarSpec *spec = NULL;
r = calendar_spec_from_string(optarg, &spec);
if (r < 0) {
log_error("Invalid calendar spec: %s", optarg);
return r;
}
free(spec);
calendar_spec_free(spec);
arg_on_calendar = optarg;
break;
}
case ARG_TIMER_PROPERTY:
@ -389,6 +392,11 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
if (arg_pty && arg_transport == BUS_TRANSPORT_REMOTE) {
log_error("--pty is only supported when connecting to the local system or containers.");
return -EINVAL;
}
if (arg_scope && with_timer()) {
log_error("Timer options are not supported in --scope mode.");
return -EINVAL;
@ -707,9 +715,9 @@ static int start_transient_service(
_cleanup_bus_unref_ sd_bus *system_bus = NULL;
const char *s;
r = sd_bus_open_system(&system_bus);
r = sd_bus_default_system(&system_bus);
if (r < 0)
log_error_errno(r, "Failed to connect to system bus: %m");
return log_error_errno(r, "Failed to connect to system bus: %m");
r = sd_bus_call_method(system_bus,
"org.freedesktop.machine1",
@ -794,10 +802,8 @@ static int start_transient_service(
polkit_agent_open_if_enabled();
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
log_error("Failed to start transient service unit: %s", bus_error_message(&error, -r));
return r;
}
if (r < 0)
return log_error_errno(r, "Failed to start transient service unit: %s", bus_error_message(&error, r));
if (w) {
const char *object;

View File

@ -315,6 +315,10 @@ static int parse_password(const char *filename, char **wall) {
tty_fd = acquire_terminal("/dev/console", false, false, false, USEC_INFINITY);
if (tty_fd < 0)
return log_error_errno(tty_fd, "Failed to acquire /dev/console: %m");
r = reset_terminal_fd(tty_fd, true);
if (r < 0)
log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
}
r = ask_password_tty(message, NULL, not_after, echo ? ASK_PASSWORD_ECHO : 0, filename, &password);