diff --git a/Makefile.am b/Makefile.am index e08785a8a3..58b3a63517 100644 --- a/Makefile.am +++ b/Makefile.am @@ -119,6 +119,13 @@ AM_CPPFLAGS += \ -DKBD_LOADKEYS=\"/bin/loadkeys\" \ -DKBD_SETFONT=\"/bin/setfont\" \ -DDEFAULT_FONT=\"latarcyrheb-sun16\" +else +if TARGET_MAGEIA +AM_CPPFLAGS += \ + -DKBD_LOADKEYS=\"/bin/loadkeys\" \ + -DKBD_SETFONT=\"/bin/setfont\" \ + -DDEFAULT_FONT=\"LatArCyrHeb-16\" +endif endif endif endif @@ -318,7 +325,7 @@ dbusinterface_DATA += \ endif dist_bashcompletion_DATA = \ - src/systemctl-bash-completion.sh + src/systemd-bash-completion.sh dist_tmpfiles_DATA = \ tmpfiles.d/systemd.conf \ @@ -546,6 +553,13 @@ dist_systemunit_DATA += \ units/suse/halt-local.service endif +if TARGET_MAGEIA +dist_systemunit_DATA += \ + units/mageia/prefdm.service \ + units/fedora/rc-local.service \ + units/fedora/halt-local.service +endif + if HAVE_PLYMOUTH dist_systemunit_DATA += \ units/plymouth-start.service \ @@ -1488,7 +1502,8 @@ systemd_stdio_bridge_LDADD = \ systemadm_SOURCES = \ src/systemadm.vala \ - src/systemd-interfaces.vala + src/systemd-interfaces.vala \ + src/wraplabel.vala systemadm_CFLAGS = \ $(AM_CFLAGS) \ @@ -1501,6 +1516,7 @@ systemadm_CFLAGS = \ systemadm_VALAFLAGS = \ --pkg=posix \ --pkg=gtk+-2.0 \ + --pkg=gee-1.0 \ -g systemadm_LDADD = \ @@ -2061,6 +2077,23 @@ if TARGET_SUSE $(LN_S) $(systemunitdir)/halt-local.service halt-local.service ) endif +if TARGET_MAGEIA + $(MKDIR_P) -m 0755 $(DESTDIR)$(systemunitdir)/final.target.wants + ( cd $(DESTDIR)$(systemunitdir)/multi-user.target.wants && \ + rm -f rc-local.service && \ + $(LN_S) $(systemunitdir)/rc-local.service rc-local.service ) + ( cd $(DESTDIR)$(systemunitdir)/final.target.wants && \ + rm -f halt-local.service && \ + $(LN_S) $(systemunitdir)/halt-local.service halt-local.service ) + ( cd $(DESTDIR)$(systemunitdir) && \ + rm -f display-manager.service && \ + $(LN_S) prefdm.service display-manager.service && \ + $(LN_S) prefdm.service dm.service ) + ( cd $(DESTDIR)$(systemunitdir)/graphical.target.wants && \ + rm -f display-manager.service && \ + $(LN_S) $(systemunitdir)/display-manager.service display-manager.service ) +endif + if HAVE_SYSV_COMPAT ( cd $(DESTDIR)$(systemunitdir)/local-fs.target.wants && \ rm -f var-lock.mount && \ diff --git a/README b/README index 15afb2cf95..a4cbeaebd3 100644 --- a/README +++ b/README @@ -30,7 +30,10 @@ LICENSE: GPLv2+ for all code, except sd-daemon.[ch] which is MIT REQUIREMENTS: - Linux kernel >= 2.6.39 (with devtmpfs, cgroups; optional but strongly recommended: autofs4, ipv6) + Linux kernel >= 2.6.39 + with devtmpfs + with cgroups (but it's OK to disable all controllers) + optional but strongly recommended: autofs4, ipv6 libudev >= 172 dbus >= 1.4.0 libcap diff --git a/TODO b/TODO index b993a6b2eb..8c3034e079 100644 --- a/TODO +++ b/TODO @@ -23,8 +23,14 @@ Features: * check utf8 everywhere +* when an instanced service exits, remove its parent cgroup too if possible. + +* as Tom Gundersen pointed out there's a always a dep loop if people use crypto file systems with random keys + * unset container= in PID1? +* automatically escape unit names passed on the service (i.e. think "systemctl start serial-getty.service@serial/by-path/jshdfjsdfhkjh" being automatically escaped as necessary. + * if we can not get user quota for tmpfs, mount a separate tmpfs instance for every user in /run/user/$USER with a configured maximum size diff --git a/configure.ac b/configure.ac index 0ec6f69bc8..596a32ac23 100644 --- a/configure.ac +++ b/configure.ac @@ -327,7 +327,7 @@ AM_CONDITIONAL(ENABLE_LOCALED, [test "$have_localed" = "yes"]) have_gtk=no AC_ARG_ENABLE(gtk, AS_HELP_STRING([--disable-gtk], [disable GTK tools])) if test "x$enable_gtk" != "xno"; then - PKG_CHECK_MODULES(GTK, [ gtk+-2.0 glib-2.0 > 2.26 gio-unix-2.0 ], + PKG_CHECK_MODULES(GTK, [ gtk+-2.0 glib-2.0 > 2.26 gio-unix-2.0 gee-1.0], [AC_DEFINE(HAVE_GTK, 1, [Define if GTK is available]) have_gtk=yes], have_gtk=no) AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) @@ -371,6 +371,7 @@ if test "z$with_distro" = "z"; then test -f "/etc/mandriva-release" && with_distro="mandriva" test -f "/etc/meego-release" && with_distro="meego" test -f "/etc/angstrom-version" && with_distro="angstrom" + test -f "/etc/mageia-release" && with_distro="mageia" if test "x`lsb_release -is 2>/dev/null`" = "xUbuntu"; then with_distro="ubuntu" fi @@ -458,6 +459,12 @@ case $with_distro in AC_DEFINE(TARGET_ANGSTROM, [], [Target is Ångström]) M4_DEFINES=-DTARGET_ANGSTROM=1 ;; + mageia) + SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d + AC_DEFINE(TARGET_MAGEIA, [], [Target is Mageia]) + M4_DISTRO_FLAG=-DTARGET_MAGEIA=1 + have_plymouth=yes + ;; other) ;; *) @@ -515,6 +522,7 @@ AM_CONDITIONAL(TARGET_ALTLINUX, test x"$with_distro" = xaltlinux) AM_CONDITIONAL(TARGET_MANDRIVA, test x"$with_distro" = xmandriva) AM_CONDITIONAL(TARGET_MEEGO, test x"$with_distro" = xmeego) AM_CONDITIONAL(TARGET_ANGSTROM, test x"$with_distro" = xangstrom) +AM_CONDITIONAL(TARGET_MAGEIA, test x"$with_distro" = xmageia) AM_CONDITIONAL(HAVE_PLYMOUTH, test "$have_plymouth" = "yes") AM_CONDITIONAL(HAVE_SYSV_COMPAT, test "$SYSTEM_SYSV_COMPAT" = "yes") diff --git a/src/.gitignore b/src/.gitignore index cafff82a75..a3fd20b404 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -12,4 +12,5 @@ org.freedesktop.systemd1.policy gnome-ask-password-agent.c systemd-interfaces.c systemadm.c +wraplabel.c 73-seat-late.rules diff --git a/src/cgroup.c b/src/cgroup.c index dcf2c2feb7..4bbb54fd7e 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)); @@ -366,7 +363,8 @@ int cgroup_notify_empty(Manager *m, const char *group) { assert(m); assert(group); - if (!(l = hashmap_get(m->cgroup_bondings, group))) + l = hashmap_get(m->cgroup_bondings, group); + if (!l) return 0; LIST_FOREACH(by_path, b, l) { @@ -375,7 +373,8 @@ int cgroup_notify_empty(Manager *m, const char *group) { if (!b->unit) continue; - if ((t = cgroup_bonding_is_empty_list(b)) < 0) { + t = cgroup_bonding_is_empty_list(b); + if (t < 0) { /* If we don't know, we don't know */ if (t != -EAGAIN) @@ -384,9 +383,13 @@ int cgroup_notify_empty(Manager *m, const char *group) { continue; } - if (t > 0) + if (t > 0) { + /* If it is empty, let's delete it */ + cgroup_bonding_trim_list(b->unit->meta.cgroup_bondings, true); + if (UNIT_VTABLE(b->unit)->cgroup_notify_empty) UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit); + } } return 0; diff --git a/src/condition.c b/src/condition.c index f18c45421a..2b51a16f17 100644 --- a/src/condition.c +++ b/src/condition.c @@ -187,6 +187,8 @@ static bool test_capability(const char *parameter) { } } + fclose(f); + return !!(capabilities & (1ULL << value)); } 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/fsck.c b/src/fsck.c index c5088ad71c..3477ba16ad 100644 --- a/src/fsck.c +++ b/src/fsck.c @@ -127,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/hostname-setup.c b/src/hostname-setup.c index 7216b75c8a..2c2f10cfd1 100644 --- a/src/hostname-setup.c +++ b/src/hostname-setup.c @@ -30,7 +30,7 @@ #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) #define FILENAME "/etc/HOSTNAME" @@ -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; 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/job.c b/src/job.c index 5c0913b7d8..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); @@ -573,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) { @@ -597,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; + } } } @@ -626,7 +635,7 @@ finish: manager_check_finished(u->meta.manager); - return 0; + return recursed; } int job_start_timer(Job *j) { diff --git a/src/locale-setup.c b/src/locale-setup.c index 340293619f..7f692e9c5d 100644 --- a/src/locale-setup.c +++ b/src/locale-setup.c @@ -199,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/manager.c b/src/manager.c index ac5bbef1a8..f8cbcfcc98 100644 --- a/src/manager.c +++ b/src/manager.c @@ -286,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 @@ -1214,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; } } diff --git a/src/mount.c b/src/mount.c index ef953f0d0a..f9cfe910a0 100644 --- a/src/mount.c +++ b/src/mount.c @@ -327,7 +327,7 @@ static bool needs_quota(MountParameters *p) { } 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; @@ -358,6 +358,7 @@ static int mount_add_fstab_links(Mount *m) { if (mount_is_network(p)) { target = SPECIAL_REMOTE_FS_TARGET; after = SPECIAL_REMOTE_FS_PRE_TARGET; + after2 = SPECIAL_NETWORK_TARGET; } else { target = SPECIAL_LOCAL_FS_TARGET; after = SPECIAL_LOCAL_FS_PRE_TARGET; @@ -374,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/quotacheck.c b/src/quotacheck.c index 98b59a090a..60033a8eb2 100644 --- a/src/quotacheck.c +++ b/src/quotacheck.c @@ -54,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 @@ -65,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/service.c b/src/service.c index e64d289fed..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] = { @@ -277,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. @@ -811,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 diff --git a/src/systemadm.vala b/src/systemadm.vala index d45ec64ca4..5971ac07e5 100644 --- a/src/systemadm.vala +++ b/src/systemadm.vala @@ -23,6 +23,20 @@ using Pango; static bool user = false; +public string format_time(uint64 time_ns) { + if (time_ns <= 0) + return ""; + Time timestamp = Time.local((time_t) (time_ns / 1000000)); + return timestamp.format("%a, %d %b %Y %H:%M:%S"); +} + +public void new_column(TreeView view, int column_id, string title) { + TreeViewColumn col; + col = new TreeViewColumn.with_attributes(title, new CellRendererText(), "text", column_id); + col.set_sort_column_id(column_id); + view.insert_column(col, -1); +} + public class LeftLabel : Label { public LeftLabel(string? text = null) { if (text != null) @@ -32,12 +46,11 @@ public class LeftLabel : Label { } } -public class RightLabel : Label { +public class RightLabel : WrapLabel { + public RightLabel(string? text = null) { - set_text_or_na(text); - set_alignment(0, 0); - set_ellipsize(EllipsizeMode.START); set_selectable(true); + set_text_or_na(text); } public void set_text_or_na(string? text = null) { @@ -66,6 +79,8 @@ public class MainWindow : Window { private ListStore unit_model; private ListStore job_model; + private Gee.HashMap unit_map; + private Button start_button; private Button stop_button; private Button restart_button; @@ -81,7 +96,6 @@ public class MainWindow : Window { private Manager manager; private RightLabel unit_id_label; - private RightLabel unit_aliases_label; private RightLabel unit_dependency_label; private RightLabel unit_description_label; private RightLabel unit_load_state_label; @@ -99,6 +113,7 @@ public class MainWindow : Window { private RightLabel job_type_label; private ComboBox unit_type_combo_box; + private CheckButton inactive_checkbox; public MainWindow() throws IOError { title = user ? "systemd User Service Manager" : "systemd System Manager"; @@ -123,18 +138,24 @@ public class MainWindow : Window { type_hbox.pack_start(unit_type_combo_box, false, false, 0); unit_vbox.pack_start(type_hbox, false, false, 0); - unit_type_combo_box.append_text("Show All Units"); - unit_type_combo_box.append_text("Show Only Live Units"); + unit_type_combo_box.append_text("All unit types"); + unit_type_combo_box.append_text("Targets"); unit_type_combo_box.append_text("Services"); - unit_type_combo_box.append_text("Sockets"); unit_type_combo_box.append_text("Devices"); unit_type_combo_box.append_text("Mounts"); unit_type_combo_box.append_text("Automounts"); - unit_type_combo_box.append_text("Targets"); + unit_type_combo_box.append_text("Swaps"); + unit_type_combo_box.append_text("Sockets"); + unit_type_combo_box.append_text("Paths"); + unit_type_combo_box.append_text("Timers"); unit_type_combo_box.append_text("Snapshots"); - unit_type_combo_box.set_active(1); + unit_type_combo_box.set_active(0); // Show All unit_type_combo_box.changed.connect(unit_type_changed); + inactive_checkbox = new CheckButton.with_label("inactive too"); + inactive_checkbox.toggled.connect(unit_type_changed); + type_hbox.pack_start(inactive_checkbox, false, false, 0); + unit_load_entry = new Entry(); unit_load_button = new Button.with_mnemonic("_Load"); unit_load_button.set_sensitive(false); @@ -160,26 +181,30 @@ public class MainWindow : Window { unit_model = new ListStore(7, typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(Unit)); job_model = new ListStore(6, typeof(string), typeof(string), typeof(string), typeof(string), typeof(Job), typeof(uint32)); + unit_map = new Gee.HashMap(); + TreeModelFilter unit_model_filter; unit_model_filter = new TreeModelFilter(unit_model, null); unit_model_filter.set_visible_func(unit_filter); - unit_view = new TreeView.with_model(unit_model_filter); + TreeModelSort unit_model_sort = new TreeModelSort.with_model(unit_model_filter); + + unit_view = new TreeView.with_model(unit_model_sort); job_view = new TreeView.with_model(job_model); unit_view.cursor_changed.connect(unit_changed); job_view.cursor_changed.connect(job_changed); - unit_view.insert_column_with_attributes(-1, "Load State", new CellRendererText(), "text", 2); - unit_view.insert_column_with_attributes(-1, "Active State", new CellRendererText(), "text", 3); - unit_view.insert_column_with_attributes(-1, "Unit State", new CellRendererText(), "text", 4); - unit_view.insert_column_with_attributes(-1, "Unit", new CellRendererText(), "text", 0); - unit_view.insert_column_with_attributes(-1, "Job", new CellRendererText(), "text", 5); + new_column(unit_view, 2, "Load State"); + new_column(unit_view, 3, "Active State"); + new_column(unit_view, 4, "Unit State"); + new_column(unit_view, 0, "Unit"); + new_column(unit_view, 5, "Job"); - job_view.insert_column_with_attributes(-1, "Job", new CellRendererText(), "text", 0); - job_view.insert_column_with_attributes(-1, "Unit", new CellRendererText(), "text", 1); - job_view.insert_column_with_attributes(-1, "Type", new CellRendererText(), "text", 2); - job_view.insert_column_with_attributes(-1, "State", new CellRendererText(), "text", 3); + new_column(job_view, 0, "Job"); + new_column(job_view, 1, "Unit"); + new_column(job_view, 2, "Type"); + new_column(job_view, 3, "State"); ScrolledWindow scroll = new ScrolledWindow(null, null); scroll.set_policy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC); @@ -194,7 +219,6 @@ public class MainWindow : Window { job_vbox.pack_start(scroll, true, true, 0); unit_id_label = new RightLabel(); - unit_aliases_label = new RightLabel(); unit_dependency_label = new RightLabel(); unit_description_label = new RightLabel(); unit_load_state_label = new RightLabel(); @@ -212,7 +236,7 @@ public class MainWindow : Window { job_type_label = new RightLabel(); unit_dependency_label.set_track_visited_links(false); - unit_dependency_label.set_selectable(false); + unit_dependency_label.set_selectable(true); unit_dependency_label.activate_link.connect(on_activate_link); unit_fragment_path_label.set_track_visited_links(false); @@ -229,33 +253,31 @@ public class MainWindow : Window { unit_table.attach(new LeftLabel("Id:"), 0, 1, 0, 1, AttachOptions.FILL, AttachOptions.FILL, 0, 0); unit_table.attach(unit_id_label, 1, 6, 0, 1, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Aliases:"), 0, 1, 1, 2, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_aliases_label, 1, 6, 1, 2, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Description:"), 0, 1, 2, 3, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_description_label, 1, 6, 2, 3, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Dependencies:"), 0, 1, 3, 4, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_dependency_label, 1, 6, 3, 4, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Fragment Path:"), 0, 1, 4, 5, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_fragment_path_label, 1, 6, 4, 5, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Control Group:"), 0, 1, 5, 6, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_cgroup_label, 1, 6, 5, 6, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(new LeftLabel("Description:"), 0, 1, 1, 2, AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(unit_description_label, 1, 6, 1, 2, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(new LeftLabel("Dependencies:"), 0, 1, 2, 3, AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(unit_dependency_label, 1, 6, 2, 3, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(new LeftLabel("Fragment Path:"), 0, 1, 3, 4, AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(unit_fragment_path_label, 1, 6, 3, 4, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(new LeftLabel("Control Group:"), 0, 1, 4, 5, AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(unit_cgroup_label, 1, 6, 4, 5, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Load State:"), 0, 1, 6, 7, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_load_state_label, 1, 2, 6, 7, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Active State:"), 0, 1, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_active_state_label, 1, 2, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Unit State:"), 0, 1, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_sub_state_label, 1, 2, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(new LeftLabel("Load State:"), 0, 1, 5, 6, AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(unit_load_state_label, 1, 2, 5, 6, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(new LeftLabel("Active State:"), 0, 1, 6, 7, AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(unit_active_state_label, 1, 2, 6, 7, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(new LeftLabel("Unit State:"), 0, 1, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(unit_sub_state_label, 1, 2, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Active Enter Timestamp:"), 2, 3, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_active_enter_timestamp_label, 3, 4, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Active Exit Timestamp:"), 2, 3, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_active_exit_timestamp_label, 3, 4, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(new LeftLabel("Activated:"), 2, 3, 6, 7, AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(unit_active_enter_timestamp_label, 3, 4, 6, 7, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(new LeftLabel("Deactivated:"), 2, 3, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(unit_active_exit_timestamp_label, 3, 4, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Can Start/Stop:"), 4, 5, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_can_start_label, 5, 6, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Can Reload:"), 4, 5, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_can_reload_label, 5, 6, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(new LeftLabel("Can Start/Stop:"), 4, 5, 6, 7, AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(unit_can_start_label, 5, 6, 6, 7, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(new LeftLabel("Can Reload:"), 4, 5, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0); + unit_table.attach(unit_can_reload_label, 5, 6, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); job_table.attach(new LeftLabel("Id:"), 0, 1, 0, 1, AttachOptions.FILL, AttachOptions.FILL, 0, 0); job_table.attach(job_id_label, 1, 2, 0, 1, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); @@ -333,6 +355,8 @@ public class MainWindow : Window { "org.freedesktop.systemd1", i.unit_path); + unit_map[i.id] = u; + unit_model.append(out iter); unit_model.set(iter, 0, i.id, @@ -393,6 +417,10 @@ public class MainWindow : Window { return u; } + public Unit? get_unit(string id) { + return this.unit_map[id]; + } + public void unit_changed() { Unit u = get_current_unit(); @@ -411,7 +439,6 @@ public class MainWindow : Window { restart_button.set_sensitive(false); unit_id_label.set_text_or_na(); - unit_aliases_label.set_text_or_na(); unit_description_label.set_text_or_na(); unit_description_label.set_text_or_na(); unit_load_state_label.set_text_or_na(); @@ -425,7 +452,33 @@ public class MainWindow : Window { unit_cgroup_label.set_text_or_na(); } + public string format_unit_link(string i, bool link) { + Unit? u = get_unit(i); + if(u == null) + return "" + i + "" + + i + "(" + + u.sub_state + ")" + ""; + if(link) + return " " + span + ""; + else + return span; + } + + public string make_dependency_string(string? prefix, string word, string[] dependencies) { + Gee.Collection sorted = new Gee.TreeSet(); + foreach (string i in dependencies) + sorted.add(i); + bool first = true; string r; @@ -434,16 +487,16 @@ public class MainWindow : Window { else r = prefix; - foreach (string i in dependencies) { + foreach (string i in sorted) { if (r != "") r += first ? "\n" : ","; if (first) { - r += word; + r += "" + word + ":"; first = false; } - r += " " + i + ""; + r += format_unit_link(i, true); } return r; @@ -452,20 +505,23 @@ public class MainWindow : Window { public void show_unit(Unit unit) { current_unit_id = unit.id; - unit_id_label.set_text_or_na(current_unit_id); - - string a = ""; + string id_display = format_unit_link(current_unit_id, false); + bool has_alias = false; foreach (string i in unit.names) { if (i == current_unit_id) continue; - if (a == "") - a = i; - else - a += "\n" + i; - } + if (!has_alias) { + id_display += " (aliases:"; + has_alias = true; + } - unit_aliases_label.set_text_or_na(a); + id_display += " " + i; + } + if(has_alias) + id_display += ")"; + + unit_id_label.set_markup_or_na(id_display); string[] requires = unit.requires, @@ -511,23 +567,16 @@ public class MainWindow : Window { string fp = unit.fragment_path; if (fp != "") - unit_fragment_path_label.set_markup_or_na("" + fp + "" ); + unit_fragment_path_label.set_markup_or_na( + "" + + "" + fp + ""); else unit_fragment_path_label.set_text_or_na(); - uint64 t = unit.active_enter_timestamp; - if (t > 0) { - Time timestamp = Time.local((time_t) (t / 1000000)); - unit_active_enter_timestamp_label.set_text_or_na(timestamp.format("%a, %d %b %Y %H:%M:%S %z")); - } else - unit_active_enter_timestamp_label.set_text_or_na(); - t = unit.active_exit_timestamp; - if (t > 0) { - Time timestamp = Time.local((time_t) (t / 1000000)); - unit_active_exit_timestamp_label.set_text_or_na(timestamp.format("%a, %d %b %Y %H:%M:%S %z")); - } else - unit_active_exit_timestamp_label.set_text_or_na(); + unit_active_enter_timestamp_label.set_text_or_na(format_time(unit.active_enter_timestamp)); + + unit_active_exit_timestamp_label.set_text_or_na(format_time(unit.active_exit_timestamp)); bool b = unit.can_start; start_button.set_sensitive(b); @@ -596,7 +645,7 @@ public class MainWindow : Window { try { u.start("replace"); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } } @@ -609,7 +658,7 @@ public class MainWindow : Window { try { u.stop("replace"); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } } @@ -622,7 +671,7 @@ public class MainWindow : Window { try { u.reload("replace"); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } } @@ -635,7 +684,7 @@ public class MainWindow : Window { try { u.restart("replace"); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } } @@ -648,7 +697,7 @@ public class MainWindow : Window { try { j.cancel(); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } } @@ -676,7 +725,7 @@ public class MainWindow : Window { 4, u.sub_state, 5, t != "" ? "→ %s".printf(t) : "", 6, u); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } } @@ -699,8 +748,10 @@ public class MainWindow : Window { "org.freedesktop.systemd1", path); + unit_map[id] = u; + update_unit_iter(iter, id, u); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } } @@ -736,7 +787,7 @@ public class MainWindow : Window { update_job_iter(iter, id, j); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } } @@ -760,6 +811,8 @@ public class MainWindow : Window { } } while (unit_model.iter_next(ref iter)); + + unit_map.unset(id); } public void on_job_removed(uint32 id, ObjectPath path, string res) { @@ -816,7 +869,7 @@ public class MainWindow : Window { } while (unit_model.iter_next(ref iter)); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } } @@ -852,7 +905,7 @@ public class MainWindow : Window { } while (job_model.iter_next(ref iter)); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } } @@ -865,41 +918,41 @@ public class MainWindow : Window { if (id == null) return false; + if (!inactive_checkbox.get_active() + && active_state == "inactive" && job == "") + return false; + switch (unit_type_combo_box.get_active()) { - - case 0: - return true; - - case 1: - return active_state != "inactive" || job != ""; - - case 2: - return id.has_suffix(".service"); - - case 3: - return id.has_suffix(".socket"); - - case 4: - return id.has_suffix(".device"); - - case 5: - return id.has_suffix(".mount"); - - case 6: - return id.has_suffix(".automount"); - - case 7: - return id.has_suffix(".target"); - - case 8: - return id.has_suffix(".snapshot"); + case 0: + return true; + case 1: + return id.has_suffix(".target"); + case 2: + return id.has_suffix(".service"); + case 3: + return id.has_suffix(".device"); + case 4: + return id.has_suffix(".mount"); + case 5: + return id.has_suffix(".automount"); + case 6: + return id.has_suffix(".swap"); + case 7: + return id.has_suffix(".socket"); + case 8: + return id.has_suffix(".path"); + case 9: + return id.has_suffix(".timer"); + case 10: + return id.has_suffix(".snapshot"); + default: + assert(false); + return false; } - - return false; } public void unit_type_changed() { - TreeModelFilter model = (TreeModelFilter) unit_view.get_model(); + TreeModelFilter model = (TreeModelFilter) ((TreeModelSort) unit_view.get_model()).get_model(); model.refilter(); } @@ -907,7 +960,7 @@ public class MainWindow : Window { public void on_server_reload() { try { manager.reload(); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } } @@ -919,7 +972,7 @@ public class MainWindow : Window { if (unit_type_combo_box.get_active() != 0) unit_type_combo_box.set_active(8); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } } @@ -948,7 +1001,7 @@ public class MainWindow : Window { m.destroy(); show_unit(u); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } } @@ -968,7 +1021,7 @@ public class MainWindow : Window { path); show_unit(u); - } catch (IOError e) { + } catch (Error e) { show_error(e.message); } 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 . - -__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 a423fdbf93..18074402e5 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -551,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; @@ -580,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); } @@ -3443,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; 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 . + +__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/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/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/vconsole-setup.c b/src/vconsole-setup.c index c5f3628c9b..91967891f1 100644 --- a/src/vconsole-setup.c +++ b/src/vconsole-setup.c @@ -160,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; @@ -371,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/wraplabel.vala b/src/wraplabel.vala new file mode 100644 index 0000000000..49858c3222 --- /dev/null +++ b/src/wraplabel.vala @@ -0,0 +1,73 @@ +// Copyright (c) 2005 VMware, Inc. + +// This is a translation of http://git.gnome.org/browse/meld/tree/meld/ui/wraplabel.py, +// which in turn is a translation of WrapLabel from libview. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// Python translation from wrapLabel.{cc|h} by Gian Mario Tagliaretti +// Vala translation from wraplabel.py by Zbigniew Jędrzejewski-Szmek + +public class WrapLabel : Gtk.Label { + private int _wrap_width; + + public WrapLabel(string? text = null) { + this._wrap_width = 0; + var layout = get_layout(); + layout.set_wrap(Pango.WrapMode.WORD_CHAR); + if (text != null) + this.set_text(text); + this.set_alignment(0, 0); + } + + public override void size_request(out Gtk.Requisition requisition) { + int width, height; + var layout = get_layout(); + layout.get_pixel_size(out width, out height); + requisition.width = 0; + requisition.height = height; + } + + public override void size_allocate(Gdk.Rectangle allocation) { + base.size_allocate (allocation); + this._set_wrap_width(allocation.width); + } + + public new void set_text(string str) { + base.set_text(str); + this._set_wrap_width(this._wrap_width); + } + + public new void set_markup(string str) { + base.set_markup(str); + this._set_wrap_width(this._wrap_width); + } + + private void _set_wrap_width(int width) { + if (width == 0) + return; + + var layout = get_layout(); + layout.set_width(width * Pango.SCALE); + if (_wrap_width != width) { + this._wrap_width = width; + this.queue_resize(); + } + } +} diff --git a/units/console-shell.service.m4 b/units/console-shell.service.m4 index a4a9108b32..02adc8403b 100644 --- a/units/console-shell.service.m4 +++ b/units/console-shell.service.m4 @@ -23,6 +23,9 @@ After=rc-local.service m4_ifdef(`TARGET_MANDRIVA', After=rc-local.service )m4_dnl +m4_ifdef(`TARGET_MAGEIA', +After=rc-local.service +)m4_dnl Before=getty.target [Service] diff --git a/units/getty@.service.m4 b/units/getty@.service.m4 index 14d8187269..d2a145dacd 100644 --- a/units/getty@.service.m4 +++ b/units/getty@.service.m4 @@ -24,6 +24,9 @@ After=rc-local.service m4_ifdef(`TARGET_MANDRIVA', After=rc-local.service )m4_dnl +m4_ifdef(`TARGET_MAGEIA', +After=rc-local.service +)m4_dnl # If additional gettys are spawned during boot then we should make # sure that this is synchronized before getty.target, even though diff --git a/units/mageia/prefdm.service b/units/mageia/prefdm.service new file mode 100644 index 0000000000..4a896bf582 --- /dev/null +++ b/units/mageia/prefdm.service @@ -0,0 +1,21 @@ +# This file is part of systemd. +# +# 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. + +[Unit] +Description=Display Manager +After=livesys-late.service rc-local.service systemd-user-sessions.service +After=network.target acpid.service fs.service haldaemon.service + +# Do not stop plymouth, it is done in prefdm if required +Conflicts=plymouth-quit.service +After=plymouth-quit.service + +[Service] +ExecStart=/etc/X11/prefdm +Type=forking +Restart=always +RestartSec=0 diff --git a/units/remote-fs-pre.target b/units/remote-fs-pre.target index 5406aa22d3..8aceb08b9d 100644 --- a/units/remote-fs-pre.target +++ b/units/remote-fs-pre.target @@ -10,6 +10,3 @@ [Unit] Description=Remote File Systems (Pre) After=network.target - -[Install] -WantedBy=multi-user.target diff --git a/units/rescue.service.m4 b/units/rescue.service.m4 index 19b30d89f9..7dd8a220b8 100644 --- a/units/rescue.service.m4 +++ b/units/rescue.service.m4 @@ -25,10 +25,13 @@ ExecStart=-/bin/bash -c "exec ${SINGLE}"', m4_ifdef(`TARGET_MANDRIVA', `EnvironmentFile=/etc/sysconfig/init ExecStart=-/bin/bash -c "exec ${SINGLE}"', +m4_ifdef(`TARGET_MAGEIA', +`EnvironmentFile=/etc/sysconfig/init +ExecStart=-/bin/bash -c "exec ${SINGLE}"', m4_ifdef(`TARGET_MEEGO', `EnvironmentFile=/etc/sysconfig/init ExecStart=-/bin/bash -c "exec ${SINGLE}"', -`ExecStart=-/sbin/sulogin'))) +`ExecStart=-/sbin/sulogin')))) ExecStopPost=-/bin/systemctl --fail --no-block default StandardInput=tty-force StandardOutput=inherit diff --git a/units/serial-getty@.service.m4 b/units/serial-getty@.service.m4 index 082290cb8b..e5f0ca6c6c 100644 --- a/units/serial-getty@.service.m4 +++ b/units/serial-getty@.service.m4 @@ -24,6 +24,9 @@ After=rc-local.service m4_ifdef(`TARGET_MANDRIVA', After=rc-local.service )m4_dnl +m4_ifdef(`TARGET_MAGEIA', +After=rc-local.service +)m4_dnl # If additional gettys are spawned during boot then we should make # sure that this is synchronized before getty.target, even though