]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #1736 from ronnychevalier/rc/test_execute_more_tests2
authorLennart Poettering <lennart@poettering.net>
Mon, 2 Nov 2015 19:06:48 +0000 (20:06 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 2 Nov 2015 19:06:48 +0000 (20:06 +0100)
test-execute: add more tests

30 files changed:
TODO
man/systemd.unit.xml
src/basic/env-util.c
src/basic/env-util.h
src/basic/fdset.c
src/basic/fdset.h
src/core/dbus.c
src/core/load-fragment.c
src/core/manager.c
src/core/service.c
src/core/unit.c
src/journal-remote/journal-remote.c
src/journal/journald-server.c
src/journal/journald-server.h
src/journal/journald-stream.c
src/journal/journald-stream.h
src/journal/journald.c
src/journal/sd-journal.c
src/libsystemd/sd-daemon/sd-daemon.c
src/machine/machine.c
src/network/networkd-link.c
src/nspawn/nspawn.c
src/shared/bus-util.c
src/shared/ptyfwd.c
src/systemctl/systemctl.c
src/sysv-generator/sysv-generator.c
src/test/test-path-lookup.c
src/test/test-unit-file.c
sysctl.d/50-default.conf
units/systemd-journald.service.in

diff --git a/TODO b/TODO
index 8deb00b5979da2cd872d5e621dc14e80e15f1e15..c1dc3921f1a66bd8d81f43bdfdbf33c2884c3f9f 100644 (file)
--- a/TODO
+++ b/TODO
@@ -231,8 +231,6 @@ Features:
 * Find a solution for SMACK capabilities stuff:
   http://lists.freedesktop.org/archives/systemd-devel/2014-December/026188.html
 
-* port libmount hookup to use API's own inotify interface, as soon as that is table in libmount
-
 * "systemctl preset-all" should probably order the unit files it
   operates on lexicographically before starting to work, in order to
   ensure deterministic behaviour if two unit files conflict (like DMs
@@ -561,9 +559,6 @@ Features:
 
 * maybe do not install getty@tty1.service symlink in /etc but in /usr?
 
-* fstab: add new mount option x-systemd-after=/foobar/waldo to allow manual dependencies to other mount points
-  https://bugzilla.redhat.com/show_bug.cgi?id=812826
-
 * print a nicer explanation if people use variable/specifier expansion in ExecStart= for the first word
 
 * mount: turn dependency information from /proc/self/mountinfo into dependency information between systemd units.
index 33f1309268224f53a5de570ad498886cd73dadce..a4eeccaed44b04b3acc2adc5ec5cb6b96cda27d9 100644 (file)
     in directories listed earlier override files with the same name in
     directories lower in the list.</para>
 
-    <para>When systemd is running in user mode
-    (<option>--user</option>) and the variable
-    <varname>$SYSTEMD_UNIT_PATH</varname> is set, the contents of this
-    variable overrides the unit load path. If
+    <para>When the variable <varname>$SYSTEMD_UNIT_PATH</varname> is set,
+    the contents of this variable overrides the unit load path. If
     <varname>$SYSTEMD_UNIT_PATH</varname> ends with an empty component
     (<literal>:</literal>), the usual unit load path will be appended
     to the contents of the variable.</para>
index 94cb25169839d8ef39c554d50ee007f11a7845e2..9ddac5d6a1c39e967c576d6cd0de6356c5375879 100644 (file)
@@ -25,6 +25,7 @@
 #include "alloc-util.h"
 #include "def.h"
 #include "env-util.h"
+#include "parse-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "utf8.h"
@@ -594,3 +595,13 @@ char **replace_env_argv(char **argv, char **env) {
         ret[k] = NULL;
         return ret;
 }
+
+int getenv_bool(const char *p) {
+        const char *e;
+
+        e = getenv(p);
+        if (!e)
+                return -ENXIO;
+
+        return parse_boolean(e);
+}
index 803aa61cad7def354ea11335cf6ba50094ebddcb..6485dade1857e16ed0f1e214b7a39ba8d0a0cbad 100644 (file)
@@ -47,3 +47,5 @@ char **strv_env_unset_many(char **l, ...) _sentinel_;
 
 char *strv_env_get_n(char **l, const char *name, size_t k) _pure_;
 char *strv_env_get(char **x, const char *n) _pure_;
+
+int getenv_bool(const char *p);
index 4b11e4ea092013f58c6425c7c2d5481db9923f5b..42b0b2b98f635eaa33c8a5b2c7c24e537264d2b0 100644 (file)
@@ -44,7 +44,7 @@ FDSet *fdset_new(void) {
         return MAKE_FDSET(set_new(NULL));
 }
 
-int fdset_new_array(FDSet **ret, int *fds, unsigned n_fds) {
+int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds) {
         unsigned i;
         FDSet *s;
         int r;
index 340438d7c401ce9cc4565242e46f11b34801a7dd..70d8acbcff3434e5e0983f1a93eeaea391d5afe1 100644 (file)
@@ -35,7 +35,7 @@ int fdset_consume(FDSet *s, int fd);
 bool fdset_contains(FDSet *s, int fd);
 int fdset_remove(FDSet *s, int fd);
 
-int fdset_new_array(FDSet **ret, int *fds, unsigned n_fds);
+int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds);
 int fdset_new_fill(FDSet **ret);
 int fdset_new_listen_fds(FDSet **ret, bool unset);
 
index 834745aeb5954d2cf28b52e62217bb8a0ef208d6..6c44b28adff20f1036edcd205df216a30c4cd8bd 100644 (file)
@@ -784,7 +784,7 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
         HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
                 r = unit_install_bus_match(u, bus, name);
                 if (r < 0)
-                        log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
+                        log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name);
         }
 
         r = sd_bus_add_match(
index 333fca46c4680ebda080b9658de2103d753eef7f..a30cd0967d5fc0c7b6228ab812a2be120ee9682a 100644 (file)
@@ -983,10 +983,10 @@ int config_parse_bounding_set(const char *unit,
 
         uint64_t *capability_bounding_set_drop = data;
         uint64_t capability_bounding_set;
-        const char *word, *state;
-        size_t l;
         bool invert = false;
         uint64_t sum = 0;
+        const char *prev;
+        const char *cur;
 
         assert(filename);
         assert(lvalue);
@@ -1003,24 +1003,32 @@ int config_parse_bounding_set(const char *unit,
          * non-inverted everywhere to have a fully normalized
          * interface. */
 
-        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
-                _cleanup_free_ char *t = NULL;
+        prev = cur = rvalue;
+        for (;;) {
+                _cleanup_free_ char *word = NULL;
                 int cap;
+                int r;
 
-                t = strndup(word, l);
-                if (!t)
+                r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
+                if (r == 0)
+                        break;
+                if (r == -ENOMEM)
                         return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in bounding set, ignoring: %s", prev);
+                        break;
+                }
 
-                cap = capability_from_name(t);
+                cap = capability_from_name(word);
                 if (cap < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", t);
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word);
+                        prev = cur;
                         continue;
                 }
 
                 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
+                prev = cur;
         }
-        if (!isempty(state))
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
 
         capability_bounding_set = invert ? ~sum : sum;
         if (*capability_bounding_set_drop && capability_bounding_set)
index d161e6c57bd20c2775e22c74530e6dfff9fb46b7..b13663e702fb364877a3eb5be38aefa0d80dd2a0 100644 (file)
@@ -86,6 +86,8 @@
 #include "virt.h"
 #include "watchdog.h"
 
+#define NOTIFY_RCVBUF_SIZE (8*1024*1024)
+
 /* Initial delay and the interval for printing status messages about running jobs */
 #define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
 #define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
@@ -689,6 +691,8 @@ static int manager_setup_notify(Manager *m) {
                 if (fd < 0)
                         return log_error_errno(errno, "Failed to allocate notification socket: %m");
 
+                fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE);
+
                 if (m->running_as == MANAGER_SYSTEM)
                         m->notify_socket = strdup("/run/systemd/notify");
                 else {
@@ -1488,7 +1492,7 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) {
         return n;
 }
 
-static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) {
+static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const char *buf, size_t n, FDSet *fds) {
         _cleanup_strv_free_ char **tags = NULL;
 
         assert(m);
@@ -1618,7 +1622,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
         return 0;
 }
 
-static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) {
+static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) {
         assert(m);
         assert(u);
         assert(si);
@@ -2000,8 +2004,7 @@ int manager_loop(Manager *m) {
         m->exit_code = MANAGER_OK;
 
         /* Release the path cache */
-        set_free_free(m->unit_path_cache);
-        m->unit_path_cache = NULL;
+        m->unit_path_cache = set_free_free(m->unit_path_cache);
 
         manager_check_finished(m);
 
@@ -2111,6 +2114,9 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
         const char *msg;
         int audit_fd, r;
 
+        if (m->running_as != MANAGER_SYSTEM)
+                return;
+
         audit_fd = get_audit_fd();
         if (audit_fd < 0)
                 return;
@@ -2120,9 +2126,6 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
         if (m->n_reloading > 0)
                 return;
 
-        if (m->running_as != MANAGER_SYSTEM)
-                return;
-
         if (u->type != UNIT_SERVICE)
                 return;
 
@@ -2771,8 +2774,7 @@ static int create_generator_dir(Manager *m, char **generator, const char *name)
                         return log_oom();
 
                 if (!mkdtemp(p)) {
-                        log_error_errno(errno, "Failed to create generator directory %s: %m",
-                                  p);
+                        log_error_errno(errno, "Failed to create generator directory %s: %m", p);
                         free(p);
                         return -errno;
                 }
index bafb532e1ee9ff56e7fd23fcf6c11ff3dbd66a7e..586eddd99a860a58e5b8f9f5be83dbbe44cd3439 100644 (file)
@@ -420,7 +420,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
         }
 
         if (fdset_size(fds) > 0)
-                log_unit_warning(UNIT(s), "Tried to store more fds than FDStoreMax=%u allows, closing remaining.", s->n_fd_store_max);
+                log_unit_warning(UNIT(s), "Tried to store more fds than FileDescriptorStoreMax=%u allows, closing remaining.", s->n_fd_store_max);
 
         return 0;
 }
index 8d56401231e4a8dd5a54ceead076d552b4d0bdf4..6c130d4cd16eaf99f4bae081602842ec52445338 100644 (file)
@@ -2328,7 +2328,7 @@ int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency
 
 int set_unit_path(const char *p) {
         /* This is mostly for debug purposes */
-        if (setenv("SYSTEMD_UNIT_PATH", p, 0) < 0)
+        if (setenv("SYSTEMD_UNIT_PATH", p, 1) < 0)
                 return -errno;
 
         return 0;
@@ -2511,7 +2511,7 @@ int unit_watch_bus_name(Unit *u, const char *name) {
                  * Otherwise, just put the name in the list. bus_setup_api() will take care later. */
                 r = unit_install_bus_match(u, u->manager->api_bus, name);
                 if (r < 0)
-                        return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
+                        return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name);
         }
 
         r = hashmap_put(u->manager->watch_bus, name, u);
index 20be5420963dc0192217895f12af9ab42d6b02b9..dc69bb8679d003e6dc7cab44e48541b6494b68c8 100644 (file)
@@ -1256,7 +1256,6 @@ static int parse_argv(int argc, char *argv[]) {
         };
 
         int c, r;
-        const char *p;
         bool type_a, type_b;
 
         assert(argc >= 0);
@@ -1417,7 +1416,7 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_GNUTLS_LOG: {
 #ifdef HAVE_GNUTLS
-                        p = optarg;
+                        const char* p = optarg;
                         for (;;) {
                                 _cleanup_free_ char *word = NULL;
 
index ecf7b7a47669f453cea57230e5fa2d1ce7e953e7..299b0a848fb12c35ff8c684ebdd62dadbafb4bb5 100644 (file)
@@ -78,6 +78,8 @@
 
 #define RECHECK_SPACE_USEC (30*USEC_PER_SEC)
 
+#define NOTIFY_SNDBUF_SIZE (8*1024*1024)
+
 static int determine_space_for(
                 Server *s,
                 JournalMetrics *metrics,
@@ -1457,6 +1459,126 @@ static int server_open_hostname(Server *s) {
         return 0;
 }
 
+static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
+        Server *s = userdata;
+        int r;
+
+        assert(s);
+        assert(s->notify_event_source == es);
+        assert(s->notify_fd == fd);
+
+        if (revents != EPOLLOUT) {
+                log_error("Invalid events on notify file descriptor.");
+                return -EINVAL;
+        }
+
+        /* The $NOTIFY_SOCKET is writable again, now send exactly one
+         * message on it. Either it's the initial READY=1 event or an
+         * stdout stream event. If there's nothing to write anymore,
+         * turn our event source off. The next time there's something
+         * to send it will be turned on again. */
+
+        if (!s->sent_notify_ready) {
+                static const char p[] =
+                        "READY=1\n"
+                        "STATUS=Processing requests...";
+                ssize_t l;
+
+                l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT);
+                if (l < 0) {
+                        if (errno == EAGAIN)
+                                return 0;
+
+                        return log_error_errno(errno, "Failed to send READY=1 notification message: %m");
+                }
+
+                s->sent_notify_ready = true;
+                log_debug("Sent READY=1 notification.");
+
+        } else if (s->stdout_streams_notify_queue)
+                /* Dispatch one stream notification event */
+                stdout_stream_send_notify(s->stdout_streams_notify_queue);
+
+        /* Leave us enabled if there's still more to to do. */
+        if (s->stdout_streams_notify_queue)
+                return 0;
+
+        /* There was nothing to do anymore, let's turn ourselves off. */
+        r = sd_event_source_set_enabled(es, SD_EVENT_OFF);
+        if (r < 0)
+                return log_error_errno(r, "Failed to turn off notify event source: %m");
+
+        return 0;
+}
+
+static int server_connect_notify(Server *s) {
+        union sockaddr_union sa = {
+                .un.sun_family = AF_UNIX,
+        };
+        const char *e;
+        int r;
+
+        assert(s);
+        assert(s->notify_fd < 0);
+        assert(!s->notify_event_source);
+
+        /*
+          So here's the problem: we'd like to send notification
+          messages to PID 1, but we cannot do that via sd_notify(),
+          since that's synchronous, and we might end up blocking on
+          it. Specifically: given that PID 1 might block on
+          dbus-daemon during IPC, and dbus-daemon is logging to us,
+          and might hence block on us, we might end up in a deadlock
+          if we block on sending PID 1 notification messages -- by
+          generating a full blocking circle. To avoid this, let's
+          create a non-blocking socket, and connect it to the
+          notification socket, and then wait for POLLOUT before we
+          send anything. This should efficiently avoid any deadlocks,
+          as we'll never block on PID 1, hence PID 1 can safely block
+          on dbus-daemon which can safely block on us again.
+
+          Don't think that this issue is real? It is, see:
+          https://github.com/systemd/systemd/issues/1505
+        */
+
+        e = getenv("NOTIFY_SOCKET");
+        if (!e)
+                return 0;
+
+        if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
+                log_error("NOTIFY_SOCKET set to an invalid value: %s", e);
+                return -EINVAL;
+        }
+
+        if (strlen(e) > sizeof(sa.un.sun_path)) {
+                log_error("NOTIFY_SOCKET path too long: %s", e);
+                return -EINVAL;
+        }
+
+        s->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (s->notify_fd < 0)
+                return log_error_errno(errno, "Failed to create notify socket: %m");
+
+        (void) fd_inc_sndbuf(s->notify_fd, NOTIFY_SNDBUF_SIZE);
+
+        strncpy(sa.un.sun_path, e, sizeof(sa.un.sun_path));
+        if (sa.un.sun_path[0] == '@')
+                sa.un.sun_path[0] = 0;
+
+        r = connect(s->notify_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(e));
+        if (r < 0)
+                return log_error_errno(errno, "Failed to connect to notify socket: %m");
+
+        r = sd_event_add_io(s->event, &s->notify_event_source, s->notify_fd, EPOLLOUT, dispatch_notify_event, s);
+        if (r < 0)
+                return log_error_errno(r, "Failed to watch notification socket: %m");
+
+        /* This should fire pretty soon, which we'll use to send the
+         * READY=1 event. */
+
+        return 0;
+}
+
 int server_init(Server *s) {
         _cleanup_fdset_free_ FDSet *fds = NULL;
         int n, r, fd;
@@ -1465,7 +1587,7 @@ int server_init(Server *s) {
         assert(s);
 
         zero(*s);
-        s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = -1;
+        s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = s->notify_fd = -1;
         s->compress = true;
         s->seal = true;
 
@@ -1511,8 +1633,6 @@ int server_init(Server *s) {
         if (r < 0)
                 return log_error_errno(r, "Failed to create event loop: %m");
 
-        sd_event_set_watchdog(s->event, true);
-
         n = sd_listen_fds(true);
         if (n < 0)
                 return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
@@ -1637,6 +1757,8 @@ int server_init(Server *s) {
         server_cache_boot_id(s);
         server_cache_machine_id(s);
 
+        (void) server_connect_notify(s);
+
         return system_journal_open(s, false);
 }
 
@@ -1685,6 +1807,7 @@ void server_done(Server *s) {
         sd_event_source_unref(s->sigterm_event_source);
         sd_event_source_unref(s->sigint_event_source);
         sd_event_source_unref(s->hostname_event_source);
+        sd_event_source_unref(s->notify_event_source);
         sd_event_unref(s->event);
 
         safe_close(s->syslog_fd);
@@ -1693,6 +1816,7 @@ void server_done(Server *s) {
         safe_close(s->dev_kmsg_fd);
         safe_close(s->audit_fd);
         safe_close(s->hostname_fd);
+        safe_close(s->notify_fd);
 
         if (s->rate_limit)
                 journal_rate_limit_free(s->rate_limit);
index a2631c6017573f1881f73c8520cc7bc272483a5e..170602ea16614f9d47e3a93bac30db0d10aee9d0 100644 (file)
 
 #include "sd-event.h"
 
+typedef struct Server Server;
+
 #include "hashmap.h"
 #include "journal-file.h"
 #include "journald-rate-limit.h"
+#include "journald-stream.h"
 #include "list.h"
 
 typedef enum Storage {
@@ -48,15 +51,14 @@ typedef enum SplitMode {
         _SPLIT_INVALID = -1
 } SplitMode;
 
-typedef struct StdoutStream StdoutStream;
-
-typedef struct Server {
+struct Server {
         int syslog_fd;
         int native_fd;
         int stdout_fd;
         int dev_kmsg_fd;
         int audit_fd;
         int hostname_fd;
+        int notify_fd;
 
         sd_event *event;
 
@@ -71,6 +73,7 @@ typedef struct Server {
         sd_event_source *sigterm_event_source;
         sd_event_source *sigint_event_source;
         sd_event_source *hostname_event_source;
+        sd_event_source *notify_event_source;
 
         JournalFile *runtime_journal;
         JournalFile *system_journal;
@@ -111,6 +114,7 @@ typedef struct Server {
         usec_t oldest_file_usec;
 
         LIST_HEAD(StdoutStream, stdout_streams);
+        LIST_HEAD(StdoutStream, stdout_streams_notify_queue);
         unsigned n_stdout_streams;
 
         char *tty_path;
@@ -132,6 +136,7 @@ typedef struct Server {
 
         struct udev *udev;
 
+        bool sent_notify_ready;
         bool sync_scheduled;
 
         char machine_id_field[sizeof("_MACHINE_ID=") + 32];
@@ -140,7 +145,7 @@ typedef struct Server {
 
         /* Cached cgroup root, so that we don't have to query that all the time */
         char *cgroup_root;
-} Server;
+};
 
 #define SERVER_MACHINE_ID(s) ((s)->machine_id_field + strlen("_MACHINE_ID="))
 
index 5300c61c022255f24f38e588b38c1da9097ae811..fb6afee1713cb4e7f5a09f4aed1a6bf9e766df9a 100644 (file)
@@ -79,6 +79,7 @@ struct StdoutStream {
         bool forward_to_console:1;
 
         bool fdstore:1;
+        bool in_notify_queue:1;
 
         char buffer[LINE_MAX+1];
         size_t length;
@@ -88,6 +89,7 @@ struct StdoutStream {
         char *state_file;
 
         LIST_FIELDS(StdoutStream, stdout_stream);
+        LIST_FIELDS(StdoutStream, stdout_stream_notify_queue);
 };
 
 void stdout_stream_free(StdoutStream *s) {
@@ -98,6 +100,9 @@ void stdout_stream_free(StdoutStream *s) {
                 assert(s->server->n_stdout_streams > 0);
                 s->server->n_stdout_streams --;
                 LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
+
+                if (s->in_notify_queue)
+                        LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
         }
 
         if (s->event_source) {
@@ -121,7 +126,7 @@ static void stdout_stream_destroy(StdoutStream *s) {
                 return;
 
         if (s->state_file)
-                unlink(s->state_file);
+                (void) unlink(s->state_file);
 
         stdout_stream_free(s);
 }
@@ -200,11 +205,15 @@ static int stdout_stream_save(StdoutStream *s) {
                 goto fail;
         }
 
-        /* Store the connection fd in PID 1, so that we get it passed
-         * in again on next start */
-        if (!s->fdstore) {
-                sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s->fd, 1);
-                s->fdstore = true;
+        if (!s->fdstore && !s->in_notify_queue) {
+                LIST_PREPEND(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
+                s->in_notify_queue = true;
+
+                if (s->server->notify_event_source) {
+                        r = sd_event_source_set_enabled(s->server->notify_event_source, SD_EVENT_ON);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to enable notify event source: %m");
+                }
         }
 
         return 0;
@@ -729,3 +738,50 @@ int server_open_stdout_socket(Server *s) {
 
         return 0;
 }
+
+void stdout_stream_send_notify(StdoutStream *s) {
+        struct iovec iovec = {
+                .iov_base = (char*) "FDSTORE=1",
+                .iov_len = strlen("FDSTORE=1"),
+        };
+        struct msghdr msghdr = {
+                .msg_iov = &iovec,
+                .msg_iovlen = 1,
+        };
+        struct cmsghdr *cmsg;
+        ssize_t l;
+
+        assert(s);
+        assert(!s->fdstore);
+        assert(s->in_notify_queue);
+        assert(s->server);
+        assert(s->server->notify_fd >= 0);
+
+        /* Store the connection fd in PID 1, so that we get it passed
+         * in again on next start */
+
+        msghdr.msg_controllen = CMSG_SPACE(sizeof(int));
+        msghdr.msg_control = alloca0(msghdr.msg_controllen);
+
+        cmsg = CMSG_FIRSTHDR(&msghdr);
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+
+        memcpy(CMSG_DATA(cmsg), &s->fd, sizeof(int));
+
+        l = sendmsg(s->server->notify_fd, &msghdr, MSG_DONTWAIT|MSG_NOSIGNAL);
+        if (l < 0) {
+                if (errno == EAGAIN)
+                        return;
+
+                log_error_errno(errno, "Failed to send stream file descriptor to service manager: %m");
+        } else {
+                log_debug("Successfully sent stream file descriptor to service manager.");
+                s->fdstore = 1;
+        }
+
+        LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
+        s->in_notify_queue = false;
+
+}
index 257dce45df3501568f30ef98ce772a0030663a31..e3497f0dedb02c64209030a338cc1628bc77f32e 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+typedef struct StdoutStream StdoutStream;
+
 #include "fdset.h"
 #include "journald-server.h"
 
 int server_open_stdout_socket(Server *s);
 int server_restore_streams(Server *s, FDSet *fds);
+
 void stdout_stream_free(StdoutStream *s);
+void stdout_stream_send_notify(StdoutStream *s);
index 83236ceba9b46cc653784ac4638686be7a6eff4d..b137e3c7beadbd85dcd4166c095ac0f3bc767ee4 100644 (file)
@@ -61,10 +61,6 @@ int main(int argc, char *argv[]) {
         log_debug("systemd-journald running as pid "PID_FMT, getpid());
         server_driver_message(&server, SD_MESSAGE_JOURNAL_START, "Journal started");
 
-        sd_notify(false,
-                  "READY=1\n"
-                  "STATUS=Processing requests...");
-
         for (;;) {
                 usec_t t = USEC_INFINITY, n;
 
@@ -117,10 +113,6 @@ int main(int argc, char *argv[]) {
         server_driver_message(&server, SD_MESSAGE_JOURNAL_STOP, "Journal stopped");
 
 finish:
-        sd_notify(false,
-                  "STOPPING=1\n"
-                  "STATUS=Shutting down...");
-
         server_done(&server);
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
index 043087485b724e3e89dc93b11cdc8470ed230520..218df8cebefe8680af84a032e94bfbbf5b8a8f12 100644 (file)
@@ -1025,8 +1025,6 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
 
 _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
         int r;
-        const char *word, *state;
-        size_t l;
         Object *o;
 
         assert_return(j, -EINVAL);
@@ -1040,20 +1038,23 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
         if (r < 0)
                 return r;
 
-        FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
+        for(;;) {
                 _cleanup_free_ char *item = NULL;
-                sd_id128_t id;
                 unsigned long long ll;
+                sd_id128_t id;
                 int k = 0;
 
-                if (l < 2 || word[1] != '=')
-                        return -EINVAL;
+                r = extract_first_word(&cursor, &item, ";", EXTRACT_DONT_COALESCE_SEPARATORS);
+                if (r < 0)
+                        return r;
 
-                item = strndup(word, l);
-                if (!item)
-                        return -ENOMEM;
+                if (r == 0)
+                        break;
 
-                switch (word[0]) {
+                if (strlen(item) < 2 || item[1] != '=')
+                        return -EINVAL;
+
+                switch (item[0]) {
 
                 case 's':
                         k = sd_id128_from_string(item+2, &id);
index 77b5dd52f6ee8c03871f1a9b56e317e3d4b9ab63..27045e25d0c583a1131ddfdf95b6b1d9e0d0ece1 100644 (file)
@@ -44,6 +44,8 @@
 #include "strv.h"
 #include "util.h"
 
+#define SNDBUF_SIZE (8*1024*1024)
+
 static void unsetenv_all(bool unset_environment) {
 
         if (!unset_environment)
@@ -434,12 +436,19 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
                 goto finish;
         }
 
+        if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
+                r = -EINVAL;
+                goto finish;
+        }
+
         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
         if (fd < 0) {
                 r = -errno;
                 goto finish;
         }
 
+        fd_inc_sndbuf(fd, SNDBUF_SIZE);
+
         iovec.iov_len = strlen(state);
 
         strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
index fa6b70f788cb46c135ad9777b244b1783be7723c..ef5c8551b542532749644dbafc35c7c19943a0d6 100644 (file)
@@ -42,6 +42,7 @@
 #include "terminal-util.h"
 #include "unit-name.h"
 #include "util.h"
+#include "extract-word.h"
 
 Machine* machine_new(Manager *manager, MachineClass class, const char *name) {
         Machine *m;
@@ -312,17 +313,26 @@ int machine_load(Machine *m) {
         }
 
         if (netif) {
-                size_t l, allocated = 0, nr = 0;
-                const char *word, *state;
+                size_t allocated = 0, nr = 0;
+                const char *p;
                 int *ni = NULL;
 
-                FOREACH_WORD(word, l, netif, state) {
-                        char buf[l+1];
+                p = netif;
+                for(;;) {
+                        _cleanup_free_ char *word = NULL;
                         int ifi;
 
-                        *(char*) (mempcpy(buf, word, l)) = 0;
+                        r = extract_first_word(&p, &word, NULL, 0);
+                        if (r == 0)
+                                break;
+                        else if (r == -ENOMEM)
+                                return log_oom();
+                        else if (r < 0) {
+                                log_warning_errno(r, "Failed to parse NETIF: %s", netif);
+                                continue;
+                        }
 
-                        if (safe_atoi(buf, &ifi) < 0)
+                        if (safe_atoi(word, &ifi) < 0)
                                 continue;
                         if (ifi <= 0)
                                 continue;
index dcc2569660c6482510b192b16d5c990c7b38b2d3..12ca02868db51c8a92a4197314886558f0db1bfb 100644 (file)
@@ -349,12 +349,12 @@ static void link_free(Link *link) {
         while (!set_isempty(link->addresses))
                 address_free(set_first(link->addresses));
 
-        set_free(link->addresses);
-
         while (!set_isempty(link->addresses_foreign))
                 address_free(set_first(link->addresses_foreign));
 
-        set_free(link->addresses_foreign);
+        link->addresses = set_free(link->addresses);
+
+        link->addresses_foreign = set_free(link->addresses_foreign);
 
         while ((address = link->pool_addresses)) {
                 LIST_REMOVE(addresses, link->pool_addresses, address);
index 44f08ab1b4432191c835be095c780759b5dd00f0..ff12ca64983c3c8b6890154db63c52fec5bf9ed3 100644 (file)
@@ -3227,8 +3227,7 @@ int main(int argc, char *argv[]) {
         }
 
         for (;;) {
-                _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 },
-                                         uid_shift_socket_pair[2] = { -1, -1 };
+                _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 };
                 ContainerStatus container_status;
                 _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
                 static const struct sigaction sa = {
index 940e393318d118fc5e6d64a1d6b8e0003c7ad318..dbae6e7c85e28377aa8f2bd87b0eee73f3c9641b 100644 (file)
@@ -1450,7 +1450,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
                        "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
                        "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
                        "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
-                       "SyslogLevelPrefix")) {
+                       "SyslogLevelPrefix", "Delegate")) {
 
                 r = parse_boolean(eq);
                 if (r < 0) {
index 786752ea941b4d38ef8d09dff2eaa54f60870ced..63e81f489490ed3af4bb8902ed8a754799815c31 100644 (file)
@@ -413,6 +413,7 @@ PTYForward *pty_forward_free(PTYForward *f) {
                 sd_event_source_unref(f->stdin_event_source);
                 sd_event_source_unref(f->stdout_event_source);
                 sd_event_source_unref(f->master_event_source);
+                sd_event_source_unref(f->sigwinch_event_source);
                 sd_event_unref(f->event);
 
                 if (f->saved_stdout)
index f5efa1a064f9d147e3551047be6650766a1746bd..70871cf3e64a32431685f875c6e7ee2334497113 100644 (file)
@@ -296,6 +296,10 @@ static bool install_client_side(void) {
         if (arg_scope == UNIT_FILE_GLOBAL)
                 return true;
 
+        /* Unsupported environment variable, mostly for debugging purposes */
+        if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0)
+                return true;
+
         return false;
 }
 
@@ -5317,6 +5321,9 @@ static int enable_sysv_units(const char *verb, char **args) {
         if (arg_scope != UNIT_FILE_SYSTEM)
                 return 0;
 
+        if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0)
+                return 0;
+
         if (!STR_IN_SET(verb,
                         "enable",
                         "disable",
@@ -6624,6 +6631,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 {}
         };
 
+        const char *p;
         int c, r;
 
         assert(argc >= 0);
@@ -6644,15 +6652,19 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         return version();
 
                 case 't': {
-                        const char *word, *state;
-                        size_t size;
+                        if (isempty(optarg))
+                                return log_error_errno(r, "--type requires arguments.");
 
-                        FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
-                                _cleanup_free_ char *type;
+                        p = optarg;
+                        for(;;) {
+                                _cleanup_free_ char *type = NULL;
 
-                                type = strndup(word, size);
-                                if (!type)
-                                        return -ENOMEM;
+                                r = extract_first_word(&p, &type, ",", 0);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse type: %s", optarg);
+
+                                if (r == 0)
+                                        break;
 
                                 if (streq(type, "help")) {
                                         help_types();
@@ -6693,18 +6705,21 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                 if (!arg_properties)
                                         return log_oom();
                         } else {
-                                const char *word, *state;
-                                size_t size;
+                                p = optarg;
+                                for(;;) {
+                                        _cleanup_free_ char *prop = NULL;
 
-                                FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
-                                        char *prop;
+                                        r = extract_first_word(&p, &prop, ",", 0);
+                                        if (r < 0)
+                                                return log_error_errno(r, "Failed to parse property: %s", optarg);
 
-                                        prop = strndup(word, size);
-                                        if (!prop)
-                                                return log_oom();
+                                        if (r == 0)
+                                                break;
 
-                                        if (strv_consume(&arg_properties, prop) < 0)
+                                        if (strv_push(&arg_properties, prop) < 0)
                                                 return log_oom();
+
+                                        prop = NULL;
                                 }
                         }
 
@@ -6870,15 +6885,19 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_STATE: {
-                        const char *word, *state;
-                        size_t size;
+                        if (isempty(optarg))
+                                return log_error_errno(r, "--signal requires arguments.");
 
-                        FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
+                        p = optarg;
+                        for(;;) {
                                 _cleanup_free_ char *s = NULL;
 
-                                s = strndup(word, size);
-                                if (!s)
-                                        return log_oom();
+                                r = extract_first_word(&p, &s, ",", 0);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse signal: %s", optarg);
+
+                                if (r == 0)
+                                        break;
 
                                 if (streq(s, "help")) {
                                         help_states();
index 0a0b9269b3f91c59af82b9657eda50bb8203def2..b2d53d3b4feff3982f3c341f38e7e382bd216367 100644 (file)
@@ -26,7 +26,9 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "dirent-util.h"
 #include "fd-util.h"
+#include "fileio.h"
 #include "hashmap.h"
 #include "hexdecoct.h"
 #include "install.h"
@@ -85,9 +87,13 @@ typedef struct SysvStub {
         char **conflicts;
         bool has_lsb;
         bool reload;
+        bool loaded;
 } SysvStub;
 
 static void free_sysvstub(SysvStub *s) {
+        if (!s)
+                return;
+
         free(s->name);
         free(s->path);
         free(s->description);
@@ -112,19 +118,14 @@ static void free_sysvstub_hashmapp(Hashmap **h) {
 }
 
 static int add_symlink(const char *service, const char *where) {
-        _cleanup_free_ char *from = NULL, *to = NULL;
+        const char *from, *to;
         int r;
 
         assert(service);
         assert(where);
 
-        from = strjoin(arg_dest, "/", service, NULL);
-        if (!from)
-                return log_oom();
-
-        to = strjoin(arg_dest, "/", where, ".wants/", service, NULL);
-        if (!to)
-                return log_oom();
+        from = strjoina(arg_dest, "/", service);
+        to = strjoina(arg_dest, "/", where, ".wants/", service);
 
         mkdir_parents_label(to, 0755);
 
@@ -132,6 +133,7 @@ static int add_symlink(const char *service, const char *where) {
         if (r < 0) {
                 if (errno == EEXIST)
                         return 0;
+
                 return -errno;
         }
 
@@ -139,20 +141,19 @@ static int add_symlink(const char *service, const char *where) {
 }
 
 static int add_alias(const char *service, const char *alias) {
-        _cleanup_free_ char *link = NULL;
+        const char *link;
         int r;
 
         assert(service);
         assert(alias);
 
-        link = strjoin(arg_dest, "/", alias, NULL);
-        if (!link)
-                return log_oom();
+        link = strjoina(arg_dest, "/", alias);
 
         r = symlink(service, link);
         if (r < 0) {
                 if (errno == EEXIST)
                         return 0;
+
                 return -errno;
         }
 
@@ -160,26 +161,32 @@ static int add_alias(const char *service, const char *alias) {
 }
 
 static int generate_unit_file(SysvStub *s) {
-        char **p;
+        _cleanup_free_ char *before = NULL, *after = NULL, *wants = NULL, *conflicts = NULL;
         _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *unit = NULL,
-                *before = NULL, *after = NULL,
-                *wants = NULL, *conflicts = NULL;
+        const char *unit;
+        char **p;
         int r;
 
+        assert(s);
+
+        if (!s->loaded)
+                return 0;
+
+        unit = strjoina(arg_dest, "/", s->name);
+
         before = strv_join(s->before, " ");
         after = strv_join(s->after, " ");
         wants = strv_join(s->wants, " ");
         conflicts = strv_join(s->conflicts, " ");
-        unit = strjoin(arg_dest, "/", s->name, NULL);
-        if (!before || !after || !wants || !conflicts || !unit)
+
+        if (!before || !after || !wants || !conflicts)
                 return log_oom();
 
         /* We might already have a symlink with the same name from a Provides:,
          * or from backup files like /etc/init.d/foo.bak. Real scripts always win,
          * so remove an existing link */
         if (is_symlink(unit) > 0) {
-                log_warning("Overwriting existing symlink %s with real service", unit);
+                log_warning("Overwriting existing symlink %s with real service.", unit);
                 (void) unlink(unit);
         }
 
@@ -191,9 +198,11 @@ static int generate_unit_file(SysvStub *s) {
                 "# Automatically generated by systemd-sysv-generator\n\n"
                 "[Unit]\n"
                 "Documentation=man:systemd-sysv-generator(8)\n"
-                "SourcePath=%s\n"
-                "Description=%s\n",
-                s->path, s->description);
+                "SourcePath=%s\n",
+                s->path);
+
+        if (s->description)
+                fprintf(f, "Description=%s\n", s->description);
 
         if (!isempty(before))
                 fprintf(f, "Before=%s\n", before);
@@ -226,13 +235,17 @@ static int generate_unit_file(SysvStub *s) {
         if (s->reload)
                 fprintf(f, "ExecReload=%s reload\n", s->path);
 
+        r = fflush_and_check(f);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write unit %s: %m", unit);
+
         STRV_FOREACH(p, s->wanted_by) {
                 r = add_symlink(s->name, *p);
                 if (r < 0)
-                        log_error_errno(r, "Failed to create 'Wants' symlink to %s: %m", *p);
+                        log_warning_errno(r, "Failed to create 'Wants' symlink to %s, ignoring: %m", *p);
         }
 
-        return 0;
+        return 1;
 }
 
 static bool usage_contains_reload(const char *line) {
@@ -262,7 +275,7 @@ static char *sysv_translate_name(const char *name) {
         return res;
 }
 
-static int sysv_translate_facility(const char *name, const char *filename, char **_r) {
+static int sysv_translate_facility(const char *name, const char *filename, char **ret) {
 
         /* We silently ignore the $ prefix here. According to the LSB
          * spec it simply indicates whether something is a
@@ -281,31 +294,45 @@ static int sysv_translate_facility(const char *name, const char *filename, char
                 "time",                 SPECIAL_TIME_SYNC_TARGET,
         };
 
-        char *filename_no_sh, *e, *r;
+        char *filename_no_sh, *e, *m;
         const char *n;
         unsigned i;
+        int r;
 
         assert(name);
-        assert(_r);
+        assert(filename);
+        assert(ret);
 
         n = *name == '$' ? name + 1 : name;
 
         for (i = 0; i < ELEMENTSOF(table); i += 2) {
-
                 if (!streq(table[i], n))
                         continue;
 
                 if (!table[i+1])
                         return 0;
 
-                r = strdup(table[i+1]);
-                if (!r)
+                m = strdup(table[i+1]);
+                if (!m)
                         return log_oom();
 
-                goto finish;
+                *ret = m;
+                return 1;
+        }
+
+        /* If we don't know this name, fallback heuristics to figure
+         * out whether something is a target or a service alias. */
+
+        /* Facilities starting with $ are most likely targets */
+        if (*name == '$')  {
+                r = unit_name_build(n, NULL, ".target", ret);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to build name: %m");
+
+                return r;
         }
 
-        /* strip ".sh" suffix from file name for comparison */
+        /* Strip ".sh" suffix from file name for comparison */
         filename_no_sh = strdupa(filename);
         e = endswith(filename_no_sh, ".sh");
         if (e) {
@@ -313,103 +340,103 @@ static int sysv_translate_facility(const char *name, const char *filename, char
                 filename = filename_no_sh;
         }
 
-        /* If we don't know this name, fallback heuristics to figure
-         * out whether something is a target or a service alias. */
-
-        if (*name == '$') {
-                int k;
-
-                /* Facilities starting with $ are most likely targets */
-                k = unit_name_build(n, NULL, ".target", &r);
-                if (k < 0)
-                        return k;
-
-        } else if (streq_ptr(n, filename))
-                /* Names equaling the file name of the services are redundant */
+        /* Names equaling the file name of the services are redundant */
+        if (streq_ptr(n, filename))
                 return 0;
-        else
-                /* Everything else we assume to be normal service names */
-                r = sysv_translate_name(n);
-        if (!r)
-                return -ENOMEM;
 
-finish:
-        *_r = r;
+        /* Everything else we assume to be normal service names */
+        m = sysv_translate_name(n);
+        if (!m)
+                return log_oom();
 
+        *ret = m;
         return 1;
 }
 
 static int handle_provides(SysvStub *s, unsigned line, const char *full_text, const char *text) {
-        const char *word, *state_;
-        size_t z;
         int r;
 
-        FOREACH_WORD_QUOTED(word, z, text, state_) {
-                _cleanup_free_ char *n = NULL, *m = NULL;
-                UnitType t;
+        assert(s);
+        assert(full_text);
+        assert(text);
 
-                n = strndup(word, z);
-                if (!n)
-                        return log_oom();
+        for (;;) {
+                _cleanup_free_ char *word = NULL, *m = NULL;
 
-                r = sysv_translate_facility(n, basename(s->path), &m);
+                r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
                 if (r < 0)
-                        return r;
+                        return log_error_errno(r, "Failed to parse word from provides string: %m");
                 if (r == 0)
+                        break;
+
+                r = sysv_translate_facility(word, basename(s->path), &m);
+                if (r <= 0) /* continue on error */
                         continue;
 
-                t = unit_name_to_type(m);
-                if (t == UNIT_SERVICE) {
+                switch (unit_name_to_type(m)) {
+
+                case UNIT_SERVICE:
                         log_debug("Adding Provides: alias '%s' for '%s'", m, s->name);
                         r = add_alias(s->name, m);
                         if (r < 0)
                                 log_warning_errno(r, "[%s:%u] Failed to add LSB Provides name %s, ignoring: %m", s->path, line, m);
-                } else if (t == UNIT_TARGET) {
+                        break;
+
+                case UNIT_TARGET:
+
                         /* NB: SysV targets which are provided by a
                          * service are pulled in by the services, as
                          * an indication that the generic service is
                          * now available. This is strictly one-way.
                          * The targets do NOT pull in SysV services! */
+
                         r = strv_extend(&s->before, m);
                         if (r < 0)
                                 return log_oom();
+
                         r = strv_extend(&s->wants, m);
                         if (r < 0)
                                 return log_oom();
+
                         if (streq(m, SPECIAL_NETWORK_ONLINE_TARGET)) {
                                 r = strv_extend(&s->before, SPECIAL_NETWORK_TARGET);
                                 if (r < 0)
                                         return log_oom();
                         }
-                } else if (t == _UNIT_TYPE_INVALID)
+
+                        break;
+
+                case _UNIT_TYPE_INVALID:
                         log_warning("Unit name '%s' is invalid", m);
-                else
+                        break;
+
+                default:
                         log_warning("Unknown unit type for unit '%s'", m);
+                }
         }
-        if (!isempty(state_))
-                log_error("[%s:%u] Trailing garbage in Provides, ignoring.", s->path, line);
+
         return 0;
 }
 
 static int handle_dependencies(SysvStub *s, unsigned line, const char *full_text, const char *text) {
-        const char *word, *state_;
-        size_t z;
         int r;
 
-        FOREACH_WORD_QUOTED(word, z, text, state_) {
-                _cleanup_free_ char *n = NULL, *m = NULL;
-                bool is_before;
+        assert(s);
+        assert(full_text);
+        assert(text);
 
-                n = strndup(word, z);
-                if (!n)
-                        return log_oom();
+        for (;;) {
+                _cleanup_free_ char *word = NULL, *m = NULL;
+                bool is_before;
 
-                r = sysv_translate_facility(n, basename(s->path), &m);
-                if (r < 0) {
-                        log_warning_errno(r, "[%s:%u] Failed to translate LSB dependency %s, ignoring: %m", s->path, line, n);
-                        continue;
-                }
+                r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse word from provides string: %m");
                 if (r == 0)
+                        break;
+
+                r = sysv_translate_facility(word, basename(s->path), &m);
+                if (r <= 0) /* continue on error */
                         continue;
 
                 is_before = startswith_no_case(full_text, "X-Start-Before:");
@@ -419,15 +446,14 @@ static int handle_dependencies(SysvStub *s, unsigned line, const char *full_text
                         r = strv_extend(&s->after, m);
                         if (r < 0)
                                 return log_oom();
+
                         r = strv_extend(&s->wants, m);
                 } else
                         r = strv_extend(is_before ? &s->before : &s->after, m);
-
                 if (r < 0)
                         return log_oom();
         }
-        if (!isempty(state_))
-                log_warning("[%s:%u] Trailing garbage in %*s, ignoring.", s->path, line, (int)(strchr(full_text, ':') - full_text), full_text);
+
         return 0;
 }
 
@@ -445,24 +471,22 @@ static int load_sysv(SysvStub *s) {
         _cleanup_free_ char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL;
         char *description;
         bool supports_reload = false;
+        char l[LINE_MAX];
 
         assert(s);
 
         f = fopen(s->path, "re");
-        if (!f)
-                return errno == ENOENT ? 0 : -errno;
+        if (!f) {
+                if (errno == ENOENT)
+                        return 0;
 
-        log_debug("Loading SysV script %s", s->path);
+                return log_error_errno(errno, "Failed to open %s: %m", s->path);
+        }
 
-        while (!feof(f)) {
-                char l[LINE_MAX], *t;
+        log_debug("Loading SysV script %s", s->path);
 
-                if (!fgets(l, sizeof(l), f)) {
-                        if (feof(f))
-                                break;
-
-                        return log_error_errno(errno, "Failed to read configuration file '%s': %m", s->path);
-                }
+        FOREACH_LINE(l, f, goto fail) {
+                char *t;
 
                 line++;
 
@@ -505,29 +529,25 @@ static int load_sysv(SysvStub *s) {
 
                         if (startswith_no_case(t, "description:")) {
 
-                                size_t k = strlen(t);
-                                char *d;
-                                const char *j;
+                                size_t k;
+                                const const char *j;
 
-                                if (t[k-1] == '\\') {
+                                k = strlen(t);
+                                if (k > 0 && t[k-1] == '\\') {
                                         state = DESCRIPTION;
                                         t[k-1] = 0;
                                 }
 
                                 j = strstrip(t+12);
-                                if (j && *j) {
-                                        d = strdup(j);
-                                        if (!d)
-                                                return -ENOMEM;
-                                } else
-                                        d = NULL;
+                                if (isempty(j))
+                                        j = NULL;
 
-                                free(chkconfig_description);
-                                chkconfig_description = d;
+                                r = free_and_strdup(&chkconfig_description, j);
+                                if (r < 0)
+                                        return log_oom();
 
                         } else if (startswith_no_case(t, "pidfile:")) {
-
-                                char *fn;
+                                const char *fn;
 
                                 state = NORMAL;
 
@@ -537,12 +557,9 @@ static int load_sysv(SysvStub *s) {
                                         continue;
                                 }
 
-                                fn = strdup(fn);
-                                if (!fn)
-                                        return -ENOMEM;
-
-                                free(s->pid_file);
-                                s->pid_file = fn;
+                                r = free_and_strdup(&s->pid_file, fn);
+                                if (r < 0)
+                                        return log_oom();
                         }
 
                 } else if (state == DESCRIPTION) {
@@ -550,25 +567,25 @@ static int load_sysv(SysvStub *s) {
                         /* Try to parse Red Hat style description
                          * continuation */
 
-                        size_t k = strlen(t);
+                        size_t k;
                         char *j;
 
-                        if (t[k-1] == '\\')
+                        k = strlen(t);
+                        if (k > 0 && t[k-1] == '\\')
                                 t[k-1] = 0;
                         else
                                 state = NORMAL;
 
                         j = strstrip(t);
-                        if (j && *j) {
+                        if (!isempty(j)) {
                                 char *d = NULL;
 
                                 if (chkconfig_description)
                                         d = strjoin(chkconfig_description, " ", j, NULL);
                                 else
                                         d = strdup(j);
-
                                 if (!d)
-                                        return -ENOMEM;
+                                        return log_oom();
 
                                 free(chkconfig_description);
                                 chkconfig_description = d;
@@ -582,6 +599,7 @@ static int load_sysv(SysvStub *s) {
                                 r = handle_provides(s, line, t, t + 9);
                                 if (r < 0)
                                         return r;
+
                         } else if (startswith_no_case(t, "Required-Start:") ||
                                    startswith_no_case(t, "Should-Start:") ||
                                    startswith_no_case(t, "X-Start-Before:") ||
@@ -593,55 +611,47 @@ static int load_sysv(SysvStub *s) {
                                 if (r < 0)
                                         return r;
 
-
                         } else if (startswith_no_case(t, "Description:")) {
-                                char *d, *j;
+                                const char *j;
 
                                 state = LSB_DESCRIPTION;
 
                                 j = strstrip(t+12);
-                                if (j && *j) {
-                                        d = strdup(j);
-                                        if (!d)
-                                                return -ENOMEM;
-                                } else
-                                        d = NULL;
+                                if (isempty(j))
+                                        j = NULL;
 
-                                free(long_description);
-                                long_description = d;
+                                r = free_and_strdup(&long_description, j);
+                                if (r < 0)
+                                        return log_oom();
 
                         } else if (startswith_no_case(t, "Short-Description:")) {
-                                char *d, *j;
+                                const char *j;
 
                                 state = LSB;
 
                                 j = strstrip(t+18);
-                                if (j && *j) {
-                                        d = strdup(j);
-                                        if (!d)
-                                                return -ENOMEM;
-                                } else
-                                        d = NULL;
+                                if (isempty(j))
+                                        j = NULL;
 
-                                free(short_description);
-                                short_description = d;
+                                r = free_and_strdup(&short_description, j);
+                                if (r < 0)
+                                        return log_oom();
 
                         } else if (state == LSB_DESCRIPTION) {
 
                                 if (startswith(l, "#\t") || startswith(l, "#  ")) {
-                                        char *j;
+                                        const char *j;
 
                                         j = strstrip(t);
-                                        if (j && *j) {
+                                        if (!isempty(j)) {
                                                 char *d = NULL;
 
                                                 if (long_description)
                                                         d = strjoin(long_description, " ", t, NULL);
                                                 else
                                                         d = strdup(j);
-
                                                 if (!d)
-                                                        return -ENOMEM;
+                                                        return log_oom();
 
                                                 free(long_description);
                                                 long_description = d;
@@ -672,12 +682,16 @@ static int load_sysv(SysvStub *s) {
 
                 d = strappend(s->has_lsb ? "LSB: " : "SYSV: ", description);
                 if (!d)
-                        return -ENOMEM;
+                        return log_oom();
 
                 s->description = d;
         }
 
+        s->loaded = true;
         return 0;
+
+fail:
+        return log_error_errno(errno, "Failed to read configuration file '%s': %m", s->path);
 }
 
 static int fix_order(SysvStub *s, Hashmap *all_services) {
@@ -687,6 +701,9 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
 
         assert(s);
 
+        if (!s->loaded)
+                return 0;
+
         if (s->sysv_start_priority < 0)
                 return 0;
 
@@ -694,6 +711,9 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
                 if (s == other)
                         continue;
 
+                if (!other->loaded)
+                        continue;
+
                 if (other->sysv_start_priority < 0)
                         continue;
 
@@ -706,13 +726,12 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
                         r = strv_extend(&s->after, other->name);
                         if (r < 0)
                                 return log_oom();
-                }
-                else if (other->sysv_start_priority > s->sysv_start_priority) {
+
+                else if (other->sysv_start_priority > s->sysv_start_priority) {
                         r = strv_extend(&s->before, other->name);
                         if (r < 0)
                                 return log_oom();
-                }
-                else
+                } else
                         continue;
 
                 /* FIXME: Maybe we should compare the name here lexicographically? */
@@ -724,6 +743,9 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
 static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
         char **path;
 
+        assert(lp);
+        assert(all_services);
+
         STRV_FOREACH(path, lp->sysvinit_path) {
                 _cleanup_closedir_ DIR *d = NULL;
                 struct dirent *de;
@@ -731,21 +753,18 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
                 d = opendir(*path);
                 if (!d) {
                         if (errno != ENOENT)
-                                log_warning_errno(errno, "opendir(%s) failed: %m", *path);
+                                log_warning_errno(errno, "Opening %s failed, ignoring: %m", *path);
                         continue;
                 }
 
-                while ((de = readdir(d))) {
+                FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", *path)) {
                         _cleanup_free_ char *fpath = NULL, *name = NULL;
                         _cleanup_(free_sysvstubp) SysvStub *service = NULL;
                         struct stat st;
                         int r;
 
-                        if (hidden_file(de->d_name))
-                                continue;
-
                         if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) {
-                                log_warning_errno(errno, "stat() failed on %s/%s: %m", *path, de->d_name);
+                                log_warning_errno(errno, "stat() failed on %s/%s, ignoring: %m", *path, de->d_name);
                                 continue;
                         }
 
@@ -762,15 +781,15 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
                         if (hashmap_contains(all_services, name))
                                 continue;
 
-                        fpath = strjoin(*path, "/", de->d_name, NULL);
-                        if (!fpath)
-                                return log_oom();
-
                         if (unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name) >= 0) {
                                 log_debug("Native unit for %s already exists, skipping", name);
                                 continue;
                         }
 
+                        fpath = strjoin(*path, "/", de->d_name, NULL);
+                        if (!fpath)
+                                return log_oom();
+
                         service = new0(SysvStub, 1);
                         if (!service)
                                 return log_oom();
@@ -778,12 +797,12 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
                         service->sysv_start_priority = -1;
                         service->name = name;
                         service->path = fpath;
+                        name = fpath = NULL;
 
                         r = hashmap_put(all_services, service->name, service);
                         if (r < 0)
                                 return log_oom();
 
-                        name = fpath = NULL;
                         service = NULL;
                 }
         }
@@ -792,43 +811,41 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
 }
 
 static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) {
-        char **p;
-        unsigned i;
-        _cleanup_closedir_ DIR *d = NULL;
-        _cleanup_free_ char *path = NULL, *fpath = NULL;
-        SysvStub *service;
-        Iterator j;
         Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {};
         _cleanup_set_free_ Set *shutdown_services = NULL;
-        int r = 0;
+        SysvStub *service;
+        unsigned i;
+        Iterator j;
+        char **p;
+        int r;
 
-        STRV_FOREACH(p, lp->sysvrcnd_path)
+        assert(lp);
+
+        STRV_FOREACH(p, lp->sysvrcnd_path) {
                 for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
+
+                        _cleanup_closedir_ DIR *d = NULL;
+                        _cleanup_free_ char *path = NULL;
                         struct dirent *de;
 
-                        free(path);
                         path = strjoin(*p, "/", rcnd_table[i].path, NULL);
-                        if (!path)
-                                return -ENOMEM;
-
-                        safe_closedir(d);
+                        if (!path) {
+                                r = log_oom();
+                                goto finish;
+                        }
 
                         d = opendir(path);
                         if (!d) {
                                 if (errno != ENOENT)
-                                        log_warning_errno(errno, "opendir(%s) failed: %m", path);
+                                        log_warning_errno(errno, "Opening %s failed, ignoring: %m", path);
 
                                 continue;
                         }
 
-                        while ((de = readdir(d))) {
-                                _cleanup_free_ char *name = NULL;
-
+                        FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", path)) {
+                                _cleanup_free_ char *name = NULL, *fpath = NULL;
                                 int a, b;
 
-                                if (hidden_file(de->d_name))
-                                        continue;
-
                                 if (de->d_name[0] != 'S' && de->d_name[0] != 'K')
                                         continue;
 
@@ -841,10 +858,9 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
                                 if (a < 0 || b < 0)
                                         continue;
 
-                                free(fpath);
                                 fpath = strjoin(*p, "/", de->d_name, NULL);
                                 if (!fpath) {
-                                        r = -ENOMEM;
+                                        r = log_oom();
                                         goto finish;
                                 }
 
@@ -856,64 +872,77 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
 
                                 service = hashmap_get(all_services, name);
                                 if (!service){
-                                        log_debug("Ignoring %s symlink in %s, not generating %s.",
-                                                  de->d_name, rcnd_table[i].path, name);
+                                        log_debug("Ignoring %s symlink in %s, not generating %s.", de->d_name, rcnd_table[i].path, name);
                                         continue;
                                 }
 
                                 if (de->d_name[0] == 'S')  {
 
-                                        if (rcnd_table[i].type == RUNLEVEL_UP) {
-                                                service->sysv_start_priority =
-                                                        MAX(a*10 + b, service->sysv_start_priority);
-                                        }
+                                        if (rcnd_table[i].type == RUNLEVEL_UP)
+                                                service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority);
 
                                         r = set_ensure_allocated(&runlevel_services[i], NULL);
-                                        if (r < 0)
+                                        if (r < 0) {
+                                                log_oom();
                                                 goto finish;
+                                        }
 
                                         r = set_put(runlevel_services[i], service);
-                                        if (r < 0)
+                                        if (r < 0) {
+                                                log_oom();
                                                 goto finish;
+                                        }
 
                                 } else if (de->d_name[0] == 'K' &&
                                            (rcnd_table[i].type == RUNLEVEL_DOWN)) {
 
                                         r = set_ensure_allocated(&shutdown_services, NULL);
-                                        if (r < 0)
+                                        if (r < 0) {
+                                                log_oom();
                                                 goto finish;
+                                        }
 
                                         r = set_put(shutdown_services, service);
-                                        if (r < 0)
+                                        if (r < 0) {
+                                                log_oom();
                                                 goto finish;
+                                        }
                                 }
                         }
                 }
+        }
 
 
         for (i = 0; i < ELEMENTSOF(rcnd_table); i ++)
                 SET_FOREACH(service, runlevel_services[i], j) {
                         r = strv_extend(&service->before, rcnd_table[i].target);
-                        if (r < 0)
-                                return log_oom();
+                        if (r < 0) {
+                                log_oom();
+                                goto finish;
+                        }
                         r = strv_extend(&service->wanted_by, rcnd_table[i].target);
-                        if (r < 0)
-                                return log_oom();
+                        if (r < 0) {
+                                log_oom();
+                                goto finish;
+                        }
                 }
 
         SET_FOREACH(service, shutdown_services, j) {
                 r = strv_extend(&service->before, SPECIAL_SHUTDOWN_TARGET);
-                if (r < 0)
-                        return log_oom();
+                if (r < 0) {
+                        log_oom();
+                        goto finish;
+                }
                 r = strv_extend(&service->conflicts, SPECIAL_SHUTDOWN_TARGET);
-                if (r < 0)
-                        return log_oom();
+                if (r < 0) {
+                        log_oom();
+                        goto finish;
+                }
         }
 
         r = 0;
 
 finish:
-
         for (i = 0; i < ELEMENTSOF(rcnd_table); i++)
                 set_free(runlevel_services[i]);
 
@@ -921,11 +950,11 @@ finish:
 }
 
 int main(int argc, char *argv[]) {
-        int r, q;
-        _cleanup_lookup_paths_free_ LookupPaths lp = {};
         _cleanup_(free_sysvstub_hashmapp) Hashmap *all_services = NULL;
+        _cleanup_lookup_paths_free_ LookupPaths lp = {};
         SysvStub *service;
         Iterator j;
+        int r;
 
         if (argc > 1 && argc != 4) {
                 log_error("This program takes three or no arguments.");
@@ -943,43 +972,34 @@ int main(int argc, char *argv[]) {
 
         r = lookup_paths_init(&lp, MANAGER_SYSTEM, true, NULL, NULL, NULL, NULL);
         if (r < 0) {
-                log_error("Failed to find lookup paths.");
-                return EXIT_FAILURE;
+                log_error_errno(r, "Failed to find lookup paths: %m");
+                goto finish;
         }
 
         all_services = hashmap_new(&string_hash_ops);
         if (!all_services) {
-                log_oom();
-                return EXIT_FAILURE;
+                r = log_oom();
+                goto finish;
         }
 
         r = enumerate_sysv(&lp, all_services);
-        if (r < 0) {
-                log_error("Failed to generate units for all init scripts.");
-                return EXIT_FAILURE;
-        }
+        if (r < 0)
+                goto finish;
 
         r = set_dependencies_from_rcnd(&lp, all_services);
-        if (r < 0) {
-                log_error("Failed to read runlevels from rcnd links.");
-                return EXIT_FAILURE;
-        }
+        if (r < 0)
+                goto finish;
 
-        HASHMAP_FOREACH(service, all_services, j) {
-                q = load_sysv(service);
-                if (q < 0)
-                        continue;
-        }
+        HASHMAP_FOREACH(service, all_services, j)
+                (void) load_sysv(service);
 
         HASHMAP_FOREACH(service, all_services, j) {
-                q = fix_order(service, all_services);
-                if (q < 0)
-                        continue;
-
-                q = generate_unit_file(service);
-                if (q < 0)
-                        continue;
+                (void) fix_order(service, all_services);
+                (void) generate_unit_file(service);
         }
 
-        return EXIT_SUCCESS;
+        r = 0;
+
+finish:
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
index 92ffa65925736d385b357a1bcd47c760b9a2aa59..65cb894ff7df5a8bbf2e1b620f85c9260bb6de2d 100644 (file)
@@ -19,6 +19,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <stdlib.h>
 #include <sys/stat.h>
 
 #include "log.h"
 static void test_paths(ManagerRunningAs running_as, bool personal) {
         char template[] = "/tmp/test-path-lookup.XXXXXXX";
 
-        _cleanup_lookup_paths_free_ LookupPaths lp = {};
-        char *exists, *not;
+        _cleanup_lookup_paths_free_ LookupPaths lp_without_env = {};
+        _cleanup_lookup_paths_free_ LookupPaths lp_with_env = {};
+        char *exists, *not, *systemd_unit_path;
 
         assert_se(mkdtemp(template));
         exists = strjoina(template, "/exists");
         assert_se(mkdir(exists, 0755) == 0);
         not = strjoina(template, "/not");
 
-        assert_se(lookup_paths_init(&lp, running_as, personal, NULL, exists, not, not) == 0);
+        assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0);
+        assert_se(lookup_paths_init(&lp_without_env, running_as, personal, NULL, exists, not, not) == 0);
 
-        assert_se(!strv_isempty(lp.unit_path));
-        assert_se(strv_contains(lp.unit_path, exists));
-        assert_se(strv_contains(lp.unit_path, not));
+        assert_se(!strv_isempty(lp_without_env.unit_path));
+        assert_se(strv_contains(lp_without_env.unit_path, exists));
+        assert_se(strv_contains(lp_without_env.unit_path, not));
+
+        systemd_unit_path = strjoina(template, "/systemd-unit-path");
+        assert_se(setenv("SYSTEMD_UNIT_PATH", systemd_unit_path, 1) == 0);
+        assert_se(lookup_paths_init(&lp_with_env, running_as, personal, NULL, exists, not, not) == 0);
+        assert_se(strv_length(lp_with_env.unit_path) == 1);
+        assert_se(streq(lp_with_env.unit_path[0], systemd_unit_path));
 
         assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
 }
index a2ca391e1ac6bdca77e2f0ee40136683e8c1a59c..f9107e0d0dbf127047111b286f02aea030524643 100644 (file)
@@ -672,6 +672,13 @@ static void test_config_parse_bounding_set(void) {
                               &capability_bounding_set_drop, NULL);
         assert_se(r >= 0);
         assert_se(capability_bounding_set_drop == (uint64_t) 0ULL);
+
+        capability_bounding_set_drop = 0;
+        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+                              "CapabilityBoundingSet", 0, "  'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage",
+                              &capability_bounding_set_drop, NULL);
+        assert_se(r >= 0);
+        assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
 }
 
 int main(int argc, char *argv[]) {
index def151bb849812297c01f27be61f01b7e52e034a..2097551c33d83c915f2580abdcf0845470d1f2b8 100644 (file)
@@ -35,6 +35,9 @@ net.ipv4.conf.all.promote_secondaries = 1
 # Fair Queue CoDel packet scheduler to fight bufferbloat
 net.core.default_qdisc = fq_codel
 
+# Make sure we can queue more than just a few datagrams in AF_UNIX sockets.
+net.unix.max_dgram_qlen = 512
+
 # Enable hard and soft link protection
 fs.protected_hardlinks = 1
 fs.protected_symlinks = 1
index 41bfde5be3c5d814e39a7d0858afdfe0652d3927..2552102bfca0246e9b190754db7e04cbaf16fb0f 100644 (file)
@@ -22,7 +22,6 @@ RestartSec=0
 NotifyAccess=all
 StandardOutput=null
 CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID CAP_MAC_OVERRIDE
-WatchdogSec=3min
 FileDescriptorStoreMax=1024
 
 # Increase the default a bit in order to allow many simultaneous