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; }
static int routing_policy_rule_add_internal(Manager *m, Set **rules, int family, const union in_addr_union *from, uint8_t from_prefixlen, const union in_addr_union *to, uint8_t to_prefixlen, uint8_t tos, uint32_t fwmark, uint32_t table, char *iif, char *oif, RoutingPolicyRule **ret) { _cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL; int r; assert_return(rules, -EINVAL); r = routing_policy_rule_new(&rule); if (r < 0) return r; rule->manager = m; rule->family = family; rule->from = *from; rule->from_prefixlen = from_prefixlen; rule->to = *to; rule->to_prefixlen = to_prefixlen; rule->tos = tos; rule->fwmark = fwmark; rule->table = table; rule->iif = iif; rule->oif = oif; r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops); if (r < 0) return r; r = set_put(*rules, rule); if (r < 0) return r; if (ret) *ret = rule; rule = NULL; return 0; }
int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule) { int r; assert(m); if (set_contains(m->rules_foreign, rule)) { set_remove(m->rules_foreign, rule); r = set_ensure_allocated(&m->rules, &routing_policy_rule_hash_ops); if (r < 0) return r; return set_put(m->rules, rule); } return -ENOENT; }
static int route_add_internal( Link *link, Set **routes, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret) { _cleanup_route_free_ Route *route = NULL; int r; assert(link); assert(routes); assert(dst); r = route_new(&route); if (r < 0) return r; route->family = family; route->dst = *dst; route->dst_prefixlen = dst_prefixlen; route->tos = tos; route->priority = priority; route->table = table; r = set_ensure_allocated(routes, &route_hash_ops); if (r < 0) return r; r = set_put(*routes, route); if (r < 0) return r; route->link = link; if (ret) *ret = route; route = NULL; return 0; }
static int add_listen_socket(Context *context, int fd) { sd_event_source *source; int r; assert(context); assert(fd >= 0); r = set_ensure_allocated(&context->listen, NULL); if (r < 0) { log_oom(); return r; } r = sd_is_socket(fd, 0, SOCK_STREAM, 1); if (r < 0) return log_error_errno(r, "Failed to determine socket type: %m"); if (r == 0) { log_error("Passed in socket is not a stream socket."); return -EINVAL; } r = fd_nonblock(fd, true); if (r < 0) return log_error_errno(r, "Failed to mark file descriptor non-blocking: %m"); r = sd_event_add_io(context->event, &source, fd, EPOLLIN, accept_cb, context); if (r < 0) return log_error_errno(r, "Failed to add event source: %m"); r = set_put(context->listen, source); if (r < 0) { log_error_errno(r, "Failed to add source to set: %m"); sd_event_source_unref(source); return r; } /* Set the watcher to oneshot in case other processes are also * watching to accept(). */ r = sd_event_source_set_enabled(source, SD_EVENT_ONESHOT); if (r < 0) return log_error_errno(r, "Failed to enable oneshot mode: %m"); return 0; }
int route_add( Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret) { Route *route; int r; r = route_get(link, family, dst, dst_prefixlen, tos, priority, table, &route); if (r == -ENOENT) { /* Route does not exist, create a new one */ r = route_add_internal(link, &link->routes, family, dst, dst_prefixlen, tos, priority, table, &route); if (r < 0) return r; } else if (r == 0) { /* Take over a foreign route */ r = set_ensure_allocated(&link->routes, &route_hash_ops); if (r < 0) return r; r = set_put(link->routes, route); if (r < 0) return r; set_remove(link->routes_foreign, route); } else if (r == 1) { /* Route exists, do nothing */ ; } else return r; if (ret) *ret = route; return 0; }
static int add_connection_socket(Context *context, int fd) { Connection *c; int r; assert(context); assert(fd >= 0); if (set_size(context->connections) > arg_connections_max) { log_warning("Hit connection limit, refusing connection."); safe_close(fd); return 0; } r = set_ensure_allocated(&context->connections, NULL); if (r < 0) { log_oom(); return 0; } c = new0(Connection, 1); if (!c) { log_oom(); return 0; } c->context = context; c->server_fd = fd; c->client_fd = -1; c->server_to_client_buffer[0] = c->server_to_client_buffer[1] = -1; c->client_to_server_buffer[0] = c->client_to_server_buffer[1] = -1; r = set_put(context->connections, c); if (r < 0) { free(c); log_oom(); return 0; } return resolve_remote(c); }
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; }
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; }
static int bus_scope_set_transient_property( Scope *s, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error) { int r; assert(s); assert(name); assert(message); if (streq(name, "PIDs")) { unsigned n = 0; uint32_t pid; r = set_ensure_allocated(&s->pids, trivial_hash_func, trivial_compare_func); if (r < 0) return r; r = sd_bus_message_enter_container(message, 'a', "u"); if (r < 0) return r; while ((r = sd_bus_message_read(message, "u", &pid)) > 0) { if (pid <= 1) return -EINVAL; if (mode != UNIT_CHECK) { r = set_put(s->pids, LONG_TO_PTR(pid)); if (r < 0 && r != -EEXIST) return r; } n++; } if (r < 0) return r; r = sd_bus_message_exit_container(message); if (r < 0) return r; if (n <= 0) return -EINVAL; return 1; } else if (streq(name, "TimeoutStopUSec")) { if (mode != UNIT_CHECK) { r = sd_bus_message_read(message, "t", &s->timeout_stop_usec); if (r < 0) return r; unit_write_drop_in_format(UNIT(s), mode, name, "[Scope]\nTimeoutStopSec=%lluus\n", (unsigned long long) s->timeout_stop_usec); } else { r = sd_bus_message_skip(message, "t"); if (r < 0) return r; } return 1; } return 0; }
static void ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) { uint32_t lifetime; const struct in6_addr *a; usec_t time_now; int i, n, r; assert(link); assert(rt); r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); if (r < 0) { log_link_warning_errno(link, r, "Failed to get RA timestamp: %m"); return; } r = sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime); if (r < 0) { log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m"); return; } n = sd_ndisc_router_rdnss_get_addresses(rt, &a); if (n < 0) { log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m"); return; } for (i = 0; i < n; i++) { NDiscRDNSS d = { .address = a[i] }, *x; if (lifetime == 0) { (void) set_remove(link->ndisc_rdnss, &d); link_dirty(link); continue; } x = set_get(link->ndisc_rdnss, &d); if (x) { x->valid_until = time_now + lifetime * USEC_PER_SEC; continue; } ndisc_vacuum(link); if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) { log_link_warning(link, "Too many RDNSS records per link, ignoring."); continue; } r = set_ensure_allocated(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops); if (r < 0) { log_oom(); return; } x = new0(NDiscRDNSS, 1); if (!x) { log_oom(); return; } x->address = a[i]; x->valid_until = time_now + lifetime * USEC_PER_SEC; r = set_put(link->ndisc_rdnss, x); if (r < 0) { free(x); log_oom(); return; } assert(r > 0); link_dirty(link); }