Merge pull request #5600 from fbuihuu/make-logind-restartable

Make logind restartable.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2017-06-24 18:58:36 -04:00 committed by GitHub
commit 7e867138f5
14 changed files with 329 additions and 84 deletions

View file

@ -782,15 +782,14 @@
<varlistentry>
<term><varname>NonBlocking=</varname></term>
<listitem><para>Set the <constant>O_NONBLOCK</constant> flag
for all file descriptors passed via socket-based activation.
If true, all file descriptors >= 3 (i.e. all except stdin,
stdout, and stderr) will have the
<constant>O_NONBLOCK</constant> flag set and hence are in
non-blocking mode. This option is only useful in conjunction
with a socket unit, as described in
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
Defaults to false.</para></listitem>
<listitem><para>Set the <constant>O_NONBLOCK</constant> flag for all file descriptors passed via socket-based
activation. If true, all file descriptors >= 3 (i.e. all except stdin, stdout, stderr), excluding those passed
in via the file descriptor storage logic (see <varname>FileDescriptorStoreMax=</varname> for details), will
have the <constant>O_NONBLOCK</constant> flag set and hence are in non-blocking mode. This option is only
useful in conjunction with a socket unit, as described in
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry> and has no
effect on file descriptors which were previously saved in the file-descriptor store for example. Defaults to
false.</para></listitem>
</varlistentry>
<varlistentry>

View file

@ -589,3 +589,18 @@ int parse_ip_port(const char *s, uint16_t *ret) {
return 0;
}
int parse_dev(const char *s, dev_t *ret) {
unsigned x, y;
dev_t d;
if (sscanf(s, "%u:%u", &x, &y) != 2)
return -EINVAL;
d = makedev(x, y);
if ((unsigned) major(d) != x || (unsigned) minor(d) != y)
return -EINVAL;
*ret = d;
return 0;
}

View file

@ -30,6 +30,7 @@
#define MODE_INVALID ((mode_t) -1)
int parse_boolean(const char *v) _pure_;
int parse_dev(const char *s, dev_t *ret);
int parse_pid(const char *s, pid_t* ret_pid);
int parse_mode(const char *s, mode_t *ret);
int parse_ifindex(const char *s, int *ret);

View file

@ -157,22 +157,26 @@ static int shift_fds(int fds[], unsigned n_fds) {
return 0;
}
static int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
unsigned i;
static int flags_fds(const int fds[], unsigned n_storage_fds, unsigned n_socket_fds, bool nonblock) {
unsigned i, n_fds;
int r;
n_fds = n_storage_fds + n_socket_fds;
if (n_fds <= 0)
return 0;
assert(fds);
/* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
/* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags.
* O_NONBLOCK only applies to socket activation though. */
for (i = 0; i < n_fds; i++) {
r = fd_nonblock(fds[i], nonblock);
if (r < 0)
return r;
if (i < n_socket_fds) {
r = fd_nonblock(fds[i], nonblock);
if (r < 0)
return r;
}
/* We unconditionally drop FD_CLOEXEC from the fds,
* since after all we want to pass these fds to our
@ -2241,7 +2245,9 @@ static int exec_child(
char **argv,
int socket_fd,
int named_iofds[3],
int *fds, unsigned n_fds,
int *fds,
unsigned n_storage_fds,
unsigned n_socket_fds,
char **files_env,
int user_lookup_fd,
int *exit_status,
@ -2258,6 +2264,7 @@ static int exec_child(
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
int i, r, ngids = 0;
unsigned n_fds;
assert(unit);
assert(command);
@ -2298,6 +2305,7 @@ static int exec_child(
log_forget_fds();
n_fds = n_storage_fds + n_socket_fds;
r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_FDS;
@ -2669,7 +2677,7 @@ static int exec_child(
if (r >= 0)
r = shift_fds(fds, n_fds);
if (r >= 0)
r = flags_fds(fds, n_fds, context->non_blocking);
r = flags_fds(fds, n_storage_fds, n_socket_fds, context->non_blocking);
if (r < 0) {
*exit_status = EXIT_FDS;
return r;
@ -2909,7 +2917,8 @@ int exec_spawn(Unit *unit,
pid_t *ret) {
_cleanup_strv_free_ char **files_env = NULL;
int *fds = NULL; unsigned n_fds = 0;
int *fds = NULL;
unsigned n_storage_fds = 0, n_socket_fds = 0;
_cleanup_free_ char *line = NULL;
int socket_fd, r;
int named_iofds[3] = { -1, -1, -1 };
@ -2921,18 +2930,18 @@ int exec_spawn(Unit *unit,
assert(context);
assert(ret);
assert(params);
assert(params->fds || params->n_fds <= 0);
assert(params->fds || (params->n_storage_fds + params->n_socket_fds <= 0));
if (context->std_input == EXEC_INPUT_SOCKET ||
context->std_output == EXEC_OUTPUT_SOCKET ||
context->std_error == EXEC_OUTPUT_SOCKET) {
if (params->n_fds > 1) {
if (params->n_socket_fds > 1) {
log_unit_error(unit, "Got more than one socket.");
return -EINVAL;
}
if (params->n_fds == 0) {
if (params->n_socket_fds == 0) {
log_unit_error(unit, "Got no socket.");
return -EINVAL;
}
@ -2941,7 +2950,8 @@ int exec_spawn(Unit *unit,
} else {
socket_fd = -1;
fds = params->fds;
n_fds = params->n_fds;
n_storage_fds = params->n_storage_fds;
n_socket_fds = params->n_socket_fds;
}
r = exec_context_named_iofds(unit, context, params, named_iofds);
@ -2979,7 +2989,9 @@ int exec_spawn(Unit *unit,
argv,
socket_fd,
named_iofds,
fds, n_fds,
fds,
n_storage_fds,
n_socket_fds,
files_env,
unit->manager->user_lookup_fds[1],
&exit_status,
@ -3188,6 +3200,7 @@ const char* exec_context_fdname(const ExecContext *c, int fd_index) {
int exec_context_named_iofds(Unit *unit, const ExecContext *c, const ExecParameters *p, int named_iofds[3]) {
unsigned i, targets;
const char* stdio_fdname[3];
unsigned n_fds;
assert(c);
assert(p);
@ -3199,7 +3212,9 @@ int exec_context_named_iofds(Unit *unit, const ExecContext *c, const ExecParamet
for (i = 0; i < 3; i++)
stdio_fdname[i] = exec_context_fdname(c, i);
for (i = 0; i < p->n_fds && targets > 0; i++)
n_fds = p->n_storage_fds + p->n_socket_fds;
for (i = 0; i < n_fds && targets > 0; i++)
if (named_iofds[STDIN_FILENO] < 0 &&
c->std_input == EXEC_INPUT_NAMED_FD &&
stdio_fdname[STDIN_FILENO] &&

View file

@ -246,7 +246,8 @@ struct ExecParameters {
int *fds;
char **fd_names;
unsigned n_fds;
unsigned n_storage_fds;
unsigned n_socket_fds;
ExecFlags flags;
bool selinux_context_net:1;

View file

@ -1068,14 +1068,21 @@ static int service_coldplug(Unit *u) {
return 0;
}
static int service_collect_fds(Service *s, int **fds, char ***fd_names) {
static int service_collect_fds(Service *s,
int **fds,
char ***fd_names,
unsigned *n_storage_fds,
unsigned *n_socket_fds) {
_cleanup_strv_free_ char **rfd_names = NULL;
_cleanup_free_ int *rfds = NULL;
int rn_fds = 0, r;
unsigned rn_socket_fds = 0, rn_storage_fds = 0;
int r;
assert(s);
assert(fds);
assert(fd_names);
assert(n_socket_fds);
if (s->socket_fd >= 0) {
@ -1090,7 +1097,7 @@ static int service_collect_fds(Service *s, int **fds, char ***fd_names) {
if (!rfd_names)
return -ENOMEM;
rn_fds = 1;
rn_socket_fds = 1;
} else {
Iterator i;
Unit *u;
@ -1116,20 +1123,20 @@ static int service_collect_fds(Service *s, int **fds, char ***fd_names) {
if (!rfds) {
rfds = cfds;
rn_fds = cn_fds;
rn_socket_fds = cn_fds;
cfds = NULL;
} else {
int *t;
t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int));
t = realloc(rfds, (rn_socket_fds + cn_fds) * sizeof(int));
if (!t)
return -ENOMEM;
memcpy(t + rn_fds, cfds, cn_fds * sizeof(int));
memcpy(t + rn_socket_fds, cfds, cn_fds * sizeof(int));
rfds = t;
rn_fds += cn_fds;
rn_socket_fds += cn_fds;
}
r = strv_extend_n(&rfd_names, socket_fdname(sock), cn_fds);
@ -1140,40 +1147,45 @@ static int service_collect_fds(Service *s, int **fds, char ***fd_names) {
if (s->n_fd_store > 0) {
ServiceFDStore *fs;
unsigned n_fds;
char **nl;
int *t;
t = realloc(rfds, (rn_fds + s->n_fd_store) * sizeof(int));
t = realloc(rfds, (rn_socket_fds + s->n_fd_store) * sizeof(int));
if (!t)
return -ENOMEM;
rfds = t;
nl = realloc(rfd_names, (rn_fds + s->n_fd_store + 1) * sizeof(char*));
nl = realloc(rfd_names, (rn_socket_fds + s->n_fd_store + 1) * sizeof(char*));
if (!nl)
return -ENOMEM;
rfd_names = nl;
n_fds = rn_socket_fds;
LIST_FOREACH(fd_store, fs, s->fd_store) {
rfds[rn_fds] = fs->fd;
rfd_names[rn_fds] = strdup(strempty(fs->fdname));
if (!rfd_names[rn_fds])
rfds[n_fds] = fs->fd;
rfd_names[n_fds] = strdup(strempty(fs->fdname));
if (!rfd_names[n_fds])
return -ENOMEM;
rn_fds++;
rn_storage_fds++;
n_fds++;
}
rfd_names[rn_fds] = NULL;
rfd_names[n_fds] = NULL;
}
*fds = rfds;
*fd_names = rfd_names;
*n_socket_fds = rn_socket_fds;
*n_storage_fds = rn_storage_fds;
rfds = NULL;
rfd_names = NULL;
return rn_fds;
return 0;
}
static bool service_exec_needs_notify_socket(Service *s, ExecFlags flags) {
@ -1204,7 +1216,7 @@ static int service_spawn(
_cleanup_strv_free_ char **final_env = NULL, **our_env = NULL, **fd_names = NULL;
_cleanup_free_ int *fds = NULL;
unsigned n_fds = 0, n_env = 0;
unsigned n_storage_fds = 0, n_socket_fds = 0, n_env = 0;
const char *path;
pid_t pid;
@ -1248,12 +1260,11 @@ static int service_spawn(
s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
r = service_collect_fds(s, &fds, &fd_names);
r = service_collect_fds(s, &fds, &fd_names, &n_storage_fds, &n_socket_fds);
if (r < 0)
return r;
n_fds = r;
log_unit_debug(UNIT(s), "Passing %i fds to service", n_fds);
log_unit_debug(UNIT(s), "Passing %i fds to service", n_storage_fds + n_socket_fds);
}
r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), timeout));
@ -1347,7 +1358,8 @@ static int service_spawn(
exec_params.environment = final_env;
exec_params.fds = fds;
exec_params.fd_names = fd_names;
exec_params.n_fds = n_fds;
exec_params.n_storage_fds = n_storage_fds;
exec_params.n_socket_fds = n_socket_fds;
exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(s)->manager);
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
exec_params.cgroup_path = path;

View file

@ -396,7 +396,7 @@ static int method_take_control(sd_bus_message *message, void *userdata, sd_bus_e
if (uid != 0 && (force || uid != s->user->uid))
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
r = session_set_controller(s, sd_bus_message_get_sender(message), force);
r = session_set_controller(s, sd_bus_message_get_sender(message), force, true);
if (r < 0)
return r;
@ -444,14 +444,23 @@ static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_er
* equivalent). */
return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
r = session_device_new(s, dev, &sd);
r = session_device_new(s, dev, true, &sd);
if (r < 0)
return r;
r = session_device_save(sd);
if (r < 0)
goto error;
r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active);
if (r < 0)
session_device_free(sd);
goto error;
session_save(s);
return 0;
error:
session_device_free(sd);
return r;
}
@ -478,6 +487,8 @@ static int method_release_device(sd_bus_message *message, void *userdata, sd_bus
return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
session_device_free(sd);
session_save(s);
return sd_bus_reply_method_return(message, NULL);
}

View file

@ -30,6 +30,8 @@
#include "fd-util.h"
#include "logind-session-device.h"
#include "missing.h"
#include "parse-util.h"
#include "sd-daemon.h"
#include "util.h"
enum SessionDeviceNotifications {
@ -206,7 +208,10 @@ static int session_device_start(SessionDevice *sd) {
r = session_device_open(sd, true);
if (r < 0)
return r;
close_nointr(sd->fd);
/* For evdev devices, the file descriptor might be left
* uninitialized. This might happen while resuming into a
* session and logind has been restarted right before. */
safe_close(sd->fd);
sd->fd = r;
break;
case DEVICE_TYPE_UNKNOWN:
@ -341,7 +346,7 @@ err_dev:
return r;
}
int session_device_new(Session *s, dev_t dev, SessionDevice **out) {
int session_device_new(Session *s, dev_t dev, bool open_device, SessionDevice **out) {
SessionDevice *sd;
int r;
@ -370,22 +375,24 @@ int session_device_new(Session *s, dev_t dev, SessionDevice **out) {
goto error;
}
/* Open the device for the first time. We need a valid fd to pass back
* to the caller. If the session is not active, this _might_ immediately
* revoke access and thus invalidate the fd. But this is still needed
* to pass a valid fd back. */
sd->active = session_is_active(s);
r = session_device_open(sd, sd->active);
if (r < 0) {
/* EINVAL _may_ mean a master is active; retry inactive */
if (sd->active && r == -EINVAL) {
sd->active = false;
r = session_device_open(sd, false);
if (open_device) {
/* Open the device for the first time. We need a valid fd to pass back
* to the caller. If the session is not active, this _might_ immediately
* revoke access and thus invalidate the fd. But this is still needed
* to pass a valid fd back. */
sd->active = session_is_active(s);
r = session_device_open(sd, sd->active);
if (r < 0) {
/* EINVAL _may_ mean a master is active; retry inactive */
if (sd->active && r == -EINVAL) {
sd->active = false;
r = session_device_open(sd, false);
}
if (r < 0)
goto error;
}
if (r < 0)
goto error;
sd->fd = r;
}
sd->fd = r;
LIST_PREPEND(sd_by_device, sd->device->session_devices, sd);
@ -435,15 +442,16 @@ void session_device_complete_pause(SessionDevice *sd) {
void session_device_resume_all(Session *s) {
SessionDevice *sd;
Iterator i;
int r;
assert(s);
HASHMAP_FOREACH(sd, s->devices, i) {
if (!sd->active) {
r = session_device_start(sd);
if (!r)
session_device_notify(sd, SESSION_DEVICE_RESUME);
if (session_device_start(sd) < 0)
continue;
if (session_device_save(sd) < 0)
continue;
session_device_notify(sd, SESSION_DEVICE_RESUME);
}
}
}
@ -478,3 +486,36 @@ unsigned int session_device_try_pause_all(Session *s) {
return num_pending;
}
int session_device_save(SessionDevice *sd) {
_cleanup_free_ char *state = NULL;
int r;
assert(sd);
/* Store device fd in PID1. It will send it back to us on
* restart so revocation will continue to work. To make things
* simple, send fds for all type of devices even if they don't
* support the revocation mechanism so we don't have to handle
* them differently later.
*
* Note: for device supporting revocation, PID1 will drop a
* stored fd automatically if the corresponding device is
* revoked. */
r = asprintf(&state, "FDSTORE=1\n"
"FDNAME=session-%s", sd->session->id);
if (r < 0)
return -ENOMEM;
return sd_pid_notify_with_fds(0, false, state, &sd->fd, 1);
}
void session_device_attach_fd(SessionDevice *sd, int fd, bool active) {
assert(fd > 0);
assert(sd);
assert(sd->fd < 0);
assert(!sd->active);
sd->fd = fd;
sd->active = active;
}

View file

@ -44,10 +44,13 @@ struct SessionDevice {
LIST_FIELDS(struct SessionDevice, sd_by_device);
};
int session_device_new(Session *s, dev_t dev, SessionDevice **out);
int session_device_new(Session *s, dev_t dev, bool open_device, SessionDevice **out);
void session_device_free(SessionDevice *sd);
void session_device_complete_pause(SessionDevice *sd);
void session_device_resume_all(Session *s);
void session_device_pause_all(Session *s);
unsigned int session_device_try_pause_all(Session *s);
int session_device_save(SessionDevice *sd);
void session_device_attach_fd(SessionDevice *sd, int fd, bool active);

View file

@ -152,6 +152,18 @@ void session_set_user(Session *s, User *u) {
LIST_PREPEND(sessions_by_user, u->sessions, s);
}
static void session_save_devices(Session *s, FILE *f) {
SessionDevice *sd;
Iterator i;
if (!hashmap_isempty(s->devices)) {
fprintf(f, "DEVICES=");
HASHMAP_FOREACH(sd, s->devices, i)
fprintf(f, "%u:%u ", major(sd->dev), minor(sd->dev));
fprintf(f, "\n");
}
}
int session_save(Session *s) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
@ -281,8 +293,10 @@ int session_save(Session *s) {
s->timestamp.realtime,
s->timestamp.monotonic);
if (s->controller)
if (s->controller) {
fprintf(f, "CONTROLLER=%s\n", s->controller);
session_save_devices(s, f);
}
r = fflush_and_check(f);
if (r < 0)
@ -304,6 +318,43 @@ fail:
return log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
}
static int session_load_devices(Session *s, const char *devices) {
const char *p;
int r = 0;
assert(s);
for (p = devices;;) {
_cleanup_free_ char *word = NULL;
SessionDevice *sd;
dev_t dev;
int k;
k = extract_first_word(&p, &word, NULL, 0);
if (k == 0)
break;
if (k < 0) {
r = k;
break;
}
k = parse_dev(word, &dev);
if (k < 0) {
r = k;
continue;
}
/* The file descriptors for loaded devices will be reattached later. */
k = session_device_new(s, dev, false, &sd);
if (k < 0)
r = k;
}
if (r < 0)
log_error_errno(r, "Loading session devices for session %s failed: %m", s->id);
return r;
}
int session_load(Session *s) {
_cleanup_free_ char *remote = NULL,
@ -317,7 +368,9 @@ int session_load(Session *s) {
*uid = NULL,
*realtime = NULL,
*monotonic = NULL,
*controller = NULL;
*controller = NULL,
*active = NULL,
*devices = NULL;
int k, r;
@ -345,6 +398,8 @@ int session_load(Session *s) {
"REALTIME", &realtime,
"MONOTONIC", &monotonic,
"CONTROLLER", &controller,
"ACTIVE", &active,
"DEVICES", &devices,
NULL);
if (r < 0)
@ -447,10 +502,17 @@ int session_load(Session *s) {
if (monotonic)
timestamp_deserialize(monotonic, &s->timestamp.monotonic);
if (active) {
k = parse_boolean(active);
if (k >= 0)
s->was_active = k;
}
if (controller) {
if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
session_set_controller(s, controller, false);
else
if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) {
session_set_controller(s, controller, false, false);
session_load_devices(s, devices);
} else
session_restore_vt(s);
}
@ -1170,7 +1232,7 @@ static int on_bus_track(sd_bus_track *track, void *userdata) {
return 0;
}
int session_set_controller(Session *s, const char *sender, bool force) {
int session_set_controller(Session *s, const char *sender, bool force, bool prepare) {
_cleanup_free_ char *name = NULL;
int r;
@ -1202,11 +1264,14 @@ int session_set_controller(Session *s, const char *sender, bool force) {
* Note that we reset the VT on ReleaseControl() and if the controller
* exits.
* If logind crashes/restarts, we restore the controller during restart
* or reset the VT in case it crashed/exited, too. */
r = session_prepare_vt(s);
if (r < 0) {
s->track = sd_bus_track_unref(s->track);
return r;
* (without preparing the VT since the controller has probably overridden
* VT state by now) or reset the VT in case it crashed/exited, too. */
if (prepare) {
r = session_prepare_vt(s);
if (r < 0) {
s->track = sd_bus_track_unref(s->track);
return r;
}
}
session_release_controller(s, true);

View file

@ -111,6 +111,8 @@ struct Session {
bool started:1;
bool stopping:1;
bool was_active:1;
sd_bus_message *create_message;
sd_event_source *timer_event_source;
@ -176,7 +178,7 @@ void session_restore_vt(Session *s);
void session_leave_vt(Session *s);
bool session_is_controller(Session *s, const char *sender);
int session_set_controller(Session *s, const char *sender, bool force);
int session_set_controller(Session *s, const char *sender, bool force, bool prepare);
void session_drop_controller(Session *s);
int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_error *error);

View file

@ -409,10 +409,71 @@ static int manager_enumerate_users(Manager *m) {
return r;
}
static int manager_attach_fds(Manager *m) {
_cleanup_strv_free_ char **fdnames = NULL;
int n, i, fd;
/* Upon restart, PID1 will send us back all fds of session devices
* that we previously opened. Each file descriptor is associated
* with a given session. The session ids are passed through FDNAMES. */
n = sd_listen_fds_with_names(true, &fdnames);
if (n <= 0)
return n;
for (i = 0; i < n; i++) {
struct stat st;
SessionDevice *sd;
Session *s;
char *id;
fd = SD_LISTEN_FDS_START + i;
id = startswith(fdnames[i], "session-");
if (!id)
continue;
s = hashmap_get(m->sessions, id);
if (!s) {
/* If the session doesn't exist anymore, the associated session
* device attached to this fd doesn't either. Let's simply close
* this fd. */
log_debug("Failed to attach fd for unknown session: %s", id);
close_nointr(fd);
continue;
}
if (fstat(fd, &st) < 0) {
/* The device is allowed to go away at a random point, in which
* case fstat failing is expected. */
log_debug_errno(errno, "Failed to stat device fd for session %s: %m", id);
close_nointr(fd);
continue;
}
sd = hashmap_get(s->devices, &st.st_rdev);
if (!sd) {
/* Weird we got an fd for a session device which wasn't
* recorded in the session state file... */
log_warning("Got fd for missing session device [%u:%u] in session %s",
major(st.st_rdev), minor(st.st_rdev), s->id);
close_nointr(fd);
continue;
}
log_debug("Attaching fd to session device [%u:%u] for session %s",
major(st.st_rdev), minor(st.st_rdev), s->id);
session_device_attach_fd(sd, fd, s->was_active);
}
return 0;
}
static int manager_enumerate_sessions(Manager *m) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
int r = 0;
int r = 0, k;
assert(m);
@ -427,7 +488,6 @@ static int manager_enumerate_sessions(Manager *m) {
FOREACH_DIRENT(de, d, return -errno) {
struct Session *s;
int k;
if (!dirent_is_file(de))
continue;
@ -441,7 +501,6 @@ static int manager_enumerate_sessions(Manager *m) {
k = manager_add_session(m, de->d_name, &s);
if (k < 0) {
log_error_errno(k, "Failed to add session by file name %s: %m", de->d_name);
r = k;
continue;
}
@ -453,6 +512,12 @@ static int manager_enumerate_sessions(Manager *m) {
r = k;
}
/* We might be restarted and PID1 could have sent us back the
* session device fds we previously saved. */
k = manager_attach_fds(m);
if (k < 0)
log_warning_errno(k, "Failed to reattach session device fds: %m");
return r;
}

View file

@ -593,6 +593,19 @@ static void test_parse_nice(void) {
assert_se(parse_nice("+20", &n) == -ERANGE);
}
static void test_parse_dev(void) {
dev_t dev;
assert_se(parse_dev("0", &dev) == -EINVAL);
assert_se(parse_dev("5", &dev) == -EINVAL);
assert_se(parse_dev("5:", &dev) == -EINVAL);
assert_se(parse_dev(":5", &dev) == -EINVAL);
#if SIZEOF_DEV_T < 8
assert_se(parse_dev("4294967295:4294967295", &dev) == -EINVAL);
#endif
assert_se(parse_dev("8:11", &dev) >= 0 && major(dev) == 8 && minor(dev) == 11);
}
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
@ -611,6 +624,7 @@ int main(int argc, char *argv[]) {
test_parse_percent();
test_parse_percent_unbounded();
test_parse_nice();
test_parse_dev();
return 0;
}

View file

@ -31,6 +31,7 @@ RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
SystemCallFilter=~@clock @cpu-emulation @debug @keyring @module @obsolete @raw-io @reboot @swap
SystemCallArchitectures=native
FileDescriptorStoreMax=512
# Increase the default a bit in order to allow many simultaneous
# logins since we keep one fd open per session.