Skip to content

Instantly share code, notes, and snippets.

@rail
Last active November 28, 2018 17:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rail/51c1293a1c7c9a35e199a95d1232d97d to your computer and use it in GitHub Desktop.
Save rail/51c1293a1c7c9a35e199a95d1232d97d to your computer and use it in GitHub Desktop.
How to generate the diff:
git clone https://salsa.debian.org/systemd-team/systemd.git
cd systemd
git diff ubuntu/219-4ubuntu4..ubuntu/219-4ubuntu10
diff --git a/debian/changelog b/debian/changelog
index 420893cd9a..607453997f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,67 @@
+systemd (219-4ubuntu10) vivid; urgency=medium
+
+ * Cherry-pick a couple of upstream commits for adding transient state,
+ fixing a race where mounts become available before the device being
+ available.
+ * Refresh core-mount-ensure-that-we-parse-proc-self-mountinfo.patch for
+ the above cherry-pick.
+
+ -- Didier Roche <didrocks@ubuntu.com> Tue, 24 Mar 2015 16:02:25 +0100
+
+systemd (219-4ubuntu9) vivid; urgency=medium
+
+ * debian/control:
+ - systemd-sysv now conflicts with upstart-sysv, not upstart itself
+ which contains upstart binaries. (LP: #1422681)
+ * debian/test/*:
+ - re-enable upstart boot test and switch to upstart instead of
+ upstart-bin
+ * debian/systemd-sysv.postinst:
+ - fix syntax for better portability
+
+ -- Didier Roche <didrocks@ubuntu.com> Mon, 23 Mar 2015 10:21:34 +0100
+
+systemd (219-4ubuntu8) vivid; urgency=medium
+
+ * force ifup@ to run after systemd-tmpfiles-setup as ifupdown
+ operations require /run/network which is being created by tmpfiles
+ (LP: #1434020).
+
+ -- Scott Moser <smoser@ubuntu.com> Fri, 20 Mar 2015 09:48:23 -0400
+
+systemd (219-4ubuntu7) vivid; urgency=medium
+
+ * use systemd-ifupdown-helper script to handle ifup and ifdown
+ of auto or hotplug devices. This allows iscsi root volumes
+ to work again. (LP: #1432829)
+ * debian/control/tests: disable running of upstart tests until
+ upstart packaging bug 1422681 is resolved.
+
+ -- Scott Moser <smoser@ubuntu.com> Thu, 19 Mar 2015 11:43:14 -0400
+
+systemd (219-4ubuntu6) vivid; urgency=medium
+
+ * d/extra/units/ifup@.service, d/extra/tmpfiles.d/debian.conf:
+ use tmpfiles.d population of /run/network rather than
+ 'RuntimeDirectory' in the ifup service. This way files created
+ in initramfs are not deleted. (LP: #1432821)
+
+ -- Scott Moser <smoser@ubuntu.com> Tue, 17 Mar 2015 19:40:45 -0400
+
+systemd (219-4ubuntu5) vivid; urgency=medium
+
+ * Merge from experimental branch:
+ - /lib/lsb/init-functions.d/40-systemd: Don't ignore systemd unit
+ dependencies in "degraded" mode. (LP: #1429734)
+ - rules-ubuntu/71-power-switch-proliant.rules: Add support for HP ProLiant
+ m400 Server Cartridge soft powerdown on Linux 3.16. (LP: #1428811)
+ * systemctl: Don't forward telinit u to upstart. This works around upstart's
+ Restart() always reexec'ing /sbin/init on Restart(), even if that changes
+ to point to systemd during the upgrade. This avoids running systemd during
+ a dist-upgrade. (LP: #1430479)
+
+ -- Martin Pitt <martin.pitt@ubuntu.com> Wed, 11 Mar 2015 11:01:36 +0100
+
systemd (219-4ubuntu4) vivid; urgency=medium
* debian/udev.postinst: Only call update-initramfs if it actually exists.
@@ -25,6 +89,12 @@ systemd (219-5) UNRELEASED; urgency=medium
* Check for correct architecture identifiers for SuperH. (Closes: #779710)
* Fix tmpfiles.d to only apply the first match again (regression in 219).
(LP: #1428540)
+ * /lib/lsb/init-functions.d/40-systemd: Don't ignore systemd unit
+ dependencies in "degraded" mode. (LP: #1429734)
+
+ [ Craig Magina ]
+ * rules-ubuntu/71-power-switch-proliant.rules: Add support for HP ProLiant
+ m400 Server Cartridge soft powerdown on Linux 3.16. (LP: #1428811)
-- Martin Pitt <mpitt@debian.org> Tue, 03 Mar 2015 14:51:46 +0100
diff --git a/debian/control b/debian/control
index 11a6c9264c..8eab33e3fc 100644
--- a/debian/control
+++ b/debian/control
@@ -87,10 +87,12 @@ Multi-Arch: foreign
Section: admin
Priority: extra
Conflicts: sysvinit-core,
- upstart
+ upstart-sysv,
+ upstart (<< 1.13.2-0ubuntu10~),
Replaces: sysvinit (<< 2.88dsf-44~),
sysvinit-core,
- upstart
+ upstart-sysv,
+ upstart (<< 1.13.2-0ubuntu10~),
Pre-Depends: systemd
Depends: ${shlibs:Depends},
${misc:Depends},
diff --git a/debian/extra/init-functions.d/40-systemd b/debian/extra/init-functions.d/40-systemd
index faa87b3674..53f5058d48 100644
--- a/debian/extra/init-functions.d/40-systemd
+++ b/debian/extra/init-functions.d/40-systemd
@@ -64,7 +64,7 @@ systemctl_redirect () {
# the synchronous wait plus systemd's normal behaviour of
# transactionally processing all dependencies first easily
# causes dependency loops
- if ! systemctl --quiet is-system-running; then
+ if ! OUT=$(systemctl is-system-running 2>/dev/null) && [ "$OUT" != "degraded" ]; then
sctl_args="--job-mode=ignore-dependencies"
fi
diff --git a/debian/extra/rules-ubuntu/71-power-switch-proliant.rules b/debian/extra/rules-ubuntu/71-power-switch-proliant.rules
index 816924e082..022baebf74 100644
--- a/debian/extra/rules-ubuntu/71-power-switch-proliant.rules
+++ b/debian/extra/rules-ubuntu/71-power-switch-proliant.rules
@@ -1,2 +1,2 @@
-ACTION!="remove", SUBSYSTEM=="input", KERNEL=="event*", SUBSYSTEMS=="platform", KERNELS=="gpio_keys.6", PROGRAM="/bin/cat /proc/device-tree/model", RESULT=="HP ProLiant m400 Server Cartridge", TAG+="power-switch"
+ACTION!="remove", SUBSYSTEM=="input", KERNEL=="event*", SUBSYSTEMS=="platform", KERNELS=="gpio_keys.6|soc:gpio_keys", PROGRAM="/bin/cat /proc/device-tree/model", RESULT=="HP ProLiant m400 Server Cartridge", TAG+="power-switch"
ACTION!="remove", SUBSYSTEM=="input", KERNEL=="event*", SUBSYSTEMS=="platform", KERNELS=="gpio_keys.12", ATTRS{keys}=="116", PROGRAM="/bin/cat /proc/device-tree/model", RESULT=="HP ProLiant m800 Server Cartridge", TAG+="power-switch"
diff --git a/debian/extra/systemd-ifupdown-helper b/debian/extra/systemd-ifupdown-helper
new file mode 100755
index 0000000000..ee21958b37
--- /dev/null
+++ b/debian/extra/systemd-ifupdown-helper
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+CR="
+"
+IFSTATE_FILE="/run/network/ifstate"
+
+do_ifup() {
+ local ifname="$1"
+ ifquery --list --allow=hotplug | grep -q "^$ifname$" ||
+ ifquery --list --allow=auto | grep -q "^$ifname$" ||
+ return 0
+ ifup "$ifname"
+}
+
+is_persistent_initramfs_iface() {
+ # open-iscsi.interface is written by open-iscsi when booting from
+ # an iscsi volume, when you can't bounce the interface that the root
+ # device is on. The other file, is meant as a more generic location
+ # for an initramfs job to write "persistent" network devices.
+ grep -qs "^$1$" /run/initramfs/open-iscsi.interface \
+ "/run/network/initramfs-persistent-iface"
+}
+
+adjust_resolvconf() {
+ local ifname="$1" data=""
+ command -v resolvconf >/dev/null 2>&1 || return 0
+
+ # /run/net-eth0.conf is written by 'ipconfig' in klibc
+ [ -f "/run/net-$ifname.conf" ] || return 0
+ . "/run/net-$ifname.conf"
+ data=""
+ [ -n "$DOMAINSEARCH" ] && data="$data${CR}domainsearch $DOMAINSEARCH"
+ for ns in "$IPV4DNS0" "$IPV4DNS1"; do
+ [ -n "$ns" -a "$ns" != "0.0.0.0" ] && data="$data${CR}nameserver $ns"
+ done
+ data=${data#${CR}}
+ [ -z "$data" ] && return 0
+ echo "$data" | resolvconf -a "$ifname.initramfs"
+}
+
+do_ifup_persistent() {
+ local ifname="$1"
+ # already done
+ grep -qs "$ifname=" $IFSTATE_FILE && return 0
+
+ adjust_resolvconf "$ifname" || return
+ # write to the ifstate file, so ifupdown thinks its up.
+ echo "$ifname=$ifname" >> $IFSTATE_FILE
+}
+
+start_main() {
+ local ifname=$1
+ shift
+ if is_persistent_initramfs_iface "$ifname"; then
+ do_ifup_persistent "$ifname" "$@" || return
+ fi
+ do_ifup "$ifname" "$@"
+}
+
+stop_main() {
+ local ifname="$1" fail=0
+ shift
+ if ! is_persistent_initramfs_iface "$ifname"; then
+ /sbin/ifdown "$ifname"
+ return
+ fi
+ # we only pretend to bring the interface down
+ # if interface is not present, we're already done
+ grep -qs "^$ifname=" $IFSTATE_FILE || return 0
+
+ sed -i "/^$ifname=/d" "$IFSTATE_FILE" || fail=1
+ resolvconf -d "$ifname.initramfs" || fail=1
+ return $fail
+}
+
+mode="$1"
+shift;
+case "$mode" in
+ start) start_main "$@";;
+ stop) stop_main "$@";;
+ *) echo "$0: unknown mode '$mode'" 1>&2; exit 1;;
+esac
+exit
diff --git a/debian/extra/tmpfiles.d/debian.conf b/debian/extra/tmpfiles.d/debian.conf
index 83f75864ea..02612dc42f 100644
--- a/debian/extra/tmpfiles.d/debian.conf
+++ b/debian/extra/tmpfiles.d/debian.conf
@@ -11,3 +11,4 @@
L /run/initctl - - - - /run/systemd/initctl/fifo
L /run/shm - - - - /dev/shm
d /run/sendsigs.omit.d 0755 root root -
+d /run/network 0755 root root -
diff --git a/debian/extra/units/ifup@.service b/debian/extra/units/ifup@.service
index d6dd1b0c48..8b2ec75be7 100644
--- a/debian/extra/units/ifup@.service
+++ b/debian/extra/units/ifup@.service
@@ -1,16 +1,12 @@
[Unit]
Description=ifup for %I
-After=local-fs.target network-pre.target
+After=local-fs.target network-pre.target systemd-tmpfiles-setup.service
Before=network.target
BindsTo=sys-subsystem-net-devices-%i.device
DefaultDependencies=no
[Service]
Type=oneshot
-RuntimeDirectory=network
-ExecStart=/sbin/ifup --allow=hotplug %I
-ExecStartPost=/sbin/ifup --allow=auto %I
-# only fail if ifupdown knows about the iface AND it's not up
-ExecStartPost=/bin/sh -c 'if ifquery %I >/dev/null; then ifquery --state %I >/dev/null; fi'
-ExecStop=/sbin/ifdown %I
+ExecStart=/lib/systemd/systemd-ifupdown-helper start %I
+ExecStop=/lib/systemd/systemd-ifupdown-helper stop %I
RemainAfterExit=true
diff --git a/debian/patches/Add_tentative_state.patch b/debian/patches/Add_tentative_state.patch
new file mode 100644
index 0000000000..838c543bf8
--- /dev/null
+++ b/debian/patches/Add_tentative_state.patch
@@ -0,0 +1,900 @@
+commit 628c89cc68ab96fce2de7ebba5933725d147aecc
+Author: Lennart Poettering <lennart@poettering.net>
+Date: Fri Feb 27 21:55:08 2015 +0100
+
+ core: rework device state logic
+
+ This change introduces a new state "tentative" for device units. Device
+ units are considered "plugged" when udev announced them, "dead" when
+ they are not available in the kernel, and "tentative" when they are
+ referenced in /proc/self/mountinfo or /proc/swaps but not (yet)
+ announced via udev.
+
+ This should fix a race when device nodes (like loop devices) are created
+ and immediately mounted. Previously, systemd might end up seeing the
+ mount unit before the device, and would thus pull down the mount because
+ its BindTo dependency on the device would not be fulfilled.
+
+Index: systemd-219/src/core/device.c
+===================================================================
+--- systemd-219.orig/src/core/device.c
++++ systemd-219/src/core/device.c
+@@ -36,7 +36,8 @@
+
+ static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
+ [DEVICE_DEAD] = UNIT_INACTIVE,
+- [DEVICE_PLUGGED] = UNIT_ACTIVE
++ [DEVICE_TENTATIVE] = UNIT_ACTIVATING,
++ [DEVICE_PLUGGED] = UNIT_ACTIVE,
+ };
+
+ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
+@@ -65,6 +66,41 @@ static void device_unset_sysfs(Device *d
+ d->sysfs = NULL;
+ }
+
++static int device_set_sysfs(Device *d, const char *sysfs) {
++ Device *first;
++ char *copy;
++ int r;
++
++ assert(d);
++
++ if (streq_ptr(d->sysfs, sysfs))
++ return 0;
++
++ r = hashmap_ensure_allocated(&UNIT(d)->manager->devices_by_sysfs, &string_hash_ops);
++ if (r < 0)
++ return r;
++
++ copy = strdup(sysfs);
++ if (!copy)
++ return -ENOMEM;
++
++ device_unset_sysfs(d);
++
++ first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, sysfs);
++ LIST_PREPEND(same_sysfs, first, d);
++
++ r = hashmap_replace(UNIT(d)->manager->devices_by_sysfs, copy, first);
++ if (r < 0) {
++ LIST_REMOVE(same_sysfs, first, d);
++ free(copy);
++ return r;
++ }
++
++ d->sysfs = copy;
++
++ return 0;
++}
++
+ static void device_init(Unit *u) {
+ Device *d = DEVICE(u);
+
+@@ -112,8 +148,13 @@ static int device_coldplug(Unit *u) {
+ assert(d);
+ assert(d->state == DEVICE_DEAD);
+
+- if (d->sysfs)
++ if (d->found & DEVICE_FOUND_UDEV)
++ /* If udev says the device is around, it's around */
+ device_set_state(d, DEVICE_PLUGGED);
++ else if (d->found != DEVICE_NOT_FOUND)
++ /* If a device is found in /proc/self/mountinfo or
++ * /proc/swaps, it's "tentatively" around. */
++ device_set_state(d, DEVICE_TENTATIVE);
+
+ return 0;
+ }
+@@ -142,49 +183,9 @@ _pure_ static const char *device_sub_sta
+ return device_state_to_string(DEVICE(u)->state);
+ }
+
+-static int device_add_escaped_name(Unit *u, const char *dn) {
+- _cleanup_free_ char *e = NULL;
+- int r;
+-
+- assert(u);
+- assert(dn);
+- assert(dn[0] == '/');
+-
+- e = unit_name_from_path(dn, ".device");
+- if (!e)
+- return -ENOMEM;
+-
+- r = unit_add_name(u, e);
+- if (r < 0 && r != -EEXIST)
+- return r;
+-
+- return 0;
+-}
+-
+-static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) {
+- _cleanup_free_ char *e = NULL;
+- Unit *u;
+-
+- assert(m);
+- assert(dn);
+- assert(dn[0] == '/');
+- assert(_u);
+-
+- e = unit_name_from_path(dn, ".device");
+- if (!e)
+- return -ENOMEM;
+-
+- u = manager_get_unit(m, e);
+- if (u) {
+- *_u = u;
+- return 1;
+- }
+-
+- return 0;
+-}
+-
+-static int device_make_description(Unit *u, struct udev_device *dev, const char *path) {
++static int device_update_description(Unit *u, struct udev_device *dev, const char *path) {
+ const char *model;
++ int r;
+
+ assert(u);
+ assert(dev);
+@@ -209,13 +210,16 @@ static int device_make_description(Unit
+
+ j = strjoin(model, " ", label, NULL);
+ if (j)
+- return unit_set_description(u, j);
+- }
++ r = unit_set_description(u, j);
++ } else
++ r = unit_set_description(u, model);
++ } else
++ r = unit_set_description(u, path);
+
+- return unit_set_description(u, model);
+- }
++ if (r < 0)
++ log_unit_error_errno(u->id, r, "Failed to set device description: %m");
+
+- return unit_set_description(u, path);
++ return r;
+ }
+
+ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
+@@ -242,20 +246,20 @@ static int device_add_udev_wants(Unit *u
+
+ n = unit_name_mangle(e, MANGLE_NOGLOB);
+ if (!n)
+- return -ENOMEM;
++ return log_oom();
+
+ r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true);
+ if (r < 0)
+- return r;
++ return log_unit_error_errno(u->id, r, "Failed to add wants dependency: %m");
+ }
+ if (!isempty(state))
+- log_unit_warning(u->id, "Property %s on %s has trailing garbage, ignoring.",
+- property, strna(udev_device_get_syspath(dev)));
++ log_unit_warning(u->id, "Property %s on %s has trailing garbage, ignoring.", property, strna(udev_device_get_syspath(dev)));
+
+ return 0;
+ }
+
+-static int device_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
++static int device_setup_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
++ _cleanup_free_ char *e = NULL;
+ const char *sysfs;
+ Unit *u = NULL;
+ bool delete;
+@@ -269,12 +273,18 @@ static int device_update_unit(Manager *m
+ if (!sysfs)
+ return 0;
+
+- r = device_find_escape_name(m, path, &u);
+- if (r < 0)
+- return r;
++ e = unit_name_from_path(path, ".device");
++ if (!e)
++ return log_oom();
++
++ u = manager_get_unit(m, e);
+
+- if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
++ if (u &&
++ DEVICE(u)->sysfs &&
++ !path_equal(DEVICE(u)->sysfs, sysfs)) {
++ log_unit_error(u->id, "Device %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs);
+ return -EEXIST;
++ }
+
+ if (!u) {
+ delete = true;
+@@ -283,7 +293,7 @@ static int device_update_unit(Manager *m
+ if (!u)
+ return log_oom();
+
+- r = device_add_escaped_name(u, path);
++ r = unit_add_name(u, e);
+ if (r < 0)
+ goto fail;
+
+@@ -295,37 +305,16 @@ static int device_update_unit(Manager *m
+ * actually been seen yet ->sysfs will not be
+ * initialized. Hence initialize it if necessary. */
+
+- if (!DEVICE(u)->sysfs) {
+- Device *first;
+-
+- DEVICE(u)->sysfs = strdup(sysfs);
+- if (!DEVICE(u)->sysfs) {
+- r = -ENOMEM;
+- goto fail;
+- }
+-
+- r = hashmap_ensure_allocated(&m->devices_by_sysfs, &string_hash_ops);
+- if (r < 0)
+- goto fail;
+-
+- first = hashmap_get(m->devices_by_sysfs, sysfs);
+- LIST_PREPEND(same_sysfs, first, DEVICE(u));
+-
+- r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first);
+- if (r < 0)
+- goto fail;
+- }
+-
+- device_make_description(u, dev, path);
++ r = device_set_sysfs(DEVICE(u), sysfs);
++ if (r < 0)
++ goto fail;
+
+- if (main) {
+- /* The additional systemd udev properties we only
+- * interpret for the main object */
++ (void) device_update_description(u, dev, path);
+
+- r = device_add_udev_wants(u, dev);
+- if (r < 0)
+- goto fail;
+- }
++ /* The additional systemd udev properties we only interpret
++ * for the main object */
++ if (main)
++ (void) device_add_udev_wants(u, dev);
+
+ /* Note that this won't dispatch the load queue, the caller
+ * has to do that if needed and appropriate */
+@@ -334,7 +323,7 @@ static int device_update_unit(Manager *m
+ return 0;
+
+ fail:
+- log_warning_errno(r, "Failed to load device unit: %m");
++ log_unit_warning_errno(u->id, r, "Failed to set up device unit: %m");
+
+ if (delete && u)
+ unit_free(u);
+@@ -342,7 +331,7 @@ fail:
+ return r;
+ }
+
+-static int device_process_new_device(Manager *m, struct udev_device *dev) {
++static int device_process_new(Manager *m, struct udev_device *dev) {
+ const char *sysfs, *dn, *alias;
+ struct udev_list_entry *item = NULL, *first = NULL;
+ int r;
+@@ -354,14 +343,14 @@ static int device_process_new_device(Man
+ return 0;
+
+ /* Add the main unit named after the sysfs path */
+- r = device_update_unit(m, dev, sysfs, true);
++ r = device_setup_unit(m, dev, sysfs, true);
+ if (r < 0)
+ return r;
+
+ /* Add an additional unit for the device node */
+ dn = udev_device_get_devnode(dev);
+ if (dn)
+- device_update_unit(m, dev, dn, false);
++ (void) device_setup_unit(m, dev, dn, false);
+
+ /* Add additional units for all symlinks */
+ first = udev_device_get_devlinks_list_entry(dev);
+@@ -388,7 +377,7 @@ static int device_process_new_device(Man
+ st.st_rdev != udev_device_get_devnum(dev))
+ continue;
+
+- device_update_unit(m, dev, p, false);
++ (void) device_setup_unit(m, dev, p, false);
+ }
+
+ /* Add additional units for all explicitly configured
+@@ -405,7 +394,7 @@ static int device_process_new_device(Man
+ e[l] = 0;
+
+ if (path_is_absolute(e))
+- device_update_unit(m, dev, e, false);
++ (void) device_setup_unit(m, dev, e, false);
+ else
+ log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, e);
+ }
+@@ -416,39 +405,62 @@ static int device_process_new_device(Man
+ return 0;
+ }
+
+-static void device_set_path_plugged(Manager *m, struct udev_device *dev) {
+- const char *sysfs;
++static void device_update_found_one(Device *d, bool add, DeviceFound found, bool now) {
++ DeviceFound n;
++
++ assert(d);
++
++ n = add ? (d->found | found) : (d->found & ~found);
++ if (n == d->found)
++ return;
++
++ d->found = n;
++
++ if (now) {
++ if (d->found & DEVICE_FOUND_UDEV)
++ device_set_state(d, DEVICE_PLUGGED);
++ else if (d->found != DEVICE_NOT_FOUND)
++ device_set_state(d, DEVICE_TENTATIVE);
++ else
++ device_set_state(d, DEVICE_DEAD);
++ }
++}
++
++static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add, DeviceFound found, bool now) {
+ Device *d, *l;
+
+ assert(m);
+- assert(dev);
++ assert(sysfs);
+
+- sysfs = udev_device_get_syspath(dev);
+- if (!sysfs)
+- return;
++ if (found == DEVICE_NOT_FOUND)
++ return 0;
+
+ l = hashmap_get(m->devices_by_sysfs, sysfs);
+ LIST_FOREACH(same_sysfs, d, l)
+- device_set_state(d, DEVICE_PLUGGED);
++ device_update_found_one(d, add, found, now);
++
++ return 0;
+ }
+
+-static int device_process_removed_device(Manager *m, struct udev_device *dev) {
+- const char *sysfs;
+- Device *d;
++static int device_update_found_by_name(Manager *m, const char *path, bool add, DeviceFound found, bool now) {
++ _cleanup_free_ char *e = NULL;
++ Unit *u;
+
+ assert(m);
+- assert(dev);
++ assert(path);
+
+- sysfs = udev_device_get_syspath(dev);
+- if (!sysfs)
+- return -ENOMEM;
++ if (found == DEVICE_NOT_FOUND)
++ return 0;
+
+- /* Remove all units of this sysfs path */
+- while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) {
+- device_unset_sysfs(d);
+- device_set_state(d, DEVICE_DEAD);
+- }
++ e = unit_name_from_path(path, ".device");
++ if (!e)
++ return log_oom();
+
++ u = manager_get_unit(m, e);
++ if (!u)
++ return 0;
++
++ device_update_found_one(DEVICE(u), add, found, now);
+ return 0;
+ }
+
+@@ -464,22 +476,6 @@ static bool device_is_ready(struct udev_
+ return parse_boolean(ready) != 0;
+ }
+
+-static int device_process_new_path(Manager *m, const char *path) {
+- _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
+-
+- assert(m);
+- assert(path);
+-
+- dev = udev_device_new_from_syspath(m->udev, path);
+- if (!dev)
+- return log_oom();
+-
+- if (!device_is_ready(dev))
+- return 0;
+-
+- return device_process_new_device(m, dev);
+-}
+-
+ static Unit *device_following(Unit *u) {
+ Device *d = DEVICE(u);
+ Device *other, *first = NULL;
+@@ -606,12 +602,31 @@ static int device_enumerate(Manager *m)
+ goto fail;
+
+ first = udev_enumerate_get_list_entry(e);
+- udev_list_entry_foreach(item, first)
+- device_process_new_path(m, udev_list_entry_get_name(item));
++ udev_list_entry_foreach(item, first) {
++ _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
++ const char *sysfs;
++
++ sysfs = udev_list_entry_get_name(item);
++
++ dev = udev_device_new_from_syspath(m->udev, sysfs);
++ if (!dev) {
++ log_oom();
++ continue;
++ }
++
++ if (!device_is_ready(dev))
++ continue;
++
++ (void) device_process_new(m, dev);
++
++ device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, false);
++ }
+
+ return 0;
+
+ fail:
++ log_error_errno(r, "Failed to enumerate devices: %m");
++
+ device_shutdown(m);
+ return r;
+ }
+@@ -619,7 +634,7 @@ fail:
+ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+ _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
+ Manager *m = userdata;
+- const char *action;
++ const char *action, *sysfs;
+ int r;
+
+ assert(m);
+@@ -641,33 +656,47 @@ static int device_dispatch_io(sd_event_s
+ if (!dev)
+ return 0;
+
++ sysfs = udev_device_get_syspath(dev);
++ if (!sysfs) {
++ log_error("Failed to get udev sys path.");
++ return 0;
++ }
++
+ action = udev_device_get_action(dev);
+ if (!action) {
+ log_error("Failed to get udev action string.");
+ return 0;
+ }
+
+- if (streq(action, "remove") || !device_is_ready(dev)) {
+- r = device_process_removed_device(m, dev);
+- if (r < 0)
+- log_error_errno(r, "Failed to process device remove event: %m");
+-
+- r = swap_process_removed_device(m, dev);
++ if (streq(action, "remove")) {
++ r = swap_process_device_remove(m, dev);
+ if (r < 0)
+ log_error_errno(r, "Failed to process swap device remove event: %m");
+
+- } else {
+- r = device_process_new_device(m, dev);
+- if (r < 0)
+- log_error_errno(r, "Failed to process device new event: %m");
++ /* If we get notified that a device was removed by
++ * udev, then it's completely gone, hence unset all
++ * found bits */
++ device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP, true);
+
+- r = swap_process_new_device(m, dev);
++ } else if (device_is_ready(dev)) {
++
++ (void) device_process_new(m, dev);
++
++ r = swap_process_device_new(m, dev);
+ if (r < 0)
+ log_error_errno(r, "Failed to process swap device new event: %m");
+
+ manager_dispatch_load_queue(m);
+
+- device_set_path_plugged(m, dev);
++ /* The device is found now, set the udev found bit */
++ device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, true);
++
++ } else {
++ /* The device is nominally around, but not ready for
++ * us. Hence unset the udev bit, but leave the rest
++ * around. */
++
++ device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV, true);
+ }
+
+ return 0;
+@@ -686,9 +715,58 @@ static bool device_supported(Manager *m)
+ return read_only <= 0;
+ }
+
++int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now) {
++ _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
++ struct stat st;
++
++ assert(m);
++ assert(node);
++
++ /* This is called whenever we find a device referenced in
++ * /proc/swaps or /proc/self/mounts. Such a device might be
++ * mounted/enabled at a time where udev has not finished
++ * probing it yet, and we thus haven't learned about it
++ * yet. In this case we will set the device unit to
++ * "tentative" state. */
++
++ if (add) {
++ if (!path_startswith(node, "/dev"))
++ return 0;
++
++ if (stat(node, &st) < 0) {
++ if (errno == ENOENT)
++ return 0;
++
++ return log_error_errno(errno, "Failed to stat device node file %s: %m", node);
++ }
++
++ if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
++ return 0;
++
++ dev = udev_device_new_from_devnum(m->udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev);
++ if (!dev) {
++ if (errno == ENOENT)
++ return 0;
++
++ return log_oom();
++ }
++
++ /* If the device is known in the kernel and newly
++ * appeared, then we'll create a device unit for it,
++ * under the name referenced in /proc/swaps or
++ * /proc/self/mountinfo. */
++
++ (void) device_setup_unit(m, dev, node, false);
++ }
++
++ /* Update the device unit's state, should it exist */
++ return device_update_found_by_name(m, node, add, found, now);
++}
++
+ static const char* const device_state_table[_DEVICE_STATE_MAX] = {
+ [DEVICE_DEAD] = "dead",
+- [DEVICE_PLUGGED] = "plugged"
++ [DEVICE_TENTATIVE] = "tentative",
++ [DEVICE_PLUGGED] = "plugged",
+ };
+
+ DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
+Index: systemd-219/src/core/device.h
+===================================================================
+--- systemd-219.orig/src/core/device.h
++++ systemd-219/src/core/device.h
+@@ -29,20 +29,28 @@ typedef struct Device Device;
+ * simplifies the state engine greatly */
+ typedef enum DeviceState {
+ DEVICE_DEAD,
+- DEVICE_PLUGGED,
++ DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */
++ DEVICE_PLUGGED, /* announced by udev */
+ _DEVICE_STATE_MAX,
+ _DEVICE_STATE_INVALID = -1
+ } DeviceState;
+
++typedef enum DeviceFound {
++ DEVICE_NOT_FOUND = 0,
++ DEVICE_FOUND_UDEV = 1,
++ DEVICE_FOUND_MOUNT = 2,
++ DEVICE_FOUND_SWAP = 4,
++} DeviceFound;
++
+ struct Device {
+ Unit meta;
+
+ char *sysfs;
++ DeviceFound found;
+
+ /* In order to be able to distinguish dependencies on
+ different device nodes we might end up creating multiple
+ devices for the same sysfs path. We chain them up here. */
+-
+ LIST_FIELDS(struct Device, same_sysfs);
+
+ DeviceState state;
+@@ -52,3 +60,5 @@ extern const UnitVTable device_vtable;
+
+ const char* device_state_to_string(DeviceState i) _const_;
+ DeviceState device_state_from_string(const char *s) _pure_;
++
++int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now);
+Index: systemd-219/src/core/mount.c
+===================================================================
+--- systemd-219.orig/src/core/mount.c
++++ systemd-219/src/core/mount.c
+@@ -1391,7 +1391,7 @@ static int mount_dispatch_timer(sd_event
+ return 0;
+ }
+
+-static int mount_add_one(
++static int mount_setup_unit(
+ Manager *m,
+ const char *what,
+ const char *where,
+@@ -1434,7 +1434,7 @@ static int mount_add_one(
+
+ u = unit_new(m, sizeof(Mount));
+ if (!u)
+- return -ENOMEM;
++ return log_oom();
+
+ r = unit_add_name(u, e);
+ if (r < 0)
+@@ -1547,6 +1547,8 @@ static int mount_add_one(
+ return 0;
+
+ fail:
++ log_warning_errno(r, "Failed to set up mount unit: %m");
++
+ if (delete && u)
+ unit_free(u);
+
+@@ -1554,33 +1556,36 @@ fail:
+ }
+
+ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
+- _cleanup_(mnt_free_tablep) struct libmnt_table *tb = NULL;
+- _cleanup_(mnt_free_iterp) struct libmnt_iter *itr = NULL;
+- struct libmnt_fs *fs;
++ _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL;
++ _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL;
+ int r = 0;
+
+ assert(m);
+
+- tb = mnt_new_table();
+- itr = mnt_new_iter(MNT_ITER_FORWARD);
+- if (!tb || !itr)
++ t = mnt_new_table();
++ if (!t)
++ return log_oom();
++
++ i = mnt_new_iter(MNT_ITER_FORWARD);
++ if (!i)
+ return log_oom();
+
+- r = mnt_table_parse_mtab(tb, NULL);
++ r = mnt_table_parse_mtab(t, NULL);
+ if (r < 0)
+- return r;
++ return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m");
+
+ r = 0;
+ for (;;) {
+ const char *device, *path, *options, *fstype;
+ _cleanup_free_ const char *d = NULL, *p = NULL;
++ struct libmnt_fs *fs;
+ int k;
+
+- k = mnt_table_next_fs(tb, itr, &fs);
++ k = mnt_table_next_fs(t, i, &fs);
+ if (k == 1)
+ break;
+- else if (k < 0)
+- return log_error_errno(k, "Failed to get next entry from /etc/fstab: %m");
++ if (k < 0)
++ return log_error_errno(k, "Failed to get next entry from /proc/self/mountinfo: %m");
+
+ device = mnt_fs_get_source(fs);
+ path = mnt_fs_get_target(fs);
+@@ -1588,11 +1593,16 @@ static int mount_load_proc_self_mountinf
+ fstype = mnt_fs_get_fstype(fs);
+
+ d = cunescape(device);
++ if (!d)
++ return log_oom();
++
+ p = cunescape(path);
+- if (!d || !p)
++ if (!p)
+ return log_oom();
+
+- k = mount_add_one(m, d, p, options, fstype, set_flags);
++ (void) device_found_node(m, d, true, DEVICE_FOUND_MOUNT, set_flags);
++
++ k = mount_setup_unit(m, d, p, options, fstype, set_flags);
+ if (r == 0 && k < 0)
+ r = k;
+ }
+@@ -1736,8 +1746,6 @@ static int mount_dispatch_io(sd_event_so
+
+ r = mount_load_proc_self_mountinfo(m, true);
+ if (r < 0) {
+- log_error_errno(r, "Failed to reread /proc/self/mountinfo: %m");
+-
+ /* Reset flags, just in case, for later calls */
+ LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
+ Mount *mount = MOUNT(u);
+@@ -1770,6 +1778,10 @@ static int mount_dispatch_io(sd_event_so
+ break;
+ }
+
++ if (mount->parameters_proc_self_mountinfo.what)
++ (void) device_found_node(m, mount->parameters_proc_self_mountinfo.what, false, DEVICE_FOUND_MOUNT, true);
++
++
+ } else if (mount->just_mounted || mount->just_changed) {
+
+ /* New or changed mount entry */
+Index: systemd-219/src/core/swap.c
+===================================================================
+--- systemd-219.orig/src/core/swap.c
++++ systemd-219/src/core/swap.c
+@@ -338,7 +338,7 @@ static int swap_load(Unit *u) {
+ return swap_verify(s);
+ }
+
+-static int swap_add_one(
++static int swap_setup_unit(
+ Manager *m,
+ const char *what,
+ const char *what_proc_swaps,
+@@ -363,8 +363,10 @@ static int swap_add_one(
+
+ if (u &&
+ SWAP(u)->from_proc_swaps &&
+- !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps))
++ !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps)) {
++ log_error("Swap %s appeared twice with different device paths %s and %s", e, SWAP(u)->parameters_proc_swaps.what, what_proc_swaps);
+ return -EEXIST;
++ }
+
+ if (!u) {
+ delete = true;
+@@ -379,7 +381,7 @@ static int swap_add_one(
+
+ SWAP(u)->what = strdup(what);
+ if (!SWAP(u)->what) {
+- r = log_oom();
++ r = -ENOMEM;
+ goto fail;
+ }
+
+@@ -407,7 +409,6 @@ static int swap_add_one(
+ p->priority = priority;
+
+ unit_add_to_dbus_queue(u);
+-
+ return 0;
+
+ fail:
+@@ -419,7 +420,7 @@ fail:
+ return r;
+ }
+
+-static int swap_process_new_swap(Manager *m, const char *device, int prio, bool set_flags) {
++static int swap_process_new(Manager *m, const char *device, int prio, bool set_flags) {
+ _cleanup_udev_device_unref_ struct udev_device *d = NULL;
+ struct udev_list_entry *item = NULL, *first = NULL;
+ const char *dn;
+@@ -428,7 +429,7 @@ static int swap_process_new_swap(Manager
+
+ assert(m);
+
+- r = swap_add_one(m, device, device, prio, set_flags);
++ r = swap_setup_unit(m, device, device, prio, set_flags);
+ if (r < 0)
+ return r;
+
+@@ -444,7 +445,7 @@ static int swap_process_new_swap(Manager
+ /* Add the main device node */
+ dn = udev_device_get_devnode(d);
+ if (dn && !streq(dn, device))
+- swap_add_one(m, dn, device, prio, set_flags);
++ swap_setup_unit(m, dn, device, prio, set_flags);
+
+ /* Add additional units for all symlinks */
+ first = udev_device_get_devlinks_list_entry(d);
+@@ -465,7 +466,7 @@ static int swap_process_new_swap(Manager
+ st.st_rdev != udev_device_get_devnum(d))
+ continue;
+
+- swap_add_one(m, p, device, prio, set_flags);
++ swap_setup_unit(m, p, device, prio, set_flags);
+ }
+
+ return r;
+@@ -1091,15 +1092,17 @@ static int swap_load_proc_swaps(Manager
+ if (k == EOF)
+ break;
+
+- log_warning("Failed to parse /proc/swaps:%u", i);
++ log_warning("Failed to parse /proc/swaps:%u.", i);
+ continue;
+ }
+
+ d = cunescape(dev);
+ if (!d)
+- return -ENOMEM;
++ return log_oom();
++
++ device_found_node(m, d, true, DEVICE_FOUND_SWAP, set_flags);
+
+- k = swap_process_new_swap(m, d, prio, set_flags);
++ k = swap_process_new(m, d, prio, set_flags);
+ if (k < 0)
+ r = k;
+ }
+@@ -1151,6 +1154,9 @@ static int swap_dispatch_io(sd_event_sou
+ break;
+ }
+
++ if (swap->what)
++ device_found_node(m, swap->what, false, DEVICE_FOUND_SWAP, true);
++
+ } else if (swap->just_activated) {
+
+ /* New swap entry */
+@@ -1298,7 +1304,7 @@ fail:
+ return r;
+ }
+
+-int swap_process_new_device(Manager *m, struct udev_device *dev) {
++int swap_process_device_new(Manager *m, struct udev_device *dev) {
+ struct udev_list_entry *item = NULL, *first = NULL;
+ _cleanup_free_ char *e = NULL;
+ const char *dn;
+@@ -1341,7 +1347,7 @@ int swap_process_new_device(Manager *m,
+ return r;
+ }
+
+-int swap_process_removed_device(Manager *m, struct udev_device *dev) {
++int swap_process_device_remove(Manager *m, struct udev_device *dev) {
+ const char *dn;
+ int r = 0;
+ Swap *s;
+Index: systemd-219/src/core/swap.h
+===================================================================
+--- systemd-219.orig/src/core/swap.h
++++ systemd-219/src/core/swap.h
+@@ -116,8 +116,8 @@ struct Swap {
+
+ extern const UnitVTable swap_vtable;
+
+-int swap_process_new_device(Manager *m, struct udev_device *dev);
+-int swap_process_removed_device(Manager *m, struct udev_device *dev);
++int swap_process_device_new(Manager *m, struct udev_device *dev);
++int swap_process_device_remove(Manager *m, struct udev_device *dev);
+
+ const char* swap_state_to_string(SwapState i) _const_;
+ SwapState swap_state_from_string(const char *s) _pure_;
+Index: systemd-219/src/core/unit.c
+===================================================================
+--- systemd-219.orig/src/core/unit.c
++++ systemd-219/src/core/unit.c
+@@ -2841,7 +2841,6 @@ int unit_add_node_link(Unit *u, const ch
+ return -ENOMEM;
+
+ r = manager_load_unit(u->manager, e, NULL, NULL, &device);
+-
+ if (r < 0)
+ return r;
+
diff --git a/debian/patches/Dont_change_removed_devices_to_tentative.patch b/debian/patches/Dont_change_removed_devices_to_tentative.patch
new file mode 100644
index 0000000000..9fce919771
--- /dev/null
+++ b/debian/patches/Dont_change_removed_devices_to_tentative.patch
@@ -0,0 +1,29 @@
+commit 496068a8288084ab3ecf8b179a8403ecff1a6be8
+Author: Martin Pitt <martin.pitt@ubuntu.com>
+Date: Fri Mar 13 08:35:59 2015 +0100
+
+ core: don't change removed devices to state "tentative"
+
+ Commit 628c89c introduced the "tentative" device state, which caused
+ devices to go from "plugged" to "tentative" on a remove uevent. This
+ breaks the cleanup of stale mounts (see commit 3b48ce4), as that only
+ applies to "dead" devices.
+
+ The "tentative" state only really makes sense on adding a device when
+ we don't know where it was coming from (i. e. not from udev). But when
+ we get a device removal from udev we definitively know that it's gone,
+ so change the device state back to "dead" as before 628c89c.
+
+diff --git a/src/core/device.c b/src/core/device.c
+index 4bfd71f..b5d9d82 100644
+--- a/src/core/device.c
++++ b/src/core/device.c
+@@ -419,7 +419,7 @@ static void device_update_found_one(Device *d, bool add, DeviceFound found, bool
+ if (now) {
+ if (d->found & DEVICE_FOUND_UDEV)
+ device_set_state(d, DEVICE_PLUGGED);
+- else if (d->found != DEVICE_NOT_FOUND)
++ else if (add && d->found != DEVICE_NOT_FOUND)
+ device_set_state(d, DEVICE_TENTATIVE);
+ else
+ device_set_state(d, DEVICE_DEAD);
diff --git a/debian/patches/core-mount-ensure-that-we-parse-proc-self-mountinfo.patch b/debian/patches/core-mount-ensure-that-we-parse-proc-self-mountinfo.patch
index f5d878c5e8..5d9d39656d 100644
--- a/debian/patches/core-mount-ensure-that-we-parse-proc-self-mountinfo.patch
+++ b/debian/patches/core-mount-ensure-that-we-parse-proc-self-mountinfo.patch
@@ -28,20 +28,20 @@ https://launchpad.net/bugs/1419623
src/core/mount.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
-diff --git a/src/core/mount.c b/src/core/mount.c
-index f3977e6..3e7d005 100644
---- a/src/core/mount.c
-+++ b/src/core/mount.c
-@@ -1566,7 +1566,11 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
- if (!tb || !itr)
+Index: systemd-219/src/core/mount.c
+===================================================================
+--- systemd-219.orig/src/core/mount.c
++++ systemd-219/src/core/mount.c
+@@ -1570,7 +1570,11 @@ static int mount_load_proc_self_mountinf
+ if (!i)
return log_oom();
-- r = mnt_table_parse_mtab(tb, NULL);
+- r = mnt_table_parse_mtab(t, NULL);
+ /* FIXME: We really mean "/proc/self/mountinfo" here, but as that's a
+ * regular file this will trick libmount into not parsing
+ * /run/mount/utab; so give it an invalid file to trigger the fallback
+ * to /proc/self/mountinfo. */
-+ r = mnt_table_parse_mtab(tb, "/");
++ r = mnt_table_parse_mtab(t, "/");
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m");
diff --git a/debian/patches/series b/debian/patches/series
index 9a765ed345..bffcfaad83 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -15,6 +15,8 @@ bootchart-fix-default-init-path.patch
journal-fix-Inappropriate-ioctl-for-device-on-ext4.patch
Use-correct-uname-identifiers-in-arch_map-for-SuperH.patch
tmpfiles-Fix-handling-of-duplicate-lines.patch
+Add_tentative_state.patch
+Dont_change_removed_devices_to_tentative.patch
## Debian specific patches
Add-back-support-for-Debian-specific-config-files.patch
@@ -73,5 +75,6 @@ Revert-journald-allow-restarting-journald-without-lo.patch
## Ubuntu patches:
Support-system-image-read-only-etc.patch
Provide-shutdown-fallback-for-upstart.patch
+systemctl-Don-t-forward-telinit-u-to-upstart.patch
Get-RTC-is-in-local-time-setting-from-etc-default-rc.patch
core-Put-session-scopes-into-all-cgroup-controllers.patch
diff --git a/debian/patches/systemctl-Don-t-forward-telinit-u-to-upstart.patch b/debian/patches/systemctl-Don-t-forward-telinit-u-to-upstart.patch
new file mode 100644
index 0000000000..8249d14e43
--- /dev/null
+++ b/debian/patches/systemctl-Don-t-forward-telinit-u-to-upstart.patch
@@ -0,0 +1,36 @@
+From: Martin Pitt <martin.pitt@ubuntu.com>
+Date: Wed, 11 Mar 2015 10:37:47 +0100
+Subject: systemctl: Don't forward telinit u to upstart
+
+When dist-upgrading and /sbin/init changes from upstart to systemd, upstart's
+Restart() exec's argv[0] which is still /sbin/init, and thus it execs systemd.
+This is triggered by glibc upgrades or other things which call "telinit u" in
+their postinst scripts.
+
+This should eventually be fixed in upstart itself, but as we can't
+retroactively fix it in previous releases we upgrade from, we simply ignore
+the request.
+
+https://launchpad.net/bugs/1430479
+---
+ src/systemctl/systemctl.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
+index 37517df..cfc501c 100644
+--- a/src/systemctl/systemctl.c
++++ b/src/systemctl/systemctl.c
+@@ -6995,6 +6995,13 @@ static int parse_argv(int argc, char *argv[]) {
+ * request to it. For now we simply
+ * guess that it is Upstart. */
+
++ /* work around upstart exec'ing systemd when /sbin/init
++ * changes (https://launchpad.net/bugs/1430479) */
++ if (argv[1] != NULL && streq(argv[1], "u")) {
++ log_warning("Ignoring telinit u request, systemd is not running");
++ return -ENOTSUP;
++ }
++
+ execv(TELINIT, argv);
+
+ log_error("Couldn't find an alternative telinit implementation to spawn.");
diff --git a/debian/systemd-sysv.postinst b/debian/systemd-sysv.postinst
index 797ec60e18..e2fd036ec0 100644
--- a/debian/systemd-sysv.postinst
+++ b/debian/systemd-sysv.postinst
@@ -3,7 +3,7 @@ set -e
# update grub on first install, so that the alternative init system boot
# entries get updated
-if [ "$1" = configure -a -z "$2" -a -e /boot/grub/grub.cfg ] && type update-grub >/dev/null 2>&1; then
+if [ "$1" = configure ] && [ -z "$2" ] && [ -e /boot/grub/grub.cfg ] && which update-grub >/dev/null 2>&1; then
update-grub || true
fi
diff --git a/debian/systemd.install b/debian/systemd.install
index e0eaed5815..cff37199f5 100644
--- a/debian/systemd.install
+++ b/debian/systemd.install
@@ -53,3 +53,4 @@ usr/share/locale/
../../extra/tmpfiles.d/*.conf usr/lib/tmpfiles.d/
../../extra/debian-fixup lib/systemd/
../../extra/units/* lib/systemd/system/
+../../extra/systemd-ifupdown-helper lib/systemd/
diff --git a/debian/tests/cmdline-upstart-boot b/debian/tests/cmdline-upstart-boot
index 010893635a..9bdbb8eccb 100755
--- a/debian/tests/cmdline-upstart-boot
+++ b/debian/tests/cmdline-upstart-boot
@@ -68,8 +68,8 @@ class ServicesTest(unittest.TestCase):
def configure_boot():
'''Reboot with upstart as init'''
- print('Installing upstart-bin and rebooting...')
- subprocess.check_call('apt-get -y install upstart-bin 2>&1',
+ print('Installing upstart and rebooting...')
+ subprocess.check_call('apt-get -y install upstart 2>&1',
shell=True)
print('Setting init=/sbin/upstart in grub kernel command line...')
subprocess.check_call(['sh', '-ec', "sed -i '/^GRUB_CMDLINE_LINUX_DEFAULT/"
@@ -86,10 +86,10 @@ def configure_boot():
if __name__ == '__main__':
- # Ubuntu split out upstart-bin, Debian doesn't
- if subprocess.call(['apt-cache', 'show', 'upstart-bin'],
+ # Don't run this test under Debian as Ubuntu split out upstart-sysv, Debian doesn't
+ if subprocess.call(['apt-cache', 'show', 'upstart-sysv'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE) != 0:
- print('SKIP: upstart-bin not available')
+ print('SKIP: upstart-sysv not available')
sys.exit(0)
if not os.getenv('ADT_REBOOT_MARK'):
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment