Beispiel #1
0
static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) {
        union autofs_v5_packet_union packet;
        Automount *a = AUTOMOUNT(userdata);
        ssize_t l;
        int r;

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

        if (events != EPOLLIN) {
                log_error_unit(UNIT(a)->id, "Got invalid poll event on pipe.");
                goto fail;
        }

        l = loop_read(a->pipe_fd, &packet, sizeof(packet), true);
        if (l != sizeof(packet)) {
                log_error_unit(UNIT(a)->id, "Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read");
                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_info_unit(UNIT(a)->id,
                                       "Got automount request for %s, triggered by "PID_FMT" (%s)",
                                       a->where, packet.v5_packet.pid, strna(p));
                } else
                        log_debug_unit(UNIT(a)->id, "Got direct mount request on %s", a->where);

                r = set_ensure_allocated(&a->tokens, trivial_hash_func, trivial_compare_func);
                if (r < 0) {
                        log_error_unit(UNIT(a)->id, "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_error_unit(UNIT(a)->id, "Failed to remember token: %s", strerror(-r));
                        goto fail;
                }

                automount_enter_runnning(a);
                break;

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

        return 0;

fail:
        automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
        return 0;
}
Beispiel #2
0
static int automount_verify(Automount *a) {
        bool b;
        char *e;
        assert(a);

        if (UNIT(a)->load_state != UNIT_LOADED)
                return 0;

        if (path_equal(a->where, "/")) {
                log_error_unit(UNIT(a)->id, "Cannot have an automount unit for the root directory. Refusing.");
                return -EINVAL;
        }

        e = unit_name_from_path(a->where, ".automount");
        if (!e)
                return -ENOMEM;

        b = unit_has_name(UNIT(a), e);
        free(e);

        if (!b) {
                log_error_unit(UNIT(a)->id, "%s's Where setting doesn't match unit name. Refusing.", UNIT(a)->id);
                return -EINVAL;
        }

        return 0;
}
Beispiel #3
0
static int slice_verify(Slice *s) {
        assert(s);

        if (UNIT(s)->load_state != UNIT_LOADED)
                return 0;

        if (UNIT_DEREF(UNIT(s)->slice)) {
                char *a, *dash;

                a = strdupa(UNIT(s)->id);
                dash = strrchr(a, '-');
                if (dash)
                        strcpy(dash, ".slice");
                else
                        a = (char*) SPECIAL_ROOT_SLICE;

                if (!unit_has_name(UNIT_DEREF(UNIT(s)->slice), a)) {
                        log_error_unit(UNIT(s)->id,
                                       "%s located outside its parent slice. Refusing.", UNIT(s)->id);
                        return -EINVAL;
                }
        }

        return 0;
}
Beispiel #4
0
static int busname_verify(BusName *n) {
        char *e;

        assert(n);

        if (UNIT(n)->load_state != UNIT_LOADED)
                return 0;

        if (!service_name_is_valid(n->name)) {
                log_error_unit(UNIT(n)->id, "%s's Name= setting is not a valid service name Refusing.", UNIT(n)->id);
                return -EINVAL;
        }

        e = strappenda(n->name, ".busname");
        if (!unit_has_name(UNIT(n), e)) {
                log_error_unit(UNIT(n)->id, "%s's Name= setting doesn't match unit name. Refusing.", UNIT(n)->id);
                return -EINVAL;
        }

        return 0;
}
Beispiel #5
0
static int scope_verify(Scope *s) {
        assert(s);

        if (UNIT(s)->load_state != UNIT_LOADED)
                return 0;

        if (set_size(s->pids) <= 0 && UNIT(s)->manager->n_reloading <= 0) {
                log_error_unit(UNIT(s)->id, "Scope %s has no PIDs. Refusing.", UNIT(s)->id);
                return -EINVAL;
        }

        return 0;
}
Beispiel #6
0
static int automount_start(Unit *u) {
        Automount *a = AUTOMOUNT(u);

        assert(a);
        assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);

        if (path_is_mount_point(a->where, false)) {
                log_error_unit(u->id,
                               "Path %s is already a mount point, refusing start for %s",
                               a->where, u->id);
                return -EEXIST;
        }

        if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
                return -ENOENT;

        a->result = AUTOMOUNT_SUCCESS;
        automount_enter_waiting(a);
        return 0;
}
Beispiel #7
0
static void automount_enter_waiting(Automount *a) {
        int p[2] = { -1, -1 };
        char name[32], options[128];
        bool mounted = false;
        int r, ioctl_fd = -1, dev_autofs_fd;
        struct stat st;

        assert(a);
        assert(a->pipe_fd < 0);
        assert(a->where);

        if (a->tokens)
                set_clear(a->tokens);

        dev_autofs_fd = open_dev_autofs(UNIT(a)->manager);
        if (dev_autofs_fd < 0) {
                r = dev_autofs_fd;
                goto fail;
        }

        /* We knowingly ignore the results of this call */
        mkdir_p_label(a->where, 0555);

        warn_if_dir_nonempty(a->meta.id, a->where);

        if (pipe2(p, O_NONBLOCK|O_CLOEXEC) < 0) {
                r = -errno;
                goto fail;
        }

        snprintf(options, sizeof(options), "fd=%i,pgrp=%u,minproto=5,maxproto=5,direct", p[1], (unsigned) getpgrp());
        char_array_0(options);

        snprintf(name, sizeof(name), "systemd-%u", (unsigned) getpid());
        char_array_0(name);

        if (mount(name, a->where, "autofs", 0, options) < 0) {
                r = -errno;
                goto fail;
        }

        mounted = true;

        close_nointr_nofail(p[1]);
        p[1] = -1;

        if (stat(a->where, &st) < 0) {
                r = -errno;
                goto fail;
        }

        ioctl_fd = open_ioctl_fd(dev_autofs_fd, a->where, st.st_dev);
        if (ioctl_fd < 0) {
                r = ioctl_fd;
                goto fail;
        }

        r = autofs_protocol(dev_autofs_fd, ioctl_fd);
        if (r < 0)
                goto fail;

        r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, 300);
        if (r < 0)
                goto fail;

        /* Autofs fun fact:
         *
         * Unless we close the ioctl fd here, for some weird reason
         * the direct mount will not receive events from the
         * kernel. */

        close_nointr_nofail(ioctl_fd);
        ioctl_fd = -1;

        r = sd_event_add_io(UNIT(a)->manager->event, p[0], EPOLLIN, automount_dispatch_io, a, &a->pipe_event_source);
        if (r < 0)
                goto fail;

        a->pipe_fd = p[0];
        a->dev_id = st.st_dev;

        automount_set_state(a, AUTOMOUNT_WAITING);

        return;

fail:
        assert_se(close_pipe(p) == 0);

        if (ioctl_fd >= 0)
                close_nointr_nofail(ioctl_fd);

        if (mounted)
                repeat_unmount(a->where);

        log_error_unit(UNIT(a)->id,
                       "Failed to initialize automounter: %s", strerror(-r));
        automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
}