Re: [systemd-devel] TTY ownership and systemd user session
On 2014-01-10, 06:27 +0100, Lennart Poettering wrote: On Thu, 09.01.14 09:56, Yin Kangkai (kangkai@linux.intel.com) wrote: Hi, I am bringing up systemd user session in Tizen, I am using v208. We run into a small issue that if a user session service file claims TTY, systemd user session will fail to chown_terminal() for it: Failed at step STDIN spawning /usr/bin/xorg-launch-helper: Permission denied My testing service file has something like this: [Service] StandardInput=tty TTYPath=/dev/tty1 ExecStart=/usr/bin/xxx I tried to look into the code... The failure seems happen after systemd --user forked and about the exec into the new process, in execute.c:exec_spawn(), when calling chown_terminal(). So my question is: * does systemd depend on other (e.g. udev) to set the /dev/tty1 permission beforehand? Or * should we do the chown_terminal() stuff in PAM/pam_systemd after we got the PAM_TTY? since otherwise it's too late to do it in exec_spawn(), it's already running as normal user, you can't chown /dev/tty1 etc. Please help me to understand this, and anything I am missing. Thanks. The chown_terminal() call is invoked at point in time where privileges have not been dropped yet for the process that is being forked off. This means that there isn't actually relly any excuse for ths to fail with EPERM, since we are still root. No? It is already in user session, systemd is not root here any more right? Do I miss anything? Is it possible that this issue is reated to SMACK or so? I.e. some SMACK policy forbidding this chowning for the forked off process? Otherwise I have no idea really how this could ever fail with EPERM... ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
[systemd-devel] TTY ownership and systemd user session
Hi, I am bringing up systemd user session in Tizen, I am using v208. We run into a small issue that if a user session service file claims TTY, systemd user session will fail to chown_terminal() for it: Failed at step STDIN spawning /usr/bin/xorg-launch-helper: Permission denied My testing service file has something like this: [Service] StandardInput=tty TTYPath=/dev/tty1 ExecStart=/usr/bin/xxx I tried to look into the code... The failure seems happen after systemd --user forked and about the exec into the new process, in execute.c:exec_spawn(), when calling chown_terminal(). So my question is: * does systemd depend on other (e.g. udev) to set the /dev/tty1 permission beforehand? Or * should we do the chown_terminal() stuff in PAM/pam_systemd after we got the PAM_TTY? since otherwise it's too late to do it in exec_spawn(), it's already running as normal user, you can't chown /dev/tty1 etc. Please help me to understand this, and anything I am missing. Thanks. Regards, Kangkai ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] [PATCH 4/4] gdbus: Add basic kdbus tests
On 2013-11-21, 12:33 +0100, Karol Lewandowski wrote: +TESTS += + +* Build test binaries: + + cd gio/tests + make + +* Set variable to use custom library and to use kdbus as session bus: + + export LD_LIBRARY_PATH=absolute_path_to_glib_libs_with_kdbus_patch + export DBUS_SESSION_BUS_ADDRESS=kdbus:path=/dev/kdbus/0-kdbus/bus + +* Run test binary server in terminal 1: + + ./gdbus-example-kdbus-server + +* Run test binary client in terminal 2: + + ./gdbus-example-kdbus-client + +* Sample client app output: + + elapsed time : 0.265072 s + elapsed time : 0.264353 s + elapsed time : 0.305062 s + elapsed time : 0.343710 s + elapsed time : 0.451501 s + elapsed time : 1.109851 s + elapsed time : 8.278217 s Will it be more interesting to show some real benchmarking numbers? ;) - results with vanilla GIO; - results with GIO with kdbus transport, talking to kdbus dbus-daemon; - results with GIO with kdbus transport, talking through systemd-bus-proxyd to systemd-bus-driverd; Regards, Kangkai ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
[systemd-devel] [PATCH] libsystemd-bus: make sure buf transfered into kenrel is 8 aligned
From: Yin Kangkai kangkai@intel.com Otherwise, for example hello arg passed to KDBUS_CMD_HELLO might not be 8 bytes aligned and kernel returns -EFAULT. 319 int bus_kernel_take_fd(sd_bus *b) { 320 struct kdbus_cmd_hello hello; (gdb) p hello $8 = (struct kdbus_cmd_hello *) 0xb354 --- src/libsystemd-bus/bus-control.c | 4 ++-- src/libsystemd-bus/bus-kernel.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libsystemd-bus/bus-control.c b/src/libsystemd-bus/bus-control.c index 0072c37..6b2790d 100644 --- a/src/libsystemd-bus/bus-control.c +++ b/src/libsystemd-bus/bus-control.c @@ -207,7 +207,7 @@ _public_ int sd_bus_release_name(sd_bus *bus, const char *name) { } static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { -struct kdbus_cmd_name_list cmd = {}; +struct kdbus_cmd_name_list __attribute__ ((__aligned__(8))) cmd = {}; struct kdbus_name_list *name_list; struct kdbus_cmd_name *name; uint64_t previous_id = 0; @@ -1088,7 +1088,7 @@ static int bus_remove_match_internal_kernel( const char *match, uint64_t cookie) { -struct kdbus_cmd_match m; +struct kdbus_cmd_match __attribute__ ((__aligned__(8))) m; int r; assert(bus); diff --git a/src/libsystemd-bus/bus-kernel.c b/src/libsystemd-bus/bus-kernel.c index 0e47308..4947d39 100644 --- a/src/libsystemd-bus/bus-kernel.c +++ b/src/libsystemd-bus/bus-kernel.c @@ -317,7 +317,7 @@ fail: } int bus_kernel_take_fd(sd_bus *b) { -struct kdbus_cmd_hello hello; +struct kdbus_cmd_hello __attribute__ ((__aligned__(8))) hello; int r; assert(b); -- 1.8.2.1 ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] [PATCH] libsystemd-bus: make sure buf transfered into kenrel is 8 aligned
On 2013-12-16, 16:01 +0100, Lennart Poettering wrote: On Mon, 16.12.13 15:50, Lennart Poettering (lenn...@poettering.net) wrote: diff --git a/src/libsystemd-bus/bus-control.c b/src/libsystemd-bus/bus-control.c index 0072c37..6b2790d 100644 --- a/src/libsystemd-bus/bus-control.c +++ b/src/libsystemd-bus/bus-control.c @@ -207,7 +207,7 @@ _public_ int sd_bus_release_name(sd_bus *bus, const char *name) { } static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { -struct kdbus_cmd_name_list cmd = {}; +struct kdbus_cmd_name_list __attribute__ ((__aligned__(8))) cmd = {}; Hmm, this feels a bit like this would be better part of the type rather than the variable. THus, kdbus.h should add this to all is structs, rather then we decorate the variables... Kay, would this make sense to you to add to kdbus.h? Hmm, so thinking about this: the kdbus_cmd_name_list structure contains 64bit values anyway, so should naturally be aligned to 64bit boundaries anyway... Or am I mistaken there and you are suggesting that on your 32bit architecture (which one is it if I may ask?) 64bit values don't I am doing tests in 32bit system. have to be aligned on an even 8byte boundary, but instead because the arch is 32bit anyway and thus 64bit values need to be read in two steps alignment on 4 is done in the abi? I am getting a little more clearer about how gcc tries to make stack boundary aligned.. I am using this example test code: 8 #include stdio.h #include linux/types.h struct kdbus_cmd_hello { __u64 size; __u64 conn_flags; __u64 attach_flags; __u64 bus_flags; __u64 id; __u64 bloom_size; __u64 pool_size; __u8 id128[16]; }; int main(int argc, char **argv) { struct kdbus_cmd_hello hello; int r; printf(hello addr: %08x\n, hello); r = 1; return 0; } 8 By default, gcc will *try* to make stack boundary 16 bytes aligned (pls refer to -mpreferred-stack-boundary=num in gcc mannual). struct kdbus_cmd_hello itself is 64bit aligned, yes. However, if you have a int r after the kdbus_cmd_hello, address of hello might be 16 bytes boundary + 4 (so that after pushing r, stack boundary will be 16 bytes aligned). $ ./test hello addr: bfe8d334 $ ./test hello addr: bf9aa9f4 $ ./test hello addr: bfe443c4 $ ./test hello addr: bfe8d334 $ ./test hello addr: bf9fdf24 Regards, Kangkai ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] [PATCH] libsystemd-bus: make sure buf transfered into kenrel is 8 aligned
On 2013-12-16, 17:49 +0100, Kay Sievers wrote: On Mon, Dec 16, 2013 at 4:09 PM, Kay Sievers k...@vrfy.org wrote: Just added __attribute__ ((__aligned__(8))) to kdbus.h for structures used in ioctls. Yes, your patch is much more cleaner, thanks Kay. Regards, Kangkai ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] [PATCH] libsystemd-bus: trivial macro KDBUS_PART_HEADER_SIZE replace
On 2013-12-10, 20:56 +0100, Lennart Poettering wrote: On Wed, 04.12.13 15:28, Yin Kangkai (kangkai@intel.com) wrote: It's a little bit cleaner(?) to replace offsetof(struct kdbus_item, data) with KDBUS_PART_HEADER_SIZE. Hmm, is this really cleaner? I kinda like using offsetof() for this, since it explains less opaquely what we are putting together here I think... OK, thanks for your information. Regards, Kangkai ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] [PATCH 1/7] libsystemd-bus: bring definitions in sync with kdbus
On 2013-12-04, 08:49 +0100, Daniel Mack wrote: Actually, I have a stupid question, do we have any particular reason to use part/PART? giving the fact that we already have term item everywhere in the code... struct kdbus_item, items, kdbus_msg.items... My opinion, on the contrary, we should replace all the KDBUS_PART_xxx into KDBUS_ITEM_xxx, that seems more reasonable to me :) Nope. A 'part' is more generic: anything that has size header and a dynamic length is a 'part' and can be iterated over with KDBUS_PART_FOREACH. Hence, an 'item' is a 'part', but not vice versa. See struct kdbus_name_list for example. Thanks Daniel for the reply. OK now I understand KDBUS_PART_NEXT/FOREACH is not only for item. But KDBUS_PART_HEADER_SIZE and KDBUS_PART_SIZE seems item specific, no? Regards, Kangkai ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] [PATCH 1/7] libsystemd-bus: bring definitions in sync with kdbus
On 2013-11-15, 19:32 +0100, Daniel Mack wrote: In particular, KDBUS_ITEM_NEXT is now called KDBUS_PART_NEXT, and KDBUS_ITEM_FOREACH was renamed to KDBUS_PART_FOREACH and takes one more argument to make it more flexible. [...] --- src/libsystemd-bus/bus-control.c | 2 +- src/libsystemd-bus/bus-kernel.c | 12 ++-- src/libsystemd-bus/bus-kernel.h | 14 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libsystemd-bus/bus-control.c b/src/libsystemd-bus/bus-control.c index f217269..5c9e746 100644 --- a/src/libsystemd-bus/bus-control.c +++ b/src/libsystemd-bus/bus-control.c @@ -468,7 +468,7 @@ int bus_add_match_internal( item-type = KDBUS_MATCH_BLOOM; memcpy(item-data64, bloom, BLOOM_SIZE); -item = KDBUS_ITEM_NEXT(item); +item = KDBUS_PART_NEXT(item); } if (sender) { diff --git a/src/libsystemd-bus/bus-kernel.c b/src/libsystemd-bus/bus-kernel.c index bf8de04..3ea85d4 100644 --- a/src/libsystemd-bus/bus-kernel.c +++ b/src/libsystemd-bus/bus-kernel.c @@ -409,7 +409,7 @@ static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) { off = (uint8_t *)k - (uint8_t *)bus-kdbus_buffer; ioctl(bus-input_fd, KDBUS_CMD_MSG_RELEASE, off); -KDBUS_ITEM_FOREACH(d, k) { +KDBUS_PART_FOREACH(d, k, items) { if (d-type == KDBUS_MSG_FDS) close_many(d-fds, (d-size - offsetof(struct kdbus_item, fds)) / sizeof(int)); @@ -435,7 +435,7 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_mess if (k-payload_type != KDBUS_PAYLOAD_DBUS1) return 0; -KDBUS_ITEM_FOREACH(d, k) { +KDBUS_PART_FOREACH(d, k, items) { size_t l; l = d-size - offsetof(struct kdbus_item, data); @@ -489,7 +489,7 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_mess if (r 0) return r; -KDBUS_ITEM_FOREACH(d, k) { +KDBUS_PART_FOREACH(d, k, items) { size_t l; l = d-size - offsetof(struct kdbus_item, data); @@ -668,13 +668,13 @@ int bus_kernel_create(const char *name, char **s) { l = strlen(name); make = alloca0(offsetof(struct kdbus_cmd_bus_make, items) + - KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t) + - KDBUS_ITEM_HEADER_SIZE + DECIMAL_STR_MAX(uid_t) + 1 + l + 1); + KDBUS_PART_HEADER_SIZE + sizeof(uint64_t) + + KDBUS_PART_HEADER_SIZE + DECIMAL_STR_MAX(uid_t) + 1 + l + 1); n = make-items; n-type = KDBUS_MAKE_NAME; sprintf(n-str, %lu-%s, (unsigned long) getuid(), name); -n-size = KDBUS_ITEM_HEADER_SIZE + strlen(n-str) + 1; +n-size = KDBUS_PART_HEADER_SIZE + strlen(n-str) + 1; make-size = offsetof(struct kdbus_cmd_bus_make, items) + n-size; make-flags = KDBUS_MAKE_POLICY_OPEN; diff --git a/src/libsystemd-bus/bus-kernel.h b/src/libsystemd-bus/bus-kernel.h index c4573c9..69df4f4 100644 --- a/src/libsystemd-bus/bus-kernel.h +++ b/src/libsystemd-bus/bus-kernel.h @@ -23,16 +23,16 @@ #include sd-bus.h -#define KDBUS_ITEM_NEXT(item) \ +#define KDBUS_PART_NEXT(item) \ (typeof(item))(((uint8_t *)item) + ALIGN8((item)-size)) -#define KDBUS_ITEM_FOREACH(item, head) \ -for (item = (head)-items; \ - (uint8_t *)(item) (uint8_t *)(head) + (head)-size; \ - item = KDBUS_ITEM_NEXT(item)) +#define KDBUS_PART_FOREACH(part, head, first) \ +for (part = (head)-first; \ + (uint8_t *)(part) (uint8_t *)(head) + (head)-size; \ + part = KDBUS_PART_NEXT(part)) -#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data) -#define KDBUS_ITEM_SIZE(s) ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE) +#define KDBUS_PART_HEADER_SIZE offsetof(struct kdbus_item, data) [...] +#define KDBUS_ITEM_SIZE(s) ALIGN8((s) + KDBUS_PART_HEADER_SIZE) We missed this one? KDBUS_ITEM_SIZE/KDBUS_PART_SIZE Actually, I have a stupid question, do we have any particular reason to use part/PART? giving the fact that we already have term item everywhere in the code... struct kdbus_item, items, kdbus_msg.items... My opinion, on the contrary, we should replace all the KDBUS_PART_xxx into KDBUS_ITEM_xxx, that seems more reasonable to me :) [Same question to the kdbus code as well] Thanks, Kangkai ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org
[systemd-devel] [PATCH] libsystemd-bus: trivial macro KDBUS_PART_HEADER_SIZE replace
It's a little bit cleaner(?) to replace offsetof(struct kdbus_item, data) with KDBUS_PART_HEADER_SIZE. --- src/libsystemd-bus/bus-control.c | 16 src/libsystemd-bus/bus-kernel.c | 41 src/libsystemd-bus/bus-kernel.h | 2 +- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/libsystemd-bus/bus-control.c b/src/libsystemd-bus/bus-control.c index 7a772ff..073e7aa 100644 --- a/src/libsystemd-bus/bus-control.c +++ b/src/libsystemd-bus/bus-control.c @@ -765,7 +765,7 @@ static int add_name_change_match(sd_bus *bus, l = name ? strlen(name) : 0; sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) + -offsetof(struct kdbus_item, name_change) + +KDBUS_PART_HEADER_SIZE + offsetof(struct kdbus_notify_name_change, name) + l+1); @@ -776,7 +776,7 @@ static int add_name_change_match(sd_bus *bus, item = m-items; item-size = -offsetof(struct kdbus_item, name_change) + +KDBUS_PART_HEADER_SIZE + offsetof(struct kdbus_notify_name_change, name) + l+1; @@ -828,7 +828,7 @@ static int add_name_change_match(sd_bus *bus, * for it */ sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) + -offsetof(struct kdbus_item, id_change) + +KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_notify_id_change)); m = alloca0(sz); @@ -837,7 +837,7 @@ static int add_name_change_match(sd_bus *bus, m-src_id = KDBUS_SRC_ID_KERNEL; item = m-items; -item-size = offsetof(struct kdbus_item, id_change) + sizeof(struct kdbus_notify_id_change); +item-size = KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_notify_id_change); item-id_change.id = name_id; /* If the old name is unset or empty, then this can @@ -907,7 +907,7 @@ static int bus_add_match_internal_kernel( if (r 0) { sender = c-value_str; sender_length = strlen(sender); -sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1); +sz += KDBUS_PART_SIZE(sender_length + 1); } break; @@ -999,7 +999,7 @@ static int bus_add_match_internal_kernel( } if (using_bloom) -sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE); +sz += KDBUS_PART_SIZE(BLOOM_SIZE); m = alloca0(sz); m-size = sz; @@ -1009,7 +1009,7 @@ static int bus_add_match_internal_kernel( item = m-items; if (using_bloom) { -item-size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE; +item-size = KDBUS_PART_HEADER_SIZE + BLOOM_SIZE; item-type = KDBUS_MATCH_BLOOM; memcpy(item-data64, bloom, BLOOM_SIZE); @@ -1017,7 +1017,7 @@ static int bus_add_match_internal_kernel( } if (sender) { -item-size = offsetof(struct kdbus_item, str) + sender_length + 1; +item-size = KDBUS_PART_HEADER_SIZE + sender_length + 1; item-type = KDBUS_MATCH_SRC_NAME; memcpy(item-str, sender, sender_length + 1); } diff --git a/src/libsystemd-bus/bus-kernel.c b/src/libsystemd-bus/bus-kernel.c index b85a10d..56259f5 100644 --- a/src/libsystemd-bus/bus-kernel.c +++ b/src/libsystemd-bus/bus-kernel.c @@ -63,7 +63,7 @@ static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) * zeroes, which is useful to optimize certain padding * conditions */ -(*d)-size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec); +(*d)-size = KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_vec); (*d)-type = KDBUS_ITEM_PAYLOAD_VEC; (*d)-vec.address = PTR_TO_UINT64(p); (*d)-vec.size = sz; @@ -77,7 +77,7 @@ static void append_payload_memfd(struct kdbus_item **d, int memfd, size_t sz) { assert(sz 0); *d = ALIGN8_PTR(*d); -(*d)-size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd); +(*d)-size = KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_memfd); (*d)-type = KDBUS_ITEM_PAYLOAD_MEMFD; (*d)-memfd.fd = memfd; (*d)-memfd.size = sz; @@ -91,7 +91,7 @@ static void append_destination(struct kdbus_item **d, const char *s, size_t leng *d = ALIGN8_PTR(*d); -(*d)-size = offsetof(struct kdbus_item, str) + length + 1; +(*d)-size = KDBUS_PART_HEADER_SIZE +
[systemd-devel] [PATCH] conf-parser: fix memory realloc error
Otherwise there is some memory corruption and undefined behavior, e.g., in my case systemd-udev was always aborted at the _cleanup_freep_ around that code blocks. Signed-off-by: Yin Kangkai kangkai@intel.com --- src/shared/conf-parser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 312315b..c194a07 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -199,7 +199,7 @@ int log_syntax_internal(const char *unit, int level, continue; \ \ *(xs + i) = x; \ -xs = realloc(xs, ++i + 1); \ +xs = realloc(xs, (++i + 1) * sizeof(type)); \ if (!xs) \ return -ENOMEM; \ *(xs + i) = invalid; \ -- 1.8.2.1 ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
[systemd-devel] [PATCH] build fix: add RT_LIBS to link against for test-bus-marshal
Otherwise, build fail: /usr/bin/ld: ./.libs/libsystemd-daemon-internal.a(sd-daemon.o): undefined reference to symbol 'mq_getattr@@GLIBC_2.3.4' /usr/bin/ld: note: 'mq_getattr@@GLIBC_2.3.4' is defined in DSO /lib/librt.so.1 so try adding it to the linker command line /lib/librt.so.1: could not read symbols: Invalid operation collect2: error: ld returned 1 exit status make[2]: *** [test-bus-marshal] Error 1 make[1]: *** [all-recursive] Error 1 make: *** [all] Error 2 Signed-off-by: Yin Kangkai kangkai@intel.com --- Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index f7fe96c..f0193e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2008,7 +2008,8 @@ test_bus_marshal_LDADD = \ libsystemd-capability.la \ $(GLIB_LIBS) \ $(DBUS_LIBS) \ - $(CAP_LIBS) + $(CAP_LIBS) \ + $(RT_LIBS) test_bus_marshal_CFLAGS = \ $(AM_CFLAGS) \ -- 1.8.2.1 ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel