Exemplo n.º 1
0
static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
        Scope *s = SCOPE(u);

        assert(u);
        assert(key);
        assert(value);
        assert(fds);

        if (streq(key, "state")) {
                ScopeState state;

                state = scope_state_from_string(value);
                if (state < 0)
                        log_unit_debug(u, "Failed to parse state value: %s", value);
                else
                        s->deserialized_state = state;

        } else if (streq(key, "was-abandoned")) {
                int k;

                k = parse_boolean(value);
                if (k < 0)
                        log_unit_debug(u, "Failed to parse boolean value: %s", value);
                else
                        s->was_abandoned = k;
        } else
                log_unit_debug(u, "Unknown serialization key: %s", key);

        return 0;
}
static int busname_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
        BusName *n = BUSNAME(u);

        assert(n);
        assert(key);
        assert(value);

        if (streq(key, "state")) {
                BusNameState state;

                state = busname_state_from_string(value);
                if (state < 0)
                        log_unit_debug(u->id, "Failed to parse state value %s", value);
                else
                        n->deserialized_state = state;

        } else if (streq(key, "result")) {
                BusNameResult f;

                f = busname_result_from_string(value);
                if (f < 0)
                        log_unit_debug(u->id, "Failed to parse result value %s", value);
                else if (f != BUSNAME_SUCCESS)
                        n->result = f;

        } else if (streq(key, "control-pid")) {
                pid_t pid;

                if (parse_pid(value, &pid) < 0)
                        log_unit_debug(u->id, "Failed to parse control-pid value %s", value);
                else
                        n->control_pid = pid;
        } else if (streq(key, "starter-fd")) {
                int fd;

                if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
                        log_unit_debug(u->id, "Failed to parse starter fd value %s", value);
                else {
                        safe_close(n->starter_fd);
                        n->starter_fd = fdset_remove(fds, fd);
                }
        } else
                log_unit_debug(u->id, "Unknown serialization key '%s'", key);

        return 0;
}
Exemplo n.º 3
0
static void scope_notify_cgroup_empty_event(Unit *u) {
        Scope *s = SCOPE(u);
        assert(u);

        log_unit_debug(u, "cgroup is empty");

        if (IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
                scope_enter_dead(s, SCOPE_SUCCESS);
}
Exemplo n.º 4
0
static void automount_enter_running(Automount *a) {
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
        Unit *trigger;
        struct stat st;
        int r;

        assert(a);

        /* If the user masked our unit in the meantime, fail */
        if (UNIT(a)->load_state != UNIT_LOADED) {
                log_unit_error(UNIT(a), "Suppressing automount event since unit is no longer loaded.");
                goto fail;
        }

        /* We don't take mount requests anymore if we are supposed to
         * shut down anyway */
        if (unit_stop_pending(UNIT(a))) {
                log_unit_debug(UNIT(a), "Suppressing automount request since unit stop is scheduled.");
                automount_send_ready(a, a->tokens, -EHOSTDOWN);
                automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
                return;
        }

        mkdir_p_label(a->where, a->directory_mode);

        /* Before we do anything, let's see if somebody is playing games with us? */
        if (lstat(a->where, &st) < 0) {
                log_unit_warning_errno(UNIT(a), errno, "Failed to stat automount point: %m");
                goto fail;
        }

        /* The mount unit may have been explicitly started before we got the
         * autofs request. Ack it to unblock anything waiting on the mount point. */
        if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) {
                log_unit_info(UNIT(a), "Automount point already active?");
                automount_send_ready(a, a->tokens, 0);
                return;
        }

        trigger = UNIT_TRIGGER(UNIT(a));
        if (!trigger) {
                log_unit_error(UNIT(a), "Unit to trigger vanished.");
                goto fail;
        }

        r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
        if (r < 0) {
                log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
                goto fail;
        }

        automount_set_state(a, AUTOMOUNT_RUNNING);
        return;

fail:
        automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
}
static void busname_unwatch_fd(BusName *n) {
        int r;

        assert(n);

        if (!n->starter_event_source)
                return;

        r = sd_event_source_set_enabled(n->starter_event_source, SD_EVENT_OFF);
        if (r < 0)
                log_unit_debug(UNIT(n)->id, "Failed to disable event source.");
}
Exemplo n.º 6
0
static int device_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
        Device *d = DEVICE(u);

        assert(u);
        assert(key);
        assert(value);
        assert(fds);

        if (streq(key, "state")) {
                DeviceState state;

                state = device_state_from_string(value);
                if (state < 0)
                        log_unit_debug(u, "Failed to parse state value: %s", value);
                else
                        d->deserialized_state = state;
        } else
                log_unit_debug(u, "Unknown serialization key: %s", key);

        return 0;
}
Exemplo n.º 7
0
static void device_set_state(Device *d, DeviceState state) {
        DeviceState old_state;
        assert(d);

        old_state = d->state;
        d->state = state;

        if (state != old_state)
                log_unit_debug(UNIT(d), "Changed %s -> %s", device_state_to_string(old_state), device_state_to_string(state));

        unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], true);
}
Exemplo n.º 8
0
static void busname_enter_running(BusName *n) {
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
        bool pending = false;
        Unit *other;
        Iterator i;
        int r;

        assert(n);

        if (!n->activating)
                return;

        /* We don't take connections anymore if we are supposed to
         * shut down anyway */

        if (unit_stop_pending(UNIT(n))) {
                log_unit_debug(UNIT(n), "Suppressing activation request since unit stop is scheduled.");

                /* Flush all queued activation reqeuest by closing and reopening the connection */
                bus_kernel_drop_one(n->starter_fd);

                busname_enter_listening(n);
                return;
        }

        /* If there's already a start pending don't bother to do
         * anything */
        SET_FOREACH(other, UNIT(n)->dependencies[UNIT_TRIGGERS], i)
                if (unit_active_or_pending(other)) {
                        pending = true;
                        break;
                }

        if (!pending) {
                if (!UNIT_ISSET(n->service)) {
                        log_unit_error(UNIT(n), "Service to activate vanished, refusing activation.");
                        r = -ENOENT;
                        goto fail;
                }

                r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, &error, NULL);
                if (r < 0)
                        goto fail;
        }

        busname_set_state(n, BUSNAME_RUNNING);
        return;

fail:
        log_unit_warning(UNIT(n), "Failed to queue service startup job: %s", bus_error_message(&error, r));
        busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
}
Exemplo n.º 9
0
static int on_controller_gone(sd_bus_track *track, void *userdata) {
        Scope *s = userdata;

        assert(track);

        if (s->controller) {
                log_unit_debug(UNIT(s), "Controller %s disappeared from bus.", s->controller);
                unit_add_to_dbus_queue(UNIT(s));
                s->controller = mfree(s->controller);
        }

        s->controller_track = sd_bus_track_unref(s->controller_track);

        return 0;
}
Exemplo n.º 10
0
static void automount_set_state(Automount *a, AutomountState state) {
        AutomountState old_state;
        assert(a);

        old_state = a->state;
        a->state = state;

        if (state != AUTOMOUNT_WAITING &&
            state != AUTOMOUNT_RUNNING)
                unmount_autofs(a);

        if (state != old_state)
                log_unit_debug(UNIT(a), "Changed %s -> %s", automount_state_to_string(old_state), automount_state_to_string(state));

        unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], true);
}
Exemplo n.º 11
0
static int device_setup_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
        _cleanup_free_ char *e = NULL;
        const char *sysfs = NULL;
        Unit *u = NULL;
        bool delete;
        int r;

        assert(m);
        assert(path);

        if (dev) {
                sysfs = udev_device_get_syspath(dev);
                if (!sysfs)
                        return 0;
        }

        r = unit_name_from_path(path, ".device", &e);
        if (r < 0)
                return log_error_errno(r, "Failed to generate unit name from device path: %m");

        u = manager_get_unit(m, e);

        /* The device unit can still be present even if the device was
         * unplugged: a mount unit can reference it hence preventing
         * the GC to have garbaged it. That's desired since the device
         * unit may have a dependency on the mount unit which was
         * added during the loading of the later. */
        if (dev && u && DEVICE(u)->state == DEVICE_PLUGGED) {
                /* This unit is in plugged state: we're sure it's
                 * attached to a device. */
                if (!path_equal(DEVICE(u)->sysfs, sysfs)) {
                        log_unit_debug(u, "Dev %s appeared twice with different sysfs paths %s and %s",
                                       e, DEVICE(u)->sysfs, sysfs);
                        return -EEXIST;
                }
        }

        if (!u) {
                delete = true;

                r = unit_new_for_name(m, sizeof(Device), e, &u);
                if (r < 0)
                        goto fail;

                unit_add_to_load_queue(u);
        } else
Exemplo n.º 12
0
static void automount_enter_runnning(Automount *a) {
        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
        struct stat st;
        int r;

        assert(a);

        /* We don't take mount requests anymore if we are supposed to
         * shut down anyway */
        if (unit_stop_pending(UNIT(a))) {
                log_unit_debug(UNIT(a), "Suppressing automount request since unit stop is scheduled.");
                automount_send_ready(a, a->tokens, -EHOSTDOWN);
                automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
                return;
        }

        mkdir_p_label(a->where, a->directory_mode);

        /* Before we do anything, let's see if somebody is playing games with us? */
        if (lstat(a->where, &st) < 0) {
                log_unit_warning_errno(UNIT(a), errno, "Failed to stat automount point: %m");
                goto fail;
        }

        if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
                log_unit_info(UNIT(a), "Automount point already active?");
        else {
                r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)),
                                    JOB_REPLACE, true, &error, NULL);
                if (r < 0) {
                        log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
                        goto fail;
                }
        }

        automount_set_state(a, AUTOMOUNT_RUNNING);
        return;

fail:
        automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
}
Exemplo n.º 13
0
static int automount_send_ready(Automount *a, Set *tokens, int status) {
        _cleanup_close_ int ioctl_fd = -1;
        unsigned token;
        int r;

        assert(a);
        assert(status <= 0);

        if (set_isempty(tokens))
                return 0;

        ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
        if (ioctl_fd < 0)
                return ioctl_fd;

        if (status != 0)
                log_unit_debug_errno(UNIT(a), status, "Sending failure: %m");
        else
                log_unit_debug(UNIT(a), "Sending success.");

        r = 0;

        /* Autofs thankfully does not hand out 0 as a token */
        while ((token = PTR_TO_UINT(set_steal_first(tokens)))) {
                int k;

                /* Autofs fun fact II:
                 *
                 * if you pass a positive status code here, the kernel will
                 * freeze! Yay! */

                k = autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
                                      ioctl_fd,
                                      token,
                                      status);
                if (k < 0)
                        r = k;
        }

        return r;
}
Exemplo n.º 14
0
static void busname_set_state(BusName *n, BusNameState state) {
        BusNameState old_state;
        assert(n);

        old_state = n->state;
        n->state = state;

        if (!IN_SET(state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) {
                n->timer_event_source = sd_event_source_unref(n->timer_event_source);
                busname_unwatch_control_pid(n);
        }

        if (state != BUSNAME_LISTENING)
                busname_unwatch_fd(n);

        if (!IN_SET(state, BUSNAME_LISTENING, BUSNAME_MAKING, BUSNAME_REGISTERED, BUSNAME_RUNNING))
                busname_close_fd(n);

        if (state != old_state)
                log_unit_debug(UNIT(n), "Changed %s -> %s", busname_state_to_string(old_state), busname_state_to_string(state));

        unit_notify(UNIT(n), state_translation_table[old_state], state_translation_table[state], true);
}
static int busname_peek_message(BusName *n) {
        struct kdbus_cmd_recv cmd_recv = {
                .size = sizeof(cmd_recv),
                .flags = KDBUS_RECV_PEEK,
        };
        struct kdbus_cmd_free cmd_free = {
                .size = sizeof(cmd_free),
        };
        const char *comm = NULL;
        struct kdbus_item *d;
        struct kdbus_msg *k;
        size_t start, ps, sz, delta;
        void *p = NULL;
        pid_t pid = 0;
        int r;

        /* Generate a friendly debug log message about which process
         * caused triggering of this bus name. This simply peeks the
         * metadata of the first queued message and logs it. */

        assert(n);

        /* Let's shortcut things a bit, if debug logging is turned off
         * anyway. */

        if (log_get_max_level() < LOG_DEBUG)
                return 0;

        r = ioctl(n->starter_fd, KDBUS_CMD_RECV, &cmd_recv);
        if (r < 0) {
                if (errno == EINTR || errno == EAGAIN)
                        return 0;

                log_unit_error(UNIT(n)->id, "%s: Failed to query activation message: %m", UNIT(n)->id);
                return -errno;
        }

        /* We map as late as possible, and unmap imemdiately after
         * use. On 32bit address space is scarce and we want to be
         * able to handle a lot of activator connections at the same
         * time, and hence shouldn't keep the mmap()s around for
         * longer than necessary. */

        ps = page_size();
        start = (cmd_recv.msg.offset / ps) * ps;
        delta = cmd_recv.msg.offset - start;
        sz = PAGE_ALIGN(delta + cmd_recv.msg.msg_size);

        p = mmap(NULL, sz, PROT_READ, MAP_SHARED, n->starter_fd, start);
        if (p == MAP_FAILED) {
                log_unit_error(UNIT(n)->id, "%s: Failed to map activation message: %m", UNIT(n)->id);
                r = -errno;
                goto finish;
        }

        k = (struct kdbus_msg *) ((uint8_t *) p + delta);
        KDBUS_ITEM_FOREACH(d, k, items) {
                switch (d->type) {

                case KDBUS_ITEM_PIDS:
                        pid = d->pids.pid;
                        break;

                case KDBUS_ITEM_PID_COMM:
                        comm = d->str;
                        break;
                }
        }

        if (pid > 0)
                log_unit_debug(UNIT(n)->id, "%s: Activation triggered by process " PID_FMT " (%s)", UNIT(n)->id, pid, strna(comm));

        r = 0;

finish:
        if (p)
                (void) munmap(p, sz);

        cmd_free.offset = cmd_recv.msg.offset;
        if (ioctl(n->starter_fd, KDBUS_CMD_FREE, &cmd_free) < 0)
                log_unit_warning(UNIT(n)->id, "Failed to free peeked message, ignoring: %m");

        return r;
}

static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
        BusName *n = userdata;

        assert(n);
        assert(fd >= 0);

        if (n->state != BUSNAME_LISTENING)
                return 0;

        log_unit_debug(UNIT(n)->id, "Activation request on %s", UNIT(n)->id);

        if (revents != EPOLLIN) {
                log_unit_error(UNIT(n)->id, "%s: Got unexpected poll event (0x%x) on starter fd.",
                               UNIT(n)->id, revents);
                goto fail;
        }

        busname_peek_message(n);
        busname_enter_running(n);
        return 0;
fail:

        busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
        return 0;
}

static void busname_sigchld_event(Unit *u, pid_t pid, int code, int status) {
        BusName *n = BUSNAME(u);
        BusNameResult f;

        assert(n);
        assert(pid >= 0);

        if (pid != n->control_pid)
                return;

        n->control_pid = 0;

        if (is_clean_exit(code, status, NULL))
                f = BUSNAME_SUCCESS;
        else if (code == CLD_EXITED)
                f = BUSNAME_FAILURE_EXIT_CODE;
        else if (code == CLD_KILLED)
                f = BUSNAME_FAILURE_SIGNAL;
        else if (code == CLD_DUMPED)
                f = BUSNAME_FAILURE_CORE_DUMP;
        else
                assert_not_reached("Unknown sigchld code");

        log_unit_full(u->id,
                      f == BUSNAME_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
                      "%s control process exited, code=%s status=%i",
                      u->id, sigchld_code_to_string(code), status);

        if (f != BUSNAME_SUCCESS)
                n->result = f;

        switch (n->state) {

        case BUSNAME_MAKING:
                if (f == BUSNAME_SUCCESS)
                        busname_enter_listening(n);
                else
                        busname_enter_signal(n, BUSNAME_SIGTERM, f);
                break;

        case BUSNAME_SIGTERM:
        case BUSNAME_SIGKILL:
                busname_enter_dead(n, f);
                break;

        default:
                assert_not_reached("Uh, control process died at wrong time.");
        }

        /* Notify clients about changed exit status */
        unit_add_to_dbus_queue(u);
}
Exemplo n.º 16
0
static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) {
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
        union autofs_v5_packet_union packet;
        Automount *a = AUTOMOUNT(userdata);
        struct stat st;
        Unit *trigger;
        int r;

        assert(a);
        assert(fd == a->pipe_fd);

        if (events != EPOLLIN) {
                log_unit_error(UNIT(a), "Got invalid poll event %"PRIu32" on pipe (fd=%d)", events, fd);
                goto fail;
        }

        r = loop_read_exact(a->pipe_fd, &packet, sizeof(packet), true);
        if (r < 0) {
                log_unit_error_errno(UNIT(a), r, "Invalid read from pipe: %m");
                goto fail;
        }

        switch (packet.hdr.type) {

        case autofs_ptype_missing_direct:

                if (packet.v5_packet.pid > 0) {
                        _cleanup_free_ char *p = NULL;

                        get_process_comm(packet.v5_packet.pid, &p);
                        log_unit_info(UNIT(a), "Got automount request for %s, triggered by %"PRIu32" (%s)", a->where, packet.v5_packet.pid, strna(p));
                } else
                        log_unit_debug(UNIT(a), "Got direct mount request on %s", a->where);

                r = set_ensure_allocated(&a->tokens, NULL);
                if (r < 0) {
                        log_unit_error(UNIT(a), "Failed to allocate token set.");
                        goto fail;
                }

                r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
                if (r < 0) {
                        log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
                        goto fail;
                }

                automount_enter_runnning(a);
                break;

        case autofs_ptype_expire_direct:
                log_unit_debug(UNIT(a), "Got direct umount request on %s", a->where);

                automount_stop_expire(a);

                r = set_ensure_allocated(&a->expire_tokens, NULL);
                if (r < 0) {
                        log_unit_error(UNIT(a), "Failed to allocate token set.");
                        goto fail;
                }

                r = set_put(a->expire_tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
                if (r < 0) {
                        log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
                        goto fail;
                }

                /* Before we do anything, let's see if somebody is playing games with us? */
                if (lstat(a->where, &st) < 0) {
                        log_unit_warning_errno(UNIT(a), errno, "Failed to stat automount point: %m");
                        goto fail;
                }

                if (!S_ISDIR(st.st_mode) || st.st_dev == a->dev_id) {
                        log_unit_info(UNIT(a), "Automount point already unmounted?");
                        automount_send_ready(a, a->expire_tokens, 0);
                        break;
                }

                trigger = UNIT_TRIGGER(UNIT(a));
                if (!trigger) {
                        log_unit_error(UNIT(a), "Unit to trigger vanished.");
                        goto fail;
                }

                r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, &error, NULL);
                if (r < 0) {
                        log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r));
                        goto fail;
                }
                break;

        default:
                log_unit_error(UNIT(a), "Received unknown automount request %i", packet.hdr.type);
                break;
        }

        return 0;

fail:
        automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
        return 0;
}
Exemplo n.º 17
0
static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
        Automount *a = AUTOMOUNT(u);
        int r;

        assert(a);
        assert(fds);

        if (streq(key, "state")) {
                AutomountState state;

                state = automount_state_from_string(value);
                if (state < 0)
                        log_unit_debug(u, "Failed to parse state value: %s", value);
                else
                        a->deserialized_state = state;
        } else if (streq(key, "result")) {
                AutomountResult f;

                f = automount_result_from_string(value);
                if (f < 0)
                        log_unit_debug(u, "Failed to parse result value: %s", value);
                else if (f != AUTOMOUNT_SUCCESS)
                        a->result = f;

        } else if (streq(key, "dev-id")) {
                unsigned d;

                if (safe_atou(value, &d) < 0)
                        log_unit_debug(u, "Failed to parse dev-id value: %s", value);
                else
                        a->dev_id = (unsigned) d;
        } else if (streq(key, "token")) {
                unsigned token;

                if (safe_atou(value, &token) < 0)
                        log_unit_debug(u, "Failed to parse token value: %s", value);
                else {
                        r = set_ensure_allocated(&a->tokens, NULL);
                        if (r < 0) {
                                log_oom();
                                return 0;
                        }

                        r = set_put(a->tokens, UINT_TO_PTR(token));
                        if (r < 0)
                                log_unit_error_errno(u, r, "Failed to add token to set: %m");
                }
        } else if (streq(key, "expire-token")) {
                unsigned token;

                if (safe_atou(value, &token) < 0)
                        log_unit_debug(u, "Failed to parse token value: %s", value);
                else {
                        r = set_ensure_allocated(&a->expire_tokens, NULL);
                        if (r < 0) {
                                log_oom();
                                return 0;
                        }

                        r = set_put(a->expire_tokens, UINT_TO_PTR(token));
                        if (r < 0)
                                log_unit_error_errno(u, r, "Failed to add expire token to set: %m");
                }
        } else if (streq(key, "pipe-fd")) {
                int fd;

                if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
                        log_unit_debug(u, "Failed to parse pipe-fd value: %s", value);
                else {
                        safe_close(a->pipe_fd);
                        a->pipe_fd = fdset_remove(fds, fd);
                }
        } else
                log_unit_debug(u, "Unknown serialization key: %s", key);

        return 0;
}