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; }
bool condition_test_list(const char *unit, Condition *first) { Condition *c; int triggered = -1; /* If the condition list is empty, then it is true */ if (!first) return true; /* Otherwise, if all of the non-trigger conditions apply and * if any of the trigger conditions apply (unless there are * none) we return true */ LIST_FOREACH(conditions, c, first) { bool b; b = condition_test(c); if (unit) log_debug_unit(unit, "%s=%s%s%s %s for %s.", condition_type_to_string(c->type), c->trigger ? "|" : "", c->negate ? "!" : "", c->parameter, b ? "succeeded" : "failed", unit); c->state = b ? 1 : -1; if (!c->trigger && !b) return false; if (c->trigger && triggered <= 0) triggered = b; }
int automount_send_ready(Automount *a, int status) { int ioctl_fd, r; unsigned token; assert(a); assert(status <= 0); if (set_isempty(a->tokens)) return 0; ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id); if (ioctl_fd < 0) { r = ioctl_fd; goto fail; } if (status) log_debug_unit(UNIT(a)->id, "Sending failure: %s", strerror(-status)); else log_debug_unit(UNIT(a)->id, "Sending success."); r = 0; /* Autofs thankfully does not hand out 0 as a token */ while ((token = PTR_TO_UINT(set_steal_first(a->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; } fail: if (ioctl_fd >= 0) close_nointr_nofail(ioctl_fd); return r; }
static void scope_notify_cgroup_empty_event(Unit *u) { Scope *s = SCOPE(u); assert(u); log_debug_unit(u->id, "%s: cgroup is empty", u->id); if (IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL)) scope_enter_dead(s, SCOPE_SUCCESS); }
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_debug_unit(UNIT(n)->id, "Failed to disable event source."); }
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_debug_unit(UNIT(d)->id, "%s changed %s -> %s", UNIT(d)->id, 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); }
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_debug_unit(UNIT(a)->id, "Suppressing automount request on %s since unit stop is scheduled.", UNIT(a)->id); automount_send_ready(a, -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_warning_unit(UNIT(a)->id, "%s failed to stat automount point: %m", UNIT(a)->id); goto fail; } if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) log_info_unit(UNIT(a)->id, "%s's automount point already active?", UNIT(a)->id); else { r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, true, &error, NULL); if (r < 0) { log_warning_unit(UNIT(a)->id, "%s failed to queue mount startup job: %s", UNIT(a)->id, bus_error_message(&error, r)); goto fail; } } automount_set_state(a, AUTOMOUNT_RUNNING); return; fail: automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES); }
static void scope_notify_cgroup_empty_event(Unit *u) { Scope *s = SCOPE(u); assert(u); log_debug_unit(u->id, "%s: cgroup is empty", u->id); switch (s->state) { case SCOPE_RUNNING: case SCOPE_STOP_SIGTERM: case SCOPE_STOP_SIGKILL: scope_enter_dead(s, SCOPE_SUCCESS); break; default: ; } }
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_debug_unit(UNIT(a)->id, "%s changed %s -> %s", UNIT(a)->id, 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); }
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_debug_unit(u->id, "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_debug_unit(u->id, "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_debug_unit(u->id, "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_debug_unit(u->id, "Failed to parse token value %s", value); else { if (!a->tokens) if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func))) return -ENOMEM; r = set_put(a->tokens, UINT_TO_PTR(token)); if (r < 0) return r; } } else if (streq(key, "pipe-fd")) { int fd; if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) log_debug_unit(u->id, "Failed to parse pipe-fd value %s", value); else { if (a->pipe_fd >= 0) close_nointr_nofail(a->pipe_fd); a->pipe_fd = fdset_remove(fds, fd); } } else log_debug_unit(u->id, "Unknown serialization key '%s'", key); return 0; }