int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) { _cleanup_(dns_transaction_freep) DnsTransaction *t = NULL; int r; assert(ret); assert(s); assert(key); r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL); if (r < 0) return r; r = hashmap_ensure_allocated(&s->transactions, &dns_resource_key_hash_ops); if (r < 0) return r; t = new0(DnsTransaction, 1); if (!t) return -ENOMEM; t->dns_udp_fd = -1; t->key = dns_resource_key_ref(key); /* Find a fresh, unused transaction id */ do random_bytes(&t->id, sizeof(t->id)); while (t->id == 0 || hashmap_get(s->manager->dns_transactions, UINT_TO_PTR(t->id))); r = hashmap_put(s->manager->dns_transactions, UINT_TO_PTR(t->id), t); if (r < 0) { t->id = 0; return r; } r = hashmap_put(s->transactions, t->key, t); if (r < 0) { hashmap_remove(s->manager->dns_transactions, UINT_TO_PTR(t->id)); return r; } t->scope = s; if (ret) *ret = t; t = NULL; return 0; }
static int device_set_sysfs(Device *d, const char *sysfs) { Device *first; char *copy; int r; assert(d); if (streq_ptr(d->sysfs, sysfs)) return 0; r = hashmap_ensure_allocated(&UNIT(d)->manager->devices_by_sysfs, &string_hash_ops); if (r < 0) return r; copy = strdup(sysfs); if (!copy) return -ENOMEM; device_unset_sysfs(d); first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, sysfs); LIST_PREPEND(same_sysfs, first, d); r = hashmap_replace(UNIT(d)->manager->devices_by_sysfs, copy, first); if (r < 0) { LIST_REMOVE(same_sysfs, first, d); free(copy); return r; } d->sysfs = copy; return 0; }
int link_new(Manager *m, Link **ret, int ifindex) { _cleanup_(link_freep) Link *l = NULL; int r; assert(m); assert(ifindex > 0); r = hashmap_ensure_allocated(&m->links, NULL); if (r < 0) return r; l = new0(Link, 1); if (!l) return -ENOMEM; l->ifindex = ifindex; l->llmnr_support = RESOLVE_SUPPORT_YES; l->mdns_support = RESOLVE_SUPPORT_NO; l->dnssec_mode = _DNSSEC_MODE_INVALID; r = hashmap_put(m->links, INT_TO_PTR(ifindex), l); if (r < 0) return r; l->manager = m; if (ret) *ret = l; l = NULL; return 0; }
static int dynamic_user_add(Manager *m, const char *name, int storage_socket[2], DynamicUser **ret) { DynamicUser *d; int r; assert(m); assert(name); assert(storage_socket); r = hashmap_ensure_allocated(&m->dynamic_users, &string_hash_ops); if (r < 0) return r; d = malloc0(offsetof(DynamicUser, name) + strlen(name) + 1); if (!d) return -ENOMEM; strcpy(d->name, name); d->storage_socket[0] = storage_socket[0]; d->storage_socket[1] = storage_socket[1]; r = hashmap_put(m->dynamic_users, d->name, d); if (r < 0) { free(d); return r; } d->manager = m; if (ret) *ret = d; return 0; }
static int client_acquire(Context *context, uint64_t id, Client **_c) { char *watch = NULL; Client *c; int r; assert(context); assert(_c); c = hashmap_get(context->clients, &id); if (c) { *_c = c; return 0; } if (hashmap_size(context->clients) >= CLIENTS_MAX) return -ENOBUFS; r = hashmap_ensure_allocated(&context->clients, uint64_hash_func, uint64_compare_func); if (r < 0) return r; c = new0(Client, 1); if (!c) return -ENOMEM; c->id = id; r = hashmap_put(context->clients, &c->id, c); if (r < 0) goto fail; c->context = context; if (asprintf(&watch, "type='signal'," "sender='org.freedesktop.DBus'," "path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus'," "member='NameOwnerChanged'," "arg0=':1.%llu'", (unsigned long long) id) < 0) { r = -ENOMEM; goto fail; } r = sd_bus_add_match(context->bus, watch, on_name_owner_changed, c); if (r < 0) { free(watch); goto fail; } c->watch = watch; *_c = c; return 0; fail: client_free(c); return r; }
int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { _cleanup_free_ char *e = NULL; Manager *m = userdata; Image *image = NULL; const char *p; int r; assert(bus); assert(path); assert(interface); assert(found); p = startswith(path, "/org/freedesktop/machine1/image/"); if (!p) return 0; e = bus_label_unescape(p); if (!e) return -ENOMEM; image = hashmap_get(m->image_cache, e); if (image) { *found = image; return 1; } r = hashmap_ensure_allocated(&m->image_cache, &string_hash_ops); if (r < 0) return r; if (!m->image_cache_defer_event) { r = sd_event_add_defer(m->event, &m->image_cache_defer_event, image_flush_cache, m); if (r < 0) return r; r = sd_event_source_set_priority(m->image_cache_defer_event, SD_EVENT_PRIORITY_IDLE); if (r < 0) return r; } r = sd_event_source_set_enabled(m->image_cache_defer_event, SD_EVENT_ONESHOT); if (r < 0) return r; r = image_find(e, &image); if (r <= 0) return r; image->userdata = m; r = hashmap_put(m->image_cache, image->name, image); if (r < 0) { image_unref(image); return r; } *found = image; return 1; }
int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) { _cleanup_(link_freep) Link *l = NULL; int r; assert(m); assert(ifindex > 0); r = hashmap_ensure_allocated(&m->links, NULL); if (r < 0) return r; r = hashmap_ensure_allocated(&m->links_by_name, &string_hash_ops); if (r < 0) return r; l = new0(Link, 1); if (!l) return -ENOMEM; l->manager = m; l->ifname = strdup(ifname); if (!l->ifname) return -ENOMEM; r = hashmap_put(m->links_by_name, l->ifname, l); if (r < 0) return r; l->ifindex = ifindex; r = hashmap_put(m->links, INT_TO_PTR(ifindex), l); if (r < 0) return r; if (ret) *ret = l; l = NULL; return 0; }
static void test_hashmap_ensure_allocated(void) { Hashmap *m; int valid_hashmap; m = hashmap_new(&string_hash_ops); valid_hashmap = hashmap_ensure_allocated(&m, &string_hash_ops); assert_se(valid_hashmap == 0); assert_se(m); hashmap_free(m); }
static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) { _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; _cleanup_(prefix_freep) Prefix *prefix = NULL; int r; assert(network); assert(ret); assert(!!filename == (section_line > 0)); if (filename) { r = network_config_section_new(filename, section_line, &n); if (r < 0) return r; if (section_line) { prefix = hashmap_get(network->prefixes_by_section, n); if (prefix) { *ret = TAKE_PTR(prefix); return 0; } } } r = prefix_new(&prefix); if (r < 0) return r; prefix->network = network; LIST_APPEND(prefixes, network->static_prefixes, prefix); network->n_static_prefixes++; if (filename) { prefix->section = TAKE_PTR(n); r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops); if (r < 0) return r; r = hashmap_put(network->prefixes_by_section, prefix->section, prefix); if (r < 0) return r; } *ret = TAKE_PTR(prefix); return 0; }
static void test_hashmap_put(void) { Hashmap *m = NULL; int valid_hashmap_put; void *val1 = (void*) "val 1"; assert_se(hashmap_ensure_allocated(&m, &string_hash_ops) >= 0); assert_se(m); valid_hashmap_put = hashmap_put(m, "key 1", val1); assert_se(valid_hashmap_put == 1); assert_se(hashmap_put(m, "key 1", val1) == 0); assert_se(hashmap_put(m, "key 1", (void *)"val 2") == -EEXIST); hashmap_free(m); }
_public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL; _cleanup_free_ char *n = NULL; const char *match; int r; assert_return(track, -EINVAL); assert_return(service_name_is_valid(name), -EINVAL); r = hashmap_ensure_allocated(&track->names, &string_hash_ops); if (r < 0) return r; n = strdup(name); if (!n) return -ENOMEM; /* First, subscribe to this name */ match = MATCH_FOR_NAME(n); r = sd_bus_add_match(track->bus, &slot, match, on_name_owner_changed, track); if (r < 0) return r; r = hashmap_put(track->names, n, slot); if (r == -EEXIST) return 0; if (r < 0) return r; /* Second, check if it is currently existing, or maybe * doesn't, or maybe disappeared already. */ r = sd_bus_get_name_creds(track->bus, n, 0, NULL); if (r < 0) { hashmap_remove(track->names, n); return r; } n = NULL; slot = NULL; bus_track_remove_from_queue(track); track->modified = true; return 1; }
static int client_context_new(Server *s, pid_t pid, ClientContext **ret) { ClientContext *c; int r; assert(s); assert(pid_is_valid(pid)); assert(ret); r = hashmap_ensure_allocated(&s->client_contexts, NULL); if (r < 0) return r; r = prioq_ensure_allocated(&s->client_contexts_lru, client_context_compare); if (r < 0) return r; c = new0(ClientContext, 1); if (!c) return -ENOMEM; c->pid = pid; c->uid = UID_INVALID; c->gid = GID_INVALID; c->auditid = AUDIT_SESSION_INVALID; c->loginuid = UID_INVALID; c->owner_uid = UID_INVALID; c->lru_index = PRIOQ_IDX_NULL; c->timestamp = USEC_INFINITY; c->extra_fields_mtime = NSEC_INFINITY; c->log_level_max = -1; c->log_rate_limit_interval = s->rate_limit_interval; c->log_rate_limit_burst = s->rate_limit_burst; r = hashmap_put(s->client_contexts, PID_TO_PTR(pid), c); if (r < 0) { free(c); return r; } *ret = c; return 0; }
static int match_new(Client *c, struct bus_match_component *components, unsigned n_components, Match **_m) { Match *m, *first; int r; assert(c); assert(_m); r = hashmap_ensure_allocated(&c->matches, string_hash_func, string_compare_func); if (r < 0) return r; m = new0(Match, 1); if (!m) return -ENOMEM; m->match = bus_match_to_string(components, n_components); if (!m->match) { r = -ENOMEM; goto fail; } m->cookie = ++c->next_cookie; first = hashmap_get(c->matches, m->match); LIST_PREPEND(matches, first, m); r = hashmap_replace(c->matches, m->match, first); if (r < 0) { LIST_REMOVE(matches, first, m); goto fail; } m->client = c; c->n_matches++; *_m = m; m = NULL; return 0; fail: match_free(m); return r; }
int dns_trust_anchor_load(DnsTrustAnchor *d) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; int r; assert(d); r = hashmap_ensure_allocated(&d->by_key, &dns_resource_key_hash_ops); if (r < 0) return r; if (hashmap_get(d->by_key, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_DS, "."))) return 0; /* Add the RR from https://data.iana.org/root-anchors/root-anchors.xml */ rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, ""); if (!rr) return -ENOMEM; rr->ds.key_tag = 19036; rr->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; rr->ds.digest_type = DNSSEC_DIGEST_SHA256; rr->ds.digest_size = sizeof(root_digest); rr->ds.digest = memdup(root_digest, rr->ds.digest_size); if (!rr->ds.digest) return -ENOMEM; answer = dns_answer_new(1); if (!answer) return -ENOMEM; r = dns_answer_add(answer, rr, 0); if (r < 0) return r; r = hashmap_put(d->by_key, rr->key, answer); if (r < 0) return r; answer = NULL; return 0; }
static void test_hashmap_put(void) { Hashmap *m = NULL; int valid_hashmap_put; void *val1 = (void*) "val 1"; void *val2 = (void*) "val 2"; _cleanup_free_ char* key1 = NULL; assert_se(hashmap_ensure_allocated(&m, &string_hash_ops) >= 0); assert_se(m); valid_hashmap_put = hashmap_put(m, "key 1", val1); assert_se(valid_hashmap_put == 1); assert_se(hashmap_put(m, "key 1", val1) == 0); assert_se(hashmap_put(m, "key 1", val2) == -EEXIST); key1 = strdup("key 1"); assert_se(hashmap_put(m, key1, val1) == 0); assert_se(hashmap_put(m, key1, val2) == -EEXIST); hashmap_free(m); }
int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsQuestion *q) { _cleanup_(dns_transaction_freep) DnsTransaction *t = NULL; int r; assert(ret); assert(s); assert(q); r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL); if (r < 0) return r; t = new0(DnsTransaction, 1); if (!t) return -ENOMEM; t->dns_fd = -1; t->question = dns_question_ref(q); do random_bytes(&t->id, sizeof(t->id)); while (t->id == 0 || hashmap_get(s->manager->dns_transactions, UINT_TO_PTR(t->id))); r = hashmap_put(s->manager->dns_transactions, UINT_TO_PTR(t->id), t); if (r < 0) { t->id = 0; return r; } LIST_PREPEND(transactions_by_scope, s->transactions, t); t->scope = s; if (ret) *ret = t; t = NULL; return 0; }
int link_new(Manager *m, Link **ret, int ifindex) { _cleanup_(link_freep) Link *l = NULL; int r; assert(m); assert(ifindex > 0); r = hashmap_ensure_allocated(&m->links, NULL); if (r < 0) return r; l = new0(Link, 1); if (!l) return -ENOMEM; l->ifindex = ifindex; l->llmnr_support = RESOLVE_SUPPORT_YES; l->mdns_support = RESOLVE_SUPPORT_NO; l->dnssec_mode = _DNSSEC_MODE_INVALID; l->operstate = IF_OPER_UNKNOWN; if (asprintf(&l->state_file, "/run/systemd/resolve/netif/%i", ifindex) < 0) return -ENOMEM; r = hashmap_put(m->links, INT_TO_PTR(ifindex), l); if (r < 0) return r; l->manager = m; if (ret) *ret = l; l = NULL; return 0; }
int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func) { return hashmap_ensure_allocated((Hashmap**) s, hash_func, compare_func); }
int bus_verify_polkit_async( sd_bus *bus, Hashmap **registry, sd_bus_message *m, const char *action, bool interactive, sd_bus_error *error, sd_bus_message_handler_t callback, void *userdata) { #ifdef ENABLE_POLKIT _cleanup_bus_message_unref_ sd_bus_message *pk = NULL; AsyncPolkitQuery *q; #endif const char *sender; uid_t uid; int r; assert(bus); assert(registry); assert(m); assert(action); #ifdef ENABLE_POLKIT q = hashmap_remove(*registry, m); if (q) { unsigned authorized, challenge; /* This is the second invocation of this function, and * there's already a response from polkit, let's * process it */ assert(q->reply); if (sd_bus_message_is_method_error(q->reply, NULL)) { const sd_bus_error *e; /* Treat no PK available as access denied */ if (sd_bus_message_is_method_error(q->reply, SD_BUS_ERROR_SERVICE_UNKNOWN)) { async_polkit_query_free(bus, q); return -EACCES; } e = sd_bus_message_get_error(q->reply); sd_bus_error_copy(error, e); r = sd_bus_error_get_errno(e); async_polkit_query_free(bus, q); return r; } r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}"); if (r >= 0) r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge); async_polkit_query_free(bus, q); if (r < 0) return r; if (authorized) return 1; return -EACCES; } #endif sender = sd_bus_message_get_sender(m); if (!sender) return -EBADMSG; r = sd_bus_get_owner_uid(bus, sender, &uid); if (r < 0) return r; if (uid == 0) return 1; #ifdef ENABLE_POLKIT r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func); if (r < 0) return r; r = sd_bus_message_new_method_call( bus, "org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority", "org.freedesktop.PolicyKit1.Authority", "CheckAuthorization", &pk); if (r < 0) return r; r = sd_bus_message_append( pk, "(sa{sv})sa{ss}us", "system-bus-name", 1, "name", "s", sender, action, 0, interactive ? 1 : 0, ""); if (r < 0) return r; q = new0(AsyncPolkitQuery, 1); if (!q) return -ENOMEM; q->request = sd_bus_message_ref(m); q->callback = callback; q->userdata = userdata; r = hashmap_put(*registry, m, q); if (r < 0) { async_polkit_query_free(bus, q); return r; } r = sd_bus_send_with_reply(bus, pk, async_polkit_callback, q, 0, &q->serial); if (r < 0) return r; return 0; #endif return -EACCES; }
if (d->manager) (void) hashmap_remove(d->manager->dynamic_users, d->name); safe_close_pair(d->storage_socket); return mfree(d); } static int dynamic_user_add(Manager *m, const char *name, int storage_socket[static 2], DynamicUser **ret) { DynamicUser *d; int r; assert(m); assert(name); assert(storage_socket); r = hashmap_ensure_allocated(&m->dynamic_users, &string_hash_ops); if (r < 0) return r; d = malloc0(offsetof(DynamicUser, name) + strlen(name) + 1); if (!d) return -ENOMEM; strcpy(d->name, name); d->storage_socket[0] = storage_socket[0]; d->storage_socket[1] = storage_socket[1]; r = hashmap_put(m->dynamic_users, d->name, d); if (r < 0) { free(d);
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 set_ensure_allocated(Set **s, const struct hash_ops *hash_ops) { return hashmap_ensure_allocated((Hashmap**) s, hash_ops); }
int bus_verify_polkit_async( sd_bus_message *call, int capability, const char *action, bool interactive, Hashmap **registry, sd_bus_error *error) { #ifdef ENABLE_POLKIT _cleanup_bus_message_unref_ sd_bus_message *pk = NULL; AsyncPolkitQuery *q; const char *sender; sd_bus_message_handler_t callback; void *userdata; #endif int r; assert(call); assert(action); assert(registry); #ifdef ENABLE_POLKIT q = hashmap_get(*registry, call); if (q) { int authorized, challenge; /* This is the second invocation of this function, and * there's already a response from polkit, let's * process it */ assert(q->reply); if (sd_bus_message_is_method_error(q->reply, NULL)) { const sd_bus_error *e; /* Copy error from polkit reply */ e = sd_bus_message_get_error(q->reply); sd_bus_error_copy(error, e); /* Treat no PK available as access denied */ if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) return -EACCES; return -sd_bus_error_get_errno(e); } r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}"); if (r >= 0) r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge); if (r < 0) return r; if (authorized) return 1; return -EACCES; } #endif r = sd_bus_query_sender_privilege(call, capability); if (r < 0) return r; else if (r > 0) return 1; #ifdef ENABLE_POLKIT if (sd_bus_get_current_message(call->bus) != call) return -EINVAL; callback = sd_bus_get_current_handler(call->bus); if (!callback) return -EINVAL; userdata = sd_bus_get_current_userdata(call->bus); sender = sd_bus_message_get_sender(call); if (!sender) return -EBADMSG; r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func); if (r < 0) return r; r = sd_bus_message_new_method_call( call->bus, &pk, "org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority", "org.freedesktop.PolicyKit1.Authority", "CheckAuthorization"); if (r < 0) return r; r = sd_bus_message_append( pk, "(sa{sv})sa{ss}us", "system-bus-name", 1, "name", "s", sender, action, 0, interactive ? 1 : 0, NULL); if (r < 0) return r; q = new0(AsyncPolkitQuery, 1); if (!q) return -ENOMEM; q->request = sd_bus_message_ref(call); q->callback = callback; q->userdata = userdata; r = hashmap_put(*registry, call, q); if (r < 0) { async_polkit_query_free(q); return r; } q->registry = *registry; r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0); if (r < 0) { async_polkit_query_free(q); return r; } return 0; #endif return -EACCES; }
int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) { _cleanup_closedir_ DIR *d = NULL; struct stat exclude_st; int r; if (keep_free == 0 && max_use == 0) return 0; if (exclude_fd >= 0) { if (fstat(exclude_fd, &exclude_st) < 0) return log_error_errno(errno, "Failed to fstat(): %m"); } /* This algorithm will keep deleting the oldest file of the * user with the most coredumps until we are back in the size * limits. Note that vacuuming for journal files is different, * because we rely on rate-limiting of the messages there, * to avoid being flooded. */ d = opendir("/var/lib/systemd/coredump"); if (!d) { if (errno == ENOENT) return 0; log_error_errno(errno, "Can't open coredump directory: %m"); return -errno; } for (;;) { _cleanup_(vacuum_candidate_hasmap_freep) Hashmap *h = NULL; struct vacuum_candidate *worst = NULL; struct dirent *de; uint64_t sum = 0; rewinddir(d); FOREACH_DIRENT(de, d, goto fail) { struct vacuum_candidate *c; struct stat st; uid_t uid; usec_t t; r = uid_from_file_name(de->d_name, &uid); if (r < 0) continue; if (fstatat(dirfd(d), de->d_name, &st, AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW) < 0) { if (errno == ENOENT) continue; log_warning("Failed to stat /var/lib/systemd/coredump/%s", de->d_name); continue; } if (!S_ISREG(st.st_mode)) continue; if (exclude_fd >= 0 && exclude_st.st_dev == st.st_dev && exclude_st.st_ino == st.st_ino) continue; r = hashmap_ensure_allocated(&h, NULL); if (r < 0) return log_oom(); t = timespec_load(&st.st_mtim); c = hashmap_get(h, UINT32_TO_PTR(uid)); if (c) { if (t < c->oldest_mtime) { char *n; n = strdup(de->d_name); if (!n) return log_oom(); free(c->oldest_file); c->oldest_file = n; c->oldest_mtime = t; } } else { _cleanup_(vacuum_candidate_freep) struct vacuum_candidate *n = NULL; n = new0(struct vacuum_candidate, 1); if (!n) return log_oom(); n->oldest_file = strdup(de->d_name); if (!n->oldest_file) return log_oom(); n->oldest_mtime = t; r = hashmap_put(h, UINT32_TO_PTR(uid), n); if (r < 0) return log_oom(); c = n; n = NULL; } c->n_files++; if (!worst || worst->n_files < c->n_files || (worst->n_files == c->n_files && c->oldest_mtime < worst->oldest_mtime)) worst = c; sum += st.st_blocks * 512; } if (!worst) break; r = vacuum_necessary(dirfd(d), sum, keep_free, max_use); if (r <= 0) return r; if (unlinkat(dirfd(d), worst->oldest_file, 0) < 0) { if (errno == ENOENT) continue; log_error_errno(errno, "Failed to remove file %s: %m", worst->oldest_file); return -errno; } else log_info("Removed old coredump %s.", worst->oldest_file); } return 0; fail: log_error_errno(errno, "Failed to read directory: %m"); return -errno; }