summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/99-systemd.rules.in9
-rw-r--r--src/binfmt.c2
-rw-r--r--src/cgroup.c3
-rw-r--r--src/condition.c98
-rw-r--r--src/condition.h3
-rw-r--r--src/conf-parser.c2
-rw-r--r--src/cryptsetup-generator.c6
-rw-r--r--src/dbus-manager.c2
-rw-r--r--src/detect-virt.c8
-rw-r--r--src/execute.c7
-rw-r--r--src/fsck.c3
-rwxr-xr-xsrc/generate-kbd-model-map33
-rw-r--r--src/getty-generator.c1
-rw-r--r--src/hashmap.c8
-rw-r--r--src/hostname-setup.c8
-rw-r--r--src/hostnamed.c5
-rw-r--r--src/initctl.c11
-rw-r--r--src/install.c3
-rw-r--r--src/job.c24
-rw-r--r--src/kbd-model-map72
-rw-r--r--src/kmsg-syslogd.c2
-rw-r--r--src/load-fragment-gperf.gperf.m43
-rw-r--r--src/load-fragment.c10
-rw-r--r--src/locale-setup.c3
-rw-r--r--src/localed.c803
-rw-r--r--src/loginctl.c53
-rw-r--r--src/logind-dbus.c15
-rw-r--r--src/logind.c7
-rw-r--r--src/main.c1
-rw-r--r--src/manager.c24
-rw-r--r--src/modules-load.c2
-rw-r--r--src/mount.c18
-rw-r--r--src/nspawn.c23
-rw-r--r--src/org.freedesktop.locale1.policy.in10
-rw-r--r--src/pager.c18
-rw-r--r--src/path.c2
-rw-r--r--src/quotacheck.c7
-rw-r--r--src/random-seed.c6
-rw-r--r--src/readahead-collect.c1
-rw-r--r--src/readahead-common.h2
-rw-r--r--src/readahead-replay.c1
-rw-r--r--src/sd-login.c45
-rw-r--r--src/sd-login.h4
-rw-r--r--src/selinux-setup.c6
-rw-r--r--src/service.c91
-rw-r--r--src/shutdown.c1
-rw-r--r--src/socket.c8
-rw-r--r--src/special.h2
-rw-r--r--src/stdout-syslog-bridge.c30
-rw-r--r--src/strv.c26
-rw-r--r--src/sysfs-show.c3
-rw-r--r--src/systemctl-bash-completion.sh150
-rw-r--r--src/systemctl.c152
-rwxr-xr-xsrc/systemd-analyze51
-rw-r--r--src/systemd-bash-completion.sh264
-rw-r--r--src/timedated.c22
-rw-r--r--src/tmpfiles.c1
-rw-r--r--src/tty-ask-password-agent.c1
-rw-r--r--src/umount.c7
-rw-r--r--src/unit.c18
-rw-r--r--src/update-utmp.c5
-rw-r--r--src/util.c332
-rw-r--r--src/util.h16
-rw-r--r--src/vconsole-setup.c9
-rw-r--r--src/virt.c314
-rw-r--r--src/virt.h38
66 files changed, 2243 insertions, 672 deletions
diff --git a/src/99-systemd.rules.in b/src/99-systemd.rules.in
index 884a614404..b2481aea9a 100644
--- a/src/99-systemd.rules.in
+++ b/src/99-systemd.rules.in
@@ -17,6 +17,7 @@ SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=
# Ignore encrypted devices with no identified superblock on it, since
# we are probably still calling mke2fs or mkswap on it.
+
SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0"
# We need a hardware independent way to identify network devices. We
@@ -41,6 +42,14 @@ SUBSYSTEM=="printer", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target"
SUBSYSTEM=="usb", KERNEL=="lp*", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target"
+# Apply sysctl variables to network devices (and only to those) as they appear.
+
SUBSYSTEM=="net", RUN+="@rootlibexecdir@/systemd-sysctl --prefix=/proc/sys/net/ipv4/conf/$name --prefix=/proc/sys/net/ipv4/neigh/$name --prefix=/proc/sys/net/ipv6/conf/$name --prefix=/proc/sys/net/ipv6/neigh/$name"
+# Asynchronously mount file systems implemented by these modules as
+# soon as they are loaded.
+
+SUBSYSTEM=="module", KERNEL=="fuse", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}="sys-fs-fuse-connections.mount"
+SUBSYSTEM=="module", KERNEL=="configfs", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}="sys-kernel-config.mount"
+
LABEL="systemd_end"
diff --git a/src/binfmt.c b/src/binfmt.c
index 552d8cc227..e8d6524391 100644
--- a/src/binfmt.c
+++ b/src/binfmt.c
@@ -33,7 +33,7 @@
#include "util.h"
static int delete_rule(const char *rule) {
- char *x, *fn, *e;
+ char *x, *fn = NULL, *e;
int r;
assert(rule[0]);
diff --git a/src/cgroup.c b/src/cgroup.c
index dcf2c2feb7..be837c3d0f 100644
--- a/src/cgroup.c
+++ b/src/cgroup.c
@@ -38,9 +38,6 @@ int cgroup_bonding_realize(CGroupBonding *b) {
assert(b->path);
assert(b->controller);
- if (b->realized)
- return 0;
-
r = cg_create(b->controller, b->path);
if (r < 0) {
log_warning("Failed to create cgroup %s:%s: %s", b->controller, b->path, strerror(-r));
diff --git a/src/condition.c b/src/condition.c
index f9202f6850..2b51a16f17 100644
--- a/src/condition.c
+++ b/src/condition.c
@@ -23,6 +23,7 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
+#include <sys/capability.h>
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
@@ -30,24 +31,28 @@
#include "util.h"
#include "condition.h"
+#include "virt.h"
Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
Condition *c;
assert(type < _CONDITION_TYPE_MAX);
- if (!(c = new0(Condition, 1)))
+ c = new0(Condition, 1);
+ if (!c)
return NULL;
c->type = type;
c->trigger = trigger;
c->negate = negate;
- if (parameter)
- if (!(c->parameter = strdup(parameter))) {
+ if (parameter) {
+ c->parameter = strdup(parameter);
+ if (!c->parameter) {
free(c);
return NULL;
}
+ }
return c;
}
@@ -75,10 +80,11 @@ static bool test_kernel_command_line(const char *parameter) {
assert(parameter);
- if (detect_virtualization(NULL) > 0)
+ if (detect_container(NULL) > 0)
return false;
- if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) {
+ r = read_one_line_file("/proc/cmdline", &line);
+ if (r < 0) {
log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
return false;
}
@@ -89,7 +95,8 @@ static bool test_kernel_command_line(const char *parameter) {
FOREACH_WORD_QUOTED(w, l, line, state) {
free(word);
- if (!(word = strndup(w, l)))
+ word = strndup(w, l);
+ if (!word)
break;
if (equal) {
@@ -113,25 +120,36 @@ static bool test_kernel_command_line(const char *parameter) {
}
static bool test_virtualization(const char *parameter) {
- int r, b;
+ int b;
+ Virtualization v;
const char *id;
assert(parameter);
- if ((r = detect_virtualization(&id)) < 0) {
- log_warning("Failed to detect virtualization, ignoring: %s", strerror(-r));
+ v = detect_virtualization(&id);
+ if (v < 0) {
+ log_warning("Failed to detect virtualization, ignoring: %s", strerror(-v));
return false;
}
+ /* First, compare with yes/no */
b = parse_boolean(parameter);
- if (r > 0 && b > 0)
+ if (v > 0 && b > 0)
+ return true;
+
+ if (v == 0 && b == 0)
+ return true;
+
+ /* Then, compare categorization */
+ if (v == VIRTUALIZATION_VM && streq(parameter, "vm"))
return true;
- if (r == 0 && b == 0)
+ if (v == VIRTUALIZATION_CONTAINER && streq(parameter, "container"))
return true;
- return streq(parameter, id);
+ /* Finally compare id */
+ return v > 0 && streq(parameter, id);
}
static bool test_security(const char *parameter) {
@@ -142,6 +160,38 @@ static bool test_security(const char *parameter) {
return false;
}
+static bool test_capability(const char *parameter) {
+ cap_value_t value;
+ FILE *f;
+ char line[LINE_MAX];
+ unsigned long long capabilities = (unsigned long long) -1;
+
+ /* If it's an invalid capability, we don't have it */
+
+ if (cap_from_name(parameter, &value) < 0)
+ return false;
+
+ /* If it's a valid capability we default to assume
+ * that we have it */
+
+ f = fopen("/proc/self/status", "re");
+ if (!f)
+ return true;
+
+ while (fgets(line, sizeof(line), f)) {
+ truncate_nl(line);
+
+ if (startswith(line, "CapBnd:")) {
+ (void) sscanf(line+7, "%llx", &capabilities);
+ break;
+ }
+ }
+
+ fclose(f);
+
+ return !!(capabilities & (1ULL << value));
+}
+
bool condition_test(Condition *c) {
assert(c);
@@ -156,11 +206,22 @@ bool condition_test(Condition *c) {
case CONDITION_PATH_IS_DIRECTORY: {
struct stat st;
- if (lstat(c->parameter, &st) < 0)
- return !c->negate;
+ if (stat(c->parameter, &st) < 0)
+ return c->negate;
return S_ISDIR(st.st_mode) == !c->negate;
}
+ case CONDITION_PATH_IS_SYMBOLIC_LINK: {
+ struct stat st;
+
+ if (lstat(c->parameter, &st) < 0)
+ return c->negate;
+ return S_ISLNK(st.st_mode) == !c->negate;
+ }
+
+ case CONDITION_PATH_IS_MOUNT_POINT:
+ return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
+
case CONDITION_DIRECTORY_NOT_EMPTY: {
int k;
@@ -171,8 +232,8 @@ bool condition_test(Condition *c) {
case CONDITION_FILE_IS_EXECUTABLE: {
struct stat st;
- if (lstat(c->parameter, &st) < 0)
- return !c->negate;
+ if (stat(c->parameter, &st) < 0)
+ return c->negate;
return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
}
@@ -186,6 +247,9 @@ bool condition_test(Condition *c) {
case CONDITION_SECURITY:
return test_security(c->parameter) == !c->negate;
+ case CONDITION_CAPABILITY:
+ return test_capability(c->parameter) == !c->negate;
+
case CONDITION_NULL:
return !c->negate;
@@ -247,6 +311,8 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
[CONDITION_PATH_EXISTS] = "ConditionPathExists",
[CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
[CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
+ [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
+ [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
[CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
[CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
[CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
diff --git a/src/condition.h b/src/condition.h
index 672996e836..71b1c6761e 100644
--- a/src/condition.h
+++ b/src/condition.h
@@ -30,11 +30,14 @@ typedef enum ConditionType {
CONDITION_PATH_EXISTS,
CONDITION_PATH_EXISTS_GLOB,
CONDITION_PATH_IS_DIRECTORY,
+ CONDITION_PATH_IS_SYMBOLIC_LINK,
+ CONDITION_PATH_IS_MOUNT_POINT,
CONDITION_DIRECTORY_NOT_EMPTY,
CONDITION_FILE_IS_EXECUTABLE,
CONDITION_KERNEL_COMMAND_LINE,
CONDITION_VIRTUALIZATION,
CONDITION_SECURITY,
+ CONDITION_CAPABILITY,
CONDITION_NULL,
_CONDITION_TYPE_MAX,
_CONDITION_TYPE_INVALID = -1
diff --git a/src/conf-parser.c b/src/conf-parser.c
index 3bb430e375..a71dcd0d8f 100644
--- a/src/conf-parser.c
+++ b/src/conf-parser.c
@@ -314,7 +314,7 @@ int config_parse(
continuation = c;
else {
continuation = strdup(l);
- if (!c) {
+ if (!continuation) {
r = -ENOMEM;
goto finish;
}
diff --git a/src/cryptsetup-generator.c b/src/cryptsetup-generator.c
index 6f3aa786bc..a48b7a4562 100644
--- a/src/cryptsetup-generator.c
+++ b/src/cryptsetup-generator.c
@@ -112,8 +112,7 @@ static int create_disk(
"DefaultDependencies=no\n"
"BindTo=%s dev-mapper-%%i.device\n"
"After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n"
- "Before=umount.target\n"
- "Before=local-fs.target\n",
+ "Before=umount.target\n",
d, d);
if (!nofail)
@@ -125,6 +124,9 @@ static int create_disk(
streq(password, "/dev/hw_random")))
fprintf(f,
"After=systemd-random-seed-load.service\n");
+ else
+ fprintf(f,
+ "Before=local-fs.target\n");
fprintf(f,
"\n[Service]\n"
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index 822189b103..7b68156abf 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -300,7 +300,7 @@ static int bus_manager_append_tainted(DBusMessageIter *i, const char *property,
free(p);
if (access("/proc/cgroups", F_OK) < 0)
- e = stpcpy(e, "cgroups-missing ");
+ stpcpy(e, "cgroups-missing ");
t = strstrip(buf);
diff --git a/src/detect-virt.c b/src/detect-virt.c
index 57f0176668..79cad5d8ab 100644
--- a/src/detect-virt.c
+++ b/src/detect-virt.c
@@ -25,16 +25,18 @@
#include <string.h>
#include "util.h"
+#include "virt.h"
int main(int argc, char *argv[]) {
- int r;
+ Virtualization r;
const char *id;
/* This is mostly intended to be used for scripts which want
* to detect whether we are being run in a virtualized
* environment or not */
- if ((r = detect_virtualization(&id)) < 0) {
+ r = detect_virtualization(&id);
+ if (r < 0) {
log_error("Failed to check for virtualization: %s", strerror(-r));
return EXIT_FAILURE;
}
@@ -42,5 +44,5 @@ int main(int argc, char *argv[]) {
if (r > 0)
puts(id);
- return r == 0;
+ return r > 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/src/execute.c b/src/execute.c
index 53e7e77fde..866e8bf2f6 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -895,12 +895,9 @@ static int do_capability_bounding_set_drop(uint64_t drop) {
}
}
- for (i = 0; i <= MAX(63LU, (unsigned long) CAP_LAST_CAP); i++)
+ for (i = 0; i <= cap_last_cap(); i++)
if (drop & ((uint64_t) 1ULL << (uint64_t) i)) {
if (prctl(PR_CAPBSET_DROP, i) < 0) {
- if (errno == EINVAL)
- break;
-
r = -errno;
goto finish;
}
@@ -1720,7 +1717,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
unsigned long l;
fprintf(f, "%sCapabilityBoundingSet:", prefix);
- for (l = 0; l <= (unsigned long) CAP_LAST_CAP; l++)
+ for (l = 0; l <= cap_last_cap(); l++)
if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l))) {
char *t;
diff --git a/src/fsck.c b/src/fsck.c
index d7d4839f1c..3477ba16ad 100644
--- a/src/fsck.c
+++ b/src/fsck.c
@@ -34,6 +34,7 @@
#include "dbus-common.h"
#include "special.h"
#include "bus-errors.h"
+#include "virt.h"
static bool arg_skip = false;
static bool arg_force = false;
@@ -126,7 +127,7 @@ static int parse_proc_cmdline(void) {
arg_skip = true;
else if (startswith(w, "fsck.mode"))
log_warning("Invalid fsck.mode= parameter. Ignoring.");
-#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA)
+#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
else if (strneq(w, "fastboot", l))
arg_skip = true;
else if (strneq(w, "forcefsck", l))
diff --git a/src/generate-kbd-model-map b/src/generate-kbd-model-map
new file mode 100755
index 0000000000..624c5179fa
--- /dev/null
+++ b/src/generate-kbd-model-map
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+
+import sys
+import system_config_keyboard.keyboard_models
+
+def strdash(s):
+ return s.strip() or '-'
+
+def tab_extend(s, n=1):
+ s = strdash(s)
+ k = len(s) // 8
+
+ if k >= n:
+ f = 1
+ else:
+ f = n - k
+
+ return s + '\t'*f
+
+
+models = system_config_keyboard.keyboard_models.KeyboardModels().get_models()
+
+print "# Generated from system-config-keyboard's model list"
+print "# consolelayout\t\txlayout\txmodel\t\txvariant\txoptions"
+
+for key, value in reversed(models.items()):
+ options = "terminate:ctrl_alt_bksp"
+ if value[4]:
+ options += ',' + value[4]
+
+ print ''.join((tab_extend(key, 3), tab_extend(value[1]),
+ tab_extend(value[2], 2), tab_extend(value[3], 2),
+ options))
diff --git a/src/getty-generator.c b/src/getty-generator.c
index d4beffaeff..6b5b254e6a 100644
--- a/src/getty-generator.c
+++ b/src/getty-generator.c
@@ -26,6 +26,7 @@
#include "log.h"
#include "util.h"
#include "unit-name.h"
+#include "virt.h"
const char *arg_dest = "/tmp";
diff --git a/src/hashmap.c b/src/hashmap.c
index 0d89da4614..95ea45da48 100644
--- a/src/hashmap.c
+++ b/src/hashmap.c
@@ -124,11 +124,13 @@ __attribute__((destructor)) static void cleanup_pool(void) {
#endif
unsigned string_hash_func(const void *p) {
- unsigned hash = 0;
- const char *c;
+ unsigned hash = 5381;
+ const signed char *c;
+
+ /* DJB's hash function */
for (c = p; *c; c++)
- hash = 31 * hash + (unsigned) *c;
+ hash = (hash << 5) + hash + (unsigned) *c;
return hash;
}
diff --git a/src/hostname-setup.c b/src/hostname-setup.c
index 57db9fbf7c..2c2f10cfd1 100644
--- a/src/hostname-setup.c
+++ b/src/hostname-setup.c
@@ -30,9 +30,9 @@
#include "util.h"
#include "log.h"
-#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO)
+#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) || defined(TARGET_MAGEIA)
#define FILENAME "/etc/sysconfig/network"
-#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE) || defined(TARGET_FRUGALWARE)
+#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
#define FILENAME "/etc/HOSTNAME"
#elif defined(TARGET_ARCH)
#define FILENAME "/etc/rc.conf"
@@ -64,7 +64,7 @@ static int read_and_strip_hostname(const char *path, char **hn) {
static int read_distro_hostname(char **hn) {
-#if defined(TARGET_FEDORA) || defined(TARGET_ARCH) || defined(TARGET_GENTOO) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO)
+#if defined(TARGET_FEDORA) || defined(TARGET_ARCH) || defined(TARGET_GENTOO) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) || defined(TARGET_MAGEIA)
int r;
FILE *f;
@@ -114,7 +114,7 @@ finish:
fclose(f);
return r;
-#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE) || defined(TARGET_FRUGALWARE)
+#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
return read_and_strip_hostname(FILENAME, hn);
#else
return -ENOENT;
diff --git a/src/hostnamed.c b/src/hostnamed.c
index 9e8825da75..f3b2c94173 100644
--- a/src/hostnamed.c
+++ b/src/hostnamed.c
@@ -31,6 +31,7 @@
#include "dbus-common.h"
#include "polkit.h"
#include "def.h"
+#include "virt.h"
#define INTERFACE \
" <interface name=\"org.freedesktop.hostname1\">\n" \
@@ -233,7 +234,7 @@ static int write_data_other(void) {
assert(name[p]);
if (isempty(data[p])) {
- l = strv_env_unset(l, name[p]);
+ strv_env_unset(l, name[p]);
continue;
}
@@ -396,7 +397,7 @@ static DBusHandlerResult hostname_message_handler(
return bus_send_error_reply(connection, message, NULL, r);
}
- log_info("Changed static host name to '%s'", strempty(data[PROP_HOSTNAME]));
+ log_info("Changed static host name to '%s'", strempty(data[PROP_STATIC_HOSTNAME]));
changed = bus_properties_changed_new(
"/org/freedesktop/hostname1",
diff --git a/src/initctl.c b/src/initctl.c
index eaa717ad91..097c85fdd4 100644
--- a/src/initctl.c
+++ b/src/initctl.c
@@ -56,6 +56,8 @@ typedef struct Server {
unsigned n_fifos;
DBusConnection *bus;
+
+ bool quit;
} Server;
struct Fifo {
@@ -174,6 +176,13 @@ static void request_process(Server *s, const struct init_request *req) {
case 'U':
if (kill(1, SIGTERM) < 0)
log_error("kill() failed: %m");
+
+ /* The bus connection will be
+ * terminated if PID 1 is reexecuted,
+ * hence let's just exit here, and
+ * rely on that we'll be restarted on
+ * the next request */
+ s->quit = true;
break;
case 'q':
@@ -404,7 +413,7 @@ int main(int argc, char *argv[]) {
"READY=1\n"
"STATUS=Processing requests...");
- for (;;) {
+ while (!server.quit) {
struct epoll_event event;
int k;
diff --git a/src/install.c b/src/install.c
index 7443973502..cfbd50ead9 100644
--- a/src/install.c
+++ b/src/install.c
@@ -479,7 +479,6 @@ static int find_symlinks_fd(
t = path_make_absolute(name, config_path);
if (!t) {
free(p);
- free(dest);
r = -ENOMEM;
break;
}
@@ -1905,7 +1904,7 @@ int unit_file_get_list(
} else if (r > 0) {
f->state = UNIT_FILE_DISABLED;
goto found;
- } else if (r == 0) {
+ } else {
f->state = UNIT_FILE_STATIC;
goto found;
}
diff --git a/src/job.c b/src/job.c
index 26e1a7ce99..20971da852 100644
--- a/src/job.c
+++ b/src/job.c
@@ -527,6 +527,7 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
Unit *other;
JobType t;
Iterator i;
+ bool recursed = false;
assert(j);
assert(j->installed);
@@ -544,7 +545,9 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
j->type = JOB_START;
job_add_to_run_queue(j);
- return 0;
+
+ u = j->unit;
+ goto finish;
}
j->result = result;
@@ -571,23 +574,29 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
if (other->meta.job &&
(other->meta.job->type == JOB_START ||
other->meta.job->type == JOB_VERIFY_ACTIVE ||
- other->meta.job->type == JOB_RELOAD_OR_START))
+ other->meta.job->type == JOB_RELOAD_OR_START)) {
job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
+ recursed = true;
+ }
SET_FOREACH(other, u->meta.dependencies[UNIT_BOUND_BY], i)
if (other->meta.job &&
(other->meta.job->type == JOB_START ||
other->meta.job->type == JOB_VERIFY_ACTIVE ||
- other->meta.job->type == JOB_RELOAD_OR_START))
+ other->meta.job->type == JOB_RELOAD_OR_START)) {
job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
+ recursed = true;
+ }
SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
if (other->meta.job &&
!other->meta.job->override &&
(other->meta.job->type == JOB_START ||
other->meta.job->type == JOB_VERIFY_ACTIVE ||
- other->meta.job->type == JOB_RELOAD_OR_START))
+ other->meta.job->type == JOB_RELOAD_OR_START)) {
job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
+ recursed = true;
+ }
} else if (t == JOB_STOP) {
@@ -595,8 +604,10 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
if (other->meta.job &&
(other->meta.job->type == JOB_START ||
other->meta.job->type == JOB_VERIFY_ACTIVE ||
- other->meta.job->type == JOB_RELOAD_OR_START))
+ other->meta.job->type == JOB_RELOAD_OR_START)) {
job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
+ recursed = true;
+ }
}
}
@@ -613,6 +624,7 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
unit_trigger_on_failure(u);
}
+finish:
/* Try to start the next jobs that can be started */
SET_FOREACH(other, u->meta.dependencies[UNIT_AFTER], i)
if (other->meta.job)
@@ -623,7 +635,7 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
manager_check_finished(u->meta.manager);
- return 0;
+ return recursed;
}
int job_start_timer(Job *j) {
diff --git a/src/kbd-model-map b/src/kbd-model-map
new file mode 100644
index 0000000000..a895880269
--- /dev/null
+++ b/src/kbd-model-map
@@ -0,0 +1,72 @@
+# Generated from system-config-keyboard's model list
+# consolelayout xlayout xmodel xvariant xoptions
+sg ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp
+nl nl pc105 - terminate:ctrl_alt_bksp
+mk-utf mkd,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+trq tr pc105 - terminate:ctrl_alt_bksp
+guj in,us pc105 guj terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+uk gb pc105 - terminate:ctrl_alt_bksp
+is-latin1 is pc105 - terminate:ctrl_alt_bksp
+de de pc105 - terminate:ctrl_alt_bksp
+gur gur,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+la-latin1 latam pc105 - terminate:ctrl_alt_bksp
+us us pc105+inet - terminate:ctrl_alt_bksp
+ko kr pc105 - terminate:ctrl_alt_bksp
+ro-std ro pc105 std terminate:ctrl_alt_bksp
+de-latin1 de pc105 - terminate:ctrl_alt_bksp
+tml-inscript in,us pc105 tam terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+slovene si pc105 - terminate:ctrl_alt_bksp
+hu101 hu pc105 qwerty terminate:ctrl_alt_bksp
+jp106 jp jp106 - terminate:ctrl_alt_bksp
+croat hr pc105 - terminate:ctrl_alt_bksp
+ben-probhat in,us pc105 ben_probhat terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+fi-latin1 fi pc105 - terminate:ctrl_alt_bksp
+it2 it pc105 - terminate:ctrl_alt_bksp
+hu hu pc105 - terminate:ctrl_alt_bksp
+sr-latin rs pc105 latin terminate:ctrl_alt_bksp
+fi fi pc105 - terminate:ctrl_alt_bksp
+fr_CH ch pc105 fr terminate:ctrl_alt_bksp
+dk-latin1 dk pc105 - terminate:ctrl_alt_bksp
+fr fr pc105 - terminate:ctrl_alt_bksp
+it it pc105 - terminate:ctrl_alt_bksp
+tml-uni in,us pc105 tam_TAB terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ua-utf ua,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+fr-latin1 fr pc105 - terminate:ctrl_alt_bksp
+sg-latin1 ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp
+be-latin1 be pc105 - terminate:ctrl_alt_bksp
+dk dk pc105 - terminate:ctrl_alt_bksp
+fr-pc fr pc105 - terminate:ctrl_alt_bksp
+bg_pho-utf8 bg,us pc105 ,phonetic terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+it-ibm it pc105 - terminate:ctrl_alt_bksp
+cz-us-qwertz cz,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ar-digits ara,us pc105 digits terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+br-abnt2 br abnt2 - terminate:ctrl_alt_bksp
+ro ro pc105 - terminate:ctrl_alt_bksp
+us-acentos us pc105 intl terminate:ctrl_alt_bksp
+pt-latin1 pt pc105 - terminate:ctrl_alt_bksp
+ro-std-cedilla ro pc105 std_cedilla terminate:ctrl_alt_bksp
+tj tj pc105 - terminate:ctrl_alt_bksp
+ar-qwerty ara,us pc105 qwerty terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ar-azerty-digits ara,us pc105 azerty_digits terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ben in,us pc105 ben terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+de-latin1-nodeadkeys de pc105 nodeadkeys terminate:ctrl_alt_bksp
+no no pc105 - terminate:ctrl_alt_bksp
+bg_bds-utf8 bg,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+dvorak us pc105 dvorak terminate:ctrl_alt_bksp
+ru ru,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+cz-lat2 cz pc105 qwerty terminate:ctrl_alt_bksp
+pl2 pl pc105 - terminate:ctrl_alt_bksp
+es es pc105 - terminate:ctrl_alt_bksp
+ro-cedilla ro pc105 cedilla terminate:ctrl_alt_bksp
+ie ie pc105 - terminate:ctrl_alt_bksp
+ar-azerty ara,us pc105 azerty terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ar-qwerty-digits ara,us pc105 qwerty_digits terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+et ee pc105 - terminate:ctrl_alt_bksp
+sk-qwerty sk pc105 - terminate:ctrl_alt_bksp,qwerty
+dev dev,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+fr-latin9 fr pc105 latin9 terminate:ctrl_alt_bksp
+fr_CH-latin1 ch pc105 fr terminate:ctrl_alt_bksp
+cf ca(fr) pc105 - terminate:ctrl_alt_bksp
+sv-latin1 se pc105 - terminate:ctrl_alt_bksp
+sr-cy rs pc105 - terminate:ctrl_alt_bksp
+gr gr,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
diff --git a/src/kmsg-syslogd.c b/src/kmsg-syslogd.c
index 83c2047a7a..0901a0e49b 100644
--- a/src/kmsg-syslogd.c
+++ b/src/kmsg-syslogd.c
@@ -379,7 +379,7 @@ static int process_event(Server *s, struct epoll_event *ev) {
return -errno;
}
- log_debug("Received SIG%s", strna(signal_to_string(sfsi.ssi_signo)));
+ log_debug("Received SIG%s", signal_to_string(sfsi.ssi_signo));
return 0;
} else {
diff --git a/src/load-fragment-gperf.gperf.m4 b/src/load-fragment-gperf.gperf.m4
index 08223c5c1b..41797d20c0 100644
--- a/src/load-fragment-gperf.gperf.m4
+++ b/src/load-fragment-gperf.gperf.m4
@@ -112,11 +112,14 @@ Unit.JobTimeoutSec, config_parse_usec, 0,
Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, 0
Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, 0
Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, 0
+Unit.ConditionPathIsSymbolicLink,config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,0
+Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, 0
Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, 0
Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, 0
Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, 0
Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, 0
Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, 0
+Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, 0
Unit.ConditionNull, config_parse_unit_condition_null, 0, 0
m4_dnl
Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file)
diff --git a/src/load-fragment.c b/src/load-fragment.c
index c8b4b5a9c6..12079c640f 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -554,6 +554,7 @@ int config_parse_exec(
if (!n[0]) {
log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
strv_free(n);
+ free(path);
return 0;
}
@@ -1545,10 +1546,12 @@ int config_parse_unit_condition_path(
assert(rvalue);
assert(data);
- if ((trigger = rvalue[0] == '|'))
+ trigger = rvalue[0] == '|';
+ if (trigger)
rvalue++;
- if ((negate = rvalue[0] == '!'))
+ negate = rvalue[0] == '!';
+ if (negate)
rvalue++;
if (!path_is_absolute(rvalue)) {
@@ -1556,7 +1559,8 @@ int config_parse_unit_condition_path(
return 0;
}
- if (!(c = condition_new(cond, rvalue, trigger, negate)))
+ c = condition_new(cond, rvalue, trigger, negate);
+ if (!c)
return -ENOMEM;
LIST_PREPEND(Condition, conditions, u->meta.conditions, c);
diff --git a/src/locale-setup.c b/src/locale-setup.c
index 41eb50bbba..7f692e9c5d 100644
--- a/src/locale-setup.c
+++ b/src/locale-setup.c
@@ -26,6 +26,7 @@
#include "locale-setup.h"
#include "util.h"
#include "macro.h"
+#include "virt.h"
enum {
/* We don't list LC_ALL here on purpose. People should be
@@ -198,7 +199,7 @@ int locale_setup(void) {
if (r != -ENOENT)
log_warning("Failed to read /etc/profile.env: %s", strerror(-r));
}
-#elif defined(TARGET_MANDRIVA)
+#elif defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA )
if (r <= 0 &&
(r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
"LANG", &variables[VARIABLE_LANG],
diff --git a/src/localed.c b/src/localed.c
index f652110db4..c6b48de5f9 100644
--- a/src/localed.c
+++ b/src/localed.c
@@ -34,10 +34,30 @@
#define INTERFACE \
" <interface name=\"org.freedesktop.locale1\">\n" \
" <property name=\"Locale\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"VConsoleKeymap\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"VConsoleKeymapToggle\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"X11Layout\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"X11Model\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"X11Variant\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"X11Options\" type=\"s\" access=\"read\"/>\n" \
" <method name=\"SetLocale\">\n" \
" <arg name=\"locale\" type=\"as\" direction=\"in\"/>\n" \
" <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
" </method>\n" \
+ " <method name=\"SetVConsoleKeyboard\">\n" \
+ " <arg name=\"keymap\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"keymap_toggle\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"convert\" type=\"b\" direction=\"in\"/>\n" \
+ " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
+ " </method>\n" \
+ " <method name=\"SetX11Keyboard\">\n" \
+ " <arg name=\"layout\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"model\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"variant\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"options\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"convert\" type=\"b\" direction=\"in\"/>\n" \
+ " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
+ " </method>\n" \
" </interface>\n"
#define INTROSPECTION \
@@ -109,9 +129,28 @@ static char *data[_PROP_MAX] = {
NULL
};
+static char *x11_layout = NULL, *x11_model = NULL, *x11_variant = NULL, *x11_options = NULL;
+static char *vc_keymap = NULL, *vc_keymap_toggle = NULL;
+
static usec_t remain_until = 0;
-static void free_data(void) {
+static int free_and_set(char **s, const char *v) {
+ int r;
+ char *t;
+
+ assert(s);
+
+ r = strdup_or_null(isempty(v) ? NULL : v, &t);
+ if (r < 0)
+ return r;
+
+ free(*s);
+ *s = t;
+
+ return 0;
+}
+
+static void free_data_locale(void) {
int p;
for (p = 0; p < _PROP_MAX; p++) {
@@ -120,6 +159,22 @@ static void free_data(void) {
}
}
+static void free_data_x11(void) {
+ free(x11_layout);
+ free(x11_model);
+ free(x11_variant);
+ free(x11_options);
+
+ x11_layout = x11_model = x11_variant = x11_options = NULL;
+}
+
+static void free_data_vconsole(void) {
+ free(vc_keymap);
+ free(vc_keymap_toggle);
+
+ vc_keymap = vc_keymap_toggle = NULL;
+}
+
static void simplify(void) {
int p;
@@ -130,10 +185,10 @@ static void simplify(void) {
}
}
-static int read_data(void) {
+static int read_data_locale(void) {
int r;
- free_data();
+ free_data_locale();
r = parse_env_file("/etc/locale.conf", NEWLINE,
"LANG", &data[PROP_LANG],
@@ -181,7 +236,129 @@ static int read_data(void) {
return r;
}
-static int write_data(void) {
+static void free_data(void) {
+ free_data_locale();
+ free_data_vconsole();
+ free_data_x11();
+}
+
+static int read_data_vconsole(void) {
+ int r;
+
+ free_data_vconsole();
+
+ r = parse_env_file("/etc/vconsole.conf", NEWLINE,
+ "KEYMAP", &vc_keymap,
+ "KEYMAP_TOGGLE", &vc_keymap_toggle,
+ NULL);
+
+ if (r < 0 && r != -ENOENT)
+ return r;
+
+ return 0;
+}
+
+static int read_data_x11(void) {
+ FILE *f;
+ char line[LINE_MAX];
+ bool in_section = false;
+
+ free_data_x11();
+
+ f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re");
+ if (!f) {
+ if (errno == ENOENT) {
+
+#ifdef TARGET_FEDORA
+ f = fopen("/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf", "re");
+ if (!f) {
+ if (errno == ENOENT)
+ return 0;
+ else
+ return -errno;
+ }
+#else
+ return 0;
+#endif
+
+ } else
+ return -errno;
+ }
+
+ while (fgets(line, sizeof(line), f)) {
+ char *l;
+
+ char_array_0(line);
+ l = strstrip(line);
+
+ if (l[0] == 0 || l[0] == '#')
+ continue;
+
+ if (in_section && first_word(l, "Option")) {
+ char **a;
+
+ a = strv_split_quoted(l);
+ if (!a) {
+ fclose(f);
+ return -ENOMEM;
+ }
+
+ if (strv_length(a) == 3) {
+
+ if (streq(a[1], "XkbLayout")) {
+ free(x11_layout);
+ x11_layout = a[2];
+ a[2] = NULL;
+ } else if (streq(a[1], "XkbModel")) {
+ free(x11_model);
+ x11_model = a[2];
+ a[2] = NULL;
+ } else if (streq(a[1], "XkbVariant")) {
+ free(x11_variant);
+ x11_variant = a[2];
+ a[2] = NULL;
+ } else if (streq(a[1], "XkbOptions")) {
+ free(x11_options);
+ x11_options = a[2];
+ a[2] = NULL;
+ }
+ }
+
+ strv_free(a);
+
+ } else if (!in_section && first_word(l, "Section")) {
+ char **a;
+
+ a = strv_split_quoted(l);
+ if (!a) {
+ fclose(f);
+ return -ENOMEM;
+ }
+
+ if (strv_length(a) == 2 && streq(a[1], "InputClass"))
+ in_section = true;
+
+ strv_free(a);
+ } else if (in_section && first_word(l, "EndSection"))
+ in_section = false;
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+static int read_data(void) {
+ int r, q, p;
+
+ r = read_data_locale();
+ q = read_data_vconsole();
+ p = read_data_x11();
+
+ return r < 0 ? r : q < 0 ? q : p;
+}
+
+static int write_data_locale(void) {
int r, p;
char **l = NULL;
@@ -215,6 +392,7 @@ static int write_data(void) {
}
if (strv_isempty(l)) {
+ strv_free(l);
if (unlink("/etc/locale.conf") < 0)
return errno == ENOENT ? 0 : -errno;
@@ -319,6 +497,482 @@ finish:
free(l_unset);
}
+static int write_data_vconsole(void) {
+ int r;
+ char **l = NULL;
+
+ r = load_env_file("/etc/vconsole.conf", &l);
+ if (r < 0 && r != -ENOENT)
+ return r;
+
+ if (isempty(vc_keymap))
+ l = strv_env_unset(l, "KEYMAP");
+ else {
+ char *s, **u;
+
+ s = strappend("KEYMAP=", vc_keymap);
+ if (!s) {
+ strv_free(l);
+ return -ENOMEM;
+ }
+
+ u = strv_env_set(l, s);
+ free(s);
+ strv_free(l);
+
+ if (!u)
+ return -ENOMEM;
+
+ l = u;
+ }
+
+ if (isempty(vc_keymap_toggle))
+ l = strv_env_unset(l, "KEYMAP_TOGGLE");
+ else {
+ char *s, **u;
+
+ s = strappend("KEYMAP_TOGGLE=", vc_keymap_toggle);
+ if (!s) {
+ strv_free(l);
+ return -ENOMEM;
+ }
+
+ u = strv_env_set(l, s);
+ free(s);
+ strv_free(l);
+
+ if (!u)
+ return -ENOMEM;
+
+ l = u;
+ }
+
+ if (strv_isempty(l)) {
+ strv_free(l);
+
+ if (unlink("/etc/vconsole.conf") < 0)
+ return errno == ENOENT ? 0 : -errno;
+
+ return 0;
+ }
+
+ r = write_env_file("/etc/vconsole.conf", l);
+ strv_free(l);
+
+ return r;
+}
+
+static int write_data_x11(void) {
+ FILE *f;
+ char *temp_path;
+ int r;
+
+ if (isempty(x11_layout) &&
+ isempty(x11_model) &&
+ isempty(x11_variant) &&
+ isempty(x11_options)) {
+
+#ifdef TARGET_FEDORA
+ unlink("/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf");
+
+ /* Symlink this to /dev/null, so that s-s-k (if it is
+ * still running) doesn't recreate this. */
+ symlink("/dev/null", "/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf");
+#endif
+
+ if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0)
+ return errno == ENOENT ? 0 : -errno;
+
+ return 0;
+ }
+
+ mkdir_parents("/etc/X11/xorg.conf.d", 0755);
+
+ r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path);
+ if (r < 0)
+ return r;
+
+ fchmod(fileno(f), 0644);
+
+ fputs("# Read and parsed by systemd-localed. It's probably wise not to edit this file\n"
+ "# manually too freely.\n"
+ "Section \"InputClass\"\n"
+ " Identifier \"system-keyboard\"\n"
+ " MatchIsKeyboard \"on\"\n", f);
+
+ if (!isempty(x11_layout))
+ fprintf(f, " Option \"XkbLayout\" \"%s\"\n", x11_layout);
+
+ if (!isempty(x11_model))
+ fprintf(f, " Option \"XkbModel\" \"%s\"\n", x11_model);
+
+ if (!isempty(x11_variant))
+ fprintf(f, " Option \"XkbVariant\" \"%s\"\n", x11_variant);
+
+ if (!isempty(x11_options))
+ fprintf(f, " Option \"XkbOptions\" \"%s\"\n", x11_options);
+
+ fputs("EndSection\n", f);
+ fflush(f);
+
+ if (ferror(f) || rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) {
+ r = -errno;
+ unlink("/etc/X11/xorg.conf.d/00-keyboard.conf");
+ unlink(temp_path);
+ } else {
+
+#ifdef TARGET_FEDORA
+ unlink("/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf");
+
+ /* Symlink this to /dev/null, so that s-s-k (if it is
+ * still running) doesn't recreate this. */
+ symlink("/dev/null", "/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf");
+#endif
+
+ r = 0;
+ }
+
+ fclose(f);
+ free(temp_path);
+
+ return r;
+}
+
+static int load_vconsole_keymap(DBusConnection *bus, DBusError *error) {
+ DBusMessage *m = NULL, *reply = NULL;
+ const char *name = "systemd-vconsole-setup.service", *mode = "replace";
+ int r;
+ DBusError _error;
+
+ assert(bus);
+
+ if (!error) {
+ dbus_error_init(&_error);
+ error = &_error;
+ }
+
+ m = dbus_message_new_method_call(
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "RestartUnit");
+ if (!m) {
+ log_error("Could not allocate message.");
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
+ if (!reply) {
+ log_error("Failed to issue method call: %s", bus_error_message(error));
+ r = -EIO;
+ goto finish;
+ }
+
+ r = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ if (error == &_error)
+ dbus_error_free(error);
+
+ return r;
+}
+
+static char *strnulldash(const char *s) {
+ return s == NULL || *s == 0 || (s[0] == '-' && s[1] == 0) ? NULL : (char*) s;
+}
+
+static int read_next_mapping(FILE *f, unsigned *n, char ***a) {
+ assert(f);
+ assert(n);
+ assert(a);
+
+ for (;;) {
+ char line[LINE_MAX];
+ char *l, **b;
+
+ errno = 0;
+ if (!fgets(line, sizeof(line), f)) {
+
+ if (ferror(f))
+ return errno ? -errno : -EIO;
+
+ return 0;
+ }
+
+ (*n) ++;
+
+ l = strstrip(line);
+ if (l[0] == 0 || l[0] == '#')
+ continue;
+
+ b = strv_split_quoted(l);
+ if (!b)
+ return -ENOMEM;
+
+ if (strv_length(b) < 5) {
+ log_error("Invalid line "SYSTEMD_KBD_MODEL_MAP":%u, ignoring.", *n);
+ strv_free(b);
+ continue;
+
+ }
+
+ *a = b;
+ return 1;
+ }
+}
+
+static int convert_vconsole_to_x11(DBusConnection *connection) {
+ bool modified = false;
+
+ assert(connection);
+
+ if (isempty(vc_keymap)) {
+
+ modified =
+ !isempty(x11_layout) ||
+ !isempty(x11_model) ||
+ !isempty(x11_variant) ||
+ !isempty(x11_options);
+
+ free_data_x11();
+ } else {
+ FILE *f;
+ unsigned n = 0;
+
+ f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
+ if (!f)
+ return -errno;
+
+ for (;;) {
+ char **a;
+ int r;
+
+ r = read_next_mapping(f, &n, &a);
+ if (r < 0) {
+ fclose(f);
+ return r;
+ }
+
+ if (r == 0)
+ break;
+
+ if (!streq(vc_keymap, a[0])) {
+ strv_free(a);
+ continue;
+ }
+
+ if (!streq_ptr(x11_layout, strnulldash(a[1])) ||
+ !streq_ptr(x11_model, strnulldash(a[2])) ||
+ !streq_ptr(x11_variant, strnulldash(a[3])) ||
+ !streq_ptr(x11_options, strnulldash(a[4]))) {
+
+ if (free_and_set(&x11_layout, strnulldash(a[1])) < 0 ||
+ free_and_set(&x11_model, strnulldash(a[2])) < 0 ||
+ free_and_set(&x11_variant, strnulldash(a[3])) < 0 ||
+ free_and_set(&x11_options, strnulldash(a[4])) < 0) {
+ strv_free(a);
+ fclose(f);
+ return -ENOMEM;
+ }
+
+ modified = true;
+ }
+
+ strv_free(a);
+ break;
+ }
+
+ fclose(f);
+ }
+
+ if (modified) {
+ dbus_bool_t b;
+ DBusMessage *changed;
+ int r;
+
+ r = write_data_x11();
+ if (r < 0)
+ log_error("Failed to set X11 keyboard layout: %s", strerror(-r));
+
+ changed = bus_properties_changed_new(
+ "/org/freedesktop/locale1",
+ "org.freedesktop.locale1",
+ "X11Layout\0"
+ "X11Model\0"
+ "X11Variant\0"
+ "X11Options\0");
+
+ if (!changed)
+ return -ENOMEM;
+
+ b = dbus_connection_send(connection, changed, NULL);
+ dbus_message_unref(changed);
+
+ if (!b)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int convert_x11_to_vconsole(DBusConnection *connection) {
+ bool modified = false;
+
+ assert(connection);
+
+ if (isempty(x11_layout)) {
+
+ modified =
+ !isempty(vc_keymap) ||
+ !isempty(vc_keymap_toggle);
+
+ free_data_x11();
+ } else {
+ FILE *f;
+ unsigned n = 0;
+ unsigned best_matching = 0;
+ char *new_keymap = NULL;
+
+ f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
+ if (!f)
+ return -errno;
+
+ for (;;) {
+ char **a;
+ unsigned matching = 0;
+ int r;
+
+ r = read_next_mapping(f, &n, &a);
+ if (r < 0) {
+ fclose(f);
+ return r;
+ }
+
+ if (r == 0)
+ break;
+
+ /* Determine how well matching this entry is */
+ if (streq_ptr(x11_layout, a[1]))
+ /* If we got an exact match, this is best */
+ matching = 10;
+ else {
+ size_t x;
+
+ x = strcspn(x11_layout, ",");
+
+ /* We have multiple X layouts, look
+ * for an entry that matches our key
+ * with the everything but the first
+ * layout stripped off. */
+ if (x > 0 &&
+ strlen(a[1]) == x &&
+ strncmp(x11_layout, a[1], x) == 0)
+ matching = 5;
+ else {
+ size_t w;
+
+ /* If that didn't work, strip
+ * off the other layouts from
+ * the entry, too */
+
+ w = strcspn(a[1], ",");
+
+ if (x > 0 && x == w &&
+ memcmp(x11_layout, a[1], x) == 0)
+ matching = 1;
+ }
+ }
+
+ if (matching > 0 &&
+ streq_ptr(x11_model, a[2])) {
+ matching++;
+
+ if (streq_ptr(x11_variant, a[3])) {
+ matching++;
+
+ if (streq_ptr(x11_options, a[4]))
+ matching++;
+ }
+ }
+
+ /* The best matching entry so far, then let's
+ * save that */
+ if (matching > best_matching) {
+ best_matching = matching;
+
+ free(new_keymap);
+ new_keymap = strdup(a[0]);
+
+ if (!new_keymap) {
+ strv_free(a);
+ fclose(f);
+ return -ENOMEM;
+ }
+ }
+
+ strv_free(a);
+ }
+
+ fclose(f);
+
+ if (!streq_ptr(vc_keymap, new_keymap)) {
+ free(vc_keymap);
+ vc_keymap = new_keymap;
+
+ free(vc_keymap_toggle);
+ vc_keymap_toggle = NULL;
+
+ modified = true;
+ } else
+ free(new_keymap);
+ }
+
+ if (modified) {
+ dbus_bool_t b;
+ DBusMessage *changed;
+ int r;
+
+ r = write_data_vconsole();
+ if (r < 0)
+ log_error("Failed to set virtual console keymap: %s", strerror(-r));
+
+ changed = bus_properties_changed_new(
+ "/org/freedesktop/locale1",
+ "org.freedesktop.locale1",
+ "VConsoleKeymap\0"
+ "VConsoleKeymapToggle\0");
+
+ if (!changed)
+ return -ENOMEM;
+
+ b = dbus_connection_send(connection, changed, NULL);
+ dbus_message_unref(changed);
+
+ if (!b)
+ return -ENOMEM;
+
+ return load_vconsole_keymap(connection, NULL);
+ }
+
+ return 0;
+}
+
static int append_locale(DBusMessageIter *i, const char *property, void *userdata) {
int r, c = 0, p;
char **l;
@@ -353,7 +1007,13 @@ static DBusHandlerResult locale_message_handler(
void *userdata) {
const BusProperty properties[] = {
- { "org.freedesktop.locale1", "Locale", append_locale, "as", NULL},
+ { "org.freedesktop.locale1", "Locale", append_locale, "as", NULL },
+ { "org.freedesktop.locale1", "X11Layout", bus_property_append_string, "s", x11_layout },
+ { "org.freedesktop.locale1", "X11Model", bus_property_append_string, "s", x11_model },
+ { "org.freedesktop.locale1", "X11Variant", bus_property_append_string, "s", x11_variant },
+ { "org.freedesktop.locale1", "X11Options", bus_property_append_string, "s", x11_options },
+ { "org.freedesktop.locale1", "VConsoleKeymap", bus_property_append_string, "s", vc_keymap },
+ { "org.freedesktop.locale1", "VConsoleKeymapToggle", bus_property_append_string, "s", vc_keymap_toggle },
{ NULL, NULL, NULL, NULL, NULL }
};
@@ -459,6 +1119,8 @@ static DBusHandlerResult locale_message_handler(
}
}
+ strv_free(l);
+
for (p = 0; p < _PROP_MAX; p++) {
if (passed[p])
continue;
@@ -469,7 +1131,7 @@ static DBusHandlerResult locale_message_handler(
simplify();
- r = write_data();
+ r = write_data_locale();
if (r < 0) {
log_error("Failed to set locale: %s", strerror(-r));
return bus_send_error_reply(connection, message, NULL, r);
@@ -486,10 +1148,139 @@ static DBusHandlerResult locale_message_handler(
if (!changed)
goto oom;
}
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.locale1", "SetVConsoleKeyboard")) {
+ const char *keymap, *keymap_toggle;
+ dbus_bool_t convert, interactive;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_STRING, &keymap,
+ DBUS_TYPE_STRING, &keymap_toggle,
+ DBUS_TYPE_BOOLEAN, &convert,
+ DBUS_TYPE_BOOLEAN, &interactive,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ if (isempty(keymap))
+ keymap = NULL;
+
+ if (isempty(keymap_toggle))
+ keymap_toggle = NULL;
+
+ if (!streq_ptr(keymap, vc_keymap) ||
+ !streq_ptr(keymap_toggle, vc_keymap_toggle)) {
+
+ r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, &error);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, &error, r);
+
+ if (free_and_set(&vc_keymap, keymap) < 0 ||
+ free_and_set(&vc_keymap_toggle, keymap_toggle) < 0)
+ goto oom;
+
+ r = write_data_vconsole();
+ if (r < 0) {
+ log_error("Failed to set virtual console keymap: %s", strerror(-r));
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ log_info("Changed virtual console keymap to '%s'", strempty(vc_keymap));
+
+ r = load_vconsole_keymap(connection, NULL);
+ if (r < 0)
+ log_error("Failed to request keymap reload: %s", strerror(-r));
+
+ changed = bus_properties_changed_new(
+ "/org/freedesktop/locale1",
+ "org.freedesktop.locale1",
+ "VConsoleKeymap\0"
+ "VConsoleKeymapToggle\0");
+ if (!changed)
+ goto oom;
+
+ if (convert) {
+ r = convert_vconsole_to_x11(connection);
+
+ if (r < 0)
+ log_error("Failed to convert keymap data: %s", strerror(-r));
+ }
+ }
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.locale1", "SetX11Keyboard")) {
+
+ const char *layout, *model, *variant, *options;
+ dbus_bool_t convert, interactive;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_STRING, &layout,
+ DBUS_TYPE_STRING, &model,
+ DBUS_TYPE_STRING, &variant,
+ DBUS_TYPE_STRING, &options,
+ DBUS_TYPE_BOOLEAN, &convert,
+ DBUS_TYPE_BOOLEAN, &interactive,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ if (isempty(layout))
+ layout = NULL;
+
+ if (isempty(model))
+ model = NULL;
+
+ if (isempty(variant))
+ variant = NULL;
+
+ if (isempty(options))
+ options = NULL;
+
+ if (!streq_ptr(layout, x11_layout) ||
+ !streq_ptr(model, x11_model) ||
+ !streq_ptr(variant, x11_variant) ||
+ !streq_ptr(options, x11_options)) {
+
+ r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, &error);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, &error, r);
+
+ if (free_and_set(&x11_layout, layout) < 0 ||
+ free_and_set(&x11_model, model) < 0 ||
+ free_and_set(&x11_variant, variant) < 0 ||
+ free_and_set(&x11_options, options) < 0)
+ goto oom;
+
+ r = write_data_x11();
+ if (r < 0) {
+ log_error("Failed to set X11 keyboard layout: %s", strerror(-r));
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ log_info("Changed X11 keyboard layout to '%s'", strempty(x11_layout));
+
+ changed = bus_properties_changed_new(
+ "/org/freedesktop/locale1",
+ "org.freedesktop.locale1",
+ "X11Layout\0"
+ "X11Model\0"
+ "X11Variant\0"
+ "X11Options\0");
+ if (!changed)
+ goto oom;
+
+ if (convert) {
+ r = convert_x11_to_vconsole(connection);
+
+ if (r < 0)
+ log_error("Failed to convert keymap data: %s", strerror(-r));
+ }
+ }
} else
return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+
if (!(reply = dbus_message_new_method_return(message)))
goto oom;
diff --git a/src/loginctl.c b/src/loginctl.c
index 53058d07a7..89762b66b0 100644
--- a/src/loginctl.c
+++ b/src/loginctl.c
@@ -64,6 +64,8 @@ static bool on_tty(void) {
}
static void pager_open_if_enabled(void) {
+
+ /* Cache result before we open the pager */
on_tty();
if (!arg_no_pager)
@@ -1061,10 +1063,9 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
uid_t uid;
uint32_t u;
- r = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
- if (r < 0) {
+ ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
+ if (ret < 0) {
log_error("User %s unknown.", args[i]);
- r = -ENOENT;
goto finish;
}
@@ -1146,7 +1147,7 @@ finish:
}
static int activate(DBusConnection *bus, char **args, unsigned n) {
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *m = NULL;
int ret = 0;
DBusError error;
unsigned i;
@@ -1157,6 +1158,8 @@ static int activate(DBusConnection *bus, char **args, unsigned n) {
dbus_error_init(&error);
for (i = 1; i < n; i++) {
+ DBusMessage *reply;
+
m = dbus_message_new_method_call(
"org.freedesktop.login1",
"/org/freedesktop/login1",
@@ -1195,16 +1198,13 @@ finish:
if (m)
dbus_message_unref(m);
- if (reply)
- dbus_message_unref(reply);
-
dbus_error_free(&error);
return ret;
}
static int kill_session(DBusConnection *bus, char **args, unsigned n) {
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *m = NULL;
int ret = 0;
DBusError error;
unsigned i;
@@ -1218,6 +1218,8 @@ static int kill_session(DBusConnection *bus, char **args, unsigned n) {
arg_kill_who = "all";
for (i = 1; i < n; i++) {
+ DBusMessage *reply;
+
m = dbus_message_new_method_call(
"org.freedesktop.login1",
"/org/freedesktop/login1",
@@ -1255,16 +1257,13 @@ finish:
if (m)
dbus_message_unref(m);
- if (reply)
- dbus_message_unref(reply);
-
dbus_error_free(&error);
return ret;
}
static int enable_linger(DBusConnection *bus, char **args, unsigned n) {
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *m = NULL;
int ret = 0;
DBusError error;
unsigned i;
@@ -1278,6 +1277,7 @@ static int enable_linger(DBusConnection *bus, char **args, unsigned n) {
b = streq(args[0], "enable-linger");
for (i = 1; i < n; i++) {
+ DBusMessage *reply;
uint32_t u;
uid_t uid;
@@ -1327,16 +1327,13 @@ finish:
if (m)
dbus_message_unref(m);
- if (reply)
- dbus_message_unref(reply);
-
dbus_error_free(&error);
return ret;
}
static int terminate_user(DBusConnection *bus, char **args, unsigned n) {
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *m = NULL;
int ret = 0;
DBusError error;
unsigned i;
@@ -1349,6 +1346,7 @@ static int terminate_user(DBusConnection *bus, char **args, unsigned n) {
for (i = 1; i < n; i++) {
uint32_t u;
uid_t uid;
+ DBusMessage *reply;
m = dbus_message_new_method_call(
"org.freedesktop.login1",
@@ -1394,16 +1392,13 @@ finish:
if (m)
dbus_message_unref(m);
- if (reply)
- dbus_message_unref(reply);
-
dbus_error_free(&error);
return ret;
}
static int kill_user(DBusConnection *bus, char **args, unsigned n) {
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *m = NULL;
int ret = 0;
DBusError error;
unsigned i;
@@ -1417,6 +1412,7 @@ static int kill_user(DBusConnection *bus, char **args, unsigned n) {
arg_kill_who = "all";
for (i = 1; i < n; i++) {
+ DBusMessage *reply;
uid_t uid;
uint32_t u;
@@ -1465,16 +1461,13 @@ finish:
if (m)
dbus_message_unref(m);
- if (reply)
- dbus_message_unref(reply);
-
dbus_error_free(&error);
return ret;
}
static int attach(DBusConnection *bus, char **args, unsigned n) {
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *m = NULL;
int ret = 0;
DBusError error;
unsigned i;
@@ -1486,6 +1479,8 @@ static int attach(DBusConnection *bus, char **args, unsigned n) {
dbus_error_init(&error);
for (i = 2; i < n; i++) {
+ DBusMessage *reply;
+
m = dbus_message_new_method_call(
"org.freedesktop.login1",
"/org/freedesktop/login1",
@@ -1523,9 +1518,6 @@ finish:
if (m)
dbus_message_unref(m);
- if (reply)
- dbus_message_unref(reply);
-
dbus_error_free(&error);
return ret;
@@ -1581,7 +1573,7 @@ finish:
}
static int terminate_seat(DBusConnection *bus, char **args, unsigned n) {
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *m = NULL;
int ret = 0;
DBusError error;
unsigned i;
@@ -1592,6 +1584,8 @@ static int terminate_seat(DBusConnection *bus, char **args, unsigned n) {
dbus_error_init(&error);
for (i = 1; i < n; i++) {
+ DBusMessage *reply;
+
m = dbus_message_new_method_call(
"org.freedesktop.login1",
"/org/freedesktop/login1",
@@ -1627,9 +1621,6 @@ finish:
if (m)
dbus_message_unref(m);
- if (reply)
- dbus_message_unref(reply);
-
dbus_error_free(&error);
return ret;
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index b8f7d6718b..0550d1bd1c 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -381,6 +381,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
session = hashmap_get(m->sessions, id);
if (session) {
+ free(id);
fifo_fd = session_create_fifo(session);
if (fifo_fd < 0) {
@@ -404,12 +405,16 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
goto fail;
}
+ seat = session->seat ? session->seat->id : "";
+ vtnr = session->vtnr;
b = dbus_message_append_args(
reply,
DBUS_TYPE_STRING, &session->id,
DBUS_TYPE_OBJECT_PATH, &p,
DBUS_TYPE_STRING, &session->user->runtime_path,
DBUS_TYPE_UNIX_FD, &fifo_fd,
+ DBUS_TYPE_STRING, &seat,
+ DBUS_TYPE_UINT32, &vtnr,
DBUS_TYPE_INVALID);
free(p);
@@ -421,6 +426,9 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
close_nointr_nofail(fifo_fd);
*_reply = reply;
+ strv_free(controllers);
+ strv_free(reset_controllers);
+
return 0;
}
@@ -965,8 +973,11 @@ static DBusHandlerResult manager_message_handler(
} else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
r = bus_manager_create_session(m, message, &reply);
- if (r == -ENOMEM)
- goto oom;
+
+ /* Don't delay the work on OOM here, since it might be
+ * triggered by a low RLIMIT_NOFILE here (since we
+ * send a dupped fd to the client), and we'd rather
+ * see this fail quickly then be retried later */
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
diff --git a/src/logind.c b/src/logind.c
index 1aad48d2dc..4633a5ef29 100644
--- a/src/logind.c
+++ b/src/logind.c
@@ -413,6 +413,7 @@ static int manager_enumerate_users_from_cgroup(Manager *m) {
int r = 0;
char *name;
DIR *d;
+ int k;
r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &d);
if (r < 0) {
@@ -423,9 +424,8 @@ static int manager_enumerate_users_from_cgroup(Manager *m) {
return r;
}
- while ((r = cg_read_subgroup(d, &name)) > 0) {
+ while ((k = cg_read_subgroup(d, &name)) > 0) {
User *user;
- int k;
k = manager_add_user_by_name(m, name, &user);
if (k < 0) {
@@ -446,6 +446,9 @@ static int manager_enumerate_users_from_cgroup(Manager *m) {
free(name);
}
+ if (r >= 0 && k < 0)
+ r = k;
+
closedir(d);
return r;
diff --git a/src/main.c b/src/main.c
index bfc48e5e39..5c28a6c191 100644
--- a/src/main.c
+++ b/src/main.c
@@ -52,6 +52,7 @@
#include "build.h"
#include "strv.h"
#include "def.h"
+#include "virt.h"
static enum {
ACTION_RUN,
diff --git a/src/manager.c b/src/manager.c
index 6311c10361..111167a8c2 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -59,6 +59,7 @@
#include "bus-errors.h"
#include "exit-status.h"
#include "sd-daemon.h"
+#include "virt.h"
/* As soon as 16 units are in our GC queue, make sure to run a gc sweep */
#define GC_QUEUE_ENTRIES_MAX 16
@@ -285,7 +286,10 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
goto fail;
#ifdef HAVE_AUDIT
- if ((m->audit_fd = audit_open()) < 0)
+ if ((m->audit_fd = audit_open()) < 0 &&
+ /* If the kernel lacks netlink or audit support,
+ * don't worry about it. */
+ errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
log_error("Failed to connect to audit log: %m");
#endif
@@ -1213,13 +1217,18 @@ static int transaction_apply(Manager *m, JobMode mode) {
/* When isolating first kill all installed jobs which
* aren't part of the new transaction */
+ rescan:
HASHMAP_FOREACH(j, m->jobs, i) {
assert(j->installed);
if (hashmap_get(m->transaction_jobs, j->unit))
continue;
- job_finish_and_invalidate(j, JOB_CANCELED);
+ /* 'j' itself is safe to remove, but if other jobs
+ are invalidated recursively, our iterator may become
+ invalid and we need to start over. */
+ if (job_finish_and_invalidate(j, JOB_CANCELED) > 0)
+ goto rescan;
}
}
@@ -2111,11 +2120,11 @@ static int manager_process_signal_fd(Manager *m) {
get_process_name(sfsi.ssi_pid, &p);
log_debug("Received SIG%s from PID %lu (%s).",
- strna(signal_to_string(sfsi.ssi_signo)),
+ signal_to_string(sfsi.ssi_signo),
(unsigned long) sfsi.ssi_pid, strna(p));
free(p);
} else
- log_debug("Received SIG%s.", strna(signal_to_string(sfsi.ssi_signo)));
+ log_debug("Received SIG%s.", signal_to_string(sfsi.ssi_signo));
switch (sfsi.ssi_signo) {
@@ -2233,8 +2242,9 @@ static int manager_process_signal_fd(Manager *m) {
if ((int) sfsi.ssi_signo >= SIGRTMIN+0 &&
(int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) {
- manager_start_target(m, target_table[sfsi.ssi_signo - SIGRTMIN],
- (sfsi.ssi_signo == 1 || sfsi.ssi_signo == 2) ? JOB_ISOLATE : JOB_REPLACE);
+ int idx = (int) sfsi.ssi_signo - SIGRTMIN;
+ manager_start_target(m, target_table[idx],
+ (idx == 1 || idx == 2) ? JOB_ISOLATE : JOB_REPLACE);
break;
}
@@ -2282,7 +2292,7 @@ static int manager_process_signal_fd(Manager *m) {
break;
default:
- log_warning("Got unhandled signal <%s>.", strna(signal_to_string(sfsi.ssi_signo)));
+ log_warning("Got unhandled signal <%s>.", signal_to_string(sfsi.ssi_signo));
}
}
}
diff --git a/src/modules-load.c b/src/modules-load.c
index 4b3b12109c..8dd98f73d8 100644
--- a/src/modules-load.c
+++ b/src/modules-load.c
@@ -77,7 +77,6 @@ int main(int argc, char *argv[]) {
continue;
log_error("Failed to open %s: %m", *fn);
- free(fn);
r = EXIT_FAILURE;
continue;
}
@@ -131,6 +130,7 @@ finish:
if (n_arguments > 3) {
arguments[n_arguments] = NULL;
+ strv_uniq(arguments);
execv("/sbin/modprobe", arguments);
log_error("Failed to execute /sbin/modprobe: %m");
diff --git a/src/mount.c b/src/mount.c
index 829c2cc13c..f9cfe910a0 100644
--- a/src/mount.c
+++ b/src/mount.c
@@ -320,11 +320,14 @@ static bool needs_quota(MountParameters *p) {
return false;
return mount_test_option(p->options, "usrquota") ||
- mount_test_option(p->options, "grpquota");
+ mount_test_option(p->options, "grpquota") ||
+ mount_test_option(p->options, "quota") ||
+ mount_test_option(p->options, "usrjquota") ||
+ mount_test_option(p->options, "grpjquota");
}
static int mount_add_fstab_links(Mount *m) {
- const char *target, *after = NULL;
+ const char *target, *after = NULL, *after2 = NULL;
MountParameters *p;
Unit *tu;
int r;
@@ -354,9 +357,12 @@ static int mount_add_fstab_links(Mount *m) {
if (mount_is_network(p)) {
target = SPECIAL_REMOTE_FS_TARGET;
- after = SPECIAL_NETWORK_TARGET;
- } else
+ after = SPECIAL_REMOTE_FS_PRE_TARGET;
+ after2 = SPECIAL_NETWORK_TARGET;
+ } else {
target = SPECIAL_LOCAL_FS_TARGET;
+ after = SPECIAL_LOCAL_FS_PRE_TARGET;
+ }
if (!path_equal(m->where, "/"))
if ((r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0)
@@ -369,6 +375,10 @@ static int mount_add_fstab_links(Mount *m) {
if ((r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true)) < 0)
return r;
+ if (after2)
+ if ((r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after2, NULL, true)) < 0)
+ return r;
+
if (automount) {
Unit *am;
diff --git a/src/nspawn.c b/src/nspawn.c
index 8c3cf6bfaa..653d7db730 100644
--- a/src/nspawn.c
+++ b/src/nspawn.c
@@ -197,8 +197,10 @@ static int mount_all(const char *dest) {
/* Fix the timezone, if possible */
if (asprintf(&where, "%s/%s", dest, "/etc/localtime") >= 0) {
- mount("/etc/localtime", where, "bind", MS_BIND, NULL);
- mount("/etc/localtime", where, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL);
+
+ if (mount("/etc/localtime", where, "bind", MS_BIND, NULL) >= 0)
+ mount("/etc/localtime", where, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL);
+
free(where);
}
@@ -359,7 +361,7 @@ static int drop_capabilities(void) {
unsigned long l;
- for (l = 0; l <= MAX(63LU, (unsigned long) CAP_LAST_CAP); l++) {
+ for (l = 0; l <= cap_last_cap(); l++) {
unsigned i;
for (i = 0; i < ELEMENTSOF(retain); i++)
@@ -370,12 +372,6 @@ static int drop_capabilities(void) {
continue;
if (prctl(PR_CAPBSET_DROP, l) < 0) {
-
- /* If this capability is not known, EINVAL
- * will be returned, let's ignore this. */
- if (errno == EINVAL)
- break;
-
log_error("PR_CAPBSET_DROP failed: %m");
return -errno;
}
@@ -725,6 +721,7 @@ int main(int argc, char *argv[]) {
gid_t gid = (gid_t) -1;
const char *envp[] = {
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+ "container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */
NULL, /* TERM */
NULL, /* HOME */
NULL, /* USER */
@@ -732,7 +729,7 @@ int main(int argc, char *argv[]) {
NULL
};
- envp[1] = strv_find_prefix(environ, "TERM=");
+ envp[2] = strv_find_prefix(environ, "TERM=");
close_nointr_nofail(master);
@@ -828,9 +825,9 @@ int main(int argc, char *argv[]) {
}
}
- if ((asprintf((char**)(envp + 2), "HOME=%s", home? home: "/root") < 0) ||
- (asprintf((char**)(envp + 3), "USER=%s", arg_user? arg_user : "root") < 0) ||
- (asprintf((char**)(envp + 4), "LOGNAME=%s", arg_user? arg_user : "root") < 0)) {
+ if ((asprintf((char**)(envp + 3), "HOME=%s", home? home: "/root") < 0) ||
+ (asprintf((char**)(envp + 4), "USER=%s", arg_user? arg_user : "root") < 0) ||
+ (asprintf((char**)(envp + 5), "LOGNAME=%s", arg_user? arg_user : "root") < 0)) {
log_error("Out of memory");
goto child_fail;
}
diff --git a/src/org.freedesktop.locale1.policy.in b/src/org.freedesktop.locale1.policy.in
index 186d7d34c5..1ac50bf86c 100644
--- a/src/org.freedesktop.locale1.policy.in
+++ b/src/org.freedesktop.locale1.policy.in
@@ -26,4 +26,14 @@
</defaults>
</action>
+ <action id="org.freedesktop.locale1.set-keyboard">
+ <_description>Set system keyboard settings</_description>
+ <_message>Authentication is required to set the system keyboard settings.</_message>
+ <defaults>
+ <allow_any>auth_admin_keep</allow_any>
+ <allow_inactive>auth_admin_keep</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
</policyconfig>
diff --git a/src/pager.c b/src/pager.c
index be284da962..3fc81820e9 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -20,6 +20,7 @@
***/
#include <sys/types.h>
+#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
@@ -31,6 +32,18 @@
static pid_t pager_pid = 0;
+_noreturn_ static void pager_fallback(void) {
+ ssize_t n;
+ do {
+ n = splice(STDIN_FILENO, NULL, STDOUT_FILENO, NULL, 64*1024, 0);
+ } while (n > 0);
+ if (n < 0) {
+ log_error("Internal pager failed: %m");
+ _exit(EXIT_FAILURE);
+ }
+ _exit(EXIT_SUCCESS);
+}
+
void pager_open(void) {
int fd[2];
const char *pager;
@@ -96,10 +109,9 @@ void pager_open(void) {
execlp("less", "less", NULL);
execlp("more", "more", NULL);
- execlp("cat", "cat", NULL);
- log_error("Unable to execute pager: %m");
- _exit(EXIT_FAILURE);
+ pager_fallback();
+ /* not reached */
}
/* Return in the parent */
diff --git a/src/path.c b/src/path.c
index 1d4aa2174a..f15c9214ef 100644
--- a/src/path.c
+++ b/src/path.c
@@ -563,7 +563,7 @@ static void path_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
assert(l > 0);
if (!(buf = malloc(l))) {
- log_error("Failed to allocate buffer: %s", strerror(-ENOMEM));
+ log_error("Failed to allocate buffer: %s", strerror(ENOMEM));
goto fail;
}
diff --git a/src/quotacheck.c b/src/quotacheck.c
index c475cecc91..60033a8eb2 100644
--- a/src/quotacheck.c
+++ b/src/quotacheck.c
@@ -26,6 +26,7 @@
#include <unistd.h>
#include "util.h"
+#include "virt.h"
static bool arg_skip = false;
static bool arg_force = false;
@@ -53,7 +54,7 @@ static int parse_proc_cmdline(void) {
arg_skip = true;
else if (startswith(w, "quotacheck.mode"))
log_warning("Invalid quotacheck.mode= parameter. Ignoring.");
-#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA)
+#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
else if (strneq(w, "forcequotacheck", l))
arg_force = true;
#endif
@@ -64,8 +65,8 @@ static int parse_proc_cmdline(void) {
}
static void test_files(void) {
-#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA)
- /* This exists only on Fedora or Mandriva */
+#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
+ /* This exists only on Fedora, Mandriva or Mageia */
if (access("/forcequotacheck", F_OK) >= 0)
arg_force = true;
#endif
diff --git a/src/random-seed.c b/src/random-seed.c
index ee5cae315c..0c63794b66 100644
--- a/src/random-seed.c
+++ b/src/random-seed.c
@@ -51,7 +51,11 @@ int main(int argc, char *argv[]) {
/* Read pool size, if possible */
if ((f = fopen("/proc/sys/kernel/random/poolsize", "re"))) {
- fscanf(f, "%zu", &buf_size);
+ if (fscanf(f, "%zu", &buf_size) > 0) {
+ /* poolsize is in bits on 2.6, but we want bytes */
+ buf_size /= 8;
+ }
+
fclose(f);
}
diff --git a/src/readahead-collect.c b/src/readahead-collect.c
index df467f1a42..eac11e7e5c 100644
--- a/src/readahead-collect.c
+++ b/src/readahead-collect.c
@@ -49,6 +49,7 @@
#include "sd-daemon.h"
#include "ioprio.h"
#include "readahead-common.h"
+#include "virt.h"
/* fixme:
*
diff --git a/src/readahead-common.h b/src/readahead-common.h
index 167df316d9..9547ad201c 100644
--- a/src/readahead-common.h
+++ b/src/readahead-common.h
@@ -27,7 +27,7 @@
#include "macro.h"
-#define READAHEAD_FILE_SIZE_MAX (128*1024*1024)
+#define READAHEAD_FILE_SIZE_MAX (10*1024*1024)
int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st);
diff --git a/src/readahead-replay.c b/src/readahead-replay.c
index e97a0cfbbf..65011ac4be 100644
--- a/src/readahead-replay.c
+++ b/src/readahead-replay.c
@@ -41,6 +41,7 @@
#include "sd-daemon.h"
#include "ioprio.h"
#include "readahead-common.h"
+#include "virt.h"
static off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX;
diff --git a/src/sd-login.c b/src/sd-login.c
index 2489d78c60..a0a56c4952 100644
--- a/src/sd-login.c
+++ b/src/sd-login.c
@@ -481,33 +481,39 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui
if (uids && t) {
char *w, *state;
size_t l;
- unsigned i = 0;
FOREACH_WORD(w, l, t, state)
n++;
- b = new(uid_t, n);
- if (!b) {
- strv_free(a);
- return -ENOMEM;
- }
-
- FOREACH_WORD(w, l, t, state) {
- char *k;
+ if (n == 0)
+ b = NULL;
+ else {
+ unsigned i = 0;
- k = strndup(w, l);
- if (!k) {
- free(t);
- free(b);
+ b = new(uid_t, n);
+ if (!b) {
+ strv_free(a);
return -ENOMEM;
}
- r = parse_uid(k, b + i);
- free(k);
- if (r < 0)
- continue;
+ FOREACH_WORD(w, l, t, state) {
+ char *k;
+
+ k = strndup(w, l);
+ if (!k) {
+ free(t);
+ free(b);
+ strv_free(a);
+ return -ENOMEM;
+ }
- i++;
+ r = parse_uid(k, b + i);
+ free(k);
+ if (r < 0)
+ continue;
+
+ i++;
+ }
}
}
@@ -574,6 +580,9 @@ _public_ int sd_get_uids(uid_t **users) {
uid_t *l = NULL;
d = opendir("/run/systemd/users/");
+ if (!d)
+ return -errno;
+
for (;;) {
struct dirent buffer, *de;
int k;
diff --git a/src/sd-login.h b/src/sd-login.h
index 7102eb88e0..0cb0bf06bb 100644
--- a/src/sd-login.h
+++ b/src/sd-login.h
@@ -83,7 +83,7 @@ int sd_session_get_seat(const char *session, char **seat);
int sd_seat_get_active(const char *seat, char **session, uid_t *uid);
/* Return sessions and users on seat. Returns number of sessions as
- * return value. If sessions is NULL returs only the number of
+ * return value. If sessions is NULL returns only the number of
* sessions. */
int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uid, unsigned *n_uids);
@@ -94,7 +94,7 @@ int sd_seat_can_multi_session(const char *seat);
* seats is NULL only returns number of seats. */
int sd_get_seats(char ***seats);
-/* Get all sessions, store in *seessions. Returns the number of
+/* Get all sessions, store in *sessions. Returns the number of
* sessions. If sessions is NULL only returns number of sessions. */
int sd_get_sessions(char ***sessions);
diff --git a/src/selinux-setup.c b/src/selinux-setup.c
index 2abd99e6a2..a7e1fa4007 100644
--- a/src/selinux-setup.c
+++ b/src/selinux-setup.c
@@ -98,11 +98,13 @@ int selinux_setup(bool *loaded_policy) {
*loaded_policy = true;
} else {
+ log_open();
+
if (enforce > 0) {
- log_error("Failed to load SELinux policy.");
+ log_error("Failed to load SELinux policy. Freezing.");
return -EIO;
} else
- log_debug("Unable to load SELinux policy.");
+ log_debug("Unable to load SELinux policy. Ignoring.");
}
#endif
diff --git a/src/service.c b/src/service.c
index abd8f36bdd..eb475d9cc9 100644
--- a/src/service.c
+++ b/src/service.c
@@ -83,7 +83,7 @@ static const struct {
#define RUNLEVELS_UP "12345"
/* #define RUNLEVELS_DOWN "06" */
-/* #define RUNLEVELS_BOOT "bBsS" */
+#define RUNLEVELS_BOOT "bBsS"
#endif
static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
@@ -121,8 +121,6 @@ static void service_init(Unit *u) {
s->guess_main_pid = true;
exec_context_init(&s->exec_context);
- s->exec_context.std_output = u->meta.manager->default_std_output;
- s->exec_context.std_error = u->meta.manager->default_std_error;
RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5);
@@ -279,7 +277,8 @@ static int sysv_translate_facility(const char *name, const char *filename, char
static const char * const table[] = {
/* LSB defined facilities */
"local_fs", SPECIAL_LOCAL_FS_TARGET,
-#ifndef TARGET_MANDRIVA
+#if defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
+#else
/* Due to unfortunate name selection in Mandriva,
* $network is provided by network-up which is ordered
* after network which actually starts interfaces.
@@ -783,19 +782,6 @@ static int service_load_sysv_path(Service *s, const char *path) {
free(short_description);
short_description = d;
- } else if (startswith_no_case(t, "X-Interactive:")) {
- int b;
-
- if ((b = parse_boolean(strstrip(t+14))) < 0) {
- log_warning("[%s:%u] Couldn't parse interactive flag. Ignoring.", path, line);
- continue;
- }
-
- if (b)
- s->exec_context.std_input = EXEC_INPUT_TTY;
- else
- s->exec_context.std_input = EXEC_INPUT_NULL;
-
} else if (state == LSB_DESCRIPTION) {
if (startswith(l, "#\t") || startswith(l, "# ")) {
@@ -826,6 +812,13 @@ static int service_load_sysv_path(Service *s, const char *path) {
if ((r = sysv_exec_commands(s)) < 0)
goto finish;
+ if (s->sysv_runlevels &&
+ chars_intersect(RUNLEVELS_BOOT, s->sysv_runlevels) &&
+ chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
+ /* Service has both boot and "up" runlevels
+ configured. Kill the "up" ones. */
+ delete_chars(s->sysv_runlevels, RUNLEVELS_UP);
+ }
if (s->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
/* If there a runlevels configured for this service
@@ -844,10 +837,12 @@ static int service_load_sysv_path(Service *s, const char *path) {
/* Special setting for all SysV services */
s->type = SERVICE_FORKING;
s->remain_after_exit = !s->pid_file;
+ s->guess_main_pid = false;
s->restart = SERVICE_RESTART_NO;
- s->exec_context.std_output =
- (s->meta.manager->sysv_console || s->exec_context.std_input == EXEC_INPUT_TTY)
- ? EXEC_OUTPUT_TTY : s->meta.manager->default_std_output;
+
+ if (s->meta.manager->sysv_console)
+ s->exec_context.std_output = EXEC_OUTPUT_TTY;
+
s->exec_context.kill_mode = KILL_PROCESS;
/* We use the long description only if
@@ -1113,6 +1108,24 @@ static int service_add_default_dependencies(Service *s) {
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
}
+static void service_fix_output(Service *s) {
+ assert(s);
+
+ /* If nothing has been explicitly configured, patch default
+ * output in. If input is socket/tty we avoid this however,
+ * since in that case we want output to default to the same
+ * place as we read input from. */
+
+ if (s->exec_context.std_error == EXEC_OUTPUT_INHERIT &&
+ s->exec_context.std_output == EXEC_OUTPUT_INHERIT &&
+ s->exec_context.std_input == EXEC_INPUT_NULL)
+ s->exec_context.std_error = s->meta.manager->default_std_error;
+
+ if (s->exec_context.std_output == EXEC_OUTPUT_INHERIT &&
+ s->exec_context.std_input == EXEC_INPUT_NULL)
+ s->exec_context.std_output = s->meta.manager->default_std_output;
+}
+
static int service_load(Unit *u) {
int r;
Service *s = SERVICE(u);
@@ -1141,6 +1154,8 @@ static int service_load(Unit *u) {
/* This is a new unit? Then let's add in some extras */
if (u->meta.load_state == UNIT_LOADED) {
+ service_fix_output(s);
+
if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
return r;
@@ -1275,21 +1290,22 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
free(p2);
}
-static int service_load_pid_file(Service *s) {
+static int service_load_pid_file(Service *s, bool warn_if_missing) {
char *k;
int r;
pid_t pid;
assert(s);
- if (s->main_pid_known)
- return 0;
-
if (!s->pid_file)
- return 0;
+ return -ENOENT;
- if ((r = read_one_line_file(s->pid_file, &k)) < 0)
+ if ((r = read_one_line_file(s->pid_file, &k)) < 0) {
+ if (warn_if_missing)
+ log_warning("Failed to read PID file %s after %s. The service might be broken.",
+ s->pid_file, service_state_to_string(s->state));
return r;
+ }
r = parse_pid(k, &pid);
free(k);
@@ -1303,6 +1319,16 @@ static int service_load_pid_file(Service *s) {
return -ESRCH;
}
+ if (s->main_pid_known) {
+ if (pid == s->main_pid)
+ return 0;
+
+ log_debug("Main PID changing: %lu -> %lu",
+ (unsigned long) s->main_pid, (unsigned long) pid);
+ service_unwatch_main_pid(s);
+ s->main_pid_known = false;
+ }
+
if ((r = service_set_main_pid(s, pid)) < 0)
return r;
@@ -2588,6 +2614,11 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
success = is_clean_exit(code, status);
if (s->main_pid == pid) {
+ /* Forking services may occasionally move to a new PID.
+ * As long as they update the PID file before exiting the old
+ * PID, they're fine. */
+ if (service_load_pid_file(s, false) == 0)
+ return;
s->main_pid = 0;
exec_status_exit(&s->main_exec_status, &s->exec_context, pid, code, status);
@@ -2718,7 +2749,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
* START_POST script */
if (success) {
- service_load_pid_file(s);
+ service_load_pid_file(s, !s->exec_command[SERVICE_EXEC_START_POST]);
service_search_main_pid(s);
service_enter_start_post(s);
@@ -2729,7 +2760,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
case SERVICE_START_POST:
if (success) {
- service_load_pid_file(s);
+ service_load_pid_file(s, true);
service_search_main_pid(s);
}
@@ -2739,7 +2770,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
case SERVICE_RELOAD:
if (success) {
- service_load_pid_file(s);
+ service_load_pid_file(s, true);
service_search_main_pid(s);
}
@@ -3093,7 +3124,7 @@ static int service_enumerate(Manager *m) {
free(fpath);
fpath = join(path, "/", de->d_name, NULL);
- if (!path) {
+ if (!fpath) {
r = -ENOMEM;
goto finish;
}
diff --git a/src/shutdown.c b/src/shutdown.c
index 1c6dc6597b..11213f9d59 100644
--- a/src/shutdown.c
+++ b/src/shutdown.c
@@ -41,6 +41,7 @@
#include "log.h"
#include "umount.h"
#include "util.h"
+#include "virt.h"
#define TIMEOUT_USEC (5 * USEC_PER_SEC)
#define FINALIZE_ATTEMPTS 50
diff --git a/src/socket.c b/src/socket.c
index 572e622011..7ddf326a22 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -844,7 +844,7 @@ static int mq_address_create(
fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr);
umask(old_mask);
- if (fd < 0 && errno != EEXIST) {
+ if (fd < 0) {
r = -errno;
goto fail;
}
@@ -1962,6 +1962,12 @@ int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) {
if (p->fd >= 0)
rn_fds++;
+ if (rn_fds <= 0) {
+ *fds = NULL;
+ *n_fds = 0;
+ return 0;
+ }
+
if (!(rfds = new(int, rn_fds)))
return -ENOMEM;
diff --git a/src/special.h b/src/special.h
index 614e53ca1b..3fe34c955c 100644
--- a/src/special.h
+++ b/src/special.h
@@ -45,7 +45,9 @@
#define SPECIAL_SYSINIT_TARGET "sysinit.target"
#define SPECIAL_SOCKETS_TARGET "sockets.target"
#define SPECIAL_LOCAL_FS_TARGET "local-fs.target" /* LSB's $local_fs */
+#define SPECIAL_LOCAL_FS_PRE_TARGET "local-fs-pre.target"
#define SPECIAL_REMOTE_FS_TARGET "remote-fs.target" /* LSB's $remote_fs */
+#define SPECIAL_REMOTE_FS_PRE_TARGET "remote-fs-pre.target"
#define SPECIAL_SWAP_TARGET "swap.target"
#define SPECIAL_BASIC_TARGET "basic.target"
diff --git a/src/stdout-syslog-bridge.c b/src/stdout-syslog-bridge.c
index 7358a42f70..9a0408819e 100644
--- a/src/stdout-syslog-bridge.c
+++ b/src/stdout-syslog-bridge.c
@@ -88,7 +88,7 @@ struct Stream {
bool prefix:1;
bool tee_console:1;
- char buffer[LINE_MAX];
+ char buffer[LINE_MAX+1];
size_t length;
LIST_FIELDS(Stream, stream);
@@ -321,16 +321,25 @@ static int stream_scan(Stream *s, usec_t ts) {
p = s->buffer;
remaining = s->length;
for (;;) {
- char *newline;
-
- if (!(newline = memchr(p, '\n', remaining)))
- break;
+ char *end;
+ size_t skip;
+
+ end = memchr(p, '\n', remaining);
+ if (!end) {
+ if (remaining >= LINE_MAX) {
+ end = p + LINE_MAX;
+ skip = LINE_MAX;
+ } else
+ break;
+ } else
+ skip = end - p + 1;
- *newline = 0;
+ *end = 0;
- if ((r = stream_line(s, p, ts)) >= 0) {
- remaining -= newline-p+1;
- p = newline+1;
+ r = stream_line(s, p, ts);
+ if (r >= 0) {
+ remaining -= skip;
+ p += skip;
}
}
@@ -347,7 +356,8 @@ static int stream_process(Stream *s, usec_t ts) {
int r;
assert(s);
- if ((l = read(s->fd, s->buffer+s->length, LINE_MAX-s->length)) < 0) {
+ l = read(s->fd, s->buffer+s->length, LINE_MAX-s->length);
+ if (l < 0) {
if (errno == EAGAIN)
return 0;
diff --git a/src/strv.c b/src/strv.c
index 92851b2233..bb309d9f92 100644
--- a/src/strv.c
+++ b/src/strv.c
@@ -67,7 +67,8 @@ void strv_free(char **l) {
char **strv_copy(char **l) {
char **r, **k;
- if (!(k = r = new(char*, strv_length(l)+1)))
+ k = r = new(char*, strv_length(l)+1);
+ if (!k)
return NULL;
if (l)
@@ -198,15 +199,23 @@ char **strv_merge_concat(char **a, char **b, const char *suffix) {
if (!b)
return strv_copy(a);
- if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
+ r = new(char*, strv_length(a) + strv_length(b) + 1);
+ if (!r)
return NULL;
- for (k = r; *a; k++, a++)
- if (!(*k = strdup(*a)))
- goto fail;
- for (; *b; k++, b++)
- if (!(*k = strappend(*b, suffix)))
+ k = r;
+ if (a)
+ for (; *a; k++, a++) {
+ *k = strdup(*a);
+ if (!*k)
+ goto fail;
+ }
+
+ for (; *b; k++, b++) {
+ *k = strappend(*b, suffix);
+ if (!*k)
goto fail;
+ }
*k = NULL;
return r;
@@ -317,7 +326,8 @@ char **strv_append(char **l, const char *s) {
if (!s)
return strv_copy(l);
- if (!(r = new(char*, strv_length(l)+2)))
+ r = new(char*, strv_length(l)+2);
+ if (!r)
return NULL;
for (k = r; *l; k++, l++)
diff --git a/src/sysfs-show.c b/src/sysfs-show.c
index ab866a4707..b8b356d77b 100644
--- a/src/sysfs-show.c
+++ b/src/sysfs-show.c
@@ -165,6 +165,9 @@ int show_sysfs(const char *seat, const char *prefix, unsigned n_columns) {
else
r = udev_enumerate_add_match_tag(e, "seat");
+ if (r < 0)
+ goto finish;
+
r = udev_enumerate_scan_devices(e);
if (r < 0)
goto finish;
diff --git a/src/systemctl-bash-completion.sh b/src/systemctl-bash-completion.sh
deleted file mode 100644
index 6369a6ca39..0000000000
--- a/src/systemctl-bash-completion.sh
+++ /dev/null
@@ -1,150 +0,0 @@
-# This file is part of systemd.
-#
-# Copyright 2010 Ran Benita
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 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
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with systemd; If not, see <http://www.gnu.org/licenses/>.
-
-__contains_word () {
- local word=$1; shift
- for w in $*; do [[ $w = $word ]] && return 0; done
- return 1
-}
-
-__filter_units_by_property () {
- local property=$1 value=$2 ; shift ; shift
- local -a units=( $* )
- local -a props=( $(systemctl show --property "$property" -- ${units[*]} | grep -v ^$) )
- for ((i=0; $i < ${#units[*]}; i++)); do
- if [[ "${props[i]}" = "$property=$value" ]]; then
- echo "${units[i]}"
- fi
- done
-}
-
-__get_all_units () { systemctl list-units --full --all | awk ' {print $1}' ; }
-__get_active_units () { systemctl list-units --full | awk ' {print $1}' ; }
-__get_inactive_units () { systemctl list-units --full --all | awk '$3 == "inactive" {print $1}' ; }
-__get_failed_units () { systemctl list-units --full | awk '$3 == "failed" {print $1}' ; }
-
-_systemctl () {
- local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
- local verb comps
-
- local -A OPTS=(
- [STANDALONE]='--all -a --defaults --fail --ignore-dependencies --failed --force -f --full --global
- --help -h --no-ask-password --no-block --no-pager --no-reload --no-wall
- --order --require --quiet -q --privileged -P --system --user --version'
- [ARG]='--host -H --kill-mode --kill-who --property -p --signal -s --type -t'
- )
-
- if __contains_word "$prev" ${OPTS[ARG]}; then
- case $prev in
- --signal|-s)
- comps=$(compgen -A signal | grep '^SIG' | grep -Ev 'RTMIN|RTMAX|JUNK')
- ;;
- --type|-t)
- comps='automount device mount path service snapshot socket swap target timer'
- ;;
- --kill-who)
- comps='all control main'
- ;;
- --kill-mode)
- comps='control-group process'
- ;;
- --property|-p|--host|-H)
- comps=''
- ;;
- esac
- COMPREPLY=( $(compgen -W "$comps" -- "$cur") )
- return 0
- fi
-
-
- if [[ "$cur" = -* ]]; then
- COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") )
- return 0
- fi
-
- local -A VERBS=(
- [ALL_UNITS]='enable disable is-active is-enabled status show'
- [FAILED_UNITS]='reset-failed'
- [STARTABLE_UNITS]='start'
- [STOPPABLE_UNITS]='stop kill try-restart condrestart'
- [ISOLATABLE_UNITS]='isolate'
- [RELOADABLE_UNITS]='reload reload-or-try-restart force-reload'
- [RESTARTABLE_UNITS]='restart reload-or-restart'
- [JOBS]='cancel'
- [SNAPSHOTS]='delete'
- [ENVS]='set-environment unset-environment'
- [STANDALONE]='daemon-reexec daemon-reload default dot dump emergency exit halt kexec
- list-jobs list-units poweroff reboot rescue show-environment'
- [NAME]='snapshot load'
- )
-
- local verb
- for ((i=0; $i <= $COMP_CWORD; i++)); do
- if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]} &&
- ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG}]}; then
- verb=${COMP_WORDS[i]}
- break
- fi
- done
-
- if [[ -z $verb ]]; then
- comps="${VERBS[*]}"
-
- elif __contains_word "$verb" ${VERBS[ALL_UNITS]}; then
- comps=$( __get_all_units )
-
- elif __contains_word "$verb" ${VERBS[STARTABLE_UNITS]}; then
- comps=$( __filter_units_by_property CanStart yes \
- $( __get_inactive_units | grep -Ev '\.(device|snapshot)$' ))
-
- elif __contains_word "$verb" ${VERBS[RESTARTABLE_UNITS]}; then
- comps=$( __filter_units_by_property CanStart yes \
- $( __get_all_units | grep -Ev '\.(device|snapshot|socket|timer)$' ))
-
- elif __contains_word "$verb" ${VERBS[STOPPABLE_UNITS]}; then
- comps=$( __filter_units_by_property CanStop yes \
- $( __get_active_units ) )
-
- elif __contains_word "$verb" ${VERBS[RELOADABLE_UNITS]}; then
- comps=$( __filter_units_by_property CanReload yes \
- $( __get_active_units ) )
-
- elif __contains_word "$verb" ${VERBS[ISOLATABLE_UNITS]}; then
- comps=$( __filter_units_by_property AllowIsolate yes \
- $( __get_all_units ) )
-
- elif __contains_word "$verb" ${VERBS[FAILED_UNITS]}; then
- comps=$( __get_failed_units )
-
- elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[NAME]}; then
- comps=''
-
- elif __contains_word "$verb" ${VERBS[JOBS]}; then
- comps=$( systemctl list-jobs | awk '{print $1}' )
-
- elif __contains_word "$verb" ${VERBS[SNAPSHOTS]}; then
- comps=$( systemctl list-units --type snapshot --full --all | awk '{print $1}' )
-
- elif __contains_word "$verb" ${VERBS[ENVS]}; then
- comps=$( systemctl show-environment | sed 's_\([^=]\+=\).*_\1_' )
- compopt -o nospace
- fi
-
- COMPREPLY=( $(compgen -W "$comps" -- "$cur") )
- return 0
-}
-complete -F _systemctl systemctl
diff --git a/src/systemctl.c b/src/systemctl.c
index 7caeb6dd91..175159d68f 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -66,6 +66,7 @@ static const char *arg_job_mode = "replace";
static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
static bool arg_immediate = false;
static bool arg_no_block = false;
+static bool arg_no_legend = false;
static bool arg_no_pager = false;
static bool arg_no_wtmp = false;
static bool arg_no_sync = false;
@@ -137,6 +138,8 @@ static bool on_tty(void) {
}
static void pager_open_if_enabled(void) {
+
+ /* Cache result before we open the pager */
on_tty();
if (arg_no_pager)
@@ -312,35 +315,60 @@ static bool output_show_unit(const struct unit_info *u) {
}
static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
- unsigned active_len, sub_len, job_len, n_shown = 0;
+ unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
const struct unit_info *u;
+ max_id_len = sizeof("UNIT")-1;
active_len = sizeof("ACTIVE")-1;
sub_len = sizeof("SUB")-1;
job_len = sizeof("JOB")-1;
+ desc_len = 0;
for (u = unit_infos; u < unit_infos + c; u++) {
if (!output_show_unit(u))
continue;
+ max_id_len = MAX(max_id_len, strlen(u->id));
active_len = MAX(active_len, strlen(u->active_state));
sub_len = MAX(sub_len, strlen(u->sub_state));
if (u->job_id != 0)
job_len = MAX(job_len, strlen(u->job_type));
}
- if (on_tty()) {
- printf("%-25s %-6s %-*s %-*s %-*s", "UNIT", "LOAD",
+ if (!arg_full) {
+ unsigned basic_len;
+ id_len = MIN(max_id_len, 25);
+ basic_len = 5 + id_len + 6 + active_len + sub_len + job_len;
+ if (basic_len < (unsigned) columns()) {
+ unsigned extra_len, incr;
+ extra_len = columns() - basic_len;
+ /* Either UNIT already got 25, or is fully satisfied.
+ * Grant up to 25 to DESC now. */
+ incr = MIN(extra_len, 25);
+ desc_len += incr;
+ extra_len -= incr;
+ /* split the remaining space between UNIT and DESC,
+ * but do not give UNIT more than it needs. */
+ if (extra_len > 0) {
+ incr = MIN(extra_len / 2, max_id_len - id_len);
+ id_len += incr;
+ desc_len += extra_len - incr;
+ }
+ }
+ } else
+ id_len = max_id_len;
+
+ if (!arg_no_legend) {
+ printf("%-*s %-6s %-*s %-*s %-*s ", id_len, "UNIT", "LOAD",
active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB");
- if (columns() >= 80+12 || arg_full || !arg_no_pager)
- printf(" %s\n", "DESCRIPTION");
+ if (!arg_full && arg_no_pager)
+ printf("%.*s\n", desc_len, "DESCRIPTION");
else
- printf("\n");
+ printf("%s\n", "DESCRIPTION");
}
for (u = unit_infos; u < unit_infos + c; u++) {
char *e;
- int a = 0, b = 0;
const char *on_loaded, *off_loaded;
const char *on_active, *off_active;
@@ -362,39 +390,23 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
} else
on_active = off_active = "";
- e = arg_full ? NULL : ellipsize(u->id, 25, 33);
+ e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
- printf("%-25s %s%-6s%s %s%-*s %-*s%s%n",
- e ? e : u->id,
+ printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s ",
+ id_len, e ? e : u->id,
on_loaded, u->load_state, off_loaded,
on_active, active_len, u->active_state,
sub_len, u->sub_state, off_active,
- &a);
-
- free(e);
-
- a -= strlen(on_loaded) + strlen(off_loaded);
- a -= strlen(on_active) + strlen(off_active);
-
- if (u->job_id != 0)
- printf(" %-*s", job_len, u->job_type);
+ job_len, u->job_id ? u->job_type : "");
+ if (!arg_full && arg_no_pager)
+ printf("%.*s\n", desc_len, u->description);
else
- b = 1 + job_len;
-
- if (a + b + 1 < columns()) {
- if (u->job_id == 0)
- printf(" %-*s", job_len, "");
+ printf("%s\n", u->description);
- if (arg_full || !arg_no_pager)
- printf(" %s", u->description);
- else
- printf(" %.*s", columns() - a - b - 1, u->description);
- }
-
- fputs("\n", stdout);
+ free(e);
}
- if (on_tty()) {
+ if (!arg_no_legend) {
printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n"
"ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
"SUB = The low-level unit activation state, values depend on unit type.\n"
@@ -539,11 +551,30 @@ static bool output_show_unit_file(const UnitFileList *u) {
}
static void output_unit_file_list(const UnitFileList *units, unsigned c) {
- unsigned n_shown = 0;
+ unsigned max_id_len, id_cols, state_cols, n_shown = 0;
const UnitFileList *u;
- if (on_tty())
- printf("%-25s %-6s\n", "UNIT FILE", "STATE");
+ max_id_len = sizeof("UNIT FILE")-1;
+ state_cols = sizeof("STATE")-1;
+ for (u = units; u < units + c; u++) {
+ if (!output_show_unit_file(u))
+ continue;
+
+ max_id_len = MAX(max_id_len, strlen(file_name_from_path(u->path)));
+ state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
+ }
+
+ if (!arg_full) {
+ unsigned basic_cols;
+ id_cols = MIN(max_id_len, 25);
+ basic_cols = 1 + id_cols + state_cols;
+ if (basic_cols < (unsigned) columns())
+ id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
+ } else
+ id_cols = max_id_len;
+
+ if (!arg_no_legend)
+ printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
for (u = units; u < units + c; u++) {
char *e;
@@ -568,16 +599,16 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
id = file_name_from_path(u->path);
- e = arg_full ? NULL : ellipsize(id, 25, 33);
+ e = arg_full ? NULL : ellipsize(id, id_cols, 33);
- printf("%-25s %s%-6s%s\n",
- e ? e : id,
- on, unit_file_state_to_string(u->state), off);
+ printf("%-*s %s%-*s%s\n",
+ id_cols, e ? e : id,
+ on, state_cols, unit_file_state_to_string(u->state), off);
free(e);
}
- if (on_tty())
+ if (!arg_no_legend)
printf("\n%u unit files listed.\n", n_shown);
}
@@ -608,6 +639,7 @@ static int list_unit_files(DBusConnection *bus, char **args) {
r = unit_file_get_list(arg_scope, arg_root, h);
if (r < 0) {
+ unit_file_list_free(h);
log_error("Failed to get unit file list: %s", strerror(-r));
return r;
}
@@ -1054,7 +1086,7 @@ finish:
}
static int load_unit(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *m = NULL;
DBusError error;
int r;
char **name;
@@ -1065,6 +1097,7 @@ static int load_unit(DBusConnection *bus, char **args) {
assert(args);
STRV_FOREACH(name, args+1) {
+ DBusMessage *reply;
if (!(m = dbus_message_new_method_call(
"org.freedesktop.systemd1",
@@ -1102,9 +1135,6 @@ finish:
if (m)
dbus_message_unref(m);
- if (reply)
- dbus_message_unref(reply);
-
dbus_error_free(&error);
return r;
@@ -1794,7 +1824,7 @@ finish:
}
static int kill_unit(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *m = NULL;
int r = 0;
DBusError error;
char **name;
@@ -1811,6 +1841,7 @@ static int kill_unit(DBusConnection *bus, char **args) {
arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process";
STRV_FOREACH(name, args+1) {
+ DBusMessage *reply;
if (!(m = dbus_message_new_method_call(
"org.freedesktop.systemd1",
@@ -1850,9 +1881,6 @@ finish:
if (m)
dbus_message_unref(m);
- if (reply)
- dbus_message_unref(reply);
-
dbus_error_free(&error);
return r;
@@ -2155,8 +2183,6 @@ static void print_status_info(UnitStatusInfo *i) {
printf(")%s\n", off);
- on = off = NULL;
-
if (i->main_pid == p->pid &&
i->start_timestamp == p->start_timestamp &&
i->exit_timestamp == p->start_timestamp)
@@ -3230,7 +3256,7 @@ finish:
}
static int reset_failed(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *m = NULL;
int r;
DBusError error;
char **name;
@@ -3242,6 +3268,7 @@ static int reset_failed(DBusConnection *bus, char **args) {
return daemon_reload(bus, args);
STRV_FOREACH(name, args+1) {
+ DBusMessage *reply;
if (!(m = dbus_message_new_method_call(
"org.freedesktop.systemd1",
@@ -3278,9 +3305,6 @@ finish:
if (m)
dbus_message_unref(m);
- if (reply)
- dbus_message_unref(reply);
-
dbus_error_free(&error);
return r;
@@ -3438,7 +3462,7 @@ finish:
static int enable_sysv_units(char **args) {
int r = 0;
-#if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX))
+#if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
const char *verb = args[0];
unsigned f = 1, t = 1;
LookupPaths paths;
@@ -3929,6 +3953,7 @@ static int systemctl_help(void) {
" --no-wall Don't send wall message before halt/power-off/reboot\n"
" --no-reload When enabling/disabling unit files, don't reload daemon\n"
" configuration\n"
+ " --no-legend Do not print a legend (column headers and hints)\n"
" --no-pager Do not pipe output into a pager\n"
" --no-ask-password\n"
" Do not ask for system passwords\n"
@@ -4079,6 +4104,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
ARG_SYSTEM,
ARG_GLOBAL,
ARG_NO_BLOCK,
+ ARG_NO_LEGEND,
ARG_NO_PAGER,
ARG_NO_WALL,
ARG_ORDER,
@@ -4107,6 +4133,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "system", no_argument, NULL, ARG_SYSTEM },
{ "global", no_argument, NULL, ARG_GLOBAL },
{ "no-block", no_argument, NULL, ARG_NO_BLOCK },
+ { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-wall", no_argument, NULL, ARG_NO_WALL },
{ "quiet", no_argument, NULL, 'q' },
@@ -4195,6 +4222,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
arg_no_block = true;
break;
+ case ARG_NO_LEGEND:
+ arg_no_legend = true;
+ break;
+
case ARG_NO_PAGER:
arg_no_pager = true;
break;
@@ -4981,8 +5012,17 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
return 0;
}
+ if (!bus) {
+ log_error("Failed to get D-Bus connection: %s",
+ dbus_error_is_set(error) ? error->message : "No connection to service manager.");
+ return -EIO;
+ }
+
+ } else {
+
if (!bus && !avoid_bus()) {
- log_error("Failed to get D-Bus connection: %s", error->message);
+ log_error("Failed to get D-Bus connection: %s",
+ dbus_error_is_set(error) ? error->message : "No connection to service manager.");
return -EIO;
}
}
diff --git a/src/systemd-analyze b/src/systemd-analyze
index ae7dcfbd8a..729aa05ca1 100755
--- a/src/systemd-analyze
+++ b/src/systemd-analyze
@@ -82,7 +82,7 @@ if len(sys.argv) <= 1 or sys.argv[1] == 'time':
initrd_time, start_time, finish_time = acquire_start_time()
if initrd_time > 0:
- print "Startup finished in %lums (kernel) + %lums (initrd) + %lums (userspace) = %lums" % ( \
+ print "Startup finished in %lums (kernel) + %lums (initramfs) + %lums (userspace) = %lums" % ( \
initrd_time/1000, \
(start_time - initrd_time)/1000, \
(finish_time - start_time)/1000, \
@@ -116,7 +116,11 @@ elif sys.argv[1] == 'plot':
data = acquire_time_data()
s = sorted(data, key = lambda i: i[1])
- count = 0
+ # Account for kernel and initramfs bars if they exist
+ if initrd_time > 0:
+ count = 3
+ else:
+ count = 2
for name, ixt, aet, axt, iet in s:
@@ -130,7 +134,7 @@ elif sys.argv[1] == 'plot':
bar_space = bar_height * 0.1
# 1000px = 10s, 1px = 10ms
- width = (finish_time - start_time)/10000 + border*2
+ width = finish_time/10000 + border*2
height = count * (bar_height + bar_space) + border * 2
if width < 1000:
@@ -147,7 +151,7 @@ elif sys.argv[1] == 'plot':
context.set_line_width(1)
context.set_source_rgb(0.7, 0.7, 0.7)
- for x in range(0, (finish_time - start_time)/10000, 100):
+ for x in range(0, finish_time/10000 + 100, 100):
context.move_to(x, 0)
context.line_to(x, height-border*2)
@@ -163,11 +167,30 @@ elif sys.argv[1] == 'plot':
banner = "Running on %s (%s %s) %s" % (os.uname()[1], os.uname()[2], os.uname()[3], os.uname()[4])
draw_text(context, 0, -15, banner, hcenter = 0, vcenter = 1)
- for x in range(0, (finish_time - start_time)/10000, 100):
+ for x in range(0, finish_time/10000 + 100, 100):
draw_text(context, x, -5, "%lus" % (x/100), vcenter = 0, hcenter = 0)
y = 0
+ # draw boxes for kernel and initramfs boot time
+ if initrd_time > 0:
+ draw_box(context, 0, y, initrd_time/10000, bar_height, 0.7, 0.7, 0.7)
+ draw_text(context, 10, y + bar_height/2, "kernel", hcenter = 0)
+ y += bar_height + bar_space
+
+ draw_box(context, initrd_time/10000, y, start_time/10000-initrd_time/10000, bar_height, 0.7, 0.7, 0.7)
+ draw_text(context, initrd_time/10000 + 10, y + bar_height/2, "initramfs", hcenter = 0)
+ y += bar_height + bar_space
+
+ else:
+ draw_box(context, 0, y, start_time/10000, bar_height, 0.6, 0.6, 0.6)
+ draw_text(context, 10, y + bar_height/2, "kernel", hcenter = 0)
+ y += bar_height + bar_space
+
+ draw_box(context, start_time/10000, y, finish_time/10000-start_time/10000, bar_height, 0.7, 0.7, 0.7)
+ draw_text(context, start_time/10000 + 10, y + bar_height/2, "userspace", hcenter = 0)
+ y += bar_height + bar_space
+
for name, ixt, aet, axt, iet in s:
drawn = False
@@ -176,7 +199,7 @@ elif sys.argv[1] == 'plot':
if ixt >= start_time and ixt <= finish_time:
# Activating
- a = ixt - start_time
+ a = ixt
b = min(filter(lambda x: x >= ixt, (aet, axt, iet, finish_time))) - ixt
draw_box(context, a/10000, y, b/10000, bar_height, 1, 0, 0)
@@ -188,7 +211,7 @@ elif sys.argv[1] == 'plot':
if aet >= start_time and aet <= finish_time:
# Active
- a = aet - start_time
+ a = aet
b = min(filter(lambda x: x >= aet, (axt, iet, finish_time))) - aet
draw_box(context, a/10000, y, b/10000, bar_height, .8, .6, .6)
@@ -200,7 +223,7 @@ elif sys.argv[1] == 'plot':
if axt >= start_time and axt <= finish_time:
# Deactivating
- a = axt - start_time
+ a = axt
b = min(filter(lambda x: x >= axt, (iet, finish_time))) - axt
draw_box(context, a/10000, y, b/10000, bar_height, .6, .4, .4)
@@ -221,6 +244,18 @@ elif sys.argv[1] == 'plot':
draw_text(context, 0, height-border*2, "Legend: Red = Activating; Pink = Active; Dark Pink = Deactivating", hcenter = 0, vcenter = -1)
+ if initrd_time > 0:
+ draw_text(context, 0, height-border*2 + bar_height, "Startup finished in %lums (kernel) + %lums (initramfs) + %lums (userspace) = %lums" % ( \
+ initrd_time/1000, \
+ (start_time - initrd_time)/1000, \
+ (finish_time - start_time)/1000, \
+ finish_time/1000), hcenter = 0, vcenter = -1)
+ else:
+ draw_text(context, 0, height-border*2 + bar_height, "Startup finished in %lums (kernel) + %lums (userspace) = %lums" % ( \
+ start_time/1000, \
+ (finish_time - start_time)/1000, \
+ finish_time/1000), hcenter = 0, vcenter = -1)
+
surface.finish()
elif sys.argv[1] in ("help", "--help", "-h"):
help()
diff --git a/src/systemd-bash-completion.sh b/src/systemd-bash-completion.sh
new file mode 100644
index 0000000000..176591f281
--- /dev/null
+++ b/src/systemd-bash-completion.sh
@@ -0,0 +1,264 @@
+# This file is part of systemd.
+#
+# Copyright 2010 Ran Benita
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+__systemctl() {
+ systemctl --full --no-legend "$@"
+}
+
+__contains_word () {
+ local word=$1; shift
+ for w in $*; do [[ $w = $word ]] && return 0; done
+ return 1
+}
+
+__filter_units_by_property () {
+ local property=$1 value=$2 ; shift ; shift
+ local -a units=( $* )
+ local -a props=( $(__systemctl show --property "$property" -- ${units[*]} | grep -v ^$) )
+ for ((i=0; $i < ${#units[*]}; i++)); do
+ if [[ "${props[i]}" = "$property=$value" ]]; then
+ echo "${units[i]}"
+ fi
+ done
+}
+
+__get_all_units () { __systemctl list-units --all | awk ' {print $1}' ; }
+__get_active_units () { __systemctl list-units | awk ' {print $1}' ; }
+__get_inactive_units () { __systemctl list-units --all | awk '$3 == "inactive" {print $1}' ; }
+__get_failed_units () { __systemctl list-units | awk '$3 == "failed" {print $1}' ; }
+__get_enabled_units () { __systemctl list-unit-files | awk '$2 == "enabled" {print $1}' ; }
+__get_disabled_units () { __systemctl list-unit-files | awk '$2 == "disabled" {print $1}' ; }
+__get_masked_units () { __systemctl list-unit-files | awk '$2 == "masked" {print $1}' ; }
+
+_systemctl () {
+ local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+ local verb comps
+
+ local -A OPTS=(
+ [STANDALONE]='--all -a --defaults --fail --ignore-dependencies --failed --force -f --full --global
+ --help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall
+ --order --require --quiet -q --privileged -P --system --user --version --runtime'
+ [ARG]='--host -H --kill-mode --kill-who --property -p --signal -s --type -t --root'
+ )
+
+ if __contains_word "$prev" ${OPTS[ARG]}; then
+ case $prev in
+ --signal|-s)
+ comps=$(compgen -A signal)
+ ;;
+ --type|-t)
+ comps='automount device mount path service snapshot socket swap target timer'
+ ;;
+ --kill-who)
+ comps='all control main'
+ ;;
+ --kill-mode)
+ comps='control-group process'
+ ;;
+ --root)
+ comps=$(compgen -A directory -- "$cur" )
+ compopt -o filenames
+ ;;
+ --host|-H)
+ comps=$(compgen -A hostname)
+ ;;
+ --property|-p)
+ comps=''
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "$comps" -- "$cur") )
+ return 0
+ fi
+
+
+ if [[ "$cur" = -* ]]; then
+ COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") )
+ return 0
+ fi
+
+ local -A VERBS=(
+ [ALL_UNITS]='is-active is-enabled status show mask preset'
+ [ENABLED_UNITS]='disable reenable'
+ [DISABLED_UNITS]='enable'
+ [FAILED_UNITS]='reset-failed'
+ [STARTABLE_UNITS]='start'
+ [STOPPABLE_UNITS]='stop condstop kill try-restart condrestart'
+ [ISOLATABLE_UNITS]='isolate'
+ [RELOADABLE_UNITS]='reload condreload reload-or-try-restart force-reload'
+ [RESTARTABLE_UNITS]='restart reload-or-restart'
+ [MASKED_UNITS]='unmask'
+ [JOBS]='cancel'
+ [SNAPSHOTS]='delete'
+ [ENVS]='set-environment unset-environment'
+ [STANDALONE]='daemon-reexec daemon-reload default dot dump
+ emergency exit halt kexec list-jobs list-units
+ list-unit-files poweroff reboot rescue show-environment'
+ [NAME]='snapshot load'
+ [FILE]='link'
+ )
+
+ for ((i=0; $i <= $COMP_CWORD; i++)); do
+ if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]} &&
+ ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG}]}; then
+ verb=${COMP_WORDS[i]}
+ break
+ fi
+ done
+
+ if [[ -z $verb ]]; then
+ comps="${VERBS[*]}"
+
+ elif __contains_word "$verb" ${VERBS[ALL_UNITS]}; then
+ comps=$( __get_all_units )
+
+ elif __contains_word "$verb" ${VERBS[ENABLED_UNITS]}; then
+ comps=$( __get_enabled_units )
+
+ elif __contains_word "$verb" ${VERBS[DISABLED_UNITS]}; then
+ comps=$( __get_disabled_units )
+
+ elif __contains_word "$verb" ${VERBS[STARTABLE_UNITS]}; then
+ comps=$( __filter_units_by_property CanStart yes \
+ $( __get_inactive_units | grep -Ev '\.(device|snapshot)$' ))
+
+ elif __contains_word "$verb" ${VERBS[RESTARTABLE_UNITS]}; then
+ comps=$( __filter_units_by_property CanStart yes \
+ $( __get_all_units | grep -Ev '\.(device|snapshot|socket|timer)$' ))
+
+ elif __contains_word "$verb" ${VERBS[STOPPABLE_UNITS]}; then
+ comps=$( __filter_units_by_property CanStop yes \
+ $( __get_active_units ) )
+
+ elif __contains_word "$verb" ${VERBS[RELOADABLE_UNITS]}; then
+ comps=$( __filter_units_by_property CanReload yes \
+ $( __get_active_units ) )
+
+ elif __contains_word "$verb" ${VERBS[ISOLATABLE_UNITS]}; then
+ comps=$( __filter_units_by_property AllowIsolate yes \
+ $( __get_all_units ) )
+
+ elif __contains_word "$verb" ${VERBS[FAILED_UNITS]}; then
+ comps=$( __get_failed_units )
+
+ elif __contains_word "$verb" ${VERBS[MASKED_UNITS]}; then
+ comps=$( __get_masked_units )
+
+ elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[NAME]}; then
+ comps=''
+
+ elif __contains_word "$verb" ${VERBS[JOBS]}; then
+ comps=$( __systemctl list-jobs | awk '{print $1}' )
+
+ elif __contains_word "$verb" ${VERBS[SNAPSHOTS]}; then
+ comps=$( __systemctl list-units --type snapshot --full --all | awk '{print $1}' )
+
+ elif __contains_word "$verb" ${VERBS[ENVS]}; then
+ comps=$( __systemctl show-environment | sed 's_\([^=]\+=\).*_\1_' )
+ compopt -o nospace
+
+ elif __contains_word "$verb" ${VERBS[FILE]}; then
+ comps=$( compgen -A file -- "$cur" )
+ compopt -o filenames
+ fi
+
+ COMPREPLY=( $(compgen -W "$comps" -- "$cur") )
+ return 0
+}
+complete -F _systemctl systemctl
+
+__get_all_sessions () { systemd-loginctl list-sessions | awk '{print $1}' ; }
+__get_all_users () { systemd-loginctl list-users | awk '{print $2}' ; }
+__get_all_seats () { systemd-loginctl list-seats | awk '{print $1}' ; }
+
+_systemd_loginctl () {
+ local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+ local verb comps
+
+ local -A OPTS=(
+ [STANDALONE]='--all -a --help -h --no-pager --privileged -P --version'
+ [ARG]='--host -H --kill-who --property -p --signal -s'
+ )
+
+ if __contains_word "$prev" ${OPTS[ARG]}; then
+ case $prev in
+ --signal|-s)
+ comps=$(compgen -A signal)
+ ;;
+ --kill-who)
+ comps='all leader'
+ ;;
+ --host|-H)
+ comps=$(compgen -A hostname)
+ ;;
+ --property|-p)
+ comps=''
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "$comps" -- "$cur") )
+ return 0
+ fi
+
+
+ if [[ "$cur" = -* ]]; then
+ COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") )
+ return 0
+ fi
+
+ local -A VERBS=(
+ [SESSIONS]='session-status show-session activate lock-session unlock-session terminate-session kill-session'
+ [USERS]='user-status show-user enable-linger disable-linger terminate-user kill-user'
+ [SEATS]='seat-status show-seat terminate-seat'
+ [STANDALONE]='list-sessions list-users list-seats flush-devices'
+ [ATTACH]='attach'
+ )
+
+ for ((i=0; $i <= $COMP_CWORD; i++)); do
+ if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]} &&
+ ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG}]}; then
+ verb=${COMP_WORDS[i]}
+ break
+ fi
+ done
+
+ if [[ -z $verb ]]; then
+ comps="${VERBS[*]}"
+
+ elif __contains_word "$verb" ${VERBS[SESSIONS]}; then
+ comps=$( __get_all_sessions )
+
+ elif __contains_word "$verb" ${VERBS[USERS]}; then
+ comps=$( __get_all_users )
+
+ elif __contains_word "$verb" ${VERBS[SEATS]}; then
+ comps=$( __get_all_seats )
+
+ elif __contains_word "$verb" ${VERBS[STANDALONE]}; then
+ comps=''
+
+ elif __contains_word "$verb" ${VERBS[ATTACH]}; then
+ if [[ $prev = $verb ]]; then
+ comps=$( __get_all_seats )
+ else
+ comps=$(compgen -A file -- "$cur" )
+ compopt -o filenames
+ fi
+ fi
+
+ COMPREPLY=( $(compgen -W "$comps" -- "$cur") )
+ return 0
+}
+complete -F _systemd_loginctl systemd-loginctl
diff --git a/src/timedated.c b/src/timedated.c
index 66e50a6868..16f54b59d2 100644
--- a/src/timedated.c
+++ b/src/timedated.c
@@ -170,8 +170,24 @@ static int read_data(void) {
free_data();
r = read_one_line_file("/etc/timezone", &zone);
- if (r < 0 && r != -ENOENT)
- return r;
+ if (r < 0) {
+ if (r != -ENOENT)
+ log_warning("Failed to read /etc/timezone: %s", strerror(-r));
+
+#ifdef TARGET_FEDORA
+ r = parse_env_file("/etc/sysconfig/clock", NEWLINE,
+ "ZONE", &zone,
+ NULL);
+
+ if (r < 0 && r != -ENOENT)
+ log_warning("Failed to read /etc/sysconfig/clock: %s", strerror(-r));
+#endif
+ }
+
+ if (isempty(zone)) {
+ free(zone);
+ zone = NULL;
+ }
verify_timezone();
@@ -246,7 +262,7 @@ static int write_data_local_rtc(void) {
p++;
e = strchr(p, '\n');
- if (!p) {
+ if (!e) {
free(s);
return -EIO;
}
diff --git a/src/tmpfiles.c b/src/tmpfiles.c
index a6b8f859aa..21bf44d3a4 100644
--- a/src/tmpfiles.c
+++ b/src/tmpfiles.c
@@ -157,6 +157,7 @@ static void load_unix_sockets(void) {
}
}
+ fclose(f);
return;
fail:
diff --git a/src/tty-ask-password-agent.c b/src/tty-ask-password-agent.c
index 43d008fc70..13481b29e9 100644
--- a/src/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent.c
@@ -206,6 +206,7 @@ static int ask_password_plymouth(
continue;
memcpy(&size, buffer+1, sizeof(size));
+ size = le32toh(size);
if (size+5 > sizeof(buffer)) {
r = -EIO;
goto finish;
diff --git a/src/umount.c b/src/umount.c
index 67be42ea33..4e036d82a3 100644
--- a/src/umount.c
+++ b/src/umount.c
@@ -565,10 +565,13 @@ int umount_all(bool *changed) {
/* retry umount, until nothing can be umounted anymore */
do {
umount_changed = false;
- r = mount_points_list_umount(&mp_list_head, &umount_changed, false);
+
+ mount_points_list_umount(&mp_list_head, &umount_changed, false);
if (umount_changed)
*changed = true;
- } while(umount_changed);
+
+ } while (umount_changed);
+
/* umount one more time with logging enabled */
r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
if (r <= 0)
diff --git a/src/unit.c b/src/unit.c
index 3ce87ea1d3..903a8e4da4 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -774,7 +774,7 @@ int unit_add_default_target_dependency(Unit *u, Unit *target) {
/* If either side wants no automatic dependencies, then let's
* skip this */
if (!u->meta.default_dependencies ||
- target->meta.default_dependencies)
+ !target->meta.default_dependencies)
return 0;
/* Don't create loops */
@@ -888,16 +888,20 @@ int unit_start(Unit *u) {
if (u->meta.load_state != UNIT_LOADED)
return -EINVAL;
- /* If this is already (being) started, then this will
- * succeed. Note that this will even succeed if this unit is
- * not startable by the user. This is relied on to detect when
- * we need to wait for units and when waiting is finished. */
+ /* If this is already started, then this will succeed. Note
+ * that this will even succeed if this unit is not startable
+ * by the user. This is relied on to detect when we need to
+ * wait for units and when waiting is finished. */
state = unit_active_state(u);
if (UNIT_IS_ACTIVE_OR_RELOADING(state))
return -EALREADY;
- /* If the conditions failed, don't do anything at all */
- if (!unit_condition_test(u)) {
+ /* If the conditions failed, don't do anything at all. If we
+ * already are activating this call might still be useful to
+ * speed up activation in case there is some hold-off time,
+ * but we don't want to recheck the condition in that case. */
+ if (state != UNIT_ACTIVATING &&
+ !unit_condition_test(u)) {
log_debug("Starting of %s requested but condition failed. Ignoring.", u->meta.id);
return -EALREADY;
}
diff --git a/src/update-utmp.c b/src/update-utmp.c
index f81e7f495f..12e4d11042 100644
--- a/src/update-utmp.c
+++ b/src/update-utmp.c
@@ -376,7 +376,10 @@ int main(int argc, char *argv[]) {
umask(0022);
#ifdef HAVE_AUDIT
- if ((c.audit_fd = audit_open()) < 0)
+ if ((c.audit_fd = audit_open()) < 0 &&
+ /* If the kernel lacks netlink or audit support,
+ * don't worry about it. */
+ errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
log_error("Failed to connect to audit log: %m");
#endif
diff --git a/src/util.c b/src/util.c
index 6033aa05b2..e93e6f6cf5 100644
--- a/src/util.c
+++ b/src/util.c
@@ -782,13 +782,7 @@ int read_full_file(const char *fn, char **contents, size_t *size) {
}
}
- if (buf)
- buf[l] = 0;
- else if (!(buf = calloc(1, 1))) {
- r = -errno;
- goto finish;
- }
-
+ buf[l] = 0;
*contents = buf;
buf = NULL;
@@ -2313,8 +2307,10 @@ int chvt(int vt) {
0
};
- if (ioctl(fd, TIOCLINUX, tiocl) < 0)
- return -errno;
+ if (ioctl(fd, TIOCLINUX, tiocl) < 0) {
+ r = -errno;
+ goto fail;
+ }
vt = tiocl[0] <= 0 ? 1 : tiocl[0];
}
@@ -2322,7 +2318,8 @@ int chvt(int vt) {
if (ioctl(fd, VT_ACTIVATE, vt) < 0)
r = -errno;
- close_nointr_nofail(r);
+fail:
+ close_nointr_nofail(fd);
return r;
}
@@ -4273,224 +4270,6 @@ const char *default_term_for_tty(const char *tty) {
return term;
}
-/* Returns a short identifier for the various VM implementations */
-int detect_vm(const char **id) {
-
-#if defined(__i386__) || defined(__x86_64__)
-
- /* Both CPUID and DMI are x86 specific interfaces... */
-
- static const char *const dmi_vendors[] = {
- "/sys/class/dmi/id/sys_vendor",
- "/sys/class/dmi/id/board_vendor",
- "/sys/class/dmi/id/bios_vendor"
- };
-
- static const char dmi_vendor_table[] =
- "QEMU\0" "qemu\0"
- /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
- "VMware\0" "vmware\0"
- "VMW\0" "vmware\0"
- "Microsoft Corporation\0" "microsoft\0"
- "innotek GmbH\0" "oracle\0"
- "Xen\0" "xen\0"
- "Bochs\0" "bochs\0";
-
- static const char cpuid_vendor_table[] =
- "XenVMMXenVMM\0" "xen\0"
- "KVMKVMKVM\0" "kvm\0"
- /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
- "VMwareVMware\0" "vmware\0"
- /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
- "Microsoft Hv\0" "microsoft\0";
-
- uint32_t eax, ecx;
- union {
- uint32_t sig32[3];
- char text[13];
- } sig;
- unsigned i;
- const char *j, *k;
- bool hypervisor;
-
- /* http://lwn.net/Articles/301888/ */
- zero(sig);
-
-#if defined (__i386__)
-#define REG_a "eax"
-#define REG_b "ebx"
-#elif defined (__amd64__)
-#define REG_a "rax"
-#define REG_b "rbx"
-#endif
-
- /* First detect whether there is a hypervisor */
- eax = 1;
- __asm__ __volatile__ (
- /* ebx/rbx is being used for PIC! */
- " push %%"REG_b" \n\t"
- " cpuid \n\t"
- " pop %%"REG_b" \n\t"
-
- : "=a" (eax), "=c" (ecx)
- : "0" (eax)
- );
-
- hypervisor = !!(ecx & 0x80000000U);
-
- if (hypervisor) {
-
- /* There is a hypervisor, see what it is */
- eax = 0x40000000U;
- __asm__ __volatile__ (
- /* ebx/rbx is being used for PIC! */
- " push %%"REG_b" \n\t"
- " cpuid \n\t"
- " mov %%ebx, %1 \n\t"
- " pop %%"REG_b" \n\t"
-
- : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
- : "0" (eax)
- );
-
- NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table)
- if (streq(sig.text, j)) {
-
- if (id)
- *id = k;
-
- return 1;
- }
- }
-
- for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
- char *s;
- int r;
- const char *found = NULL;
-
- if ((r = read_one_line_file(dmi_vendors[i], &s)) < 0) {
- if (r != -ENOENT)
- return r;
-
- continue;
- }
-
- NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table)
- if (startswith(s, j))
- found = k;
- free(s);
-
- if (found) {
- if (id)
- *id = found;
-
- return 1;
- }
- }
-
- if (hypervisor) {
- if (id)
- *id = "other";
-
- return 1;
- }
-
-#endif
- return 0;
-}
-
-int detect_container(const char **id) {
- FILE *f;
-
- /* Unfortunately many of these operations require root access
- * in one way or another */
-
- if (geteuid() != 0)
- return -EPERM;
-
- if (running_in_chroot() > 0) {
-
- if (id)
- *id = "chroot";
-
- return 1;
- }
-
- /* /proc/vz exists in container and outside of the container,
- * /proc/bc only outside of the container. */
- if (access("/proc/vz", F_OK) >= 0 &&
- access("/proc/bc", F_OK) < 0) {
-
- if (id)
- *id = "openvz";
-
- return 1;
- }
-
- if ((f = fopen("/proc/self/cgroup", "re"))) {
-
- for (;;) {
- char line[LINE_MAX], *p;
-
- if (!fgets(line, sizeof(line), f))
- break;
-
- if (!(p = strchr(strstrip(line), ':')))
- continue;
-
- if (strncmp(p, ":ns:", 4))
- continue;
-
- if (!streq(p, ":ns:/")) {
- fclose(f);
-
- if (id)
- *id = "pidns";
-
- return 1;
- }
- }
-
- fclose(f);
- }
-
- return 0;
-}
-
-/* Returns a short identifier for the various VM/container implementations */
-int detect_virtualization(const char **id) {
- static __thread const char *cached_id = NULL;
- const char *_id;
- int r;
-
- if (_likely_(cached_id)) {
-
- if (cached_id == (const char*) -1)
- return 0;
-
- if (id)
- *id = cached_id;
-
- return 1;
- }
-
- if ((r = detect_container(&_id)) != 0)
- goto finish;
-
- r = detect_vm(&_id);
-
-finish:
- if (r > 0) {
- cached_id = _id;
-
- if (id)
- *id = _id;
- } else if (r == 0)
- cached_id = (const char*) -1;
-
- return r;
-}
-
bool dirent_is_file(struct dirent *de) {
assert(de);
@@ -5529,6 +5308,9 @@ int get_files_in_directory(const char *path, char ***list) {
* number */
d = opendir(path);
+ if (!d)
+ return -errno;
+
for (;;) {
struct dirent buffer, *de;
int k;
@@ -5629,6 +5411,8 @@ char *join(const char *x, ...) {
p = stpcpy(p, t);
}
+
+ va_end(ap);
} else
r[0] = 0;
@@ -5815,7 +5599,7 @@ static const char* const ip_tos_table[] = {
DEFINE_STRING_TABLE_LOOKUP(ip_tos, int);
-static const char *const signal_table[] = {
+static const char *const __signal_table[] = {
[SIGHUP] = "HUP",
[SIGINT] = "INT",
[SIGQUIT] = "QUIT",
@@ -5851,7 +5635,44 @@ static const char *const signal_table[] = {
[SIGSYS] = "SYS"
};
-DEFINE_STRING_TABLE_LOOKUP(signal, int);
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
+
+const char *signal_to_string(int signo) {
+ static __thread char buf[12];
+ const char *name;
+
+ name = __signal_to_string(signo);
+ if (name)
+ return name;
+
+ if (signo >= SIGRTMIN && signo <= SIGRTMAX)
+ snprintf(buf, sizeof(buf) - 1, "RTMIN+%d", signo - SIGRTMIN);
+ else
+ snprintf(buf, sizeof(buf) - 1, "%d", signo);
+ char_array_0(buf);
+ return buf;
+}
+
+int signal_from_string(const char *s) {
+ int signo;
+ int offset = 0;
+ unsigned u;
+
+ signo =__signal_from_string(s);
+ if (signo > 0)
+ return signo;
+
+ if (startswith(s, "RTMIN+")) {
+ s += 6;
+ offset = SIGRTMIN;
+ }
+ if (safe_atou(s, &u) >= 0) {
+ signo = (int) u + offset;
+ if (signo > 0 && signo < _NSIG)
+ return signo;
+ }
+ return -1;
+}
bool kexec_loaded(void) {
bool loaded = false;
@@ -5864,3 +5685,54 @@ bool kexec_loaded(void) {
}
return loaded;
}
+
+int strdup_or_null(const char *a, char **b) {
+ char *c;
+
+ assert(b);
+
+ if (!a) {
+ *b = NULL;
+ return 0;
+ }
+
+ c = strdup(a);
+ if (!c)
+ return -ENOMEM;
+
+ *b = c;
+ return 0;
+}
+
+unsigned long cap_last_cap(void) {
+ static __thread unsigned long saved;
+ static __thread bool valid = false;
+ unsigned long p;
+
+ if (valid)
+ return saved;
+
+ p = (unsigned long) CAP_LAST_CAP;
+
+ if (prctl(PR_CAPBSET_READ, p) < 0) {
+
+ /* Hmm, look downwards, until we find one that
+ * works */
+ for (p--; p > 0; p --)
+ if (prctl(PR_CAPBSET_READ, p) >= 0)
+ break;
+
+ } else {
+
+ /* Hmm, look upwards, until we find one that doesn't
+ * work */
+ for (;; p++)
+ if (prctl(PR_CAPBSET_READ, p+1) < 0)
+ break;
+ }
+
+ saved = p;
+ valid = true;
+
+ return p;
+}
diff --git a/src/util.h b/src/util.h
index 3e1f46d826..a71a297eab 100644
--- a/src/util.h
+++ b/src/util.h
@@ -288,13 +288,13 @@ int make_null_stdio(void);
unsigned long long random_ull(void);
-#define DEFINE_STRING_TABLE_LOOKUP(name,type) \
- const char *name##_to_string(type i) { \
+#define __DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
+ scope const char *name##_to_string(type i) { \
if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \
return NULL; \
return name##_table[i]; \
} \
- type name##_from_string(const char *s) { \
+ scope type name##_from_string(const char *s) { \
type i; \
unsigned u = 0; \
assert(s); \
@@ -309,6 +309,8 @@ unsigned long long random_ull(void);
} \
struct __useless_struct_to_allow_trailing_semicolon__
+#define DEFINE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,static)
int fd_nonblock(int fd, bool nonblock);
int fd_cloexec(int fd, bool cloexec);
@@ -404,10 +406,6 @@ bool tty_is_vc(const char *tty);
int vtnr_from_tty(const char *tty);
const char *default_term_for_tty(const char *tty);
-int detect_vm(const char **id);
-int detect_container(const char **id);
-int detect_virtualization(const char **id);
-
void execute_directory(const char *directory, DIR *_d, char *argv[]);
int kill_and_sigcont(pid_t pid, int sig);
@@ -469,6 +467,8 @@ int block_get_whole_disk(dev_t d, dev_t *ret);
int file_is_sticky(const char *p);
+int strdup_or_null(const char *a, char **b);
+
#define NULSTR_FOREACH(i, l) \
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
@@ -506,4 +506,6 @@ extern char **saved_argv;
bool kexec_loaded(void);
+unsigned long cap_last_cap(void);
+
#endif
diff --git a/src/vconsole-setup.c b/src/vconsole-setup.c
index 4347a2078f..91967891f1 100644
--- a/src/vconsole-setup.c
+++ b/src/vconsole-setup.c
@@ -39,6 +39,7 @@
#include "util.h"
#include "log.h"
#include "macro.h"
+#include "virt.h"
static bool is_vconsole(int fd) {
unsigned char data[1];
@@ -159,7 +160,7 @@ int main(int argc, char **argv) {
#ifdef TARGET_GENTOO
char *vc_unicode = NULL;
#endif
-#ifdef TARGET_MANDRIVA
+#if defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
char *vc_keytable = NULL;
#endif
int fd = -1;
@@ -202,10 +203,6 @@ int main(int argc, char **argv) {
if (detect_container(NULL) <= 0)
if ((r = parse_env_file("/proc/cmdline", WHITESPACE,
-#if defined(TARGET_FEDORA) || defined(TARGET_MEEGO)
- "SYSFONT", &vc_font,
- "KEYTABLE", &vc_keymap,
-#endif
"vconsole.keymap", &vc_keymap,
"vconsole.keymap.toggle", &vc_keymap_toggle,
"vconsole.font", &vc_font,
@@ -374,7 +371,7 @@ int main(int argc, char **argv) {
log_warning("Failed to read /etc/conf.d/keymaps: %s", strerror(-r));
}
-#elif defined(TARGET_MANDRIVA)
+#elif defined(TARGET_MANDRIVA) || defined (TARGET_MAGEIA)
if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
"SYSFONT", &vc_font,
diff --git a/src/virt.c b/src/virt.c
new file mode 100644
index 0000000000..380fabded2
--- /dev/null
+++ b/src/virt.c
@@ -0,0 +1,314 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "virt.h"
+
+/* Returns a short identifier for the various VM implementations */
+int detect_vm(const char **id) {
+
+#if defined(__i386__) || defined(__x86_64__)
+
+ /* Both CPUID and DMI are x86 specific interfaces... */
+
+ static const char *const dmi_vendors[] = {
+ "/sys/class/dmi/id/sys_vendor",
+ "/sys/class/dmi/id/board_vendor",
+ "/sys/class/dmi/id/bios_vendor"
+ };
+
+ static const char dmi_vendor_table[] =
+ "QEMU\0" "qemu\0"
+ /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
+ "VMware\0" "vmware\0"
+ "VMW\0" "vmware\0"
+ "Microsoft Corporation\0" "microsoft\0"
+ "innotek GmbH\0" "oracle\0"
+ "Xen\0" "xen\0"
+ "Bochs\0" "bochs\0";
+
+ static const char cpuid_vendor_table[] =
+ "XenVMMXenVMM\0" "xen\0"
+ "KVMKVMKVM\0" "kvm\0"
+ /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
+ "VMwareVMware\0" "vmware\0"
+ /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
+ "Microsoft Hv\0" "microsoft\0";
+
+ uint32_t eax, ecx;
+ union {
+ uint32_t sig32[3];
+ char text[13];
+ } sig;
+ unsigned i;
+ const char *j, *k;
+ bool hypervisor;
+
+ /* http://lwn.net/Articles/301888/ */
+ zero(sig);
+
+#if defined (__i386__)
+#define REG_a "eax"
+#define REG_b "ebx"
+#elif defined (__amd64__)
+#define REG_a "rax"
+#define REG_b "rbx"
+#endif
+
+ /* First detect whether there is a hypervisor */
+ eax = 1;
+ __asm__ __volatile__ (
+ /* ebx/rbx is being used for PIC! */
+ " push %%"REG_b" \n\t"
+ " cpuid \n\t"
+ " pop %%"REG_b" \n\t"
+
+ : "=a" (eax), "=c" (ecx)
+ : "0" (eax)
+ );
+
+ hypervisor = !!(ecx & 0x80000000U);
+
+ if (hypervisor) {
+
+ /* There is a hypervisor, see what it is */
+ eax = 0x40000000U;
+ __asm__ __volatile__ (
+ /* ebx/rbx is being used for PIC! */
+ " push %%"REG_b" \n\t"
+ " cpuid \n\t"
+ " mov %%ebx, %1 \n\t"
+ " pop %%"REG_b" \n\t"
+
+ : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
+ : "0" (eax)
+ );
+
+ NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table)
+ if (streq(sig.text, j)) {
+
+ if (id)
+ *id = k;
+
+ return 1;
+ }
+ }
+
+ for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
+ char *s;
+ int r;
+ const char *found = NULL;
+
+ if ((r = read_one_line_file(dmi_vendors[i], &s)) < 0) {
+ if (r != -ENOENT)
+ return r;
+
+ continue;
+ }
+
+ NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table)
+ if (startswith(s, j))
+ found = k;
+ free(s);
+
+ if (found) {
+ if (id)
+ *id = found;
+
+ return 1;
+ }
+ }
+
+ if (hypervisor) {
+ if (id)
+ *id = "other";
+
+ return 1;
+ }
+
+#endif
+ return 0;
+}
+
+int detect_container(const char **id) {
+ FILE *f;
+
+ /* Unfortunately many of these operations require root access
+ * in one way or another */
+
+ if (geteuid() != 0)
+ return -EPERM;
+
+ if (running_in_chroot() > 0) {
+
+ if (id)
+ *id = "chroot";
+
+ return 1;
+ }
+
+ /* /proc/vz exists in container and outside of the container,
+ * /proc/bc only outside of the container. */
+ if (access("/proc/vz", F_OK) >= 0 &&
+ access("/proc/bc", F_OK) < 0) {
+
+ if (id)
+ *id = "openvz";
+
+ return 1;
+ }
+
+ f = fopen("/proc/1/environ", "re");
+ if (f) {
+ bool done = false;
+
+ do {
+ char line[LINE_MAX];
+ unsigned i;
+
+ for (i = 0; i < sizeof(line)-1; i++) {
+ int c;
+
+ c = getc(f);
+ if (_unlikely_(c == EOF)) {
+ done = true;
+ break;
+ } else if (c == 0)
+ break;
+
+ line[i] = c;
+ }
+ line[i] = 0;
+
+ if (streq(line, "container=lxc")) {
+ fclose(f);
+
+ if (id)
+ *id = "lxc";
+ return 1;
+
+ } else if (streq(line, "container=systemd-nspawn")) {
+ fclose(f);
+
+ if (id)
+ *id = "systemd-nspawn";
+ return 1;
+
+ } else if (startswith(line, "container=")) {
+ fclose(f);
+
+ if (id)
+ *id = "other";
+ return 1;
+ }
+
+ } while (!done);
+
+ fclose(f);
+ }
+
+ f = fopen("/proc/self/cgroup", "re");
+ if (f) {
+
+ for (;;) {
+ char line[LINE_MAX], *p;
+
+ if (!fgets(line, sizeof(line), f))
+ break;
+
+ p = strchr(strstrip(line), ':');
+ if (!p)
+ continue;
+
+ if (strncmp(p, ":ns:", 4))
+ continue;
+
+ if (!streq(p, ":ns:/")) {
+ fclose(f);
+
+ if (id)
+ *id = "pidns";
+
+ return 1;
+ }
+ }
+
+ fclose(f);
+ }
+
+ return 0;
+}
+
+/* Returns a short identifier for the various VM/container implementations */
+Virtualization detect_virtualization(const char **id) {
+
+ static __thread Virtualization cached_virt = _VIRTUALIZATION_INVALID;
+ static __thread const char *cached_id = NULL;
+
+ const char *_id;
+ int r;
+ Virtualization v;
+
+ if (_likely_(cached_virt >= 0)) {
+
+ if (id && cached_virt > 0)
+ *id = cached_id;
+
+ return cached_virt;
+ }
+
+ r = detect_container(&_id);
+ if (r < 0) {
+ v = r;
+ goto finish;
+ } else if (r > 0) {
+ v = VIRTUALIZATION_CONTAINER;
+ goto finish;
+ }
+
+ r = detect_vm(&_id);
+ if (r < 0) {
+ v = r;
+ goto finish;
+ } else if (r > 0) {
+ v = VIRTUALIZATION_VM;
+ goto finish;
+ }
+
+ v = VIRTUALIZATION_NONE;
+
+finish:
+ if (v > 0) {
+ cached_id = _id;
+
+ if (id)
+ *id = _id;
+ }
+
+ if (v >= 0)
+ cached_virt = v;
+
+ return v;
+}
diff --git a/src/virt.h b/src/virt.h
new file mode 100644
index 0000000000..f55c9a68fd
--- /dev/null
+++ b/src/virt.h
@@ -0,0 +1,38 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foovirthfoo
+#define foovirthfoo
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int detect_vm(const char **id);
+int detect_container(const char **id);
+
+typedef enum Virtualization {
+ VIRTUALIZATION_NONE = 0,
+ VIRTUALIZATION_VM,
+ VIRTUALIZATION_CONTAINER,
+ _VIRTUALIZATION_MAX,
+ _VIRTUALIZATION_INVALID = -1
+} Virtualization;
+
+Virtualization detect_virtualization(const char **id);
+
+#endif