static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, const char *id, usec_t ts) { JournalRateLimitGroup *g; struct siphash state; assert(r); assert(id); g = new0(JournalRateLimitGroup, 1); if (!g) return NULL; g->id = strdup(id); if (!g->id) goto fail; siphash24_init(&state, r->hash_key); string_hash_func(g->id, &state); g->hash = siphash24_finalize(&state); journal_rate_limit_vacuum(r, ts); LIST_PREPEND(bucket, r->buckets[g->hash % BUCKETS_MAX], g); LIST_PREPEND(lru, r->lru, g); if (!g->lru_next) r->lru_tail = g; r->n_groups++; g->parent = r; return g; fail: journal_rate_limit_group_free(g); return NULL; }
sd_bus_slot *bus_slot_allocate( sd_bus *bus, bool floating, BusSlotType type, size_t extra, void *userdata) { sd_bus_slot *slot; assert(bus); slot = malloc0(offsetof(sd_bus_slot, reply_callback) + extra); if (!slot) return NULL; slot->n_ref = 1; slot->type = type; slot->bus = bus; slot->floating = floating; slot->userdata = userdata; if (!floating) sd_bus_ref(bus); LIST_PREPEND(slots, bus->slots, slot); return slot; }
int address_new_static(Network *network, unsigned section, Address **ret) { _cleanup_address_free_ Address *address = NULL; if (section) { uint64_t key = section; address = hashmap_get(network->addresses_by_section, &key); if (address) { *ret = address; address = NULL; return 0; } } address = new0(Address, 1); if (!address) return -ENOMEM; address->family = AF_UNSPEC; address->network = network; LIST_PREPEND(static_addresses, network->static_addresses, address); if (section) { address->section = section; hashmap_put(network->addresses_by_section, &address->section, address); } *ret = address; address = 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 route_new_static(Network *network, unsigned section, Route **ret) { _cleanup_route_free_ Route *route = NULL; int r; if (section) { route = hashmap_get(network->routes_by_section, UINT_TO_PTR(section)); if (route) { *ret = route; route = NULL; return 0; } } r = route_new(&route); if (r < 0) return r; route->protocol = RTPROT_STATIC; route->network = network; LIST_PREPEND(routes, network->static_routes, route); if (section) { route->section = section; hashmap_put(network->routes_by_section, UINT_TO_PTR(route->section), route); } *ret = route; route = NULL; return 0; }
static void tile_link(grdev_tile *tile, grdev_tile *parent) { grdev_display *display; grdev_tile *t; assert(tile); assert(!tile->parent); assert(!tile->display); assert(parent); assert(parent->type == GRDEV_TILE_NODE); display = parent->display; assert(!display || !display->enabled); ++parent->node.n_children; LIST_PREPEND(children_by_node, parent->node.child_list, tile); tile->parent = parent; if (display) { display->modified = true; TILE_FOREACH(tile, t) { t->display = display; if (t->type == GRDEV_TILE_LEAF) { ++display->n_leafs; if (display->enabled) pipe_enable(t->leaf.pipe); } } }
_public_ int sd_bus_track_new( sd_bus *bus, sd_bus_track **track, sd_bus_track_handler_t handler, void *userdata) { sd_bus_track *t; assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(track, -EINVAL); if (!bus->bus_client) return -EINVAL; t = new0(sd_bus_track, 1); if (!t) return -ENOMEM; t->n_ref = 1; t->handler = handler; t->userdata = userdata; t->bus = sd_bus_ref(bus); LIST_PREPEND(tracks, bus->tracks, t); t->in_list = true; bus_track_add_to_queue(t); *track = t; return 0; }
int route_new_static(Network *network, unsigned section, Route **ret) { _cleanup_route_free_ Route *route = NULL; if (section) { uint64_t key = section; route = hashmap_get(network->routes_by_section, &key); if (route) { *ret = route; route = NULL; return 0; } } route = new0(Route, 1); if (!route) return -ENOMEM; route->family = AF_UNSPEC; route->network = network; LIST_PREPEND(static_routes, network->static_routes, route); if (section) { route->section = section; hashmap_put(network->routes_by_section, &route->section, route); } *ret = route; route = NULL; return 0; }
static void bus_track_add_to_queue(sd_bus_track *track) { assert(track); /* Adds the bus track object to the queue of objects we should dispatch next, subject to a number of * conditions. */ /* Already in the queue? */ if (track->in_queue) return; /* if we are currently in the process of adding a new name, then let's not enqueue this just yet, let's wait * until the addition is complete. */ if (track->n_adding > 0) return; /* still referenced? */ if (hashmap_size(track->names) > 0) return; /* Nothing to call? */ if (!track->handler) return; /* Already closed? */ if (!track->in_list) return; LIST_PREPEND(queue, track->bus->track_queue, track); track->in_queue = true; }
static int loopback_list_get(MountPoint **head) { _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; struct udev_list_entry *item = NULL, *first = NULL; _cleanup_udev_unref_ struct udev *udev = NULL; int r; assert(head); udev = udev_new(); if (!udev) return -ENOMEM; e = udev_enumerate_new(udev); if (!e) return -ENOMEM; r = udev_enumerate_add_match_subsystem(e, "block"); if (r < 0) return r; r = udev_enumerate_add_match_sysname(e, "loop*"); if (r < 0) return r; r = udev_enumerate_add_match_sysattr(e, "loop/backing_file", NULL); if (r < 0) return r; r = udev_enumerate_scan_devices(e); if (r < 0) return r; first = udev_enumerate_get_list_entry(e); udev_list_entry_foreach(item, first) { MountPoint *lb; _cleanup_udev_device_unref_ struct udev_device *d; char *loop; const char *dn; d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); if (!d) return -ENOMEM; dn = udev_device_get_devnode(d); if (!dn) continue; loop = strdup(dn); if (!loop) return -ENOMEM; lb = new0(MountPoint, 1); if (!lb) { free(loop); return -ENOMEM; } lb->path = loop; LIST_PREPEND(mount_point, *head, lb); }
static int swap_list_get(MountPoint **head) { _cleanup_fclose_ FILE *proc_swaps = NULL; unsigned int i; int r; assert(head); proc_swaps = fopen("/proc/swaps", "re"); if (!proc_swaps) return (errno == ENOENT) ? 0 : -errno; (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n"); for (i = 2;; i++) { MountPoint *swap; char *dev = NULL, *d; int k; k = fscanf(proc_swaps, "%ms " /* device/file */ "%*s " /* type of swap */ "%*s " /* swap size */ "%*s " /* used */ "%*s\n", /* priority */ &dev); if (k != 1) { if (k == EOF) break; log_warning("Failed to parse /proc/swaps:%u.", i); free(dev); continue; } if (endswith(dev, " (deleted)")) { free(dev); continue; } r = cunescape(dev, UNESCAPE_RELAX, &d); free(dev); if (r < 0) return r; swap = new0(MountPoint, 1); if (!swap) { free(d); return -ENOMEM; } swap->path = d; LIST_PREPEND(mount_point, *head, swap); } return 0; }
/* create a new FDB entry or get an existing one. */ int fdb_entry_new_static( Network *network, unsigned section, FdbEntry **ret) { _cleanup_fdbentry_free_ FdbEntry *fdb_entry = NULL; struct ether_addr *mac_addr = NULL; assert(network); assert(ret); /* search entry in hashmap first. */ if (section) { fdb_entry = hashmap_get(network->fdb_entries_by_section, UINT_TO_PTR(section)); if (fdb_entry) { *ret = fdb_entry; fdb_entry = NULL; return 0; } } if (network->n_static_fdb_entries >= STATIC_FDB_ENTRIES_PER_NETWORK_MAX) return -E2BIG; /* allocate space for MAC address. */ mac_addr = new0(struct ether_addr, 1); if (!mac_addr) return -ENOMEM; /* allocate space for and FDB entry. */ fdb_entry = new0(FdbEntry, 1); if (!fdb_entry) { /* free previously allocated space for mac_addr. */ free(mac_addr); return -ENOMEM; } /* init FDB structure. */ fdb_entry->network = network; fdb_entry->mac_addr = mac_addr; LIST_PREPEND(static_fdb_entries, network->static_fdb_entries, fdb_entry); network->n_static_fdb_entries++; if (section) { fdb_entry->section = section; hashmap_put(network->fdb_entries_by_section, UINT_TO_PTR(fdb_entry->section), fdb_entry); } /* return allocated FDB structure. */ *ret = fdb_entry; fdb_entry = NULL; return 0; }
int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd, Operation **ret) { Operation *o; int r; assert(manager); assert(child > 1); assert(message); assert(errno_fd >= 0); o = new0(Operation, 1); if (!o) return -ENOMEM; o->extra_fd = -1; r = sd_event_add_child(manager->event, &o->event_source, child, WEXITED, operation_done, o); if (r < 0) { free(o); return r; } o->pid = child; o->message = sd_bus_message_ref(message); o->errno_fd = errno_fd; LIST_PREPEND(operations, manager->operations, o); manager->n_operations++; o->manager = manager; if (machine) { LIST_PREPEND(operations_by_machine, machine->operations, o); o->machine = machine; } log_debug("Started new operation " PID_FMT ".", child); /* At this point we took ownership of both the child and the errno file descriptor! */ if (ret) *ret = o; return 0; }
static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) { _cleanup_(stdout_stream_freep) StdoutStream *stream = NULL; sd_id128_t id; int r; assert(s); assert(fd >= 0); r = sd_id128_randomize(&id); if (r < 0) return log_error_errno(r, "Failed to generate stream ID: %m"); stream = new0(StdoutStream, 1); if (!stream) return log_oom(); stream->fd = -1; stream->priority = LOG_INFO; xsprintf(stream->id_field, "_STREAM_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id)); r = getpeercred(fd, &stream->ucred); if (r < 0) return log_error_errno(r, "Failed to determine peer credentials: %m"); if (mac_selinux_use()) { r = getpeersec(fd, &stream->label); if (r < 0 && r != -EOPNOTSUPP) (void) log_warning_errno(r, "Failed to determine peer security context: %m"); } (void) shutdown(fd, SHUT_WR); r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream); if (r < 0) return log_error_errno(r, "Failed to add stream to event loop: %m"); r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5); if (r < 0) return log_error_errno(r, "Failed to adjust stdout event source priority: %m"); stream->fd = fd; stream->server = s; LIST_PREPEND(stdout_stream, s->stdout_streams, stream); s->n_stdout_streams++; if (ret) *ret = stream; stream = NULL; return 0; }
static int load_link(link_config_ctx *ctx, const char *filename) { _cleanup_(link_config_freep) link_config *link = NULL; _cleanup_fclose_ FILE *file = NULL; int r; assert(ctx); assert(filename); file = fopen(filename, "re"); if (!file) { if (errno == ENOENT) return 0; else return -errno; } if (null_or_empty_fd(fileno(file))) { log_debug("Skipping empty file: %s", filename); return 0; } link = new0(link_config, 1); if (!link) return log_oom(); link->mac_policy = _MACPOLICY_INVALID; link->wol = _WOL_INVALID; link->duplex = _DUP_INVALID; link->port = _NET_DEV_PORT_INVALID; link->autonegotiation = -1; memset(&link->features, 0xFF, sizeof(link->features)); r = config_parse(NULL, filename, file, "Match\0Link\0Ethernet\0", config_item_perf_lookup, link_config_gperf_lookup, CONFIG_PARSE_WARN, link); if (r < 0) return r; else log_debug("Parsed configuration file %s", filename); if (link->speed > UINT_MAX) return -ERANGE; link->filename = strdup(filename); if (!link->filename) return log_oom(); LIST_PREPEND(links, ctx->links, link); link = NULL; return 0; }
static void bus_track_add_to_queue(sd_bus_track *track) { assert(track); if (track->in_queue) return; if (!track->handler) return; LIST_PREPEND(queue, track->bus->track_queue, track); track->in_queue = true; }
int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) { _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL; _cleanup_route_free_ Route *route = 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; route = hashmap_get(network->routes_by_section, n); if (route) { *ret = route; route = NULL; return 0; } } if (network->n_static_routes >= routes_max()) return -E2BIG; r = route_new(&route); if (r < 0) return r; route->protocol = RTPROT_STATIC; if (filename) { route->section = n; n = NULL; r = hashmap_put(network->routes_by_section, route->section, route); if (r < 0) return r; } route->network = network; LIST_PREPEND(routes, network->static_routes, route); network->n_static_routes++; *ret = route; route = NULL; return 0; }
void device_attach(Device *d, Seat *s) { assert(d); assert(s); if (d->seat == s) return; if (d->seat) device_detach(d); d->seat = s; LIST_PREPEND(Device, devices, s->devices, d); seat_send_changed(s, "CanGraphical\0"); }
static ImageClass * ImageclassCreate(const char *name) { ImageClass *ic; ic = ECALLOC(ImageClass, 1); if (!ic) return NULL; LIST_PREPEND(ImageClass, &iclass_list, ic); ic->name = Estrdup(name); return ic; }
static int load_link(link_config_ctx *ctx, const char *filename) { _cleanup_(link_config_freep) link_config *link = NULL; _cleanup_fclose_ FILE *file = NULL; int r; assert(ctx); assert(filename); file = fopen(filename, "re"); if (!file) { if (errno == ENOENT) return 0; else return -errno; } if (null_or_empty_fd(fileno(file))) { log_debug("Skipping empty file: %s", filename); return 0; } link = new0(link_config, 1); if (!link) return log_oom(); link->mac_policy = _MACPOLICY_INVALID; link->wol = _WOL_INVALID; link->duplex = _DUP_INVALID; r = config_parse(NULL, filename, file, "Match\0Link\0Ethernet\0", config_item_perf_lookup, link_config_gperf_lookup, false, false, true, link); if (r < 0) return r; else log_debug("Parsed configuration file %s", filename); link->filename = strdup(filename); LIST_PREPEND(links, ctx->links, link); link = NULL; return 0; }
int route_new_static(Network *network, unsigned section, Route **ret) { _cleanup_route_free_ Route *route = NULL; int r; assert(network); assert(ret); if (section) { route = hashmap_get(network->routes_by_section, UINT_TO_PTR(section)); if (route) { *ret = route; route = NULL; return 0; } } if (network->n_static_routes >= STATIC_ROUTES_PER_NETWORK_MAX) return -E2BIG; r = route_new(&route); if (r < 0) return r; route->protocol = RTPROT_STATIC; if (section) { route->section = section; r = hashmap_put(network->routes_by_section, UINT_TO_PTR(route->section), route); if (r < 0) return r; } route->network = network; LIST_PREPEND(routes, network->static_routes, route); network->n_static_routes++; *ret = route; route = NULL; 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_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 netlink_slot_allocate( sd_netlink *nl, bool floating, NetlinkSlotType type, size_t extra, sd_netlink_destroy_t destroy_callback, void *userdata, const char *description, sd_netlink_slot **ret) { _cleanup_free_ sd_netlink_slot *slot = NULL; assert(nl); assert(ret); slot = malloc0(offsetof(sd_netlink_slot, reply_callback) + extra); if (!slot) return -ENOMEM; slot->n_ref = 1; slot->netlink = nl; slot->userdata = userdata; slot->destroy_callback = destroy_callback; slot->type = type; slot->floating = floating; if (description) { slot->description = strdup(description); if (!slot->description) return -ENOMEM; } if (!floating) sd_netlink_ref(nl); LIST_PREPEND(slots, nl->slots, slot); *ret = TAKE_PTR(slot); return 0; }
static void ECursorCreate(const char *name, const char *image, int native_id, unsigned int fg, unsigned int bg) { ECursor *ec; if ((!name) || (!image && native_id == -1)) return; ec = ECALLOC(ECursor, 1); if (!ec) return; ec->name = Estrdup(name); ec->file = Estrdup(image); ec->fg = 0xff000000 | fg; ec->bg = 0xff000000 | bg; ec->native_id = native_id; LIST_PREPEND(ECursor, &cursor_list, ec); }
static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) { HashmapBase *h; const struct hashmap_type_info *hi = &hashmap_type_info[type]; bool use_pool; use_pool = is_main_thread(); h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size); if (!h) return NULL; h->type = type; h->from_pool = use_pool; h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops; if (type == HASHMAP_TYPE_ORDERED) { OrderedHashmap *lh = (OrderedHashmap*)h; lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; } reset_direct_storage(h); if (!shared_hash_key_initialized) { random_bytes(shared_hash_key, sizeof(shared_hash_key)); shared_hash_key_initialized= true; } #ifdef ENABLE_DEBUG_HASHMAP h->debug.func = func; h->debug.file = file; h->debug.line = line; assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0); LIST_PREPEND(debug_list, hashmap_debug_list, &h->debug); assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0); #endif return h; }
int route_new_static(Network *network, unsigned section, Route **ret) { _cleanup_route_free_ Route *route = NULL; if (section) { route = hashmap_get(network->routes_by_section, UINT_TO_PTR(section)); if (route) { *ret = route; route = NULL; return 0; } } route = new0(Route, 1); if (!route) return -ENOMEM; route->family = AF_UNSPEC; route->scope = RT_SCOPE_UNIVERSE; route->protocol = RTPROT_STATIC; route->network = network; LIST_PREPEND(routes, network->static_routes, route); if (section) { route->section = section; hashmap_put(network->routes_by_section, UINT_TO_PTR(route->section), route); } *ret = route; route = NULL; return 0; }
static int server_init(Server *s, unsigned n_sockets) { int r; unsigned i; assert(s); assert(n_sockets > 0); zero(*s); s->epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (s->epoll_fd < 0) { r = log_error_errno(errno, "Failed to create epoll object: %m"); goto fail; } for (i = 0; i < n_sockets; i++) { struct epoll_event ev; Fifo *f; int fd; fd = SD_LISTEN_FDS_START+i; r = sd_is_fifo(fd, NULL); if (r < 0) { log_error_errno(r, "Failed to determine file descriptor type: %m"); goto fail; } if (!r) { log_error("Wrong file descriptor type."); r = -EINVAL; goto fail; } f = new0(Fifo, 1); if (!f) { r = -ENOMEM; log_error_errno(errno, "Failed to create fifo object: %m"); goto fail; } f->fd = -1; zero(ev); ev.events = EPOLLIN; ev.data.ptr = f; if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { r = -errno; fifo_free(f); log_error_errno(errno, "Failed to add fifo fd to epoll object: %m"); goto fail; } f->fd = fd; LIST_PREPEND(fifo, s->fifos, f); f->server = s; s->n_fifos++; } r = bus_connect_system_systemd(&s->bus); if (r < 0) { log_error_errno(r, "Failed to get D-Bus connection: %m"); r = -EIO; goto fail; } return 0; fail: server_done(s); return r; }
int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { _cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL; DnssdService *s = userdata; DnsTxtItem *last = NULL; assert(filename); assert(lvalue); assert(rvalue); assert(s); if (isempty(rvalue)) { /* Flush out collected items */ s->txt_data_items = dnssd_txtdata_free_all(s->txt_data_items); return 0; } txt_data = new0(DnssdTxtData, 1); if (!txt_data) return log_oom(); for (;;) { _cleanup_free_ char *word = NULL; _cleanup_free_ char *key = NULL; _cleanup_free_ char *value = NULL; _cleanup_free_ void *decoded = NULL; size_t length = 0; DnsTxtItem *i; int r; r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX); if (r == 0) break; if (r == -ENOMEM) return log_oom(); if (r < 0) return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); r = split_pair(word, "=", &key, &value); if (r == -ENOMEM) return log_oom(); if (r == -EINVAL) key = TAKE_PTR(word); if (!ascii_is_valid(key)) { log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring: %s", key); return -EINVAL; } switch (ltype) { case DNS_TXT_ITEM_DATA: if (value) { r = unbase64mem(value, strlen(value), &decoded, &length); if (r == -ENOMEM) return log_oom(); if (r < 0) return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid base64 encoding, ignoring: %s", value); } r = dnssd_txt_item_new_from_data(key, decoded, length, &i); if (r < 0) return log_oom(); break; case DNS_TXT_ITEM_TEXT: r = dnssd_txt_item_new_from_string(key, value, &i); if (r < 0) return log_oom(); break; default: assert_not_reached("Unknown type of Txt config"); } LIST_INSERT_AFTER(items, txt_data->txt, last, i); last = i; } if (!LIST_IS_EMPTY(txt_data->txt)) { LIST_PREPEND(items, s->txt_data_items, txt_data); txt_data = NULL; } return 0; }
/** * Entry point into bt-daemon * @param argc Number of arguments passed * @param argv An array of string arguments * @returns EXIT_SUCCESS if the operation succeeded, otherwise EXIT_FAILURE */ int main(int argc, char *argv[]) { int fd; int smackfd = -1; socklen_t addr_len; struct sockaddr_un remote; int descriptors; int ret; bool manual_start = false; struct sigaction sa; if (!buxton_cache_smack_rules()) exit(EXIT_FAILURE); smackfd = buxton_watch_smack_rules(); if (smackfd < 0 && errno) exit(EXIT_FAILURE); self.nfds_alloc = 0; self.accepting_alloc = 0; self.nfds = 0; self.buxton.client.direct = true; self.buxton.client.uid = geteuid(); if (!buxton_direct_open(&self.buxton)) exit(EXIT_FAILURE); sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sa.sa_handler = my_handler; ret = sigaction(SIGINT, &sa, NULL); if (ret == -1) exit(EXIT_FAILURE); ret = sigaction(SIGTERM, &sa, NULL); if (ret == -1) exit(EXIT_FAILURE); /* For client notifications */ self.notify_mapping = hashmap_new(string_hash_func, string_compare_func); /* Store a list of connected clients */ LIST_HEAD_INIT(client_list_item, self.client_list); descriptors = sd_listen_fds(0); if (descriptors < 0) { buxton_log("sd_listen_fds: %m\n"); exit(EXIT_FAILURE); } else if (descriptors == 0) { /* Manual invocation */ manual_start = true; union { struct sockaddr sa; struct sockaddr_un un; } sa; fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { buxton_log("socket(): %m\n"); exit(EXIT_FAILURE); } memset(&sa, 0, sizeof(sa)); sa.un.sun_family = AF_UNIX; strncpy(sa.un.sun_path, BUXTON_SOCKET, sizeof(sa.un.sun_path) - 1); sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0; ret = unlink(sa.un.sun_path); if (ret == -1 && errno != ENOENT) { exit(EXIT_FAILURE); } if (bind(fd, &sa.sa, sizeof(sa)) < 0) { buxton_log("bind(): %m\n"); exit(EXIT_FAILURE); } chmod(sa.un.sun_path, 0666); if (listen(fd, SOMAXCONN) < 0) { buxton_log("listen(): %m\n"); exit(EXIT_FAILURE); } add_pollfd(&self, fd, POLLIN | POLLPRI, true); } else { /* systemd socket activation */ for (fd = SD_LISTEN_FDS_START + 0; fd < SD_LISTEN_FDS_START + descriptors; fd++) { if (sd_is_fifo(fd, NULL)) { add_pollfd(&self, fd, POLLIN, false); buxton_debug("Added fd %d type FIFO\n", fd); } else if (sd_is_socket_unix(fd, SOCK_STREAM, -1, BUXTON_SOCKET, 0)) { add_pollfd(&self, fd, POLLIN | POLLPRI, true); buxton_debug("Added fd %d type UNIX\n", fd); } else if (sd_is_socket(fd, AF_UNSPEC, 0, -1)) { add_pollfd(&self, fd, POLLIN | POLLPRI, true); buxton_debug("Added fd %d type SOCKET\n", fd); } } } if (smackfd >= 0) { /* add Smack rule fd to pollfds */ add_pollfd(&self, smackfd, POLLIN | POLLPRI, false); } buxton_log("%s: Started\n", argv[0]); /* Enter loop to accept clients */ for (;;) { ret = poll(self.pollfds, self.nfds, -1); if (ret < 0) { buxton_log("poll(): %m\n"); if (errno == EINTR) { if (do_shutdown) break; else continue; } break; } if (ret == 0) continue; for (nfds_t i=0; i<self.nfds; i++) { client_list_item *cl = NULL; char discard[256]; if (self.pollfds[i].revents == 0) continue; if (self.pollfds[i].fd == -1) { /* TODO: Remove client from list */ buxton_debug("Removing / Closing client for fd %d\n", self.pollfds[i].fd); del_pollfd(&self, i); continue; } if (smackfd >= 0) { if (self.pollfds[i].fd == smackfd) { if (!buxton_cache_smack_rules()) exit(EXIT_FAILURE); buxton_log("Reloaded Smack access rules\n"); /* discard inotify data itself */ while (read(smackfd, &discard, 256) == 256); continue; } } if (self.accepting[i] == true) { struct timeval tv; int fd; int on = 1; addr_len = sizeof(remote); if ((fd = accept(self.pollfds[i].fd, (struct sockaddr *)&remote, &addr_len)) == -1) { buxton_log("accept(): %m\n"); break; } buxton_debug("New client fd %d connected through fd %d\n", fd, self.pollfds[i].fd); cl = malloc0(sizeof(client_list_item)); if (!cl) exit(EXIT_FAILURE); LIST_INIT(client_list_item, item, cl); cl->fd = fd; cl->cred = (struct ucred) {0, 0, 0}; LIST_PREPEND(client_list_item, item, self.client_list, cl); /* poll for data on this new client as well */ add_pollfd(&self, cl->fd, POLLIN | POLLPRI, false); /* Mark our packets as high prio */ if (setsockopt(cl->fd, SOL_SOCKET, SO_PRIORITY, &on, sizeof(on)) == -1) buxton_log("setsockopt(SO_PRIORITY): %m\n"); /* Set socket recv timeout */ tv.tv_sec = SOCKET_TIMEOUT; tv.tv_usec = 0; if (setsockopt(cl->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)) == -1) buxton_log("setsockopt(SO_RCVTIMEO): %m\n"); /* check if this is optimal or not */ break; } assert(self.accepting[i] == 0); if (smackfd >= 0) assert(self.pollfds[i].fd != smackfd); /* handle data on any connection */ /* TODO: Replace with hash table lookup */ LIST_FOREACH(item, cl, self.client_list) if (self.pollfds[i].fd == cl->fd) break; assert(cl); handle_client(&self, cl, i); } } buxton_log("%s: Closing all connections\n", argv[0]); if (manual_start) unlink(BUXTON_SOCKET); for (int i = 0; i < self.nfds; i++) { close(self.pollfds[i].fd); } for (client_list_item *i = self.client_list; i;) { client_list_item *j = i->item_next; free(i); i = j; } hashmap_free(self.notify_mapping); buxton_direct_close(&self.buxton); return EXIT_SUCCESS; }