Compare commits

...

5 Commits

Author SHA1 Message Date
Dan Streetman cad6727906 test: find path for systemd-journal-remote
As Debian/Ubuntu use /lib/systemd instead of /usr/lib/systemd,
add systemd-journal-remote to the list of programs that test-functions
detects the correct path to, and replace its direct usage with
$SYSTEMD_JOURNAL_REMOTE

Also use $JOURNALCTL instead of journalctl.

Also minor correction in install_plymouth() to look in /lib/... as
well as /usr/lib/... and /etc/...
2020-04-30 22:33:47 +02:00
Lennart Poettering a8332698d7
Merge pull request #15592 from kennylevinsen/fdpoll-standalone
Introduce FDPOLL=0
2020-04-30 22:32:28 +02:00
Corey Hinshaw db72aea4a9 Add SetType method to login Session interface 2020-04-30 21:29:26 +02:00
Kenny Levinsen 3052049260 core: (De-)Serialize poll flag for fds in fdstore
This replaces manual string splitting and unescaping with
extract_first_word.
2020-04-30 19:42:53 +02:00
Kenny Levinsen cb5a46b845 core: Add optional FDPOLL=0 argument to fdstore
A service can specify FDSTORE=1 FDPOLL=0 to request that PID1 does not
poll the fd to remove them on error. If set, fds will only be removed on
FDSTOREREMOVE=1 or when the service is done.

Fixes: #12086
2020-04-30 19:42:26 +02:00
9 changed files with 126 additions and 39 deletions

View File

@ -219,8 +219,8 @@
in a <citerefentry><refentrytitle>memfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry> memory
file descriptor. Note that the service manager will accept messages for a service only if its
<varname>FileDescriptorStoreMax=</varname> setting is non-zero (defaults to zero, see
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>). If file
descriptors sent are pollable (see
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>). If
<varname>FDPOLL=0</varname> is not set and the file descriptors sent are pollable (see
<citerefentry><refentrytitle>epoll_ctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>), then any
<constant>EPOLLHUP</constant> or <constant>EPOLLERR</constant> event seen on them will result in their
automatic removal from the store. Multiple arrays of file descriptors may be sent in separate messages, in
@ -251,6 +251,16 @@
submitted name does not follow these restrictions, it is ignored.</para></listitem>
</varlistentry>
<varlistentry>
<term>FDPOLL=0</term>
<listitem><para>When used in combination with <varname>FDSTORE=1</varname>, disables polling of the stored
file descriptors regardless of whether or not they are pollable. As this option disables automatic cleanup
of the stored file descriptors on EPOLLERR and EPOLLHUP, care must be taken to ensure proper manual cleanup.
Use of this option is not generally recommended except for when automatic cleanup has unwanted behavior such
as prematurely discarding file descriptors from the store.</para></listitem>
</varlistentry>
</variablelist>
<para>It is recommended to prefix variable names that are not

View File

@ -423,7 +423,7 @@ static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *us
return 0;
}
static int service_add_fd_store(Service *s, int fd, const char *name) {
static int service_add_fd_store(Service *s, int fd, const char *name, bool do_poll) {
ServiceFDStore *fs;
int r;
@ -453,19 +453,22 @@ static int service_add_fd_store(Service *s, int fd, const char *name) {
fs->fd = fd;
fs->service = s;
fs->do_poll = do_poll;
fs->fdname = strdup(name ?: "stored");
if (!fs->fdname) {
free(fs);
return -ENOMEM;
}
r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
if (r < 0 && r != -EPERM) { /* EPERM indicates fds that aren't pollable, which is OK */
free(fs->fdname);
free(fs);
return r;
} else if (r >= 0)
(void) sd_event_source_set_description(fs->event_source, "service-fd-store");
if (do_poll) {
r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
if (r < 0 && r != -EPERM) { /* EPERM indicates fds that aren't pollable, which is OK */
free(fs->fdname);
free(fs);
return r;
} else if (r >= 0)
(void) sd_event_source_set_description(fs->event_source, "service-fd-store");
}
LIST_PREPEND(fd_store, s->fd_store, fs);
s->n_fd_store++;
@ -473,7 +476,7 @@ static int service_add_fd_store(Service *s, int fd, const char *name) {
return 1; /* fd newly stored */
}
static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name, bool do_poll) {
int r;
assert(s);
@ -485,7 +488,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
if (fd < 0)
break;
r = service_add_fd_store(s, fd, name);
r = service_add_fd_store(s, fd, name, do_poll);
if (r == -EXFULL)
return log_unit_warning_errno(UNIT(s), r,
"Cannot store more fds than FileDescriptorStoreMax=%u, closing remaining.",
@ -2715,7 +2718,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (!c)
return log_oom();
(void) serialize_item_format(f, "fd-store-fd", "%i %s", copy, c);
(void) serialize_item_format(f, "fd-store-fd", "%i \"%s\" %i", copy, c, fs->do_poll);
}
if (s->main_exec_status.pid > 0) {
@ -2944,30 +2947,36 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
s->socket_fd = fdset_remove(fds, fd);
}
} else if (streq(key, "fd-store-fd")) {
const char *fdv;
size_t pf;
_cleanup_free_ char *fdv = NULL, *fdn = NULL, *fdp = NULL;
int fd;
int do_poll;
pf = strcspn(value, WHITESPACE);
fdv = strndupa(value, pf);
if (safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
r = extract_first_word(&value, &fdv, NULL, 0);
if (r <= 0 || safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) {
log_unit_debug(u, "Failed to parse fd-store-fd value: %s", value);
else {
_cleanup_free_ char *t = NULL;
const char *fdn;
fdn = value + pf;
fdn += strspn(fdn, WHITESPACE);
(void) cunescape(fdn, 0, &t);
r = service_add_fd_store(s, fd, t);
if (r < 0)
log_unit_error_errno(u, r, "Failed to add fd to store: %m");
else
fdset_remove(fds, fd);
return 0;
}
r = extract_first_word(&value, &fdn, NULL, EXTRACT_CUNESCAPE | EXTRACT_UNQUOTE);
if (r <= 0) {
log_unit_debug_errno(u, r, "Failed to parse fd-store-fd value \"%s\": %m", value);
return 0;
}
r = extract_first_word(&value, &fdp, NULL, 0);
if (r == 0) {
/* If the value is not present, we assume the default */
do_poll = 1;
} else if (r < 0 || safe_atoi(fdp, &do_poll) < 0) {
log_unit_debug_errno(u, r, "Failed to parse fd-store-fd value \"%s\": %m", value);
return 0;
}
r = service_add_fd_store(s, fd, fdn, do_poll);
if (r < 0)
log_unit_error_errno(u, r, "Failed to add fd to store: %m");
else
fdset_remove(fds, fd);
} else if (streq(key, "main-exec-status-pid")) {
pid_t pid;
@ -4068,7 +4077,7 @@ static void service_notify_message(
name = NULL;
}
(void) service_add_fd_store_set(s, fds, name);
(void) service_add_fd_store_set(s, fds, name, !strv_contains(tags, "FDPOLL=0"));
}
/* Notify clients about changed status or main pid */

View File

@ -80,6 +80,7 @@ struct ServiceFDStore {
int fd;
char *fdname;
sd_event_source *event_source;
bool do_poll;
LIST_FIELDS(ServiceFDStore, fd_store);
};

View File

@ -885,7 +885,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
if (r < 0)
goto fail;
session->type = t;
session->original_type = session->type = t;
session->class = c;
session->remote = remote;
session->vtnr = vtnr;

View File

@ -393,6 +393,32 @@ static int method_release_control(sd_bus_message *message, void *userdata, sd_bu
return sd_bus_reply_method_return(message, NULL);
}
static int method_set_type(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
const char *t;
SessionType type;
int r;
assert(message);
assert(s);
r = sd_bus_message_read(message, "s", &t);
if (r < 0)
return r;
type = session_type_from_string(t);
if (type < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Invalid session type '%s'", t);
if (!session_is_controller(s, sd_bus_message_get_sender(message)))
return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You must be in control of this session to set type");
session_set_type(s, type);
return sd_bus_reply_method_return(message, NULL);
}
static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
uint32_t major, minor;
@ -574,7 +600,7 @@ const sd_bus_vtable session_vtable[] = {
SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("State", "s", property_get_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@ -633,6 +659,12 @@ const sd_bus_vtable session_vtable[] = {
NULL,
method_release_control,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_NAMES("SetType",
"s",
SD_BUS_PARAM(type),
NULL,,
method_set_type,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_NAMES("TakeDevice",
"uu",
SD_BUS_PARAM(major)

View File

@ -240,6 +240,9 @@ int session_save(Session *s) {
if (s->type >= 0)
fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
if (s->original_type >= 0)
fprintf(f, "ORIGINAL_TYPE=%s\n", session_type_to_string(s->original_type));
if (s->class >= 0)
fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
@ -402,6 +405,7 @@ int session_load(Session *s) {
*position = NULL,
*leader = NULL,
*type = NULL,
*original_type = NULL,
*class = NULL,
*uid = NULL,
*realtime = NULL,
@ -433,6 +437,7 @@ int session_load(Session *s) {
"POSITION", &position,
"LEADER", &leader,
"TYPE", &type,
"ORIGINAL_TYPE", &original_type,
"CLASS", &class,
"UID", &uid,
"REALTIME", &realtime,
@ -529,6 +534,16 @@ int session_load(Session *s) {
s->type = t;
}
if (original_type) {
SessionType ot;
ot = session_type_from_string(original_type);
if (ot >= 0)
s->original_type = ot;
} else
/* Pre-v246 compat: initialize original_type if not set in the state file */
s->original_type = s->type;
if (class) {
SessionClass c;
@ -1018,6 +1033,18 @@ void session_set_locked_hint(Session *s, bool b) {
session_send_changed(s, "LockedHint", NULL);
}
void session_set_type(Session *s, SessionType t) {
assert(s);
if (s->type == t)
return;
s->type = t;
session_save(s);
session_send_changed(s, "Type", NULL);
}
static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
Session *s = userdata;
@ -1385,6 +1412,7 @@ void session_drop_controller(Session *s) {
return;
s->track = sd_bus_track_unref(s->track);
session_set_type(s, s->original_type);
session_release_controller(s, false);
session_save(s);
session_restore_vt(s);

View File

@ -61,6 +61,7 @@ struct Session {
const char *id;
unsigned position;
SessionType type;
SessionType original_type;
SessionClass class;
char *state_file;
@ -135,6 +136,7 @@ int session_get_idle_hint(Session *s, dual_timestamp *t);
int session_set_idle_hint(Session *s, bool b);
int session_get_locked_hint(Session *s);
void session_set_locked_hint(Session *s, bool b);
void session_set_type(Session *s, SessionType t);
int session_create_fifo(Session *s);
int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error);
int session_stop(Session *s, bool force);

View File

@ -290,6 +290,10 @@
send_interface="org.freedesktop.login1.Session"
send_member="ReleaseControl"/>
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Session"
send_member="SetType"/>
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Session"
send_member="TakeDevice"/>

View File

@ -38,6 +38,7 @@ fi
PATH_TO_INIT=$ROOTLIBDIR/systemd
[ "$SYSTEMD_JOURNALD" ] || SYSTEMD_JOURNALD=$(which -a $BUILD_DIR/systemd-journald $ROOTLIBDIR/systemd-journald 2>/dev/null | grep '^/' -m1)
[ "$SYSTEMD_JOURNAL_REMOTE" ] || SYSTEMD_JOURNAL_REMOTE=$(which -a $BUILD_DIR/systemd-journal-remote $ROOTLIBDIR/systemd-journal-remote 2>/dev/null | grep '^/' -m1)
[ "$SYSTEMD" ] || SYSTEMD=$(which -a $BUILD_DIR/systemd $ROOTLIBDIR/systemd 2>/dev/null | grep '^/' -m1)
[ "$SYSTEMD_NSPAWN" ] || SYSTEMD_NSPAWN=$(which -a $BUILD_DIR/systemd-nspawn systemd-nspawn 2>/dev/null | grep '^/' -m1)
[ "$JOURNALCTL" ] || JOURNALCTL=$(which -a $BUILD_DIR/journalctl journalctl 2>/dev/null | grep '^/' -m1)
@ -800,13 +801,13 @@ save_journal() {
fi
for j in $1/*; do
/usr/lib/systemd/systemd-journal-remote \
$SYSTEMD_JOURNAL_REMOTE \
-o $dest \
--getter="journalctl -o export -D $j"
--getter="$JOURNALCTL -o export -D $j"
if [ -n "${TEST_SHOW_JOURNAL}" ]; then
echo "---- $j ----"
journalctl --no-pager -o short-monotonic --no-hostname --priority=${TEST_SHOW_JOURNAL} -D $j
$JOURNALCTL --no-pager -o short-monotonic --no-hostname --priority=${TEST_SHOW_JOURNAL} -D $j
fi
rm -r $j
@ -906,7 +907,7 @@ install_plymouth() {
# /usr/libexec/plymouth/plymouth-populate-initrd -t $initdir
# dracut_install plymouth plymouthd
# else
rm -f $initdir/{usr/lib,etc}/systemd/system/plymouth* $initdir/{usr/lib,etc}/systemd/system/*/plymouth*
rm -f $initdir/{usr/lib,lib,etc}/systemd/system/plymouth* $initdir/{usr/lib,lib,etc}/systemd/system/*/plymouth*
# fi
}