core: add support for setting stdin/stdout/stderr for transient services
When starting a transient service, allow setting stdin/stdout/stderr fds for it, by passing them in via the bus. This also simplifies some of the serialization code for units.
This commit is contained in:
parent
66cb2fde7b
commit
a34ceba66f
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
@ -1324,6 +1364,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 +1417,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 +1456,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 +1512,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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue