bus: add generator that turns old dbus1 activation files into .busname + .service units

This commit is contained in:
Lennart Poettering 2013-12-03 01:13:03 +01:00
parent e821075a23
commit 674eb68520
6 changed files with 308 additions and 11 deletions

1
.gitignore vendored
View File

@ -40,6 +40,7 @@
/systemd-coredumpctl
/systemd-cryptsetup
/systemd-cryptsetup-generator
/systemd-dbus1-generator
/systemd-delta
/systemd-detect-virt
/systemd-efi-boot-generator

View File

@ -1752,6 +1752,18 @@ systemd_gpt_auto_generator_CFLAGS = \
$(BLKID_CFLAGS)
endif
# ------------------------------------------------------------------------------
systemgenerator_PROGRAMS += \
systemd-dbus1-generator
systemd_dbus1_generator_SOURCES = \
src/dbus1-generator/dbus1-generator.c
systemd_dbus1_generator_LDADD = \
libsystemd-label.la \
libsystemd-shared.la \
libsystemd-bus-internal.la
# ------------------------------------------------------------------------------
systemd_rc_local_generator_SOURCES = \
src/rc-local-generator/rc-local-generator.c

View File

@ -0,0 +1 @@
../Makefile

View File

@ -0,0 +1,279 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "util.h"
#include "conf-parser.h"
#include "special.h"
#include "mkdir.h"
#include "bus-util.h"
#include "bus-internal.h"
#include "unit-name.h"
#include "cgroup-util.h"
static const char *arg_dest = "/tmp";
static int create_dbus_files(
const char *path,
const char *name,
const char *service,
const char *exec,
const char *user,
const char *type) {
_cleanup_free_ char *b = NULL, *s = NULL, *lnk = NULL;
_cleanup_fclose_ FILE *f = NULL;
assert(path);
assert(name);
if (!service) {
_cleanup_free_ char *a = NULL;
s = strjoin("dbus-", name, ".service", NULL);
if (!s)
return log_oom();
a = strjoin(arg_dest, "/", s, NULL);
if (!a)
return log_oom();
f = fopen(a, "wxe");
if (!f) {
log_error("Failed to create %s: %m", a);
return -errno;
}
fprintf(f,
"# Automatically generated by systemd-dbus1-generator\n\n"
"[Unit]\n"
"Source=%s\n"
"Description=DBUS1: %s\n\n"
"[Service]\n"
"ExecStart=%s\n"
"Type=dbus\n"
"BusName=%s\n",
path,
name,
exec,
name);
if (user)
fprintf(f, "User=%s\n", user);
if (type) {
fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type);
if (streq(type, "system"))
fprintf(f, "Environment=DBUS_STARTER_ADDRESS=kernel:/dev/kdbus/0-system\n");
else if (streq(type, "session"))
fprintf(f, "Environment=DBUS_STARTER_ADDRESS=kernel:/dev/kdbus/%lu-user\n", (unsigned long) getuid());
}
fflush(f);
if (ferror(f)) {
log_error("Failed to write %s: %m", a);
return -errno;
}
service = s;
}
b = strjoin(arg_dest, "/", name, ".busname", NULL);
if (!b)
return log_oom();
f = fopen(b, "wxe");
if (!f) {
log_error("Failed to create %s: %m", b);
return -errno;
}
fprintf(f,
"# Automatically generated by systemd-dbus1-generator\n\n"
"[Unit]\n"
"Source=%s\n"
"Description=DBUS1: %s\n\n"
"[BusName]\n"
"Name=%s\n"
"Service=%s\n",
path,
name,
name,
service);
fflush(f);
if (ferror(f)) {
log_error("Failed to write %s: %m", b);
return -errno;
}
lnk = strjoin(arg_dest, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL);
if (!lnk)
return log_oom();
mkdir_parents_label(lnk, 0755);
if (symlink(b, lnk)) {
log_error("Failed to create symlinks %s: %m", lnk);
return -errno;
}
return 0;
}
static int add_dbus(const char *path, const char *fname, const char *type) {
_cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL;
ConfigTableItem table[] = {
{ "D-BUS Service", "Name", config_parse_string, 0, &name },
{ "D-BUS Service", "Exec", config_parse_string, 0, &exec },
{ "D-BUS Service", "User", config_parse_string, 0, &user },
{ "D-BUS Service", "SystemdService", config_parse_string, 0, &service },
};
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
int r;
assert(path);
assert(fname);
p = strjoin(path, "/", fname, NULL);
if (!p)
return log_oom();
f = fopen(p, "re");
if (!f) {
if (errno == -ENOENT)
return 0;
log_error("Failed to read %s: %m", p);
return -errno;
}
r = config_parse(NULL, p, f, "D-BUS Service\0", config_item_table_lookup, table, true, false, NULL);
if (r < 0)
return r;
if (!name) {
log_warning("Activation file %s lacks name setting, ignoring.", p);
return 0;
}
if (!service_name_is_valid(name)) {
log_warning("Bus service name %s is not valid, ignoring.", name);
return 0;
}
if (service) {
if (!unit_name_is_valid(service, false)) {
log_warning("Unit name %s is not valid, ignoring.", service);
return 0;
}
if (!endswith(service, ".service")) {
log_warning("Bus names can only activate services, ignoring %s.", p);
return 0;
}
} else {
if (!exec) {
log_warning("Neither service name nor binary path specified, ignoring %s.", p);
return 0;
}
if (exec[0] != '/') {
log_warning("Exec= in %s does not start with an absolute path, ignoring.", p);
return 0;
}
}
return create_dbus_files(p, name, service, exec, user, type);
}
static int parse_dbus_fragments(void) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
const char *p, *type;
int r;
r = cg_pid_get_owner_uid(0, NULL);
if (r >= 0) {
p = "/usr/share/dbus-1/services";
type = "session";
} else if (r == -ENOENT) {
p = "/usr/share/dbus-1/system-services";
type = "systemd";
} else if (r < 0) {
log_error("Failed to determine whether we are running as user or system instance: %s", strerror(-r));
return r;
}
d = opendir(p);
if (!d) {
if (errno == -ENOENT)
return 0;
log_error("Failed to enumerate D-Bus activated services: %m");
return -errno;
}
r = 0;
FOREACH_DIRENT(de, d, goto fail) {
int q;
if (!endswith(de->d_name, ".service"))
continue;
q = add_dbus(p, de->d_name, type);
if (q < 0)
r = q;
}
return r;
fail:
log_error("Failed to read D-Bus services directory: %m");
return -errno;
}
int main(int argc, char *argv[]) {
int r;
if (argc > 1 && argc != 4) {
log_error("This program takes three or no arguments.");
return EXIT_FAILURE;
}
if (argc > 1)
arg_dest = argv[3];
log_set_target(LOG_TARGET_SAFE);
log_parse_environment();
log_open();
umask(0022);
if (access("/dev/kdbus/control", F_OK) < 0)
return 0;
r = parse_dbus_fragments();
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

View File

@ -228,7 +228,6 @@ static int add_home(const char *path, const char *fstype) {
if (!lnk)
return log_oom();
mkdir_parents_label(lnk, 0755);
if (symlink(unit, lnk) < 0) {
log_error("Failed to create symlink %s: %m", lnk);

View File

@ -1337,36 +1337,41 @@ int cg_pid_get_session(pid_t pid, char **session) {
int cg_path_get_owner_uid(const char *path, uid_t *uid) {
_cleanup_free_ char *slice = NULL;
const char *e;
const char *start, *end;
char *s;
uid_t u;
int r;
assert(path);
assert(uid);
r = cg_path_get_slice(path, &slice);
if (r < 0)
return r;
e = startswith(slice, "user-");
if (!e)
start = startswith(slice, "user-");
if (!start)
return -ENOENT;
if (!endswith(slice, ".slice"))
end = endswith(slice, ".slice");
if (!end)
return -ENOENT;
s = strndupa(e, strlen(e) - 6);
s = strndupa(start, end - start);
if (!s)
return -ENOMEM;
return -ENOENT;
return parse_uid(s, uid);
if (parse_uid(s, &u) < 0)
return -EIO;
if (uid)
*uid = u;
return 0;
}
int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
_cleanup_free_ char *cgroup = NULL;
int r;
assert(uid);
r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
if (r < 0)
return r;