diff --git a/0001-Add-bootsplash-handling-for-password-dialogs.patch b/0001-Add-bootsplash-handling-for-password-dialogs.patch index e4bdce2..7338d21 100644 --- a/0001-Add-bootsplash-handling-for-password-dialogs.patch +++ b/0001-Add-bootsplash-handling-for-password-dialogs.patch @@ -8,8 +8,8 @@ splash screen to verbose when a password is asked... --- diff --git a/src/ask-password-api.c b/src/ask-password-api.c index da967ab..b89bcea 100644 ---- a/src/ask-password-api.c -+++ b/src/ask-password-api.c +--- a/src/shared/ask-password-api.c ++++ b/src/shared/ask-password-api.c @@ -62,6 +62,9 @@ int ask_password_tty( bool reset_tty = false; bool silent_mode = false; diff --git a/0001-Reinstate-TIMEOUT-handling.patch b/0001-Reinstate-TIMEOUT-handling.patch new file mode 100644 index 0000000..9e451f4 --- /dev/null +++ b/0001-Reinstate-TIMEOUT-handling.patch @@ -0,0 +1,130 @@ +Without treating events with timeouts specially some drivers would +cause a 30 seconds stall on boot: . + +I also received reports of some drivers not working at all, even +after the timeout. + +We will remove this patch when more drivers have been fixed in +the kernel (3.4?). + +This reverts 43d5c5f03645c4b842659f9b5bd0ae465e885e92 and +57c6f8ae5f52a6e8ffc66a54966346f733dded39. +--- + +Note: this is mostly a FYI, and whether or not it makes sense +to apply this upstream depends on how big problems other report +regarding this issue. + + src/libudev-device.c | 19 +++++++++++++++++++ + src/libudev-private.h | 1 + + src/udevd.c | 13 ++++++++++--- + 4 files changed, 32 insertions(+), 3 deletions(-) + +Index: systemd-190/src/libudev/libudev-device.c +=================================================================== +--- systemd-190.orig/src/libudev/libudev-device.c ++++ systemd-190/src/libudev/libudev-device.c +@@ -68,6 +68,7 @@ struct udev_device { + struct udev_list tags_list; + unsigned long long int seqnum; + unsigned long long int usec_initialized; ++ int timeout; + int devlink_priority; + int refcount; + dev_t devnum; +@@ -162,6 +163,21 @@ static int udev_device_set_devnum(struct + return 0; + } + ++int udev_device_get_timeout(struct udev_device *udev_device) ++{ ++ return udev_device->timeout; ++} ++ ++static int udev_device_set_timeout(struct udev_device *udev_device, int timeout) ++{ ++ char num[32]; ++ ++ udev_device->timeout = timeout; ++ snprintf(num, sizeof(num), "%u", timeout); ++ udev_device_add_property(udev_device, "TIMEOUT", num); ++ return 0; ++} ++ + const char *udev_device_get_devpath_old(struct udev_device *udev_device) + { + return udev_device->devpath_old; +@@ -418,6 +434,8 @@ void udev_device_add_property_from_strin + udev_device_set_devpath_old(udev_device, &property[12]); + } else if (startswith(property, "SEQNUM=")) { + udev_device_set_seqnum(udev_device, strtoull(&property[7], NULL, 10)); ++ } else if (startswith(property, "TIMEOUT=")) { ++ udev_device_set_timeout(udev_device, strtoull(&property[8], NULL, 10)); + } else if (startswith(property, "IFINDEX=")) { + udev_device_set_ifindex(udev_device, strtoull(&property[8], NULL, 10)); + } else if (startswith(property, "DEVMODE=")) { +@@ -605,6 +623,7 @@ struct udev_device *udev_device_new(stru + udev_list_init(udev, &udev_device->sysattr_value_list, true); + udev_list_init(udev, &udev_device->sysattr_list, false); + udev_list_init(udev, &udev_device->tags_list, true); ++ udev_device->timeout = -1; + udev_device->watch_handle = -1; + /* copy global properties */ + udev_list_entry_foreach(list_entry, udev_get_properties_list_entry(udev)) +Index: systemd-190/src/libudev/libudev-private.h +=================================================================== +--- systemd-190.orig/src/libudev/libudev-private.h ++++ systemd-190/src/libudev/libudev-private.h +@@ -65,6 +65,7 @@ const char *udev_device_get_id_filename( + void udev_device_set_is_initialized(struct udev_device *udev_device); + int udev_device_add_tag(struct udev_device *udev_device, const char *tag); + void udev_device_cleanup_tags_list(struct udev_device *udev_device); ++int udev_device_get_timeout(struct udev_device *udev_device); + unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device); + void udev_device_set_usec_initialized(struct udev_device *udev_device, unsigned long long usec_initialized); + int udev_device_get_devlink_priority(struct udev_device *udev_device); +Index: systemd-190/src/udev/udevd.c +=================================================================== +--- systemd-190.orig/src/udev/udevd.c ++++ systemd-190/src/udev/udevd.c +@@ -387,7 +387,7 @@ out: + } + } + +-static void event_run(struct event *event) ++static void event_run(struct event *event, bool force) + { + struct udev_list_node *loop; + +@@ -413,7 +413,7 @@ static void event_run(struct event *even + return; + } + +- if (children >= children_max) { ++ if (!force && children >= children_max) { + if (children_max > 1) + log_debug("maximum number (%i) of children reached\n", children); + return; +@@ -447,6 +447,13 @@ static int event_queue_insert(struct ude + + event->state = EVENT_QUEUED; + udev_list_node_append(&event->node, &event_list); ++ ++ /* run all events with a timeout set immediately */ ++ if (udev_device_get_timeout(dev) > 0) { ++ event_run(event, true); ++ return 0; ++ } ++ + return 0; + } + +@@ -552,7 +559,7 @@ static void event_queue_start(struct ude + if (is_devpath_busy(event)) + continue; + +- event_run(event); ++ event_run(event, false); + } + } + diff --git a/0001-add-sparse-support-to-detect-endianness-bug.patch b/0001-add-sparse-support-to-detect-endianness-bug.patch deleted file mode 100644 index d4c084d..0000000 --- a/0001-add-sparse-support-to-detect-endianness-bug.patch +++ /dev/null @@ -1,368 +0,0 @@ -From 7644bc8665f39a6428049e81e8c04e4d755e55a1 Mon Sep 17 00:00:00 2001 -From: Frederic Crozat -Date: Fri, 16 Mar 2012 11:59:04 +0100 -Subject: [PATCH] add sparse support to detect endianness bug - -le16/32/64_t type should be used when storing little-endian value - -header to integrate with sparse from Josh Triplett ---- - src/journal/journal-def.h | 74 +++++++++++++++++----------------- - src/journal/journal-file.c | 15 ++++--- - src/journal/journal-internal.h | 2 +- - src/journal/journald.c | 5 +- - src/journal/sd-journal.c | 10 +++-- - src/journal/sparse-endian.h | 87 ++++++++++++++++++++++++++++++++++++++++ - 6 files changed, 142 insertions(+), 51 deletions(-) - create mode 100644 src/journal/sparse-endian.h - -diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h -index 964e0c2..9cb8051 100644 ---- a/src/journal/journal-def.h -+++ b/src/journal/journal-def.h -@@ -22,7 +22,7 @@ - along with systemd; If not, see . - ***/ - --#include -+#include "sparse-endian.h" - - #include - -@@ -60,48 +60,48 @@ _packed_ struct ObjectHeader { - uint8_t type; - uint8_t flags; - uint8_t reserved[6]; -- uint64_t size; -+ le64_t size; - uint8_t payload[]; - }; - - _packed_ struct DataObject { - ObjectHeader object; -- uint64_t hash; -- uint64_t next_hash_offset; -- uint64_t next_field_offset; -- uint64_t entry_offset; /* the first array entry we store inline */ -- uint64_t entry_array_offset; -- uint64_t n_entries; -+ le64_t hash; -+ le64_t next_hash_offset; -+ le64_t next_field_offset; -+ le64_t entry_offset; /* the first array entry we store inline */ -+ le64_t entry_array_offset; -+ le64_t n_entries; - uint8_t payload[]; - }; - - _packed_ struct FieldObject { - ObjectHeader object; -- uint64_t hash; -- uint64_t next_hash_offset; -- uint64_t head_data_offset; -- uint64_t tail_data_offset; -+ le64_t hash; -+ le64_t next_hash_offset; -+ le64_t head_data_offset; -+ le64_t tail_data_offset; - uint8_t payload[]; - }; - - _packed_ struct EntryItem { -- uint64_t object_offset; -- uint64_t hash; -+ le64_t object_offset; -+ le64_t hash; - }; - - _packed_ struct EntryObject { - ObjectHeader object; -- uint64_t seqnum; -- uint64_t realtime; -- uint64_t monotonic; -+ le64_t seqnum; -+ le64_t realtime; -+ le64_t monotonic; - sd_id128_t boot_id; -- uint64_t xor_hash; -+ le64_t xor_hash; - EntryItem items[]; - }; - - _packed_ struct HashItem { -- uint64_t head_hash_offset; -- uint64_t tail_hash_offset; -+ le64_t head_hash_offset; -+ le64_t tail_hash_offset; - }; - - _packed_ struct HashTableObject { -@@ -111,8 +111,8 @@ _packed_ struct HashTableObject { - - _packed_ struct EntryArrayObject { - ObjectHeader object; -- uint64_t next_entry_array_offset; -- uint64_t items[]; -+ le64_t next_entry_array_offset; -+ le64_t items[]; - }; - - union Object { -@@ -145,21 +145,21 @@ _packed_ struct Header { - sd_id128_t machine_id; - sd_id128_t boot_id; - sd_id128_t seqnum_id; -- uint64_t arena_offset; -- uint64_t arena_size; -- uint64_t data_hash_table_offset; /* for looking up data objects */ -- uint64_t data_hash_table_size; -- uint64_t field_hash_table_offset; /* for looking up field objects */ -- uint64_t field_hash_table_size; -- uint64_t tail_object_offset; -- uint64_t n_objects; -- uint64_t n_entries; -- uint64_t seqnum; -- uint64_t first_seqnum; -- uint64_t entry_array_offset; -- uint64_t head_entry_realtime; -- uint64_t tail_entry_realtime; -- uint64_t tail_entry_monotonic; -+ le64_t arena_offset; -+ le64_t arena_size; -+ le64_t data_hash_table_offset; /* for looking up data objects */ -+ le64_t data_hash_table_size; -+ le64_t field_hash_table_offset; /* for looking up field objects */ -+ le64_t field_hash_table_size; -+ le64_t tail_object_offset; -+ le64_t n_objects; -+ le64_t n_entries; -+ le64_t seqnum; -+ le64_t first_seqnum; -+ le64_t entry_array_offset; -+ le64_t head_entry_realtime; -+ le64_t tail_entry_realtime; -+ le64_t tail_entry_monotonic; - }; - - #endif -diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c -index 474dd5c..e803cec 100644 ---- a/src/journal/journal-file.c -+++ b/src/journal/journal-file.c -@@ -793,8 +793,8 @@ static uint64_t journal_file_entry_array_n_items(Object *o) { - } - - static int link_entry_into_array(JournalFile *f, -- uint64_t *first, -- uint64_t *idx, -+ le64_t *first, -+ le64_t *idx, - uint64_t p) { - int r; - uint64_t n = 0, ap = 0, q, i, a, hidx; -@@ -857,9 +857,9 @@ static int link_entry_into_array(JournalFile *f, - } - - static int link_entry_into_array_plus_one(JournalFile *f, -- uint64_t *extra, -- uint64_t *first, -- uint64_t *idx, -+ le64_t *extra, -+ le64_t *first, -+ le64_t *idx, - uint64_t p) { - - int r; -@@ -873,7 +873,7 @@ static int link_entry_into_array_plus_one(JournalFile *f, - if (*idx == 0) - *extra = htole64(p); - else { -- uint64_t i; -+ le64_t i; - - i = htole64(le64toh(*idx) - 1); - r = link_entry_into_array(f, first, &i, p); -@@ -2141,7 +2141,8 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6 - items = alloca(sizeof(EntryItem) * n); - - for (i = 0; i < n; i++) { -- uint64_t le_hash, l, h; -+ uint64_t l, h; -+ le64_t le_hash; - size_t t; - void *data; - Object *u; -diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h -index e5914bf..17f1d31 100644 ---- a/src/journal/journal-internal.h -+++ b/src/journal/journal-internal.h -@@ -35,7 +35,7 @@ typedef struct Match Match; - struct Match { - char *data; - size_t size; -- uint64_t le_hash; -+ le64_t le_hash; - - LIST_FIELDS(Match, matches); - }; -diff --git a/src/journal/journald.c b/src/journal/journald.c -index baad3ab..ebb4275 100644 ---- a/src/journal/journald.c -+++ b/src/journal/journald.c -@@ -1251,6 +1251,7 @@ static void process_native_message( - p = e + 1; - continue; - } else { -+ le64_t l_le; - uint64_t l; - char *k; - -@@ -1259,8 +1260,8 @@ static void process_native_message( - break; - } - -- memcpy(&l, e + 1, sizeof(uint64_t)); -- l = le64toh(l); -+ memcpy(&l_le, e + 1, sizeof(uint64_t)); -+ l = le64toh(l_le); - - if (remaining < e - p + 1 + sizeof(uint64_t) + l + 1 || - e[1+sizeof(uint64_t)+l] != '\n') { -diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c -index 86ac267..e9cd26e 100644 ---- a/src/journal/sd-journal.c -+++ b/src/journal/sd-journal.c -@@ -108,7 +108,7 @@ static int same_field(const void *_a, size_t s, const void *_b, size_t t) { - - _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) { - Match *m, *after = NULL; -- uint64_t le_hash; -+ le64_t le_hash; - - if (!j) - return -EINVAL; -@@ -356,7 +356,7 @@ static int find_location(sd_journal *j, JournalFile *f, direction_t direction, O - Object *c, *d; - uint64_t cp, dp; - -- r = journal_file_find_data_object_with_hash(f, m->data, m->size, m->le_hash, &d, &dp); -+ r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), &d, &dp); - if (r <= 0) - return r; - -@@ -1349,7 +1349,8 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** - - n = journal_file_entry_n_items(o); - for (i = 0; i < n; i++) { -- uint64_t p, l, le_hash; -+ uint64_t p, l; -+ le64_t le_hash; - size_t t; - - p = le64toh(o->entry.items[i].object_offset); -@@ -1410,7 +1411,8 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** - - _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) { - JournalFile *f; -- uint64_t p, l, n, le_hash; -+ uint64_t p, l, n; -+ le64_t le_hash; - int r; - Object *o; - size_t t; -diff --git a/src/journal/sparse-endian.h b/src/journal/sparse-endian.h -new file mode 100644 -index 0000000..eb4dbf3 ---- /dev/null -+++ b/src/journal/sparse-endian.h -@@ -0,0 +1,87 @@ -+/* Copyright (c) 2012 Josh Triplett -+ * -+ * 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. -+ */ -+#ifndef SPARSE_ENDIAN_H -+#define SPARSE_ENDIAN_H -+ -+#include -+#include -+ -+#ifdef __CHECKER__ -+#define __bitwise __attribute__((bitwise)) -+#define __force __attribute__((force)) -+#else -+#define __bitwise -+#define __force -+#endif -+ -+typedef uint16_t __bitwise le16_t; -+typedef uint16_t __bitwise be16_t; -+typedef uint32_t __bitwise le32_t; -+typedef uint32_t __bitwise be32_t; -+typedef uint64_t __bitwise le64_t; -+typedef uint64_t __bitwise be64_t; -+ -+#undef htobe16 -+#undef htole16 -+#undef be16toh -+#undef le16toh -+#undef htobe32 -+#undef htole32 -+#undef be32toh -+#undef le32toh -+#undef htobe64 -+#undef htole64 -+#undef be64toh -+#undef le64toh -+ -+#if __BYTE_ORDER == __LITTLE_ENDIAN -+#define bswap_16_on_le(x) __bswap_16(x) -+#define bswap_32_on_le(x) __bswap_32(x) -+#define bswap_64_on_le(x) __bswap_64(x) -+#define bswap_16_on_be(x) (x) -+#define bswap_32_on_be(x) (x) -+#define bswap_64_on_be(x) (x) -+#elif __BYTE_ORDER == __BIG_ENDIAN -+#define bswap_16_on_le(x) (x) -+#define bswap_32_on_le(x) (x) -+#define bswap_64_on_le(x) (x) -+#define bswap_16_on_be(x) __bswap_16(x) -+#define bswap_32_on_be(x) __bswap_32(x) -+#define bswap_64_on_be(x) __bswap_64(x) -+#endif -+ -+static inline le16_t htole16(uint16_t value) { return (le16_t __force) bswap_16_on_be(value); } -+static inline le32_t htole32(uint32_t value) { return (le32_t __force) bswap_32_on_be(value); } -+static inline le64_t htole64(uint64_t value) { return (le64_t __force) bswap_64_on_be(value); } -+ -+static inline be16_t htobe16(uint16_t value) { return (be16_t __force) bswap_16_on_le(value); } -+static inline be32_t htobe32(uint32_t value) { return (be32_t __force) bswap_32_on_le(value); } -+static inline be64_t htobe64(uint64_t value) { return (be64_t __force) bswap_64_on_le(value); } -+ -+static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __force)value); } -+static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __force)value); } -+static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __force)value); } -+ -+static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __force)value); } -+static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __force)value); } -+static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __force)value); } -+ -+#endif /* SPARSE_ENDIAN_H */ --- -1.7.7 - diff --git a/0001-handle-disable_caplock-and-compose_table-and-kbd_rat.patch b/0001-handle-disable_caplock-and-compose_table-and-kbd_rat.patch index af4e4fb..8376c34 100644 --- a/0001-handle-disable_caplock-and-compose_table-and-kbd_rat.patch +++ b/0001-handle-disable_caplock-and-compose_table-and-kbd_rat.patch @@ -7,10 +7,10 @@ Subject: [PATCH] handle disable_caplock and compose_table and kbd_rate src/vconsole-setup.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 121 insertions(+), 3 deletions(-) -Index: systemd-37/src/vconsole-setup.c +Index: systemd-189/src/vconsole/vconsole-setup.c =================================================================== ---- systemd-37.orig/src/vconsole/vconsole-setup.c -+++ systemd-37/src/vconsole/vconsole-setup.c +--- systemd-189.orig/src/vconsole/vconsole-setup.c ++++ systemd-189/src/vconsole/vconsole-setup.c @@ -40,6 +40,7 @@ #include "log.h" #include "macro.h" @@ -19,7 +19,7 @@ Index: systemd-37/src/vconsole-setup.c static bool is_vconsole(int fd) { unsigned char data[1]; -@@ -79,8 +80,8 @@ +@@ -99,8 +100,8 @@ static int enable_utf8(int fd) { return r; } @@ -30,7 +30,7 @@ Index: systemd-37/src/vconsole-setup.c int i = 0; pid_t pid; -@@ -99,6 +100,8 @@ +@@ -119,6 +120,8 @@ static int load_keymap(const char *vc, c args[i++] = map; if (map_toggle) args[i++] = map_toggle; @@ -38,8 +38,8 @@ Index: systemd-37/src/vconsole-setup.c + args[i++] = "disable.capslock"; args[i++] = NULL; - if ((pid = fork()) < 0) { -@@ -150,6 +153,101 @@ + pid = fork(); +@@ -172,6 +175,101 @@ static int load_font(const char *vc, con return 0; } @@ -141,7 +141,7 @@ Index: systemd-37/src/vconsole-setup.c int main(int argc, char **argv) { const char *vc; char *vc_keymap = NULL; -@@ -163,8 +261,16 @@ +@@ -185,8 +283,16 @@ int main(int argc, char **argv) { #if defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA) char *vc_keytable = NULL; #endif @@ -158,29 +158,26 @@ Index: systemd-37/src/vconsole-setup.c int r = EXIT_FAILURE; pid_t font_pid = 0, keymap_pid = 0; -@@ -265,6 +371,10 @@ - #elif defined(TARGET_SUSE) - if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE, - "KEYTABLE", &vc_keymap, -+ "KBD_DELAY", &vc_kbd_delay, -+ "KBD_RATE", &vc_kbd_rate, -+ "KBD_DISABLE_CAPS_LOCK", &vc_kbd_disable_caps_lock, -+ "COMPOSETABLE", &vc_compose_table, - NULL)) < 0) { - - if (r != -ENOENT) -@@ -280,6 +390,7 @@ - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r)); +@@ -281,10 +387,15 @@ int main(int argc, char **argv) { + free(vc_keymap); + vc_keymap = t; } + disable_capslock = vc_kbd_disable_caps_lock && strcasecmp(vc_kbd_disable_caps_lock, "YES") == 0; - #elif defined(TARGET_ARCH) - if ((r = parse_env_file("/etc/rc.conf", NEWLINE, -@@ -436,7 +547,11 @@ - if (!utf8) + #elif defined(TARGET_SUSE) + r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE, + "KEYTABLE", &vc_keymap, ++ "KBD_DELAY", &vc_kbd_delay, ++ "KBD_RATE", &vc_kbd_rate, ++ "KBD_DISABLE_CAPS_LOCK", &vc_kbd_disable_caps_lock, ++ "COMPOSETABLE", &vc_compose_table, + NULL); + if (r < 0 && r != -ENOENT) + log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r)); +@@ -443,7 +554,11 @@ int main(int argc, char **argv) { disable_utf8(fd); + - if (load_keymap(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 && + if (load_keymap(vc, vc_keymap, vc_keymap_toggle, utf8, disable_capslock, &keymap_pid) >= 0 && +#ifdef TARGET_SUSE @@ -190,7 +187,7 @@ Index: systemd-37/src/vconsole-setup.c load_font(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0) r = EXIT_SUCCESS; -@@ -444,6 +559,14 @@ +@@ -451,6 +566,14 @@ finish: if (keymap_pid > 0) wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid); @@ -205,7 +202,7 @@ Index: systemd-37/src/vconsole-setup.c if (font_pid > 0) wait_for_terminate_and_warn(KBD_SETFONT, font_pid); -@@ -451,6 +574,12 @@ +@@ -458,6 +581,12 @@ finish: free(vc_font); free(vc_font_map); free(vc_font_unimap); @@ -218,4 +215,3 @@ Index: systemd-37/src/vconsole-setup.c if (fd >= 0) close_nointr_nofail(fd); -Only in new/src/vconsole: vconsole-setup.c.orig diff --git a/0001-service-Fix-dependencies-added-when-parsing-insserv..patch b/0001-service-Fix-dependencies-added-when-parsing-insserv..patch index 6719794..36ca5a7 100644 --- a/0001-service-Fix-dependencies-added-when-parsing-insserv..patch +++ b/0001-service-Fix-dependencies-added-when-parsing-insserv..patch @@ -9,8 +9,8 @@ Subject: [PATCH] service: Fix dependencies added when parsing insserv.conf Index: systemd-41/src/service.c =================================================================== ---- systemd-41.orig/src/service.c -+++ systemd-41/src/service.c +--- systemd-41.orig/src/core/service.c ++++ systemd-41/src/core/service.c @@ -3210,23 +3210,30 @@ static void sysv_facility_in_insserv_con Unit *u; if (sysv_translate_facility(parsed[0], NULL, &facility) < 0) diff --git a/0001-service-flags-sysv-service-with-detected-pid-as-Rema.patch b/0001-service-flags-sysv-service-with-detected-pid-as-Rema.patch index 3f1770f..eebd73f 100644 --- a/0001-service-flags-sysv-service-with-detected-pid-as-Rema.patch +++ b/0001-service-flags-sysv-service-with-detected-pid-as-Rema.patch @@ -14,8 +14,8 @@ Fixes https://bugzilla.novell.com/show_bug.cgi?id=721426 Index: systemd-37/src/service.c =================================================================== ---- systemd-37.orig/src/service.c -+++ systemd-37/src/service.c +--- systemd-37.orig/src/core/service.c ++++ systemd-37/src/core/service.c @@ -2014,8 +2014,13 @@ static void service_enter_running(Servic cgroup_ok = cgroup_good(s); diff --git a/0001-util-never-follow-symlinks-in-rm_rf_children.patch b/0001-util-never-follow-symlinks-in-rm_rf_children.patch deleted file mode 100644 index 38579de..0000000 --- a/0001-util-never-follow-symlinks-in-rm_rf_children.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 5ebff5337594d690b322078c512eb222d34aaa82 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Fri, 2 Mar 2012 10:39:10 +0100 -Subject: [PATCH] util: never follow symlinks in rm_rf_children() - -The function checks if the entry is a directory before recursing, but -there is a window between the check and the open, during which the -directory could be replaced with a symlink. - -CVE-2012-1174 -https://bugzilla.redhat.com/show_bug.cgi?id=803358 ---- - src/util.c | 3 ++- - 1 files changed, 2 insertions(+), 1 deletions(-) - -diff --git a/src/util.c b/src/util.c -index 20cbc2b..dfc1dc6 100644 ---- a/src/util.c -+++ b/src/util.c -@@ -3593,7 +3593,8 @@ static int rm_rf_children(int fd, bool only_dirs, bool honour_sticky) { - if (is_dir) { - int subdir_fd; - -- if ((subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) { -+ subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); -+ if (subdir_fd < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - continue; --- -1.7.7 - -From c9d8629baa09f853fbcc44972c9748e70562270c Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Thu, 22 Mar 2012 01:43:36 +0100 -Subject: [PATCH] logind: extend comment about X11 socket symlink - ---- - src/login/logind-session.c | 4 ++++ - 1 files changed, 4 insertions(+), 0 deletions(-) - -diff --git a/src/login/logind-session.c b/src/login/logind-session.c -index af9c12d..4e0af86 100644 ---- a/src/login/logind-session.c -+++ b/src/login/logind-session.c -@@ -391,6 +391,10 @@ static int session_link_x11_socket(Session *s) { - return -ENOENT; - } - -+ /* Note that this cannot be in a subdir to avoid -+ * vulnerabilities since we are privileged but the runtime -+ * path is owned by the user */ -+ - t = strappend(s->user->runtime_path, "/X11-display"); - if (!t) { - log_error("Out of memory"); --- -1.7.7 - diff --git a/0013-re-enable-by_path-links-for-ata-devices.patch b/0013-re-enable-by_path-links-for-ata-devices.patch new file mode 100644 index 0000000..41242f3 --- /dev/null +++ b/0013-re-enable-by_path-links-for-ata-devices.patch @@ -0,0 +1,108 @@ +Index: udev-182/src/udev-builtin-path_id.c +=================================================================== +--- udev-182.orig/src/udev/udev-builtin-path_id.c ++++ udev-182/src/udev/udev-builtin-path_id.c +@@ -286,6 +286,85 @@ out: + return hostdev; + } + ++static struct udev_device *handle_ata(struct udev_device *parent, char **path) ++{ ++ struct udev_device *hostdev; ++ int host, bus, target, lun; ++ const char *name; ++ char *base; ++ char *pos; ++ DIR *dir; ++ struct dirent *dent; ++ int basenum, len; ++ ++ hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host"); ++ if (hostdev == NULL) ++ return NULL; ++ ++ name = udev_device_get_sysname(parent); ++ if (sscanf(name, "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4) ++ return NULL; ++ ++ /* rebase ata offset to get the local relative number */ ++ basenum = -1; ++ base = strdup(udev_device_get_syspath(hostdev)); ++ if (base == NULL) ++ return NULL; ++ pos = strrchr(base, '/'); ++ if (pos == NULL) { ++ parent = NULL; ++ goto out; ++ } ++ pos[0] = '\0'; ++ len = strlen(base) - 5; ++ if (len <= 0) { ++ parent = NULL; ++ goto out; ++ } ++ base[len] = '\0'; ++ dir = opendir(base); ++ if (dir == NULL) { ++ parent = NULL; ++ goto out; ++ } ++ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { ++ char *rest; ++ int i; ++ ++ if (dent->d_name[0] == '.') ++ continue; ++ if (dent->d_type != DT_DIR && dent->d_type != DT_LNK) ++ continue; ++ if (strncmp(dent->d_name, "ata", 3) != 0) ++ continue; ++ i = strtoul(&dent->d_name[3], &rest, 10); ++ ++ /* ata devices start with 1, so decrease by 1 if i is bigger then 0 */ ++ if (i > 0) ++ i--; ++ if (rest[0] != '\0') ++ continue; ++ /* ++ * find the smallest number; the host really needs to export its ++ * own instance number per parent device; relying on the global host ++ * enumeration and plainly rebasing the numbers sounds unreliable ++ */ ++ if (basenum == -1 || i < basenum) ++ basenum = i; ++ } ++ closedir(dir); ++ if (basenum == -1) { ++ parent = NULL; ++ goto out; ++ } ++ host -= basenum; ++ ++ path_prepend(path, "scsi-%u:%u:%u:%u", host, bus, target, lun); ++out: ++ free(base); ++ return hostdev; ++} ++ + static struct udev_device *handle_scsi(struct udev_device *parent, char **path) + { + const char *devtype; +@@ -322,16 +401,8 @@ static struct udev_device *handle_scsi(s + goto out; + } + +- /* +- * We do not support the ATA transport class, it creates duplicated link +- * names as the fake SCSI host adapters are all separated, they are all +- * re-based as host == 0. ATA should just stop faking two duplicated +- * hierarchies for a single topology and leave the SCSI stuff alone; +- * until that happens, there are no by-path/ links for ATA devices behind +- * an ATA transport class. +- */ + if (strstr(name, "/ata") != NULL) { +- parent = NULL; ++ parent = handle_ata(parent, path); + goto out; + } + diff --git a/0014-rules-create-by-id-scsi-links-for-ATA-devices.patch b/0014-rules-create-by-id-scsi-links-for-ATA-devices.patch new file mode 100644 index 0000000..240d820 --- /dev/null +++ b/0014-rules-create-by-id-scsi-links-for-ATA-devices.patch @@ -0,0 +1,15 @@ +Index: udev-182/rules/60-persistent-storage.rules +=================================================================== +--- udev-182.orig/rules/60-persistent-storage.rules ++++ udev-182/rules/60-persistent-storage.rules +@@ -44,6 +44,10 @@ KERNEL=="cciss*", ENV{DEVTYPE}=="disk", + KERNEL=="sd*|sr*|cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}" + KERNEL=="sd*|cciss*", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}-part%n" + ++# scsi compat links for ATA devices ++KERNEL=="sd*[!0-9]", ENV{ID_BUS}=="ata", PROGRAM="scsi_id --whitelisted --replace-whitespace -p0x80 -d $devnode", RESULT=="?*", ENV{ID_SCSI_COMPAT}="$result", SYMLINK+="disk/by-id/scsi-$env{ID_SCSI_COMPAT}" ++KERNEL=="sd*[0-9]", ENV{ID_SCSI_COMPAT}=="?*", SYMLINK+="disk/by-id/scsi-$env{ID_SCSI_COMPAT}-part%n" ++ + # firewire + KERNEL=="sd*[!0-9]|sr*", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}" + KERNEL=="sd*[0-9]", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}-part%n" diff --git a/0026-udev-netlink-null-rules.patch b/0026-udev-netlink-null-rules.patch new file mode 100644 index 0000000..c0b7d44 --- /dev/null +++ b/0026-udev-netlink-null-rules.patch @@ -0,0 +1,13 @@ +Index: udev-182/src/udevd.c +=================================================================== +--- udev-182.orig/src/udev/udevd.c ++++ udev-182/src/udev/udevd.c +@@ -1683,6 +1683,8 @@ int main(int argc, char *argv[]) + dev = udev_monitor_receive_device(monitor); + if (dev != NULL) { + udev_device_set_usec_initialized(dev, now_usec()); ++ if (rules == NULL) ++ rules = udev_rules_new(udev, resolve_names); + if (event_queue_insert(dev) < 0) + udev_device_unref(dev); + } diff --git a/0027-udev-fix-sg-autoload-regression.patch b/0027-udev-fix-sg-autoload-regression.patch new file mode 100644 index 0000000..642f4fa --- /dev/null +++ b/0027-udev-fix-sg-autoload-regression.patch @@ -0,0 +1,12 @@ +Index: systemd-190/rules/80-drivers.rules +=================================================================== +--- systemd-190.orig/rules/80-drivers.rules ++++ systemd-190/rules/80-drivers.rules +@@ -7,6 +7,7 @@ SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}== + SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="MS", IMPORT{builtin}="kmod load tifm_ms" + SUBSYSTEM=="memstick", IMPORT{builtin}="kmod load ms_block mspro_block" + SUBSYSTEM=="i2o", IMPORT{builtin}="kmod load i2o_block" ++SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST!="[module/sg]", IMPORT{builtin}="kmod load sg" + SUBSYSTEM=="module", KERNEL=="parport_pc", RUN{builtin}="kmod load ppdev" + + LABEL="drivers_end" diff --git a/avoid-random-seed-cycle.patch b/avoid-random-seed-cycle.patch deleted file mode 100644 index daada87..0000000 --- a/avoid-random-seed-cycle.patch +++ /dev/null @@ -1,109 +0,0 @@ - -Rather than ordering systemd-random-seed-load.service after local-fs.target, -start it by path-activation. - -We need write access to the seed, so we order the path unit after -remount-rootfs.service (in case /var is on the root fs). - -A better solution might be to introduce PathIsWritable=, but that is not -necessary in order to solve the problem, and I don't know of any other -usecases for it. - -Cc: Frederic Crozat -Cc: Michal Schmidt ---- - -This is my second attempt at solving this problem. The first one had -some issues as pointed out by Frederic and Michael. - - Makefile.am | 7 +++++-- - TODO | 2 -- - units/.gitignore | 1 + - units/systemd-random-seed-load.path.in | 18 ++++++++++++++++++ - units/systemd-random-seed-load.service.in | 3 +-- - 5 files changed, 25 insertions(+), 6 deletions(-) - create mode 100644 units/systemd-random-seed-load.path.in - -diff -urB systemd-38/Makefile.am new/Makefile.am ---- systemd-38/Makefile.am 2012-01-11 04:01:36.734404653 +0100 -+++ new/Makefile.am 2012-01-18 09:53:12.763115731 +0100 -@@ -1530,11 +1530,14 @@ - - nodist_systemunit_DATA += \ - units/systemd-random-seed-save.service \ -- units/systemd-random-seed-load.service -+ units/systemd-random-seed-load.service \ -+ units/systemd-random-seed-load.path -+ - - EXTRA_DIST += \ - units/systemd-random-seed-save.service.in \ -- units/systemd-random-seed-load.service.in -+ units/systemd-random-seed-load.service.in \ -+ units/systemd-random-seed-load.path.in - - systemd_random_seed_SOURCES = \ - src/random-seed.c -@@ -1550,8 +1553,8 @@ - rm -f systemd-random-seed-save.service && \ - $(LN_S) ../systemd-random-seed-save.service systemd-random-seed-save.service ) - ( cd $(DESTDIR)$(systemunitdir)/sysinit.target.wants && \ -- rm -f systemd-random-seed-load.service && \ -- $(LN_S) ../systemd-random-seed-load.service systemd-random-seed-load.service ) -+ rm -f systemd-random-seed-load.path && \ -+ $(LN_S) ../systemd-random-seed-load.path systemd-random-seed-load.path ) - - INSTALL_DATA_HOOKS += \ - randomseed-install-data-hook -@@ -2052,6 +2055,7 @@ - -e 's,@exec_prefix\@,$(exec_prefix),g' \ - -e 's,@libdir\@,$(libdir),g' \ - -e 's,@includedir\@,$(includedir),g' \ -+ -e 's,@localstatedir\@,$(localstatedir),g' \ - < $< > $@ || rm $@ - - units/%: units/%.in Makefile -diff --git a/units/systemd-random-seed-load.path.in b/units/systemd-random-seed-load.path.in -new file mode 100644 -index 0000000..614c1d4 ---- /dev/null -+++ b/units/systemd-random-seed-load.path.in -@@ -0,0 +1,18 @@ -+# 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=Random Seed -+DefaultDependencies=no -+Conflicts=shutdown.target -+Before=basic.target shutdown.target -+# in case the seed is on the rootfs, we must -+# wait for the rootfs to be remonuted rw -+After=remount-rootfs.service -+ -+[Path] -+PathExists=@localstatedir@/lib/random-seed -diff --git a/units/systemd-random-seed-load.service.in b/units/systemd-random-seed-load.service.in -index a2b6a55..2bcf1aa 100644 ---- a/units/systemd-random-seed-load.service.in -+++ b/units/systemd-random-seed-load.service.in -@@ -8,9 +8,8 @@ - [Unit] - Description=Load Random Seed - DefaultDependencies=no --Wants=local-fs.target - Conflicts=shutdown.target --After=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target -+After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-random-seed-load.path - Before=sysinit.target shutdown.target - - [Service] --- -1.7.8 - - - diff --git a/baselibs.conf b/baselibs.conf index e0865a2..ea8c7e1 100644 --- a/baselibs.conf +++ b/baselibs.conf @@ -1,3 +1,6 @@ systemd supplements "packageand(systemd:pam-)" -/lib/systemd/system/ +libudev0 +libgudev-1_0-0 + diff --git a/boot.udev b/boot.udev new file mode 100644 index 0000000..82ea239 --- /dev/null +++ b/boot.udev @@ -0,0 +1,81 @@ +#!/bin/sh +# +### BEGIN INIT INFO +# Provides: boot.udev +# Required-Start: +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: B +# Default-Stop: +# Short-Description: manage /dev and kernel device-events +# Description: udevd daemon to manage /dev and kernel device events +### END INIT INFO + +. /etc/rc.status + +PATH="/sbin:/bin" +udev_timeout=180 + +case "$1" in + start) + # create /dev/root symlink with dynamic rule + if [ -x /lib/udev/write_dev_root_rule ]; then + /lib/udev/write_dev_root_rule + fi + + # start udevd + echo -n "Starting udevd: " + /sbin/udevd --daemon + if [ $? -ne 0 ]; then + rc_status -v + rc_exit + fi + rc_status -v + + # trigger events for all devices + echo -n "Loading drivers, configuring devices: " + /sbin/udevadm trigger --type=subsystems --action=add + /sbin/udevadm trigger --type=devices --action=add + + # wait for events to finish + /sbin/udevadm settle --timeout=$udev_timeout + rc_status -v + ;; + stop) + echo -n "Stopping udevd: " + killproc /sbin/udevd + rc_status -v + ;; + restart) + echo -n "Restarting udevd: " + killproc /sbin/udevd + /sbin/udevd --daemon + rc_status -v + ;; + status) + echo -n "Checking for udevd: " + checkproc /sbin/udevd + rc_status -v + ;; + reload) + echo -n "Reloading udev rules: " + /sbin/udevadm control --reload-rules + rc_status -v + ;; + force-reload) + echo -n "Restarting udev and reconfiguring all devices: " + killproc /sbin/udevd + rm -rf /dev/.udev /dev/disk + root_symlink_rule + /sbin/udevd --daemon + /sbin/udevadm trigger --action=add + /sbin/udevadm settle --timeout=$udev_timeout + rc_status -v + ;; + *) + echo "Usage: $0 {start|stop|restart|status|reload|force-reload}" + exit 1 + ;; +esac +rc_exit diff --git a/change-terminal.patch b/change-terminal.patch deleted file mode 100644 index 93d877c..0000000 --- a/change-terminal.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 1505a61772a6e697f2aabdbb0e827a88b0d7ee6b Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Sun, 22 Apr 2012 02:45:39 +0200 -Subject: [PATCH] default to v102 everywhere, instead of vt100, to synchronize - with agetty - ---- - src/util.c | 2 +- - units/serial-getty@.service.m4 | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -Index: systemd-44/src/util.c -=================================================================== ---- systemd-44.orig/src/util.c -+++ systemd-44/src/util.c -@@ -4425,7 +4425,7 @@ bool tty_is_vc_resolve(const char *tty) - const char *default_term_for_tty(const char *tty) { - assert(tty); - -- return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt100"; -+ return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt102"; - } - - bool dirent_is_file(const struct dirent *de) { -Index: systemd-44/units/serial-getty@.service.m4 -=================================================================== ---- systemd-44.orig/units/serial-getty@.service.m4 -+++ systemd-44/units/serial-getty@.service.m4 -@@ -35,7 +35,7 @@ Before=getty.target - IgnoreOnIsolate=yes - - [Service] --Environment=TERM=vt100 -+Environment=TERM=vt102 - ExecStart=-/sbin/agetty -s %I 115200,38400,9600 - Restart=always - RestartSec=0 diff --git a/crypt-loop-file.patch b/crypt-loop-file.patch index 317bec7..7078552 100644 --- a/crypt-loop-file.patch +++ b/crypt-loop-file.patch @@ -1,8 +1,8 @@ -Index: systemd-37/src/cryptsetup/cryptsetup-generator.c +Index: systemd-190/src/cryptsetup/cryptsetup-generator.c =================================================================== ---- systemd-37.orig/src/cryptsetup/cryptsetup-generator.c -+++ systemd-37/src/cryptsetup/cryptsetup-generator.c -@@ -138,7 +138,7 @@ static int create_disk( +--- systemd-190.orig/src/cryptsetup/cryptsetup-generator.c ++++ systemd-190/src/cryptsetup/cryptsetup-generator.c +@@ -136,7 +136,7 @@ static int create_disk( const char *password, const char *options) { @@ -11,62 +11,64 @@ Index: systemd-37/src/cryptsetup/cryptsetup-generator.c int r; FILE *f = NULL; bool noauto, nofail; -@@ -167,10 +167,50 @@ static int create_disk( +@@ -168,11 +168,51 @@ static int create_disk( goto fail; } -- if (!(d = unit_name_from_path(u, ".device"))) { +- d = unit_name_from_path(u, ".device"); +- if (!d) { - r = -ENOMEM; - log_error("Failed to allocate device name."); - goto fail; + if (!startswith(device,"/dev/")) { ++ d = unit_name_from_path_instance("cryptsetup", name, ".path"); ++ if (!d) { ++ r = -ENOMEM; ++ log_error("Failed to allocate path name."); ++ goto fail; ++ } + -+ if (!(d = unit_name_build_escape("cryptsetup", name, ".path"))) { -+ r = -ENOMEM; -+ log_error("Failed to allocate path name."); -+ goto fail; -+ } ++ if (asprintf(&path_file, "%s/%s", arg_dest, d) < 0) { ++ r = -ENOMEM; ++ log_error("Failed to allocate unit file name."); ++ goto fail; ++ } + -+ if (asprintf(&path_file, "%s/%s", arg_dest, d) < 0) { -+ r = -ENOMEM; -+ log_error("Failed to allocate unit file name."); -+ goto fail; -+ } ++ f = fopen(path_file, "wxe"); ++ if (!f) { ++ r = -errno; ++ log_error("Failed to create unit file: %m"); ++ goto fail; ++ } + -+ if (!(f = fopen(path_file, "wxe"))) { -+ r = -errno; -+ log_error("Failed to create unit file: %m"); -+ goto fail; -+ } ++ fprintf(f, ++ "[Unit]\n" ++ "Description=Cryptography Setup for %s\n" ++ "DefaultDependencies=no\n" ++ "[Path]\n" ++ "PathExists=%s\n", ++ device, device); + -+ fprintf(f, -+ "[Unit]\n" -+ "Description=Cryptography Setup for %s\n" -+ "DefaultDependencies=no\n" -+ "[Path]\n" -+ "PathExists=%s\n", -+ device, device); ++ fflush(f); + -+ fflush(f); ++ if (ferror(f)) { ++ r = -errno; ++ log_error("Failed to write file: %m"); ++ goto fail; ++ } + -+ if (ferror(f)) { -+ r = -errno; -+ log_error("Failed to write file: %m"); -+ goto fail; -+ } -+ -+ f = NULL; ++ f = NULL; + } else { -+ -+ if (!(d = unit_name_from_path(u, ".device"))) { -+ r = -ENOMEM; -+ log_error("Failed to allocate device name."); -+ goto fail; -+ } ++ d = unit_name_from_path(u, ".device"); ++ if (!d) { ++ r = -ENOMEM; ++ log_error("Failed to allocate device name."); ++ goto fail; ++ } } - if (!(f = fopen(p, "wxe"))) { -@@ -300,6 +340,7 @@ fail: + f = fopen(p, "wxe"); +@@ -298,6 +338,7 @@ fail: free(n); free(d); free(e); diff --git a/delay-fsck-cryptsetup-after-md-lvm-dmraid.patch b/delay-fsck-cryptsetup-after-md-lvm-dmraid.patch index 52d4c46..58a4f92 100644 --- a/delay-fsck-cryptsetup-after-md-lvm-dmraid.patch +++ b/delay-fsck-cryptsetup-after-md-lvm-dmraid.patch @@ -8,26 +8,26 @@ Subject: [PATCH] delay fsck / cryptsetup after md / dmraid / lvm are started units/fsck@.service.in | 2 +- 2 files changed, 2 insertions(+), 1 deletions(-) -Index: systemd-37/src/cryptsetup/cryptsetup-generator.c +Index: systemd-189/src/cryptsetup/cryptsetup-generator.c =================================================================== ---- systemd-37.orig/src/cryptsetup/cryptsetup-generator.c -+++ systemd-37/src/cryptsetup/cryptsetup-generator.c -@@ -112,6 +112,7 @@ static int create_disk( +--- systemd-189.orig/src/cryptsetup/cryptsetup-generator.c ++++ systemd-189/src/cryptsetup/cryptsetup-generator.c +@@ -192,6 +192,7 @@ static int create_disk( "DefaultDependencies=no\n" - "BindTo=%s dev-mapper-%%i.device\n" + "BindsTo=%s dev-mapper-%%i.device\n" "After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n" + "After=md.service dmraid.service lvm.service\n" "Before=umount.target\n", d, d); -Index: systemd-37/units/fsck@.service.in +Index: systemd-189/units/systemd-fsck@.service.in =================================================================== ---- systemd-37.orig/units/fsck@.service.in -+++ systemd-37/units/fsck@.service.in -@@ -9,7 +9,7 @@ - Description=File System Check on %f +--- systemd-189.orig/units/systemd-fsck@.service.in ++++ systemd-189/units/systemd-fsck@.service.in +@@ -10,7 +10,7 @@ Description=File System Check on %f + Documentation=man:systemd-fsck@.service(8) DefaultDependencies=no - BindTo=%i.device + BindsTo=%i.device -After=systemd-readahead-collect.service systemd-readahead-replay.service %i.device +After=systemd-readahead-collect.service systemd-readahead-replay.service %i.device lvm.service md.service dmraid.service Before=shutdown.target diff --git a/dm-lvm-after-local-fs-pre-target.patch b/dm-lvm-after-local-fs-pre-target.patch index 2e4c046..d3467af 100644 --- a/dm-lvm-after-local-fs-pre-target.patch +++ b/dm-lvm-after-local-fs-pre-target.patch @@ -1,9 +1,9 @@ -Index: systemd-37/units/local-fs-pre.target +Index: systemd-189/units/local-fs-pre.target =================================================================== ---- systemd-37.orig/units/local-fs-pre.target -+++ systemd-37/units/local-fs-pre.target -@@ -9,3 +9,4 @@ - +--- systemd-189.orig/units/local-fs-pre.target ++++ systemd-189/units/local-fs-pre.target +@@ -8,3 +8,4 @@ [Unit] Description=Local File Systems (Pre) + Documentation=man:systemd.special(7) +After=md.service lvm.service dmraid.service diff --git a/drop-timezone.patch b/drop-timezone.patch deleted file mode 100644 index 0229807..0000000 --- a/drop-timezone.patch +++ /dev/null @@ -1,48 +0,0 @@ -Index: systemd-44/src/timedate/timedated.c -=================================================================== ---- systemd-44.orig/src/timedate/timedated.c -+++ systemd-44/src/timedate/timedated.c -@@ -203,24 +203,18 @@ static int read_data(void) { - - free(t); - -- r = read_one_line_file("/etc/timezone", &tz.zone); -- if (r < 0) { -- if (r != -ENOENT) -- log_warning("Failed to read /etc/timezone: %s", strerror(-r)); -- - #if defined(TARGET_FEDORA) || defined(TARGET_SUSE) -- r = parse_env_file("/etc/sysconfig/clock", NEWLINE, -+ r = parse_env_file("/etc/sysconfig/clock", NEWLINE, - #ifdef TARGET_FEDORA -- "ZONE", &tz.zone, -+ "ZONE", &tz.zone, - #else /* TARGET_SUSE */ -- "TIMEZONE", &tz.zone, -+ "TIMEZONE", &tz.zone, - #endif -- NULL); -+ NULL); - -- if (r < 0 && r != -ENOENT) -- log_warning("Failed to read /etc/sysconfig/clock: %s", strerror(-r)); -+ if (r < 0 && r != -ENOENT) -+ log_warning("Failed to read /etc/sysconfig/clock: %s", strerror(-r)); - #endif -- } - - have_timezone: - if (isempty(tz.zone)) { -@@ -263,12 +257,6 @@ static int write_data_timezone(void) { - if (r < 0) - return -errno; - -- if (stat("/etc/timezone", &st) == 0 && S_ISREG(st.st_mode)) { -- r = write_one_line_file_atomic("/etc/timezone", tz.zone); -- if (r < 0) -- return r; -- } -- - return 0; - } - diff --git a/fastboot-forcefsck.patch b/fastboot-forcefsck.patch index 4d76eb2..f0898e8 100644 --- a/fastboot-forcefsck.patch +++ b/fastboot-forcefsck.patch @@ -1,11 +1,11 @@ -Index: systemd-44/src/fsck.c +Index: systemd-189/src/fsck/fsck.c =================================================================== ---- systemd-44.orig/src/fsck.c -+++ systemd-44/src/fsck.c -@@ -127,7 +127,7 @@ static int parse_proc_cmdline(void) { +--- systemd-189.orig/src/fsck/fsck.c ++++ systemd-189/src/fsck/fsck.c +@@ -128,7 +128,7 @@ static int parse_proc_cmdline(void) { arg_skip = true; - else if (startswith(w, "fsck.mode")) - log_warning("Invalid fsck.mode= parameter. Ignoring."); + else if (startswith(w, "fsck")) + log_warning("Invalid fsck parameter. Ignoring."); -#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA) +#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA) || defined(TARGET_SUSE) else if (strneq(w, "fastboot", l)) diff --git a/fix-analyze-exception.patch b/fix-analyze-exception.patch deleted file mode 100644 index 0069985..0000000 --- a/fix-analyze-exception.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 6070fe66ac2f317e7e85e5685f0916d1e2b73a28 Mon Sep 17 00:00:00 2001 -From: Colin Guthrie -Date: Mon, 2 Apr 2012 11:08:20 +0100 -Subject: [PATCH] analyze: Cosmetic exit when the bootup is not yet complete - when plotting. - -This is just a nicer message than a python traceback. ---- - src/systemd-analyze | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/systemd-analyze b/src/systemd-analyze -index 8148bfb..a49fbb7 100755 ---- a/src/systemd-analyze -+++ b/src/systemd-analyze -@@ -31,6 +31,10 @@ def acquire_start_time(): - startup_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'StartupTimestampMonotonic')) - finish_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'FinishTimestampMonotonic')) - -+ if finish_time == 0: -+ sys.stderr.write("Bootup is not yet finished. Please try again later.\n") -+ sys.exit(1) -+ - assert initrd_time <= startup_time - assert startup_time <= finish_time - --- -1.7.10.4 - diff --git a/fix-dir-noatime-tmpfiles.patch b/fix-dir-noatime-tmpfiles.patch deleted file mode 100644 index 714ada2..0000000 --- a/fix-dir-noatime-tmpfiles.patch +++ /dev/null @@ -1,41 +0,0 @@ -From de49f6dd99aca059da24c9afc672782f1768abd2 Mon Sep 17 00:00:00 2001 -From: Kay Sievers -Date: Wed, 11 Apr 2012 21:33:12 +0200 -Subject: [PATCH] tmpfiles: open directories with O_NOATIME to preserve - timestamp - -Before: - # stat /tmp/pulse-Du5ectm60QYM | grep 'Access: 20' - Access: 2012-04-11 21:32:48.444920237 +0200 - # systemd-tmpfiles --clean - # stat /tmp/pulse-Du5ectm60QYM | grep 'Access: 20' - Access: 2012-04-11 21:36:27.628925459 +0200 - -After: - # stat /tmp/pulse-Du5ectm60QYM | grep 'Access: 20' - Access: 2012-04-11 21:32:48.444920237 +0200 - # ./systemd-tmpfiles --clean - # stat /tmp/pulse-Du5ectm60QYM | grep 'Access: 20' - Access: 2012-04-11 21:32:48.444920237 +0200 - -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=810257 ---- - src/tmpfiles.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/src/tmpfiles.c b/src/tmpfiles.c -index 21bf44d..09eefcf 100644 ---- a/src/tmpfiles.c -+++ b/src/tmpfiles.c -@@ -250,7 +250,7 @@ static int dir_cleanup( - DIR *sub_dir; - int q; - -- sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW); -+ sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME); - if (sub_dir == NULL) { - if (errno != ENOENT) { - log_error("opendir(%s/%s) failed: %m", p, dent->d_name); --- -1.7.7 - diff --git a/fix-enable-disable-boot-initscript.patch b/fix-enable-disable-boot-initscript.patch index 1f4fe5c..84efd6b 100644 --- a/fix-enable-disable-boot-initscript.patch +++ b/fix-enable-disable-boot-initscript.patch @@ -7,11 +7,11 @@ Subject: [PATCH] fix support for boot prefixed initscript (bnc#746506) src/systemctl.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) -diff --git a/src/systemctl.c b/src/systemctl.c -index e94e024..1a98599 100644 ---- a/src/systemctl.c -+++ b/src/systemctl.c -@@ -3669,7 +3669,27 @@ static int enable_sysv_units(char **args) { +Index: systemd-193/src/systemctl/systemctl.c +=================================================================== +--- systemd-193.orig/src/systemctl/systemctl.c ++++ systemd-193/src/systemctl/systemctl.c +@@ -3475,7 +3475,27 @@ static int enable_sysv_units(char **args if (!found_sysv) { free(p); @@ -39,6 +39,3 @@ index e94e024..1a98599 100644 } /* Mark this entry, so that we don't try enabling it as native unit */ --- -1.7.10.4 - diff --git a/fix-getty-isolate.patch b/fix-getty-isolate.patch deleted file mode 100644 index 4cf794a..0000000 --- a/fix-getty-isolate.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 4771148bb92ace55eaa6759a53d04a0f2de9b0d2 Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Wed, 11 Apr 2012 21:58:33 +0200 -Subject: [PATCH] units: exclude gettys from isolate requests - -gettys are nowadays mostly autospawned and hence usually subject to -being shut down on isolate requests, since they are no dependency of any -other unit. This is a bad idea if the user isolates between -multi-user.graphical and graphical.target, hence exclude them from the -isolation. - -This has the effect that gettys no longer cleaned up when -emergency.target is isolated, which might actualy be considered a -feature, even though it is a change from previous behaviour... - -Note that the one getty that really matters (the one on tty1) is still -removed when isolating to emergency.target since it conflicts with -emergency.service. ---- - TODO | 4 ++-- - units/getty@.service.m4 | 1 + - units/serial-getty@.service.m4 | 1 + - 3 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/units/getty@.service.m4 b/units/getty@.service.m4 -index a02838d..6b931fb 100644 ---- a/units/getty@.service.m4 -+++ b/units/getty@.service.m4 -@@ -32,6 +32,7 @@ After=rc-local.service - # sure that this is synchronized before getty.target, even though - # getty.target didn't actually pull it in. - Before=getty.target -+IgnoreOnIsolate=yes - - [Service] - Environment=TERM=linux -diff --git a/units/serial-getty@.service.m4 b/units/serial-getty@.service.m4 -index fc8b57b..d1d14d3 100644 ---- a/units/serial-getty@.service.m4 -+++ b/units/serial-getty@.service.m4 -@@ -32,6 +32,7 @@ After=rc-local.service - # sure that this is synchronized before getty.target, even though - # getty.target didn't actually pull it in. - Before=getty.target -+IgnoreOnIsolate=yes - - [Service] - Environment=TERM=vt100 --- -1.7.7 - diff --git a/fix-swap-priority.patch b/fix-swap-priority.patch deleted file mode 100644 index 2c3fd5f..0000000 --- a/fix-swap-priority.patch +++ /dev/null @@ -1,36 +0,0 @@ -Index: systemd-37/src/mount.c -=================================================================== ---- systemd-37.orig/src/mount.c -+++ systemd-37/src/mount.c -@@ -1485,7 +1485,7 @@ fail: - return r; - } - --static int mount_find_pri(char *options) { -+static int mount_find_pri(char *options, int *ret) { - char *end, *pri; - unsigned long r; - -@@ -1503,7 +1503,8 @@ static int mount_find_pri(char *options) - if (end == pri || (*end != ',' && *end != 0)) - return -EINVAL; - -- return (int) r; -+ *ret = (int) r; -+ return 1; - } - - static int mount_load_etc_fstab(Manager *m) { -@@ -1539,9 +1540,10 @@ static int mount_load_etc_fstab(Manager - path_kill_slashes(where); - - if (streq(me->mnt_type, "swap")) { -- int pri; -+ int r, pri = -1; - -- if ((pri = mount_find_pri(me->mnt_opts)) < 0) -+ r = mount_find_pri(me->mnt_opts,&pri); -+ if (r < 0) - k = pri; - else - k = swap_add_one(m, diff --git a/fix-tty-startup.patch b/fix-tty-startup.patch deleted file mode 100644 index 293839c..0000000 --- a/fix-tty-startup.patch +++ /dev/null @@ -1,40 +0,0 @@ -From d55248d6a6f69f3b6c86cfc0d11aff8831590a4f Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Thu, 12 Apr 2012 17:29:42 +0200 -Subject: [PATCH] getty: VC devices are always available, we don't need to - wait until they show up - ---- - src/99-systemd.rules.in | 1 - - units/getty@.service.m4 | 3 +-- - 2 files changed, 1 insertions(+), 3 deletions(-) - -diff --git a/src/99-systemd.rules.in b/src/99-systemd.rules.in -index d306f71..8cc7523 100644 ---- a/src/99-systemd.rules.in -+++ b/src/99-systemd.rules.in -@@ -7,7 +7,6 @@ - - ACTION=="remove", GOTO="systemd_end" - --SUBSYSTEM=="tty", KERNEL=="tty[0-9]|tty1[0-2]", TAG+="systemd" - SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*|xvc*|hvsi*", TAG+="systemd" - - KERNEL=="vport*", TAG+="systemd" -diff --git a/units/getty@.service.m4 b/units/getty@.service.m4 -index a02838d..c397a4d 100644 ---- a/units/getty@.service.m4 -+++ b/units/getty@.service.m4 -@@ -7,8 +7,7 @@ - - [Unit] - Description=Getty on %I --BindTo=dev-%i.device --After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service -+After=systemd-user-sessions.service plymouth-quit-wait.service - m4_ifdef(`TARGET_FEDORA', - After=rc-local.service - )m4_dnl --- -1.7.7 - diff --git a/fix-write-user-state-file.patch b/fix-write-user-state-file.patch deleted file mode 100644 index e0cd289..0000000 --- a/fix-write-user-state-file.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 0753f9b016f144a6ebe11cd8a2c377e5a0345443 Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Tue, 22 May 2012 16:46:11 +0200 -Subject: [PATCH] logind: fix write out of user state file - ---- - src/login/logind-user.c | 65 ++++++++++++++++++++++++++++++---------------- - 1 files changed, 42 insertions(+), 23 deletions(-) - -diff --git a/src/login/logind-user.c b/src/login/logind-user.c -index 717f0e2..b7f579c 100644 ---- a/src/login/logind-user.c -+++ b/src/login/logind-user.c -@@ -136,40 +136,59 @@ int user_save(User *u) { - - if (u->sessions) { - Session *i; -+ bool first; - - fputs("SESSIONS=", f); -+ first = true; - LIST_FOREACH(sessions_by_user, i, u->sessions) { -- fprintf(f, -- "%s%c", -- i->id, -- i->sessions_by_user_next ? ' ' : '\n'); -+ if (first) -+ first = false; -+ else -+ fputc(' ', f); -+ -+ fputs(i->id, f); - } - -- fputs("SEATS=", f); -+ fputs("\nSEATS=", f); -+ first = true; - LIST_FOREACH(sessions_by_user, i, u->sessions) { -- if (i->seat) -- fprintf(f, -- "%s%c", -- i->seat->id, -- i->sessions_by_user_next ? ' ' : '\n'); -+ if (!i->seat) -+ continue; -+ -+ if (first) -+ first = false; -+ else -+ fputc(' ', f); -+ -+ fputs(i->seat->id, f); - } - -- fputs("ACTIVE_SESSIONS=", f); -- LIST_FOREACH(sessions_by_user, i, u->sessions) -- if (session_is_active(i)) -- fprintf(f, -- "%lu%c", -- (unsigned long) i->user->uid, -- i->sessions_by_user_next ? ' ' : '\n'); -+ fputs("\nACTIVE_SESSIONS=", f); -+ first = true; -+ LIST_FOREACH(sessions_by_user, i, u->sessions) { -+ if (!session_is_active(i)) -+ continue; -+ -+ if (first) -+ first = false; -+ else -+ fputc(' ', f); -+ -+ fputs(i->id, f); -+ } - -- fputs("ACTIVE_SEATS=", f); -+ fputs("\nACTIVE_SEATS=", f); -+ first = true; - LIST_FOREACH(sessions_by_user, i, u->sessions) { -- if (session_is_active(i) && i->seat) -- fprintf(f, -- "%s%c", -- i->seat->id, -- i->sessions_by_user_next ? ' ' : '\n'); -+ if (!session_is_active(i) || !i->seat) -+ continue; -+ -+ if (first) -+ first = false; -+ else -+ fputs(i->seat->id, f); - } -+ fputc('\n', f); - } - - fflush(f); --- -1.7.7 - diff --git a/fixppc.patch b/fixppc.patch deleted file mode 100644 index eeb7ce5..0000000 --- a/fixppc.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 7264278fbbdc1dc6c30fedc902d1337594aa6ff6 Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Wed, 21 Mar 2012 23:47:44 +0100 -Subject: [PATCH] journal: PAGE_SIZE is not known on ppc and other archs - -Let's use NAME_MAX, as suggested by Dan Walsh ---- - src/journal/journald.c | 15 ++++++++++++--- - 1 files changed, 12 insertions(+), 3 deletions(-) - -diff --git a/src/journal/journald.c b/src/journal/journald.c -index d27cb60..87390bd 100644 ---- a/src/journal/journald.c -+++ b/src/journal/journald.c -@@ -29,7 +29,6 @@ - #include - #include - #include --#include - - #include - #include -@@ -2149,10 +2148,20 @@ static int process_event(Server *s, struct epoll_event *ev) { - size_t label_len = 0; - union { - struct cmsghdr cmsghdr; -+ -+ /* We use NAME_MAX space for the -+ * SELinux label here. The kernel -+ * currently enforces no limit, but -+ * according to suggestions from the -+ * SELinux people this will change and -+ * it will probably be identical to -+ * NAME_MAX. For now we use that, but -+ * this should be updated one day when -+ * the final limit is known.*/ - uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + - CMSG_SPACE(sizeof(struct timeval)) + -- CMSG_SPACE(sizeof(int)) + -- CMSG_SPACE(PAGE_SIZE)]; /* selinux label */ -+ CMSG_SPACE(sizeof(int)) + /* fd */ -+ CMSG_SPACE(NAME_MAX)]; /* selinux label */ - } control; - ssize_t n; - int v; --- -1.7.7 - -From dd1e3d5a396284d1afdb2828991a543eb80c8040 Mon Sep 17 00:00:00 2001 -From: Frederic Crozat -Date: Thu, 22 Mar 2012 09:39:54 +0100 -Subject: [PATCH] journal: char is unsigned on ppc, use int8_t instead. - ---- - src/journal/cat.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/src/journal/cat.c b/src/journal/cat.c -index 31d76f3..8a51fb7 100644 ---- a/src/journal/cat.c -+++ b/src/journal/cat.c -@@ -33,7 +33,7 @@ - #include "build.h" - - static char *arg_identifier = NULL; --static char arg_priority = LOG_INFO; -+static int8_t arg_priority = LOG_INFO; - static bool arg_level_prefix = true; - - static int help(void) { --- -1.7.7 - diff --git a/improve-restart-behaviour.patch b/improve-restart-behaviour.patch deleted file mode 100644 index 2852182..0000000 --- a/improve-restart-behaviour.patch +++ /dev/null @@ -1,7661 +0,0 @@ -From 4cbb803c2197b6be6be709a11911bde00f6853f6 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Wed, 28 Mar 2012 00:42:27 +0200 -Subject: [PATCH 01/30] job: fix loss of ordering with restart jobs - -Suppose that foo.service/start is a job waiting on other job bar.service/start -to finish. And then foo.service/restart is enqueued (not using ---ignore-dependencies). - -Currently this makes foo.service start immediately, forgetting about the -ordering to bar.service. - -The runnability check for JOB_RESTART jobs looks only at dependencies for -stopping. That's actually correct, because restart jobs should be treated the -same as stop jobs at first. The bug is that job_run_and_invalidate() does not -treat them exactly the same as stop jobs. unit_start() gets called without -checking for the runnability of the converted JOB_START job. - -The fix is to simplify the switch in job_run_and_invalidate(). Handle -JOB_RESTART identically to JOB_STOP. -Also simplify the handling of JOB_TRY_RESTART - just convert it to JOB_RESTART -if the unit is active and let it fall through to the JOB_RESTART case. -Similarly for JOB_RELOAD_OR_START - have a fall through to JOB_START. - -In job_finish_and_invalidate() it's not necessary to check for JOB_TRY_RESTART -with JOB_DONE, because JOB_TRY_RESTART jobs will have been converted to -JOB_RESTART already. - -Speeding up the restart of services in "auto-restart" state still works as -before. - -Improves: https://bugzilla.redhat.com/show_bug.cgi?id=753586 -but it's still not perfect. With this fix the try-restart action will wait for -the restart to complete in the right order, but the optimal behaviour would be -to finish quickly (without disturbing the start job). ---- - src/job.c | 64 ++++++++++++++++++++----------------------------------------- - 1 files changed, 21 insertions(+), 43 deletions(-) - -diff --git a/src/job.c b/src/job.c -index e57286f..d43ce8e 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -387,14 +387,21 @@ int job_run_and_invalidate(Job *j) { - - switch (j->type) { - -+ case JOB_RELOAD_OR_START: -+ if (unit_active_state(j->unit) == UNIT_ACTIVE) { -+ j->type = JOB_RELOAD; -+ r = unit_reload(j->unit); -+ break; -+ } -+ j->type = JOB_START; -+ /* fall through */ -+ - case JOB_START: - r = unit_start(j->unit); - -- /* If this unit cannot be started, then simply -- * wait */ -+ /* If this unit cannot be started, then simply wait */ - if (r == -EBADR) - r = 0; -- - break; - - case JOB_VERIFY_ACTIVE: { -@@ -408,11 +415,19 @@ int job_run_and_invalidate(Job *j) { - break; - } - -+ case JOB_TRY_RESTART: -+ if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(j->unit))) { -+ r = -ENOEXEC; -+ break; -+ } -+ j->type = JOB_RESTART; -+ /* fall through */ -+ - case JOB_STOP: -+ case JOB_RESTART: - r = unit_stop(j->unit); - -- /* If this unit cannot stopped, then simply -- * wait. */ -+ /* If this unit cannot stopped, then simply wait. */ - if (r == -EBADR) - r = 0; - break; -@@ -421,43 +436,6 @@ int job_run_and_invalidate(Job *j) { - r = unit_reload(j->unit); - break; - -- case JOB_RELOAD_OR_START: -- if (unit_active_state(j->unit) == UNIT_ACTIVE) { -- j->type = JOB_RELOAD; -- r = unit_reload(j->unit); -- } else { -- j->type = JOB_START; -- r = unit_start(j->unit); -- -- if (r == -EBADR) -- r = 0; -- } -- break; -- -- case JOB_RESTART: { -- UnitActiveState t = unit_active_state(j->unit); -- if (t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_ACTIVATING) { -- j->type = JOB_START; -- r = unit_start(j->unit); -- } else -- r = unit_stop(j->unit); -- break; -- } -- -- case JOB_TRY_RESTART: { -- UnitActiveState t = unit_active_state(j->unit); -- if (t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_DEACTIVATING) -- r = -ENOEXEC; -- else if (t == UNIT_ACTIVATING) { -- j->type = JOB_START; -- r = unit_start(j->unit); -- } else { -- j->type = JOB_RESTART; -- r = unit_stop(j->unit); -- } -- break; -- } -- - default: - assert_not_reached("Unknown job type"); - } -@@ -536,7 +514,7 @@ int job_finish_and_invalidate(Job *j, JobResult result) { - job_add_to_dbus_queue(j); - - /* Patch restart jobs so that they become normal start jobs */ -- if (result == JOB_DONE && (j->type == JOB_RESTART || j->type == JOB_TRY_RESTART)) { -+ if (result == JOB_DONE && j->type == JOB_RESTART) { - - log_debug("Converting job %s/%s -> %s/%s", - j->unit->id, job_type_to_string(j->type), --- -1.7.7 - - -From 8166db595346260a3e36206249f7e82bc9ad7406 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Wed, 28 Mar 2012 01:26:04 +0200 -Subject: [PATCH 02/30] job: add debug prints where job type gets changed - -Conflicts: - - src/job.c ---- - src/job.c | 14 +++++++++----- - 1 files changed, 9 insertions(+), 5 deletions(-) - -diff --git a/src/job.c b/src/job.c -index d43ce8e..6a4d8a7 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -355,6 +355,14 @@ bool job_is_runnable(Job *j) { - return true; - } - -+static void job_change_type(Job *j, JobType newtype) { -+ log_debug("Converting job %s/%s -> %s/%s", -+ j->unit->id, job_type_to_string(j->type), -+ j->unit->id, job_type_to_string(newtype)); -+ -+ j->type = newtype; -+} -+ - int job_run_and_invalidate(Job *j) { - int r; - uint32_t id; -@@ -516,12 +524,8 @@ int job_finish_and_invalidate(Job *j, JobResult result) { - /* Patch restart jobs so that they become normal start jobs */ - if (result == JOB_DONE && j->type == JOB_RESTART) { - -- log_debug("Converting job %s/%s -> %s/%s", -- j->unit->id, job_type_to_string(j->type), -- j->unit->id, job_type_to_string(JOB_START)); -- -+ job_change_type(j, JOB_START); - j->state = JOB_WAITING; -- j->type = JOB_START; - - job_add_to_run_queue(j); - --- -1.7.7 - - -From b0055c992aefe7512ad0f53d7c6e202d4db2bf53 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Thu, 5 Apr 2012 08:34:05 +0200 -Subject: [PATCH 03/30] job: use a lookup table for merging of job types - -It is easier to see what job_type_merge() is doing when the merging -rules are written in the form of a table. - -job_type_is_superset() contained redundant information. It can be -simplified to a simple rule: Type A is a superset of B iff merging A -with B gives A. - -Two job types are conflicting iff they are not mergeable. - -Make job_type_lookup_merge() the core function to decide the type -merging. All other job_type_*() are just short wrappers around it. -They can be inline. - -test-job-type gives the same results as before. -btw, the systemd binary is smaller by almost 1 KB. -(cherry picked from commit 348e27fedfd4cdd2238ff31a46785a70b9dc6fc0) ---- - src/job.c | 123 +++++++++++++++++------------------------------------------- - src/job.h | 29 ++++++++++++-- - 2 files changed, 60 insertions(+), 92 deletions(-) - -diff --git a/src/job.c b/src/job.c -index 6a4d8a7..da939fb 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -164,100 +164,47 @@ bool job_is_anchor(Job *j) { - return false; - } - --static bool types_match(JobType a, JobType b, JobType c, JobType d) { -- return -- (a == c && b == d) || -- (a == d && b == c); --} -- --int job_type_merge(JobType *a, JobType b) { -- if (*a == b) -- return 0; -- -- /* Merging is associative! a merged with b merged with c is -- * the same as a merged with c merged with b. */ -- -- /* Mergeability is transitive! if a can be merged with b and b -- * with c then a also with c */ -- -- /* Also, if a merged with b cannot be merged with c, then -- * either a or b cannot be merged with c either */ -- -- if (types_match(*a, b, JOB_START, JOB_VERIFY_ACTIVE)) -- *a = JOB_START; -- else if (types_match(*a, b, JOB_START, JOB_RELOAD) || -- types_match(*a, b, JOB_START, JOB_RELOAD_OR_START) || -- types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD_OR_START) || -- types_match(*a, b, JOB_RELOAD, JOB_RELOAD_OR_START)) -- *a = JOB_RELOAD_OR_START; -- else if (types_match(*a, b, JOB_START, JOB_RESTART) || -- types_match(*a, b, JOB_START, JOB_TRY_RESTART) || -- types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RESTART) || -- types_match(*a, b, JOB_RELOAD, JOB_RESTART) || -- types_match(*a, b, JOB_RELOAD_OR_START, JOB_RESTART) || -- types_match(*a, b, JOB_RELOAD_OR_START, JOB_TRY_RESTART) || -- types_match(*a, b, JOB_RESTART, JOB_TRY_RESTART)) -- *a = JOB_RESTART; -- else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD)) -- *a = JOB_RELOAD; -- else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_TRY_RESTART) || -- types_match(*a, b, JOB_RELOAD, JOB_TRY_RESTART)) -- *a = JOB_TRY_RESTART; -- else -- return -EEXIST; -- -- return 0; --} -- --bool job_type_is_mergeable(JobType a, JobType b) { -- return job_type_merge(&a, b) >= 0; --} -- --bool job_type_is_superset(JobType a, JobType b) { -+/* -+ * Merging is commutative, so imagine the matrix as symmetric. We store only -+ * its lower triangle to avoid duplication. We don't store the main diagonal, -+ * because A merged with A is simply A. -+ * -+ * Merging is associative! A merged with B merged with C is the same as -+ * A merged with C merged with B. -+ * -+ * Mergeability is transitive! If A can be merged with B and B with C then -+ * A also with C. -+ * -+ * Also, if A merged with B cannot be merged with C, then either A or B cannot -+ * be merged with C either. -+ */ -+static const JobType job_merging_table[] = { -+/* What \ With * JOB_START JOB_VERIFY_ACTIVE JOB_STOP JOB_RELOAD JOB_RELOAD_OR_START JOB_RESTART JOB_TRY_RESTART */ -+/************************************************************************************************************************************/ -+/*JOB_START */ -+/*JOB_VERIFY_ACTIVE */ JOB_START, -+/*JOB_STOP */ -1, -1, -+/*JOB_RELOAD */ JOB_RELOAD_OR_START, JOB_RELOAD, -1, -+/*JOB_RELOAD_OR_START*/ JOB_RELOAD_OR_START, JOB_RELOAD_OR_START, -1, JOB_RELOAD_OR_START, -+/*JOB_RESTART */ JOB_RESTART, JOB_RESTART, -1, JOB_RESTART, JOB_RESTART, -+/*JOB_TRY_RESTART */ JOB_RESTART, JOB_TRY_RESTART, -1, JOB_TRY_RESTART, JOB_RESTART, JOB_RESTART, -+}; - -- /* Checks whether operation a is a "superset" of b in its -- * actions */ -+JobType job_type_lookup_merge(JobType a, JobType b) { -+ assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX * (_JOB_TYPE_MAX - 1) / 2); -+ assert(a >= 0 && a < _JOB_TYPE_MAX); -+ assert(b >= 0 && b < _JOB_TYPE_MAX); - - if (a == b) -- return true; -- -- switch (a) { -- case JOB_START: -- return b == JOB_VERIFY_ACTIVE; -- -- case JOB_RELOAD: -- return -- b == JOB_VERIFY_ACTIVE; -- -- case JOB_RELOAD_OR_START: -- return -- b == JOB_RELOAD || -- b == JOB_START || -- b == JOB_VERIFY_ACTIVE; -- -- case JOB_RESTART: -- return -- b == JOB_START || -- b == JOB_VERIFY_ACTIVE || -- b == JOB_RELOAD || -- b == JOB_RELOAD_OR_START || -- b == JOB_TRY_RESTART; -- -- case JOB_TRY_RESTART: -- return -- b == JOB_VERIFY_ACTIVE || -- b == JOB_RELOAD; -- default: -- return false; -+ return a; - -+ if (a < b) { -+ JobType tmp = a; -+ a = b; -+ b = tmp; - } --} -- --bool job_type_is_conflicting(JobType a, JobType b) { -- assert(a >= 0 && a < _JOB_TYPE_MAX); -- assert(b >= 0 && b < _JOB_TYPE_MAX); - -- return (a == JOB_STOP) != (b == JOB_STOP); -+ return job_merging_table[(a - 1) * a / 2 + b]; - } - - bool job_type_is_redundant(JobType a, UnitActiveState b) { -diff --git a/src/job.h b/src/job.h -index 2121426..60a43e0 100644 ---- a/src/job.h -+++ b/src/job.h -@@ -24,6 +24,7 @@ - - #include - #include -+#include - - typedef struct Job Job; - typedef struct JobDependency JobDependency; -@@ -37,6 +38,7 @@ typedef enum JobResult JobResult; - #include "hashmap.h" - #include "list.h" - -+/* Be careful when changing the job types! Adjust job_merging_table[] accordingly! */ - enum JobType { - JOB_START, /* if a unit does not support being started, we'll just wait until it becomes active */ - JOB_VERIFY_ACTIVE, -@@ -145,10 +147,29 @@ bool job_is_anchor(Job *j); - - int job_merge(Job *j, Job *other); - --int job_type_merge(JobType *a, JobType b); --bool job_type_is_mergeable(JobType a, JobType b); --bool job_type_is_superset(JobType a, JobType b); --bool job_type_is_conflicting(JobType a, JobType b); -+JobType job_type_lookup_merge(JobType a, JobType b); -+ -+static inline int job_type_merge(JobType *a, JobType b) { -+ JobType t = job_type_lookup_merge(*a, b); -+ if (t < 0) -+ return -EEXIST; -+ *a = t; -+ return 0; -+} -+ -+static inline bool job_type_is_mergeable(JobType a, JobType b) { -+ return job_type_lookup_merge(a, b) >= 0; -+} -+ -+static inline bool job_type_is_conflicting(JobType a, JobType b) { -+ return !job_type_is_mergeable(a, b); -+} -+ -+static inline bool job_type_is_superset(JobType a, JobType b) { -+ /* Checks whether operation a is a "superset" of b in its actions */ -+ return a == job_type_lookup_merge(a, b); -+} -+ - bool job_type_is_redundant(JobType a, UnitActiveState b); - - bool job_is_runnable(Job *j); --- -1.7.7 - - -From 5503c3419fbcceebb6f8e94c291457adb260537b Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Thu, 19 Apr 2012 23:20:34 +0200 -Subject: [PATCH 04/30] job: allow job_free() only on already unlinked jobs - -job_free() is IMO too helpful when it unlinks the job from the transaction. -The callers should ensure the job is already unlinked before freeing. -The added assertions check if anyone gets it wrong. -(cherry picked from commit 02a3bcc6b4372ca50c0a62b193f9a75b988ffa69) ---- - src/job.c | 6 ++++-- - src/manager.c | 11 ++++++++--- - src/manager.h | 2 -- - 3 files changed, 12 insertions(+), 7 deletions(-) - -diff --git a/src/job.c b/src/job.c -index da939fb..8e4d93e 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -71,8 +71,10 @@ void job_free(Job *j) { - j->installed = false; - } - -- /* Detach from next 'smaller' objects */ -- manager_transaction_unlink_job(j->manager, j, true); -+ assert(!j->transaction_prev); -+ assert(!j->transaction_next); -+ assert(!j->subject_list); -+ assert(!j->object_list); - - if (j->in_run_queue) - LIST_REMOVE(Job, run_queue, j->manager->run_queue, j); -diff --git a/src/manager.c b/src/manager.c -index 74bd740..c77b5d2 100644 ---- a/src/manager.c -+++ b/src/manager.c -@@ -637,13 +637,15 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { - return r; - } - -+static void transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies); -+ - static void transaction_delete_job(Manager *m, Job *j, bool delete_dependencies) { - assert(m); - assert(j); - - /* Deletes one job from the transaction */ - -- manager_transaction_unlink_job(m, j, delete_dependencies); -+ transaction_unlink_job(m, j, delete_dependencies); - - if (!j->installed) - job_free(j); -@@ -685,8 +687,10 @@ static void transaction_abort(Manager *m) { - while ((j = hashmap_first(m->transaction_jobs))) - if (j->installed) - transaction_delete_job(m, j, true); -- else -+ else { -+ transaction_unlink_job(m, j, true); - job_free(j); -+ } - - assert(hashmap_isempty(m->transaction_jobs)); - -@@ -1415,6 +1419,7 @@ static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool o - LIST_PREPEND(Job, transaction, f, j); - - if (hashmap_replace(m->transaction_jobs, unit, f) < 0) { -+ LIST_REMOVE(Job, transaction, f, j); - job_free(j); - return NULL; - } -@@ -1427,7 +1432,7 @@ static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool o - return j; - } - --void manager_transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies) { -+static void transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies) { - assert(m); - assert(j); - -diff --git a/src/manager.h b/src/manager.h -index a9d08f0..64d8d0e 100644 ---- a/src/manager.h -+++ b/src/manager.h -@@ -254,8 +254,6 @@ int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode - void manager_dump_units(Manager *s, FILE *f, const char *prefix); - void manager_dump_jobs(Manager *s, FILE *f, const char *prefix); - --void manager_transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies); -- - void manager_clear_jobs(Manager *m); - - unsigned manager_dispatch_load_queue(Manager *m); --- -1.7.7 - - -From c2c46edd09f2d0eefc127d22fd38312bf2bed01a Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Thu, 19 Apr 2012 23:23:04 +0200 -Subject: [PATCH 05/30] manager: simplify transaction_abort() - -This is equivalent. -(cherry picked from commit 121b3b318042b7fd67ac96601971c1c2f9b77be5) ---- - src/manager.c | 7 +------ - 1 files changed, 1 insertions(+), 6 deletions(-) - -diff --git a/src/manager.c b/src/manager.c -index c77b5d2..cac1fe8 100644 ---- a/src/manager.c -+++ b/src/manager.c -@@ -685,12 +685,7 @@ static void transaction_abort(Manager *m) { - assert(m); - - while ((j = hashmap_first(m->transaction_jobs))) -- if (j->installed) -- transaction_delete_job(m, j, true); -- else { -- transaction_unlink_job(m, j, true); -- job_free(j); -- } -+ transaction_delete_job(m, j, true); - - assert(hashmap_isempty(m->transaction_jobs)); - --- -1.7.7 - - -From 4eb87c1148bd48b5d121297f72aa47eb39482ad3 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Fri, 20 Apr 2012 10:21:37 +0200 -Subject: [PATCH 06/30] job: job_uninstall() - -Split the uninstallation of the job from job_free() into a separate function. -Adjust the callers. - -job_free() now only works on unlinked and uninstalled jobs. This enforces clear -thinking about job lifetimes. -(cherry picked from commit 97e7d748d1bf26790fc3b2607885f4ac8c4ecf3a) ---- - src/job.c | 25 ++++++++++++++----------- - src/job.h | 1 + - src/manager.c | 8 ++++++-- - src/unit.c | 7 +++++-- - 4 files changed, 26 insertions(+), 15 deletions(-) - -diff --git a/src/job.c b/src/job.c -index 8e4d93e..35e358d 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -55,22 +55,24 @@ Job* job_new(Manager *m, JobType type, Unit *unit) { - return j; - } - --void job_free(Job *j) { -- assert(j); -- -+void job_uninstall(Job *j) { -+ assert(j->installed); - /* Detach from next 'bigger' objects */ -- if (j->installed) { -- bus_job_send_removed_signal(j); - -- if (j->unit->job == j) { -- j->unit->job = NULL; -- unit_add_to_gc_queue(j->unit); -- } -+ bus_job_send_removed_signal(j); - -- hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id)); -- j->installed = false; -+ if (j->unit->job == j) { -+ j->unit->job = NULL; -+ unit_add_to_gc_queue(j->unit); - } - -+ hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id)); -+ j->installed = false; -+} -+ -+void job_free(Job *j) { -+ assert(j); -+ assert(!j->installed); - assert(!j->transaction_prev); - assert(!j->transaction_next); - assert(!j->subject_list); -@@ -491,6 +493,7 @@ int job_finish_and_invalidate(Job *j, JobResult result) { - - u = j->unit; - t = j->type; -+ job_uninstall(j); - job_free(j); - - job_print_status_message(u, t, result); -diff --git a/src/job.h b/src/job.h -index 60a43e0..ed375fa 100644 ---- a/src/job.h -+++ b/src/job.h -@@ -137,6 +137,7 @@ struct Job { - }; - - Job* job_new(Manager *m, JobType type, Unit *unit); -+void job_uninstall(Job *j); - void job_free(Job *job); - void job_dump(Job *j, FILE*f, const char *prefix); - -diff --git a/src/manager.c b/src/manager.c -index cac1fe8..f8e5d64 100644 ---- a/src/manager.c -+++ b/src/manager.c -@@ -1249,13 +1249,17 @@ static int transaction_apply(Manager *m, JobMode mode) { - } - - while ((j = hashmap_steal_first(m->transaction_jobs))) { -+ Job *uj; - if (j->installed) { - /* log_debug("Skipping already installed job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); */ - continue; - } - -- if (j->unit->job) -- job_free(j->unit->job); -+ uj = j->unit->job; -+ if (uj) { -+ job_uninstall(uj); -+ job_free(uj); -+ } - - j->unit->job = j; - j->installed = true; -diff --git a/src/unit.c b/src/unit.c -index 9e33701..1949995 100644 ---- a/src/unit.c -+++ b/src/unit.c -@@ -352,8 +352,11 @@ void unit_free(Unit *u) { - SET_FOREACH(t, u->names, i) - hashmap_remove_value(u->manager->units, t, u); - -- if (u->job) -- job_free(u->job); -+ if (u->job) { -+ Job *j = u->job; -+ job_uninstall(j); -+ job_free(j); -+ } - - for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) - bidi_set_free(u, u->dependencies[d]); --- -1.7.7 - - -From b95d521e3816800bf43d5e11cef58b69b360233d Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Fri, 20 Apr 2012 10:22:07 +0200 -Subject: [PATCH 07/30] manager: Transaction as an object - -This makes it obvious that transactions are short-lived. They are created in -manager_add_job() and destroyed after the application of jobs. -It also prepares for a split of the transaction code to a new source. -(cherry picked from commit 7527cb527598aaabf0ed9b38a352edb28536392a) ---- - src/job.c | 8 +- - src/job.h | 4 +- - src/manager.c | 390 +++++++++++++++++++++++++++++++-------------------------- - src/manager.h | 11 +- - 4 files changed, 225 insertions(+), 188 deletions(-) - -diff --git a/src/job.c b/src/job.c -index 35e358d..6d48748 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -97,7 +97,7 @@ void job_free(Job *j) { - free(j); - } - --JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) { -+JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts, Transaction *tr) { - JobDependency *l; - - assert(object); -@@ -118,20 +118,20 @@ JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool - if (subject) - LIST_PREPEND(JobDependency, subject, subject->subject_list, l); - else -- LIST_PREPEND(JobDependency, subject, object->manager->transaction_anchor, l); -+ LIST_PREPEND(JobDependency, subject, tr->anchor, l); - - LIST_PREPEND(JobDependency, object, object->object_list, l); - - return l; - } - --void job_dependency_free(JobDependency *l) { -+void job_dependency_free(JobDependency *l, Transaction *tr) { - assert(l); - - if (l->subject) - LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l); - else -- LIST_REMOVE(JobDependency, subject, l->object->manager->transaction_anchor, l); -+ LIST_REMOVE(JobDependency, subject, tr->anchor, l); - - LIST_REMOVE(JobDependency, object, l->object->object_list, l); - -diff --git a/src/job.h b/src/job.h -index ed375fa..18ba64f 100644 ---- a/src/job.h -+++ b/src/job.h -@@ -141,8 +141,8 @@ void job_uninstall(Job *j); - void job_free(Job *job); - void job_dump(Job *j, FILE*f, const char *prefix); - --JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts); --void job_dependency_free(JobDependency *l); -+JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts, Transaction *tr); -+void job_dependency_free(JobDependency *l, Transaction *tr); - - bool job_is_anchor(Job *j); - -diff --git a/src/manager.c b/src/manager.c -index f8e5d64..ff4249d 100644 ---- a/src/manager.c -+++ b/src/manager.c -@@ -259,9 +259,6 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) { - if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func))) - goto fail; - -- if (!(m->transaction_jobs = hashmap_new(trivial_hash_func, trivial_compare_func))) -- goto fail; -- - if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func))) - goto fail; - -@@ -429,14 +426,10 @@ static unsigned manager_dispatch_gc_queue(Manager *m) { - } - - static void manager_clear_jobs_and_units(Manager *m) { -- Job *j; - Unit *u; - - assert(m); - -- while ((j = hashmap_first(m->transaction_jobs))) -- job_free(j); -- - while ((u = hashmap_first(m->units))) - unit_free(u); - -@@ -449,7 +442,6 @@ static void manager_clear_jobs_and_units(Manager *m) { - assert(!m->cleanup_queue); - assert(!m->gc_queue); - -- assert(hashmap_isempty(m->transaction_jobs)); - assert(hashmap_isempty(m->jobs)); - assert(hashmap_isempty(m->units)); - } -@@ -475,7 +467,6 @@ void manager_free(Manager *m) { - - hashmap_free(m->units); - hashmap_free(m->jobs); -- hashmap_free(m->transaction_jobs); - hashmap_free(m->watch_pids); - hashmap_free(m->watch_bus); - -@@ -637,65 +628,47 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { - return r; - } - --static void transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies); -+static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies); - --static void transaction_delete_job(Manager *m, Job *j, bool delete_dependencies) { -- assert(m); -+static void transaction_delete_job(Transaction *tr, Job *j, bool delete_dependencies) { -+ assert(tr); - assert(j); - - /* Deletes one job from the transaction */ - -- transaction_unlink_job(m, j, delete_dependencies); -+ transaction_unlink_job(tr, j, delete_dependencies); - - if (!j->installed) - job_free(j); - } - --static void transaction_delete_unit(Manager *m, Unit *u) { -+static void transaction_delete_unit(Transaction *tr, Unit *u) { - Job *j; - - /* Deletes all jobs associated with a certain unit from the - * transaction */ - -- while ((j = hashmap_get(m->transaction_jobs, u))) -- transaction_delete_job(m, j, true); --} -- --static void transaction_clean_dependencies(Manager *m) { -- Iterator i; -- Job *j; -- -- assert(m); -- -- /* Drops all dependencies of all installed jobs */ -- -- HASHMAP_FOREACH(j, m->jobs, i) { -- while (j->subject_list) -- job_dependency_free(j->subject_list); -- while (j->object_list) -- job_dependency_free(j->object_list); -- } -- -- assert(!m->transaction_anchor); -+ while ((j = hashmap_get(tr->jobs, u))) -+ transaction_delete_job(tr, j, true); - } - --static void transaction_abort(Manager *m) { -+static void transaction_abort(Transaction *tr) { - Job *j; - -- assert(m); -+ assert(tr); - -- while ((j = hashmap_first(m->transaction_jobs))) -- transaction_delete_job(m, j, true); -+ while ((j = hashmap_first(tr->jobs))) -+ transaction_delete_job(tr, j, true); - -- assert(hashmap_isempty(m->transaction_jobs)); -+ assert(hashmap_isempty(tr->jobs)); - -- transaction_clean_dependencies(m); -+ assert(!tr->anchor); - } - --static void transaction_find_jobs_that_matter_to_anchor(Manager *m, Job *j, unsigned generation) { -+static void transaction_find_jobs_that_matter_to_anchor(Transaction *tr, Job *j, unsigned generation) { - JobDependency *l; - -- assert(m); -+ assert(tr); - - /* A recursive sweep through the graph that marks all units - * that matter to the anchor job, i.e. are directly or -@@ -705,7 +678,7 @@ static void transaction_find_jobs_that_matter_to_anchor(Manager *m, Job *j, unsi - if (j) - l = j->subject_list; - else -- l = m->transaction_anchor; -+ l = tr->anchor; - - LIST_FOREACH(subject, l, l) { - -@@ -720,11 +693,11 @@ static void transaction_find_jobs_that_matter_to_anchor(Manager *m, Job *j, unsi - l->object->matters_to_anchor = true; - l->object->generation = generation; - -- transaction_find_jobs_that_matter_to_anchor(m, l->object, generation); -+ transaction_find_jobs_that_matter_to_anchor(tr, l->object, generation); - } - } - --static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, JobType t) { -+static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other, JobType t) { - JobDependency *l, *last; - - assert(j); -@@ -775,7 +748,7 @@ static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, Job - /* Kill the other job */ - other->subject_list = NULL; - other->object_list = NULL; -- transaction_delete_job(m, other, true); -+ transaction_delete_job(tr, other, true); - } - static bool job_is_conflicted_by(Job *j) { - JobDependency *l; -@@ -792,7 +765,7 @@ static bool job_is_conflicted_by(Job *j) { - return false; - } - --static int delete_one_unmergeable_job(Manager *m, Job *j) { -+static int delete_one_unmergeable_job(Transaction *tr, Job *j) { - Job *k; - - assert(j); -@@ -853,23 +826,23 @@ static int delete_one_unmergeable_job(Manager *m, Job *j) { - - /* Ok, we can drop one, so let's do so. */ - log_debug("Fixing conflicting jobs by deleting job %s/%s", d->unit->id, job_type_to_string(d->type)); -- transaction_delete_job(m, d, true); -+ transaction_delete_job(tr, d, true); - return 0; - } - - return -EINVAL; - } - --static int transaction_merge_jobs(Manager *m, DBusError *e) { -+static int transaction_merge_jobs(Transaction *tr, DBusError *e) { - Job *j; - Iterator i; - int r; - -- assert(m); -+ assert(tr); - - /* First step, check whether any of the jobs for one specific - * task conflict. If so, try to drop one of them. */ -- HASHMAP_FOREACH(j, m->transaction_jobs, i) { -+ HASHMAP_FOREACH(j, tr->jobs, i) { - JobType t; - Job *k; - -@@ -882,7 +855,8 @@ static int transaction_merge_jobs(Manager *m, DBusError *e) { - * action. Let's see if we can get rid of one - * of them */ - -- if ((r = delete_one_unmergeable_job(m, j)) >= 0) -+ r = delete_one_unmergeable_job(tr, j); -+ if (r >= 0) - /* Ok, we managed to drop one, now - * let's ask our callers to call us - * again after garbage collecting */ -@@ -896,7 +870,7 @@ static int transaction_merge_jobs(Manager *m, DBusError *e) { - } - - /* Second step, merge the jobs. */ -- HASHMAP_FOREACH(j, m->transaction_jobs, i) { -+ HASHMAP_FOREACH(j, tr->jobs, i) { - JobType t = j->type; - Job *k; - -@@ -910,14 +884,14 @@ static int transaction_merge_jobs(Manager *m, DBusError *e) { - - while ((k = j->transaction_next)) { - if (j->installed) { -- transaction_merge_and_delete_job(m, k, j, t); -+ transaction_merge_and_delete_job(tr, k, j, t); - j = k; - } else -- transaction_merge_and_delete_job(m, j, k, t); -+ transaction_merge_and_delete_job(tr, j, k, t); - } - - if (j->unit->job && !j->installed) -- transaction_merge_and_delete_job(m, j, j->unit->job, t); -+ transaction_merge_and_delete_job(tr, j, j->unit->job, t); - - assert(!j->transaction_next); - assert(!j->transaction_prev); -@@ -926,10 +900,10 @@ static int transaction_merge_jobs(Manager *m, DBusError *e) { - return 0; - } - --static void transaction_drop_redundant(Manager *m) { -+static void transaction_drop_redundant(Transaction *tr) { - bool again; - -- assert(m); -+ assert(tr); - - /* Goes through the transaction and removes all jobs that are - * a noop */ -@@ -940,7 +914,7 @@ static void transaction_drop_redundant(Manager *m) { - - again = false; - -- HASHMAP_FOREACH(j, m->transaction_jobs, i) { -+ HASHMAP_FOREACH(j, tr->jobs, i) { - bool changes_something = false; - Job *k; - -@@ -959,7 +933,7 @@ static void transaction_drop_redundant(Manager *m) { - continue; - - /* log_debug("Found redundant job %s/%s, dropping.", j->unit->id, job_type_to_string(j->type)); */ -- transaction_delete_job(m, j, false); -+ transaction_delete_job(tr, j, false); - again = true; - break; - } -@@ -981,12 +955,12 @@ static bool unit_matters_to_anchor(Unit *u, Job *j) { - return false; - } - --static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned generation, DBusError *e) { -+static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, DBusError *e) { - Iterator i; - Unit *u; - int r; - -- assert(m); -+ assert(tr); - assert(j); - assert(!j->transaction_prev); - -@@ -1033,7 +1007,7 @@ static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned - - if (delete) { - log_warning("Breaking ordering cycle by deleting job %s/%s", delete->unit->id, job_type_to_string(delete->type)); -- transaction_delete_unit(m, delete->unit); -+ transaction_delete_unit(tr, delete->unit); - return -EAGAIN; - } - -@@ -1056,15 +1030,18 @@ static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned - Job *o; - - /* Is there a job for this unit? */ -- if (!(o = hashmap_get(m->transaction_jobs, u))) -- -+ o = hashmap_get(tr->jobs, u); -+ if (!o) { - /* Ok, there is no job for this in the - * transaction, but maybe there is already one - * running? */ -- if (!(o = u->job)) -+ o = u->job; -+ if (!o) - continue; -+ } - -- if ((r = transaction_verify_order_one(m, o, j, generation, e)) < 0) -+ r = transaction_verify_order_one(tr, o, j, generation, e); -+ if (r < 0) - return r; - } - -@@ -1075,13 +1052,13 @@ static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned - return 0; - } - --static int transaction_verify_order(Manager *m, unsigned *generation, DBusError *e) { -+static int transaction_verify_order(Transaction *tr, unsigned *generation, DBusError *e) { - Job *j; - int r; - Iterator i; - unsigned g; - -- assert(m); -+ assert(tr); - assert(generation); - - /* Check if the ordering graph is cyclic. If it is, try to fix -@@ -1089,17 +1066,17 @@ static int transaction_verify_order(Manager *m, unsigned *generation, DBusError - - g = (*generation)++; - -- HASHMAP_FOREACH(j, m->transaction_jobs, i) -- if ((r = transaction_verify_order_one(m, j, NULL, g, e)) < 0) -+ HASHMAP_FOREACH(j, tr->jobs, i) -+ if ((r = transaction_verify_order_one(tr, j, NULL, g, e)) < 0) - return r; - - return 0; - } - --static void transaction_collect_garbage(Manager *m) { -+static void transaction_collect_garbage(Transaction *tr) { - bool again; - -- assert(m); -+ assert(tr); - - /* Drop jobs that are not required by any other job */ - -@@ -1109,7 +1086,7 @@ static void transaction_collect_garbage(Manager *m) { - - again = false; - -- HASHMAP_FOREACH(j, m->transaction_jobs, i) { -+ HASHMAP_FOREACH(j, tr->jobs, i) { - if (j->object_list) { - /* log_debug("Keeping job %s/%s because of %s/%s", */ - /* j->unit->id, job_type_to_string(j->type), */ -@@ -1119,7 +1096,7 @@ static void transaction_collect_garbage(Manager *m) { - } - - /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */ -- transaction_delete_job(m, j, true); -+ transaction_delete_job(tr, j, true); - again = true; - break; - } -@@ -1127,16 +1104,16 @@ static void transaction_collect_garbage(Manager *m) { - } while (again); - } - --static int transaction_is_destructive(Manager *m, DBusError *e) { -+static int transaction_is_destructive(Transaction *tr, DBusError *e) { - Iterator i; - Job *j; - -- assert(m); -+ assert(tr); - - /* Checks whether applying this transaction means that - * existing jobs would be replaced */ - -- HASHMAP_FOREACH(j, m->transaction_jobs, i) { -+ HASHMAP_FOREACH(j, tr->jobs, i) { - - /* Assume merged */ - assert(!j->transaction_prev); -@@ -1154,9 +1131,9 @@ static int transaction_is_destructive(Manager *m, DBusError *e) { - return 0; - } - --static void transaction_minimize_impact(Manager *m) { -+static void transaction_minimize_impact(Transaction *tr) { - bool again; -- assert(m); -+ assert(tr); - - /* Drops all unnecessary jobs that reverse already active jobs - * or that stop a running service. */ -@@ -1167,7 +1144,7 @@ static void transaction_minimize_impact(Manager *m) { - - again = false; - -- HASHMAP_FOREACH(j, m->transaction_jobs, i) { -+ HASHMAP_FOREACH(j, tr->jobs, i) { - LIST_FOREACH(transaction, j, j) { - bool stops_running_service, changes_existing_job; - -@@ -1198,7 +1175,7 @@ static void transaction_minimize_impact(Manager *m) { - /* Ok, let's get rid of this */ - log_debug("Deleting %s/%s to minimize impact.", j->unit->id, job_type_to_string(j->type)); - -- transaction_delete_job(m, j, true); -+ transaction_delete_job(tr, j, true); - again = true; - break; - } -@@ -1210,7 +1187,7 @@ static void transaction_minimize_impact(Manager *m) { - } while (again); - } - --static int transaction_apply(Manager *m, JobMode mode) { -+static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { - Iterator i; - Job *j; - int r; -@@ -1225,7 +1202,7 @@ static int transaction_apply(Manager *m, JobMode mode) { - HASHMAP_FOREACH(j, m->jobs, i) { - assert(j->installed); - -- if (hashmap_get(m->transaction_jobs, j->unit)) -+ if (hashmap_get(tr->jobs, j->unit)) - continue; - - /* 'j' itself is safe to remove, but if other jobs -@@ -1236,7 +1213,7 @@ static int transaction_apply(Manager *m, JobMode mode) { - } - } - -- HASHMAP_FOREACH(j, m->transaction_jobs, i) { -+ HASHMAP_FOREACH(j, tr->jobs, i) { - /* Assume merged */ - assert(!j->transaction_prev); - assert(!j->transaction_next); -@@ -1244,11 +1221,12 @@ static int transaction_apply(Manager *m, JobMode mode) { - if (j->installed) - continue; - -- if ((r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j)) < 0) -+ r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j); -+ if (r < 0) - goto rollback; - } - -- while ((j = hashmap_steal_first(m->transaction_jobs))) { -+ while ((j = hashmap_steal_first(tr->jobs))) { - Job *uj; - if (j->installed) { - /* log_debug("Skipping already installed job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); */ -@@ -1271,6 +1249,9 @@ static int transaction_apply(Manager *m, JobMode mode) { - assert(!j->transaction_next); - assert(!j->transaction_prev); - -+ /* Clean the job dependencies */ -+ transaction_unlink_job(tr, j, false); -+ - job_add_to_run_queue(j); - job_add_to_dbus_queue(j); - job_start_timer(j); -@@ -1278,14 +1259,13 @@ static int transaction_apply(Manager *m, JobMode mode) { - log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); - } - -- /* As last step, kill all remaining job dependencies. */ -- transaction_clean_dependencies(m); -+ assert(!tr->anchor); - - return 0; - - rollback: - -- HASHMAP_FOREACH(j, m->transaction_jobs, i) { -+ HASHMAP_FOREACH(j, tr->jobs, i) { - if (j->installed) - continue; - -@@ -1295,41 +1275,42 @@ rollback: - return r; - } - --static int transaction_activate(Manager *m, JobMode mode, DBusError *e) { -+static int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e) { - int r; - unsigned generation = 1; - -- assert(m); -+ assert(tr); - -- /* This applies the changes recorded in transaction_jobs to -+ /* This applies the changes recorded in tr->jobs to - * the actual list of jobs, if possible. */ - - /* First step: figure out which jobs matter */ -- transaction_find_jobs_that_matter_to_anchor(m, NULL, generation++); -+ transaction_find_jobs_that_matter_to_anchor(tr, NULL, generation++); - - /* Second step: Try not to stop any running services if - * we don't have to. Don't try to reverse running - * jobs if we don't have to. */ - if (mode == JOB_FAIL) -- transaction_minimize_impact(m); -+ transaction_minimize_impact(tr); - - /* Third step: Drop redundant jobs */ -- transaction_drop_redundant(m); -+ transaction_drop_redundant(tr); - - for (;;) { - /* Fourth step: Let's remove unneeded jobs that might - * be lurking. */ - if (mode != JOB_ISOLATE) -- transaction_collect_garbage(m); -+ transaction_collect_garbage(tr); - - /* Fifth step: verify order makes sense and correct - * cycles if necessary and possible */ -- if ((r = transaction_verify_order(m, &generation, e)) >= 0) -+ r = transaction_verify_order(tr, &generation, e); -+ if (r >= 0) - break; - - if (r != -EAGAIN) { - log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error(e, r)); -- goto rollback; -+ return r; - } - - /* Let's see if the resulting transaction ordering -@@ -1340,60 +1321,60 @@ static int transaction_activate(Manager *m, JobMode mode, DBusError *e) { - /* Sixth step: let's drop unmergeable entries if - * necessary and possible, merge entries we can - * merge */ -- if ((r = transaction_merge_jobs(m, e)) >= 0) -+ r = transaction_merge_jobs(tr, e); -+ if (r >= 0) - break; - - if (r != -EAGAIN) { - log_warning("Requested transaction contains unmergeable jobs: %s", bus_error(e, r)); -- goto rollback; -+ return r; - } - - /* Seventh step: an entry got dropped, let's garbage - * collect its dependencies. */ - if (mode != JOB_ISOLATE) -- transaction_collect_garbage(m); -+ transaction_collect_garbage(tr); - - /* Let's see if the resulting transaction still has - * unmergeable entries ... */ - } - - /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */ -- transaction_drop_redundant(m); -+ transaction_drop_redundant(tr); - - /* Ninth step: check whether we can actually apply this */ -- if (mode == JOB_FAIL) -- if ((r = transaction_is_destructive(m, e)) < 0) { -+ if (mode == JOB_FAIL) { -+ r = transaction_is_destructive(tr, e); -+ if (r < 0) { - log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r)); -- goto rollback; -+ return r; - } -+ } - - /* Tenth step: apply changes */ -- if ((r = transaction_apply(m, mode)) < 0) { -+ r = transaction_apply(tr, m, mode); -+ if (r < 0) { - log_warning("Failed to apply transaction: %s", strerror(-r)); -- goto rollback; -+ return r; - } - -- assert(hashmap_isempty(m->transaction_jobs)); -- assert(!m->transaction_anchor); -+ assert(hashmap_isempty(tr->jobs)); -+ assert(!tr->anchor); - - return 0; -- --rollback: -- transaction_abort(m); -- return r; - } - --static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool override, bool *is_new) { -+static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) { - Job *j, *f; - -- assert(m); -+ assert(tr); - assert(unit); - - /* Looks for an existing prospective job and returns that. If - * it doesn't exist it is created and added to the prospective - * jobs list. */ - -- f = hashmap_get(m->transaction_jobs, unit); -+ f = hashmap_get(tr->jobs, unit); - - LIST_FOREACH(transaction, j, f) { - assert(j->unit == unit); -@@ -1407,8 +1388,11 @@ static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool o - - if (unit->job && unit->job->type == type) - j = unit->job; -- else if (!(j = job_new(m, type, unit))) -- return NULL; -+ else { -+ j = job_new(unit->manager, type, unit); -+ if (!j) -+ return NULL; -+ } - - j->generation = 0; - j->marker = NULL; -@@ -1417,7 +1401,7 @@ static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool o - - LIST_PREPEND(Job, transaction, f, j); - -- if (hashmap_replace(m->transaction_jobs, unit, f) < 0) { -+ if (hashmap_replace(tr->jobs, unit, f) < 0) { - LIST_REMOVE(Job, transaction, f, j); - job_free(j); - return NULL; -@@ -1431,16 +1415,16 @@ static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool o - return j; - } - --static void transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies) { -- assert(m); -+static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) { -+ assert(tr); - assert(j); - - if (j->transaction_prev) - j->transaction_prev->transaction_next = j->transaction_next; - else if (j->transaction_next) -- hashmap_replace(m->transaction_jobs, j->unit, j->transaction_next); -+ hashmap_replace(tr->jobs, j->unit, j->transaction_next); - else -- hashmap_remove_value(m->transaction_jobs, j->unit, j); -+ hashmap_remove_value(tr->jobs, j->unit, j); - - if (j->transaction_next) - j->transaction_next->transaction_prev = j->transaction_prev; -@@ -1448,24 +1432,24 @@ static void transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies) - j->transaction_prev = j->transaction_next = NULL; - - while (j->subject_list) -- job_dependency_free(j->subject_list); -+ job_dependency_free(j->subject_list, tr); - - while (j->object_list) { - Job *other = j->object_list->matters ? j->object_list->subject : NULL; - -- job_dependency_free(j->object_list); -+ job_dependency_free(j->object_list, tr); - - if (other && delete_dependencies) { - log_debug("Deleting job %s/%s as dependency of job %s/%s", - other->unit->id, job_type_to_string(other->type), - j->unit->id, job_type_to_string(j->type)); -- transaction_delete_job(m, other, delete_dependencies); -+ transaction_delete_job(tr, other, delete_dependencies); - } - } - } - - static int transaction_add_job_and_dependencies( -- Manager *m, -+ Transaction *tr, - JobType type, - Unit *unit, - Job *by, -@@ -1482,7 +1466,7 @@ static int transaction_add_job_and_dependencies( - int r; - bool is_new; - -- assert(m); -+ assert(tr); - assert(type < _JOB_TYPE_MAX); - assert(unit); - -@@ -1519,13 +1503,14 @@ static int transaction_add_job_and_dependencies( - } - - /* First add the job. */ -- if (!(ret = transaction_add_one_job(m, type, unit, override, &is_new))) -+ ret = transaction_add_one_job(tr, type, unit, override, &is_new); -+ if (!ret) - return -ENOMEM; - - ret->ignore_order = ret->ignore_order || ignore_order; - - /* Then, add a link to the job. */ -- if (!job_dependency_new(by, ret, matters, conflicts)) -+ if (!job_dependency_new(by, ret, matters, conflicts, tr)) - return -ENOMEM; - - if (is_new && !ignore_requirements) { -@@ -1534,120 +1519,136 @@ static int transaction_add_job_and_dependencies( - /* If we are following some other unit, make sure we - * add all dependencies of everybody following. */ - if (unit_following_set(ret->unit, &following) > 0) { -- SET_FOREACH(dep, following, i) -- if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) { -+ SET_FOREACH(dep, following, i) { -+ r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - - if (e) - dbus_error_free(e); - } -+ } - - set_free(following); - } - - /* Finally, recursively add in all dependencies. */ - if (type == JOB_START || type == JOB_RELOAD_OR_START) { -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) -- if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { - if (r != -EBADR) - goto fail; - - if (e) - dbus_error_free(e); - } -+ } - -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_BIND_TO], i) -- if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { -- -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_BIND_TO], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { - if (r != -EBADR) - goto fail; - - if (e) - dbus_error_free(e); - } -+ } - -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) -- if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) { -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - - if (e) - dbus_error_free(e); - } -+ } - -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) -- if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, false, false, ignore_order, e, NULL)) < 0) { -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e, NULL); -+ if (r < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - - if (e) - dbus_error_free(e); - } -+ } - -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) -- if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { -- -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { - if (r != -EBADR) - goto fail; - - if (e) - dbus_error_free(e); - } -+ } - -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) -- if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) { -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - - if (e) - dbus_error_free(e); - } -+ } - -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) -- if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e, NULL)) < 0) { -- -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e, NULL); -+ if (r < 0) { - if (r != -EBADR) - goto fail; - - if (e) - dbus_error_free(e); - } -+ } - -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) -- if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) { -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - - if (e) - dbus_error_free(e); - } -+ } - - } - - if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) { - -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) -- if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { -- -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) { -+ r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { - if (r != -EBADR) - goto fail; - - if (e) - dbus_error_free(e); - } -+ } - -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) -- if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { -- -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) { -+ r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { - if (r != -EBADR) - goto fail; - - if (e) - dbus_error_free(e); - } -+ } - } - - if (type == JOB_RELOAD || type == JOB_RELOAD_OR_START) { - - SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATE_RELOAD_TO], i) { -- r = transaction_add_job_and_dependencies(m, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e, NULL); -- -+ r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e, NULL); - if (r < 0) { - log_warning("Cannot add dependency reload job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - -@@ -1669,12 +1670,13 @@ fail: - return r; - } - --static int transaction_add_isolate_jobs(Manager *m) { -+static int transaction_add_isolate_jobs(Transaction *tr, Manager *m) { - Iterator i; - Unit *u; - char *k; - int r; - -+ assert(tr); - assert(m); - - HASHMAP_FOREACH_KEY(u, k, m->units, i) { -@@ -1691,19 +1693,43 @@ static int transaction_add_isolate_jobs(Manager *m) { - continue; - - /* Is there already something listed for this? */ -- if (hashmap_get(m->transaction_jobs, u)) -+ if (hashmap_get(tr->jobs, u)) - continue; - -- if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, u, NULL, true, false, false, false, false, NULL, NULL)) < 0) -+ r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, NULL, true, false, false, false, false, NULL, NULL); -+ if (r < 0) - log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->id, strerror(-r)); - } - - return 0; - } - -+static Transaction *transaction_new(void) { -+ Transaction *tr; -+ -+ tr = new0(Transaction, 1); -+ if (!tr) -+ return NULL; -+ -+ tr->jobs = hashmap_new(trivial_hash_func, trivial_compare_func); -+ if (!tr->jobs) { -+ free(tr); -+ return NULL; -+ } -+ -+ return tr; -+} -+ -+static void transaction_free(Transaction *tr) { -+ assert(hashmap_isempty(tr->jobs)); -+ hashmap_free(tr->jobs); -+ free(tr); -+} -+ - int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *e, Job **_ret) { - int r; - Job *ret; -+ Transaction *tr; - - assert(m); - assert(type < _JOB_TYPE_MAX); -@@ -1722,28 +1748,38 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove - - log_debug("Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode)); - -- if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, false, -- mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS, -- mode == JOB_IGNORE_DEPENDENCIES, e, &ret)) < 0) { -- transaction_abort(m); -- return r; -- } -+ tr = transaction_new(); -+ if (!tr) -+ return -ENOMEM; - -- if (mode == JOB_ISOLATE) -- if ((r = transaction_add_isolate_jobs(m)) < 0) { -- transaction_abort(m); -- return r; -- } -+ r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false, -+ mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS, -+ mode == JOB_IGNORE_DEPENDENCIES, e, &ret); -+ if (r < 0) -+ goto tr_abort; - -- if ((r = transaction_activate(m, mode, e)) < 0) -- return r; -+ if (mode == JOB_ISOLATE) { -+ r = transaction_add_isolate_jobs(tr, m); -+ if (r < 0) -+ goto tr_abort; -+ } -+ -+ r = transaction_activate(tr, m, mode, e); -+ if (r < 0) -+ goto tr_abort; - - log_debug("Enqueued job %s/%s as %u", unit->id, job_type_to_string(type), (unsigned) ret->id); - - if (_ret) - *_ret = ret; - -+ transaction_free(tr); - return 0; -+ -+tr_abort: -+ transaction_abort(tr); -+ transaction_free(tr); -+ return r; - } - - int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, DBusError *e, Job **_ret) { -@@ -1907,8 +1943,6 @@ void manager_clear_jobs(Manager *m) { - - assert(m); - -- transaction_abort(m); -- - while ((j = hashmap_first(m->jobs))) - job_finish_and_invalidate(j, JOB_CANCELED); - } -diff --git a/src/manager.h b/src/manager.h -index 64d8d0e..b982d7e 100644 ---- a/src/manager.h -+++ b/src/manager.h -@@ -33,6 +33,7 @@ - #define MANAGER_MAX_NAMES 131072 /* 128K */ - - typedef struct Manager Manager; -+typedef struct Transaction Transaction; - typedef enum WatchType WatchType; - typedef struct Watch Watch; - -@@ -91,6 +92,12 @@ struct Watch { - #include "dbus.h" - #include "path-lookup.h" - -+struct Transaction { -+ /* Jobs to be added */ -+ Hashmap *jobs; /* Unit object => Job object list 1:1 */ -+ JobDependency *anchor; -+}; -+ - struct Manager { - /* Note that the set of units we know of is allowed to be - * inconsistent. However the subset of it that is loaded may -@@ -123,10 +130,6 @@ struct Manager { - /* Units to check when doing GC */ - LIST_HEAD(Unit, gc_queue); - -- /* Jobs to be added */ -- Hashmap *transaction_jobs; /* Unit object => Job object list 1:1 */ -- JobDependency *transaction_anchor; -- - Hashmap *watch_pids; /* pid => Unit object n:1 */ - - char *notify_socket; --- -1.7.7 - - -From e617c9a330b60d070e3db57c1f86f3c579e03f0c Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Thu, 19 Apr 2012 23:54:11 +0200 -Subject: [PATCH 08/30] manager: split transaction.[ch] - -manager.c takes care of the main loop, unit management, signal handling, ... -transaction.c computes transactions. - -After split: -manager.c: 65 KB -transaction.c: 40 KB -(cherry picked from commit 75778e21dfeee51036d24501e39ea7398fabe502) - -Conflicts: - - Makefile.am - src/manager.c ---- - Makefile.am | 2 + - src/job.h | 1 + - src/manager.c | 1099 +---------------------------------------------------- - src/manager.h | 7 - - src/transaction.c | 1101 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - src/transaction.h | 36 ++ - 6 files changed, 1141 insertions(+), 1105 deletions(-) - create mode 100644 src/transaction.c - create mode 100644 src/transaction.h - -diff --git a/Makefile.am b/Makefile.am -index 079c118..45a0b10 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -483,6 +483,7 @@ libsystemd_core_la_SOURCES = \ - src/unit.c \ - src/job.c \ - src/manager.c \ -+ src/transaction.c \ - src/path-lookup.c \ - src/load-fragment.c \ - src/service.c \ -@@ -579,6 +580,7 @@ EXTRA_DIST += \ - src/unit.h \ - src/job.h \ - src/manager.h \ -+ src/transaction.h \ - src/path-lookup.h \ - src/load-fragment.h \ - src/service.h \ -diff --git a/src/job.h b/src/job.h -index 18ba64f..efb0af9 100644 ---- a/src/job.h -+++ b/src/job.h -@@ -34,6 +34,7 @@ typedef enum JobMode JobMode; - typedef enum JobResult JobResult; - - #include "manager.h" -+#include "transaction.h" - #include "unit.h" - #include "hashmap.h" - #include "list.h" -diff --git a/src/manager.c b/src/manager.c -index ff4249d..a129b88 100644 ---- a/src/manager.c -+++ b/src/manager.c -@@ -44,6 +44,7 @@ - #include - - #include "manager.h" -+#include "transaction.h" - #include "hashmap.h" - #include "macro.h" - #include "strv.h" -@@ -628,1104 +629,6 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { - return r; - } - --static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies); -- --static void transaction_delete_job(Transaction *tr, Job *j, bool delete_dependencies) { -- assert(tr); -- assert(j); -- -- /* Deletes one job from the transaction */ -- -- transaction_unlink_job(tr, j, delete_dependencies); -- -- if (!j->installed) -- job_free(j); --} -- --static void transaction_delete_unit(Transaction *tr, Unit *u) { -- Job *j; -- -- /* Deletes all jobs associated with a certain unit from the -- * transaction */ -- -- while ((j = hashmap_get(tr->jobs, u))) -- transaction_delete_job(tr, j, true); --} -- --static void transaction_abort(Transaction *tr) { -- Job *j; -- -- assert(tr); -- -- while ((j = hashmap_first(tr->jobs))) -- transaction_delete_job(tr, j, true); -- -- assert(hashmap_isempty(tr->jobs)); -- -- assert(!tr->anchor); --} -- --static void transaction_find_jobs_that_matter_to_anchor(Transaction *tr, Job *j, unsigned generation) { -- JobDependency *l; -- -- assert(tr); -- -- /* A recursive sweep through the graph that marks all units -- * that matter to the anchor job, i.e. are directly or -- * indirectly a dependency of the anchor job via paths that -- * are fully marked as mattering. */ -- -- if (j) -- l = j->subject_list; -- else -- l = tr->anchor; -- -- LIST_FOREACH(subject, l, l) { -- -- /* This link does not matter */ -- if (!l->matters) -- continue; -- -- /* This unit has already been marked */ -- if (l->object->generation == generation) -- continue; -- -- l->object->matters_to_anchor = true; -- l->object->generation = generation; -- -- transaction_find_jobs_that_matter_to_anchor(tr, l->object, generation); -- } --} -- --static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other, JobType t) { -- JobDependency *l, *last; -- -- assert(j); -- assert(other); -- assert(j->unit == other->unit); -- assert(!j->installed); -- -- /* Merges 'other' into 'j' and then deletes j. */ -- -- j->type = t; -- j->state = JOB_WAITING; -- j->override = j->override || other->override; -- -- j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor; -- -- /* Patch us in as new owner of the JobDependency objects */ -- last = NULL; -- LIST_FOREACH(subject, l, other->subject_list) { -- assert(l->subject == other); -- l->subject = j; -- last = l; -- } -- -- /* Merge both lists */ -- if (last) { -- last->subject_next = j->subject_list; -- if (j->subject_list) -- j->subject_list->subject_prev = last; -- j->subject_list = other->subject_list; -- } -- -- /* Patch us in as new owner of the JobDependency objects */ -- last = NULL; -- LIST_FOREACH(object, l, other->object_list) { -- assert(l->object == other); -- l->object = j; -- last = l; -- } -- -- /* Merge both lists */ -- if (last) { -- last->object_next = j->object_list; -- if (j->object_list) -- j->object_list->object_prev = last; -- j->object_list = other->object_list; -- } -- -- /* Kill the other job */ -- other->subject_list = NULL; -- other->object_list = NULL; -- transaction_delete_job(tr, other, true); --} --static bool job_is_conflicted_by(Job *j) { -- JobDependency *l; -- -- assert(j); -- -- /* Returns true if this job is pulled in by a least one -- * ConflictedBy dependency. */ -- -- LIST_FOREACH(object, l, j->object_list) -- if (l->conflicts) -- return true; -- -- return false; --} -- --static int delete_one_unmergeable_job(Transaction *tr, Job *j) { -- Job *k; -- -- assert(j); -- -- /* Tries to delete one item in the linked list -- * j->transaction_next->transaction_next->... that conflicts -- * with another one, in an attempt to make an inconsistent -- * transaction work. */ -- -- /* We rely here on the fact that if a merged with b does not -- * merge with c, either a or b merge with c neither */ -- LIST_FOREACH(transaction, j, j) -- LIST_FOREACH(transaction, k, j->transaction_next) { -- Job *d; -- -- /* Is this one mergeable? Then skip it */ -- if (job_type_is_mergeable(j->type, k->type)) -- continue; -- -- /* Ok, we found two that conflict, let's see if we can -- * drop one of them */ -- if (!j->matters_to_anchor && !k->matters_to_anchor) { -- -- /* Both jobs don't matter, so let's -- * find the one that is smarter to -- * remove. Let's think positive and -- * rather remove stops then starts -- -- * except if something is being -- * stopped because it is conflicted by -- * another unit in which case we -- * rather remove the start. */ -- -- log_debug("Looking at job %s/%s conflicted_by=%s", j->unit->id, job_type_to_string(j->type), yes_no(j->type == JOB_STOP && job_is_conflicted_by(j))); -- log_debug("Looking at job %s/%s conflicted_by=%s", k->unit->id, job_type_to_string(k->type), yes_no(k->type == JOB_STOP && job_is_conflicted_by(k))); -- -- if (j->type == JOB_STOP) { -- -- if (job_is_conflicted_by(j)) -- d = k; -- else -- d = j; -- -- } else if (k->type == JOB_STOP) { -- -- if (job_is_conflicted_by(k)) -- d = j; -- else -- d = k; -- } else -- d = j; -- -- } else if (!j->matters_to_anchor) -- d = j; -- else if (!k->matters_to_anchor) -- d = k; -- else -- return -ENOEXEC; -- -- /* Ok, we can drop one, so let's do so. */ -- log_debug("Fixing conflicting jobs by deleting job %s/%s", d->unit->id, job_type_to_string(d->type)); -- transaction_delete_job(tr, d, true); -- return 0; -- } -- -- return -EINVAL; --} -- --static int transaction_merge_jobs(Transaction *tr, DBusError *e) { -- Job *j; -- Iterator i; -- int r; -- -- assert(tr); -- -- /* First step, check whether any of the jobs for one specific -- * task conflict. If so, try to drop one of them. */ -- HASHMAP_FOREACH(j, tr->jobs, i) { -- JobType t; -- Job *k; -- -- t = j->type; -- LIST_FOREACH(transaction, k, j->transaction_next) { -- if (job_type_merge(&t, k->type) >= 0) -- continue; -- -- /* OK, we could not merge all jobs for this -- * action. Let's see if we can get rid of one -- * of them */ -- -- r = delete_one_unmergeable_job(tr, j); -- if (r >= 0) -- /* Ok, we managed to drop one, now -- * let's ask our callers to call us -- * again after garbage collecting */ -- return -EAGAIN; -- -- /* We couldn't merge anything. Failure */ -- dbus_set_error(e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, "Transaction contains conflicting jobs '%s' and '%s' for %s. Probably contradicting requirement dependencies configured.", -- job_type_to_string(t), job_type_to_string(k->type), k->unit->id); -- return r; -- } -- } -- -- /* Second step, merge the jobs. */ -- HASHMAP_FOREACH(j, tr->jobs, i) { -- JobType t = j->type; -- Job *k; -- -- /* Merge all transactions */ -- LIST_FOREACH(transaction, k, j->transaction_next) -- assert_se(job_type_merge(&t, k->type) == 0); -- -- /* If an active job is mergeable, merge it too */ -- if (j->unit->job) -- job_type_merge(&t, j->unit->job->type); /* Might fail. Which is OK */ -- -- while ((k = j->transaction_next)) { -- if (j->installed) { -- transaction_merge_and_delete_job(tr, k, j, t); -- j = k; -- } else -- transaction_merge_and_delete_job(tr, j, k, t); -- } -- -- if (j->unit->job && !j->installed) -- transaction_merge_and_delete_job(tr, j, j->unit->job, t); -- -- assert(!j->transaction_next); -- assert(!j->transaction_prev); -- } -- -- return 0; --} -- --static void transaction_drop_redundant(Transaction *tr) { -- bool again; -- -- assert(tr); -- -- /* Goes through the transaction and removes all jobs that are -- * a noop */ -- -- do { -- Job *j; -- Iterator i; -- -- again = false; -- -- HASHMAP_FOREACH(j, tr->jobs, i) { -- bool changes_something = false; -- Job *k; -- -- LIST_FOREACH(transaction, k, j) { -- -- if (!job_is_anchor(k) && -- (k->installed || job_type_is_redundant(k->type, unit_active_state(k->unit))) && -- (!k->unit->job || !job_type_is_conflicting(k->type, k->unit->job->type))) -- continue; -- -- changes_something = true; -- break; -- } -- -- if (changes_something) -- continue; -- -- /* log_debug("Found redundant job %s/%s, dropping.", j->unit->id, job_type_to_string(j->type)); */ -- transaction_delete_job(tr, j, false); -- again = true; -- break; -- } -- -- } while (again); --} -- --static bool unit_matters_to_anchor(Unit *u, Job *j) { -- assert(u); -- assert(!j->transaction_prev); -- -- /* Checks whether at least one of the jobs for this unit -- * matters to the anchor. */ -- -- LIST_FOREACH(transaction, j, j) -- if (j->matters_to_anchor) -- return true; -- -- return false; --} -- --static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, DBusError *e) { -- Iterator i; -- Unit *u; -- int r; -- -- assert(tr); -- assert(j); -- assert(!j->transaction_prev); -- -- /* Does a recursive sweep through the ordering graph, looking -- * for a cycle. If we find cycle we try to break it. */ -- -- /* Have we seen this before? */ -- if (j->generation == generation) { -- Job *k, *delete; -- -- /* If the marker is NULL we have been here already and -- * decided the job was loop-free from here. Hence -- * shortcut things and return right-away. */ -- if (!j->marker) -- return 0; -- -- /* So, the marker is not NULL and we already have been -- * here. We have a cycle. Let's try to break it. We go -- * backwards in our path and try to find a suitable -- * job to remove. We use the marker to find our way -- * back, since smart how we are we stored our way back -- * in there. */ -- log_warning("Found ordering cycle on %s/%s", j->unit->id, job_type_to_string(j->type)); -- -- delete = NULL; -- for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) { -- -- log_info("Walked on cycle path to %s/%s", k->unit->id, job_type_to_string(k->type)); -- -- if (!delete && -- !k->installed && -- !unit_matters_to_anchor(k->unit, k)) { -- /* Ok, we can drop this one, so let's -- * do so. */ -- delete = k; -- } -- -- /* Check if this in fact was the beginning of -- * the cycle */ -- if (k == j) -- break; -- } -- -- -- if (delete) { -- log_warning("Breaking ordering cycle by deleting job %s/%s", delete->unit->id, job_type_to_string(delete->type)); -- transaction_delete_unit(tr, delete->unit); -- return -EAGAIN; -- } -- -- log_error("Unable to break cycle"); -- -- dbus_set_error(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, "Transaction order is cyclic. See system logs for details."); -- return -ENOEXEC; -- } -- -- /* Make the marker point to where we come from, so that we can -- * find our way backwards if we want to break a cycle. We use -- * a special marker for the beginning: we point to -- * ourselves. */ -- j->marker = from ? from : j; -- j->generation = generation; -- -- /* We assume that the the dependencies are bidirectional, and -- * hence can ignore UNIT_AFTER */ -- SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) { -- Job *o; -- -- /* Is there a job for this unit? */ -- o = hashmap_get(tr->jobs, u); -- if (!o) { -- /* Ok, there is no job for this in the -- * transaction, but maybe there is already one -- * running? */ -- o = u->job; -- if (!o) -- continue; -- } -- -- r = transaction_verify_order_one(tr, o, j, generation, e); -- if (r < 0) -- return r; -- } -- -- /* Ok, let's backtrack, and remember that this entry is not on -- * our path anymore. */ -- j->marker = NULL; -- -- return 0; --} -- --static int transaction_verify_order(Transaction *tr, unsigned *generation, DBusError *e) { -- Job *j; -- int r; -- Iterator i; -- unsigned g; -- -- assert(tr); -- assert(generation); -- -- /* Check if the ordering graph is cyclic. If it is, try to fix -- * that up by dropping one of the jobs. */ -- -- g = (*generation)++; -- -- HASHMAP_FOREACH(j, tr->jobs, i) -- if ((r = transaction_verify_order_one(tr, j, NULL, g, e)) < 0) -- return r; -- -- return 0; --} -- --static void transaction_collect_garbage(Transaction *tr) { -- bool again; -- -- assert(tr); -- -- /* Drop jobs that are not required by any other job */ -- -- do { -- Iterator i; -- Job *j; -- -- again = false; -- -- HASHMAP_FOREACH(j, tr->jobs, i) { -- if (j->object_list) { -- /* log_debug("Keeping job %s/%s because of %s/%s", */ -- /* j->unit->id, job_type_to_string(j->type), */ -- /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */ -- /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */ -- continue; -- } -- -- /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */ -- transaction_delete_job(tr, j, true); -- again = true; -- break; -- } -- -- } while (again); --} -- --static int transaction_is_destructive(Transaction *tr, DBusError *e) { -- Iterator i; -- Job *j; -- -- assert(tr); -- -- /* Checks whether applying this transaction means that -- * existing jobs would be replaced */ -- -- HASHMAP_FOREACH(j, tr->jobs, i) { -- -- /* Assume merged */ -- assert(!j->transaction_prev); -- assert(!j->transaction_next); -- -- if (j->unit->job && -- j->unit->job != j && -- !job_type_is_superset(j->type, j->unit->job->type)) { -- -- dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive."); -- return -EEXIST; -- } -- } -- -- return 0; --} -- --static void transaction_minimize_impact(Transaction *tr) { -- bool again; -- assert(tr); -- -- /* Drops all unnecessary jobs that reverse already active jobs -- * or that stop a running service. */ -- -- do { -- Job *j; -- Iterator i; -- -- again = false; -- -- HASHMAP_FOREACH(j, tr->jobs, i) { -- LIST_FOREACH(transaction, j, j) { -- bool stops_running_service, changes_existing_job; -- -- /* If it matters, we shouldn't drop it */ -- if (j->matters_to_anchor) -- continue; -- -- /* Would this stop a running service? -- * Would this change an existing job? -- * If so, let's drop this entry */ -- -- stops_running_service = -- j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit)); -- -- changes_existing_job = -- j->unit->job && -- job_type_is_conflicting(j->type, j->unit->job->type); -- -- if (!stops_running_service && !changes_existing_job) -- continue; -- -- if (stops_running_service) -- log_debug("%s/%s would stop a running service.", j->unit->id, job_type_to_string(j->type)); -- -- if (changes_existing_job) -- log_debug("%s/%s would change existing job.", j->unit->id, job_type_to_string(j->type)); -- -- /* Ok, let's get rid of this */ -- log_debug("Deleting %s/%s to minimize impact.", j->unit->id, job_type_to_string(j->type)); -- -- transaction_delete_job(tr, j, true); -- again = true; -- break; -- } -- -- if (again) -- break; -- } -- -- } while (again); --} -- --static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { -- Iterator i; -- Job *j; -- int r; -- -- /* Moves the transaction jobs to the set of active jobs */ -- -- if (mode == JOB_ISOLATE) { -- -- /* 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(tr->jobs, j->unit)) -- continue; -- -- /* '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; -- } -- } -- -- HASHMAP_FOREACH(j, tr->jobs, i) { -- /* Assume merged */ -- assert(!j->transaction_prev); -- assert(!j->transaction_next); -- -- if (j->installed) -- continue; -- -- r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j); -- if (r < 0) -- goto rollback; -- } -- -- while ((j = hashmap_steal_first(tr->jobs))) { -- Job *uj; -- if (j->installed) { -- /* log_debug("Skipping already installed job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); */ -- continue; -- } -- -- uj = j->unit->job; -- if (uj) { -- job_uninstall(uj); -- job_free(uj); -- } -- -- j->unit->job = j; -- j->installed = true; -- m->n_installed_jobs ++; -- -- /* We're fully installed. Now let's free data we don't -- * need anymore. */ -- -- assert(!j->transaction_next); -- assert(!j->transaction_prev); -- -- /* Clean the job dependencies */ -- transaction_unlink_job(tr, j, false); -- -- job_add_to_run_queue(j); -- job_add_to_dbus_queue(j); -- job_start_timer(j); -- -- log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); -- } -- -- assert(!tr->anchor); -- -- return 0; -- --rollback: -- -- HASHMAP_FOREACH(j, tr->jobs, i) { -- if (j->installed) -- continue; -- -- hashmap_remove(m->jobs, UINT32_TO_PTR(j->id)); -- } -- -- return r; --} -- --static int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e) { -- int r; -- unsigned generation = 1; -- -- assert(tr); -- -- /* This applies the changes recorded in tr->jobs to -- * the actual list of jobs, if possible. */ -- -- /* First step: figure out which jobs matter */ -- transaction_find_jobs_that_matter_to_anchor(tr, NULL, generation++); -- -- /* Second step: Try not to stop any running services if -- * we don't have to. Don't try to reverse running -- * jobs if we don't have to. */ -- if (mode == JOB_FAIL) -- transaction_minimize_impact(tr); -- -- /* Third step: Drop redundant jobs */ -- transaction_drop_redundant(tr); -- -- for (;;) { -- /* Fourth step: Let's remove unneeded jobs that might -- * be lurking. */ -- if (mode != JOB_ISOLATE) -- transaction_collect_garbage(tr); -- -- /* Fifth step: verify order makes sense and correct -- * cycles if necessary and possible */ -- r = transaction_verify_order(tr, &generation, e); -- if (r >= 0) -- break; -- -- if (r != -EAGAIN) { -- log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error(e, r)); -- return r; -- } -- -- /* Let's see if the resulting transaction ordering -- * graph is still cyclic... */ -- } -- -- for (;;) { -- /* Sixth step: let's drop unmergeable entries if -- * necessary and possible, merge entries we can -- * merge */ -- r = transaction_merge_jobs(tr, e); -- if (r >= 0) -- break; -- -- if (r != -EAGAIN) { -- log_warning("Requested transaction contains unmergeable jobs: %s", bus_error(e, r)); -- return r; -- } -- -- /* Seventh step: an entry got dropped, let's garbage -- * collect its dependencies. */ -- if (mode != JOB_ISOLATE) -- transaction_collect_garbage(tr); -- -- /* Let's see if the resulting transaction still has -- * unmergeable entries ... */ -- } -- -- /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */ -- transaction_drop_redundant(tr); -- -- /* Ninth step: check whether we can actually apply this */ -- if (mode == JOB_FAIL) { -- r = transaction_is_destructive(tr, e); -- if (r < 0) { -- log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r)); -- return r; -- } -- } -- -- /* Tenth step: apply changes */ -- r = transaction_apply(tr, m, mode); -- if (r < 0) { -- log_warning("Failed to apply transaction: %s", strerror(-r)); -- return r; -- } -- -- assert(hashmap_isempty(tr->jobs)); -- assert(!tr->anchor); -- -- return 0; --} -- --static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) { -- Job *j, *f; -- -- assert(tr); -- assert(unit); -- -- /* Looks for an existing prospective job and returns that. If -- * it doesn't exist it is created and added to the prospective -- * jobs list. */ -- -- f = hashmap_get(tr->jobs, unit); -- -- LIST_FOREACH(transaction, j, f) { -- assert(j->unit == unit); -- -- if (j->type == type) { -- if (is_new) -- *is_new = false; -- return j; -- } -- } -- -- if (unit->job && unit->job->type == type) -- j = unit->job; -- else { -- j = job_new(unit->manager, type, unit); -- if (!j) -- return NULL; -- } -- -- j->generation = 0; -- j->marker = NULL; -- j->matters_to_anchor = false; -- j->override = override; -- -- LIST_PREPEND(Job, transaction, f, j); -- -- if (hashmap_replace(tr->jobs, unit, f) < 0) { -- LIST_REMOVE(Job, transaction, f, j); -- job_free(j); -- return NULL; -- } -- -- if (is_new) -- *is_new = true; -- -- /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */ -- -- return j; --} -- --static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) { -- assert(tr); -- assert(j); -- -- if (j->transaction_prev) -- j->transaction_prev->transaction_next = j->transaction_next; -- else if (j->transaction_next) -- hashmap_replace(tr->jobs, j->unit, j->transaction_next); -- else -- hashmap_remove_value(tr->jobs, j->unit, j); -- -- if (j->transaction_next) -- j->transaction_next->transaction_prev = j->transaction_prev; -- -- j->transaction_prev = j->transaction_next = NULL; -- -- while (j->subject_list) -- job_dependency_free(j->subject_list, tr); -- -- while (j->object_list) { -- Job *other = j->object_list->matters ? j->object_list->subject : NULL; -- -- job_dependency_free(j->object_list, tr); -- -- if (other && delete_dependencies) { -- log_debug("Deleting job %s/%s as dependency of job %s/%s", -- other->unit->id, job_type_to_string(other->type), -- j->unit->id, job_type_to_string(j->type)); -- transaction_delete_job(tr, other, delete_dependencies); -- } -- } --} -- --static int transaction_add_job_and_dependencies( -- Transaction *tr, -- JobType type, -- Unit *unit, -- Job *by, -- bool matters, -- bool override, -- bool conflicts, -- bool ignore_requirements, -- bool ignore_order, -- DBusError *e, -- Job **_ret) { -- Job *ret; -- Iterator i; -- Unit *dep; -- int r; -- bool is_new; -- -- assert(tr); -- assert(type < _JOB_TYPE_MAX); -- assert(unit); -- -- /* log_debug("Pulling in %s/%s from %s/%s", */ -- /* unit->id, job_type_to_string(type), */ -- /* by ? by->unit->id : "NA", */ -- /* by ? job_type_to_string(by->type) : "NA"); */ -- -- if (unit->load_state != UNIT_LOADED && -- unit->load_state != UNIT_ERROR && -- unit->load_state != UNIT_MASKED) { -- dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id); -- return -EINVAL; -- } -- -- if (type != JOB_STOP && unit->load_state == UNIT_ERROR) { -- dbus_set_error(e, BUS_ERROR_LOAD_FAILED, -- "Unit %s failed to load: %s. " -- "See system logs and 'systemctl status %s' for details.", -- unit->id, -- strerror(-unit->load_error), -- unit->id); -- return -EINVAL; -- } -- -- if (type != JOB_STOP && unit->load_state == UNIT_MASKED) { -- dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->id); -- return -EINVAL; -- } -- -- if (!unit_job_is_applicable(unit, type)) { -- dbus_set_error(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->id); -- return -EBADR; -- } -- -- /* First add the job. */ -- ret = transaction_add_one_job(tr, type, unit, override, &is_new); -- if (!ret) -- return -ENOMEM; -- -- ret->ignore_order = ret->ignore_order || ignore_order; -- -- /* Then, add a link to the job. */ -- if (!job_dependency_new(by, ret, matters, conflicts, tr)) -- return -ENOMEM; -- -- if (is_new && !ignore_requirements) { -- Set *following; -- -- /* If we are following some other unit, make sure we -- * add all dependencies of everybody following. */ -- if (unit_following_set(ret->unit, &following) > 0) { -- SET_FOREACH(dep, following, i) { -- r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e, NULL); -- if (r < 0) { -- log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -- -- if (e) -- dbus_error_free(e); -- } -- } -- -- set_free(following); -- } -- -- /* Finally, recursively add in all dependencies. */ -- if (type == JOB_START || type == JOB_RELOAD_OR_START) { -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL); -- if (r < 0) { -- if (r != -EBADR) -- goto fail; -- -- if (e) -- dbus_error_free(e); -- } -- } -- -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_BIND_TO], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL); -- if (r < 0) { -- if (r != -EBADR) -- goto fail; -- -- if (e) -- dbus_error_free(e); -- } -- } -- -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e, NULL); -- if (r < 0) { -- log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -- -- if (e) -- dbus_error_free(e); -- } -- } -- -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e, NULL); -- if (r < 0) { -- log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -- -- if (e) -- dbus_error_free(e); -- } -- } -- -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e, NULL); -- if (r < 0) { -- if (r != -EBADR) -- goto fail; -- -- if (e) -- dbus_error_free(e); -- } -- } -- -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e, NULL); -- if (r < 0) { -- log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -- -- if (e) -- dbus_error_free(e); -- } -- } -- -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e, NULL); -- if (r < 0) { -- if (r != -EBADR) -- goto fail; -- -- if (e) -- dbus_error_free(e); -- } -- } -- -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e, NULL); -- if (r < 0) { -- log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -- -- if (e) -- dbus_error_free(e); -- } -- } -- -- } -- -- if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) { -- -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) { -- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e, NULL); -- if (r < 0) { -- if (r != -EBADR) -- goto fail; -- -- if (e) -- dbus_error_free(e); -- } -- } -- -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) { -- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e, NULL); -- if (r < 0) { -- if (r != -EBADR) -- goto fail; -- -- if (e) -- dbus_error_free(e); -- } -- } -- } -- -- if (type == JOB_RELOAD || type == JOB_RELOAD_OR_START) { -- -- SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATE_RELOAD_TO], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e, NULL); -- if (r < 0) { -- log_warning("Cannot add dependency reload job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -- -- if (e) -- dbus_error_free(e); -- } -- } -- } -- -- /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */ -- } -- -- if (_ret) -- *_ret = ret; -- -- return 0; -- --fail: -- return r; --} -- --static int transaction_add_isolate_jobs(Transaction *tr, Manager *m) { -- Iterator i; -- Unit *u; -- char *k; -- int r; -- -- assert(tr); -- assert(m); -- -- HASHMAP_FOREACH_KEY(u, k, m->units, i) { -- -- /* ignore aliases */ -- if (u->id != k) -- continue; -- -- if (u->ignore_on_isolate) -- continue; -- -- /* No need to stop inactive jobs */ -- if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job) -- continue; -- -- /* Is there already something listed for this? */ -- if (hashmap_get(tr->jobs, u)) -- continue; -- -- r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, NULL, true, false, false, false, false, NULL, NULL); -- if (r < 0) -- log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->id, strerror(-r)); -- } -- -- return 0; --} -- --static Transaction *transaction_new(void) { -- Transaction *tr; -- -- tr = new0(Transaction, 1); -- if (!tr) -- return NULL; -- -- tr->jobs = hashmap_new(trivial_hash_func, trivial_compare_func); -- if (!tr->jobs) { -- free(tr); -- return NULL; -- } -- -- return tr; --} -- --static void transaction_free(Transaction *tr) { -- assert(hashmap_isempty(tr->jobs)); -- hashmap_free(tr->jobs); -- free(tr); --} -- - int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *e, Job **_ret) { - int r; - Job *ret; -diff --git a/src/manager.h b/src/manager.h -index b982d7e..915f6fc 100644 ---- a/src/manager.h -+++ b/src/manager.h -@@ -33,7 +33,6 @@ - #define MANAGER_MAX_NAMES 131072 /* 128K */ - - typedef struct Manager Manager; --typedef struct Transaction Transaction; - typedef enum WatchType WatchType; - typedef struct Watch Watch; - -@@ -92,12 +91,6 @@ struct Watch { - #include "dbus.h" - #include "path-lookup.h" - --struct Transaction { -- /* Jobs to be added */ -- Hashmap *jobs; /* Unit object => Job object list 1:1 */ -- JobDependency *anchor; --}; -- - struct Manager { - /* Note that the set of units we know of is allowed to be - * inconsistent. However the subset of it that is loaded may -diff --git a/src/transaction.c b/src/transaction.c -new file mode 100644 -index 0000000..8fa89a7 ---- /dev/null -+++ b/src/transaction.c -@@ -0,0 +1,1101 @@ -+#include "transaction.h" -+#include "bus-errors.h" -+ -+static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies); -+ -+static void transaction_delete_job(Transaction *tr, Job *j, bool delete_dependencies) { -+ assert(tr); -+ assert(j); -+ -+ /* Deletes one job from the transaction */ -+ -+ transaction_unlink_job(tr, j, delete_dependencies); -+ -+ if (!j->installed) -+ job_free(j); -+} -+ -+static void transaction_delete_unit(Transaction *tr, Unit *u) { -+ Job *j; -+ -+ /* Deletes all jobs associated with a certain unit from the -+ * transaction */ -+ -+ while ((j = hashmap_get(tr->jobs, u))) -+ transaction_delete_job(tr, j, true); -+} -+ -+void transaction_abort(Transaction *tr) { -+ Job *j; -+ -+ assert(tr); -+ -+ while ((j = hashmap_first(tr->jobs))) -+ transaction_delete_job(tr, j, true); -+ -+ assert(hashmap_isempty(tr->jobs)); -+ -+ assert(!tr->anchor); -+} -+ -+static void transaction_find_jobs_that_matter_to_anchor(Transaction *tr, Job *j, unsigned generation) { -+ JobDependency *l; -+ -+ assert(tr); -+ -+ /* A recursive sweep through the graph that marks all units -+ * that matter to the anchor job, i.e. are directly or -+ * indirectly a dependency of the anchor job via paths that -+ * are fully marked as mattering. */ -+ -+ if (j) -+ l = j->subject_list; -+ else -+ l = tr->anchor; -+ -+ LIST_FOREACH(subject, l, l) { -+ -+ /* This link does not matter */ -+ if (!l->matters) -+ continue; -+ -+ /* This unit has already been marked */ -+ if (l->object->generation == generation) -+ continue; -+ -+ l->object->matters_to_anchor = true; -+ l->object->generation = generation; -+ -+ transaction_find_jobs_that_matter_to_anchor(tr, l->object, generation); -+ } -+} -+ -+static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other, JobType t) { -+ JobDependency *l, *last; -+ -+ assert(j); -+ assert(other); -+ assert(j->unit == other->unit); -+ assert(!j->installed); -+ -+ /* Merges 'other' into 'j' and then deletes 'other'. */ -+ -+ j->type = t; -+ j->state = JOB_WAITING; -+ j->override = j->override || other->override; -+ -+ j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor; -+ -+ /* Patch us in as new owner of the JobDependency objects */ -+ last = NULL; -+ LIST_FOREACH(subject, l, other->subject_list) { -+ assert(l->subject == other); -+ l->subject = j; -+ last = l; -+ } -+ -+ /* Merge both lists */ -+ if (last) { -+ last->subject_next = j->subject_list; -+ if (j->subject_list) -+ j->subject_list->subject_prev = last; -+ j->subject_list = other->subject_list; -+ } -+ -+ /* Patch us in as new owner of the JobDependency objects */ -+ last = NULL; -+ LIST_FOREACH(object, l, other->object_list) { -+ assert(l->object == other); -+ l->object = j; -+ last = l; -+ } -+ -+ /* Merge both lists */ -+ if (last) { -+ last->object_next = j->object_list; -+ if (j->object_list) -+ j->object_list->object_prev = last; -+ j->object_list = other->object_list; -+ } -+ -+ /* Kill the other job */ -+ other->subject_list = NULL; -+ other->object_list = NULL; -+ transaction_delete_job(tr, other, true); -+} -+ -+static bool job_is_conflicted_by(Job *j) { -+ JobDependency *l; -+ -+ assert(j); -+ -+ /* Returns true if this job is pulled in by a least one -+ * ConflictedBy dependency. */ -+ -+ LIST_FOREACH(object, l, j->object_list) -+ if (l->conflicts) -+ return true; -+ -+ return false; -+} -+ -+static int delete_one_unmergeable_job(Transaction *tr, Job *j) { -+ Job *k; -+ -+ assert(j); -+ -+ /* Tries to delete one item in the linked list -+ * j->transaction_next->transaction_next->... that conflicts -+ * with another one, in an attempt to make an inconsistent -+ * transaction work. */ -+ -+ /* We rely here on the fact that if a merged with b does not -+ * merge with c, either a or b merge with c neither */ -+ LIST_FOREACH(transaction, j, j) -+ LIST_FOREACH(transaction, k, j->transaction_next) { -+ Job *d; -+ -+ /* Is this one mergeable? Then skip it */ -+ if (job_type_is_mergeable(j->type, k->type)) -+ continue; -+ -+ /* Ok, we found two that conflict, let's see if we can -+ * drop one of them */ -+ if (!j->matters_to_anchor && !k->matters_to_anchor) { -+ -+ /* Both jobs don't matter, so let's -+ * find the one that is smarter to -+ * remove. Let's think positive and -+ * rather remove stops then starts -- -+ * except if something is being -+ * stopped because it is conflicted by -+ * another unit in which case we -+ * rather remove the start. */ -+ -+ log_debug("Looking at job %s/%s conflicted_by=%s", j->unit->id, job_type_to_string(j->type), yes_no(j->type == JOB_STOP && job_is_conflicted_by(j))); -+ log_debug("Looking at job %s/%s conflicted_by=%s", k->unit->id, job_type_to_string(k->type), yes_no(k->type == JOB_STOP && job_is_conflicted_by(k))); -+ -+ if (j->type == JOB_STOP) { -+ -+ if (job_is_conflicted_by(j)) -+ d = k; -+ else -+ d = j; -+ -+ } else if (k->type == JOB_STOP) { -+ -+ if (job_is_conflicted_by(k)) -+ d = j; -+ else -+ d = k; -+ } else -+ d = j; -+ -+ } else if (!j->matters_to_anchor) -+ d = j; -+ else if (!k->matters_to_anchor) -+ d = k; -+ else -+ return -ENOEXEC; -+ -+ /* Ok, we can drop one, so let's do so. */ -+ log_debug("Fixing conflicting jobs by deleting job %s/%s", d->unit->id, job_type_to_string(d->type)); -+ transaction_delete_job(tr, d, true); -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ -+static int transaction_merge_jobs(Transaction *tr, DBusError *e) { -+ Job *j; -+ Iterator i; -+ int r; -+ -+ assert(tr); -+ -+ /* First step, check whether any of the jobs for one specific -+ * task conflict. If so, try to drop one of them. */ -+ HASHMAP_FOREACH(j, tr->jobs, i) { -+ JobType t; -+ Job *k; -+ -+ t = j->type; -+ LIST_FOREACH(transaction, k, j->transaction_next) { -+ if (job_type_merge(&t, k->type) >= 0) -+ continue; -+ -+ /* OK, we could not merge all jobs for this -+ * action. Let's see if we can get rid of one -+ * of them */ -+ -+ r = delete_one_unmergeable_job(tr, j); -+ if (r >= 0) -+ /* Ok, we managed to drop one, now -+ * let's ask our callers to call us -+ * again after garbage collecting */ -+ return -EAGAIN; -+ -+ /* We couldn't merge anything. Failure */ -+ dbus_set_error(e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, "Transaction contains conflicting jobs '%s' and '%s' for %s. Probably contradicting requirement dependencies configured.", -+ job_type_to_string(t), job_type_to_string(k->type), k->unit->id); -+ return r; -+ } -+ } -+ -+ /* Second step, merge the jobs. */ -+ HASHMAP_FOREACH(j, tr->jobs, i) { -+ JobType t = j->type; -+ Job *k; -+ -+ /* Merge all transactions */ -+ LIST_FOREACH(transaction, k, j->transaction_next) -+ assert_se(job_type_merge(&t, k->type) == 0); -+ -+ /* If an active job is mergeable, merge it too */ -+ if (j->unit->job) -+ job_type_merge(&t, j->unit->job->type); /* Might fail. Which is OK */ -+ -+ while ((k = j->transaction_next)) { -+ if (j->installed) { -+ transaction_merge_and_delete_job(tr, k, j, t); -+ j = k; -+ } else -+ transaction_merge_and_delete_job(tr, j, k, t); -+ } -+ -+ if (j->unit->job && !j->installed) -+ transaction_merge_and_delete_job(tr, j, j->unit->job, t); -+ -+ assert(!j->transaction_next); -+ assert(!j->transaction_prev); -+ } -+ -+ return 0; -+} -+ -+static void transaction_drop_redundant(Transaction *tr) { -+ bool again; -+ -+ assert(tr); -+ -+ /* Goes through the transaction and removes all jobs that are -+ * a noop */ -+ -+ do { -+ Job *j; -+ Iterator i; -+ -+ again = false; -+ -+ HASHMAP_FOREACH(j, tr->jobs, i) { -+ bool changes_something = false; -+ Job *k; -+ -+ LIST_FOREACH(transaction, k, j) { -+ -+ if (!job_is_anchor(k) && -+ (k->installed || job_type_is_redundant(k->type, unit_active_state(k->unit))) && -+ (!k->unit->job || !job_type_is_conflicting(k->type, k->unit->job->type))) -+ continue; -+ -+ changes_something = true; -+ break; -+ } -+ -+ if (changes_something) -+ continue; -+ -+ /* log_debug("Found redundant job %s/%s, dropping.", j->unit->id, job_type_to_string(j->type)); */ -+ transaction_delete_job(tr, j, false); -+ again = true; -+ break; -+ } -+ -+ } while (again); -+} -+ -+static bool unit_matters_to_anchor(Unit *u, Job *j) { -+ assert(u); -+ assert(!j->transaction_prev); -+ -+ /* Checks whether at least one of the jobs for this unit -+ * matters to the anchor. */ -+ -+ LIST_FOREACH(transaction, j, j) -+ if (j->matters_to_anchor) -+ return true; -+ -+ return false; -+} -+ -+static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, DBusError *e) { -+ Iterator i; -+ Unit *u; -+ int r; -+ -+ assert(tr); -+ assert(j); -+ assert(!j->transaction_prev); -+ -+ /* Does a recursive sweep through the ordering graph, looking -+ * for a cycle. If we find cycle we try to break it. */ -+ -+ /* Have we seen this before? */ -+ if (j->generation == generation) { -+ Job *k, *delete; -+ -+ /* If the marker is NULL we have been here already and -+ * decided the job was loop-free from here. Hence -+ * shortcut things and return right-away. */ -+ if (!j->marker) -+ return 0; -+ -+ /* So, the marker is not NULL and we already have been -+ * here. We have a cycle. Let's try to break it. We go -+ * backwards in our path and try to find a suitable -+ * job to remove. We use the marker to find our way -+ * back, since smart how we are we stored our way back -+ * in there. */ -+ log_warning("Found ordering cycle on %s/%s", j->unit->id, job_type_to_string(j->type)); -+ -+ delete = NULL; -+ for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) { -+ -+ log_info("Walked on cycle path to %s/%s", k->unit->id, job_type_to_string(k->type)); -+ -+ if (!delete && -+ !k->installed && -+ !unit_matters_to_anchor(k->unit, k)) { -+ /* Ok, we can drop this one, so let's -+ * do so. */ -+ delete = k; -+ } -+ -+ /* Check if this in fact was the beginning of -+ * the cycle */ -+ if (k == j) -+ break; -+ } -+ -+ -+ if (delete) { -+ log_warning("Breaking ordering cycle by deleting job %s/%s", delete->unit->id, job_type_to_string(delete->type)); -+ transaction_delete_unit(tr, delete->unit); -+ return -EAGAIN; -+ } -+ -+ log_error("Unable to break cycle"); -+ -+ dbus_set_error(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, "Transaction order is cyclic. See system logs for details."); -+ return -ENOEXEC; -+ } -+ -+ /* Make the marker point to where we come from, so that we can -+ * find our way backwards if we want to break a cycle. We use -+ * a special marker for the beginning: we point to -+ * ourselves. */ -+ j->marker = from ? from : j; -+ j->generation = generation; -+ -+ /* We assume that the the dependencies are bidirectional, and -+ * hence can ignore UNIT_AFTER */ -+ SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) { -+ Job *o; -+ -+ /* Is there a job for this unit? */ -+ o = hashmap_get(tr->jobs, u); -+ if (!o) { -+ /* Ok, there is no job for this in the -+ * transaction, but maybe there is already one -+ * running? */ -+ o = u->job; -+ if (!o) -+ continue; -+ } -+ -+ r = transaction_verify_order_one(tr, o, j, generation, e); -+ if (r < 0) -+ return r; -+ } -+ -+ /* Ok, let's backtrack, and remember that this entry is not on -+ * our path anymore. */ -+ j->marker = NULL; -+ -+ return 0; -+} -+ -+static int transaction_verify_order(Transaction *tr, unsigned *generation, DBusError *e) { -+ Job *j; -+ int r; -+ Iterator i; -+ unsigned g; -+ -+ assert(tr); -+ assert(generation); -+ -+ /* Check if the ordering graph is cyclic. If it is, try to fix -+ * that up by dropping one of the jobs. */ -+ -+ g = (*generation)++; -+ -+ HASHMAP_FOREACH(j, tr->jobs, i) -+ if ((r = transaction_verify_order_one(tr, j, NULL, g, e)) < 0) -+ return r; -+ -+ return 0; -+} -+ -+static void transaction_collect_garbage(Transaction *tr) { -+ bool again; -+ -+ assert(tr); -+ -+ /* Drop jobs that are not required by any other job */ -+ -+ do { -+ Iterator i; -+ Job *j; -+ -+ again = false; -+ -+ HASHMAP_FOREACH(j, tr->jobs, i) { -+ if (j->object_list) { -+ /* log_debug("Keeping job %s/%s because of %s/%s", */ -+ /* j->unit->id, job_type_to_string(j->type), */ -+ /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */ -+ /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */ -+ continue; -+ } -+ -+ /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */ -+ transaction_delete_job(tr, j, true); -+ again = true; -+ break; -+ } -+ -+ } while (again); -+} -+ -+static int transaction_is_destructive(Transaction *tr, DBusError *e) { -+ Iterator i; -+ Job *j; -+ -+ assert(tr); -+ -+ /* Checks whether applying this transaction means that -+ * existing jobs would be replaced */ -+ -+ HASHMAP_FOREACH(j, tr->jobs, i) { -+ -+ /* Assume merged */ -+ assert(!j->transaction_prev); -+ assert(!j->transaction_next); -+ -+ if (j->unit->job && -+ j->unit->job != j && -+ !job_type_is_superset(j->type, j->unit->job->type)) { -+ -+ dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive."); -+ return -EEXIST; -+ } -+ } -+ -+ return 0; -+} -+ -+static void transaction_minimize_impact(Transaction *tr) { -+ bool again; -+ assert(tr); -+ -+ /* Drops all unnecessary jobs that reverse already active jobs -+ * or that stop a running service. */ -+ -+ do { -+ Job *j; -+ Iterator i; -+ -+ again = false; -+ -+ HASHMAP_FOREACH(j, tr->jobs, i) { -+ LIST_FOREACH(transaction, j, j) { -+ bool stops_running_service, changes_existing_job; -+ -+ /* If it matters, we shouldn't drop it */ -+ if (j->matters_to_anchor) -+ continue; -+ -+ /* Would this stop a running service? -+ * Would this change an existing job? -+ * If so, let's drop this entry */ -+ -+ stops_running_service = -+ j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit)); -+ -+ changes_existing_job = -+ j->unit->job && -+ job_type_is_conflicting(j->type, j->unit->job->type); -+ -+ if (!stops_running_service && !changes_existing_job) -+ continue; -+ -+ if (stops_running_service) -+ log_debug("%s/%s would stop a running service.", j->unit->id, job_type_to_string(j->type)); -+ -+ if (changes_existing_job) -+ log_debug("%s/%s would change existing job.", j->unit->id, job_type_to_string(j->type)); -+ -+ /* Ok, let's get rid of this */ -+ log_debug("Deleting %s/%s to minimize impact.", j->unit->id, job_type_to_string(j->type)); -+ -+ transaction_delete_job(tr, j, true); -+ again = true; -+ break; -+ } -+ -+ if (again) -+ break; -+ } -+ -+ } while (again); -+} -+ -+static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { -+ Iterator i; -+ Job *j; -+ int r; -+ -+ /* Moves the transaction jobs to the set of active jobs */ -+ -+ if (mode == JOB_ISOLATE) { -+ -+ /* 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(tr->jobs, j->unit)) -+ continue; -+ -+ /* '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; -+ } -+ } -+ -+ HASHMAP_FOREACH(j, tr->jobs, i) { -+ /* Assume merged */ -+ assert(!j->transaction_prev); -+ assert(!j->transaction_next); -+ -+ if (j->installed) -+ continue; -+ -+ r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j); -+ if (r < 0) -+ goto rollback; -+ } -+ -+ while ((j = hashmap_steal_first(tr->jobs))) { -+ Job *uj; -+ if (j->installed) { -+ /* log_debug("Skipping already installed job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); */ -+ continue; -+ } -+ -+ uj = j->unit->job; -+ if (uj) { -+ job_uninstall(uj); -+ job_free(uj); -+ } -+ -+ j->unit->job = j; -+ j->installed = true; -+ m->n_installed_jobs ++; -+ -+ /* We're fully installed. Now let's free data we don't -+ * need anymore. */ -+ -+ assert(!j->transaction_next); -+ assert(!j->transaction_prev); -+ -+ /* Clean the job dependencies */ -+ transaction_unlink_job(tr, j, false); -+ -+ job_add_to_run_queue(j); -+ job_add_to_dbus_queue(j); -+ job_start_timer(j); -+ -+ log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); -+ } -+ -+ assert(!tr->anchor); -+ -+ return 0; -+ -+rollback: -+ -+ HASHMAP_FOREACH(j, tr->jobs, i) { -+ if (j->installed) -+ continue; -+ -+ hashmap_remove(m->jobs, UINT32_TO_PTR(j->id)); -+ } -+ -+ return r; -+} -+ -+int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e) { -+ int r; -+ unsigned generation = 1; -+ -+ assert(tr); -+ -+ /* This applies the changes recorded in tr->jobs to -+ * the actual list of jobs, if possible. */ -+ -+ /* First step: figure out which jobs matter */ -+ transaction_find_jobs_that_matter_to_anchor(tr, NULL, generation++); -+ -+ /* Second step: Try not to stop any running services if -+ * we don't have to. Don't try to reverse running -+ * jobs if we don't have to. */ -+ if (mode == JOB_FAIL) -+ transaction_minimize_impact(tr); -+ -+ /* Third step: Drop redundant jobs */ -+ transaction_drop_redundant(tr); -+ -+ for (;;) { -+ /* Fourth step: Let's remove unneeded jobs that might -+ * be lurking. */ -+ if (mode != JOB_ISOLATE) -+ transaction_collect_garbage(tr); -+ -+ /* Fifth step: verify order makes sense and correct -+ * cycles if necessary and possible */ -+ r = transaction_verify_order(tr, &generation, e); -+ if (r >= 0) -+ break; -+ -+ if (r != -EAGAIN) { -+ log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error(e, r)); -+ return r; -+ } -+ -+ /* Let's see if the resulting transaction ordering -+ * graph is still cyclic... */ -+ } -+ -+ for (;;) { -+ /* Sixth step: let's drop unmergeable entries if -+ * necessary and possible, merge entries we can -+ * merge */ -+ r = transaction_merge_jobs(tr, e); -+ if (r >= 0) -+ break; -+ -+ if (r != -EAGAIN) { -+ log_warning("Requested transaction contains unmergeable jobs: %s", bus_error(e, r)); -+ return r; -+ } -+ -+ /* Seventh step: an entry got dropped, let's garbage -+ * collect its dependencies. */ -+ if (mode != JOB_ISOLATE) -+ transaction_collect_garbage(tr); -+ -+ /* Let's see if the resulting transaction still has -+ * unmergeable entries ... */ -+ } -+ -+ /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */ -+ transaction_drop_redundant(tr); -+ -+ /* Ninth step: check whether we can actually apply this */ -+ if (mode == JOB_FAIL) { -+ r = transaction_is_destructive(tr, e); -+ if (r < 0) { -+ log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r)); -+ return r; -+ } -+ } -+ -+ /* Tenth step: apply changes */ -+ r = transaction_apply(tr, m, mode); -+ if (r < 0) { -+ log_warning("Failed to apply transaction: %s", strerror(-r)); -+ return r; -+ } -+ -+ assert(hashmap_isempty(tr->jobs)); -+ assert(!tr->anchor); -+ -+ return 0; -+} -+ -+static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) { -+ Job *j, *f; -+ -+ assert(tr); -+ assert(unit); -+ -+ /* Looks for an existing prospective job and returns that. If -+ * it doesn't exist it is created and added to the prospective -+ * jobs list. */ -+ -+ f = hashmap_get(tr->jobs, unit); -+ -+ LIST_FOREACH(transaction, j, f) { -+ assert(j->unit == unit); -+ -+ if (j->type == type) { -+ if (is_new) -+ *is_new = false; -+ return j; -+ } -+ } -+ -+ if (unit->job && unit->job->type == type) -+ j = unit->job; -+ else { -+ j = job_new(unit->manager, type, unit); -+ if (!j) -+ return NULL; -+ } -+ -+ j->generation = 0; -+ j->marker = NULL; -+ j->matters_to_anchor = false; -+ j->override = override; -+ -+ LIST_PREPEND(Job, transaction, f, j); -+ -+ if (hashmap_replace(tr->jobs, unit, f) < 0) { -+ LIST_REMOVE(Job, transaction, f, j); -+ job_free(j); -+ return NULL; -+ } -+ -+ if (is_new) -+ *is_new = true; -+ -+ /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */ -+ -+ return j; -+} -+ -+static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) { -+ assert(tr); -+ assert(j); -+ -+ if (j->transaction_prev) -+ j->transaction_prev->transaction_next = j->transaction_next; -+ else if (j->transaction_next) -+ hashmap_replace(tr->jobs, j->unit, j->transaction_next); -+ else -+ hashmap_remove_value(tr->jobs, j->unit, j); -+ -+ if (j->transaction_next) -+ j->transaction_next->transaction_prev = j->transaction_prev; -+ -+ j->transaction_prev = j->transaction_next = NULL; -+ -+ while (j->subject_list) -+ job_dependency_free(j->subject_list, tr); -+ -+ while (j->object_list) { -+ Job *other = j->object_list->matters ? j->object_list->subject : NULL; -+ -+ job_dependency_free(j->object_list, tr); -+ -+ if (other && delete_dependencies) { -+ log_debug("Deleting job %s/%s as dependency of job %s/%s", -+ other->unit->id, job_type_to_string(other->type), -+ j->unit->id, job_type_to_string(j->type)); -+ transaction_delete_job(tr, other, delete_dependencies); -+ } -+ } -+} -+ -+int transaction_add_job_and_dependencies( -+ Transaction *tr, -+ JobType type, -+ Unit *unit, -+ Job *by, -+ bool matters, -+ bool override, -+ bool conflicts, -+ bool ignore_requirements, -+ bool ignore_order, -+ DBusError *e, -+ Job **_ret) { -+ Job *ret; -+ Iterator i; -+ Unit *dep; -+ int r; -+ bool is_new; -+ -+ assert(tr); -+ assert(type < _JOB_TYPE_MAX); -+ assert(unit); -+ -+ /* log_debug("Pulling in %s/%s from %s/%s", */ -+ /* unit->id, job_type_to_string(type), */ -+ /* by ? by->unit->id : "NA", */ -+ /* by ? job_type_to_string(by->type) : "NA"); */ -+ -+ if (unit->load_state != UNIT_LOADED && -+ unit->load_state != UNIT_ERROR && -+ unit->load_state != UNIT_MASKED) { -+ dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id); -+ return -EINVAL; -+ } -+ -+ if (type != JOB_STOP && unit->load_state == UNIT_ERROR) { -+ dbus_set_error(e, BUS_ERROR_LOAD_FAILED, -+ "Unit %s failed to load: %s. " -+ "See system logs and 'systemctl status %s' for details.", -+ unit->id, -+ strerror(-unit->load_error), -+ unit->id); -+ return -EINVAL; -+ } -+ -+ if (type != JOB_STOP && unit->load_state == UNIT_MASKED) { -+ dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->id); -+ return -EINVAL; -+ } -+ -+ if (!unit_job_is_applicable(unit, type)) { -+ dbus_set_error(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->id); -+ return -EBADR; -+ } -+ -+ /* First add the job. */ -+ ret = transaction_add_one_job(tr, type, unit, override, &is_new); -+ if (!ret) -+ return -ENOMEM; -+ -+ ret->ignore_order = ret->ignore_order || ignore_order; -+ -+ /* Then, add a link to the job. */ -+ if (!job_dependency_new(by, ret, matters, conflicts, tr)) -+ return -ENOMEM; -+ -+ if (is_new && !ignore_requirements) { -+ Set *following; -+ -+ /* If we are following some other unit, make sure we -+ * add all dependencies of everybody following. */ -+ if (unit_following_set(ret->unit, &following) > 0) { -+ SET_FOREACH(dep, following, i) { -+ r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { -+ log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -+ -+ if (e) -+ dbus_error_free(e); -+ } -+ } -+ -+ set_free(following); -+ } -+ -+ /* Finally, recursively add in all dependencies. */ -+ if (type == JOB_START || type == JOB_RELOAD_OR_START) { -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { -+ if (r != -EBADR) -+ goto fail; -+ -+ if (e) -+ dbus_error_free(e); -+ } -+ } -+ -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_BIND_TO], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { -+ if (r != -EBADR) -+ goto fail; -+ -+ if (e) -+ dbus_error_free(e); -+ } -+ } -+ -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { -+ log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -+ -+ if (e) -+ dbus_error_free(e); -+ } -+ } -+ -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e, NULL); -+ if (r < 0) { -+ log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -+ -+ if (e) -+ dbus_error_free(e); -+ } -+ } -+ -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { -+ if (r != -EBADR) -+ goto fail; -+ -+ if (e) -+ dbus_error_free(e); -+ } -+ } -+ -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { -+ log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -+ -+ if (e) -+ dbus_error_free(e); -+ } -+ } -+ -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e, NULL); -+ if (r < 0) { -+ if (r != -EBADR) -+ goto fail; -+ -+ if (e) -+ dbus_error_free(e); -+ } -+ } -+ -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { -+ log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -+ -+ if (e) -+ dbus_error_free(e); -+ } -+ } -+ -+ } -+ -+ if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) { -+ -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) { -+ r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { -+ if (r != -EBADR) -+ goto fail; -+ -+ if (e) -+ dbus_error_free(e); -+ } -+ } -+ -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) { -+ r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { -+ if (r != -EBADR) -+ goto fail; -+ -+ if (e) -+ dbus_error_free(e); -+ } -+ } -+ } -+ -+ if (type == JOB_RELOAD || type == JOB_RELOAD_OR_START) { -+ -+ SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATE_RELOAD_TO], i) { -+ r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e, NULL); -+ if (r < 0) { -+ log_warning("Cannot add dependency reload job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -+ -+ if (e) -+ dbus_error_free(e); -+ } -+ } -+ } -+ -+ /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */ -+ } -+ -+ if (_ret) -+ *_ret = ret; -+ -+ return 0; -+ -+fail: -+ return r; -+} -+ -+int transaction_add_isolate_jobs(Transaction *tr, Manager *m) { -+ Iterator i; -+ Unit *u; -+ char *k; -+ int r; -+ -+ assert(tr); -+ assert(m); -+ -+ HASHMAP_FOREACH_KEY(u, k, m->units, i) { -+ -+ /* ignore aliases */ -+ if (u->id != k) -+ continue; -+ -+ if (u->ignore_on_isolate) -+ continue; -+ -+ /* No need to stop inactive jobs */ -+ if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job) -+ continue; -+ -+ /* Is there already something listed for this? */ -+ if (hashmap_get(tr->jobs, u)) -+ continue; -+ -+ r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, NULL, true, false, false, false, false, NULL, NULL); -+ if (r < 0) -+ log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->id, strerror(-r)); -+ } -+ -+ return 0; -+} -+ -+Transaction *transaction_new(void) { -+ Transaction *tr; -+ -+ tr = new0(Transaction, 1); -+ if (!tr) -+ return NULL; -+ -+ tr->jobs = hashmap_new(trivial_hash_func, trivial_compare_func); -+ if (!tr->jobs) { -+ free(tr); -+ return NULL; -+ } -+ -+ return tr; -+} -+ -+void transaction_free(Transaction *tr) { -+ assert(hashmap_isempty(tr->jobs)); -+ hashmap_free(tr->jobs); -+ free(tr); -+} -diff --git a/src/transaction.h b/src/transaction.h -new file mode 100644 -index 0000000..d519ffb ---- /dev/null -+++ b/src/transaction.h -@@ -0,0 +1,36 @@ -+#ifndef footransactionhfoo -+#define footransactionhfoo -+ -+typedef struct Transaction Transaction; -+ -+#include "unit.h" -+#include "manager.h" -+#include "job.h" -+#include "hashmap.h" -+ -+struct Transaction { -+ /* Jobs to be added */ -+ Hashmap *jobs; /* Unit object => Job object list 1:1 */ -+ JobDependency *anchor; -+}; -+ -+Transaction *transaction_new(void); -+void transaction_free(Transaction *tr); -+ -+int transaction_add_job_and_dependencies( -+ Transaction *tr, -+ JobType type, -+ Unit *unit, -+ Job *by, -+ bool matters, -+ bool override, -+ bool conflicts, -+ bool ignore_requirements, -+ bool ignore_order, -+ DBusError *e, -+ Job **_ret); -+int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e); -+int transaction_add_isolate_jobs(Transaction *tr, Manager *m); -+void transaction_abort(Transaction *tr); -+ -+#endif --- -1.7.7 - - -From bd61057f3d44d7bb4e279310a16646eb8ab9bb8c Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Wed, 18 Apr 2012 01:39:20 +0200 -Subject: [PATCH 09/30] job: job_new() can find the manager from the unit - (cherry picked from commit - 668ad332a404736474749cbcc8404af3e4447170) - ---- - src/job.c | 7 +++---- - src/job.h | 2 +- - src/transaction.c | 2 +- - 3 files changed, 5 insertions(+), 6 deletions(-) - -diff --git a/src/job.c b/src/job.c -index 6d48748..c30bfda 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -33,18 +33,17 @@ - #include "log.h" - #include "dbus-job.h" - --Job* job_new(Manager *m, JobType type, Unit *unit) { -+Job* job_new(Unit *unit, JobType type) { - Job *j; - -- assert(m); - assert(type < _JOB_TYPE_MAX); - assert(unit); - - if (!(j = new0(Job, 1))) - return NULL; - -- j->manager = m; -- j->id = m->current_job_id++; -+ j->manager = unit->manager; -+ j->id = j->manager->current_job_id++; - j->type = type; - j->unit = unit; - -diff --git a/src/job.h b/src/job.h -index efb0af9..faa10e3 100644 ---- a/src/job.h -+++ b/src/job.h -@@ -137,7 +137,7 @@ struct Job { - bool ignore_order:1; - }; - --Job* job_new(Manager *m, JobType type, Unit *unit); -+Job* job_new(Unit *unit, JobType type); - void job_uninstall(Job *j); - void job_free(Job *job); - void job_dump(Job *j, FILE*f, const char *prefix); -diff --git a/src/transaction.c b/src/transaction.c -index 8fa89a7..1344e2f 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -763,7 +763,7 @@ static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, b - if (unit->job && unit->job->type == type) - j = unit->job; - else { -- j = job_new(unit->manager, type, unit); -+ j = job_new(unit, type); - if (!j) - return NULL; - } --- -1.7.7 - - -From 0d6df78cb48dfbd1c37444ee3702ba59d87ca352 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Wed, 18 Apr 2012 15:21:24 +0200 -Subject: [PATCH 10/30] job: jobs shouldn't need to know about transaction - anchors - -Let the transactions maintain their own anchor links. -(cherry picked from commit 1da4264fbd0fa5e6b1bd5e0ac4674a3503774369) ---- - src/job.c | 8 ++------ - src/job.h | 5 ++--- - src/transaction.c | 18 +++++++++++++++--- - 3 files changed, 19 insertions(+), 12 deletions(-) - -diff --git a/src/job.c b/src/job.c -index c30bfda..a5ce2d4 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -96,7 +96,7 @@ void job_free(Job *j) { - free(j); - } - --JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts, Transaction *tr) { -+JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) { - JobDependency *l; - - assert(object); -@@ -116,21 +116,17 @@ JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool - - if (subject) - LIST_PREPEND(JobDependency, subject, subject->subject_list, l); -- else -- LIST_PREPEND(JobDependency, subject, tr->anchor, l); - - LIST_PREPEND(JobDependency, object, object->object_list, l); - - return l; - } - --void job_dependency_free(JobDependency *l, Transaction *tr) { -+void job_dependency_free(JobDependency *l) { - assert(l); - - if (l->subject) - LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l); -- else -- LIST_REMOVE(JobDependency, subject, tr->anchor, l); - - LIST_REMOVE(JobDependency, object, l->object->object_list, l); - -diff --git a/src/job.h b/src/job.h -index faa10e3..cbd10c5 100644 ---- a/src/job.h -+++ b/src/job.h -@@ -34,7 +34,6 @@ typedef enum JobMode JobMode; - typedef enum JobResult JobResult; - - #include "manager.h" --#include "transaction.h" - #include "unit.h" - #include "hashmap.h" - #include "list.h" -@@ -142,8 +141,8 @@ void job_uninstall(Job *j); - void job_free(Job *job); - void job_dump(Job *j, FILE*f, const char *prefix); - --JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts, Transaction *tr); --void job_dependency_free(JobDependency *l, Transaction *tr); -+JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts); -+void job_dependency_free(JobDependency *l); - - bool job_is_anchor(Job *j); - -diff --git a/src/transaction.c b/src/transaction.c -index 1344e2f..2a6f1de 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -789,6 +789,12 @@ static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, b - return j; - } - -+static void transaction_job_dependency_free(Transaction *tr, JobDependency *l) { -+ if (!l->subject) -+ LIST_REMOVE(JobDependency, subject, tr->anchor, l); -+ job_dependency_free(l); -+} -+ - static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) { - assert(tr); - assert(j); -@@ -806,12 +812,12 @@ static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependen - j->transaction_prev = j->transaction_next = NULL; - - while (j->subject_list) -- job_dependency_free(j->subject_list, tr); -+ transaction_job_dependency_free(tr, j->subject_list); - - while (j->object_list) { - Job *other = j->object_list->matters ? j->object_list->subject : NULL; - -- job_dependency_free(j->object_list, tr); -+ transaction_job_dependency_free(tr, j->object_list); - - if (other && delete_dependencies) { - log_debug("Deleting job %s/%s as dependency of job %s/%s", -@@ -835,6 +841,7 @@ int transaction_add_job_and_dependencies( - DBusError *e, - Job **_ret) { - Job *ret; -+ JobDependency *l; - Iterator i; - Unit *dep; - int r; -@@ -884,9 +891,14 @@ int transaction_add_job_and_dependencies( - ret->ignore_order = ret->ignore_order || ignore_order; - - /* Then, add a link to the job. */ -- if (!job_dependency_new(by, ret, matters, conflicts, tr)) -+ l = job_dependency_new(by, ret, matters, conflicts); -+ if (!l) - return -ENOMEM; - -+ /* If the link has no subject job, it's the anchor link. */ -+ if (!by) -+ LIST_PREPEND(JobDependency, subject, tr->anchor, l); -+ - if (is_new && !ignore_requirements) { - Set *following; - --- -1.7.7 - - -From 0799fe0aa4a9e74a0a11cedeb76a630c6db853d5 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Wed, 18 Apr 2012 18:15:49 +0200 -Subject: [PATCH 11/30] transaction: do not add installed jobs to the - transaction - -Do not attempt to optimize away the job creation by refering to installed jobs. -We do not want to disturb installed jobs until commiting the transaction. - -(A later patch to job merging will make the separation of transaction jobs and -installed jobs complete.) -(cherry picked from commit 3c956cfee29fe2642fbe257f55adb3583a4af878) ---- - src/transaction.c | 10 +++------- - 1 files changed, 3 insertions(+), 7 deletions(-) - -diff --git a/src/transaction.c b/src/transaction.c -index 2a6f1de..c00dd45 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -760,13 +760,9 @@ static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, b - } - } - -- if (unit->job && unit->job->type == type) -- j = unit->job; -- else { -- j = job_new(unit, type); -- if (!j) -- return NULL; -- } -+ j = job_new(unit, type); -+ if (!j) -+ return NULL; - - j->generation = 0; - j->marker = NULL; --- -1.7.7 - - -From 7f60fce10d4c111bcd274d0fcd83a0139b53a9bc Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Fri, 20 Apr 2012 00:33:26 +0200 -Subject: [PATCH 12/30] transaction: maintain anchor_job - -Track which job is the anchor in the transaction. -(cherry picked from commit b94fbd30781d7533492cec65bf7d86fa19a1a074) ---- - src/manager.c | 7 +++---- - src/transaction.c | 37 ++++++++++++++++++------------------- - src/transaction.h | 4 ++-- - 3 files changed, 23 insertions(+), 25 deletions(-) - -diff --git a/src/manager.c b/src/manager.c -index a129b88..86ec858 100644 ---- a/src/manager.c -+++ b/src/manager.c -@@ -631,7 +631,6 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { - - int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *e, Job **_ret) { - int r; -- Job *ret; - Transaction *tr; - - assert(m); -@@ -657,7 +656,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove - - r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false, - mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS, -- mode == JOB_IGNORE_DEPENDENCIES, e, &ret); -+ mode == JOB_IGNORE_DEPENDENCIES, e); - if (r < 0) - goto tr_abort; - -@@ -671,10 +670,10 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove - if (r < 0) - goto tr_abort; - -- log_debug("Enqueued job %s/%s as %u", unit->id, job_type_to_string(type), (unsigned) ret->id); -+ log_debug("Enqueued job %s/%s as %u", unit->id, job_type_to_string(type), (unsigned) tr->anchor_job->id); - - if (_ret) -- *_ret = ret; -+ *_ret = tr->anchor_job; - - transaction_free(tr); - return 0; -diff --git a/src/transaction.c b/src/transaction.c -index c00dd45..d7ecfdb 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -834,8 +834,7 @@ int transaction_add_job_and_dependencies( - bool conflicts, - bool ignore_requirements, - bool ignore_order, -- DBusError *e, -- Job **_ret) { -+ DBusError *e) { - Job *ret; - JobDependency *l; - Iterator i; -@@ -892,8 +891,11 @@ int transaction_add_job_and_dependencies( - return -ENOMEM; - - /* If the link has no subject job, it's the anchor link. */ -- if (!by) -+ if (!by) { - LIST_PREPEND(JobDependency, subject, tr->anchor, l); -+ if (!tr->anchor_job) -+ tr->anchor_job = ret; -+ } - - if (is_new && !ignore_requirements) { - Set *following; -@@ -902,7 +904,7 @@ int transaction_add_job_and_dependencies( - * add all dependencies of everybody following. */ - if (unit_following_set(ret->unit, &following) > 0) { - SET_FOREACH(dep, following, i) { -- r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e, NULL); -+ r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e); - if (r < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - -@@ -917,7 +919,7 @@ int transaction_add_job_and_dependencies( - /* Finally, recursively add in all dependencies. */ - if (type == JOB_START || type == JOB_RELOAD_OR_START) { - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e); - if (r < 0) { - if (r != -EBADR) - goto fail; -@@ -928,7 +930,7 @@ int transaction_add_job_and_dependencies( - } - - SET_FOREACH(dep, ret->unit->dependencies[UNIT_BIND_TO], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e); - if (r < 0) { - if (r != -EBADR) - goto fail; -@@ -939,7 +941,7 @@ int transaction_add_job_and_dependencies( - } - - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e, NULL); -+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e); - if (r < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - -@@ -949,7 +951,7 @@ int transaction_add_job_and_dependencies( - } - - SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e, NULL); -+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e); - if (r < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - -@@ -959,7 +961,7 @@ int transaction_add_job_and_dependencies( - } - - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e); - if (r < 0) { - if (r != -EBADR) - goto fail; -@@ -970,7 +972,7 @@ int transaction_add_job_and_dependencies( - } - - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e, NULL); -+ r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e); - if (r < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - -@@ -980,7 +982,7 @@ int transaction_add_job_and_dependencies( - } - - SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e, NULL); -+ r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e); - if (r < 0) { - if (r != -EBADR) - goto fail; -@@ -991,7 +993,7 @@ int transaction_add_job_and_dependencies( - } - - SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e, NULL); -+ r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e); - if (r < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - -@@ -1005,7 +1007,7 @@ int transaction_add_job_and_dependencies( - if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) { - - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) { -- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e); - if (r < 0) { - if (r != -EBADR) - goto fail; -@@ -1016,7 +1018,7 @@ int transaction_add_job_and_dependencies( - } - - SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) { -- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e, NULL); -+ r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e); - if (r < 0) { - if (r != -EBADR) - goto fail; -@@ -1030,7 +1032,7 @@ int transaction_add_job_and_dependencies( - if (type == JOB_RELOAD || type == JOB_RELOAD_OR_START) { - - SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATE_RELOAD_TO], i) { -- r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e, NULL); -+ r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e); - if (r < 0) { - log_warning("Cannot add dependency reload job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - -@@ -1043,9 +1045,6 @@ int transaction_add_job_and_dependencies( - /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */ - } - -- if (_ret) -- *_ret = ret; -- - return 0; - - fail: -@@ -1078,7 +1077,7 @@ int transaction_add_isolate_jobs(Transaction *tr, Manager *m) { - if (hashmap_get(tr->jobs, u)) - continue; - -- r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, NULL, true, false, false, false, false, NULL, NULL); -+ r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, NULL, true, false, false, false, false, NULL); - if (r < 0) - log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->id, strerror(-r)); - } -diff --git a/src/transaction.h b/src/transaction.h -index d519ffb..4818cea 100644 ---- a/src/transaction.h -+++ b/src/transaction.h -@@ -12,6 +12,7 @@ struct Transaction { - /* Jobs to be added */ - Hashmap *jobs; /* Unit object => Job object list 1:1 */ - JobDependency *anchor; -+ Job *anchor_job; /* the job the user asked for */ - }; - - Transaction *transaction_new(void); -@@ -27,8 +28,7 @@ int transaction_add_job_and_dependencies( - bool conflicts, - bool ignore_requirements, - bool ignore_order, -- DBusError *e, -- Job **_ret); -+ DBusError *e); - int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e); - int transaction_add_isolate_jobs(Transaction *tr, Manager *m); - void transaction_abort(Transaction *tr); --- -1.7.7 - - -From 3020dc5e2b840b8732cfdb81c322a47120a0a42f Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Fri, 20 Apr 2012 10:33:37 +0200 -Subject: [PATCH 13/30] transaction: change the linking of isolate jobs to the - anchor - -When isolating, the JOB_STOP jobs have no parent job, so they are all peers -of the real anchor job. This is a bit odd. - -Link them from the anchor job. -(cherry picked from commit 4483f694983382b4092e3e295ffb59926cff96d9) ---- - src/transaction.c | 6 +++--- - 1 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/transaction.c b/src/transaction.c -index d7ecfdb..09abe00 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -893,8 +893,8 @@ int transaction_add_job_and_dependencies( - /* If the link has no subject job, it's the anchor link. */ - if (!by) { - LIST_PREPEND(JobDependency, subject, tr->anchor, l); -- if (!tr->anchor_job) -- tr->anchor_job = ret; -+ assert(!tr->anchor_job); -+ tr->anchor_job = ret; - } - - if (is_new && !ignore_requirements) { -@@ -1077,7 +1077,7 @@ int transaction_add_isolate_jobs(Transaction *tr, Manager *m) { - if (hashmap_get(tr->jobs, u)) - continue; - -- r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, NULL, true, false, false, false, false, NULL); -+ r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL); - if (r < 0) - log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->id, strerror(-r)); - } --- -1.7.7 - - -From 1ceeee2cf56d60ac37199ba9ebbe02144200857c Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Fri, 20 Apr 2012 01:20:14 +0200 -Subject: [PATCH 14/30] transaction: simplify - transaction_find_jobs_that_matter_to_anchor() (cherry - picked from commit - 0d9989aa68963037a18fb7ed4f309f6155927d70) - ---- - src/transaction.c | 19 ++++++------------- - 1 files changed, 6 insertions(+), 13 deletions(-) - -diff --git a/src/transaction.c b/src/transaction.c -index 09abe00..cac58e6 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -38,22 +38,18 @@ void transaction_abort(Transaction *tr) { - assert(!tr->anchor); - } - --static void transaction_find_jobs_that_matter_to_anchor(Transaction *tr, Job *j, unsigned generation) { -+static void transaction_find_jobs_that_matter_to_anchor(Job *j, unsigned generation) { - JobDependency *l; - -- assert(tr); -- - /* A recursive sweep through the graph that marks all units - * that matter to the anchor job, i.e. are directly or - * indirectly a dependency of the anchor job via paths that - * are fully marked as mattering. */ - -- if (j) -- l = j->subject_list; -- else -- l = tr->anchor; -+ j->matters_to_anchor = true; -+ j->generation = generation; - -- LIST_FOREACH(subject, l, l) { -+ LIST_FOREACH(subject, l, j->subject_list) { - - /* This link does not matter */ - if (!l->matters) -@@ -63,10 +59,7 @@ static void transaction_find_jobs_that_matter_to_anchor(Transaction *tr, Job *j, - if (l->object->generation == generation) - continue; - -- l->object->matters_to_anchor = true; -- l->object->generation = generation; -- -- transaction_find_jobs_that_matter_to_anchor(tr, l->object, generation); -+ transaction_find_jobs_that_matter_to_anchor(l->object, generation); - } - } - -@@ -659,7 +652,7 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e - * the actual list of jobs, if possible. */ - - /* First step: figure out which jobs matter */ -- transaction_find_jobs_that_matter_to_anchor(tr, NULL, generation++); -+ transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++); - - /* Second step: Try not to stop any running services if - * we don't have to. Don't try to reverse running --- -1.7.7 - - -From ba088fafbe639c1a8e859406e9f82d0d8bffc804 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Fri, 20 Apr 2012 02:48:24 +0200 -Subject: [PATCH 15/30] transaction: avoid garbage collecting the anchor job - -Make sure the anchor job is never considered garbage, even if it has no links -leading to it (this will be allowed in the next patch). -(cherry picked from commit 38809d9dfed4c75d9e97c4e5da2ff957723c4cad) ---- - src/transaction.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/src/transaction.c b/src/transaction.c -index cac58e6..ddb02c0 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -454,7 +454,7 @@ static void transaction_collect_garbage(Transaction *tr) { - again = false; - - HASHMAP_FOREACH(j, tr->jobs, i) { -- if (j->object_list) { -+ if (tr->anchor_job == j || j->object_list) { - /* log_debug("Keeping job %s/%s because of %s/%s", */ - /* j->unit->id, job_type_to_string(j->type), */ - /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */ --- -1.7.7 - - -From 436271253850ec21fccfaa435fa2c6ce445721ac Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Fri, 20 Apr 2012 02:11:14 +0200 -Subject: [PATCH 16/30] transaction: remove the anchor link - -tr->anchor_job is sufficient. -(cherry picked from commit e6eda1f23efab618bb26e7015230d8552b401dc6) ---- - src/job.c | 12 ------------ - src/job.h | 2 -- - src/transaction.c | 31 ++++++++----------------------- - src/transaction.h | 1 - - 4 files changed, 8 insertions(+), 38 deletions(-) - -diff --git a/src/job.c b/src/job.c -index a5ce2d4..6b93b63 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -151,18 +151,6 @@ void job_dump(Job *j, FILE*f, const char *prefix) { - prefix, yes_no(j->override)); - } - --bool job_is_anchor(Job *j) { -- JobDependency *l; -- -- assert(j); -- -- LIST_FOREACH(object, l, j->object_list) -- if (!l->subject) -- return true; -- -- return false; --} -- - /* - * Merging is commutative, so imagine the matrix as symmetric. We store only - * its lower triangle to avoid duplication. We don't store the main diagonal, -diff --git a/src/job.h b/src/job.h -index cbd10c5..6b06c2a 100644 ---- a/src/job.h -+++ b/src/job.h -@@ -144,8 +144,6 @@ void job_dump(Job *j, FILE*f, const char *prefix); - JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts); - void job_dependency_free(JobDependency *l); - --bool job_is_anchor(Job *j); -- - int job_merge(Job *j, Job *other); - - JobType job_type_lookup_merge(JobType a, JobType b); -diff --git a/src/transaction.c b/src/transaction.c -index ddb02c0..39cfe54 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -34,8 +34,6 @@ void transaction_abort(Transaction *tr) { - transaction_delete_job(tr, j, true); - - assert(hashmap_isempty(tr->jobs)); -- -- assert(!tr->anchor); - } - - static void transaction_find_jobs_that_matter_to_anchor(Job *j, unsigned generation) { -@@ -287,7 +285,7 @@ static void transaction_drop_redundant(Transaction *tr) { - - LIST_FOREACH(transaction, k, j) { - -- if (!job_is_anchor(k) && -+ if (tr->anchor_job != k && - (k->installed || job_type_is_redundant(k->type, unit_active_state(k->unit))) && - (!k->unit->job || !job_type_is_conflicting(k->type, k->unit->job->type))) - continue; -@@ -626,8 +624,6 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { - log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); - } - -- assert(!tr->anchor); -- - return 0; - - rollback: -@@ -726,7 +722,6 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e - } - - assert(hashmap_isempty(tr->jobs)); -- assert(!tr->anchor); - - return 0; - } -@@ -778,12 +773,6 @@ static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, b - return j; - } - --static void transaction_job_dependency_free(Transaction *tr, JobDependency *l) { -- if (!l->subject) -- LIST_REMOVE(JobDependency, subject, tr->anchor, l); -- job_dependency_free(l); --} -- - static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) { - assert(tr); - assert(j); -@@ -801,12 +790,12 @@ static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependen - j->transaction_prev = j->transaction_next = NULL; - - while (j->subject_list) -- transaction_job_dependency_free(tr, j->subject_list); -+ job_dependency_free(j->subject_list); - - while (j->object_list) { - Job *other = j->object_list->matters ? j->object_list->subject : NULL; - -- transaction_job_dependency_free(tr, j->object_list); -+ job_dependency_free(j->object_list); - - if (other && delete_dependencies) { - log_debug("Deleting job %s/%s as dependency of job %s/%s", -@@ -829,7 +818,6 @@ int transaction_add_job_and_dependencies( - bool ignore_order, - DBusError *e) { - Job *ret; -- JobDependency *l; - Iterator i; - Unit *dep; - int r; -@@ -879,17 +867,14 @@ int transaction_add_job_and_dependencies( - ret->ignore_order = ret->ignore_order || ignore_order; - - /* Then, add a link to the job. */ -- l = job_dependency_new(by, ret, matters, conflicts); -- if (!l) -- return -ENOMEM; -- -- /* If the link has no subject job, it's the anchor link. */ -- if (!by) { -- LIST_PREPEND(JobDependency, subject, tr->anchor, l); -+ if (by) { -+ if (!job_dependency_new(by, ret, matters, conflicts)) -+ return -ENOMEM; -+ } else { -+ /* If the job has no parent job, it is the anchor job. */ - assert(!tr->anchor_job); - tr->anchor_job = ret; - } -- - if (is_new && !ignore_requirements) { - Set *following; - -diff --git a/src/transaction.h b/src/transaction.h -index 4818cea..74d7461 100644 ---- a/src/transaction.h -+++ b/src/transaction.h -@@ -11,7 +11,6 @@ typedef struct Transaction Transaction; - struct Transaction { - /* Jobs to be added */ - Hashmap *jobs; /* Unit object => Job object list 1:1 */ -- JobDependency *anchor; - Job *anchor_job; /* the job the user asked for */ - }; - --- -1.7.7 - - -From cdfe041c84fb813d883de58003e4a986ebde35e6 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Thu, 19 Apr 2012 23:56:26 +0200 -Subject: [PATCH 17/30] transaction: remove a couple of asserts - -We already asserted these facts in the previous loop. -(cherry picked from commit f1c2bdca422dba1bc5615f72662dee5ce69c147b) ---- - src/transaction.c | 3 --- - 1 files changed, 0 insertions(+), 3 deletions(-) - -diff --git a/src/transaction.c b/src/transaction.c -index 39cfe54..41f7b82 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -611,9 +611,6 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { - /* We're fully installed. Now let's free data we don't - * need anymore. */ - -- assert(!j->transaction_next); -- assert(!j->transaction_prev); -- - /* Clean the job dependencies */ - transaction_unlink_job(tr, j, false); - --- -1.7.7 - - -From ff3ec7f35ab49a1e306f90b33866f4dc7fba282f Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Fri, 20 Apr 2012 02:04:01 +0200 -Subject: [PATCH 18/30] job: separate job_install() - -Let the jobs install themselves. -(cherry picked from commit 05d576f1f77699ea5c2e5ed0e04451b14dfc45a0) ---- - src/job.c | 44 +++++++++++++++++++++++++++++--------------- - src/job.h | 3 ++- - src/transaction.c | 18 ++---------------- - 3 files changed, 33 insertions(+), 32 deletions(-) - -diff --git a/src/job.c b/src/job.c -index 6b93b63..c5bf9cd 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -54,21 +54,6 @@ Job* job_new(Unit *unit, JobType type) { - return j; - } - --void job_uninstall(Job *j) { -- assert(j->installed); -- /* Detach from next 'bigger' objects */ -- -- bus_job_send_removed_signal(j); -- -- if (j->unit->job == j) { -- j->unit->job = NULL; -- unit_add_to_gc_queue(j->unit); -- } -- -- hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id)); -- j->installed = false; --} -- - void job_free(Job *j) { - assert(j); - assert(!j->installed); -@@ -96,6 +81,35 @@ void job_free(Job *j) { - free(j); - } - -+void job_uninstall(Job *j) { -+ assert(j->installed); -+ /* Detach from next 'bigger' objects */ -+ -+ bus_job_send_removed_signal(j); -+ -+ if (j->unit->job == j) { -+ j->unit->job = NULL; -+ unit_add_to_gc_queue(j->unit); -+ } -+ -+ hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id)); -+ j->installed = false; -+} -+ -+void job_install(Job *j) { -+ Job *uj = j->unit->job; -+ -+ if (uj) { -+ job_uninstall(uj); -+ job_free(uj); -+ } -+ -+ j->unit->job = j; -+ j->installed = true; -+ j->manager->n_installed_jobs ++; -+ log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); -+} -+ - JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) { - JobDependency *l; - -diff --git a/src/job.h b/src/job.h -index 6b06c2a..8fa9046 100644 ---- a/src/job.h -+++ b/src/job.h -@@ -137,8 +137,9 @@ struct Job { - }; - - Job* job_new(Unit *unit, JobType type); --void job_uninstall(Job *j); - void job_free(Job *job); -+void job_install(Job *j); -+void job_uninstall(Job *j); - void job_dump(Job *j, FILE*f, const char *prefix); - - JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts); -diff --git a/src/transaction.c b/src/transaction.c -index 41f7b82..d495cbd 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -592,33 +592,19 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { - } - - while ((j = hashmap_steal_first(tr->jobs))) { -- Job *uj; - if (j->installed) { - /* log_debug("Skipping already installed job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); */ - continue; - } - -- uj = j->unit->job; -- if (uj) { -- job_uninstall(uj); -- job_free(uj); -- } -- -- j->unit->job = j; -- j->installed = true; -- m->n_installed_jobs ++; -- -- /* We're fully installed. Now let's free data we don't -- * need anymore. */ -- - /* Clean the job dependencies */ - transaction_unlink_job(tr, j, false); - -+ job_install(j); -+ - job_add_to_run_queue(j); - job_add_to_dbus_queue(j); - job_start_timer(j); -- -- log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); - } - - return 0; --- -1.7.7 - - -From 78c1339da1446bac0f4a5fbb0f1add66a6246bec Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Fri, 20 Apr 2012 09:38:43 +0200 -Subject: [PATCH 19/30] transaction: rework merging with installed jobs - -Previously transactions could reference installed jobs. It made some issues -difficult to fix. - -This sets new rules for jobs: -A job cannot be both a member of a transaction and installed. When jobs are -created, they are linked to a transaction. The whole transaction is constructed -(with merging of jobs within, etc.). When it's complete, all the jobs are -unlinked from it one by one and let to install themselves. It is during the -installation when merging with previously installed jobs (from older -transactions) is contemplated. - -Merging with installed jobs has different rules than merging within a -transaction: - - An installed conflicting job gets cancelled. It cannot be simply deleted, - because someone might be waiting for its completion on DBus. - - An installed, but still waiting, job can be safely merged into. - - An installed and running job can be tricky. For some job types it is safe to - just merge. For the other types we merge anyway, but put the job back into - JOB_WAITING to allow it to run again. This may be suboptimal, but it is not - currently possible to have more than one installed job for a unit. - -Note this also fixes a bug where the anchor job could be deleted during merging -within the transaction. -(cherry picked from commit 656bbffc6c45bdd8d5c28a96ca948ba16c546547) ---- - src/job.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++-- - src/job.h | 2 +- - src/transaction.c | 21 +++++++++++-------- - 3 files changed, 68 insertions(+), 13 deletions(-) - -diff --git a/src/job.c b/src/job.c -index c5bf9cd..e6737df 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -96,18 +96,70 @@ void job_uninstall(Job *j) { - j->installed = false; - } - --void job_install(Job *j) { -+static bool job_type_allows_late_merge(JobType t) { -+ /* Tells whether it is OK to merge a job of type 't' with an already -+ * running job. -+ * Reloads cannot be merged this way. Think of the sequence: -+ * 1. Reload of a daemon is in progress; the daemon has already loaded -+ * its config file, but hasn't completed the reload operation yet. -+ * 2. Edit foo's config file. -+ * 3. Trigger another reload to have the daemon use the new config. -+ * Should the second reload job be merged into the first one, the daemon -+ * would not know about the new config. -+ * JOB_RESTART jobs on the other hand can be merged, because they get -+ * patched into JOB_START after stopping the unit. So if we see a -+ * JOB_RESTART running, it means the unit hasn't stopped yet and at -+ * this time the merge is still allowed. */ -+ return !(t == JOB_RELOAD || t == JOB_RELOAD_OR_START); -+} -+ -+static void job_merge_into_installed(Job *j, Job *other) { -+ assert(j->installed); -+ assert(j->unit == other->unit); -+ -+ j->type = job_type_lookup_merge(j->type, other->type); -+ assert(j->type >= 0); -+ -+ j->override = j->override || other->override; -+} -+ -+Job* job_install(Job *j) { - Job *uj = j->unit->job; - -+ assert(!j->installed); -+ - if (uj) { -- job_uninstall(uj); -- job_free(uj); -+ if (job_type_is_conflicting(uj->type, j->type)) -+ job_finish_and_invalidate(uj, JOB_CANCELED); -+ else { -+ /* not conflicting, i.e. mergeable */ -+ -+ if (uj->state == JOB_WAITING || -+ (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) { -+ job_merge_into_installed(uj, j); -+ log_debug("Merged into installed job %s/%s as %u", -+ uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id); -+ return uj; -+ } else { -+ /* already running and not safe to merge into */ -+ /* Patch uj to become a merged job and re-run it. */ -+ /* XXX It should be safer to queue j to run after uj finishes, but it is -+ * not currently possible to have more than one installed job per unit. */ -+ job_merge_into_installed(uj, j); -+ log_debug("Merged into running job, re-running: %s/%s as %u", -+ uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id); -+ uj->state = JOB_WAITING; -+ return uj; -+ } -+ } - } - -+ /* Install the job */ - j->unit->job = j; - j->installed = true; - j->manager->n_installed_jobs ++; - log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); -+ return j; - } - - JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) { -diff --git a/src/job.h b/src/job.h -index 8fa9046..eab0e07 100644 ---- a/src/job.h -+++ b/src/job.h -@@ -138,7 +138,7 @@ struct Job { - - Job* job_new(Unit *unit, JobType type); - void job_free(Job *job); --void job_install(Job *j); -+Job* job_install(Job *j); - void job_uninstall(Job *j); - void job_dump(Job *j, FILE*f, const char *prefix); - -diff --git a/src/transaction.c b/src/transaction.c -index d495cbd..aa0cedf 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -243,21 +243,14 @@ static int transaction_merge_jobs(Transaction *tr, DBusError *e) { - LIST_FOREACH(transaction, k, j->transaction_next) - assert_se(job_type_merge(&t, k->type) == 0); - -- /* If an active job is mergeable, merge it too */ -- if (j->unit->job) -- job_type_merge(&t, j->unit->job->type); /* Might fail. Which is OK */ -- - while ((k = j->transaction_next)) { -- if (j->installed) { -+ if (tr->anchor_job == k) { - transaction_merge_and_delete_job(tr, k, j, t); - j = k; - } else - transaction_merge_and_delete_job(tr, j, k, t); - } - -- if (j->unit->job && !j->installed) -- transaction_merge_and_delete_job(tr, j, j->unit->job, t); -- - assert(!j->transaction_next); - assert(!j->transaction_prev); - } -@@ -592,6 +585,8 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { - } - - while ((j = hashmap_steal_first(tr->jobs))) { -+ Job *installed_job; -+ - if (j->installed) { - /* log_debug("Skipping already installed job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); */ - continue; -@@ -600,7 +595,15 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { - /* Clean the job dependencies */ - transaction_unlink_job(tr, j, false); - -- job_install(j); -+ installed_job = job_install(j); -+ if (installed_job != j) { -+ /* j has been merged into a previously installed job */ -+ if (tr->anchor_job == j) -+ tr->anchor_job = installed_job; -+ hashmap_remove(m->jobs, UINT32_TO_PTR(j->id)); -+ job_free(j); -+ j = installed_job; -+ } - - job_add_to_run_queue(j); - job_add_to_dbus_queue(j); --- -1.7.7 - - -From 3d47dab6ed99778f9812ec4039135feb950f02da Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Fri, 20 Apr 2012 10:02:05 +0200 -Subject: [PATCH 20/30] transaction: remove checks for installed - -Transactions cannot contain installed jobs anymore. Remove the now pointless -checks. -(cherry picked from commit d6a093d098054b6fe866441251ad9485c9e31584) ---- - src/job.c | 7 +++---- - src/transaction.c | 21 +++------------------ - 2 files changed, 6 insertions(+), 22 deletions(-) - -diff --git a/src/job.c b/src/job.c -index e6737df..fb759a5 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -83,14 +83,13 @@ void job_free(Job *j) { - - void job_uninstall(Job *j) { - assert(j->installed); -+ assert(j->unit->job == j); - /* Detach from next 'bigger' objects */ - - bus_job_send_removed_signal(j); - -- if (j->unit->job == j) { -- j->unit->job = NULL; -- unit_add_to_gc_queue(j->unit); -- } -+ j->unit->job = NULL; -+ unit_add_to_gc_queue(j->unit); - - hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id)); - j->installed = false; -diff --git a/src/transaction.c b/src/transaction.c -index aa0cedf..c3e1e13 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -11,8 +11,7 @@ static void transaction_delete_job(Transaction *tr, Job *j, bool delete_dependen - - transaction_unlink_job(tr, j, delete_dependencies); - -- if (!j->installed) -- job_free(j); -+ job_free(j); - } - - static void transaction_delete_unit(Transaction *tr, Unit *u) { -@@ -279,7 +278,7 @@ static void transaction_drop_redundant(Transaction *tr) { - LIST_FOREACH(transaction, k, j) { - - if (tr->anchor_job != k && -- (k->installed || job_type_is_redundant(k->type, unit_active_state(k->unit))) && -+ job_type_is_redundant(k->type, unit_active_state(k->unit)) && - (!k->unit->job || !job_type_is_conflicting(k->type, k->unit->job->type))) - continue; - -@@ -349,7 +348,6 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi - log_info("Walked on cycle path to %s/%s", k->unit->id, job_type_to_string(k->type)); - - if (!delete && -- !k->installed && - !unit_matters_to_anchor(k->unit, k)) { - /* Ok, we can drop this one, so let's - * do so. */ -@@ -478,7 +476,6 @@ static int transaction_is_destructive(Transaction *tr, DBusError *e) { - assert(!j->transaction_next); - - if (j->unit->job && -- j->unit->job != j && - !job_type_is_superset(j->type, j->unit->job->type)) { - - dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive."); -@@ -576,9 +573,6 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { - assert(!j->transaction_prev); - assert(!j->transaction_next); - -- if (j->installed) -- continue; -- - r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j); - if (r < 0) - goto rollback; -@@ -587,11 +581,6 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { - while ((j = hashmap_steal_first(tr->jobs))) { - Job *installed_job; - -- if (j->installed) { -- /* log_debug("Skipping already installed job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); */ -- continue; -- } -- - /* Clean the job dependencies */ - transaction_unlink_job(tr, j, false); - -@@ -614,12 +603,8 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { - - rollback: - -- HASHMAP_FOREACH(j, tr->jobs, i) { -- if (j->installed) -- continue; -- -+ HASHMAP_FOREACH(j, tr->jobs, i) - hashmap_remove(m->jobs, UINT32_TO_PTR(j->id)); -- } - - return r; - } --- -1.7.7 - - -From 55284fc0ba28bf10d4fa535a86921bad23505c96 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Fri, 20 Apr 2012 12:28:31 +0200 -Subject: [PATCH 21/30] dbus-job: allow multiple bus clients - -Merging of jobs can result in more than one client being interested in a job. -(cherry picked from commit 97e6a11996855800f68dc41c13537784198c8b61) ---- - src/dbus-job.c | 146 +++++++++++++++++++++++++++++++--------------------- - src/dbus-manager.c | 6 ++- - src/dbus.c | 14 +++-- - src/job.c | 21 +++++++- - src/job.h | 15 ++++- - 5 files changed, 131 insertions(+), 71 deletions(-) - -diff --git a/src/dbus-job.c b/src/dbus-job.c -index ab6d610..aa1b4eb 100644 ---- a/src/dbus-job.c -+++ b/src/dbus-job.c -@@ -225,61 +225,71 @@ const DBusObjectPathVTable bus_job_vtable = { - .message_function = bus_job_message_handler - }; - --static int job_send_message(Job *j, DBusMessage *m) { -+static int job_send_message(Job *j, DBusMessage* (*new_message)(Job *j)) { -+ DBusMessage *m = NULL; - int r; - - assert(j); -- assert(m); -+ assert(new_message); - - if (bus_has_subscriber(j->manager)) { -- if ((r = bus_broadcast(j->manager, m)) < 0) -+ m = new_message(j); -+ if (!m) -+ goto oom; -+ r = bus_broadcast(j->manager, m); -+ dbus_message_unref(m); -+ if (r < 0) - return r; - -- } else if (j->bus_client) { -+ } else { - /* If nobody is subscribed, we just send the message -- * to the client which created the job */ -+ * to the client(s) which created the job */ -+ JobBusClient *cl; -+ assert(j->bus_client_list); -+ LIST_FOREACH(client, cl, j->bus_client_list) { -+ assert(cl->bus); - -- assert(j->bus); -+ m = new_message(j); -+ if (!m) -+ goto oom; - -- if (!dbus_message_set_destination(m, j->bus_client)) -- return -ENOMEM; -+ if (!dbus_message_set_destination(m, cl->name)) -+ goto oom; -+ -+ if (!dbus_connection_send(cl->bus, m, NULL)) -+ goto oom; - -- if (!dbus_connection_send(j->bus, m, NULL)) -- return -ENOMEM; -+ dbus_message_unref(m); -+ m = NULL; -+ } - } - - return 0; -+oom: -+ if (m) -+ dbus_message_unref(m); -+ return -ENOMEM; - } - --void bus_job_send_change_signal(Job *j) { -- char *p = NULL; -+static DBusMessage* new_change_signal_message(Job *j) { - DBusMessage *m = NULL; -+ char *p = NULL; - -- assert(j); -- -- if (j->in_dbus_queue) { -- LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j); -- j->in_dbus_queue = false; -- } -- -- if (!bus_has_subscriber(j->manager) && !j->bus_client) { -- j->sent_dbus_new_signal = true; -- return; -- } -- -- if (!(p = job_dbus_path(j))) -+ p = job_dbus_path(j); -+ if (!p) - goto oom; - - if (j->sent_dbus_new_signal) { - /* Send a properties changed signal */ -- -- if (!(m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Job", INVALIDATING_PROPERTIES))) -+ m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Job", INVALIDATING_PROPERTIES); -+ if (!m) - goto oom; - - } else { - /* Send a new signal */ - -- if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobNew"))) -+ m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobNew"); -+ if (!m) - goto oom; - - if (!dbus_message_append_args(m, -@@ -289,42 +299,26 @@ void bus_job_send_change_signal(Job *j) { - goto oom; - } - -- if (job_send_message(j, m) < 0) -- goto oom; -- -- free(p); -- dbus_message_unref(m); -- -- j->sent_dbus_new_signal = true; -- -- return; -+ return m; - - oom: -- free(p); -- - if (m) - dbus_message_unref(m); -- -- log_error("Failed to allocate job change signal."); -+ free(p); -+ return NULL; - } - --void bus_job_send_removed_signal(Job *j) { -- char *p = NULL; -+static DBusMessage* new_removed_signal_message(Job *j) { - DBusMessage *m = NULL; -+ char *p = NULL; - const char *r; - -- assert(j); -- -- if (!bus_has_subscriber(j->manager) && !j->bus_client) -- return; -- -- if (!j->sent_dbus_new_signal) -- bus_job_send_change_signal(j); -- -- if (!(p = job_dbus_path(j))) -+ p = job_dbus_path(j); -+ if (!p) - goto oom; - -- if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobRemoved"))) -+ m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobRemoved"); -+ if (!m) - goto oom; - - r = job_result_to_string(j->result); -@@ -336,19 +330,53 @@ void bus_job_send_removed_signal(Job *j) { - DBUS_TYPE_INVALID)) - goto oom; - -- if (job_send_message(j, m) < 0) -- goto oom; -+ return m; - -+oom: -+ if (m) -+ dbus_message_unref(m); - free(p); -- dbus_message_unref(m); -+ return NULL; -+} -+ -+void bus_job_send_change_signal(Job *j) { -+ assert(j); -+ -+ if (j->in_dbus_queue) { -+ LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j); -+ j->in_dbus_queue = false; -+ } -+ -+ if (!bus_has_subscriber(j->manager) && !j->bus_client_list) { -+ j->sent_dbus_new_signal = true; -+ return; -+ } -+ -+ if (job_send_message(j, new_change_signal_message) < 0) -+ goto oom; -+ -+ j->sent_dbus_new_signal = true; - - return; - - oom: -- free(p); -+ log_error("Failed to allocate job change signal."); -+} - -- if (m) -- dbus_message_unref(m); -+void bus_job_send_removed_signal(Job *j) { -+ assert(j); -+ -+ if (!bus_has_subscriber(j->manager) && !j->bus_client_list) -+ return; -+ -+ if (!j->sent_dbus_new_signal) -+ bus_job_send_change_signal(j); - -+ if (job_send_message(j, new_removed_signal_message) < 0) -+ goto oom; -+ -+ return; -+ -+oom: - log_error("Failed to allocate job remove signal."); - } -diff --git a/src/dbus-manager.c b/src/dbus-manager.c -index 6d272cb..0b78375 100644 ---- a/src/dbus-manager.c -+++ b/src/dbus-manager.c -@@ -1435,6 +1435,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, - const char *name, *smode, *old_name = NULL; - JobMode mode; - Job *j; -+ JobBusClient *cl; - Unit *u; - bool b; - -@@ -1492,10 +1493,11 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, - if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0) - return bus_send_error_reply(connection, message, &error, r); - -- if (!(j->bus_client = strdup(message_get_sender_with_fallback(message)))) -+ cl = job_bus_client_new(connection, message_get_sender_with_fallback(message)); -+ if (!cl) - goto oom; - -- j->bus = connection; -+ LIST_PREPEND(JobBusClient, client, j->bus_client_list, cl); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; -diff --git a/src/dbus.c b/src/dbus.c -index 8e6e9fd..50e8c9c 100644 ---- a/src/dbus.c -+++ b/src/dbus.c -@@ -1166,13 +1166,15 @@ static void shutdown_connection(Manager *m, DBusConnection *c) { - Job *j; - Iterator i; - -- HASHMAP_FOREACH(j, m->jobs, i) -- if (j->bus == c) { -- free(j->bus_client); -- j->bus_client = NULL; -- -- j->bus = NULL; -+ HASHMAP_FOREACH(j, m->jobs, i) { -+ JobBusClient *cl, *nextcl; -+ LIST_FOREACH_SAFE(client, cl, nextcl, j->bus_client_list) { -+ if (cl->bus == c) { -+ LIST_REMOVE(JobBusClient, client, j->bus_client_list, cl); -+ free(cl); -+ } - } -+ } - - set_remove(m->bus_connections, c); - set_remove(m->bus_connections_for_dispatch, c); -diff --git a/src/job.c b/src/job.c -index fb759a5..de74751 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -33,6 +33,20 @@ - #include "log.h" - #include "dbus-job.h" - -+JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name) { -+ JobBusClient *cl; -+ size_t name_len; -+ -+ name_len = strlen(name); -+ cl = malloc0(sizeof(JobBusClient) + name_len + 1); -+ if (!cl) -+ return NULL; -+ -+ cl->bus = connection; -+ memcpy(cl->name, name, name_len + 1); -+ return cl; -+} -+ - Job* job_new(Unit *unit, JobType type) { - Job *j; - -@@ -55,6 +69,8 @@ Job* job_new(Unit *unit, JobType type) { - } - - void job_free(Job *j) { -+ JobBusClient *cl; -+ - assert(j); - assert(!j->installed); - assert(!j->transaction_prev); -@@ -77,7 +93,10 @@ void job_free(Job *j) { - close_nointr_nofail(j->timer_watch.fd); - } - -- free(j->bus_client); -+ while ((cl = j->bus_client_list)) { -+ LIST_REMOVE(JobBusClient, client, j->bus_client_list, cl); -+ free(cl); -+ } - free(j); - } - -diff --git a/src/job.h b/src/job.h -index eab0e07..2025b5b 100644 ---- a/src/job.h -+++ b/src/job.h -@@ -28,6 +28,7 @@ - - typedef struct Job Job; - typedef struct JobDependency JobDependency; -+typedef struct JobBusClient JobBusClient; - typedef enum JobType JobType; - typedef enum JobState JobState; - typedef enum JobMode JobMode; -@@ -99,6 +100,13 @@ struct JobDependency { - bool conflicts; - }; - -+struct JobBusClient { -+ LIST_FIELDS(JobBusClient, client); -+ /* Note that this bus object is not ref counted here. */ -+ DBusConnection *bus; -+ char name[0]; -+}; -+ - struct Job { - Manager *manager; - Unit *unit; -@@ -121,9 +129,8 @@ struct Job { - - Watch timer_watch; - -- /* Note that this bus object is not ref counted here. */ -- DBusConnection *bus; -- char *bus_client; -+ /* There can be more than one client, because of job merging. */ -+ LIST_HEAD(JobBusClient, bus_client_list); - - JobResult result; - -@@ -136,6 +143,8 @@ struct Job { - bool ignore_order:1; - }; - -+JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name); -+ - Job* job_new(Unit *unit, JobType type); - void job_free(Job *job); - Job* job_install(Job *j); --- -1.7.7 - - -From 45aca411e44be019c9ba1bc1500e0b7df73bbf75 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Fri, 20 Apr 2012 14:44:00 +0200 -Subject: [PATCH 22/30] transaction: add starting requirements for JOB_RESTART - -While having a Requires= dependency between units, the dependency is started -automatically on "systemctl start", but it's not started on "systemctl -restart". - -JOB_RESTART jobs did not pull the dependencies for starting into the -transaction. - -https://bugzilla.redhat.com/show_bug.cgi?id=802770 - -Note that the other bug noted in comment #2 has been fixed already by avoiding -the deletion of anchor jobs. -(cherry picked from commit 65304075249449a713b4e4842b8538ef4aa1c725) ---- - src/transaction.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/src/transaction.c b/src/transaction.c -index c3e1e13..a2efcbc 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -866,7 +866,7 @@ int transaction_add_job_and_dependencies( - } - - /* Finally, recursively add in all dependencies. */ -- if (type == JOB_START || type == JOB_RELOAD_OR_START) { -+ if (type == JOB_START || type == JOB_RELOAD_OR_START || type == JOB_RESTART) { - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) { - r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e); - if (r < 0) { --- -1.7.7 - - -From 029699f2de954461054efb21e91994ca6e9df46a Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Sun, 22 Apr 2012 15:22:52 +0200 -Subject: [PATCH 23/30] transaction: downgrade warnings about masked units - (cherry picked from commit - 59e132a7f416d7c4a33a46d791f250e03d2c2cd0) - ---- - src/transaction.c | 11 +++++++---- - 1 files changed, 7 insertions(+), 4 deletions(-) - -diff --git a/src/transaction.c b/src/transaction.c -index a2efcbc..a36f1df 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -822,7 +822,7 @@ int transaction_add_job_and_dependencies( - - if (type != JOB_STOP && unit->load_state == UNIT_MASKED) { - dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->id); -- return -EINVAL; -+ return -EADDRNOTAVAIL; - } - - if (!unit_job_is_applicable(unit, type)) { -@@ -892,7 +892,8 @@ int transaction_add_job_and_dependencies( - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) { - r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e); - if (r < 0) { -- log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -+ log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, -+ "Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - - if (e) - dbus_error_free(e); -@@ -902,7 +903,8 @@ int transaction_add_job_and_dependencies( - SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) { - r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e); - if (r < 0) { -- log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -+ log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, -+ "Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - - if (e) - dbus_error_free(e); -@@ -923,7 +925,8 @@ int transaction_add_job_and_dependencies( - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) { - r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e); - if (r < 0) { -- log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); -+ log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, -+ "Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); - - if (e) - dbus_error_free(e); --- -1.7.7 - - -From 0ee2f52343ed0da6dc9006be54c9de57b762e563 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Sat, 21 Apr 2012 21:40:40 +0200 -Subject: [PATCH 24/30] transaction: improve readability - -The functions looked complicated with the nested loops with breaks, -continues, and "while (again)". -Here using goto actually makes them easier to understand. - -Also correcting the comment about redundant jobs. -(cherry picked from commit 055163ad15a5ca1eb5626c63fa7163e152698e2b) ---- - src/transaction.c | 152 ++++++++++++++++++++++------------------------------- - 1 files changed, 62 insertions(+), 90 deletions(-) - -diff --git a/src/transaction.c b/src/transaction.c -index a36f1df..2bd6541 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -258,44 +258,32 @@ static int transaction_merge_jobs(Transaction *tr, DBusError *e) { - } - - static void transaction_drop_redundant(Transaction *tr) { -- bool again; -- -- assert(tr); -- -- /* Goes through the transaction and removes all jobs that are -- * a noop */ -- -- do { -- Job *j; -- Iterator i; -- -- again = false; -- -- HASHMAP_FOREACH(j, tr->jobs, i) { -- bool changes_something = false; -- Job *k; -+ Job *j; -+ Iterator i; - -- LIST_FOREACH(transaction, k, j) { -+ /* Goes through the transaction and removes all jobs of the units -+ * whose jobs are all noops. If not all of a unit's jobs are -+ * redundant, they are kept. */ - -- if (tr->anchor_job != k && -- job_type_is_redundant(k->type, unit_active_state(k->unit)) && -- (!k->unit->job || !job_type_is_conflicting(k->type, k->unit->job->type))) -- continue; -+ assert(tr); - -- changes_something = true; -- break; -- } -+rescan: -+ HASHMAP_FOREACH(j, tr->jobs, i) { -+ Job *k; - -- if (changes_something) -- continue; -+ LIST_FOREACH(transaction, k, j) { - -- /* log_debug("Found redundant job %s/%s, dropping.", j->unit->id, job_type_to_string(j->type)); */ -- transaction_delete_job(tr, j, false); -- again = true; -- break; -+ if (tr->anchor_job == k || -+ !job_type_is_redundant(k->type, unit_active_state(k->unit)) || -+ (k->unit->job && job_type_is_conflicting(k->type, k->unit->job->type))) -+ goto next_unit; - } - -- } while (again); -+ /* log_debug("Found redundant job %s/%s, dropping.", j->unit->id, job_type_to_string(j->type)); */ -+ transaction_delete_job(tr, j, false); -+ goto rescan; -+ next_unit:; -+ } - } - - static bool unit_matters_to_anchor(Unit *u, Job *j) { -@@ -430,34 +418,27 @@ static int transaction_verify_order(Transaction *tr, unsigned *generation, DBusE - } - - static void transaction_collect_garbage(Transaction *tr) { -- bool again; -+ Iterator i; -+ Job *j; - - assert(tr); - - /* Drop jobs that are not required by any other job */ - -- do { -- Iterator i; -- Job *j; -- -- again = false; -- -- HASHMAP_FOREACH(j, tr->jobs, i) { -- if (tr->anchor_job == j || j->object_list) { -- /* log_debug("Keeping job %s/%s because of %s/%s", */ -- /* j->unit->id, job_type_to_string(j->type), */ -- /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */ -- /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */ -- continue; -- } -- -- /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */ -- transaction_delete_job(tr, j, true); -- again = true; -- break; -+rescan: -+ HASHMAP_FOREACH(j, tr->jobs, i) { -+ if (tr->anchor_job == j || j->object_list) { -+ /* log_debug("Keeping job %s/%s because of %s/%s", */ -+ /* j->unit->id, job_type_to_string(j->type), */ -+ /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */ -+ /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */ -+ continue; - } - -- } while (again); -+ /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */ -+ transaction_delete_job(tr, j, true); -+ goto rescan; -+ } - } - - static int transaction_is_destructive(Transaction *tr, DBusError *e) { -@@ -487,59 +468,50 @@ static int transaction_is_destructive(Transaction *tr, DBusError *e) { - } - - static void transaction_minimize_impact(Transaction *tr) { -- bool again; -+ Job *j; -+ Iterator i; -+ - assert(tr); - - /* Drops all unnecessary jobs that reverse already active jobs - * or that stop a running service. */ - -- do { -- Job *j; -- Iterator i; -- -- again = false; -- -- HASHMAP_FOREACH(j, tr->jobs, i) { -- LIST_FOREACH(transaction, j, j) { -- bool stops_running_service, changes_existing_job; -+rescan: -+ HASHMAP_FOREACH(j, tr->jobs, i) { -+ LIST_FOREACH(transaction, j, j) { -+ bool stops_running_service, changes_existing_job; - -- /* If it matters, we shouldn't drop it */ -- if (j->matters_to_anchor) -- continue; -+ /* If it matters, we shouldn't drop it */ -+ if (j->matters_to_anchor) -+ continue; - -- /* Would this stop a running service? -- * Would this change an existing job? -- * If so, let's drop this entry */ -+ /* Would this stop a running service? -+ * Would this change an existing job? -+ * If so, let's drop this entry */ - -- stops_running_service = -- j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit)); -+ stops_running_service = -+ j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit)); - -- changes_existing_job = -- j->unit->job && -- job_type_is_conflicting(j->type, j->unit->job->type); -+ changes_existing_job = -+ j->unit->job && -+ job_type_is_conflicting(j->type, j->unit->job->type); - -- if (!stops_running_service && !changes_existing_job) -- continue; -+ if (!stops_running_service && !changes_existing_job) -+ continue; - -- if (stops_running_service) -- log_debug("%s/%s would stop a running service.", j->unit->id, job_type_to_string(j->type)); -+ if (stops_running_service) -+ log_debug("%s/%s would stop a running service.", j->unit->id, job_type_to_string(j->type)); - -- if (changes_existing_job) -- log_debug("%s/%s would change existing job.", j->unit->id, job_type_to_string(j->type)); -+ if (changes_existing_job) -+ log_debug("%s/%s would change existing job.", j->unit->id, job_type_to_string(j->type)); - -- /* Ok, let's get rid of this */ -- log_debug("Deleting %s/%s to minimize impact.", j->unit->id, job_type_to_string(j->type)); -+ /* Ok, let's get rid of this */ -+ log_debug("Deleting %s/%s to minimize impact.", j->unit->id, job_type_to_string(j->type)); - -- transaction_delete_job(tr, j, true); -- again = true; -- break; -- } -- -- if (again) -- break; -+ transaction_delete_job(tr, j, true); -+ goto rescan; - } -- -- } while (again); -+ } - } - - static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { --- -1.7.7 - - -From f613fa87549229f257444c41f5155fb1f5f30f44 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Sun, 22 Apr 2012 02:09:04 +0200 -Subject: [PATCH 25/30] transaction: fix detection of cycles involving - installed jobs - -A transaction can be acyclic, but when it's added to installed jobs, -a cycle may result. - -transaction_verify_order_one() attempts to detect these cases, but it -fails because the installed jobs often have the exact generation number -that makes them look as if they were walked already. - -Fix it by resetting the generation numbers of all installed jobs before -detecting cycles. - -An alternative fix could be to add the generation counter to the -Manager and use it instead of starting always from 1 in -transaction_activate(). But I prefer not having to worry about it -wrapping around. -(cherry picked from commit 4e7bd268ae1f39675988b9ac61b9378a67e3ae3e) ---- - src/transaction.c | 8 ++++++++ - 1 files changed, 8 insertions(+), 0 deletions(-) - -diff --git a/src/transaction.c b/src/transaction.c -index 2bd6541..9676b57 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -582,6 +582,8 @@ rollback: - } - - int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e) { -+ Iterator i; -+ Job *j; - int r; - unsigned generation = 1; - -@@ -590,6 +592,12 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e - /* This applies the changes recorded in tr->jobs to - * the actual list of jobs, if possible. */ - -+ /* Reset the generation counter of all installed jobs. The detection of cycles -+ * looks at installed jobs. If they had a non-zero generation from some previous -+ * walk of the graph, the algorithm would break. */ -+ HASHMAP_FOREACH(j, m->jobs, i) -+ j->generation = 0; -+ - /* First step: figure out which jobs matter */ - transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++); - --- -1.7.7 - - -From 374998cf2930534951bc0dace5025468cdf3c247 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Sun, 22 Apr 2012 10:54:58 +0200 -Subject: [PATCH 26/30] transaction: abort does not need to use recursive - deletion - -Recursion is unnecessary, because we're deleting all transaction jobs -anyway. And the recursive deletion produces debug messages that are -pointless in transaction abort. -(cherry picked from commit 1b9cea0caa85dce6d9f117638a296b141c49a8fd) ---- - src/transaction.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/src/transaction.c b/src/transaction.c -index 9676b57..b0a26f2 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -30,7 +30,7 @@ void transaction_abort(Transaction *tr) { - assert(tr); - - while ((j = hashmap_first(tr->jobs))) -- transaction_delete_job(tr, j, true); -+ transaction_delete_job(tr, j, false); - - assert(hashmap_isempty(tr->jobs)); - } --- -1.7.7 - - -From 0d806f0c0bebf755867cfe0b3cc41d55aebea66a Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Mon, 23 Apr 2012 01:24:04 +0200 -Subject: [PATCH 27/30] job: serialize jobs properly - -Jobs were not preserved correctly over a daemon-reload operation. -A systemctl process waiting for a job completion received a job removal -signal. The job itself changed its id. The job timeout started ticking all -over again. - -This fixes the deficiencies. -(cherry picked from commit 39a18c60d07319ebfcfd476556729c2cadd616d6) ---- - src/dbus-job.c | 6 +- - src/job.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- - src/job.h | 6 ++ - src/unit.c | 45 ++++++++++++--- - src/unit.h | 4 +- - 5 files changed, 203 insertions(+), 20 deletions(-) - -diff --git a/src/dbus-job.c b/src/dbus-job.c -index aa1b4eb..63e5846 100644 ---- a/src/dbus-job.c -+++ b/src/dbus-job.c -@@ -232,7 +232,7 @@ static int job_send_message(Job *j, DBusMessage* (*new_message)(Job *j)) { - assert(j); - assert(new_message); - -- if (bus_has_subscriber(j->manager)) { -+ if (bus_has_subscriber(j->manager) || j->forgot_bus_clients) { - m = new_message(j); - if (!m) - goto oom; -@@ -347,7 +347,7 @@ void bus_job_send_change_signal(Job *j) { - j->in_dbus_queue = false; - } - -- if (!bus_has_subscriber(j->manager) && !j->bus_client_list) { -+ if (!bus_has_subscriber(j->manager) && !j->bus_client_list && !j->forgot_bus_clients) { - j->sent_dbus_new_signal = true; - return; - } -@@ -366,7 +366,7 @@ oom: - void bus_job_send_removed_signal(Job *j) { - assert(j); - -- if (!bus_has_subscriber(j->manager) && !j->bus_client_list) -+ if (!bus_has_subscriber(j->manager) && !j->bus_client_list && !j->forgot_bus_clients) - return; - - if (!j->sent_dbus_new_signal) -diff --git a/src/job.c b/src/job.c -index de74751..69df024 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -47,22 +47,36 @@ JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name) { - return cl; - } - --Job* job_new(Unit *unit, JobType type) { -+Job* job_new_raw(Unit *unit) { - Job *j; - -- assert(type < _JOB_TYPE_MAX); -+ /* used for deserialization */ -+ - assert(unit); - -- if (!(j = new0(Job, 1))) -+ j = new0(Job, 1); -+ if (!j) - return NULL; - - j->manager = unit->manager; -- j->id = j->manager->current_job_id++; -- j->type = type; - j->unit = unit; -- - j->timer_watch.type = WATCH_INVALID; - -+ return j; -+} -+ -+Job* job_new(Unit *unit, JobType type) { -+ Job *j; -+ -+ assert(type < _JOB_TYPE_MAX); -+ -+ j = job_new_raw(unit); -+ if (!j) -+ return NULL; -+ -+ j->id = j->manager->current_job_id++; -+ j->type = type; -+ - /* We don't link it here, that's what job_dependency() is for */ - - return j; -@@ -105,7 +119,9 @@ void job_uninstall(Job *j) { - assert(j->unit->job == j); - /* Detach from next 'bigger' objects */ - -- bus_job_send_removed_signal(j); -+ /* daemon-reload should be transparent to job observers */ -+ if (j->manager->n_reloading <= 0) -+ bus_job_send_removed_signal(j); - - j->unit->job = NULL; - unit_add_to_gc_queue(j->unit); -@@ -180,6 +196,18 @@ Job* job_install(Job *j) { - return j; - } - -+void job_install_deserialized(Job *j) { -+ assert(!j->installed); -+ -+ if (j->unit->job) { -+ log_debug("Unit %s already has a job installed. Not installing deserialized job.", j->unit->id); -+ return; -+ } -+ j->unit->job = j; -+ j->installed = true; -+ log_debug("Reinstalled deserialized job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); -+} -+ - JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) { - JobDependency *l; - -@@ -732,6 +760,126 @@ void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) { - job_finish_and_invalidate(j, JOB_TIMEOUT); - } - -+int job_serialize(Job *j, FILE *f, FDSet *fds) { -+ fprintf(f, "job-id=%u\n", j->id); -+ fprintf(f, "job-type=%s\n", job_type_to_string(j->type)); -+ fprintf(f, "job-state=%s\n", job_state_to_string(j->state)); -+ fprintf(f, "job-override=%s\n", yes_no(j->override)); -+ fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal)); -+ fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order)); -+ /* Cannot save bus clients. Just note the fact that we're losing -+ * them. job_send_message() will fallback to broadcasting. */ -+ fprintf(f, "job-forgot-bus-clients=%s\n", -+ yes_no(j->forgot_bus_clients || j->bus_client_list)); -+ if (j->timer_watch.type == WATCH_JOB_TIMER) { -+ int copy = fdset_put_dup(fds, j->timer_watch.fd); -+ if (copy < 0) -+ return copy; -+ fprintf(f, "job-timer-watch-fd=%d\n", copy); -+ } -+ -+ /* End marker */ -+ fputc('\n', f); -+ return 0; -+} -+ -+int job_deserialize(Job *j, FILE *f, FDSet *fds) { -+ for (;;) { -+ char line[LINE_MAX], *l, *v; -+ size_t k; -+ -+ if (!fgets(line, sizeof(line), f)) { -+ if (feof(f)) -+ return 0; -+ return -errno; -+ } -+ -+ char_array_0(line); -+ l = strstrip(line); -+ -+ /* End marker */ -+ if (l[0] == 0) -+ return 0; -+ -+ k = strcspn(l, "="); -+ -+ if (l[k] == '=') { -+ l[k] = 0; -+ v = l+k+1; -+ } else -+ v = l+k; -+ -+ if (streq(l, "job-id")) { -+ if (safe_atou32(v, &j->id) < 0) -+ log_debug("Failed to parse job id value %s", v); -+ } else if (streq(l, "job-type")) { -+ JobType t = job_type_from_string(v); -+ if (t < 0) -+ log_debug("Failed to parse job type %s", v); -+ else -+ j->type = t; -+ } else if (streq(l, "job-state")) { -+ JobState s = job_state_from_string(v); -+ if (s < 0) -+ log_debug("Failed to parse job state %s", v); -+ else -+ j->state = s; -+ } else if (streq(l, "job-override")) { -+ int b = parse_boolean(v); -+ if (b < 0) -+ log_debug("Failed to parse job override flag %s", v); -+ else -+ j->override = j->override || b; -+ } else if (streq(l, "job-sent-dbus-new-signal")) { -+ int b = parse_boolean(v); -+ if (b < 0) -+ log_debug("Failed to parse job sent_dbus_new_signal flag %s", v); -+ else -+ j->sent_dbus_new_signal = j->sent_dbus_new_signal || b; -+ } else if (streq(l, "job-ignore-order")) { -+ int b = parse_boolean(v); -+ if (b < 0) -+ log_debug("Failed to parse job ignore_order flag %s", v); -+ else -+ j->ignore_order = j->ignore_order || b; -+ } else if (streq(l, "job-forgot-bus-clients")) { -+ int b = parse_boolean(v); -+ if (b < 0) -+ log_debug("Failed to parse job forgot_bus_clients flag %s", v); -+ else -+ j->forgot_bus_clients = j->forgot_bus_clients || b; -+ } else if (streq(l, "job-timer-watch-fd")) { -+ int fd; -+ if (safe_atoi(v, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) -+ log_debug("Failed to parse job-timer-watch-fd value %s", v); -+ else { -+ if (j->timer_watch.type == WATCH_JOB_TIMER) -+ close_nointr_nofail(j->timer_watch.fd); -+ -+ j->timer_watch.type = WATCH_JOB_TIMER; -+ j->timer_watch.fd = fdset_remove(fds, fd); -+ j->timer_watch.data.job = j; -+ } -+ } -+ } -+} -+ -+int job_coldplug(Job *j) { -+ struct epoll_event ev; -+ -+ if (j->timer_watch.type != WATCH_JOB_TIMER) -+ return 0; -+ -+ zero(ev); -+ ev.data.ptr = &j->timer_watch; -+ ev.events = EPOLLIN; -+ -+ if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, j->timer_watch.fd, &ev) < 0) -+ return -errno; -+ -+ return 0; -+} -+ - static const char* const job_state_table[_JOB_STATE_MAX] = { - [JOB_WAITING] = "waiting", - [JOB_RUNNING] = "running" -diff --git a/src/job.h b/src/job.h -index 2025b5b..eea8242 100644 ---- a/src/job.h -+++ b/src/job.h -@@ -141,15 +141,21 @@ struct Job { - bool in_dbus_queue:1; - bool sent_dbus_new_signal:1; - bool ignore_order:1; -+ bool forgot_bus_clients:1; - }; - - JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name); - - Job* job_new(Unit *unit, JobType type); -+Job* job_new_raw(Unit *unit); - void job_free(Job *job); - Job* job_install(Job *j); -+void job_install_deserialized(Job *j); - void job_uninstall(Job *j); - void job_dump(Job *j, FILE*f, const char *prefix); -+int job_serialize(Job *j, FILE *f, FDSet *fds); -+int job_deserialize(Job *j, FILE *f, FDSet *fds); -+int job_coldplug(Job *j); - - JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts); - void job_dependency_free(JobDependency *l); -diff --git a/src/unit.c b/src/unit.c -index 1949995..c203a31 100644 ---- a/src/unit.c -+++ b/src/unit.c -@@ -2288,8 +2288,10 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds) { - if ((r = UNIT_VTABLE(u)->serialize(u, f, fds)) < 0) - return r; - -- if (u->job) -- unit_serialize_item(u, f, "job", job_type_to_string(u->job->type)); -+ if (u->job) { -+ fprintf(f, "job\n"); -+ job_serialize(u->job, f, fds); -+ } - - dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp); - dual_timestamp_serialize(f, "active-enter-timestamp", &u->active_enter_timestamp); -@@ -2368,13 +2370,32 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { - v = l+k; - - if (streq(l, "job")) { -- JobType type; -+ if (v[0] == '\0') { -+ /* new-style serialized job */ -+ Job *j = job_new_raw(u); -+ if (!j) -+ return -ENOMEM; - -- if ((type = job_type_from_string(v)) < 0) -- log_debug("Failed to parse job type value %s", v); -- else -- u->deserialized_job = type; -+ r = job_deserialize(j, f, fds); -+ if (r < 0) { -+ job_free(j); -+ return r; -+ } - -+ job_install_deserialized(j); -+ r = hashmap_put(u->manager->jobs, UINT32_TO_PTR(j->id), j); -+ if (r < 0) { -+ job_free(j); -+ return r; -+ } -+ } else { -+ /* legacy */ -+ JobType type = job_type_from_string(v); -+ if (type < 0) -+ log_debug("Failed to parse job type value %s", v); -+ else -+ u->deserialized_job = type; -+ } - continue; - } else if (streq(l, "inactive-exit-timestamp")) { - dual_timestamp_deserialize(v, &u->inactive_exit_timestamp); -@@ -2450,8 +2471,14 @@ int unit_coldplug(Unit *u) { - if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0) - return r; - -- if (u->deserialized_job >= 0) { -- if ((r = manager_add_job(u->manager, u->deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL)) < 0) -+ if (u->job) { -+ r = job_coldplug(u->job); -+ if (r < 0) -+ return r; -+ } else if (u->deserialized_job >= 0) { -+ /* legacy */ -+ r = manager_add_job(u->manager, u->deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL); -+ if (r < 0) - return r; - - u->deserialized_job = _JOB_TYPE_INVALID; -diff --git a/src/unit.h b/src/unit.h -index 756f465..5fceabb 100644 ---- a/src/unit.h -+++ b/src/unit.h -@@ -200,7 +200,9 @@ struct Unit { - unsigned gc_marker; - - /* When deserializing, temporarily store the job type for this -- * unit here, if there was a job scheduled */ -+ * unit here, if there was a job scheduled. -+ * Only for deserializing from a legacy version. New style uses full -+ * serialized jobs. */ - int deserialized_job; /* This is actually of type JobType */ - - /* Error code when we didn't manage to load the unit (negative) */ --- -1.7.7 - - -From f2e0e5d5c80c8a489faa584539d7010b056dee7b Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Tue, 24 Apr 2012 11:21:03 +0200 -Subject: [PATCH 28/30] transaction: cancel jobs non-recursively on isolate - -Recursive cancellation of jobs would trigger OnFailure actions of -dependent jobs. This is not desirable when isolating. - -Fixes https://bugzilla.redhat.com/show_bug.cgi?id=798328 -(cherry picked from commit 5273510e9f228a300ec6207d4502f1c6253aed5e) ---- - src/dbus-job.c | 2 +- - src/job.c | 41 ++++++++++++++++------------------------- - src/job.h | 2 +- - src/manager.c | 3 ++- - src/transaction.c | 10 ++++------ - src/unit.c | 12 ++++++------ - 6 files changed, 30 insertions(+), 40 deletions(-) - -diff --git a/src/dbus-job.c b/src/dbus-job.c -index 63e5846..8474138 100644 ---- a/src/dbus-job.c -+++ b/src/dbus-job.c -@@ -100,7 +100,7 @@ static DBusHandlerResult bus_job_message_dispatch(Job *j, DBusConnection *connec - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - -- job_finish_and_invalidate(j, JOB_CANCELED); -+ job_finish_and_invalidate(j, JOB_CANCELED, true); - - } else { - const BusBoundProperties bps[] = { -diff --git a/src/job.c b/src/job.c -index 69df024..e8e0264 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -164,7 +164,7 @@ Job* job_install(Job *j) { - - if (uj) { - if (job_type_is_conflicting(uj->type, j->type)) -- job_finish_and_invalidate(uj, JOB_CANCELED); -+ job_finish_and_invalidate(uj, JOB_CANCELED, true); - else { - /* not conflicting, i.e. mergeable */ - -@@ -496,13 +496,13 @@ int job_run_and_invalidate(Job *j) { - - if ((j = manager_get_job(m, id))) { - if (r == -EALREADY) -- r = job_finish_and_invalidate(j, JOB_DONE); -+ r = job_finish_and_invalidate(j, JOB_DONE, true); - else if (r == -ENOEXEC) -- r = job_finish_and_invalidate(j, JOB_SKIPPED); -+ r = job_finish_and_invalidate(j, JOB_SKIPPED, true); - else if (r == -EAGAIN) - j->state = JOB_WAITING; - else if (r < 0) -- r = job_finish_and_invalidate(j, JOB_FAILED); -+ r = job_finish_and_invalidate(j, JOB_FAILED, true); - } - - return r; -@@ -555,12 +555,11 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) { - } - } - --int job_finish_and_invalidate(Job *j, JobResult result) { -+int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { - Unit *u; - Unit *other; - JobType t; - Iterator i; -- bool recursed = false; - - assert(j); - assert(j->installed); -@@ -594,7 +593,7 @@ int job_finish_and_invalidate(Job *j, JobResult result) { - job_print_status_message(u, t, result); - - /* Fail depending jobs on failure */ -- if (result != JOB_DONE) { -+ if (result != JOB_DONE && recursive) { - - if (t == JOB_START || - t == JOB_VERIFY_ACTIVE || -@@ -604,29 +603,23 @@ int job_finish_and_invalidate(Job *j, JobResult result) { - if (other->job && - (other->job->type == JOB_START || - other->job->type == JOB_VERIFY_ACTIVE || -- other->job->type == JOB_RELOAD_OR_START)) { -- job_finish_and_invalidate(other->job, JOB_DEPENDENCY); -- recursed = true; -- } -+ other->job->type == JOB_RELOAD_OR_START)) -+ job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); - - SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i) - if (other->job && - (other->job->type == JOB_START || - other->job->type == JOB_VERIFY_ACTIVE || -- other->job->type == JOB_RELOAD_OR_START)) { -- job_finish_and_invalidate(other->job, JOB_DEPENDENCY); -- recursed = true; -- } -+ other->job->type == JOB_RELOAD_OR_START)) -+ job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); - - SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i) - if (other->job && - !other->job->override && - (other->job->type == JOB_START || - other->job->type == JOB_VERIFY_ACTIVE || -- other->job->type == JOB_RELOAD_OR_START)) { -- job_finish_and_invalidate(other->job, JOB_DEPENDENCY); -- recursed = true; -- } -+ other->job->type == JOB_RELOAD_OR_START)) -+ job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); - - } else if (t == JOB_STOP) { - -@@ -634,10 +627,8 @@ int job_finish_and_invalidate(Job *j, JobResult result) { - if (other->job && - (other->job->type == JOB_START || - other->job->type == JOB_VERIFY_ACTIVE || -- other->job->type == JOB_RELOAD_OR_START)) { -- job_finish_and_invalidate(other->job, JOB_DEPENDENCY); -- recursed = true; -- } -+ other->job->type == JOB_RELOAD_OR_START)) -+ job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); - } - } - -@@ -665,7 +656,7 @@ finish: - - manager_check_finished(u->manager); - -- return recursed; -+ return 0; - } - - int job_start_timer(Job *j) { -@@ -757,7 +748,7 @@ void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) { - assert(w == &j->timer_watch); - - log_warning("Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type)); -- job_finish_and_invalidate(j, JOB_TIMEOUT); -+ job_finish_and_invalidate(j, JOB_TIMEOUT, true); - } - - int job_serialize(Job *j, FILE *f, FDSet *fds) { -diff --git a/src/job.h b/src/job.h -index eea8242..5b326ef 100644 ---- a/src/job.h -+++ b/src/job.h -@@ -196,7 +196,7 @@ int job_start_timer(Job *j); - void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w); - - int job_run_and_invalidate(Job *j); --int job_finish_and_invalidate(Job *j, JobResult result); -+int job_finish_and_invalidate(Job *j, JobResult result, bool recursive); - - char *job_dbus_path(Job *j); - -diff --git a/src/manager.c b/src/manager.c -index 86ec858..7bff456 100644 ---- a/src/manager.c -+++ b/src/manager.c -@@ -846,7 +846,8 @@ void manager_clear_jobs(Manager *m) { - assert(m); - - while ((j = hashmap_first(m->jobs))) -- job_finish_and_invalidate(j, JOB_CANCELED); -+ /* No need to recurse. We're cancelling all jobs. */ -+ job_finish_and_invalidate(j, JOB_CANCELED, false); - } - - unsigned manager_dispatch_run_queue(Manager *m) { -diff --git a/src/transaction.c b/src/transaction.c -index b0a26f2..f687539 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -525,18 +525,16 @@ static int transaction_apply(Transaction *tr, 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(tr->jobs, j->unit)) - continue; - -- /* '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; -+ /* Not invalidating recursively. Avoids triggering -+ * OnFailure= actions of dependent jobs. Also avoids -+ * invalidating our iterator. */ -+ job_finish_and_invalidate(j, JOB_CANCELED, false); - } - } - -diff --git a/src/unit.c b/src/unit.c -index c203a31..ff8331c 100644 ---- a/src/unit.c -+++ b/src/unit.c -@@ -1226,12 +1226,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su - case JOB_VERIFY_ACTIVE: - - if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) -- job_finish_and_invalidate(u->job, JOB_DONE); -+ job_finish_and_invalidate(u->job, JOB_DONE, true); - else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) { - unexpected = true; - - if (UNIT_IS_INACTIVE_OR_FAILED(ns)) -- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE); -+ job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true); - } - - break; -@@ -1241,12 +1241,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su - - if (u->job->state == JOB_RUNNING) { - if (ns == UNIT_ACTIVE) -- job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED); -+ job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true); - else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) { - unexpected = true; - - if (UNIT_IS_INACTIVE_OR_FAILED(ns)) -- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE); -+ job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true); - } - } - -@@ -1257,10 +1257,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su - case JOB_TRY_RESTART: - - if (UNIT_IS_INACTIVE_OR_FAILED(ns)) -- job_finish_and_invalidate(u->job, JOB_DONE); -+ job_finish_and_invalidate(u->job, JOB_DONE, true); - else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) { - unexpected = true; -- job_finish_and_invalidate(u->job, JOB_FAILED); -+ job_finish_and_invalidate(u->job, JOB_FAILED, true); - } - - break; --- -1.7.7 - - -From 38a2f4227415ebf3519369d27a23750948f6dddf Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Wed, 25 Apr 2012 11:58:27 +0200 -Subject: [PATCH 29/30] core: add NOP jobs, job type collapsing - -Two of our current job types are special: -JOB_TRY_RESTART, JOB_RELOAD_OR_START. - -They differ from other job types by being sensitive to the unit active state. -They perform some action when the unit is active and some other action -otherwise. This raises a question: when exactly should the unit state be -checked to make the decision? - -Currently the unit state is checked when the job becomes runnable. It's more -sensible to check the state immediately when the job is added by the user. -When the user types "systemctl try-restart foo.service", he really intends -to restart the service if it's running right now. If it isn't running right -now, the restart is pointless. - -Consider the example (from Bugzilla[1]): - -sleep.service takes some time to start. -hello.service has After=sleep.service. -Both services get started. Two jobs will appear: - hello.service/start waiting - sleep.service/start running -Then someone runs "systemctl try-restart hello.service". - -Currently the try-restart operation will block and wait for -sleep.service/start to complete. - -The correct result is to complete the try-restart operation immediately -with success, because hello.service is not running. The two original -jobs must not be disturbed by this. - -To fix this we introduce two new concepts: -- a new job type: JOB_NOP - A JOB_NOP job does not do anything to the unit. It does not pull in any - dependencies. It is always immediately runnable. When installed to a unit, - it sits in a special slot (u->nop_job) where it never conflicts with - the installed job (u->job) of a different type. It never merges with jobs - of other types, but it can merge into an already installed JOB_NOP job. - -- "collapsing" of job types - When a job of one of the two special types is added, the state of the unit - is checked immediately and the job type changes: - JOB_TRY_RESTART -> JOB_RESTART or JOB_NOP - JOB_RELOAD_OR_START -> JOB_RELOAD or JOB_START - Should a job type JOB_RELOAD_OR_START appear later during job merging, it - collapses immediately afterwards. - Collapsing actually makes some things simpler, because there are now fewer - job types that are allowed in the transaction. - -[1] Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=753586 -(cherry picked from commit e0209d83e7b30153f43b1a633c955f66eb2c2e4a) - -Conflicts: - - Makefile.am - src/job.c ---- - src/job.c | 163 ++++++++++++++++++++++++++++++++------------------- - src/job.h | 44 ++++++++++---- - src/manager.c | 2 + - src/test-job-type.c | 85 +++++++++++++++++---------- - src/transaction.c | 18 +++--- - src/unit.c | 29 +++++++++- - src/unit.h | 6 +- - 7 files changed, 230 insertions(+), 117 deletions(-) - -diff --git a/src/job.c b/src/job.c -index e8e0264..2438f39 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -60,6 +60,7 @@ Job* job_new_raw(Unit *unit) { - - j->manager = unit->manager; - j->unit = unit; -+ j->type = _JOB_TYPE_INVALID; - j->timer_watch.type = WATCH_INVALID; - - return j; -@@ -115,15 +116,21 @@ void job_free(Job *j) { - } - - void job_uninstall(Job *j) { -+ Job **pj; -+ - assert(j->installed); -- assert(j->unit->job == j); -+ -+ pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job; -+ assert(*pj == j); -+ - /* Detach from next 'bigger' objects */ - - /* daemon-reload should be transparent to job observers */ - if (j->manager->n_reloading <= 0) - bus_job_send_removed_signal(j); - -- j->unit->job = NULL; -+ *pj = NULL; -+ - unit_add_to_gc_queue(j->unit); - - hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id)); -@@ -144,31 +151,38 @@ static bool job_type_allows_late_merge(JobType t) { - * patched into JOB_START after stopping the unit. So if we see a - * JOB_RESTART running, it means the unit hasn't stopped yet and at - * this time the merge is still allowed. */ -- return !(t == JOB_RELOAD || t == JOB_RELOAD_OR_START); -+ return t != JOB_RELOAD; - } - - static void job_merge_into_installed(Job *j, Job *other) { - assert(j->installed); - assert(j->unit == other->unit); - -- j->type = job_type_lookup_merge(j->type, other->type); -- assert(j->type >= 0); -+ if (j->type != JOB_NOP) -+ job_type_merge_and_collapse(&j->type, other->type, j->unit); -+ else -+ assert(other->type == JOB_NOP); - - j->override = j->override || other->override; - } - - Job* job_install(Job *j) { -- Job *uj = j->unit->job; -+ Job **pj; -+ Job *uj; - - assert(!j->installed); -+ assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION); -+ -+ pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job; -+ uj = *pj; - - if (uj) { -- if (job_type_is_conflicting(uj->type, j->type)) -+ if (j->type != JOB_NOP && job_type_is_conflicting(uj->type, j->type)) - job_finish_and_invalidate(uj, JOB_CANCELED, true); - else { - /* not conflicting, i.e. mergeable */ - -- if (uj->state == JOB_WAITING || -+ if (j->type == JOB_NOP || uj->state == JOB_WAITING || - (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) { - job_merge_into_installed(uj, j); - log_debug("Merged into installed job %s/%s as %u", -@@ -189,23 +203,33 @@ Job* job_install(Job *j) { - } - - /* Install the job */ -- j->unit->job = j; -+ *pj = j; - j->installed = true; - j->manager->n_installed_jobs ++; - log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); - return j; - } - --void job_install_deserialized(Job *j) { -+int job_install_deserialized(Job *j) { -+ Job **pj; -+ - assert(!j->installed); - -- if (j->unit->job) { -+ if (j->type < 0 || j->type >= _JOB_TYPE_MAX_IN_TRANSACTION) { -+ log_debug("Invalid job type %s in deserialization.", strna(job_type_to_string(j->type))); -+ return -EINVAL; -+ } -+ -+ pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job; -+ -+ if (*pj) { - log_debug("Unit %s already has a job installed. Not installing deserialized job.", j->unit->id); -- return; -+ return -EEXIST; - } -- j->unit->job = j; -+ *pj = j; - j->installed = true; - log_debug("Reinstalled deserialized job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); -+ return 0; - } - - JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) { -@@ -268,6 +292,10 @@ void job_dump(Job *j, FILE*f, const char *prefix) { - * its lower triangle to avoid duplication. We don't store the main diagonal, - * because A merged with A is simply A. - * -+ * If the resulting type is collapsed immediately afterwards (to get rid of -+ * the JOB_RELOAD_OR_START, which lies outside the lookup function's domain), -+ * the following properties hold: -+ * - * Merging is associative! A merged with B merged with C is the same as - * A merged with C merged with B. - * -@@ -278,21 +306,19 @@ void job_dump(Job *j, FILE*f, const char *prefix) { - * be merged with C either. - */ - static const JobType job_merging_table[] = { --/* What \ With * JOB_START JOB_VERIFY_ACTIVE JOB_STOP JOB_RELOAD JOB_RELOAD_OR_START JOB_RESTART JOB_TRY_RESTART */ --/************************************************************************************************************************************/ -+/* What \ With * JOB_START JOB_VERIFY_ACTIVE JOB_STOP JOB_RELOAD */ -+/*********************************************************************************/ - /*JOB_START */ - /*JOB_VERIFY_ACTIVE */ JOB_START, - /*JOB_STOP */ -1, -1, - /*JOB_RELOAD */ JOB_RELOAD_OR_START, JOB_RELOAD, -1, --/*JOB_RELOAD_OR_START*/ JOB_RELOAD_OR_START, JOB_RELOAD_OR_START, -1, JOB_RELOAD_OR_START, --/*JOB_RESTART */ JOB_RESTART, JOB_RESTART, -1, JOB_RESTART, JOB_RESTART, --/*JOB_TRY_RESTART */ JOB_RESTART, JOB_TRY_RESTART, -1, JOB_TRY_RESTART, JOB_RESTART, JOB_RESTART, -+/*JOB_RESTART */ JOB_RESTART, JOB_RESTART, -1, JOB_RESTART, - }; - - JobType job_type_lookup_merge(JobType a, JobType b) { -- assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX * (_JOB_TYPE_MAX - 1) / 2); -- assert(a >= 0 && a < _JOB_TYPE_MAX); -- assert(b >= 0 && b < _JOB_TYPE_MAX); -+ assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX_MERGING * (_JOB_TYPE_MAX_MERGING - 1) / 2); -+ assert(a >= 0 && a < _JOB_TYPE_MAX_MERGING); -+ assert(b >= 0 && b < _JOB_TYPE_MAX_MERGING); - - if (a == b) - return a; -@@ -328,24 +354,50 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) { - return - b == UNIT_RELOADING; - -- case JOB_RELOAD_OR_START: -- return -- b == UNIT_ACTIVATING || -- b == UNIT_RELOADING; -- - case JOB_RESTART: - return - b == UNIT_ACTIVATING; - -+ default: -+ assert_not_reached("Invalid job type"); -+ } -+} -+ -+void job_type_collapse(JobType *t, Unit *u) { -+ UnitActiveState s; -+ -+ switch (*t) { -+ - case JOB_TRY_RESTART: -- return -- b == UNIT_ACTIVATING; -+ s = unit_active_state(u); -+ if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s)) -+ *t = JOB_NOP; -+ else -+ *t = JOB_RESTART; -+ break; -+ -+ case JOB_RELOAD_OR_START: -+ s = unit_active_state(u); -+ if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s)) -+ *t = JOB_START; -+ else -+ *t = JOB_RELOAD; -+ break; - - default: -- assert_not_reached("Invalid job type"); -+ ; - } - } - -+int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) { -+ JobType t = job_type_lookup_merge(*a, b); -+ if (t < 0) -+ return -EEXIST; -+ *a = t; -+ job_type_collapse(a, u); -+ return 0; -+} -+ - bool job_is_runnable(Job *j) { - Iterator i; - Unit *other; -@@ -362,10 +414,12 @@ bool job_is_runnable(Job *j) { - if (j->ignore_order) - return true; - -+ if (j->type == JOB_NOP) -+ return true; -+ - if (j->type == JOB_START || - j->type == JOB_VERIFY_ACTIVE || -- j->type == JOB_RELOAD || -- j->type == JOB_RELOAD_OR_START) { -+ j->type == JOB_RELOAD) { - - /* Immediate result is that the job is or might be - * started. In this case lets wait for the -@@ -383,8 +437,7 @@ bool job_is_runnable(Job *j) { - SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) - if (other->job && - (other->job->type == JOB_STOP || -- other->job->type == JOB_RESTART || -- other->job->type == JOB_TRY_RESTART)) -+ other->job->type == JOB_RESTART)) - return false; - - /* This means that for a service a and a service b where b -@@ -416,6 +469,7 @@ int job_run_and_invalidate(Job *j) { - - assert(j); - assert(j->installed); -+ assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION); - - if (j->in_run_queue) { - LIST_REMOVE(Job, run_queue, j->manager->run_queue, j); -@@ -441,15 +495,6 @@ int job_run_and_invalidate(Job *j) { - - switch (j->type) { - -- case JOB_RELOAD_OR_START: -- if (unit_active_state(j->unit) == UNIT_ACTIVE) { -- j->type = JOB_RELOAD; -- r = unit_reload(j->unit); -- break; -- } -- j->type = JOB_START; -- /* fall through */ -- - case JOB_START: - r = unit_start(j->unit); - -@@ -469,14 +514,6 @@ int job_run_and_invalidate(Job *j) { - break; - } - -- case JOB_TRY_RESTART: -- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(j->unit))) { -- r = -ENOEXEC; -- break; -- } -- j->type = JOB_RESTART; -- /* fall through */ -- - case JOB_STOP: - case JOB_RESTART: - r = unit_stop(j->unit); -@@ -490,11 +527,16 @@ int job_run_and_invalidate(Job *j) { - r = unit_reload(j->unit); - break; - -+ case JOB_NOP: -+ r = -EALREADY; -+ break; -+ - default: - assert_not_reached("Unknown job type"); - } - -- if ((j = manager_get_job(m, id))) { -+ j = manager_get_job(m, id); -+ if (j) { - if (r == -EALREADY) - r = job_finish_and_invalidate(j, JOB_DONE, true); - else if (r == -ENOEXEC) -@@ -563,6 +605,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { - - assert(j); - assert(j->installed); -+ assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION); - - job_add_to_dbus_queue(j); - -@@ -596,29 +639,25 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { - if (result != JOB_DONE && recursive) { - - if (t == JOB_START || -- t == JOB_VERIFY_ACTIVE || -- t == JOB_RELOAD_OR_START) { -+ t == JOB_VERIFY_ACTIVE) { - - SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i) - if (other->job && - (other->job->type == JOB_START || -- other->job->type == JOB_VERIFY_ACTIVE || -- other->job->type == JOB_RELOAD_OR_START)) -+ other->job->type == JOB_VERIFY_ACTIVE)) - job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); - - SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i) - if (other->job && - (other->job->type == JOB_START || -- other->job->type == JOB_VERIFY_ACTIVE || -- other->job->type == JOB_RELOAD_OR_START)) -+ other->job->type == JOB_VERIFY_ACTIVE)) - job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); - - SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i) - if (other->job && - !other->job->override && - (other->job->type == JOB_START || -- other->job->type == JOB_VERIFY_ACTIVE || -- other->job->type == JOB_RELOAD_OR_START)) -+ other->job->type == JOB_VERIFY_ACTIVE)) - job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); - - } else if (t == JOB_STOP) { -@@ -626,8 +665,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { - SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i) - if (other->job && - (other->job->type == JOB_START || -- other->job->type == JOB_VERIFY_ACTIVE || -- other->job->type == JOB_RELOAD_OR_START)) -+ other->job->type == JOB_VERIFY_ACTIVE)) - job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); - } - } -@@ -807,6 +845,8 @@ int job_deserialize(Job *j, FILE *f, FDSet *fds) { - JobType t = job_type_from_string(v); - if (t < 0) - log_debug("Failed to parse job type %s", v); -+ else if (t >= _JOB_TYPE_MAX_IN_TRANSACTION) -+ log_debug("Cannot deserialize job of type %s", v); - else - j->type = t; - } else if (streq(l, "job-state")) { -@@ -886,6 +926,7 @@ static const char* const job_type_table[_JOB_TYPE_MAX] = { - [JOB_RELOAD_OR_START] = "reload-or-start", - [JOB_RESTART] = "restart", - [JOB_TRY_RESTART] = "try-restart", -+ [JOB_NOP] = "nop", - }; - - DEFINE_STRING_TABLE_LOOKUP(job_type, JobType); -diff --git a/src/job.h b/src/job.h -index 5b326ef..4edf3b9 100644 ---- a/src/job.h -+++ b/src/job.h -@@ -46,14 +46,34 @@ enum JobType { - - JOB_STOP, - -- JOB_RELOAD, /* if running reload */ -- JOB_RELOAD_OR_START, /* if running reload, if not running start */ -+ JOB_RELOAD, /* if running, reload */ - - /* Note that restarts are first treated like JOB_STOP, but - * then instead of finishing are patched to become - * JOB_START. */ -- JOB_RESTART, /* if running stop, then start unconditionally */ -- JOB_TRY_RESTART, /* if running stop and then start */ -+ JOB_RESTART, /* If running, stop. Then start unconditionally. */ -+ -+ _JOB_TYPE_MAX_MERGING, -+ -+ /* JOB_NOP can enter into a transaction, but as it won't pull in -+ * any dependencies, it won't have to merge with anything. -+ * job_install() avoids the problem of merging JOB_NOP too (it's -+ * special-cased, only merges with other JOB_NOPs). */ -+ JOB_NOP = _JOB_TYPE_MAX_MERGING, /* do nothing */ -+ -+ _JOB_TYPE_MAX_IN_TRANSACTION, -+ -+ /* JOB_TRY_RESTART can never appear in a transaction, because -+ * it always collapses into JOB_RESTART or JOB_NOP before entering. -+ * Thus we never need to merge it with anything. */ -+ JOB_TRY_RESTART = _JOB_TYPE_MAX_IN_TRANSACTION, /* if running, stop and then start */ -+ -+ /* JOB_RELOAD_OR_START won't enter into a transaction and cannot result -+ * from transaction merging (there's no way for JOB_RELOAD and -+ * JOB_START to meet in one transaction). It can result from a merge -+ * during job installation, but then it will immediately collapse into -+ * one of the two simpler types. */ -+ JOB_RELOAD_OR_START, /* if running, reload, otherwise start */ - - _JOB_TYPE_MAX, - _JOB_TYPE_INVALID = -1 -@@ -150,7 +170,7 @@ Job* job_new(Unit *unit, JobType type); - Job* job_new_raw(Unit *unit); - void job_free(Job *job); - Job* job_install(Job *j); --void job_install_deserialized(Job *j); -+int job_install_deserialized(Job *j); - void job_uninstall(Job *j); - void job_dump(Job *j, FILE*f, const char *prefix); - int job_serialize(Job *j, FILE *f, FDSet *fds); -@@ -164,14 +184,6 @@ int job_merge(Job *j, Job *other); - - JobType job_type_lookup_merge(JobType a, JobType b); - --static inline int job_type_merge(JobType *a, JobType b) { -- JobType t = job_type_lookup_merge(*a, b); -- if (t < 0) -- return -EEXIST; -- *a = t; -- return 0; --} -- - static inline bool job_type_is_mergeable(JobType a, JobType b) { - return job_type_lookup_merge(a, b) >= 0; - } -@@ -187,6 +199,12 @@ static inline bool job_type_is_superset(JobType a, JobType b) { - - bool job_type_is_redundant(JobType a, UnitActiveState b); - -+/* Collapses a state-dependent job type into a simpler type by observing -+ * the state of the unit which it is going to be applied to. */ -+void job_type_collapse(JobType *t, Unit *u); -+ -+int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u); -+ - bool job_is_runnable(Job *j); - - void job_add_to_run_queue(Job *j); -diff --git a/src/manager.c b/src/manager.c -index 7bff456..0f87e9f 100644 ---- a/src/manager.c -+++ b/src/manager.c -@@ -650,6 +650,8 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove - - log_debug("Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode)); - -+ job_type_collapse(&type, unit); -+ - tr = transaction_new(); - if (!tr) - return -ENOMEM; -diff --git a/src/test-job-type.c b/src/test-job-type.c -index 9de21e1..c7a9b5a 100644 ---- a/src/test-job-type.c -+++ b/src/test-job-type.c -@@ -25,59 +25,80 @@ - #include - - #include "job.h" -+#include "unit.h" -+#include "service.h" - - int main(int argc, char*argv[]) { -- JobType a, b, c, d, e, f, g; -+ JobType a, b, c, ab, bc, ab_c, bc_a, a_bc; -+ const ServiceState test_states[] = { SERVICE_DEAD, SERVICE_RUNNING }; -+ unsigned i; -+ bool merged_ab; - -- for (a = 0; a < _JOB_TYPE_MAX; a++) -- for (b = 0; b < _JOB_TYPE_MAX; b++) { -+ /* fake a unit */ -+ static Service s = { -+ .meta.load_state = UNIT_LOADED, -+ .type = UNIT_SERVICE -+ }; -+ Unit *u = UNIT(&s); - -- if (!job_type_is_mergeable(a, b)) -- printf("Not mergeable: %s + %s\n", job_type_to_string(a), job_type_to_string(b)); -+ for (i = 0; i < ELEMENTSOF(test_states); i++) { -+ s.state = test_states[i]; -+ printf("\nWith collapsing for service state %s\n" -+ "=========================================\n", service_state_to_string(s.state)); -+ for (a = 0; a < _JOB_TYPE_MAX_MERGING; a++) { -+ for (b = 0; b < _JOB_TYPE_MAX_MERGING; b++) { - -- for (c = 0; c < _JOB_TYPE_MAX; c++) { -+ ab = a; -+ merged_ab = (job_type_merge_and_collapse(&ab, b, u) >= 0); - -- /* Verify transitivity of mergeability -- * of job types */ -- assert(!job_type_is_mergeable(a, b) || -- !job_type_is_mergeable(b, c) || -- job_type_is_mergeable(a, c)); -+ if (!job_type_is_mergeable(a, b)) { -+ assert(!merged_ab); -+ printf("Not mergeable: %s + %s\n", job_type_to_string(a), job_type_to_string(b)); -+ continue; -+ } -+ -+ assert(merged_ab); -+ printf("%s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(ab)); - -- d = a; -- if (job_type_merge(&d, b) >= 0) { -+ for (c = 0; c < _JOB_TYPE_MAX_MERGING; c++) { - -- printf("%s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(d)); -+ /* Verify transitivity of mergeability of job types */ -+ assert(!job_type_is_mergeable(a, b) || -+ !job_type_is_mergeable(b, c) || -+ job_type_is_mergeable(a, c)); - -- /* Verify that merged entries can be -- * merged with the same entries they -- * can be merged with separately */ -- assert(!job_type_is_mergeable(a, c) || job_type_is_mergeable(d, c)); -- assert(!job_type_is_mergeable(b, c) || job_type_is_mergeable(d, c)); -+ /* Verify that merged entries can be merged with the same entries -+ * they can be merged with separately */ -+ assert(!job_type_is_mergeable(a, c) || job_type_is_mergeable(ab, c)); -+ assert(!job_type_is_mergeable(b, c) || job_type_is_mergeable(ab, c)); - -- /* Verify that if a merged -- * with b is not mergeable with -- * c then either a or b is not -- * mergeable with c either. */ -- assert(job_type_is_mergeable(d, c) || !job_type_is_mergeable(a, c) || !job_type_is_mergeable(b, c)); -+ /* Verify that if a merged with b is not mergeable with c, then -+ * either a or b is not mergeable with c either. */ -+ assert(job_type_is_mergeable(ab, c) || !job_type_is_mergeable(a, c) || !job_type_is_mergeable(b, c)); - -- e = b; -- if (job_type_merge(&e, c) >= 0) { -+ bc = b; -+ if (job_type_merge_and_collapse(&bc, c, u) >= 0) { - - /* Verify associativity */ - -- f = d; -- assert(job_type_merge(&f, c) == 0); -+ ab_c = ab; -+ assert(job_type_merge_and_collapse(&ab_c, c, u) == 0); -+ -+ bc_a = bc; -+ assert(job_type_merge_and_collapse(&bc_a, a, u) == 0); - -- g = e; -- assert(job_type_merge(&g, a) == 0); -+ a_bc = a; -+ assert(job_type_merge_and_collapse(&a_bc, bc, u) == 0); - -- assert(f == g); -+ assert(ab_c == bc_a); -+ assert(ab_c == a_bc); - -- printf("%s + %s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(c), job_type_to_string(d)); -+ printf("%s + %s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(c), job_type_to_string(ab_c)); - } - } - } - } -+ } - - - return 0; -diff --git a/src/transaction.c b/src/transaction.c -index f687539..ceac5a6 100644 ---- a/src/transaction.c -+++ b/src/transaction.c -@@ -212,7 +212,7 @@ static int transaction_merge_jobs(Transaction *tr, DBusError *e) { - - t = j->type; - LIST_FOREACH(transaction, k, j->transaction_next) { -- if (job_type_merge(&t, k->type) >= 0) -+ if (job_type_merge_and_collapse(&t, k->type, j->unit) >= 0) - continue; - - /* OK, we could not merge all jobs for this -@@ -238,9 +238,9 @@ static int transaction_merge_jobs(Transaction *tr, DBusError *e) { - JobType t = j->type; - Job *k; - -- /* Merge all transactions */ -+ /* Merge all transaction jobs for j->unit */ - LIST_FOREACH(transaction, k, j->transaction_next) -- assert_se(job_type_merge(&t, k->type) == 0); -+ assert_se(job_type_merge_and_collapse(&t, k->type, j->unit) == 0); - - while ((k = j->transaction_next)) { - if (tr->anchor_job == k) { -@@ -774,6 +774,7 @@ int transaction_add_job_and_dependencies( - - assert(tr); - assert(type < _JOB_TYPE_MAX); -+ assert(type < _JOB_TYPE_MAX_IN_TRANSACTION); - assert(unit); - - /* log_debug("Pulling in %s/%s from %s/%s", */ -@@ -824,7 +825,8 @@ int transaction_add_job_and_dependencies( - assert(!tr->anchor_job); - tr->anchor_job = ret; - } -- if (is_new && !ignore_requirements) { -+ -+ if (is_new && !ignore_requirements && type != JOB_NOP) { - Set *following; - - /* If we are following some other unit, make sure we -@@ -844,7 +846,7 @@ int transaction_add_job_and_dependencies( - } - - /* Finally, recursively add in all dependencies. */ -- if (type == JOB_START || type == JOB_RELOAD_OR_START || type == JOB_RESTART) { -+ if (type == JOB_START || type == JOB_RESTART) { - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) { - r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e); - if (r < 0) { -@@ -934,7 +936,7 @@ int transaction_add_job_and_dependencies( - - } - -- if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) { -+ if (type == JOB_STOP || type == JOB_RESTART) { - - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) { - r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e); -@@ -959,7 +961,7 @@ int transaction_add_job_and_dependencies( - } - } - -- if (type == JOB_RELOAD || type == JOB_RELOAD_OR_START) { -+ if (type == JOB_RELOAD) { - - SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATE_RELOAD_TO], i) { - r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e); -@@ -972,7 +974,7 @@ int transaction_add_job_and_dependencies( - } - } - -- /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */ -+ /* JOB_VERIFY_STARTED require no dependency handling */ - } - - return 0; -diff --git a/src/unit.c b/src/unit.c -index ff8331c..3625ed2 100644 ---- a/src/unit.c -+++ b/src/unit.c -@@ -249,6 +249,9 @@ bool unit_check_gc(Unit *u) { - if (u->job) - return true; - -+ if (u->nop_job) -+ return true; -+ - if (unit_active_state(u) != UNIT_INACTIVE) - return true; - -@@ -358,6 +361,12 @@ void unit_free(Unit *u) { - job_free(j); - } - -+ if (u->nop_job) { -+ Job *j = u->nop_job; -+ job_uninstall(j); -+ job_free(j); -+ } -+ - for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) - bidi_set_free(u, u->dependencies[d]); - -@@ -501,6 +510,9 @@ int unit_merge(Unit *u, Unit *other) { - if (other->job) - return -EEXIST; - -+ if (other->nop_job) -+ return -EEXIST; -+ - if (!UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) - return -EEXIST; - -@@ -729,6 +741,9 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { - if (u->job) - job_dump(u->job, f, prefix2); - -+ if (u->nop_job) -+ job_dump(u->nop_job, f, prefix2); -+ - free(p2); - } - -@@ -1507,6 +1522,7 @@ bool unit_job_is_applicable(Unit *u, JobType j) { - case JOB_VERIFY_ACTIVE: - case JOB_START: - case JOB_STOP: -+ case JOB_NOP: - return true; - - case JOB_RESTART: -@@ -2293,6 +2309,11 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds) { - job_serialize(u->job, f, fds); - } - -+ if (u->nop_job) { -+ fprintf(f, "job\n"); -+ job_serialize(u->nop_job, f, fds); -+ } -+ - dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp); - dual_timestamp_serialize(f, "active-enter-timestamp", &u->active_enter_timestamp); - dual_timestamp_serialize(f, "active-exit-timestamp", &u->active_exit_timestamp); -@@ -2382,12 +2403,18 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { - return r; - } - -- job_install_deserialized(j); - r = hashmap_put(u->manager->jobs, UINT32_TO_PTR(j->id), j); - if (r < 0) { - job_free(j); - return r; - } -+ -+ r = job_install_deserialized(j); -+ if (r < 0) { -+ hashmap_remove(u->manager->jobs, UINT32_TO_PTR(j->id)); -+ job_free(j); -+ return r; -+ } - } else { - /* legacy */ - JobType type = job_type_from_string(v); -diff --git a/src/unit.h b/src/unit.h -index 5fceabb..62b82bc 100644 ---- a/src/unit.h -+++ b/src/unit.h -@@ -158,10 +158,12 @@ struct Unit { - char *fragment_path; /* if loaded from a config file this is the primary path to it */ - usec_t fragment_mtime; - -- /* If there is something to do with this unit, then this is -- * the job for it */ -+ /* If there is something to do with this unit, then this is the installed job for it */ - Job *job; - -+ /* JOB_NOP jobs are special and can be installed without disturbing the real job. */ -+ Job *nop_job; -+ - usec_t job_timeout; - - /* References to this */ --- -1.7.7 - - -From ad1ece751b204c21424b6bf1de265fec406ba2e4 Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Sat, 12 May 2012 21:06:27 +0200 -Subject: [PATCH 30/30] job: only jobs on the runqueue can be run - ---- - src/job.c | 7 +++---- - 1 files changed, 3 insertions(+), 4 deletions(-) - -diff --git a/src/job.c b/src/job.c -index 2438f39..d6e7cb1 100644 ---- a/src/job.c -+++ b/src/job.c -@@ -470,11 +470,10 @@ int job_run_and_invalidate(Job *j) { - assert(j); - assert(j->installed); - assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION); -+ assert(j->in_run_queue); - -- if (j->in_run_queue) { -- LIST_REMOVE(Job, run_queue, j->manager->run_queue, j); -- j->in_run_queue = false; -- } -+ LIST_REMOVE(Job, run_queue, j->manager->run_queue, j); -+ j->in_run_queue = false; - - if (j->state != JOB_WAITING) - return 0; --- -1.7.7 - diff --git a/journal-bugfixes.patch b/journal-bugfixes.patch deleted file mode 100644 index 428d165..0000000 --- a/journal-bugfixes.patch +++ /dev/null @@ -1,186 +0,0 @@ -From 911efc97f9bfe2ad4f4d021f5e76d05c8d5d81ac Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Thu, 12 Apr 2012 12:57:41 +0200 -Subject: [PATCH 1/4] journald: add missing flag to open() - ---- - src/journal/journald.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/src/journal/journald.c b/src/journal/journald.c -index baad3ab..c8b400a 100644 ---- a/src/journal/journald.c -+++ b/src/journal/journald.c -@@ -2461,7 +2461,7 @@ static int open_proc_kmsg(Server *s) { - return 0; - - -- s->proc_kmsg_fd = open("/proc/kmsg", O_CLOEXEC|O_NONBLOCK|O_NOCTTY); -+ s->proc_kmsg_fd = open("/proc/kmsg", O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); - if (s->proc_kmsg_fd < 0) { - log_warning("Failed to open /proc/kmsg, ignoring: %m"); - return 0; --- -1.7.7 - - -From 94b8299358fd743137857bc0f28ab62bcf6eec92 Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Fri, 13 Apr 2012 13:58:50 +0200 -Subject: [PATCH 2/4] fix a couple of things found with the llvm static - analyzer - ---- - src/journal/journal-file.c | 2 +- - src/journal/journald.c | 2 +- - src/logs-show.c | 2 +- - src/manager.c | 2 +- - 4 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c -index 474dd5c..5255c3b 100644 ---- a/src/journal/journal-file.c -+++ b/src/journal/journal-file.c -@@ -1974,7 +1974,7 @@ int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t m - size_t q; - struct stat st; - char *p; -- unsigned long long seqnum, realtime; -+ unsigned long long seqnum = 0, realtime; - sd_id128_t seqnum_id; - bool have_seqnum; - -diff --git a/src/journal/journald.c b/src/journal/journald.c -index c8b400a..1118b7e 100644 ---- a/src/journal/journald.c -+++ b/src/journal/journald.c -@@ -1140,7 +1140,7 @@ static void process_native_message( - char *identifier = NULL, *message = NULL; - - assert(s); -- assert(buffer || n == 0); -+ assert(buffer || buffer_size == 0); - - p = buffer; - remaining = buffer_size; -diff --git a/src/logs-show.c b/src/logs-show.c -index f71c6b0..eb9a902 100644 ---- a/src/logs-show.c -+++ b/src/logs-show.c -@@ -541,7 +541,7 @@ int show_journal_by_unit( - bool follow) { - - char *m = NULL; -- sd_journal *j; -+ sd_journal *j = NULL; - int r; - int fd; - unsigned line = 0; -diff --git a/src/manager.c b/src/manager.c -index 74bd740..3e592b6 100644 ---- a/src/manager.c -+++ b/src/manager.c -@@ -2979,7 +2979,7 @@ bool manager_unit_pending_inactive(Manager *m, const char *name) { - - void manager_check_finished(Manager *m) { - char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX]; -- usec_t kernel_usec = 0, initrd_usec = 0, userspace_usec = 0, total_usec = 0; -+ usec_t kernel_usec, initrd_usec, userspace_usec, total_usec; - - assert(m); - --- -1.7.7 - - -From f83fa045b967478a80ca55477dfe6a5be5f0b4a8 Mon Sep 17 00:00:00 2001 -From: Sjoerd Simons -Date: Sat, 14 Apr 2012 14:11:08 +0200 -Subject: [PATCH 3/4] journal: crash when filesystem is low on space - -When space is getting too low on a file system rotating the journal file -will fail after the rotation, as opening the new logfile will fail. - -Recognize this when logging the error and don't try to dereference a -NULL JournalFile pointer. ---- - src/journal/journald.c | 16 +++++++++++++--- - 1 files changed, 13 insertions(+), 3 deletions(-) - -diff --git a/src/journal/journald.c b/src/journal/journald.c -index 1118b7e..9180656 100644 ---- a/src/journal/journald.c -+++ b/src/journal/journald.c -@@ -330,7 +330,10 @@ static void server_rotate(Server *s) { - if (s->runtime_journal) { - r = journal_file_rotate(&s->runtime_journal); - if (r < 0) -- log_error("Failed to rotate %s: %s", s->runtime_journal->path, strerror(-r)); -+ if (s->runtime_journal) -+ log_error("Failed to rotate %s: %s", s->runtime_journal->path, strerror(-r)); -+ else -+ log_error("Failed to create new runtime journal: %s", strerror(-r)); - else - server_fix_perms(s, s->runtime_journal, 0); - } -@@ -338,7 +341,11 @@ static void server_rotate(Server *s) { - if (s->system_journal) { - r = journal_file_rotate(&s->system_journal); - if (r < 0) -- log_error("Failed to rotate %s: %s", s->system_journal->path, strerror(-r)); -+ if (s->system_journal) -+ log_error("Failed to rotate %s: %s", s->system_journal->path, strerror(-r)); -+ else -+ log_error("Failed to create new system journal: %s", strerror(-r)); -+ - else - server_fix_perms(s, s->system_journal, 0); - } -@@ -346,7 +353,10 @@ static void server_rotate(Server *s) { - HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) { - r = journal_file_rotate(&f); - if (r < 0) -- log_error("Failed to rotate %s: %s", f->path, strerror(-r)); -+ if (f->path) -+ log_error("Failed to rotate %s: %s", f->path, strerror(-r)); -+ else -+ log_error("Failed to create user journal: %s", strerror(-r)); - else { - hashmap_replace(s->user_journals, k, f); - server_fix_perms(s, s->system_journal, PTR_TO_UINT32(k)); --- -1.7.7 - - -From d80e2f5c26aae25c0773042bcd1599d3c583bf6a Mon Sep 17 00:00:00 2001 -From: Michal Schmidt -Date: Tue, 12 Jun 2012 16:45:09 +0200 -Subject: [PATCH 4/4] journal-file: fix mmap leak - -https://bugzilla.redhat.com/show_bug.cgi?id=831132 ---- - src/journal/journal-file.c | 7 +++++-- - 1 files changed, 5 insertions(+), 2 deletions(-) - -diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c -index 5255c3b..e242fa2 100644 ---- a/src/journal/journal-file.c -+++ b/src/journal/journal-file.c -@@ -67,9 +67,12 @@ void journal_file_close(JournalFile *f) { - - assert(f); - -- if (f->header && f->writable) -- f->header->state = STATE_OFFLINE; -+ if (f->header) { -+ if (f->writable) -+ f->header->state = STATE_OFFLINE; - -+ munmap(f->header, PAGE_ALIGN(sizeof(Header))); -+ } - - for (t = 0; t < _WINDOW_MAX; t++) - if (f->windows[t].ptr) --- -1.7.7 - diff --git a/journalctl-pager-improvement.patch b/journalctl-pager-improvement.patch deleted file mode 100644 index 81be11e..0000000 --- a/journalctl-pager-improvement.patch +++ /dev/null @@ -1,448 +0,0 @@ -From 1682c4bf5b993b956b0367aedc9f0638055540f4 Mon Sep 17 00:00:00 2001 -From: Eelco Dolstra -Date: Thu, 19 Jul 2012 21:12:16 +0000 -Subject: [PATCH 1/3] journalctl: fix assertion failure in ellipsize_mem() - -When showing the journal through "journalctl --no-pager", if the -prefix of the log message (i.e. the date and syslog identifier) is -less than 3 characters shorter than the width of the terminal, you -get: - -Assertion 'new_length >= 3' failed at src/shared/util.c:3859, function ellipsize_mem(). Aborting. - -because there is not enough space for the "...". This patch add the -necessary check. ---- - src/logs-show.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/logs-show.c b/src/logs-show.c -index eb9a902..72367f2 100644 ---- a/src/logs-show.c -+++ b/src/logs-show.c -@@ -230,7 +230,7 @@ static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool s - printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len)); - } else if (message_len + n < n_columns) - printf(": %.*s\n", (int) message_len, message); -- else if (n < n_columns) { -+ else if (n < n_columns && n_columns - n - 2 >= 3) { - char *e; - - e = ellipsize_mem(message, message_len, n_columns - n - 2, 90); --- -1.7.10.4 - - -From ee385756e10862a8bcc0e5c7a3776135af84c750 Mon Sep 17 00:00:00 2001 -From: Zbigniew Jedrzejewski-Szmek -Date: Fri, 20 Jul 2012 09:06:26 +0200 -Subject: [PATCH 2/3] journalctl: fix ellipsization with PAGER=cat - -There are other reasons for not opening the pager then the --no-pager -or --follow options (described below). If the pager is not used, -messages must be ellipsized. - -On Fri, Jul 20, 2012 at 05:42:44AM +0000, Shawn Landen wrote: -> "Pager to use when --no-pager is not given; overrides $PAGER. -> Setting this to an empty string or the value cat is equivalent to passing --no-pager." - -Conflicts: - src/journal/journalctl.c ---- - src/journal/journalctl.c | 5 +---- - src/pager.c | 17 ++++++++++------- - src/pager.h | 4 +++- - 3 files changed, 14 insertions(+), 12 deletions(-) - -diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c -index f90b2dd..3a3b043 100644 ---- a/src/journal/journalctl.c -+++ b/src/journal/journalctl.c -@@ -259,10 +259,7 @@ int main(int argc, char *argv[]) { - goto finish; - } - -- if (!arg_no_pager && !arg_follow) { -- columns(); -- pager_open(); -- } -+ have_pager = !arg_no_pager && !arg_follow && pager_open(); - - if (arg_output == OUTPUT_JSON) { - fputc('[', stdout); -diff --git a/src/pager.c b/src/pager.c -index 3fc8182..8065841 100644 ---- a/src/pager.c -+++ b/src/pager.c -@@ -44,20 +44,20 @@ _noreturn_ static void pager_fallback(void) { - _exit(EXIT_SUCCESS); - } - --void pager_open(void) { -+bool pager_open(void) { - int fd[2]; - const char *pager; - pid_t parent_pid; - - if (pager_pid > 0) -- return; -+ return false; - - if ((pager = getenv("SYSTEMD_PAGER")) || (pager = getenv("PAGER"))) - if (!*pager || streq(pager, "cat")) -- return; -+ return false; - - if (isatty(STDOUT_FILENO) <= 0) -- return; -+ return false; - - /* Determine and cache number of columns before we spawn the - * pager so that we get the value from the actual tty */ -@@ -65,7 +65,7 @@ void pager_open(void) { - - if (pipe(fd) < 0) { - log_error("Failed to create pager pipe: %m"); -- return; -+ return false; - } - - parent_pid = getpid(); -@@ -74,7 +74,7 @@ void pager_open(void) { - if (pager_pid < 0) { - log_error("Failed to fork pager: %m"); - close_pipe(fd); -- return; -+ return false; - } - - /* In the child start the pager */ -@@ -115,10 +115,13 @@ void pager_open(void) { - } - - /* Return in the parent */ -- if (dup2(fd[1], STDOUT_FILENO) < 0) -+ if (dup2(fd[1], STDOUT_FILENO) < 0) { - log_error("Failed to duplicate pager pipe: %m"); -+ return false; -+ } - - close_pipe(fd); -+ return true; - } - - void pager_close(void) { -diff --git a/src/pager.h b/src/pager.h -index b5b4998..bd1a983 100644 ---- a/src/pager.h -+++ b/src/pager.h -@@ -22,7 +22,9 @@ - along with systemd; If not, see . - ***/ - --void pager_open(void); -+#include -+ -+bool pager_open(void); - void pager_close(void); - - #endif --- -1.7.10.4 - - -From ae88e07aec6280e90582703f7950468604182a4b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= -Date: Tue, 17 Jul 2012 07:35:08 +0200 -Subject: [PATCH 3/3] journalctl: do not ellipsize when using pager -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If a pager is used, ellipsization is redundant — the pager does -that better by hiding the part that cannot be shown. Pager's advantage -is that the user can press → to view the hidden part of a message, -and then ← to return. - -cherry-picked from 92a1fd9e95954a557d6fe27b56f5ef1b89fc2f5e and 25277cd7fbd77e4c8b20572570aa77c7da9abcc2 ---- - src/journal/journalctl.c | 7 ++++- - src/logs-show.c | 66 ++++++++++++++++++++++++++++------------------ - src/logs-show.h | 14 +++++++--- - src/systemctl.c | 8 +++++- - 4 files changed, 64 insertions(+), 31 deletions(-) - -diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c -index 3a3b043..197af71 100644 ---- a/src/journal/journalctl.c -+++ b/src/journal/journalctl.c -@@ -198,6 +198,7 @@ int main(int argc, char *argv[]) { - sd_journal *j = NULL; - unsigned line = 0; - bool need_seek = false; -+ bool have_pager; - - log_parse_environment(); - log_open(); -@@ -268,6 +269,10 @@ int main(int argc, char *argv[]) { - - for (;;) { - for (;;) { -+ int flags = -+ arg_show_all * OUTPUT_SHOW_ALL | -+ have_pager * OUTPUT_FULL_WIDTH; -+ - if (need_seek) { - r = sd_journal_next(j); - if (r < 0) { -@@ -281,7 +286,7 @@ int main(int argc, char *argv[]) { - - line ++; - -- r = output_journal(j, arg_output, line, 0, arg_show_all); -+ r = output_journal(j, arg_output, line, 0, flags); - if (r < 0) - goto finish; - -diff --git a/src/logs-show.c b/src/logs-show.c -index 72367f2..06ba569 100644 ---- a/src/logs-show.c -+++ b/src/logs-show.c -@@ -86,7 +86,8 @@ static bool shall_print(bool show_all, char *p, size_t l) { - return true; - } - --static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool show_all, bool monotonic_mode) { -+static int output_short(sd_journal *j, unsigned line, unsigned n_columns, -+ OutputFlags flags) { - int r; - const void *data; - size_t length; -@@ -150,7 +151,7 @@ static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool s - goto finish; - } - -- if (monotonic_mode) { -+ if (flags & OUTPUT_MONOTONIC_MODE) { - uint64_t t; - sd_id128_t boot_id; - -@@ -202,33 +203,39 @@ static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool s - n += strlen(buf); - } - -- if (hostname && shall_print(show_all, hostname, hostname_len)) { -+ if (hostname && shall_print(flags & OUTPUT_SHOW_ALL, -+ hostname, hostname_len)) { - printf(" %.*s", (int) hostname_len, hostname); - n += hostname_len + 1; - } - -- if (identifier && shall_print(show_all, identifier, identifier_len)) { -+ if (identifier && shall_print(flags & OUTPUT_SHOW_ALL, -+ identifier, identifier_len)) { - printf(" %.*s", (int) identifier_len, identifier); - n += identifier_len + 1; -- } else if (comm && shall_print(show_all, comm, comm_len)) { -+ } else if (comm && shall_print(flags & OUTPUT_SHOW_ALL, -+ comm, comm_len)) { - printf(" %.*s", (int) comm_len, comm); - n += comm_len + 1; -- } -+ } else -+ putchar(' '); - -- if (pid && shall_print(show_all, pid, pid_len)) { -+ if (pid && shall_print(flags & OUTPUT_SHOW_ALL, pid, pid_len)) { - printf("[%.*s]", (int) pid_len, pid); - n += pid_len + 2; -- } else if (fake_pid && shall_print(show_all, fake_pid, fake_pid_len)) { -+ } else if (fake_pid && shall_print(flags & OUTPUT_SHOW_ALL, -+ fake_pid, fake_pid_len)) { - printf("[%.*s]", (int) fake_pid_len, fake_pid); - n += fake_pid_len + 2; - } - -- if (show_all) -+ if (flags & OUTPUT_SHOW_ALL) - printf(": %.*s\n", (int) message_len, message); - else if (contains_unprintable(message, message_len)) { - char bytes[FORMAT_BYTES_MAX]; - printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len)); -- } else if (message_len + n < n_columns) -+ } else if ((flags & OUTPUT_FULL_WIDTH) || -+ (message_len + n + 1 < n_columns)) - printf(": %.*s\n", (int) message_len, message); - else if (n < n_columns && n_columns - n - 2 >= 3) { - char *e; -@@ -259,15 +266,18 @@ finish: - return r; - } - --static int output_short_realtime(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { -- return output_short(j, line, n_columns, show_all, false); -+static int output_short_realtime(sd_journal *j, unsigned line, -+ unsigned n_columns, OutputFlags flags) { -+ return output_short(j, line, n_columns, flags & ~OUTPUT_MONOTONIC_MODE); - } - --static int output_short_monotonic(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { -- return output_short(j, line, n_columns, show_all, true); -+static int output_short_monotonic(sd_journal *j, unsigned line, -+ unsigned n_columns, OutputFlags flags) { -+ return output_short(j, line, n_columns, flags | OUTPUT_MONOTONIC_MODE); - } - --static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { -+static int output_verbose(sd_journal *j, unsigned line, -+ unsigned n_columns, OutputFlags flags) { - const void *data; - size_t length; - char *cursor; -@@ -296,7 +306,7 @@ static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool - free(cursor); - - SD_JOURNAL_FOREACH_DATA(j, data, length) { -- if (!show_all && (length > PRINT_THRESHOLD || -+ if (!(flags & OUTPUT_SHOW_ALL) && (length > PRINT_THRESHOLD || - contains_unprintable(data, length))) { - const char *c; - char bytes[FORMAT_BYTES_MAX]; -@@ -318,7 +328,8 @@ static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool - return 0; - } - --static int output_export(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { -+static int output_export(sd_journal *j, unsigned line, -+ unsigned n_columns, OutputFlags flags) { - sd_id128_t boot_id; - char sid[33]; - int r; -@@ -424,7 +435,8 @@ static void json_escape(const char* p, size_t l) { - } - } - --static int output_json(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { -+static int output_json(sd_journal *j, unsigned line, -+ unsigned n_columns, OutputFlags flags) { - uint64_t realtime, monotonic; - char *cursor; - const void *data; -@@ -491,7 +503,8 @@ static int output_json(sd_journal *j, unsigned line, unsigned n_columns, bool sh - return 0; - } - --static int output_cat(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { -+static int output_cat(sd_journal *j, unsigned line, -+ unsigned n_columns, OutputFlags flags) { - const void *data; - size_t l; - int r; -@@ -512,7 +525,8 @@ static int output_cat(sd_journal *j, unsigned line, unsigned n_columns, bool sho - return 0; - } - --static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, unsigned n_columns, bool show_all) = { -+static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, -+ unsigned n_columns, OutputFlags flags) = { - [OUTPUT_SHORT] = output_short_realtime, - [OUTPUT_SHORT_MONOTONIC] = output_short_monotonic, - [OUTPUT_VERBOSE] = output_verbose, -@@ -521,14 +535,15 @@ static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, unsign - [OUTPUT_CAT] = output_cat - }; - --int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all) { -+int output_journal(sd_journal *j, OutputMode mode, unsigned line, -+ unsigned n_columns, OutputFlags flags) { - assert(mode >= 0); - assert(mode < _OUTPUT_MODE_MAX); - - if (n_columns <= 0) - n_columns = columns(); - -- return output_funcs[mode](j, line, n_columns, show_all); -+ return output_funcs[mode](j, line, n_columns, flags); - } - - int show_journal_by_unit( -@@ -537,8 +552,7 @@ int show_journal_by_unit( - unsigned n_columns, - usec_t not_before, - unsigned how_many, -- bool show_all, -- bool follow) { -+ OutputFlags flags) { - - char *m = NULL; - sd_journal *j = NULL; -@@ -621,12 +635,12 @@ int show_journal_by_unit( - - line ++; - -- r = output_journal(j, mode, line, n_columns, show_all); -+ r = output_journal(j, mode, line, n_columns, flags); - if (r < 0) - goto finish; - } - -- if (!follow) -+ if (!(flags & OUTPUT_FOLLOW)) - break; - - r = fd_wait_for_event(fd, POLLIN, (usec_t) -1); -diff --git a/src/logs-show.h b/src/logs-show.h -index db9c7e3..e8c6b03 100644 ---- a/src/logs-show.h -+++ b/src/logs-show.h -@@ -39,7 +39,16 @@ typedef enum OutputMode { - _OUTPUT_MODE_INVALID = -1 - } OutputMode; - --int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all); -+typedef enum OutputFlags { -+ OUTPUT_SHOW_ALL = 1 << 0, -+ OUTPUT_MONOTONIC_MODE = 1 << 1, -+ OUTPUT_FOLLOW = 1 << 2, -+ OUTPUT_WARN_CUTOFF = 1 << 3, -+ OUTPUT_FULL_WIDTH = 1 << 4, -+} OutputFlags; -+ -+int output_journal(sd_journal *j, OutputMode mode, unsigned line, -+ unsigned n_columns, OutputFlags flags); - - int show_journal_by_unit( - const char *unit, -@@ -47,8 +56,7 @@ int show_journal_by_unit( - unsigned n_columns, - usec_t not_before, - unsigned how_many, -- bool show_all, -- bool follow); -+ OutputFlags flags); - - const char* output_mode_to_string(OutputMode m); - OutputMode output_mode_from_string(const char *s); -diff --git a/src/systemctl.c b/src/systemctl.c -index f51085f..e94e024 100644 ---- a/src/systemctl.c -+++ b/src/systemctl.c -@@ -2374,8 +2374,14 @@ static void print_status_info(UnitStatusInfo *i) { - } - - if (i->id && arg_transport != TRANSPORT_SSH) { -+ int flags = -+ arg_lines * OUTPUT_SHOW_ALL | -+ arg_follow * OUTPUT_FOLLOW; -+ - printf("\n"); -- show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow); -+ show_journal_by_unit(i->id, arg_output, 0, -+ i->inactive_exit_timestamp_monotonic, -+ arg_lines, flags); - } - - if (i->need_daemon_reload) --- -1.7.10.4 - diff --git a/logind-logout.patch b/logind-logout.patch deleted file mode 100644 index 5949223..0000000 --- a/logind-logout.patch +++ /dev/null @@ -1,156 +0,0 @@ -From 75c8e3cffd7da8eede614cf61384957af2c82a29 Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Thu, 22 Mar 2012 02:06:40 +0100 -Subject: [PATCH] logind: close FIFO before ending sessions cleanly - -For clean session endings ask logind explicitly to get rid of the FIFO -before closing it so that the FIFO logic doesn't result in su/sudo to be -terminated immediately. ---- - src/login/logind-dbus.c | 30 ++++++++++++++++++++ - src/login/pam-module.c | 71 +++++++++++++++++++++++++++++++++++++++++++++-- - 2 files changed, 98 insertions(+), 3 deletions(-) - -diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c -index d8f4d89..ea6b89f 100644 ---- a/src/login/logind-dbus.c -+++ b/src/login/logind-dbus.c -@@ -80,6 +80,9 @@ - " \n" \ - " \n" \ - " \n" \ -+ " \n" \ -+ " \n" \ -+ " \n" \ - " \n" \ - " \n" \ - " \n" \ -@@ -1075,6 +1078,33 @@ static DBusHandlerResult manager_message_handler( - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - -+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) { -+ const char *name; -+ Session *session; -+ -+ if (!dbus_message_get_args( -+ message, -+ &error, -+ DBUS_TYPE_STRING, &name, -+ DBUS_TYPE_INVALID)) -+ return bus_send_error_reply(connection, message, &error, -EINVAL); -+ -+ session = hashmap_get(m->sessions, name); -+ if (!session) -+ return bus_send_error_reply(connection, message, &error, -ENOENT); -+ -+ /* We use the FIFO to detect stray sessions where the -+ process invoking PAM dies abnormally. We need to make -+ sure that that process is not killed if at the clean -+ end of the session it closes the FIFO. Hence, with -+ this call explicitly turn off the FIFO logic, so that -+ the PAM code can finish clean up on its own */ -+ session_remove_fifo(session); -+ -+ reply = dbus_message_new_method_return(message); -+ if (!reply) -+ goto oom; -+ - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) { - const char *name; - Session *session; -diff --git a/src/login/pam-module.c b/src/login/pam-module.c -index 8544413..4106d2b 100644 ---- a/src/login/pam-module.c -+++ b/src/login/pam-module.c -@@ -414,7 +414,6 @@ _public_ PAM_EXTERN int pam_sm_open_session( - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "CreateSession"); -- - if (!m) { - pam_syslog(handle, LOG_ERR, "Could not allocate create session message."); - r = PAM_BUF_ERR; -@@ -620,11 +619,77 @@ _public_ PAM_EXTERN int pam_sm_close_session( - int argc, const char **argv) { - - const void *p = NULL; -+ const char *id; -+ DBusConnection *bus = NULL; -+ DBusMessage *m = NULL, *reply = NULL; -+ DBusError error; -+ int r; - -- pam_get_data(handle, "systemd.session-fd", &p); -+ assert(handle); -+ -+ dbus_error_init(&error); -+ -+ id = pam_getenv(handle, "XDG_SESSION_ID"); -+ if (id) { -+ -+ /* Before we go and close the FIFO we need to tell -+ * logind that this is a clean session shutdown, so -+ * that it doesn't just go and slaughter us -+ * immediately after closing the fd */ -+ -+ bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); -+ if (!bus) { -+ pam_syslog(handle, LOG_ERR, "Failed to connect to system bus: %s", bus_error_message(&error)); -+ r = PAM_SESSION_ERR; -+ goto finish; -+ } -+ -+ m = dbus_message_new_method_call( -+ "org.freedesktop.login1", -+ "/org/freedesktop/login1", -+ "org.freedesktop.login1.Manager", -+ "ReleaseSession"); -+ if (!m) { -+ pam_syslog(handle, LOG_ERR, "Could not allocate release session message."); -+ r = PAM_BUF_ERR; -+ goto finish; -+ } -+ -+ if (!dbus_message_append_args(m, -+ DBUS_TYPE_STRING, &id, -+ DBUS_TYPE_INVALID)) { -+ pam_syslog(handle, LOG_ERR, "Could not attach parameters to message."); -+ r = PAM_BUF_ERR; -+ goto finish; -+ } - -+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); -+ if (!reply) { -+ pam_syslog(handle, LOG_ERR, "Failed to release session: %s", bus_error_message(&error)); -+ r = PAM_SESSION_ERR; -+ goto finish; -+ } -+ } -+ -+ r = PAM_SUCCESS; -+ -+finish: -+ pam_get_data(handle, "systemd.session-fd", &p); - if (p) - close_nointr(PTR_TO_INT(p) - 1); - -- return PAM_SUCCESS; -+ dbus_error_free(&error); -+ -+ if (bus) { -+ dbus_connection_close(bus); -+ dbus_connection_unref(bus); -+ } -+ -+ if (m) -+ dbus_message_unref(m); -+ -+ if (reply) -+ dbus_message_unref(reply); -+ -+ return r; - } --- -1.7.7 - diff --git a/macros.systemd b/macros.systemd index 802380d..68ff878 100644 --- a/macros.systemd +++ b/macros.systemd @@ -20,14 +20,14 @@ # ### -# This is for /bin/systemctl +# This is for systemctl %systemd_requires \ Requires(pre): systemd \ Requires(post): systemd \ Requires(preun): systemd \ Requires(postun): systemd \ -%_unitdir /lib/systemd/system +%_unitdir /usr/lib/systemd/system %service_add_pre() \ test -n "$FIRST_ARG" || FIRST_ARG=$1 \ @@ -62,11 +62,11 @@ for service in %{?*} ; do \ touch "/var/lib/systemd/migrated/$sysv_service" || : \ fi \ done \ -/bin/systemctl daemon-reload >/dev/null 2>&1 || : \ +/usr/bin/systemctl daemon-reload >/dev/null 2>&1 || : \ if [ -n "$services_to_migrate" ]; then \ /usr/sbin/systemd-sysv-convert --apply $services_to_migrate >/dev/null 2>&1 || : \ elif [ $FIRST_ARG -eq 1 ]; then \ - /bin/systemctl preset %{?*} >/dev/null 2>&1 || : \ + /usr/bin/systemctl preset %{?*} >/dev/null 2>&1 || : \ fi \ %{nil} @@ -75,8 +75,8 @@ fi \ test -n "$FIRST_ARG" || FIRST_ARG=$1 \ if [ $FIRST_ARG -eq 0 ]; then \ # Package removal, not upgrade \ - /bin/systemctl --no-reload disable %{?*} > /dev/null 2>&1 || : \ - /bin/systemctl stop %{?*} > /dev/null 2>&1 || : \ + /usr/bin/systemctl --no-reload disable %{?*} > /dev/null 2>&1 || : \ + /usr/bin/systemctl stop %{?*} > /dev/null 2>&1 || : \ fi \ %{nil} @@ -85,13 +85,13 @@ fi \ test -n "$FIRST_ARG" || FIRST_ARG=$1 \ if [ $FIRST_ARG -ge 1 ]; then \ # Package upgrade, not uninstall \ - /bin/systemctl try-restart %{?*} >/dev/null 2>&1 || : \ + /usr/bin/systemctl try-restart %{?*} >/dev/null 2>&1 || : \ else # package uninstall \ for service in %{?*} ; do \ sysv_service=${service%.*} \ rm -f "/var/lib/systemd/migrated/$sysv_service" 2> /dev/null || : \ done \ - /bin/systemctl daemon-reload >/dev/null 2>&1 || : \ + /usr/bin/systemctl daemon-reload >/dev/null 2>&1 || : \ fi \ %{nil} diff --git a/modules_on_boot.patch b/modules_on_boot.patch index f1b6fdb..8257954 100644 --- a/modules_on_boot.patch +++ b/modules_on_boot.patch @@ -7,24 +7,25 @@ Subject: [PATCH] module-load: handle SUSE /etc/sysconfig/kernel module list src/modules-load.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 42 insertions(+), 0 deletions(-) -Index: systemd-44/src/modules-load.c +Index: systemd-191/src/modules-load/modules-load.c =================================================================== ---- systemd-44.orig/src/modules-load.c -+++ systemd-44/src/modules-load.c -@@ -44,6 +44,9 @@ static void systemd_kmod_log(void *data, - int main(int argc, char *argv[]) { - int r = EXIT_FAILURE; - char **files, **fn; +--- systemd-191.orig/src/modules-load/modules-load.c ++++ systemd-191/src/modules-load/modules-load.c +@@ -173,6 +173,9 @@ int main(int argc, char *argv[]) { + int r = EXIT_FAILURE, k; + char **files = NULL, **fn, **i; + struct kmod_ctx *ctx; +#if defined(TARGET_SUSE) + char *modules_on_boot = NULL; +#endif - struct kmod_ctx *ctx; - const int probe_flags = KMOD_PROBE_APPLY_BLACKLIST|KMOD_PROBE_IGNORE_LOADED; -@@ -141,9 +144,59 @@ int main(int argc, char *argv[]) { + if (argc > 1) { + log_error("This program takes no argument."); +@@ -256,9 +259,34 @@ int main(int argc, char *argv[]) { fclose(f); } +- +#if defined(TARGET_SUSE) + log_debug("apply: /etc/sysconfig/kernel MODULES_LOADED_ON_BOOT"); + if ((r = parse_env_file("/etc/sysconfig/kernel", NEWLINE, @@ -37,37 +38,12 @@ Index: systemd-44/src/modules-load.c + if (modules_on_boot) { + char **modules = strv_split(modules_on_boot,WHITESPACE); + char **module; -+ struct kmod_list *itr, *modlist = NULL; -+ int err; + + if (modules) { + STRV_FOREACH(module, modules) { -+ err = kmod_module_new_from_lookup(ctx, *module, &modlist); -+ if (err < 0) { -+ log_error("Failed to lookup alias '%s'", *module); ++ k = load_module(ctx, *module); ++ if (k < 0) + r = EXIT_FAILURE; -+ continue; -+ } -+ kmod_list_foreach(itr, modlist) { -+ struct kmod_module *mod = kmod_module_get_module(itr); -+ err = kmod_module_probe_insert_module(mod, probe_flags, -+ NULL, NULL, NULL, NULL); -+ -+ if (err == 0) -+ log_info("Inserted module '%s'", kmod_module_get_name(mod)); -+ else if (err == KMOD_PROBE_APPLY_BLACKLIST) -+ log_info("Module '%s' is blacklisted", kmod_module_get_name(mod)); -+ else { -+ log_error("Failed to insert '%s': %s", kmod_module_get_name(mod), -+ strerror(-err)); -+ r = EXIT_FAILURE; -+ } -+ -+ kmod_module_unref(mod); -+ } - -+ kmod_module_unref_list(modlist); -+ modlist = NULL; + } + } + strv_free(modules); @@ -79,16 +55,16 @@ Index: systemd-44/src/modules-load.c + free(modules_on_boot); +#endif kmod_unref(ctx); + strv_free(arg_proc_cmdline_modules); - return r; -Index: systemd-44/units/systemd-modules-load.service.in +Index: systemd-191/units/systemd-modules-load.service.in =================================================================== ---- systemd-44.orig/units/systemd-modules-load.service.in -+++ systemd-44/units/systemd-modules-load.service.in -@@ -11,6 +11,7 @@ DefaultDependencies=no - Conflicts=shutdown.target +--- systemd-191.orig/units/systemd-modules-load.service.in ++++ systemd-191/units/systemd-modules-load.service.in +@@ -13,6 +13,7 @@ Conflicts=shutdown.target After=systemd-readahead-collect.service systemd-readahead-replay.service Before=sysinit.target shutdown.target + ConditionCapability=CAP_SYS_MODULE +ConditionPathExists=|/etc/sysconfig/kernel ConditionDirectoryNotEmpty=|/lib/modules-load.d ConditionDirectoryNotEmpty=|/usr/lib/modules-load.d diff --git a/new-lsb-headers.patch b/new-lsb-headers.patch index e0b0787..2c20a48 100644 --- a/new-lsb-headers.patch +++ b/new-lsb-headers.patch @@ -1,8 +1,8 @@ -Index: systemd-44/src/service.c +Index: systemd-189/src/core/service.c =================================================================== ---- systemd-44.orig/src/service.c -+++ systemd-44/src/service.c -@@ -122,6 +122,7 @@ static void service_init(Unit *u) { +--- systemd-189.orig/src/core/service.c ++++ systemd-189/src/core/service.c +@@ -145,6 +145,7 @@ static void service_init(Unit *u) { #ifdef HAVE_SYSV_COMPAT s->sysv_start_priority = -1; s->sysv_start_priority_from_rcnd = -1; @@ -10,7 +10,7 @@ Index: systemd-44/src/service.c #endif s->socket_fd = -1; s->guess_main_pid = true; -@@ -840,6 +841,34 @@ static int service_load_sysv_path(Servic +@@ -877,6 +878,34 @@ static int service_load_sysv_path(Servic free(short_description); short_description = d; @@ -45,7 +45,7 @@ Index: systemd-44/src/service.c } else if (state == LSB_DESCRIPTION) { if (startswith(l, "#\t") || startswith(l, "# ")) { -@@ -894,7 +923,8 @@ static int service_load_sysv_path(Servic +@@ -935,7 +964,8 @@ static int service_load_sysv_path(Servic /* Special setting for all SysV services */ s->type = SERVICE_FORKING; @@ -55,7 +55,7 @@ Index: systemd-44/src/service.c s->guess_main_pid = false; s->restart = SERVICE_RESTART_NO; s->exec_context.ignore_sigpipe = false; -@@ -2036,7 +2066,7 @@ static void service_enter_running(Servic +@@ -2107,7 +2137,7 @@ static void service_enter_running(Servic if ((main_pid_ok > 0 || (main_pid_ok < 0 && cgroup_ok != 0)) && (s->bus_name_good || s->type != SERVICE_DBUS)) { #ifdef HAVE_SYSV_COMPAT @@ -64,12 +64,12 @@ Index: systemd-44/src/service.c s->remain_after_exit = false; #endif service_set_state(s, SERVICE_RUNNING); -Index: systemd-44/src/service.h +Index: systemd-189/src/core/service.h =================================================================== ---- systemd-44.orig/src/service.h -+++ systemd-44/src/service.h -@@ -166,6 +166,7 @@ struct Service { - #ifdef HAVE_SYSV_COMPAT +--- systemd-189.orig/src/core/service.h ++++ systemd-189/src/core/service.h +@@ -176,6 +176,7 @@ struct Service { + bool is_sysv:1; bool sysv_has_lsb:1; bool sysv_enabled:1; + bool sysv_remain_after_exit_heuristic:1; diff --git a/pre_checkin.sh b/pre_checkin.sh index 3f06f65..1870630 100644 --- a/pre_checkin.sh +++ b/pre_checkin.sh @@ -1,6 +1,16 @@ #!/bin/sh -VERSION=`sed -e '/^Version:/!d' -e 's/Version: *//' systemd.spec` -RELEASE=`sed -e '/^Release:/!d' -e 's/Release: *//' systemd.spec` -sed -i -e "s,^\(Version:[ tab]*\).*,\1$VERSION," -e "s,^\(Release:[ tab]*\).*,\1$RELEASE," systemd-gtk.spec -cp systemd.changes systemd-gtk.changes +# This script is based on libcdio_spec-prepare.sh (thanks to sbrabec@suse.cz) +# create a -mini spec for systemd for bootstrapping + +ORIG_SPEC=systemd +EDIT_WARNING="##### WARNING: please do not edit this auto generated spec file. Use the ${ORIG_SPEC}.spec! #####\n" +sed "s/^%define bootstrap.*$/${EDIT_WARNING}%define bootstrap 1/; + s/^%define udevpkgname.*$/${EDIT_WARNING}%define udevpkgname udev-mini/; + s/^\(Name:.*\)$/\1-mini/; + s/^BuildRoot.*/&\n\nProvides: %{real} = %{version}-%{release}\n/ + " < ${ORIG_SPEC}.spec > ${ORIG_SPEC}-mini.spec +cp ${ORIG_SPEC}.changes ${ORIG_SPEC}-mini.changes +cp ${ORIG_SPEC}-rpmlintrc ${ORIG_SPEC}-mini-rpmlintrc + +osc service localrun format_spec_file diff --git a/storage-after-cryptsetup.patch b/storage-after-cryptsetup.patch index 1716fd6..51c5a0b 100644 --- a/storage-after-cryptsetup.patch +++ b/storage-after-cryptsetup.patch @@ -7,10 +7,10 @@ Subject: [PATCH] force lvm restart after cryptsetup target is reached src/cryptsetup-generator.c | 80 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 80 insertions(+), 0 deletions(-) -Index: systemd-37/src/cryptsetup/cryptsetup-generator.c +Index: systemd-194/src/cryptsetup/cryptsetup-generator.c =================================================================== ---- systemd-37.orig/src/cryptsetup/cryptsetup-generator.c -+++ systemd-37/src/cryptsetup/cryptsetup-generator.c +--- systemd-194.orig/src/cryptsetup/cryptsetup-generator.c ++++ systemd-194/src/cryptsetup/cryptsetup-generator.c @@ -22,6 +22,7 @@ #include #include @@ -19,7 +19,7 @@ Index: systemd-37/src/cryptsetup/cryptsetup-generator.c #include "log.h" #include "util.h" -@@ -58,6 +59,71 @@ static bool has_option(const char *hayst +@@ -64,6 +65,71 @@ static bool has_option(const char *hayst return false; } @@ -91,13 +91,13 @@ Index: systemd-37/src/cryptsetup/cryptsetup-generator.c static int create_disk( const char *name, const char *device, -@@ -291,6 +357,9 @@ int main(int argc, char *argv[]) { +@@ -439,6 +505,9 @@ int main(int argc, char *argv[]) { free(options); } -+ if (create_storage_after_cryptsetup () < 0) ++ if ((r == EXIT_SUCCESS) && (create_storage_after_cryptsetup () < 0)) + r = EXIT_FAILURE; + finish: - return r; - } + if (f) + fclose(f); diff --git a/support-suse-clock-sysconfig.patch b/support-suse-clock-sysconfig.patch index de3992a..0df1208 100644 --- a/support-suse-clock-sysconfig.patch +++ b/support-suse-clock-sysconfig.patch @@ -8,25 +8,21 @@ Subject: [PATCH] timedate: add support for openSUSE version of src/timedate/timedated.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) -diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c -index 6a7d980..fbebc1d 100644 ---- a/src/timedate/timedated.c -+++ b/src/timedate/timedated.c -@@ -180,9 +180,13 @@ static int read_data(void) { - if (r != -ENOENT) - log_warning("Failed to read /etc/timezone: %s", strerror(-r)); - --#ifdef TARGET_FEDORA -+#if defined(TARGET_FEDORA) || defined(TARGET_SUSE) - r = parse_env_file("/etc/sysconfig/clock", NEWLINE, -+#ifdef TARGET_FEDORA - "ZONE", &tz.zone, -+#else /* TARGET_SUSE */ -+ "TIMEZONE", &tz.zone, +Index: systemd-190/src/timedate/timedated.c +=================================================================== +--- systemd-190.orig/src/timedate/timedated.c ++++ systemd-190/src/timedate/timedated.c +@@ -175,6 +175,13 @@ static int read_data(void) { + goto have_timezone; + } + } ++#ifdef TARGET_SUSE ++ r = parse_env_file("/etc/sysconfig/clock", NEWLINE, ++ "TIMEZONE", &tz.zone, ++ NULL); ++ if (r < 0 && r != -ENOENT) ++ log_warning("Failed to read /etc/sysconfig/clock: %s", strerror(-r)); +#endif - NULL); - if (r < 0 && r != -ENOENT) --- -1.7.10.4 - + #ifdef HAVE_DEBIAN + r = read_one_line_file("/etc/timezone", &tz.zone); diff --git a/support-sysvinit.patch b/support-sysvinit.patch index 627a308..98c91ce 100644 --- a/support-sysvinit.patch +++ b/support-sysvinit.patch @@ -1,7 +1,7 @@ Index: systemd-36/src/systemctl.c =================================================================== ---- systemd-36.orig/src/systemctl.c -+++ systemd-36/src/systemctl.c +--- systemd-36.orig/src/systemctl/systemctl.c ++++ systemd-36/src/systemctl/systemctl.c @@ -4672,10 +4672,13 @@ static int parse_argv(int argc, char *ar /* Hmm, so some other init system is * running, we need to forward this diff --git a/sysctl-modules.patch b/sysctl-modules.patch index 9348df0..c6d4058 100644 --- a/sysctl-modules.patch +++ b/sysctl-modules.patch @@ -1,12 +1,12 @@ -Index: systemd-37/units/systemd-sysctl.service.in +Index: systemd-189/units/systemd-sysctl.service.in =================================================================== ---- systemd-37.orig/units/systemd-sysctl.service.in -+++ systemd-37/units/systemd-sysctl.service.in -@@ -10,6 +10,7 @@ Description=Apply Kernel Variables +--- systemd-189.orig/units/systemd-sysctl.service.in ++++ systemd-189/units/systemd-sysctl.service.in +@@ -11,6 +11,7 @@ Documentation=man:systemd-sysctl.service DefaultDependencies=no Conflicts=shutdown.target After=systemd-readahead-collect.service systemd-readahead-replay.service +After=systemd-modules-load.service Before=sysinit.target shutdown.target + ConditionPathIsReadWrite=/proc/sys/ ConditionPathExists=|/etc/sysctl.conf - ConditionDirectoryNotEmpty=|/lib/sysctl.d diff --git a/systemd-194.tar.xz b/systemd-194.tar.xz new file mode 100644 index 0000000..9317049 --- /dev/null +++ b/systemd-194.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a275ce044f66f28c5ed0846e7019438ce8b5f596e8255f3455e32b3c0db5f631 +size 1409672 diff --git a/systemd-44.tar.xz b/systemd-44.tar.xz deleted file mode 100644 index 2f31a60..0000000 --- a/systemd-44.tar.xz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7a5aac4b4b8b3a82bf59292f10e43d8f2c2d7039f34e95714f81d8edcb42233c -size 885636 diff --git a/systemd-gtk.spec b/systemd-gtk.spec deleted file mode 100644 index 1cc8b14..0000000 --- a/systemd-gtk.spec +++ /dev/null @@ -1,94 +0,0 @@ -# -# spec file for package systemd-gtk -# -# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. -# -# All modifications and additions to the file contributed by third parties -# remain the property of their copyright owners, unless otherwise agreed -# upon. The license for this file, and modifications and additions to the -# file, is the same license as for the pristine package itself (unless the -# license for the pristine package is not an Open Source License, in which -# case the license is the MIT License). An "Open Source License" is a -# license that conforms to the Open Source Definition (Version 1.9) -# published by the Open Source Initiative. - -# Please submit bugfixes or comments via http://bugs.opensuse.org/ -# - - -Name: systemd-gtk -Url: http://www.freedesktop.org/wiki/Software/systemd -Version: 44 -Release: 0 -BuildRoot: %{_tmppath}/%{name}-%{version}-build -BuildRequires: audit-devel -BuildRequires: gperf -BuildRequires: intltool -BuildRequires: libacl-devel -BuildRequires: libcap-devel -BuildRequires: libtool -BuildRequires: pam-devel -BuildRequires: pkg-config -BuildRequires: tcpd-devel -BuildRequires: udev -BuildRequires: xz -BuildRequires: pkgconfig(dbus-1) >= 1.5.2 -BuildRequires: pkgconfig(gee-1.0) -BuildRequires: pkgconfig(gio-unix-2.0) -BuildRequires: pkgconfig(glib-2.0) > 2.26 -BuildRequires: pkgconfig(gtk+-2.0) -BuildRequires: pkgconfig(libcryptsetup) -BuildRequires: pkgconfig(libkmod) >= 5 -BuildRequires: pkgconfig(liblzma) -BuildRequires: pkgconfig(libnotify) -BuildRequires: pkgconfig(libselinux) -BuildRequires: pkgconfig(libsepol) -BuildRequires: pkgconfig(udev) >= 172 -Summary: Graphical front-end for systemd -License: GPL-2.0+ -Group: System/Base -Requires: systemd = %{version} -Source0: http://www.freedesktop.org/software/systemd/systemd-%{version}.tar.xz -Source1: systemd-rpmlintrc -Patch0: fixppc.patch - -# Upstream First - Policy: -# Never add any patches to this package without the upstream commit id -# in the patch. Any patches added here without a very good reason to make -# an exception will be silently removed with the next version update. - -%description -Graphical front-end for systemd system and service manager. - -%prep -%setup -q -n systemd-%{version} -%patch0 -p1 - -%build -autoreconf -fiv -# prevent pre-generated and distributed files from re-building -find . -name "*.[1-8]" -exec touch '{}' \; -touch src/systemadm.c -export V=1 -%configure \ - --with-distro=suse \ - --docdir=%{_docdir}/systemd \ - --with-rootprefix= \ - CFLAGS="%{optflags}" -make %{?_smp_mflags} - -%install -%makeinstall -# remove everything but systemadm and password agent -find %{buildroot} -not -type d -not -name 'systemadm*' -not -name systemd-gnome-ask-password-agent -delete - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%{_bindir}/systemadm -%{_bindir}/systemd-gnome-ask-password-agent -%{_mandir}/man1/systemadm.1* - -%changelog diff --git a/systemd-mini-rpmlintrc b/systemd-mini-rpmlintrc new file mode 100644 index 0000000..5b28a2c --- /dev/null +++ b/systemd-mini-rpmlintrc @@ -0,0 +1,20 @@ +addFilter(".*dangling-symlink /sbin/(halt|init|poweroff|telinit|shutdown|runlevel|reboot).*") +addFilter(".*dangling-symlink .* /dev/null.*") +addFilter(".*files-duplicate .*/reboot.8.*") +addFilter(".*files-duplicate .*/sd_is_socket.3.*") +addFilter("non-conffile-in-etc /etc/bash_completion.d/systemd-bash-completion.sh") +addFilter("non-conffile-in-etc /etc/rpm/macros.systemd") +addFilter(".*dbus-policy-allow-receive") +# Do not enable for submission into openSUSE:Factory, +# just for testing while polkit-default-privs is not checked in +setBadness('polkit-unauthorized-privilege', 1) +addFilter(".*dangling-symlink /lib/udev/devices/std(in|out|err).*") +addFilter(".*dangling-symlink /lib/udev/devices/core.*") +addFilter(".*dangling-symlink /lib/udev/devices/fd.*") +addFilter(".*incoherent-init-script-name boot.udev.*") +addFilter(".init-script-without-%stop_on_removal-preun /etc/init.d/boot.udev") +addFilter(".init-script-without-%restart_on_update-postun /etc/init.d/boot.udev") +addFilter(".*devel-file-in-non-devel-package.*udev.pc.*") +addFilter(".*libgudev-.*shlib-fixed-dependency.*") +addFilter(".*suse-filelist-forbidden-systemd-userdirs.*") +addFilter("libudev-mini.*shlib-policy-name-error.*") diff --git a/systemd-gtk.changes b/systemd-mini.changes similarity index 87% rename from systemd-gtk.changes rename to systemd-mini.changes index e40aeb8..fa78071 100644 --- a/systemd-gtk.changes +++ b/systemd-mini.changes @@ -1,3 +1,270 @@ +------------------------------------------------------------------- +Thu Oct 18 12:27:07 UTC 2012 - fcrozat@suse.com + +- Create and own more systemd drop-in directories. + +------------------------------------------------------------------- +Tue Oct 16 13:18:13 UTC 2012 - fcrozat@suse.com + +- Improve mini packages for bootstrapping. +- do not mount /tmp as tmpfs by default. + +------------------------------------------------------------------- +Tue Oct 16 07:40:23 UTC 2012 - fcrozat@suse.com + +- Fix install script when there is no inittab + +------------------------------------------------------------------- +Mon Oct 15 14:48:47 UTC 2012 - fcrozat@suse.com + +- Create a systemd-mini specfile to prevent cycle in bootstrapping + +------------------------------------------------------------------- +Thu Oct 4 11:23:42 UTC 2012 - fcrozat@suse.com + +- udev and its subpackages are now generated by systemd source + package. +- migrate udev and systemd to /usr +- Update to version 194: + + if /etc/vconsole.conf is non-existent or empty and if + /etc/sysconfig/console:CONSOLE_FONT (resp + /etc/sysconfig/keyboard:KEYTABLE) set, console font (resp + keymap) is not modified. +- Changes from version 44 to 193: + + journalctl gained --cursor= to show entries starting from a + specified location in journal. + + Size limit enforced to 4K for fields exported with "-o json" in + journalctl. Use --all to disable this behavior. + + Optional journal gateway daemon + (systemd-journal-gatewayd.service) to access journal via HTTP + and JSON. Use "wget http://localhost:19531/entries" to get + /var/log/messages compatible format and + 'curl -H"Accept: application/json" + http://localhost:19531/entries' for JSON formatted content. + HTML5 static page is also available as explained on + http://0pointer.de/public/journal-gatewayd + + do not mount cpuset controler, doesn't work well by default + ATM. + + improved nspawn behaviour with /etc/localtime + + journald logs its maximize size on disk + + multi-seat X wrapper (partially merged in upstream X server). + + HandleSleepKey has been splitted into HandleSuspendKey and + HandleHibernateKey. + + systemd and logind now handle system sleep states, in + particular suspending and hibernating. + + new cgroups are mounted by default (cpu, cpuacct, + net_cls, net_pri) + + sync at shutdown is now handled by kernel + + imported journalctl output (colors, filtering, pager, bash + completion). + + suffix ".service" may now be ommited on most systemctl command + involving service unit names. + + much improved nspawn containers support. + + new conditions added : ConditionFileNotEmpty, ConditionHost, + ConditionPathIsReadWrite + + tmpfiles "w" supports file globbing + + logind handles lid switch, power and sleep keys all the time, + unless systemd-inhibit + --what=handle-power-key:handle-sleep-key:handle-lid-switch is + run by Desktop Environments. + + support for reading structured kernel message is used by + default (need kernel >= 3.5). /proc/kmsg is now used only by + classic syslog daemons. + + Forward Secure Sealing is now support for Journal files. + + RestartPrevenExitStatus and SuccessExitStatus allow configure + of exit status (exit code or signal). + + handles keyfile-size and keyfile-offset in /etc/crypttab. + + TimeoutSec settings has been splitted into TimeoutStartSec and + TimeoutStopSec. + + add SystemCallFilters option to add blacklist/whitelist to + system calls, using SECCOMP mode 2 of kernel >= 3.5. + + systemctl udevadm info now takes a /dev or /sys path as argument: + - udevadm info /dev/sda + + XDG_RUNTIME_DIR now uses numeric UIDs instead of usernames. + + systemd-loginctl and systemd-journalctl have been renamed + to loginctl and journalctl to match systemctl. + + udev: RUN+="socket:..." and udev_monitor_new_from_socket() is + no longer supported. udev_monitor_new_from_netlink() needs to + be used to subscribe to events. + + udev: when udevd is started by systemd, processes which are left + behind by forking them off of udev rules, are unconditionally + cleaned up and killed now after the event handling has finished. + Services or daemons must be started as systemd services. + Services can be pulled-in by udev to get started, but they can + no longer be directly forked by udev rules. + + For almost all files, license is now LGPL2.1+ (from previous + GPL2.0+). Exception are some minor stuff in udev (will be + changed to LGPL2.1 eventually) and MIT license sd-daemon.[ch] + library. + + var-run.mount and var-lock.mount are no longer provided + (should be converted to symlinks). + + A new service type Type=idle to avoid ugly interleaving of + getty output and boot status messages. + + systemd-delta has been added, a tool to explore differences + between user/admin configuration and vendor defaults. + + /tmp mouted as tmpfs by default. + + /media is now longer mounted as tmpfs + + GTK tool has been split off to systemd-ui package. + + much improved documentation. +- Merge BuildRequires from udev package: + gobject-introspection-devel, gtk-doc, libsepol-devel, + libusb-devel, pkgconfig(blkid), pkgconfig-glib-2.0), + pjgconfig(libcryptsetup), pkgconfig(libpci), + pkgconfig(libqrencode), pkgconfig(libselinux), + pkgconfig(usbutils). +- Add pkgconfig(libqrencode) and pkgconfig(libmicrohttpd) +- Merge sources from udev package: boot.udev, write_dev_root.rules, + udev-root-symlink.systemd. +- Merge patches from udev package: numbered started from 1000): + 0001-Reinstate-TIMEOUT-handling.patch, + 0013-re-enable-by_path-links-for-ata-devices.patch, + 0014-rules-create-by-id-scsi-links-for-ATA-devices.patch, + 0026-udev-netlink-null-rules.patch, + 0027-udev-fix-sg-autoload-regression.patch. +- Remove following patches, merged upstream: + 0001-util-never-follow-symlinks-in-rm_rf_children.patch, + fixppc.patch, logind-logout.patch, fix-getty-isolate.patch, + fix-swap-priority.patch, improve-restart-behaviour.patch, + fix-dir-noatime-tmpfiles.patch, journal-bugfixes.patch, + ulimit-support.patch, change-terminal.patch, + fix-tty-startup.patch, fix-write-user-state-file.patch, + fix-analyze-exception.patch, use_localtime.patch, + journalctl-pager-improvement.patch, + avoid-random-seed-cycle.patch, + 0001-add-sparse-support-to-detect-endianness-bug.patch, + drop-timezone.patch. +- Rebase the following patches: + 0001-Add-bootsplash-handling-for-password-dialogs.patch, + 0001-handle-disable_caplock-and-compose_table-and-kbd_rat.patch, + 0001-service-Fix-dependencies-added-when-parsing-insserv..patch, + 0001-service-flags-sysv-service-with-detected-pid-as-Rema.patch, + crypt-loop-file.patch, + delay-fsck-cryptsetup-after-md-lvm-dmraid.patch, + dm-lvm-after-local-fs-pre-target.patch, fastboot-forcefsck.patch, + fix-enable-disable-boot-initscript.patch, modules_on_boot.patch, + new-lsb-headers.patch, storage-after-cryptsetup.patch, + support-suse-clock-sysconfig.patch, support-sysvinit.patch, + sysctl-modules.patch, systemd-numlock-suse.patch, tty1.patch. + +------------------------------------------------------------------- +Thu Aug 23 11:11:25 CEST 2012 - fcrozat@suse.com + +- Add use_localtime.patch: use /etc/localtime instead of + /etc/timezone (bnc#773491) +- Add support-suse-clock-sysconfig.patch: read SUSE + /etc/sysconfig/clock file. +- Add drop-timezone.patch: drop support for /etc/timezone, never + supported on openSUSE. +- Add journalctl-pager-improvement.patch: better handle output when + using pager. +- Add fix-enable-disable-boot-initscript.patch: support boot.* + initscripts for systemctl enable /disable (bnc#746506). + +------------------------------------------------------------------- +Mon Jul 30 11:37:17 UTC 2012 - fcrozat@suse.com + +- Ensure systemd macros never fails (if systemd isn't install) + +------------------------------------------------------------------- +Mon Jul 23 08:28:15 UTC 2012 - fcrozat@suse.com + +- Add fix-analyze-exception.patch: prevent exception if running + systemd-analyze before boot is complete (bnc#772506) + +------------------------------------------------------------------- +Fri Jul 20 19:24:08 CEST 2012 - sbrabec@suse.cz + +- Fix NumLock detection/set race condition (bnc#746595#c47). + +------------------------------------------------------------------- +Wed Jul 18 13:14:37 UTC 2012 - fcrozat@suse.com + +- Move systemd-analyse to a subpackage, to remove any python + dependencies from systemd main package (bnc#772039). + +------------------------------------------------------------------- +Tue Jul 10 16:48:20 UTC 2012 - fcrozat@suse.com + +- Add fastboot-forcefsck.patch: ensure fastboot and forcefsck on + kernel commandline are handled. +- Add fix-write-user-state-file.patch: write logind state file + correctly. +- Disable logind-logout.patch: cause too many issues (bnc#769531). + +------------------------------------------------------------------- +Mon Jul 9 11:01:20 UTC 2012 - fcrozat@suse.com + +- Add fix-tty-startup.patch: don't limit tty VT to 12 (bnc#770182). + +------------------------------------------------------------------- +Tue Jul 3 20:07:47 CEST 2012 - sbrabec@suse.cz + +- Fix SUSE specific sysconfig numlock logic for 12.2 (bnc#746595). + +------------------------------------------------------------------- +Tue Jul 3 17:58:39 CEST 2012 - fcrozat@suse.com + +- Add fix-dir-noatime-tmpfiles.patch: do not modify directory + atime, which was preventing removing empty directories + (bnc#751253, rh#810257). +- Add improve-restart-behaviour.patch: prevent deadlock during + try-restart (bnc#743218). +- Add journal-bugfixes.patch: don't crash when rotating journal + (bnc#768953) and prevent memleak at rotation time too. +- Add ulimit-support.patch: add support for system wide ulimit + (bnc#744818). +- Add change-terminal.patch: use vt102 instead of vt100 as terminal + for non-vc tty. +- Package various .wants directories, which were no longer packaged + due to plymouth units being removed from systemd package. +- Fix buildrequires for manpages build. + +------------------------------------------------------------------- +Mon Jul 2 15:44:28 UTC 2012 - fcrozat@suse.com + +- Do not ship plymouth units, they are shipped by plymouth package + now (bnc#769397). +- Fix module loading (bnc#769462) + +------------------------------------------------------------------- +Thu Jun 7 13:14:40 UTC 2012 - fcrozat@suse.com + +- Add fix-swap-priority: fix default swap priority (bnc#731601). + +------------------------------------------------------------------- +Fri May 25 11:08:27 UTC 2012 - fcrozat@suse.com + +- Re-enable logind-logout.patch, fix in xdm-np PAM file is the real + fix. + +------------------------------------------------------------------- +Thu May 24 11:45:54 UTC 2012 - fcrozat@suse.com + +- Update new-lsb-headers.patch to handle entries written after + description tag (bnc#727771, bnc#747931). + +------------------------------------------------------------------- +Thu May 3 11:40:20 UTC 2012 - fcrozat@suse.com + +- Disable logind-logout.patch: it crashes sudo session (if called + after su -l) (bnc#746704). + +------------------------------------------------------------------- +Tue Apr 24 15:46:54 UTC 2012 - fcrozat@suse.com + +- Add fix-getty-isolate.patch: don't quit getty when changing + runlevel (bnc#746594) + +------------------------------------------------------------------- +Fri Apr 20 17:16:37 CEST 2012 - sbrabec@suse.cz + +- Implemented SUSE specific sysconfig numlock logic (bnc#746595). + +------------------------------------------------------------------- +Thu Apr 19 10:07:47 UTC 2012 - fcrozat@suse.com + +- Add dbus-1 as BuildRequires to fix build. + ------------------------------------------------------------------- Tue Apr 3 09:37:09 UTC 2012 - dvaleev@suse.com diff --git a/systemd-mini.spec b/systemd-mini.spec new file mode 100644 index 0000000..f9b8321 --- /dev/null +++ b/systemd-mini.spec @@ -0,0 +1,803 @@ +# +# spec file for package systemd-mini +# +# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# + + +##### WARNING: please do not edit this auto generated spec file. Use the systemd.spec! ##### +%define bootstrap 1 +%define real systemd +##### WARNING: please do not edit this auto generated spec file. Use the systemd.spec! ##### +%define udevpkgname udev-mini +%define udev_major 1 + +Name: systemd-mini +Url: http://www.freedesktop.org/wiki/Software/systemd +Version: 194 +Release: 0 +Summary: A System and Session Manager +License: LGPL-2.1+ +Group: System/Base +BuildRoot: %{_tmppath}/%{name}-%{version}-build + +Provides: %{real} = %{version}-%{release} + +BuildRequires: audit-devel +BuildRequires: dbus-1 +%if ! 0%{?bootstrap} +BuildRequires: docbook-xsl-stylesheets +%endif +BuildRequires: fdupes +%if ! 0%{?bootstrap} +BuildRequires: gobject-introspection-devel +%endif +BuildRequires: gperf +%if ! 0%{?bootstrap} +BuildRequires: gtk-doc +%endif +BuildRequires: intltool +BuildRequires: libacl-devel +BuildRequires: libcap-devel +BuildRequires: libsepol-devel +BuildRequires: libtool +BuildRequires: libusb-devel +%if ! 0%{?bootstrap} +BuildRequires: libxslt-tools +%endif +BuildRequires: pam-devel +BuildRequires: tcpd-devel +BuildRequires: xz +BuildRequires: pkgconfig(blkid) >= 2.20 +BuildRequires: pkgconfig(dbus-1) >= 1.3.2 +%if ! 0%{?bootstrap} +BuildRequires: pkgconfig(glib-2.0) >= 2.22.0 +BuildRequires: pkgconfig(libcryptsetup) >= 1.4.2 +%endif +BuildRequires: pkgconfig(libkmod) >= 5 +BuildRequires: pkgconfig(liblzma) +%if ! 0%{?bootstrap} +BuildRequires: pkgconfig(libmicrohttpd) +%endif +BuildRequires: pkgconfig(libpci) >= 3 +%if ! 0%{?bootstrap} +BuildRequires: pkgconfig(libqrencode) +%endif +BuildRequires: pkgconfig(libselinux) >= 2.1.9 +BuildRequires: pkgconfig(libsepol) +BuildRequires: pkgconfig(usbutils) >= 0.82 +%if 0%{?bootstrap} +Requires: this-is-only-for-build-envs +%else +# the buildignore is important for bootstrapping +#!BuildIgnore: udev +Requires: %{udevpkgname} >= 172 +Requires: dbus-1 >= 1.4.0 +Requires: kbd +Requires: pam-config >= 0.79-5 +Requires: systemd-presets-branding +Requires: util-linux >= 2.21 +%endif +Conflicts: filesystem < 11.5 +Conflicts: mkinitrd < 2.7.0 +Source0: http://www.freedesktop.org/software/systemd/systemd-%{version}.tar.xz +Source1: systemd-rpmlintrc +Source2: localfs.service +Source3: systemd-sysv-convert +Source4: macros.systemd +Source5: systemd-insserv_conf +Source6: baselibs.conf + +Source1060: boot.udev +Source1061: write_dev_root_rule +Source1062: udev-root-symlink.systemd + +Patch1: 0001-Add-bootsplash-handling-for-password-dialogs.patch +# handle SUSE specific kbd settings +Patch6: 0001-handle-disable_caplock-and-compose_table-and-kbd_rat.patch +Patch7: systemd-numlock-suse.patch +# don't start getty on tty1 until all password request are done +Patch8: tty1.patch +Patch10: 0001-service-Fix-dependencies-added-when-parsing-insserv..patch +Patch13: 0001-service-flags-sysv-service-with-detected-pid-as-Rema.patch +Patch15: support-sysvinit.patch +Patch16: modules_on_boot.patch +Patch22: new-lsb-headers.patch +Patch23: storage-after-cryptsetup.patch +Patch24: delay-fsck-cryptsetup-after-md-lvm-dmraid.patch +Patch31: lock-opensuse.patch +Patch33: crypt-loop-file.patch +Patch36: sysctl-modules.patch +Patch38: dm-lvm-after-local-fs-pre-target.patch +Patch53: fastboot-forcefsck.patch +Patch56: support-suse-clock-sysconfig.patch +Patch59: fix-enable-disable-boot-initscript.patch + +# Upstream First - Policy: +# Never add any patches to this package without the upstream commit id +# in the patch. Any patches added here without a very good reason to make +# an exception will be silently removed with the next version update. + +# udev patches +# PATCH-FIX-OPENSUSE 0001-Reinstate-TIMEOUT-handling.patch +Patch1001: 0001-Reinstate-TIMEOUT-handling.patch +# PATCH-FIX-OPENSUSE 0013-re-enable-by_path-links-for-ata-devices.patch +Patch1013: 0013-re-enable-by_path-links-for-ata-devices.patch +# PATCH-FIX-OPENSUSE 0014-rules-create-by-id-scsi-links-for-ATA-devices.patch +Patch1014: 0014-rules-create-by-id-scsi-links-for-ATA-devices.patch + +# PATCH-FIX-OPENSUSE 0026-udev-netlink-null-rules.patch +Patch1026: 0026-udev-netlink-null-rules.patch +# PATCH-FIX-OPENSUSE 0027-udev-fix-sg-autoload-regression.patch +Patch1027: 0027-udev-fix-sg-autoload-regression.patch + +# systemd patches + +%description +Systemd is a system and service manager, compatible with SysV and LSB +init scripts for Linux. systemd provides aggressive parallelization +capabilities, uses socket and D-Bus activation for starting services, +offers on-demand starting of daemons, keeps track of processes using +Linux cgroups, supports snapshotting and restoring of the system state, +maintains mount and automount points and implements an elaborate +transactional dependency-based service control logic. It can work as a +drop-in replacement for sysvinit. + + + +%package devel +Summary: Development headers for systemd +Group: Development/Libraries/C and C++ +Requires: %{name} = %{version} + +%description devel +Development headers and auxiliary files for developing applications for systemd. + +%package sysvinit +Summary: System V init tools +Group: System/Base +Requires: %{name} = %{version} +Provides: sbin_init +Conflicts: otherproviders(sbin_init) +Provides: sysvinit:/sbin/init + +%description sysvinit +Drop-in replacement of System V init tools. + +%package analyze +Summary: Tool for processing systemd profiling information +Group: System/Base +Requires: %{name} = %{version} +Requires: dbus-1-python +Requires: python-cairo +# for the systemd-analyze split: +Conflicts: systemd < 44-10 + +%description analyze +'systemd-analyze blame' lists which systemd unit needed how much time to finish +initialization at boot. +'systemd-analyze plot' renders an SVG visualizing the parallel start of units +at boot. + +%package -n %{udevpkgname} +Summary: A rule-based device node and kernel event manager +Group: System/Kernel +Url: http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html +PreReq: /bin/pidof /bin/rm /usr/bin/stat %insserv_prereq %fillup_prereq /usr/sbin/groupadd /usr/bin/getent /sbin/mkinitrd +Conflicts: systemd < 39 +Conflicts: aaa_base < 11.5 +Conflicts: filesystem < 11.5 +Conflicts: mkinitrd < 2.7.0 +Conflicts: util-linux < 2.16 +Conflicts: ConsoleKit < 0.4.1 +Requires: filesystem +%if 0%{?bootstrap} +Provides: udev = %{version} +%endif + +%description -n %{udevpkgname} +Udev creates and removes device nodes in /dev for devices discovered or +removed from the system. It receives events via kernel netlink messages +and dispatches them according to rules in /lib/udev/rules.d/. Matching +rules may name a device node, create additional symlinks to the node, +call tools to initialize a device, or load needed kernel modules. + + + +%package -n lib%{udevpkgname}%{udev_major} +Summary: Dynamic library to access udev device information +Group: System/Libraries +Requires: %{udevpkgname} >= %{version}-%{release} + +%description -n lib%{udevpkgname}%{udev_major} +This package contains the dynamic library libudev, which provides +access to udev device information + +%package -n lib%{udevpkgname}-devel +Summary: Development files for libudev +Group: Development/Libraries/Other +Requires: lib%{udevpkgname}%{udev_major} = %{version}-%{release} +%if 0%{?bootstrap} +Provides: libudev-devel = %{version} +%endif + +%description -n lib%{udevpkgname}-devel +This package contains the development files for the library libudev, a +dynamic library, which provides access to udev device information. + +%if ! 0%{?bootstrap} +%package -n libgudev-1_0-0 +Summary: GObject library, to access udev device information +Group: System/Libraries +Requires: lib%{udevpkgname}%{udev_major} = %{version}-%{release} + +%description -n libgudev-1_0-0 +This package contains the GObject library libgudev, which provides +access to udev device information. + +%package -n typelib-1_0-GUdev-1_0 +Summary: GObject library, to access udev device information -- Introspection bindings +Group: System/Libraries + +%description -n typelib-1_0-GUdev-1_0 +This package provides the GObject Introspection bindings for libgudev, which +provides access to udev device information. + +%package -n libgudev-1_0-devel +Summary: Devel package for libgudev +Group: Development/Libraries/Other +Requires: glib2-devel +Requires: libgudev-1_0-0 = %{version}-%{release} +Requires: libudev-devel = %{version}-%{release} +Requires: typelib-1_0-GUdev-1_0 = %{version}-%{release} + +%description -n libgudev-1_0-devel +This is the devel package for the GObject library libgudev, which +provides GObject access to udev device information. +%endif + +%prep +%setup -q -n systemd-%{version} + +#udev +%patch1001 -p1 +%patch1013 -p1 +%patch1014 -p1 +%patch1026 -p1 +%patch1027 -p1 + +%patch1 -p1 +%patch6 -p1 +# don't apply when bootstrapping to not modify configure.in +%if ! 0%{?bootstrap} +%patch7 -p1 +%endif +%patch8 -p1 +%patch10 -p1 +%patch13 -p1 +%patch15 -p1 +%patch16 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch31 -p1 +%patch33 -p1 +%patch36 -p1 +%patch38 -p1 +%patch53 -p1 +%patch56 -p1 +%patch59 -p1 + +%build +%if ! 0%{?bootstrap} +autoreconf -fiv +%endif +# prevent pre-generated and distributed files from re-building +find . -name "*.[1-8]" -exec touch '{}' \; +export V=1 +# keep split-usr until all packages have moved their systemd rules to /usr +%configure \ + --with-distro=suse \ + --docdir=%{_docdir}/systemd \ + --with-pamlibdir=/%{_lib}/security \ +%if 0%{?bootstrap} + --disable-gudev \ +%else + --enable-manpages \ + --enable-gtk-doc \ +%endif + --enable-selinux \ + --enable-split-usr \ + --disable-static \ + CFLAGS="%{optflags}" +make %{?_smp_mflags} + +%install +%makeinstall + +mkdir -p $RPM_BUILD_ROOT/{sbin,lib,bin} +ln -sf %{_bindir}/udevadm $RPM_BUILD_ROOT/sbin/udevadm +ln -sf %{_prefix}/lib/systemd/systemd-udevd $RPM_BUILD_ROOT/sbin/udevd +mkdir -p $RPM_BUILD_ROOT/%{_prefix}/usr/lib/firmware/updates +ln -sf /lib/firmware $RPM_BUILD_ROOT/usr/lib/firmware + +install -m755 -D %{S:1060} $RPM_BUILD_ROOT/etc/init.d/boot.udev +install -m755 -D %{S:1061} $RPM_BUILD_ROOT/%{_prefix}/lib/udev/write_dev_root_rule +install -m644 -D %{S:1062} $RPM_BUILD_ROOT/%{_prefix}/lib/systemd/system/udev-root-symlink.service +mkdir -p $RPM_BUILD_ROOT/lib/systemd/system/basic.target.wants +ln -sf ../udev-root-symlink.service $RPM_BUILD_ROOT/%{_prefix}/lib/systemd/system/basic.target.wants + +#fix manpages +%if ! 0%{?bootstrap} +sed -i -e 's,^\(\.so \)\(.*\.\)\([0-9]\),\1man\3/\2\3,g' %{buildroot}/%{_mandir}/*/* +%endif + +#workaround for 716939 +chmod 644 %{buildroot}%{_bindir}/systemd-analyze +mkdir -p %{buildroot}%{_sysconfdir}/rpm +install -m644 %{S:4} %{buildroot}%{_sysconfdir}/rpm +find %{buildroot} -type f -name '*.la' -exec rm -f {} ';' +mkdir -p %{buildroot}/{sbin,var/lib/systemd/sysv-convert,var/lib/systemd/migrated} %{buildroot}/usr/lib/systemd/{system-generators,user-generators,system-preset,user-preset,system/halt.target.wants,system/kexec.target.wants,system/poweroff.target.wants,system/reboot.target.wants} + +install -m755 %{S:3} -D %{buildroot}%{_sbindir}/systemd-sysv-convert +# do not install, code has been fixed, might be useful in the future +#install -m755 %{S:5} %{buildroot}/lib/systemd/system-generators +ln -s ../usr/lib/systemd/systemd %{buildroot}/bin/systemd +ln -s ../usr/lib/systemd/systemd %{buildroot}/sbin/init +ln -s ../usr/bin/systemctl %{buildroot}/sbin/reboot +ln -s ../usr/bin/systemctl %{buildroot}/sbin/halt +ln -s ../usr/bin/systemctl %{buildroot}/sbin/shutdown +ln -s ../usr/bin/systemctl %{buildroot}/sbin/poweroff +ln -s ../usr/bin/systemctl %{buildroot}/sbin/telinit +ln -s ../usr/bin/systemctl %{buildroot}/sbin/runlevel +rm -rf %{buildroot}/etc/systemd/system/*.target.wants +rm -f %{buildroot}/etc/systemd/system/default.target +# aliases for /etc/init.d/* +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/cgroup.service +ln -s systemd-tmpfiles-setup.service %{buildroot}/%{_prefix}/lib/systemd/system/cleanup.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/clock.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/crypto.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/crypto-early.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/device-mapper.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/earlysyslog.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/kbd.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/ldconfig.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/loadmodules.service +install -m644 %{S:2} %{buildroot}/%{_prefix}/lib/systemd/system/localfs.service +# need to be implemented in systemd directly +#ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/localnet.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/proc.service +ln -s systemd-fsck-root.service %{buildroot}/%{_prefix}/lib/systemd/system/rootfsck.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/single.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/swap.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/startpreload.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/stoppreload.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/earlyxdm.service +ln -s systemd-sysctl.service %{buildroot}/%{_prefix}/lib/systemd/system/sysctl.service +ln -s systemd-random-seed-load.service %{buildroot}/%{_prefix}/lib/systemd/system/random.service +# don't mount /tmp as tmpfs for now +rm %{buildroot}/%{_prefix}/lib/systemd/system/local-fs.target.wants/tmp.mount + +# To avoid making life hard for Factory developers, don't package the +# kernel.core_pattern setting until systemd-coredump is a part of an actual +# systemd release and it's made clear how to get the core dumps out of the +# journal. +rm -f %{buildroot}%{_libdir}/../lib/sysctl.d/coredump.conf + +# legacy links +ln -s loginctl %{buildroot}%{_bindir}/systemd-loginctl +ln -s journalctl %{buildroot}%{_bindir}/systemd-journalctl +ln -s /usr/lib/udev %{buildroot}/lib/udev + +# Create the /var/log/journal directory to change the volatile journal to a persistent one +mkdir -p %{buildroot}/var/log/journal + +# Make sure the NTP units dir exists +mkdir -p %{buildroot}%{_prefix}/lib/systemd/ntp-units.d/ + +# Make sure the shutdown/sleep drop-in dirs exist +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-shutdown/ +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-sleep/ + +# Make sure these directories are properly owned +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/default.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/dbus.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/syslog.target.wants + +%fdupes -s %{buildroot}%{_mandir} + +%post +/usr/sbin/pam-config -a --systemd >/dev/null 2>&1 || : +/sbin/ldconfig +/bin/systemd-machine-id-setup >/dev/null 2>&1 || : +/bin/systemctl daemon-reexec >/dev/null 2>&1 || : + +# Try to read default runlevel from the old inittab if it exists +if [ ! -e /etc/systemd/system/default.target -a -e /etc/inittab ]; then + runlevel=$(awk -F ':' '$3 == "initdefault" && $1 !~ "^#" { print $2 }' /etc/inittab 2> /dev/null) + if [ -n "$runlevel" ] ; then + /bin/ln -sf /usr/lib/systemd/system/runlevel$runlevel.target /etc/systemd/system/default.target 2>&1 || : + fi +fi +# Create default config in /etc at first install. +# Later package updates should not overwrite these settings. +if [ "$1" -eq 1 ]; then + # Enable these services by default. + /bin/systemctl enable \ + getty@.service \ + systemd-readahead-collect.service \ + systemd-readahead-replay.service \ + remote-fs.target >/dev/null 2>&1 || : +fi + +%postun +/sbin/ldconfig +if [ $1 -ge 1 ]; then + /bin/systemctl try-restart systemd-logind.service >/dev/null 2>&1 || : +fi +if [ $1 -eq 0 ]; then + /usr/sbin/pam-config -d --systemd >/dev/null 2>&1 || : +fi + +%preun +if [ $1 -eq 0 ]; then + /bin/systemctl disable \ + getty@.service \ + systemd-readahead-collect.service \ + systemd-readahead-replay.service \ + remote-fs.target >/dev/null 2>&1 || : + rm -f /etc/systemd/system/default.target 2>&1 || : +fi + +%pretrans -n %{udevpkgname} -p +if posix.stat("/lib/udev") and not posix.stat("/usr/lib/udev") then + posix.symlink("/lib/udev", "/usr/lib/udev") +end + +%pre -n %{udevpkgname} +if test -L /usr/lib/udev -a /lib/udev -ef /usr/lib/udev ; then + rm /usr/lib/udev + mv /lib/udev /usr/lib + ln -s /usr/lib/udev /lib/udev +fi + +%post -n %{udevpkgname} +%{fillup_and_insserv -Y boot.udev} +# add KERNEL name match to existing persistent net rules +sed -ri '/KERNEL/ ! { s/NAME="(eth|wlan|ath)([0-9]+)"/KERNEL=="\1*", NAME="\1\2"/}' \ + /etc/udev/rules.d/70-persistent-net.rules >/dev/null 2>&1 || : +# cleanup old stuff +rm -f /etc/sysconfig/udev +rm -f /etc/udev/rules.d/20-cdrom.rules +rm -f /etc/udev/rules.d/55-cdrom.rules +rm -f /etc/udev/rules.d/65-cdrom.rules +/bin/systemctl daemon-reload >/dev/null 2>&1 || : +# start daemon if we are not in a chroot +if test -f /proc/1/exe -a -d /proc/1/root; then + if test "$(stat -Lc '%%D-%%i' /)" = "$(stat -Lc '%%D-%%i' /proc/1/root)"; then + /bin/systemctl start systemd-udevd.service >/dev/null 2>&1 || : + /sbin/udevd --daemon >/dev/null 2>&1 || : + fi +fi + +[ -x /sbin/mkinitrd_setup ] && /sbin/mkinitrd_setup +if [ -e /var/lib/no_initrd_recreation_by_suspend ]; then + echo "Skipping recreation of existing initial ramdisks, due" + echo "to presence of /var/lib/no_initrd_recreation_by_suspend" +elif [ -x /sbin/mkinitrd ]; then + /sbin/mkinitrd +fi + +%postun -n %{udevpkgname} +%insserv_cleanup +/bin/systemctl daemon-reload >/dev/null 2>&1 || : + +[ -x /sbin/mkinitrd_setup ] && /sbin/mkinitrd_setup +if [ -e /var/lib/no_initrd_recreation_by_suspend ]; then + echo "Skipping recreation of existing initial ramdisks, due" + echo "to presence of /var/lib/no_initrd_recreation_by_suspend" +elif [ -x /sbin/mkinitrd ]; then + /sbin/mkinitrd +fi + +%post -n lib%{udevpkgname}%{udev_major} -p /sbin/ldconfig + +%postun -n lib%{udevpkgname}%{udev_major} -p /sbin/ldconfig + +%if ! 0%{?bootstrap} + +%post -n libgudev-1_0-0 -p /sbin/ldconfig + +%postun -n libgudev-1_0-0 -p /sbin/ldconfig +%endif + +%clean +rm -rf %{buildroot} + +%files +%defattr(-,root,root) +/bin/systemd +%{_bindir}/systemctl +%{_bindir}/systemd-delta +%{_bindir}/systemd-notify +%{_bindir}/systemd-journalctl +%{_bindir}/journalctl +%{_bindir}/systemd-ask-password +%{_bindir}/loginctl +%{_bindir}/systemd-loginctl +%{_bindir}/systemd-inhibit +%{_bindir}/systemd-tty-ask-password-agent +%{_bindir}/systemd-tmpfiles +%{_bindir}/systemd-machine-id-setup +%{_bindir}/systemd-nspawn +%{_bindir}/systemd-stdio-bridge +%{_bindir}/systemd-detect-virt +%{_sbindir}/systemd-sysv-convert +%{_libdir}/libsystemd-daemon.so.* +%{_libdir}/libsystemd-login.so.* +%{_libdir}/libsystemd-id128.so.* +%{_libdir}/libsystemd-journal.so.* +%{_bindir}/systemd-cgls +%{_bindir}/systemd-cgtop +%{_bindir}/systemd-cat +%dir %{_prefix}/lib/systemd +%dir %{_prefix}/lib/systemd/user +%dir %{_prefix}/lib/systemd/system +%exclude %{_prefix}/lib/systemd/system/systemd-udev*.* +%exclude %{_prefix}/lib/systemd/system/udev-root-symlink.service +%exclude %{_prefix}/lib/systemd/system/*.target.wants/systemd-udev*.* +%exclude %{_prefix}/lib/systemd/system/basic.target.wants/udev-root-symlink.service +%{_prefix}/lib/systemd/system/*.automount +%{_prefix}/lib/systemd/system/*.service +%{_prefix}/lib/systemd/system/*.target +%{_prefix}/lib/systemd/system/*.mount +%{_prefix}/lib/systemd/system/*.timer +%{_prefix}/lib/systemd/system/*.socket +%{_prefix}/lib/systemd/system/*.wants +%{_prefix}/lib/systemd/system/*.path +%{_prefix}/lib/systemd/user/*.target +%{_prefix}/lib/systemd/user/*.service +%exclude %{_prefix}/lib/systemd/systemd-udevd +%{_prefix}/lib/systemd/systemd-* +%{_prefix}/lib/systemd/systemd +%dir %{_prefix}/lib/systemd/system-shutdown +%dir %{_prefix}/lib/systemd/system-preset +%dir %{_prefix}/lib/systemd/user-preset +%dir %{_prefix}/lib/systemd/system-generators +%dir %{_prefix}/lib/systemd/user-generators +%dir %{_prefix}/lib/systemd/ntp-units.d/ +%dir %{_prefix}/lib/systemd/system-shutdown/ +%dir %{_prefix}/lib/systemd/system-sleep/ +%dir %{_prefix}/lib/systemd/system/default.target.wants +%dir %{_prefix}/lib/systemd/system/dbus.target.wants +%dir %{_prefix}/lib/systemd/system/syslog.target.wants +%if ! 0%{?bootstrap} +%{_prefix}/lib/systemd/system-generators/systemd-cryptsetup-generator +%endif +%{_prefix}/lib/systemd/system-generators/systemd-getty-generator +%{_prefix}/lib/systemd/system-generators/systemd-rc-local-generator +%{_prefix}/lib/systemd/system-generators/systemd-fstab-generator +%{_prefix}/lib/systemd/system-generators/systemd-system-update-generator +/%{_lib}/security/pam_systemd.so + +%dir %{_libexecdir}/modules-load.d +%dir %{_sysconfdir}/modules-load.d + +%dir %{_libexecdir}/tmpfiles.d +%dir %{_sysconfdir}/tmpfiles.d +%{_libexecdir}/tmpfiles.d/*.conf + +%dir %{_libexecdir}/binfmt.d +%dir %{_sysconfdir}/binfmt.d + +%dir %{_libexecdir}/sysctl.d +%dir %{_sysconfdir}/sysctl.d + +%dir %{_sysconfdir}/systemd +%dir %{_sysconfdir}/systemd/system +%dir %{_sysconfdir}/systemd/user +%dir %{_sysconfdir}/xdg/systemd +%dir %{_sysconfdir}/xdg/systemd/user +%config(noreplace) %{_sysconfdir}/systemd/system.conf +%config(noreplace) %{_sysconfdir}/systemd/logind.conf +%config(noreplace) %{_sysconfdir}/systemd/journald.conf +%config(noreplace) %{_sysconfdir}/systemd/user.conf +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.locale1.conf +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.login1.conf +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.systemd1.conf +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.hostname1.conf +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.timedate1.conf + +%{_datadir}/dbus-1/interfaces/org.freedesktop.hostname1.xml +%{_datadir}/dbus-1/interfaces/org.freedesktop.locale1.xml +%{_datadir}/dbus-1/interfaces/org.freedesktop.systemd1.*.xml +%{_datadir}/dbus-1/interfaces/org.freedesktop.timedate1.xml +%{_datadir}/dbus-1/services/org.freedesktop.systemd1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.systemd1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.locale1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.login1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.hostname1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.timedate1.service +%dir %{_datadir}/polkit-1 +%dir %{_datadir}/polkit-1/actions +%{_datadir}/polkit-1/actions/org.freedesktop.systemd1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.hostname1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.locale1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.timedate1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.login1.policy +%{_datadir}/systemd + +%if ! 0%{?bootstrap} +# Packaged in sysvinit subpackage +%exclude %{_mandir}/man1/init.1* +%exclude %{_mandir}/man8/halt.8* +%exclude %{_mandir}/man8/reboot.8* +%exclude %{_mandir}/man8/shutdown.8* +%exclude %{_mandir}/man8/poweroff.8* +%exclude %{_mandir}/man8/telinit.8* +%exclude %{_mandir}/man8/runlevel.8* +%exclude %{_mandir}/man*/*udev*.[0-9]* +%{_mandir}/man1/*.1* +%{_mandir}/man3/*.3* +%{_mandir}/man5/*.5* +%{_mandir}/man7/*.7* +%{_mandir}/man8/*.8* +%endif +%{_docdir}/systemd +%{_prefix}/lib/udev/rules.d/70-uaccess.rules +%{_prefix}/lib/udev/rules.d/71-seat.rules +%{_prefix}/lib/udev/rules.d/73-seat-late.rules +%if ! 0%{?bootstrap} +%{_prefix}/lib/udev/rules.d/73-seat-numlock.rules +%endif +%{_prefix}/lib/udev/rules.d/99-systemd.rules +%if ! 0%{?bootstrap} +%{_prefix}/lib/udev/numlock-on +%endif +%dir %{_sysconfdir}/bash_completion.d +%{_sysconfdir}/bash_completion.d/systemd-bash-completion.sh +%{_sysconfdir}/rpm/macros.systemd +%dir /var/lib/systemd +%dir /var/lib/systemd/sysv-convert +%dir /var/lib/systemd/migrated +%dir /var/log/journal + +%files devel +%defattr(-,root,root,-) +%{_libdir}/libsystemd-daemon.so +%{_libdir}/libsystemd-login.so +%{_libdir}/libsystemd-id128.so +%{_libdir}/libsystemd-journal.so +%dir %{_includedir}/systemd +%{_includedir}/systemd/sd-login.h +%{_includedir}/systemd/sd-daemon.h +%{_includedir}/systemd/sd-id128.h +%{_includedir}/systemd/sd-journal.h +%{_includedir}/systemd/sd-messages.h +%{_includedir}/systemd/sd-shutdown.h +%{_datadir}/pkgconfig/systemd.pc +%{_libdir}/pkgconfig/libsystemd-daemon.pc +%{_libdir}/pkgconfig/libsystemd-login.pc +%{_libdir}/pkgconfig/libsystemd-id128.pc +%{_libdir}/pkgconfig/libsystemd-journal.pc + +%files sysvinit +%defattr(-,root,root,-) +/sbin/init +/sbin/reboot +/sbin/halt +/sbin/shutdown +/sbin/poweroff +/sbin/telinit +/sbin/runlevel +%if ! 0%{?bootstrap} +%{_mandir}/man1/init.1* +%{_mandir}/man8/halt.8* +%{_mandir}/man8/reboot.8* +%{_mandir}/man8/shutdown.8* +%{_mandir}/man8/poweroff.8* +%{_mandir}/man8/telinit.8* +%{_mandir}/man8/runlevel.8* +%endif + +%files analyze +%attr(0755,root,root) /usr/bin/systemd-analyze + +%files -n %{udevpkgname} +%defattr(-,root,root) +/sbin/udevd +/sbin/udevadm +# keep for compatibility +%ghost /lib/udev +%{_bindir}/udevadm +%{_prefix}/lib/firmware +%dir %{_prefix}/lib/udev/ +%{_prefix}/lib/udev/accelerometer +%{_prefix}/lib/udev/ata_id +%{_prefix}/lib/udev/cdrom_id +%{_prefix}/lib/udev/collect +%{_prefix}/lib/udev/findkeyboards +%{_prefix}/lib/udev/keymap +%{_prefix}/lib/udev/mtd_probe +%{_prefix}/lib/udev/scsi_id +%{_prefix}/lib/udev/v4l_id +%{_prefix}/lib/udev/write_dev_root_rule +%dir %{_prefix}/lib/udev/keymaps +%{_prefix}/lib/udev/keymaps/* +%{_prefix}/lib/udev/keyboard-force-release.sh +%dir %{_prefix}/lib/udev/rules.d/ +%exclude %{_prefix}/lib/udev/rules.d/70-uaccess.rules +%exclude %{_prefix}/lib/udev/rules.d/71-seat.rules +%exclude %{_prefix}/lib/udev/rules.d/73-seat-late.rules +%exclude %{_prefix}/lib/udev/rules.d/73-seat-numlock.rules +%exclude %{_prefix}/lib/udev/rules.d/99-systemd.rules +%{_prefix}/lib/udev/rules.d/*.rules +%{_sysconfdir}/init.d/boot.udev +%dir %{_sysconfdir}/udev/ +%dir %{_sysconfdir}/udev/rules.d/ +%config(noreplace) %{_sysconfdir}/udev/udev.conf +%if ! 0%{?bootstrap} +%{_mandir}/man?/*udev*.[0-9]* +%endif +%dir %{_prefix}/lib/systemd/system +%{_prefix}/lib/systemd/systemd-udevd +%{_prefix}/lib/systemd/system/udev-root-symlink.service +%{_prefix}/lib/systemd/system/*udev*.service +%{_prefix}/lib/systemd/system/systemd-udevd*.socket +%dir %{_prefix}/lib/systemd/system/sysinit.target.wants +%{_prefix}/lib/systemd/system/sysinit.target.wants/systemd-udev*.service +%dir %{_prefix}/lib/systemd/system/sockets.target.wants +%{_prefix}/lib/systemd/system/sockets.target.wants/systemd-udev*.socket + +%files -n lib%{udevpkgname}%{udev_major} +%defattr(-,root,root) +%{_libdir}/libudev.so.* + +%files -n lib%{udevpkgname}-devel +%defattr(-,root,root) +%{_includedir}/libudev.h +%{_libdir}/libudev.so +%{_datadir}/pkgconfig/udev.pc +%{_libdir}/pkgconfig/libudev.pc +%if ! 0%{?bootstrap} +%dir %{_datadir}/gtk-doc +%dir %{_datadir}/gtk-doc/html +%dir %{_datadir}/gtk-doc/html/libudev +%{_datadir}/gtk-doc/html/libudev/* +%endif + +%if ! 0%{?bootstrap} +%files -n libgudev-1_0-0 +%defattr(-,root,root) +%{_libdir}/libgudev-1.0.so.* + +%files -n typelib-1_0-GUdev-1_0 +%defattr(-,root,root) +%{_libdir}/girepository-1.0/GUdev-1.0.typelib + +%files -n libgudev-1_0-devel +%defattr(-,root,root) +%dir %{_includedir}/gudev-1.0 +%dir %{_includedir}/gudev-1.0/gudev +%{_includedir}/gudev-1.0/gudev/*.h +%{_libdir}/libgudev-1.0.so +%{_libdir}/pkgconfig/gudev-1.0.pc +%dir %{_datadir}/gtk-doc +%dir %{_datadir}/gtk-doc/html +%dir %{_datadir}/gtk-doc/html/gudev +%{_datadir}/gtk-doc/html/gudev/* +%{_datadir}/gir-1.0/GUdev-1.0.gir +%endif + +%changelog diff --git a/systemd-numlock-suse.patch b/systemd-numlock-suse.patch index 3c7d9c9..2c90cde 100644 --- a/systemd-numlock-suse.patch +++ b/systemd-numlock-suse.patch @@ -1,8 +1,8 @@ -Index: systemd-44/src/vconsole/vconsole-setup.c +Index: systemd-190/src/vconsole/vconsole-setup.c =================================================================== ---- systemd-44.orig/src/vconsole/vconsole-setup.c -+++ systemd-44/src/vconsole/vconsole-setup.c -@@ -265,12 +265,14 @@ int main(int argc, char **argv) { +--- systemd-190.orig/src/vconsole/vconsole-setup.c ++++ systemd-190/src/vconsole/vconsole-setup.c +@@ -287,12 +287,14 @@ int main(int argc, char **argv) { char *vc_kbd_delay = NULL; char *vc_kbd_rate = NULL; char *vc_kbd_disable_caps_lock = NULL; @@ -17,16 +17,8 @@ Index: systemd-44/src/vconsole/vconsole-setup.c int r = EXIT_FAILURE; pid_t font_pid = 0, keymap_pid = 0; -@@ -374,6 +376,7 @@ int main(int argc, char **argv) { - "KBD_DELAY", &vc_kbd_delay, - "KBD_RATE", &vc_kbd_rate, - "KBD_DISABLE_CAPS_LOCK", &vc_kbd_disable_caps_lock, -+ "KBD_NUMLOCK", &vc_kbd_numlock, - "COMPOSETABLE", &vc_compose_table, - NULL)) < 0) { - -@@ -391,6 +394,37 @@ int main(int argc, char **argv) { - log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r)); +@@ -388,6 +390,37 @@ int main(int argc, char **argv) { + vc_keymap = t; } disable_capslock = vc_kbd_disable_caps_lock && strcasecmp(vc_kbd_disable_caps_lock, "YES") == 0; + if (vc_kbd_numlock && strcasecmp(vc_kbd_numlock, "BIOS") == 0) { @@ -61,9 +53,17 @@ Index: systemd-44/src/vconsole/vconsole-setup.c + } else + numlock = vc_kbd_numlock && strcasecmp(vc_kbd_numlock, "YES") == 0; - #elif defined(TARGET_ARCH) - if ((r = parse_env_file("/etc/rc.conf", NEWLINE, -@@ -558,6 +592,10 @@ int main(int argc, char **argv) { + #elif defined(TARGET_SUSE) + r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE, +@@ -395,6 +428,7 @@ int main(int argc, char **argv) { + "KBD_DELAY", &vc_kbd_delay, + "KBD_RATE", &vc_kbd_rate, + "KBD_DISABLE_CAPS_LOCK", &vc_kbd_disable_caps_lock, ++ "KBD_NUMLOCK", &vc_kbd_numlock, + "COMPOSETABLE", &vc_compose_table, + NULL); + if (r < 0 && r != -ENOENT) +@@ -565,6 +599,10 @@ int main(int argc, char **argv) { finish: if (keymap_pid > 0) wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid); @@ -74,56 +74,35 @@ Index: systemd-44/src/vconsole/vconsole-setup.c #ifdef TARGET_SUSE if (compose_table_pid > 0) -Index: systemd-44/Makefile.am +Index: systemd-190/Makefile.am =================================================================== ---- systemd-44.orig/Makefile.am -+++ systemd-44/Makefile.am -@@ -42,6 +42,7 @@ dbussessionservicedir=@dbussessionservic - dbussystemservicedir=@dbussystemservicedir@ - dbusinterfacedir=@dbusinterfacedir@ - udevrulesdir=@udevrulesdir@ -+udevhelperdir=@udevhelperdir@ - pamlibdir=@pamlibdir@ - pkgconfigdatadir=$(datadir)/pkgconfig - pkgconfiglibdir=$(libdir)/pkgconfig -@@ -202,6 +203,9 @@ rootlibexec_PROGRAMS = \ - systemgenerator_PROGRAMS = \ - systemd-getty-generator - -+udevhelper_PROGRAMS = \ -+ numlock-on -+ - noinst_PROGRAMS = \ - test-engine \ - test-job-type \ -@@ -2033,6 +2037,12 @@ systemd_uaccess_LDADD = \ - $(UDEV_LIBS) \ - $(ACL_LIBS) +--- systemd-190.orig/Makefile.am ++++ systemd-190/Makefile.am +@@ -1989,6 +1989,19 @@ dist_udevrules_DATA += \ + rules/61-accelerometer.rules + # ------------------------------------------------------------------------------ +numlock_on_SOURCES = \ + src/login/numlock-on.c + +numlock_on_CFLAGS = \ + $(AM_CFLAGS) + - rootlibexec_PROGRAMS += \ - systemd-uaccess - -@@ -2040,7 +2050,8 @@ dist_udevrules_DATA += \ - src/login/70-uaccess.rules - - dist_udevrules_DATA += \ -- src/login/71-seat.rules -+ src/login/71-seat.rules \ -+ src/login/73-seat-numlock.rules - - nodist_udevrules_DATA += \ - src/login/73-seat-late.rules -Index: systemd-44/configure.ac ++udevlibexec_PROGRAMS += \ ++ numlock-on ++ ++dist_udevrules_DATA += \ ++ rules/73-seat-numlock.rules ++ ++# ------------------------------------------------------------------------------ + if ENABLE_GUDEV + if ENABLE_GTK_DOC + SUBDIRS += \ +Index: systemd-190/configure.ac =================================================================== ---- systemd-44.orig/configure.ac -+++ systemd-44/configure.ac -@@ -410,6 +410,13 @@ fi +--- systemd-190.orig/configure.ac ++++ systemd-190/configure.ac +@@ -598,6 +598,13 @@ fi with_distro=`echo ${with_distro} | tr '[[:upper:]]' '[[:lower:]]' ` AC_DEFINE_UNQUOTED(DISTRIBUTION, ["${with_distro}"], [Target Distribution]) @@ -137,38 +116,10 @@ Index: systemd-44/configure.ac # Location of the init scripts as mandated by LSB SYSTEM_SYSVINIT_PATH=/etc/init.d SYSTEM_SYSVRCND_PATH=/etc/rc.d -@@ -579,6 +586,11 @@ AC_ARG_WITH([udevrulesdir], - [], - [with_udevrulesdir=`pkg-config --variable=udevdir udev`/rules.d]) - -+AC_ARG_WITH([udevhelperdir], -+ AS_HELP_STRING([--with-udevhelperdir=DIR], [Directory for udev helpers]), -+ [], -+ [with_udevhelperdir=`pkg-config --variable=udevdir udev`]) -+ - AC_ARG_WITH([rootprefix], - AS_HELP_STRING([--with-rootprefix=DIR], [rootfs directory prefix for config files and kernel modules]), - [], [with_rootprefix=${ac_default_prefix}]) -@@ -611,6 +623,7 @@ AC_SUBST([dbussessionservicedir], [$with - AC_SUBST([dbussystemservicedir], [$with_dbussystemservicedir]) - AC_SUBST([dbusinterfacedir], [$with_dbusinterfacedir]) - AC_SUBST([udevrulesdir], [$with_udevrulesdir]) -+AC_SUBST([udevhelperdir], [$with_udevhelperdir]) - AC_SUBST([pamlibdir], [$with_pamlibdir]) - AC_SUBST([rootprefix], [$with_rootprefix]) - AC_SUBST([rootlibdir], [$with_rootlibdir]) -@@ -650,6 +663,7 @@ AC_MSG_RESULT([ - rootlib dir: ${with_rootlibdir} - PAM modules dir: ${with_pamlibdir} - udev rules dir: ${with_udevrulesdir} -+ udev hepler dir: ${with_udevhelperdir} - D-Bus policy dir: ${with_dbuspolicydir} - D-Bus session dir: ${with_dbussessionservicedir} - D-Bus system dir: ${with_dbussystemservicedir} -Index: systemd-44/src/login/73-seat-numlock.rules +Index: systemd-190/rules/73-seat-numlock.rules =================================================================== --- /dev/null -+++ systemd-44/src/login/73-seat-numlock.rules ++++ systemd-190/rules/73-seat-numlock.rules @@ -0,0 +1,8 @@ +# This file is part of systemd. +# @@ -178,10 +129,10 @@ Index: systemd-44/src/login/73-seat-numlock.rules +# (at your option) any later version. + +SUBSYSTEM=="tty", ACTION=="add", KERNEL=="tty[0-9]|tty1[0-2]", TEST=="/run/numlock-on", RUN+="numlock-on $env{DEVNAME}" -Index: systemd-44/src/login/numlock-on.c +Index: systemd-190/src/login/numlock-on.c =================================================================== --- /dev/null -+++ systemd-44/src/login/numlock-on.c ++++ systemd-190/src/login/numlock-on.c @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + @@ -219,16 +170,16 @@ Index: systemd-44/src/login/numlock-on.c + return EX_IOERR; + return execv(args[0], args); +} -Index: systemd-44/units/systemd-vconsole-setup.service.in +Index: systemd-190/units/systemd-vconsole-setup.service.in =================================================================== ---- systemd-44.orig/units/systemd-vconsole-setup.service.in -+++ systemd-44/units/systemd-vconsole-setup.service.in -@@ -10,7 +10,7 @@ Description=Setup Virtual Console +--- systemd-190.orig/units/systemd-vconsole-setup.service.in ++++ systemd-190/units/systemd-vconsole-setup.service.in +@@ -11,7 +11,7 @@ Documentation=man:systemd-vconsole-setup DefaultDependencies=no Conflicts=shutdown.target After=systemd-readahead-collect.service systemd-readahead-replay.service -Before=sysinit.target shutdown.target +Before=sysinit.target shutdown.target udev-trigger.service + ConditionPathExists=/dev/tty0 [Service] - Type=oneshot diff --git a/systemd-rpmlintrc b/systemd-rpmlintrc index cc21ff2..5b28a2c 100644 --- a/systemd-rpmlintrc +++ b/systemd-rpmlintrc @@ -2,9 +2,19 @@ addFilter(".*dangling-symlink /sbin/(halt|init|poweroff|telinit|shutdown|runleve addFilter(".*dangling-symlink .* /dev/null.*") addFilter(".*files-duplicate .*/reboot.8.*") addFilter(".*files-duplicate .*/sd_is_socket.3.*") -addFilter("non-conffile-in-etc /etc/bash_completion.d/systemctl-bash-completion.sh") +addFilter("non-conffile-in-etc /etc/bash_completion.d/systemd-bash-completion.sh") +addFilter("non-conffile-in-etc /etc/rpm/macros.systemd") addFilter(".*dbus-policy-allow-receive") # Do not enable for submission into openSUSE:Factory, # just for testing while polkit-default-privs is not checked in -# setBadness('polkit-unauthorized-privilege', 1) - +setBadness('polkit-unauthorized-privilege', 1) +addFilter(".*dangling-symlink /lib/udev/devices/std(in|out|err).*") +addFilter(".*dangling-symlink /lib/udev/devices/core.*") +addFilter(".*dangling-symlink /lib/udev/devices/fd.*") +addFilter(".*incoherent-init-script-name boot.udev.*") +addFilter(".init-script-without-%stop_on_removal-preun /etc/init.d/boot.udev") +addFilter(".init-script-without-%restart_on_update-postun /etc/init.d/boot.udev") +addFilter(".*devel-file-in-non-devel-package.*udev.pc.*") +addFilter(".*libgudev-.*shlib-fixed-dependency.*") +addFilter(".*suse-filelist-forbidden-systemd-userdirs.*") +addFilter("libudev-mini.*shlib-policy-name-error.*") diff --git a/systemd.changes b/systemd.changes index 7b07e1c..fa78071 100644 --- a/systemd.changes +++ b/systemd.changes @@ -1,3 +1,151 @@ +------------------------------------------------------------------- +Thu Oct 18 12:27:07 UTC 2012 - fcrozat@suse.com + +- Create and own more systemd drop-in directories. + +------------------------------------------------------------------- +Tue Oct 16 13:18:13 UTC 2012 - fcrozat@suse.com + +- Improve mini packages for bootstrapping. +- do not mount /tmp as tmpfs by default. + +------------------------------------------------------------------- +Tue Oct 16 07:40:23 UTC 2012 - fcrozat@suse.com + +- Fix install script when there is no inittab + +------------------------------------------------------------------- +Mon Oct 15 14:48:47 UTC 2012 - fcrozat@suse.com + +- Create a systemd-mini specfile to prevent cycle in bootstrapping + +------------------------------------------------------------------- +Thu Oct 4 11:23:42 UTC 2012 - fcrozat@suse.com + +- udev and its subpackages are now generated by systemd source + package. +- migrate udev and systemd to /usr +- Update to version 194: + + if /etc/vconsole.conf is non-existent or empty and if + /etc/sysconfig/console:CONSOLE_FONT (resp + /etc/sysconfig/keyboard:KEYTABLE) set, console font (resp + keymap) is not modified. +- Changes from version 44 to 193: + + journalctl gained --cursor= to show entries starting from a + specified location in journal. + + Size limit enforced to 4K for fields exported with "-o json" in + journalctl. Use --all to disable this behavior. + + Optional journal gateway daemon + (systemd-journal-gatewayd.service) to access journal via HTTP + and JSON. Use "wget http://localhost:19531/entries" to get + /var/log/messages compatible format and + 'curl -H"Accept: application/json" + http://localhost:19531/entries' for JSON formatted content. + HTML5 static page is also available as explained on + http://0pointer.de/public/journal-gatewayd + + do not mount cpuset controler, doesn't work well by default + ATM. + + improved nspawn behaviour with /etc/localtime + + journald logs its maximize size on disk + + multi-seat X wrapper (partially merged in upstream X server). + + HandleSleepKey has been splitted into HandleSuspendKey and + HandleHibernateKey. + + systemd and logind now handle system sleep states, in + particular suspending and hibernating. + + new cgroups are mounted by default (cpu, cpuacct, + net_cls, net_pri) + + sync at shutdown is now handled by kernel + + imported journalctl output (colors, filtering, pager, bash + completion). + + suffix ".service" may now be ommited on most systemctl command + involving service unit names. + + much improved nspawn containers support. + + new conditions added : ConditionFileNotEmpty, ConditionHost, + ConditionPathIsReadWrite + + tmpfiles "w" supports file globbing + + logind handles lid switch, power and sleep keys all the time, + unless systemd-inhibit + --what=handle-power-key:handle-sleep-key:handle-lid-switch is + run by Desktop Environments. + + support for reading structured kernel message is used by + default (need kernel >= 3.5). /proc/kmsg is now used only by + classic syslog daemons. + + Forward Secure Sealing is now support for Journal files. + + RestartPrevenExitStatus and SuccessExitStatus allow configure + of exit status (exit code or signal). + + handles keyfile-size and keyfile-offset in /etc/crypttab. + + TimeoutSec settings has been splitted into TimeoutStartSec and + TimeoutStopSec. + + add SystemCallFilters option to add blacklist/whitelist to + system calls, using SECCOMP mode 2 of kernel >= 3.5. + + systemctl udevadm info now takes a /dev or /sys path as argument: + - udevadm info /dev/sda + + XDG_RUNTIME_DIR now uses numeric UIDs instead of usernames. + + systemd-loginctl and systemd-journalctl have been renamed + to loginctl and journalctl to match systemctl. + + udev: RUN+="socket:..." and udev_monitor_new_from_socket() is + no longer supported. udev_monitor_new_from_netlink() needs to + be used to subscribe to events. + + udev: when udevd is started by systemd, processes which are left + behind by forking them off of udev rules, are unconditionally + cleaned up and killed now after the event handling has finished. + Services or daemons must be started as systemd services. + Services can be pulled-in by udev to get started, but they can + no longer be directly forked by udev rules. + + For almost all files, license is now LGPL2.1+ (from previous + GPL2.0+). Exception are some minor stuff in udev (will be + changed to LGPL2.1 eventually) and MIT license sd-daemon.[ch] + library. + + var-run.mount and var-lock.mount are no longer provided + (should be converted to symlinks). + + A new service type Type=idle to avoid ugly interleaving of + getty output and boot status messages. + + systemd-delta has been added, a tool to explore differences + between user/admin configuration and vendor defaults. + + /tmp mouted as tmpfs by default. + + /media is now longer mounted as tmpfs + + GTK tool has been split off to systemd-ui package. + + much improved documentation. +- Merge BuildRequires from udev package: + gobject-introspection-devel, gtk-doc, libsepol-devel, + libusb-devel, pkgconfig(blkid), pkgconfig-glib-2.0), + pjgconfig(libcryptsetup), pkgconfig(libpci), + pkgconfig(libqrencode), pkgconfig(libselinux), + pkgconfig(usbutils). +- Add pkgconfig(libqrencode) and pkgconfig(libmicrohttpd) +- Merge sources from udev package: boot.udev, write_dev_root.rules, + udev-root-symlink.systemd. +- Merge patches from udev package: numbered started from 1000): + 0001-Reinstate-TIMEOUT-handling.patch, + 0013-re-enable-by_path-links-for-ata-devices.patch, + 0014-rules-create-by-id-scsi-links-for-ATA-devices.patch, + 0026-udev-netlink-null-rules.patch, + 0027-udev-fix-sg-autoload-regression.patch. +- Remove following patches, merged upstream: + 0001-util-never-follow-symlinks-in-rm_rf_children.patch, + fixppc.patch, logind-logout.patch, fix-getty-isolate.patch, + fix-swap-priority.patch, improve-restart-behaviour.patch, + fix-dir-noatime-tmpfiles.patch, journal-bugfixes.patch, + ulimit-support.patch, change-terminal.patch, + fix-tty-startup.patch, fix-write-user-state-file.patch, + fix-analyze-exception.patch, use_localtime.patch, + journalctl-pager-improvement.patch, + avoid-random-seed-cycle.patch, + 0001-add-sparse-support-to-detect-endianness-bug.patch, + drop-timezone.patch. +- Rebase the following patches: + 0001-Add-bootsplash-handling-for-password-dialogs.patch, + 0001-handle-disable_caplock-and-compose_table-and-kbd_rat.patch, + 0001-service-Fix-dependencies-added-when-parsing-insserv..patch, + 0001-service-flags-sysv-service-with-detected-pid-as-Rema.patch, + crypt-loop-file.patch, + delay-fsck-cryptsetup-after-md-lvm-dmraid.patch, + dm-lvm-after-local-fs-pre-target.patch, fastboot-forcefsck.patch, + fix-enable-disable-boot-initscript.patch, modules_on_boot.patch, + new-lsb-headers.patch, storage-after-cryptsetup.patch, + support-suse-clock-sysconfig.patch, support-sysvinit.patch, + sysctl-modules.patch, systemd-numlock-suse.patch, tty1.patch. + ------------------------------------------------------------------- Thu Aug 23 11:11:25 CEST 2012 - fcrozat@suse.com diff --git a/systemd.spec b/systemd.spec index 90324d8..ffae0f9 100644 --- a/systemd.spec +++ b/systemd.spec @@ -16,51 +16,88 @@ # +%define bootstrap 0 +%define real systemd +%define udevpkgname udev +%define udev_major 1 + Name: systemd Url: http://www.freedesktop.org/wiki/Software/systemd -Version: 44 +Version: 194 Release: 0 Summary: A System and Session Manager -License: GPL-2.0+ +License: LGPL-2.1+ Group: System/Base BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: audit-devel BuildRequires: dbus-1 +%if ! 0%{?bootstrap} BuildRequires: docbook-xsl-stylesheets +%endif BuildRequires: fdupes +%if ! 0%{?bootstrap} +BuildRequires: gobject-introspection-devel +%endif BuildRequires: gperf +%if ! 0%{?bootstrap} +BuildRequires: gtk-doc +%endif BuildRequires: intltool BuildRequires: libacl-devel BuildRequires: libcap-devel +BuildRequires: libsepol-devel BuildRequires: libtool +BuildRequires: libusb-devel +%if ! 0%{?bootstrap} BuildRequires: libxslt-tools +%endif BuildRequires: pam-devel -BuildRequires: pkg-config BuildRequires: tcpd-devel -BuildRequires: udev BuildRequires: xz +BuildRequires: pkgconfig(blkid) >= 2.20 BuildRequires: pkgconfig(dbus-1) >= 1.3.2 -BuildRequires: pkgconfig(libcryptsetup) +%if ! 0%{?bootstrap} +BuildRequires: pkgconfig(glib-2.0) >= 2.22.0 +BuildRequires: pkgconfig(libcryptsetup) >= 1.4.2 +%endif BuildRequires: pkgconfig(libkmod) >= 5 BuildRequires: pkgconfig(liblzma) -BuildRequires: pkgconfig(libselinux) +%if ! 0%{?bootstrap} +BuildRequires: pkgconfig(libmicrohttpd) +%endif +BuildRequires: pkgconfig(libpci) >= 3 +%if ! 0%{?bootstrap} +BuildRequires: pkgconfig(libqrencode) +%endif +BuildRequires: pkgconfig(libselinux) >= 2.1.9 BuildRequires: pkgconfig(libsepol) -BuildRequires: pkgconfig(udev) >= 172 +BuildRequires: pkgconfig(usbutils) >= 0.82 +%if 0%{?bootstrap} +Requires: this-is-only-for-build-envs +%else +# the buildignore is important for bootstrapping +#!BuildIgnore: udev +Requires: %{udevpkgname} >= 172 Requires: dbus-1 >= 1.4.0 Requires: kbd Requires: pam-config >= 0.79-5 Requires: systemd-presets-branding -Requires: udev >= 172 Requires: util-linux >= 2.21 +%endif Conflicts: filesystem < 11.5 Conflicts: mkinitrd < 2.7.0 -Source0: http://www.freedesktop.org/software/systemd/%{name}-%{version}.tar.xz +Source0: http://www.freedesktop.org/software/systemd/systemd-%{version}.tar.xz Source1: systemd-rpmlintrc Source2: localfs.service Source3: systemd-sysv-convert Source4: macros.systemd Source5: systemd-insserv_conf Source6: baselibs.conf + +Source1060: boot.udev +Source1061: write_dev_root_rule +Source1062: udev-root-symlink.systemd + Patch1: 0001-Add-bootsplash-handling-for-password-dialogs.patch # handle SUSE specific kbd settings Patch6: 0001-handle-disable_caplock-and-compose_table-and-kbd_rat.patch @@ -71,7 +108,6 @@ Patch10: 0001-service-Fix-dependencies-added-when-parsing-insserv..patch Patch13: 0001-service-flags-sysv-service-with-detected-pid-as-Rema.patch Patch15: support-sysvinit.patch Patch16: modules_on_boot.patch -Patch19: avoid-random-seed-cycle.patch Patch22: new-lsb-headers.patch Patch23: storage-after-cryptsetup.patch Patch24: delay-fsck-cryptsetup-after-md-lvm-dmraid.patch @@ -79,31 +115,29 @@ Patch31: lock-opensuse.patch Patch33: crypt-loop-file.patch Patch36: sysctl-modules.patch Patch38: dm-lvm-after-local-fs-pre-target.patch -Patch41: 0001-add-sparse-support-to-detect-endianness-bug.patch Patch53: fastboot-forcefsck.patch Patch56: support-suse-clock-sysconfig.patch -Patch57: drop-timezone.patch Patch59: fix-enable-disable-boot-initscript.patch # Upstream First - Policy: # Never add any patches to this package without the upstream commit id # in the patch. Any patches added here without a very good reason to make # an exception will be silently removed with the next version update. -Patch40: 0001-util-never-follow-symlinks-in-rm_rf_children.patch -Patch42: fixppc.patch -Patch43: logind-logout.patch -Patch44: fix-getty-isolate.patch -Patch45: fix-swap-priority.patch -Patch46: improve-restart-behaviour.patch -Patch47: fix-dir-noatime-tmpfiles.patch -Patch48: journal-bugfixes.patch -Patch49: ulimit-support.patch -Patch50: change-terminal.patch -Patch51: fix-tty-startup.patch -Patch52: fix-write-user-state-file.patch -Patch54: fix-analyze-exception.patch -Patch55: use_localtime.patch -Patch58: journalctl-pager-improvement.patch + +# udev patches +# PATCH-FIX-OPENSUSE 0001-Reinstate-TIMEOUT-handling.patch +Patch1001: 0001-Reinstate-TIMEOUT-handling.patch +# PATCH-FIX-OPENSUSE 0013-re-enable-by_path-links-for-ata-devices.patch +Patch1013: 0013-re-enable-by_path-links-for-ata-devices.patch +# PATCH-FIX-OPENSUSE 0014-rules-create-by-id-scsi-links-for-ATA-devices.patch +Patch1014: 0014-rules-create-by-id-scsi-links-for-ATA-devices.patch + +# PATCH-FIX-OPENSUSE 0026-udev-netlink-null-rules.patch +Patch1026: 0026-udev-netlink-null-rules.patch +# PATCH-FIX-OPENSUSE 0027-udev-fix-sg-autoload-regression.patch +Patch1027: 0027-udev-fix-sg-autoload-regression.patch + +# systemd patches %description Systemd is a system and service manager, compatible with SysV and LSB @@ -115,11 +149,12 @@ maintains mount and automount points and implements an elaborate transactional dependency-based service control logic. It can work as a drop-in replacement for sysvinit. + + %package devel Summary: Development headers for systemd Group: Development/Libraries/C and C++ Requires: %{name} = %{version} -Requires: pkg-config %description devel Development headers and auxiliary files for developing applications for systemd. @@ -150,17 +185,104 @@ initialization at boot. 'systemd-analyze plot' renders an SVG visualizing the parallel start of units at boot. +%package -n %{udevpkgname} +Summary: A rule-based device node and kernel event manager +Group: System/Kernel +Url: http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html +PreReq: /bin/pidof /bin/rm /usr/bin/stat %insserv_prereq %fillup_prereq /usr/sbin/groupadd /usr/bin/getent /sbin/mkinitrd +Conflicts: systemd < 39 +Conflicts: aaa_base < 11.5 +Conflicts: filesystem < 11.5 +Conflicts: mkinitrd < 2.7.0 +Conflicts: util-linux < 2.16 +Conflicts: ConsoleKit < 0.4.1 +Requires: filesystem +%if 0%{?bootstrap} +Provides: udev = %{version} +%endif + +%description -n %{udevpkgname} +Udev creates and removes device nodes in /dev for devices discovered or +removed from the system. It receives events via kernel netlink messages +and dispatches them according to rules in /lib/udev/rules.d/. Matching +rules may name a device node, create additional symlinks to the node, +call tools to initialize a device, or load needed kernel modules. + + + +%package -n lib%{udevpkgname}%{udev_major} +Summary: Dynamic library to access udev device information +Group: System/Libraries +Requires: %{udevpkgname} >= %{version}-%{release} + +%description -n lib%{udevpkgname}%{udev_major} +This package contains the dynamic library libudev, which provides +access to udev device information + +%package -n lib%{udevpkgname}-devel +Summary: Development files for libudev +Group: Development/Libraries/Other +Requires: lib%{udevpkgname}%{udev_major} = %{version}-%{release} +%if 0%{?bootstrap} +Provides: libudev-devel = %{version} +%endif + +%description -n lib%{udevpkgname}-devel +This package contains the development files for the library libudev, a +dynamic library, which provides access to udev device information. + +%if ! 0%{?bootstrap} +%package -n libgudev-1_0-0 +Summary: GObject library, to access udev device information +Group: System/Libraries +Requires: lib%{udevpkgname}%{udev_major} = %{version}-%{release} + +%description -n libgudev-1_0-0 +This package contains the GObject library libgudev, which provides +access to udev device information. + +%package -n typelib-1_0-GUdev-1_0 +Summary: GObject library, to access udev device information -- Introspection bindings +Group: System/Libraries + +%description -n typelib-1_0-GUdev-1_0 +This package provides the GObject Introspection bindings for libgudev, which +provides access to udev device information. + +%package -n libgudev-1_0-devel +Summary: Devel package for libgudev +Group: Development/Libraries/Other +Requires: glib2-devel +Requires: libgudev-1_0-0 = %{version}-%{release} +Requires: libudev-devel = %{version}-%{release} +Requires: typelib-1_0-GUdev-1_0 = %{version}-%{release} + +%description -n libgudev-1_0-devel +This is the devel package for the GObject library libgudev, which +provides GObject access to udev device information. +%endif + %prep -%setup -q +%setup -q -n systemd-%{version} + +#udev +%patch1001 -p1 +%patch1013 -p1 +%patch1014 -p1 +%patch1026 -p1 +%patch1027 -p1 + %patch1 -p1 %patch6 -p1 +# don't apply when bootstrapping to not modify configure.in +%if ! 0%{?bootstrap} %patch7 -p1 +%endif %patch8 -p1 %patch10 -p1 %patch13 -p1 %patch15 -p1 %patch16 -p1 -%patch19 -p1 %patch22 -p1 %patch23 -p1 %patch24 -p1 @@ -168,99 +290,99 @@ at boot. %patch33 -p1 %patch36 -p1 %patch38 -p1 -%patch40 -p1 -%patch41 -p1 -%patch42 -p1 -# this one causes too many trouble for now, disabling (bnc#769531) -#patch43 -p1 -%patch44 -p1 -%patch45 -p1 -%patch46 -p1 -%patch47 -p1 -%patch48 -p1 -%patch49 -p1 -%patch50 -p1 -%patch51 -p1 -%patch52 -p1 %patch53 -p1 -%patch54 -p1 -%patch55 -p1 %patch56 -p1 -%patch57 -p1 -%patch58 -p1 %patch59 -p1 -#needed by patch49 -rm man/systemd.conf.5 - %build +%if ! 0%{?bootstrap} autoreconf -fiv +%endif # prevent pre-generated and distributed files from re-building find . -name "*.[1-8]" -exec touch '{}' \; -touch src/systemadm.c export V=1 -# disable plymouth at configure time, units are shipped in plymouth package now +# keep split-usr until all packages have moved their systemd rules to /usr %configure \ --with-distro=suse \ --docdir=%{_docdir}/systemd \ - --with-rootprefix= \ --with-pamlibdir=/%{_lib}/security \ - --enable-split-usr \ - --disable-gtk \ +%if 0%{?bootstrap} + --disable-gudev \ +%else --enable-manpages \ - --disable-plymouth \ + --enable-gtk-doc \ +%endif + --enable-selinux \ + --enable-split-usr \ + --disable-static \ CFLAGS="%{optflags}" make %{?_smp_mflags} %install %makeinstall +mkdir -p $RPM_BUILD_ROOT/{sbin,lib,bin} +ln -sf %{_bindir}/udevadm $RPM_BUILD_ROOT/sbin/udevadm +ln -sf %{_prefix}/lib/systemd/systemd-udevd $RPM_BUILD_ROOT/sbin/udevd +mkdir -p $RPM_BUILD_ROOT/%{_prefix}/usr/lib/firmware/updates +ln -sf /lib/firmware $RPM_BUILD_ROOT/usr/lib/firmware + +install -m755 -D %{S:1060} $RPM_BUILD_ROOT/etc/init.d/boot.udev +install -m755 -D %{S:1061} $RPM_BUILD_ROOT/%{_prefix}/lib/udev/write_dev_root_rule +install -m644 -D %{S:1062} $RPM_BUILD_ROOT/%{_prefix}/lib/systemd/system/udev-root-symlink.service +mkdir -p $RPM_BUILD_ROOT/lib/systemd/system/basic.target.wants +ln -sf ../udev-root-symlink.service $RPM_BUILD_ROOT/%{_prefix}/lib/systemd/system/basic.target.wants + #fix manpages +%if ! 0%{?bootstrap} sed -i -e 's,^\(\.so \)\(.*\.\)\([0-9]\),\1man\3/\2\3,g' %{buildroot}/%{_mandir}/*/* +%endif #workaround for 716939 chmod 644 %{buildroot}%{_bindir}/systemd-analyze mkdir -p %{buildroot}%{_sysconfdir}/rpm install -m644 %{S:4} %{buildroot}%{_sysconfdir}/rpm find %{buildroot} -type f -name '*.la' -exec rm -f {} ';' -mkdir -p %{buildroot}/{sbin,var/lib/systemd/sysv-convert,var/lib/systemd/migrated} %{buildroot}/lib/systemd/{system.preset,user.preset,system/halt.target.wants,system/kexec.target.wants,system/poweroff.target.wants,system/reboot.target.wants} +mkdir -p %{buildroot}/{sbin,var/lib/systemd/sysv-convert,var/lib/systemd/migrated} %{buildroot}/usr/lib/systemd/{system-generators,user-generators,system-preset,user-preset,system/halt.target.wants,system/kexec.target.wants,system/poweroff.target.wants,system/reboot.target.wants} install -m755 %{S:3} -D %{buildroot}%{_sbindir}/systemd-sysv-convert # do not install, code has been fixed, might be useful in the future #install -m755 %{S:5} %{buildroot}/lib/systemd/system-generators -ln -s ../lib/systemd/systemd %{buildroot}/bin/systemd -ln -s ../lib/systemd/systemd %{buildroot}/sbin/init -ln -s ../bin/systemctl %{buildroot}/sbin/reboot -ln -s ../bin/systemctl %{buildroot}/sbin/halt -ln -s ../bin/systemctl %{buildroot}/sbin/shutdown -ln -s ../bin/systemctl %{buildroot}/sbin/poweroff -ln -s ../bin/systemctl %{buildroot}/sbin/telinit -ln -s ../bin/systemctl %{buildroot}/sbin/runlevel +ln -s ../usr/lib/systemd/systemd %{buildroot}/bin/systemd +ln -s ../usr/lib/systemd/systemd %{buildroot}/sbin/init +ln -s ../usr/bin/systemctl %{buildroot}/sbin/reboot +ln -s ../usr/bin/systemctl %{buildroot}/sbin/halt +ln -s ../usr/bin/systemctl %{buildroot}/sbin/shutdown +ln -s ../usr/bin/systemctl %{buildroot}/sbin/poweroff +ln -s ../usr/bin/systemctl %{buildroot}/sbin/telinit +ln -s ../usr/bin/systemctl %{buildroot}/sbin/runlevel rm -rf %{buildroot}/etc/systemd/system/*.target.wants rm -f %{buildroot}/etc/systemd/system/default.target # aliases for /etc/init.d/* -ln -s /dev/null %{buildroot}/lib/systemd/system/cgroup.service -ln -s systemd-tmpfiles-setup.service %{buildroot}/lib/systemd/system/cleanup.service -ln -s /dev/null %{buildroot}/lib/systemd/system/clock.service -ln -s /dev/null %{buildroot}/lib/systemd/system/crypto.service -ln -s /dev/null %{buildroot}/lib/systemd/system/crypto-early.service -ln -s /dev/null %{buildroot}/lib/systemd/system/device-mapper.service -ln -s /dev/null %{buildroot}/lib/systemd/system/earlysyslog.service -ln -s /dev/null %{buildroot}/lib/systemd/system/kbd.service -ln -s /dev/null %{buildroot}/lib/systemd/system/ldconfig.service -ln -s /dev/null %{buildroot}/lib/systemd/system/loadmodules.service -install -m644 %{S:2} %{buildroot}/lib/systemd/system/localfs.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/cgroup.service +ln -s systemd-tmpfiles-setup.service %{buildroot}/%{_prefix}/lib/systemd/system/cleanup.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/clock.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/crypto.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/crypto-early.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/device-mapper.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/earlysyslog.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/kbd.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/ldconfig.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/loadmodules.service +install -m644 %{S:2} %{buildroot}/%{_prefix}/lib/systemd/system/localfs.service # need to be implemented in systemd directly -#ln -s /dev/null %{buildroot}/lib/systemd/system/localnet.service -ln -s /dev/null %{buildroot}/lib/systemd/system/proc.service -ln -s fsck-root.service %{buildroot}/lib/systemd/system/rootfsck.service -ln -s /dev/null %{buildroot}/lib/systemd/system/single.service -ln -s /dev/null %{buildroot}/lib/systemd/system/swap.service -ln -s /dev/null %{buildroot}/lib/systemd/system/startpreload.service -ln -s /dev/null %{buildroot}/lib/systemd/system/stoppreload.service -ln -s /dev/null %{buildroot}/lib/systemd/system/earlyxdm.service -ln -s systemd-sysctl.service %{buildroot}/lib/systemd/system/sysctl.service -ln -s systemd-random-seed-load.service %{buildroot}/lib/systemd/system/random.service +#ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/localnet.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/proc.service +ln -s systemd-fsck-root.service %{buildroot}/%{_prefix}/lib/systemd/system/rootfsck.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/single.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/swap.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/startpreload.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/stoppreload.service +ln -s /dev/null %{buildroot}/%{_prefix}/lib/systemd/system/earlyxdm.service +ln -s systemd-sysctl.service %{buildroot}/%{_prefix}/lib/systemd/system/sysctl.service +ln -s systemd-random-seed-load.service %{buildroot}/%{_prefix}/lib/systemd/system/random.service +# don't mount /tmp as tmpfs for now +rm %{buildroot}/%{_prefix}/lib/systemd/system/local-fs.target.wants/tmp.mount # To avoid making life hard for Factory developers, don't package the # kernel.core_pattern setting until systemd-coredump is a part of an actual @@ -268,13 +390,27 @@ ln -s systemd-random-seed-load.service %{buildroot}/lib/systemd/system/random.se # journal. rm -f %{buildroot}%{_libdir}/../lib/sysctl.d/coredump.conf -# Let rsyslog read from /proc/kmsg for now -sed -i -e 's/\#ImportKernel=yes/ImportKernel=no/' %{buildroot}%{_sysconfdir}/systemd/systemd-journald.conf +# legacy links +ln -s loginctl %{buildroot}%{_bindir}/systemd-loginctl +ln -s journalctl %{buildroot}%{_bindir}/systemd-journalctl +ln -s /usr/lib/udev %{buildroot}/lib/udev # Create the /var/log/journal directory to change the volatile journal to a persistent one mkdir -p %{buildroot}/var/log/journal -%fdupes $RPM_BUILD_ROOT +# Make sure the NTP units dir exists +mkdir -p %{buildroot}%{_prefix}/lib/systemd/ntp-units.d/ + +# Make sure the shutdown/sleep drop-in dirs exist +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-shutdown/ +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-sleep/ + +# Make sure these directories are properly owned +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/default.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/dbus.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/syslog.target.wants + +%fdupes -s %{buildroot}%{_mandir} %post /usr/sbin/pam-config -a --systemd >/dev/null 2>&1 || : @@ -283,10 +419,10 @@ mkdir -p %{buildroot}/var/log/journal /bin/systemctl daemon-reexec >/dev/null 2>&1 || : # Try to read default runlevel from the old inittab if it exists -if [ ! -e /etc/systemd/system/default.target ]; then +if [ ! -e /etc/systemd/system/default.target -a -e /etc/inittab ]; then runlevel=$(awk -F ':' '$3 == "initdefault" && $1 !~ "^#" { print $2 }' /etc/inittab 2> /dev/null) if [ -n "$runlevel" ] ; then - /bin/ln -sf /lib/systemd/system/runlevel$runlevel.target /etc/systemd/system/default.target 2>&1 || : + /bin/ln -sf /usr/lib/systemd/system/runlevel$runlevel.target /etc/systemd/system/default.target 2>&1 || : fi fi # Create default config in /etc at first install. @@ -319,22 +455,89 @@ if [ $1 -eq 0 ]; then rm -f /etc/systemd/system/default.target 2>&1 || : fi +%pretrans -n %{udevpkgname} -p +if posix.stat("/lib/udev") and not posix.stat("/usr/lib/udev") then + posix.symlink("/lib/udev", "/usr/lib/udev") +end + +%pre -n %{udevpkgname} +if test -L /usr/lib/udev -a /lib/udev -ef /usr/lib/udev ; then + rm /usr/lib/udev + mv /lib/udev /usr/lib + ln -s /usr/lib/udev /lib/udev +fi + +%post -n %{udevpkgname} +%{fillup_and_insserv -Y boot.udev} +# add KERNEL name match to existing persistent net rules +sed -ri '/KERNEL/ ! { s/NAME="(eth|wlan|ath)([0-9]+)"/KERNEL=="\1*", NAME="\1\2"/}' \ + /etc/udev/rules.d/70-persistent-net.rules >/dev/null 2>&1 || : +# cleanup old stuff +rm -f /etc/sysconfig/udev +rm -f /etc/udev/rules.d/20-cdrom.rules +rm -f /etc/udev/rules.d/55-cdrom.rules +rm -f /etc/udev/rules.d/65-cdrom.rules +/bin/systemctl daemon-reload >/dev/null 2>&1 || : +# start daemon if we are not in a chroot +if test -f /proc/1/exe -a -d /proc/1/root; then + if test "$(stat -Lc '%%D-%%i' /)" = "$(stat -Lc '%%D-%%i' /proc/1/root)"; then + /bin/systemctl start systemd-udevd.service >/dev/null 2>&1 || : + /sbin/udevd --daemon >/dev/null 2>&1 || : + fi +fi + +[ -x /sbin/mkinitrd_setup ] && /sbin/mkinitrd_setup +if [ -e /var/lib/no_initrd_recreation_by_suspend ]; then + echo "Skipping recreation of existing initial ramdisks, due" + echo "to presence of /var/lib/no_initrd_recreation_by_suspend" +elif [ -x /sbin/mkinitrd ]; then + /sbin/mkinitrd +fi + +%postun -n %{udevpkgname} +%insserv_cleanup +/bin/systemctl daemon-reload >/dev/null 2>&1 || : + +[ -x /sbin/mkinitrd_setup ] && /sbin/mkinitrd_setup +if [ -e /var/lib/no_initrd_recreation_by_suspend ]; then + echo "Skipping recreation of existing initial ramdisks, due" + echo "to presence of /var/lib/no_initrd_recreation_by_suspend" +elif [ -x /sbin/mkinitrd ]; then + /sbin/mkinitrd +fi + +%post -n lib%{udevpkgname}%{udev_major} -p /sbin/ldconfig + +%postun -n lib%{udevpkgname}%{udev_major} -p /sbin/ldconfig + +%if ! 0%{?bootstrap} + +%post -n libgudev-1_0-0 -p /sbin/ldconfig + +%postun -n libgudev-1_0-0 -p /sbin/ldconfig +%endif + %clean rm -rf %{buildroot} %files %defattr(-,root,root) /bin/systemd -/bin/systemctl -/bin/systemd-notify -/bin/systemd-journalctl -/bin/systemd-ask-password -/bin/systemd-loginctl -/bin/systemd-tty-ask-password-agent -/bin/systemd-tmpfiles -/bin/systemd-machine-id-setup -/usr/bin/systemd-nspawn -/usr/bin/systemd-stdio-bridge +%{_bindir}/systemctl +%{_bindir}/systemd-delta +%{_bindir}/systemd-notify +%{_bindir}/systemd-journalctl +%{_bindir}/journalctl +%{_bindir}/systemd-ask-password +%{_bindir}/loginctl +%{_bindir}/systemd-loginctl +%{_bindir}/systemd-inhibit +%{_bindir}/systemd-tty-ask-password-agent +%{_bindir}/systemd-tmpfiles +%{_bindir}/systemd-machine-id-setup +%{_bindir}/systemd-nspawn +%{_bindir}/systemd-stdio-bridge +%{_bindir}/systemd-detect-virt %{_sbindir}/systemd-sysv-convert %{_libdir}/libsystemd-daemon.so.* %{_libdir}/libsystemd-login.so.* @@ -343,35 +546,74 @@ rm -rf %{buildroot} %{_bindir}/systemd-cgls %{_bindir}/systemd-cgtop %{_bindir}/systemd-cat -/lib/systemd/systemd-* -%dir /lib/systemd/system-shutdown -%dir /lib/systemd/system.preset -%dir /lib/systemd/user.preset +%dir %{_prefix}/lib/systemd +%dir %{_prefix}/lib/systemd/user +%dir %{_prefix}/lib/systemd/system +%exclude %{_prefix}/lib/systemd/system/systemd-udev*.* +%exclude %{_prefix}/lib/systemd/system/udev-root-symlink.service +%exclude %{_prefix}/lib/systemd/system/*.target.wants/systemd-udev*.* +%exclude %{_prefix}/lib/systemd/system/basic.target.wants/udev-root-symlink.service +%{_prefix}/lib/systemd/system/*.automount +%{_prefix}/lib/systemd/system/*.service +%{_prefix}/lib/systemd/system/*.target +%{_prefix}/lib/systemd/system/*.mount +%{_prefix}/lib/systemd/system/*.timer +%{_prefix}/lib/systemd/system/*.socket +%{_prefix}/lib/systemd/system/*.wants +%{_prefix}/lib/systemd/system/*.path +%{_prefix}/lib/systemd/user/*.target +%{_prefix}/lib/systemd/user/*.service +%exclude %{_prefix}/lib/systemd/systemd-udevd +%{_prefix}/lib/systemd/systemd-* +%{_prefix}/lib/systemd/systemd +%dir %{_prefix}/lib/systemd/system-shutdown +%dir %{_prefix}/lib/systemd/system-preset +%dir %{_prefix}/lib/systemd/user-preset +%dir %{_prefix}/lib/systemd/system-generators +%dir %{_prefix}/lib/systemd/user-generators +%dir %{_prefix}/lib/systemd/ntp-units.d/ +%dir %{_prefix}/lib/systemd/system-shutdown/ +%dir %{_prefix}/lib/systemd/system-sleep/ +%dir %{_prefix}/lib/systemd/system/default.target.wants +%dir %{_prefix}/lib/systemd/system/dbus.target.wants +%dir %{_prefix}/lib/systemd/system/syslog.target.wants +%if ! 0%{?bootstrap} +%{_prefix}/lib/systemd/system-generators/systemd-cryptsetup-generator +%endif +%{_prefix}/lib/systemd/system-generators/systemd-getty-generator +%{_prefix}/lib/systemd/system-generators/systemd-rc-local-generator +%{_prefix}/lib/systemd/system-generators/systemd-fstab-generator +%{_prefix}/lib/systemd/system-generators/systemd-system-update-generator /%{_lib}/security/pam_systemd.so + +%dir %{_libexecdir}/modules-load.d +%dir %{_sysconfdir}/modules-load.d + +%dir %{_libexecdir}/tmpfiles.d +%dir %{_sysconfdir}/tmpfiles.d +%{_libexecdir}/tmpfiles.d/*.conf + +%dir %{_libexecdir}/binfmt.d +%dir %{_sysconfdir}/binfmt.d + +%dir %{_libexecdir}/sysctl.d +%dir %{_sysconfdir}/sysctl.d + +%dir %{_sysconfdir}/systemd %dir %{_sysconfdir}/systemd/system %dir %{_sysconfdir}/systemd/user %dir %{_sysconfdir}/xdg/systemd %dir %{_sysconfdir}/xdg/systemd/user - -%dir /usr/lib/modules-load.d -%dir %{_sysconfdir}/modules-load.d -%dir /usr/lib/tmpfiles.d -%dir %{_sysconfdir}/tmpfiles.d -%dir /usr/lib/binfmt.d -%dir %{_sysconfdir}/binfmt.d -%dir /usr/lib/sysctl.d -%dir %{_sysconfdir}/sysctl.d -/usr/lib/tmpfiles.d/*.conf %config(noreplace) %{_sysconfdir}/systemd/system.conf -%config(noreplace) %{_sysconfdir}/systemd/systemd-logind.conf -%config(noreplace) %{_sysconfdir}/systemd/systemd-journald.conf +%config(noreplace) %{_sysconfdir}/systemd/logind.conf +%config(noreplace) %{_sysconfdir}/systemd/journald.conf %config(noreplace) %{_sysconfdir}/systemd/user.conf -%config(noreplace) %{_sysconfdir}/systemd/system.conf %config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.locale1.conf %config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.login1.conf %config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.systemd1.conf %config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.hostname1.conf %config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.timedate1.conf + %{_datadir}/dbus-1/interfaces/org.freedesktop.hostname1.xml %{_datadir}/dbus-1/interfaces/org.freedesktop.locale1.xml %{_datadir}/dbus-1/interfaces/org.freedesktop.systemd1.*.xml @@ -382,12 +624,16 @@ rm -rf %{buildroot} %{_datadir}/dbus-1/system-services/org.freedesktop.login1.service %{_datadir}/dbus-1/system-services/org.freedesktop.hostname1.service %{_datadir}/dbus-1/system-services/org.freedesktop.timedate1.service -%{_datadir}/polkit-1 -%{_datadir}/polkit-1/actions +%dir %{_datadir}/polkit-1 +%dir %{_datadir}/polkit-1/actions %{_datadir}/polkit-1/actions/org.freedesktop.systemd1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.hostname1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.locale1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.timedate1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.login1.policy %{_datadir}/systemd -# Packaged in gtk subpackage -%exclude %{_mandir}/man1/systemadm.1* + +%if ! 0%{?bootstrap} # Packaged in sysvinit subpackage %exclude %{_mandir}/man1/init.1* %exclude %{_mandir}/man8/halt.8* @@ -396,24 +642,27 @@ rm -rf %{buildroot} %exclude %{_mandir}/man8/poweroff.8* %exclude %{_mandir}/man8/telinit.8* %exclude %{_mandir}/man8/runlevel.8* +%exclude %{_mandir}/man*/*udev*.[0-9]* %{_mandir}/man1/*.1* %{_mandir}/man3/*.3* %{_mandir}/man5/*.5* %{_mandir}/man7/*.7* %{_mandir}/man8/*.8* +%endif %{_docdir}/systemd -/lib/udev/rules.d/*.rules -/lib/udev/numlock-on -%dir /lib/systemd -/lib/systemd/system -/lib/systemd/system-generators -/lib/systemd/systemd -%dir /usr/lib/systemd -/usr/lib/systemd/user -%dir %{_sysconfdir}/systemd +%{_prefix}/lib/udev/rules.d/70-uaccess.rules +%{_prefix}/lib/udev/rules.d/71-seat.rules +%{_prefix}/lib/udev/rules.d/73-seat-late.rules +%if ! 0%{?bootstrap} +%{_prefix}/lib/udev/rules.d/73-seat-numlock.rules +%endif +%{_prefix}/lib/udev/rules.d/99-systemd.rules +%if ! 0%{?bootstrap} +%{_prefix}/lib/udev/numlock-on +%endif %dir %{_sysconfdir}/bash_completion.d -/etc/bash_completion.d/systemd-bash-completion.sh -/etc/rpm/macros.systemd +%{_sysconfdir}/bash_completion.d/systemd-bash-completion.sh +%{_sysconfdir}/rpm/macros.systemd %dir /var/lib/systemd %dir /var/lib/systemd/sysv-convert %dir /var/lib/systemd/migrated @@ -431,6 +680,7 @@ rm -rf %{buildroot} %{_includedir}/systemd/sd-id128.h %{_includedir}/systemd/sd-journal.h %{_includedir}/systemd/sd-messages.h +%{_includedir}/systemd/sd-shutdown.h %{_datadir}/pkgconfig/systemd.pc %{_libdir}/pkgconfig/libsystemd-daemon.pc %{_libdir}/pkgconfig/libsystemd-login.pc @@ -446,6 +696,7 @@ rm -rf %{buildroot} /sbin/poweroff /sbin/telinit /sbin/runlevel +%if ! 0%{?bootstrap} %{_mandir}/man1/init.1* %{_mandir}/man8/halt.8* %{_mandir}/man8/reboot.8* @@ -453,8 +704,95 @@ rm -rf %{buildroot} %{_mandir}/man8/poweroff.8* %{_mandir}/man8/telinit.8* %{_mandir}/man8/runlevel.8* +%endif %files analyze %attr(0755,root,root) /usr/bin/systemd-analyze +%files -n %{udevpkgname} +%defattr(-,root,root) +/sbin/udevd +/sbin/udevadm +# keep for compatibility +%ghost /lib/udev +%{_bindir}/udevadm +%{_prefix}/lib/firmware +%dir %{_prefix}/lib/udev/ +%{_prefix}/lib/udev/accelerometer +%{_prefix}/lib/udev/ata_id +%{_prefix}/lib/udev/cdrom_id +%{_prefix}/lib/udev/collect +%{_prefix}/lib/udev/findkeyboards +%{_prefix}/lib/udev/keymap +%{_prefix}/lib/udev/mtd_probe +%{_prefix}/lib/udev/scsi_id +%{_prefix}/lib/udev/v4l_id +%{_prefix}/lib/udev/write_dev_root_rule +%dir %{_prefix}/lib/udev/keymaps +%{_prefix}/lib/udev/keymaps/* +%{_prefix}/lib/udev/keyboard-force-release.sh +%dir %{_prefix}/lib/udev/rules.d/ +%exclude %{_prefix}/lib/udev/rules.d/70-uaccess.rules +%exclude %{_prefix}/lib/udev/rules.d/71-seat.rules +%exclude %{_prefix}/lib/udev/rules.d/73-seat-late.rules +%exclude %{_prefix}/lib/udev/rules.d/73-seat-numlock.rules +%exclude %{_prefix}/lib/udev/rules.d/99-systemd.rules +%{_prefix}/lib/udev/rules.d/*.rules +%{_sysconfdir}/init.d/boot.udev +%dir %{_sysconfdir}/udev/ +%dir %{_sysconfdir}/udev/rules.d/ +%config(noreplace) %{_sysconfdir}/udev/udev.conf +%if ! 0%{?bootstrap} +%{_mandir}/man?/*udev*.[0-9]* +%endif +%dir %{_prefix}/lib/systemd/system +%{_prefix}/lib/systemd/systemd-udevd +%{_prefix}/lib/systemd/system/udev-root-symlink.service +%{_prefix}/lib/systemd/system/*udev*.service +%{_prefix}/lib/systemd/system/systemd-udevd*.socket +%dir %{_prefix}/lib/systemd/system/sysinit.target.wants +%{_prefix}/lib/systemd/system/sysinit.target.wants/systemd-udev*.service +%dir %{_prefix}/lib/systemd/system/sockets.target.wants +%{_prefix}/lib/systemd/system/sockets.target.wants/systemd-udev*.socket + +%files -n lib%{udevpkgname}%{udev_major} +%defattr(-,root,root) +%{_libdir}/libudev.so.* + +%files -n lib%{udevpkgname}-devel +%defattr(-,root,root) +%{_includedir}/libudev.h +%{_libdir}/libudev.so +%{_datadir}/pkgconfig/udev.pc +%{_libdir}/pkgconfig/libudev.pc +%if ! 0%{?bootstrap} +%dir %{_datadir}/gtk-doc +%dir %{_datadir}/gtk-doc/html +%dir %{_datadir}/gtk-doc/html/libudev +%{_datadir}/gtk-doc/html/libudev/* +%endif + +%if ! 0%{?bootstrap} +%files -n libgudev-1_0-0 +%defattr(-,root,root) +%{_libdir}/libgudev-1.0.so.* + +%files -n typelib-1_0-GUdev-1_0 +%defattr(-,root,root) +%{_libdir}/girepository-1.0/GUdev-1.0.typelib + +%files -n libgudev-1_0-devel +%defattr(-,root,root) +%dir %{_includedir}/gudev-1.0 +%dir %{_includedir}/gudev-1.0/gudev +%{_includedir}/gudev-1.0/gudev/*.h +%{_libdir}/libgudev-1.0.so +%{_libdir}/pkgconfig/gudev-1.0.pc +%dir %{_datadir}/gtk-doc +%dir %{_datadir}/gtk-doc/html +%dir %{_datadir}/gtk-doc/html/gudev +%{_datadir}/gtk-doc/html/gudev/* +%{_datadir}/gir-1.0/GUdev-1.0.gir +%endif + %changelog diff --git a/tty1.patch b/tty1.patch index 938066f..79145db 100644 --- a/tty1.patch +++ b/tty1.patch @@ -1,13 +1,13 @@ -Index: systemd-29/units/systemd-ask-password-wall.service.in +Index: systemd-189/units/systemd-ask-password-wall.service.in =================================================================== ---- systemd-29.orig/units/systemd-ask-password-wall.service.in -+++ systemd-29/units/systemd-ask-password-wall.service.in -@@ -7,7 +7,7 @@ - +--- systemd-189.orig/units/systemd-ask-password-wall.service.in ++++ systemd-189/units/systemd-ask-password-wall.service.in +@@ -8,7 +8,7 @@ [Unit] Description=Forward Password Requests to Wall + Documentation=man:systemd-ask-password-console.service(8) -After=systemd-user-sessions.service +After=systemd-user-sessions.service getty@tty1.service [Service] - ExecStartPre=-@rootbindir@/systemctl stop systemd-ask-password-console.path systemd-ask-password-console.service + ExecStartPre=-@SYSTEMCTL@ stop systemd-ask-password-console.path systemd-ask-password-console.service systemd-ask-password-plymouth.path systemd-ask-password-plymouth.service diff --git a/udev-root-symlink.systemd b/udev-root-symlink.systemd new file mode 100644 index 0000000..145a7fc --- /dev/null +++ b/udev-root-symlink.systemd @@ -0,0 +1,9 @@ +[Unit] +Description=create /dev/root symlink with dynamic rule +Before=udev.service +DefaultDependencies=no + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/lib/udev/write_dev_root_rule diff --git a/ulimit-support.patch b/ulimit-support.patch deleted file mode 100644 index ae6d355..0000000 --- a/ulimit-support.patch +++ /dev/null @@ -1,253 +0,0 @@ -From 03854532d39613723dc8b85c424737ecf2e46f74 Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Mon, 16 Apr 2012 18:54:45 +0200 -Subject: [PATCH 1/3] util: introduce memdup() - ---- - src/util.h | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) - -diff --git a/src/util.h b/src/util.h -index b1af6db..06c9933 100644 ---- a/src/util.h -+++ b/src/util.h -@@ -99,6 +99,8 @@ bool streq_ptr(const char *a, const char *b); - - #define new0(t, n) ((t*) calloc((n), sizeof(t))) - -+#define newdup(t, p, n) ((t*) memdup(p, sizeof(t)*(n)) -+ - #define malloc0(n) (calloc((n), 1)) - - static inline const char* yes_no(bool b) { --- -1.7.7 - - -From f60b5d436f502152415b08758737f200113ce4bc Mon Sep 17 00:00:00 2001 -From: Frederic Crozat -Date: Mon, 21 May 2012 16:53:18 +0200 -Subject: [PATCH 2/3] util: fix typo in newdup - -Conflicts: - - src/util.h ---- - src/util.h | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/src/util.h b/src/util.h -index 06c9933..41b4c9f 100644 ---- a/src/util.h -+++ b/src/util.h -@@ -99,7 +99,7 @@ bool streq_ptr(const char *a, const char *b); - - #define new0(t, n) ((t*) calloc((n), sizeof(t))) - --#define newdup(t, p, n) ((t*) memdup(p, sizeof(t)*(n)) -+#define newdup(t, p, n) ((t*) memdup(p, sizeof(t)*(n))) - - #define malloc0(n) (calloc((n), 1)) - --- -1.7.7 - - -From 8e7fa2b3e68b691c522cf2b60ed920452c146c2e Mon Sep 17 00:00:00 2001 -From: Frederic Crozat -Date: Wed, 27 Jun 2012 14:12:44 +0200 -Subject: [PATCH 3/3] main: allow system wide limits for services - ---- - man/systemd.conf.xml | 27 +++++++++++++++++++++++++++ - src/main.c | 22 ++++++++++++++++++++++ - src/manager.c | 22 ++++++++++++++++++++++ - src/manager.h | 3 +++ - src/service.c | 4 ++++ - 5 files changed, 78 insertions(+), 0 deletions(-) - -diff --git a/man/systemd.conf.xml b/man/systemd.conf.xml -index ba144da..ee461e3 100644 ---- a/man/systemd.conf.xml -+++ b/man/systemd.conf.xml -@@ -149,6 +149,33 @@ - controllers in separate - hierarchies. - -+ -+ -+ DefaultLimitCPU= -+ DefaultLimitFSIZE= -+ DefaultLimitDATA= -+ DefaultLimitSTACK= -+ DefaultLimitCORE= -+ DefaultLimitRSS= -+ DefaultLimitNOFILE= -+ DefaultLimitAS= -+ DefaultLimitNPROC= -+ DefaultLimitMEMLOCK= -+ DefaultLimitLOCKS= -+ DefaultLimitSIGPENDING= -+ DefaultLimitMSGQUEUE= -+ DefaultLimitNICE= -+ DefaultLimitRTPRIO= -+ DefaultLimitRTTIME= -+ These settings control -+ various default resource limits for units. See -+ setrlimit2 -+ for details. Use the string -+ infinity to -+ configure no limit on a specific -+ resource. They can be overriden in units files -+ using corresponding LimitXXXX parameter. -+ - - - -diff --git a/src/main.c b/src/main.c -index ed317b4..3f5f3d7 100644 ---- a/src/main.c -+++ b/src/main.c -@@ -79,6 +79,7 @@ static char **arg_default_controllers = NULL; - static char ***arg_join_controllers = NULL; - static ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL; - static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT; -+static struct rlimit *arg_default_rlimit[RLIMIT_NLIMITS] = {}; - - static FILE* serialization = NULL; - -@@ -659,6 +660,22 @@ static int parse_config_file(void) { - { "Manager", "DefaultStandardOutput", config_parse_output, 0, &arg_default_std_output }, - { "Manager", "DefaultStandardError", config_parse_output, 0, &arg_default_std_error }, - { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers }, -+ { "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU]}, -+ { "Manager", "DefaultLimitFSIZE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE]}, -+ { "Manager", "DefaultLimitDATA", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_DATA]}, -+ { "Manager", "DefaultLimitSTACK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_STACK]}, -+ { "Manager", "DefaultLimitCORE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CORE]}, -+ { "Manager", "DefaultLimitRSS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RSS]}, -+ { "Manager", "DefaultLimitNOFILE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NOFILE]}, -+ { "Manager", "DefaultLimitAS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_AS]}, -+ { "Manager", "DefaultLimitNPROC", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NPROC]}, -+ { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK]}, -+ { "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS]}, -+ { "Manager", "DefaultLimitSIGPENDING",config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING]}, -+ { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE]}, -+ { "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE]}, -+ { "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO]}, -+ { "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME]}, - { NULL, NULL, NULL, 0, NULL } - }; - -@@ -1401,6 +1418,8 @@ int main(int argc, char *argv[]) { - m->default_std_output = arg_default_std_output; - m->default_std_error = arg_default_std_error; - -+ manager_set_default_rlimits(m, arg_default_rlimit); -+ - if (dual_timestamp_is_set(&initrd_timestamp)) - m->initrd_timestamp = initrd_timestamp; - -@@ -1539,6 +1558,9 @@ finish: - if (m) - manager_free(m); - -+ for (j = 0; j < RLIMIT_NLIMITS; j++) -+ free (arg_default_rlimit[j]); -+ - free(arg_default_unit); - strv_free(arg_default_controllers); - free_join_controllers(); -diff --git a/src/manager.c b/src/manager.c -index 3e592b6..c6cd06c 100644 ---- a/src/manager.c -+++ b/src/manager.c -@@ -456,6 +456,7 @@ static void manager_clear_jobs_and_units(Manager *m) { - - void manager_free(Manager *m) { - UnitType c; -+ int i; - - assert(m); - -@@ -501,6 +502,9 @@ void manager_free(Manager *m) { - hashmap_free(m->cgroup_bondings); - set_free_free(m->unit_path_cache); - -+ for (i = 0; i < RLIMIT_NLIMITS; i++) -+ free(m->rlimit[i]); -+ - free(m); - } - -@@ -3137,6 +3141,24 @@ int manager_set_default_controllers(Manager *m, char **controllers) { - return 0; - } - -+int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) { -+ int i; -+ -+ assert(m); -+ -+ for (i = 0; i < RLIMIT_NLIMITS; i++) { -+ if (default_rlimit[i]) { -+ m->rlimit[i] = newdup(struct rlimit, default_rlimit[i], 1); -+ -+ if (!m->rlimit[i]) -+ return -ENOMEM; -+ } -+ } -+ -+ return 0; -+} -+ -+ - void manager_recheck_journal(Manager *m) { - Unit *u; - -diff --git a/src/manager.h b/src/manager.h -index a9d08f0..5f5de8e 100644 ---- a/src/manager.h -+++ b/src/manager.h -@@ -225,6 +225,8 @@ struct Manager { - - ExecOutput default_std_output, default_std_error; - -+ struct rlimit *rlimit[RLIMIT_NLIMITS]; -+ - /* non-zero if we are reloading or reexecuting, */ - int n_reloading; - -@@ -263,6 +265,7 @@ unsigned manager_dispatch_run_queue(Manager *m); - unsigned manager_dispatch_dbus_queue(Manager *m); - - int manager_set_default_controllers(Manager *m, char **controllers); -+int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit); - - int manager_loop(Manager *m); - -diff --git a/src/service.c b/src/service.c -index 8b5c0b0..892392d 100644 ---- a/src/service.c -+++ b/src/service.c -@@ -109,6 +109,7 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = { - - static void service_init(Unit *u) { - Service *s = SERVICE(u); -+ int i; - - assert(u); - assert(u->load_state == UNIT_STUB); -@@ -127,6 +128,9 @@ static void service_init(Unit *u) { - s->guess_main_pid = true; - - exec_context_init(&s->exec_context); -+ for (i = 0; i < RLIMIT_NLIMITS; i++) -+ if (UNIT(s)->manager->rlimit[i]) -+ s->exec_context.rlimit[i] = newdup(struct rlimit, UNIT(s)->manager->rlimit[i], 1); - - RATELIMIT_INIT(s->start_limit, 10*USEC_PER_SEC, 5); - --- -1.7.7 - diff --git a/use_localtime.patch b/use_localtime.patch deleted file mode 100644 index f078561..0000000 --- a/use_localtime.patch +++ /dev/null @@ -1,397 +0,0 @@ -unlike symlink_or_copy_atomic(), this function creates a symlink even if the -oldname and newname (from and to) are on differn't devices. (stat.st_dev) ---- - src/shared/util.c | 19 +++++++++++++++++-- - src/shared/util.h | 1 + - 2 files changed, 18 insertions(+), 2 deletions(-) - -Index: systemd-44/src/util.c -=================================================================== ---- systemd-44.orig/src/util.c -+++ systemd-44/src/util.c -@@ -5352,7 +5352,7 @@ finish: - return r; - } - --int symlink_or_copy_atomic(const char *from, const char *to) { -+static int symlink_atomic_raw(const char *from, const char *to, bool allow_copy) { - char *t, *x; - const char *fn; - size_t k; -@@ -5381,7 +5381,14 @@ int symlink_or_copy_atomic(const char *f - - *x = 0; - -- r = symlink_or_copy(from, t); -+ if (allow_copy) -+ r = symlink_or_copy(from, t); -+ else { -+ r = symlink(from, t); -+ if (r < 0) -+ r = -errno; -+ } -+ - if (r < 0) { - unlink(t); - free(t); -@@ -5482,6 +5489,14 @@ int audit_loginuid_from_pid(pid_t pid, u - return 0; - } - -+int symlink_or_copy_atomic(const char *from, const char *to) { -+ return symlink_atomic_raw(from, to, true); -+} -+ -+int symlink_atomic(const char *from, const char *to) { -+ return symlink_atomic_raw(from, to, false); -+} -+ - bool display_is_local(const char *display) { - assert(display); - -Index: systemd-44/src/util.h -=================================================================== ---- systemd-44.orig/src/util.h -+++ systemd-44/src/util.h -@@ -448,6 +448,7 @@ int vt_disallocate(const char *name); - int copy_file(const char *from, const char *to); - int symlink_or_copy(const char *from, const char *to); - int symlink_or_copy_atomic(const char *from, const char *to); -+int symlink_atomic(const char *from, const char *to); - - int fchmod_umask(int fd, mode_t mode); - -Index: systemd-44/Makefile.am -=================================================================== ---- systemd-44.orig/Makefile.am -+++ systemd-44/Makefile.am -@@ -690,7 +690,7 @@ MANPAGES = \ - man/systemd.conf.5 \ - man/tmpfiles.d.5 \ - man/hostname.5 \ -- man/timezone.5 \ -+ man/localtime.5 \ - man/machine-id.5 \ - man/locale.conf.5 \ - man/os-release.5 \ -Index: systemd-44/man/timezone.xml -=================================================================== ---- systemd-44.orig/man/timezone.xml -+++ /dev/null -@@ -1,90 +0,0 @@ -- -- -- -- -- -- -- -- -- /etc/timezone -- systemd -- -- -- -- Developer -- Lennart -- Poettering -- lennart@poettering.net -- -- -- -- -- -- timezone -- 5 -- -- -- -- timezone -- Local time zone configuration file -- -- -- -- /etc/timezone -- -- -- -- Description -- -- The /etc/timezone file -- configures the system-wide time zone of the local -- system that is used by applications for presentation -- to the user. It should contain a single -- newline-terminated line consisting of a time zone -- identifier such as -- Europe/Berlin. The file -- /etc/localtime corresponds with -- /etc/timezone and contains the -- binary time zone data for the time zone. These files -- should always be changed simultaneously and kept in -- sync. -- -- The time zone may be overridden for individual -- programs by using the TZ environment variable. See -- environ7. -- -- -- -- History -- -- The simple configuration file format of -- /etc/timezone originates from -- Debian GNU/Linux. -- -- -- -- See Also -- -- systemd1 -- -- -- -- -Index: systemd-44/man/localtime.xml -=================================================================== ---- /dev/null -+++ systemd-44/man/localtime.xml -@@ -0,0 +1,93 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ /etc/localtime -+ systemd -+ -+ -+ -+ Developer -+ Lennart -+ Poettering -+ lennart@poettering.net -+ -+ -+ Developer -+ Shawn -+ Landden -+ shawnlandden@gmail.com -+ -+ -+ -+ -+ -+ localtime -+ 5 -+ -+ -+ -+ localtime -+ Local time zone configuration file -+ -+ -+ -+ /etc/localtime -> /usr/share/zoneinfo/… -+ -+ -+ -+ Description -+ -+ The /etc/localtime file -+ configures the system-wide time zone of the local -+ system that is used by applications for presentation -+ to the user. It should be an absolute symbolic link -+ with a destination of /usr/share/zoneinfo/, -+ fallowed by a time zone identifier such as -+ Europe/Berlin or Etc/UTC. -+ The resulting link should point to the corresponding binary -+ tzfile5 -+ time zone data for the configured time zone. -+ -+ As the time zone identifier is extracted from the name of -+ the target of /etc/localtime this file may -+ not be a normal file or hardlink. -+ -+ The time zone may be overridden for individual -+ programs by using the TZ environment variable. See -+ environ7. -+ -+ -+ -+ See Also -+ -+ tzset3 -+ localtime3 -+ systemd1 -+ -+ -+ -+ -Index: systemd-44/src/timedate/timedated.c -=================================================================== ---- systemd-44.orig/src/timedate/timedated.c -+++ systemd-44/src/timedate/timedated.c -@@ -72,6 +72,9 @@ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.timedate1\0" - -+/* Must start and end with '/' */ -+#define ZONEINFO_PATH "/usr/share/zoneinfo/" -+ - const char timedate_interface[] _introspect_("timedate1") = INTERFACE; - - typedef struct TZ { -@@ -125,7 +128,7 @@ static bool valid_timezone(const char *n - if (slash) - return false; - -- t = strappend("/usr/share/zoneinfo/", name); -+ t = strappend(ZONEINFO_PATH, name); - if (!t) - return false; - -@@ -149,17 +152,17 @@ static void verify_timezone(void) { - if (!tz.zone) - return; - -- p = strappend("/usr/share/zoneinfo/", tz.zone); -+ p = strappend(ZONEINFO_PATH, tz.zone); - if (!p) { - log_error("Out of memory"); - return; - } - -- j = read_full_file("/etc/localtime", &a, &l); - k = read_full_file(p, &b, &q); -- - free(p); - -+ j = read_full_file("/etc/localtime", &a, &l); -+ - if (j < 0 || k < 0 || l != q || memcmp(a, b, l)) { - log_warning("/etc/localtime and /etc/timezone out of sync."); - free(tz.zone); -@@ -172,9 +175,36 @@ static void verify_timezone(void) { - - static int read_data(void) { - int r; -+ char *t = NULL; - - free_data(); - -+ r = readlink_malloc("/etc/localtime", &t); -+ if (r < 0) { -+ if (r == -EINVAL) -+ log_warning("/etc/localtime should be a symbolic link to a timezone data file in " ZONEINFO_PATH); -+ else -+ log_warning("Failed to get target of %s: %s", "/etc/localtime", strerror(-r)); -+ } else { -+ /* we only support the trivial relative link of (/etc/)..$ABSOLUTE */ -+ int rel_link_offset = startswith(t, "..") ? strlen("..") : 0; -+ -+ if (!startswith(t + rel_link_offset, ZONEINFO_PATH)) -+ log_warning("/etc/localtime should be a symbolic link to a timezone data file in " ZONEINFO_PATH); -+ else { -+ tz.zone = strdup(t + rel_link_offset + strlen(ZONEINFO_PATH)); -+ free(t); -+ if (!tz.zone) { -+ log_error("Out of memory"); -+ return -ENOMEM; -+ } -+ -+ goto have_timezone; -+ } -+ } -+ -+ free(t); -+ - r = read_one_line_file("/etc/timezone", &tz.zone); - if (r < 0) { - if (r != -ENOENT) -@@ -190,6 +220,7 @@ static int read_data(void) { - #endif - } - -+have_timezone: - if (isempty(tz.zone)) { - free(tz.zone); - tz.zone = NULL; -@@ -205,6 +236,7 @@ static int read_data(void) { - static int write_data_timezone(void) { - int r = 0; - char *p; -+ struct stat st; - - if (!tz.zone) { - if (unlink("/etc/timezone") < 0 && errno != ENOENT) -@@ -216,21 +248,24 @@ static int write_data_timezone(void) { - return r; - } - -- p = strappend("/usr/share/zoneinfo/", tz.zone); -+ p = strappend(ZONEINFO_PATH, tz.zone); - if (!p) { - log_error("Out of memory"); - return -ENOMEM; - } - -- r = symlink_or_copy_atomic(p, "/etc/localtime"); -+ r = symlink_atomic(p, "/etc/localtime"); -+ - free(p); - - if (r < 0) -- return r; -+ return -errno; - -- r = write_one_line_file_atomic("/etc/timezone", tz.zone); -- if (r < 0) -- return r; -+ if (stat("/etc/timezone", &st) == 0 && S_ISREG(st.st_mode)) { -+ r = write_one_line_file_atomic("/etc/timezone", tz.zone); -+ if (r < 0) -+ return r; -+ } - - return 0; - } diff --git a/write_dev_root_rule b/write_dev_root_rule new file mode 100644 index 0000000..9555789 --- /dev/null +++ b/write_dev_root_rule @@ -0,0 +1,13 @@ +#!/bin/sh + +eval $(/sbin/udevadm info --export --export-prefix=ROOT_ --device-id-of-file=/) + +[ "$ROOT_MAJOR" -gt 0 ] || return +mkdir -m 0755 -p /run/udev/rules.d >/dev/null 2>&1 +ln -sf /run/udev /dev/.udev 2>/dev/null || : + +echo "ACTION==\"add|change\", SUBSYSTEM==\"block\", \ +ENV{MAJOR}==\"$ROOT_MAJOR\", ENV{MINOR}==\"$ROOT_MINOR\", \ +SYMLINK+=\"root\"" > /run/udev/rules.d/10-root-symlink.rules + +exit 0