int raw_import_start(RawImport *i, int fd, const char *local, bool force_local, bool read_only) { int r; assert(i); assert(fd >= 0); assert(local); if (!machine_name_is_valid(local)) return -EINVAL; if (i->input_fd >= 0) return -EBUSY; r = fd_nonblock(fd, true); if (r < 0) return r; r = free_and_strdup(&i->local, local); if (r < 0) return r; i->force_local = force_local; i->read_only = read_only; if (fstat(fd, &i->st) < 0) return -errno; r = sd_event_add_io(i->event, &i->input_event_source, fd, EPOLLIN, raw_import_on_input, i); if (r == -EPERM) { /* This fd does not support epoll, for example because it is a regular file. Busy read in that case */ r = sd_event_add_defer(i->event, &i->input_event_source, raw_import_on_defer, i); if (r < 0) return r; r = sd_event_source_set_enabled(i->input_event_source, SD_EVENT_ON); } if (r < 0) return r; i->input_fd = fd; return r; }
static int defer_handler(sd_event_source *s, void *userdata) { sd_event_source *p = NULL; sigset_t ss; assert_se(s); log_info("got defer on %c", PTR_TO_INT(userdata)); assert_se(userdata == INT_TO_PTR('d')); assert_se(sigemptyset(&ss) >= 0); assert_se(sigaddset(&ss, SIGUSR1) >= 0); assert_se(sigprocmask(SIG_BLOCK, &ss, NULL) >= 0); assert_se(sd_event_add_signal(sd_event_source_get_event(s), &p, SIGUSR1, signal_handler, INT_TO_PTR('e')) >= 0); assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0); raise(SIGUSR1); sd_event_source_unref(s); return 1; }
static int PmonRemove(sd_bus_message *m, void *userdata, sd_bus_error *retError) { int id = 0; sd_bus_message_read(m, "u", &id); char *sid = (char*)sd_event_source_get_userdata(clients[id]); if (sid == NULL) { return sd_bus_reply_method_return(m, "b", false); } if (strcmp((char*)sd_event_source_get_userdata(clients[id]), sd_bus_message_get_sender(m)) != 0) { return sd_bus_reply_method_return(m, "b", false); } sd_event_source_set_enabled(clients[id], SD_EVENT_OFF); sd_event_source_unref(clients[id]); //systemd will gc object after unrefing it. clients[id] = NULL; lastFreedSlot += 1; openSlots += 1; freeIds[lastFreedSlot] = id; return sd_bus_reply_method_return(m, "b", true); }
static int busname_watch_fd(BusName *n) { int r; assert(n); if (n->starter_fd < 0) return 0; if (n->starter_event_source) r = sd_event_source_set_enabled(n->starter_event_source, SD_EVENT_ON); else r = sd_event_add_io(UNIT(n)->manager->event, &n->starter_event_source, n->starter_fd, EPOLLIN, busname_dispatch_io, n); if (r < 0) { log_unit_warning_errno(UNIT(n)->id, r, "Failed to watch starter fd: %m"); busname_unwatch_fd(n); return r; } (void) sd_event_source_set_description(n->starter_event_source, "busname-starter"); return 0; }
int main(int argc, char *argv[]) { sd_event *e = NULL; sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL; static const char ch = 'x'; int a[2] = { -1, -1 }, b[2] = { -1, -1}, d[2] = { -1, -1}, k[2] = { -1, -1 }; assert_se(pipe(a) >= 0); assert_se(pipe(b) >= 0); assert_se(pipe(d) >= 0); assert_se(pipe(k) >= 0); assert_se(sd_event_default(&e) >= 0); assert_se(sd_event_set_watchdog(e, true) >= 0); /* Test whether we cleanly can destroy an io event source from its own handler */ got_unref = false; assert_se(sd_event_add_io(e, &t, k[0], EPOLLIN, unref_handler, NULL) >= 0); assert_se(write(k[1], &ch, 1) == 1); assert_se(sd_event_run(e, (uint64_t) -1) >= 1); assert_se(got_unref); got_a = false, got_b = false, got_c = false, got_d = 0; /* Add a oneshot handler, trigger it, re-enable it, and trigger * it again. */ assert_se(sd_event_add_io(e, &w, d[0], EPOLLIN, io_handler, INT_TO_PTR('d')) >= 0); assert_se(sd_event_source_set_enabled(w, SD_EVENT_ONESHOT) >= 0); assert_se(write(d[1], &ch, 1) >= 0); assert_se(sd_event_run(e, (uint64_t) -1) >= 1); assert_se(got_d == 1); assert_se(write(d[1], &ch, 1) >= 0); assert_se(sd_event_run(e, (uint64_t) -1) >= 1); assert_se(got_d == 2); assert_se(sd_event_add_io(e, &x, a[0], EPOLLIN, io_handler, INT_TO_PTR('a')) >= 0); assert_se(sd_event_add_io(e, &y, b[0], EPOLLIN, io_handler, INT_TO_PTR('b')) >= 0); assert_se(sd_event_add_time(e, &z, CLOCK_MONOTONIC, 0, 0, time_handler, INT_TO_PTR('c')) >= 0); assert_se(sd_event_add_exit(e, &q, exit_handler, INT_TO_PTR('g')) >= 0); assert_se(sd_event_source_set_priority(x, 99) >= 0); assert_se(sd_event_source_set_enabled(y, SD_EVENT_ONESHOT) >= 0); assert_se(sd_event_source_set_prepare(x, prepare_handler) >= 0); assert_se(sd_event_source_set_priority(z, 50) >= 0); assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0); assert_se(sd_event_source_set_prepare(z, prepare_handler) >= 0); /* Test for floating event sources */ assert_se(sigprocmask_many(SIG_BLOCK, SIGRTMIN+1, -1) == 0); assert_se(sd_event_add_signal(e, NULL, SIGRTMIN+1, NULL, NULL) >= 0); assert_se(write(a[1], &ch, 1) >= 0); assert_se(write(b[1], &ch, 1) >= 0); assert_se(!got_a && !got_b && !got_c); assert_se(sd_event_run(e, (uint64_t) -1) >= 1); assert_se(!got_a && got_b && !got_c); assert_se(sd_event_run(e, (uint64_t) -1) >= 1); assert_se(!got_a && got_b && got_c); assert_se(sd_event_run(e, (uint64_t) -1) >= 1); assert_se(got_a && got_b && got_c); sd_event_source_unref(x); sd_event_source_unref(y); do_quit = true; assert_se(sd_event_source_set_time(z, now(CLOCK_MONOTONIC) + 200 * USEC_PER_MSEC) >= 0); assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0); assert_se(sd_event_loop(e) >= 0); sd_event_source_unref(z); sd_event_source_unref(q); sd_event_source_unref(w); sd_event_unref(e); safe_close_pair(a); safe_close_pair(b); safe_close_pair(d); safe_close_pair(k); return 0; }
static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, void *userdata, void *socketp) { sd_event_source *io; CurlGlue *g = userdata; uint32_t events = 0; int r; assert(curl); assert(g); io = hashmap_get(g->ios, FD_TO_PTR(s)); if (action == CURL_POLL_REMOVE) { if (io) { int fd; fd = sd_event_source_get_io_fd(io); assert(fd >= 0); sd_event_source_set_enabled(io, SD_EVENT_OFF); sd_event_source_unref(io); hashmap_remove(g->ios, FD_TO_PTR(s)); hashmap_remove(g->translate_fds, FD_TO_PTR(fd)); safe_close(fd); } return 0; } r = hashmap_ensure_allocated(&g->ios, &trivial_hash_ops); if (r < 0) { log_oom(); return -1; } r = hashmap_ensure_allocated(&g->translate_fds, &trivial_hash_ops); if (r < 0) { log_oom(); return -1; } if (action == CURL_POLL_IN) events = EPOLLIN; else if (action == CURL_POLL_OUT) events = EPOLLOUT; else if (action == CURL_POLL_INOUT) events = EPOLLIN|EPOLLOUT; if (io) { if (sd_event_source_set_io_events(io, events) < 0) return -1; if (sd_event_source_set_enabled(io, SD_EVENT_ON) < 0) return -1; } else { _cleanup_close_ int fd = -1; /* When curl needs to remove an fd from us it closes * the fd first, and only then calls into us. This is * nasty, since we cannot pass the fd on to epoll() * anymore. Hence, duplicate the fds here, and keep a * copy for epoll which we control after use. */ fd = fcntl(s, F_DUPFD_CLOEXEC, 3); if (fd < 0) return -1; if (sd_event_add_io(g->event, &io, fd, events, curl_glue_on_io, g) < 0) return -1; (void) sd_event_source_set_description(io, "curl-io"); r = hashmap_put(g->ios, FD_TO_PTR(s), io); if (r < 0) { log_oom(); sd_event_source_unref(io); return -1; } r = hashmap_put(g->translate_fds, FD_TO_PTR(fd), FD_TO_PTR(s)); if (r < 0) { log_oom(); hashmap_remove(g->ios, FD_TO_PTR(s)); sd_event_source_unref(io); return -1; } fd = -1; } return 0; }
int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType compress) { _cleanup_close_ int sfd = -1; int r; assert(e); assert(path); assert(fd >= 0); assert(compress < _IMPORT_COMPRESS_TYPE_MAX); assert(compress != IMPORT_COMPRESS_UNKNOWN); if (e->output_fd >= 0) return -EBUSY; sfd = open(path, O_DIRECTORY|O_RDONLY|O_NOCTTY|O_CLOEXEC); if (sfd < 0) return -errno; if (fstat(sfd, &e->st) < 0) return -errno; r = fd_nonblock(fd, true); if (r < 0) return r; r = free_and_strdup(&e->path, path); if (r < 0) return r; e->quota_referenced = (uint64_t) -1; if (e->st.st_ino == 256) { /* might be a btrfs subvolume? */ BtrfsQuotaInfo q; r = btrfs_subvol_get_subtree_quota_fd(sfd, 0, &q); if (r >= 0) e->quota_referenced = q.referenced; e->temp_path = mfree(e->temp_path); r = tempfn_random(path, NULL, &e->temp_path); if (r < 0) return r; /* Let's try to make a snapshot, if we can, so that the export is atomic */ r = btrfs_subvol_snapshot_fd(sfd, e->temp_path, BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_RECURSIVE); if (r < 0) { log_debug_errno(r, "Couldn't create snapshot %s of %s, not exporting atomically: %m", e->temp_path, path); e->temp_path = mfree(e->temp_path); } } r = import_compress_init(&e->compress, compress); if (r < 0) return r; r = sd_event_add_io(e->event, &e->output_event_source, fd, EPOLLOUT, tar_export_on_output, e); if (r == -EPERM) { r = sd_event_add_defer(e->event, &e->output_event_source, tar_export_on_defer, e); if (r < 0) return r; r = sd_event_source_set_enabled(e->output_event_source, SD_EVENT_ON); } if (r < 0) return r; e->tar_fd = import_fork_tar_c(e->temp_path ?: e->path, &e->tar_pid); if (e->tar_fd < 0) { e->output_event_source = sd_event_source_unref(e->output_event_source); return e->tar_fd; } e->output_fd = fd; return r; }
int idev_keyboard_new(idev_device **out, idev_session *s, const char *name) { _cleanup_(idev_device_freep) idev_device *d = NULL; idev_keyboard *k; char *kname; int r; assert_return(out, -EINVAL); assert_return(s, -EINVAL); assert_return(name, -EINVAL); k = new0(idev_keyboard, 1); if (!k) return -ENOMEM; d = &k->device; k->device = IDEV_DEVICE_INIT(&keyboard_vtable, s); k->repeat_delay = 250 * USEC_PER_MSEC; k->repeat_rate = 30 * USEC_PER_MSEC; /* TODO: add key-repeat configuration */ r = get_kbdctx(s->context, &k->kbdctx); if (r < 0) return r; r = keyboard_update_kbdmap(k); if (r < 0) return r; r = keyboard_update_kbdtbl(k); if (r < 0) return r; r = keyboard_resize_bufs(k, 8); if (r < 0) return r; r = sd_event_add_time(s->context->event, &k->repeat_timer, CLOCK_MONOTONIC, 0, 10 * USEC_PER_MSEC, keyboard_repeat_timer_fn, k); if (r < 0) return r; r = sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF); if (r < 0) return r; kname = strjoina("keyboard/", name); r = idev_device_add(d, kname); if (r < 0) return r; if (out) *out = d; d = NULL; return 0; }
static int stdout_stream_save(StdoutStream *s) { _cleanup_free_ char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; int r; assert(s); if (s->state != STDOUT_STREAM_RUNNING) return 0; if (!s->state_file) { struct stat st; r = fstat(s->fd, &st); if (r < 0) return log_warning_errno(errno, "Failed to stat connected stream: %m"); /* We use device and inode numbers as identifier for the stream */ if (asprintf(&s->state_file, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino) < 0) return log_oom(); } mkdir_p("/run/systemd/journal/streams", 0755); r = fopen_temporary(s->state_file, &f, &temp_path); if (r < 0) goto fail; fprintf(f, "# This is private data. Do not parse\n" "PRIORITY=%i\n" "LEVEL_PREFIX=%i\n" "FORWARD_TO_SYSLOG=%i\n" "FORWARD_TO_KMSG=%i\n" "FORWARD_TO_CONSOLE=%i\n" "STREAM_ID=%s\n", s->priority, s->level_prefix, s->forward_to_syslog, s->forward_to_kmsg, s->forward_to_console, s->id_field + strlen("_STREAM_ID=")); if (!isempty(s->identifier)) { _cleanup_free_ char *escaped; escaped = cescape(s->identifier); if (!escaped) { r = -ENOMEM; goto fail; } fprintf(f, "IDENTIFIER=%s\n", escaped); } if (!isempty(s->unit_id)) { _cleanup_free_ char *escaped; escaped = cescape(s->unit_id); if (!escaped) { r = -ENOMEM; goto fail; } fprintf(f, "UNIT=%s\n", escaped); } r = fflush_and_check(f); if (r < 0) goto fail; if (rename(temp_path, s->state_file) < 0) { r = -errno; goto fail; } 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; fail: (void) unlink(s->state_file); if (temp_path) (void) unlink(temp_path); return log_error_errno(r, "Failed to save stream data %s: %m", s->state_file); }
static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; union autofs_v5_packet_union packet; Automount *a = AUTOMOUNT(userdata); struct stat st; 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); (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF); 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; } r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, true, &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; }