/* * Create a new hash context */ ni_hashctx_t * __ni_hashctx_new(int algo) { ni_hashctx_t *ctx; gcry_error_t err; ctx = calloc(1, sizeof(*ctx)); err = gcry_md_open(&ctx->handle, algo, 0); if (err) { ni_error("%s: gcry_md_open failed", __func__); ni_hashctx_free(ctx); return NULL; } ctx->md_length = gcry_md_get_algo_dlen(algo); return ctx; }
static dbus_bool_t ni_objectmodel_dummy_change(ni_dbus_object_t *object, const ni_dbus_method_t *method, unsigned int argc, const ni_dbus_variant_t *argv, ni_dbus_message_t *reply, DBusError *error) { ni_netconfig_t *nc = ni_global_state_handle(0); ni_netdev_t *dev, *cfg; /* we've already checked that argv matches our signature */ ni_assert(argc == 1); if (!(dev = ni_objectmodel_unwrap_netif(object, error)) || !(cfg = __ni_objectmodel_dummy_device_arg(&argv[0]))) { ni_dbus_error_invalid_args(error, object->path, method->name); return FALSE; } cfg->link.ifindex = dev->link.ifindex; if (ni_string_empty(cfg->name)) ni_string_dup(&cfg->name, dev->name); if (ni_netdev_device_is_up(dev)) { ni_debug_objectmodel("Skipping dummy changeDevice call on %s: " "device is up", dev->name); return TRUE; } if (ni_system_dummy_change(nc, dev, cfg) < 0) { dbus_set_error(error, DBUS_ERROR_FAILED, "Unable to change dummy properties on interface %s", dev->name); return FALSE; } if (cfg->link.hwaddr.type == ARPHRD_VOID) cfg->link.hwaddr.type = ARPHRD_ETHER; if (!ni_link_address_is_invalid(&cfg->link.hwaddr) && ni_system_hwaddr_change(nc, dev, &cfg->link.hwaddr) < 0) { ni_error("Unable to change hwaddr on dummy interface %s", dev->name); /* fail? */ } return TRUE; }
/* * pidfile management functions */ static int __ni_pidfile_write(const char *pidfile, unsigned int permissions, pid_t pid, int oflags) { FILE *fp; if ((fp = __ni_file_open(pidfile, "w", O_WRONLY|oflags, permissions)) == NULL) return -1; fprintf(fp, "%u", (unsigned int) pid); if (fclose(fp) < 0) { ni_error("error writing to pidfile %s: %m", pidfile); unlink(pidfile); return -1; } return 0; }
static void dhcp4_tester_protocol_event(enum ni_dhcp4_event ev, const ni_dhcp4_device_t *dev, ni_addrconf_lease_t *lease) { ni_debug_dhcp("%s(ev=%u, dev=%s[%u], config-uuid=%s)", __func__, ev, dev->ifname, dev->link.ifindex, dev->config ? ni_uuid_print(&dev->config->uuid) : "<none>"); switch (ev) { case NI_DHCP4_EVENT_ACQUIRED: if (lease && lease->state == NI_ADDRCONF_STATE_GRANTED) { FILE *fp = stdout; if (dhcp4_tester_opts.output != NULL) { fp = fopen(dhcp4_tester_opts.output, "w"); if (!fp) { ni_error("Cannot open %s for output", dhcp4_tester_opts.output); dhcp4_tester_status = NI_WICKED_RC_ERROR; return; } } if (dhcp4_tester_opts.outfmt == DHCP4_TESTER_OUT_LEASE_XML) { xml_node_t *xml = NULL; if (ni_addrconf_lease_to_xml(lease, &xml) != 0) { if (dhcp4_tester_opts.output) fclose(fp); dhcp4_tester_status = NI_WICKED_RC_ERROR; return; } xml_node_print(xml, fp); xml_node_free(xml); } else { ni_leaseinfo_dump(fp, lease, dev->ifname, NULL); } fflush(fp); if (dhcp4_tester_opts.output) fclose(fp); dhcp4_tester_status = 0; } break; default: break; } }
static ni_bool_t ni_objectmodel_save_state_xml(xml_node_t *list, ni_dbus_server_t *server) { ni_dbus_object_t *object, *netif_object; ni_bool_t rv = TRUE; object = ni_objectmodel_object_by_path(NI_OBJECTMODEL_NETIF_LIST_PATH); if (object == NULL) { ni_error("Cannot save state: no object list at %s", NI_OBJECTMODEL_NETIF_LIST_PATH); return FALSE; } for (netif_object = object->children; rv && netif_object; netif_object = netif_object->next) { rv = ni_objectmodel_save_object_state_xml(netif_object, list); } return rv; }
/* * Restore existing configuration */ static ni_bool_t ni_system_updater_restore(ni_updater_t *updater, const char *ifname) { if (!updater->have_backup) return TRUE; if (!updater->proc_restore) return TRUE; if (!ni_system_updater_run(updater->proc_restore, NULL)) { ni_error("failed to restore current %s settings", ni_updater_name(updater->kind)); return FALSE; } updater->have_backup = 0; return TRUE; }
int ni_hashctx_get_digest(ni_hashctx_t *ctx, void *md_buffer, size_t md_size) { void *md; if (ctx->handle == NULL) return -1; if (!(md = gcry_md_read(ctx->handle, 0))) { ni_error("%s: failed to obtain digest", __func__); return -1; } if (md_size > ctx->md_length) md_size = ctx->md_length; memcpy(md_buffer, md, md_size); return md_size; }
/* * Given a path name /foo/bar/baz, and a relative file name "blubber", * build /foo/bar/blubber */ const char * ni_sibling_path(const char *path, const char *file) { static char buffer[PATH_MAX]; unsigned int len; if (!__ni_dirname(path, buffer, sizeof(buffer))) return NULL; len = strlen(buffer); if (len + 2 + strlen(file) >= sizeof(buffer)) { ni_error("%s(%s, %s): path name too long", __func__, path, file); return FALSE; } snprintf(buffer + len, sizeof(buffer) - len, "/%s", file); return buffer; }
/* * XML Reader object */ static int xml_reader_open(xml_reader_t *xr, const char *filename) { memset(xr, 0, sizeof(*xr)); xr->filename = filename; xr->file = fopen(filename, "r"); if (xr->file == NULL) { ni_error("Unable to open %s: %m", filename); return -1; } xr->buffer = xmalloc(XML_READER_BUFSZ); xr->state = Initial; xr->lineCount = 1; xr->shared_location = xml_location_shared_new(filename); return 0; }
static ni_status start_service(ni_name tag) { ni_name master; ni_name mastertag; ni_status status; ni_name dbname; struct in_addr inaddr; system_log(LOG_DEBUG, "directory cleanup"); dir_cleanup(tag); dir_getnames(tag, &dbname, NULL, NULL); system_log(LOG_DEBUG, "initializing server"); status = ni_init(dbname, &db_ni); ni_name_free(&dbname); if (status != NI_OK) { system_log(LOG_ERR, "ni_init failed: %s", ni_error(status)); return (status); } system_log(LOG_DEBUG, "checksum = %u", ni_getchecksum(db_ni)); /* "local" is never a clone */ if (strcmp(tag, "local")) { if (getmaster(db_ni, &master, &mastertag)) { inaddr.s_addr = getaddress(db_ni, master); if (!sys_is_my_address(&inaddr)) i_am_clone++; if (!ni_name_match(tag, mastertag)) i_am_clone++; ni_name_free(&master); ni_name_free(&mastertag); } } if (forcedIsRoot == 0) forcedIsRoot = get_forced_root(db_ni); system_log(LOG_DEBUG, "registering tag %s", tag); status = register_it(tag); return (status); }
/* * Another class of extensions helps with updating system files such as resolv.conf * This expects scripts for install, backup and restore (named accordingly). * * <system-updater name="resolver"> * <script name="install" command="/some/crazy/path/to/script install" /> * <script name="backup" command="/some/crazy/path/to/script backup" /> * <script name="restore" command="/some/crazy/path/to/script restore" /> * ... * </system-updater> */ ni_bool_t ni_config_parse_system_updater(ni_extension_t **list, xml_node_t *node) { ni_extension_t *ex; const char *name; if (!(name = xml_node_get_attr(node, "name"))) { ni_error("%s: <%s> element lacks name attribute", node->name, xml_node_location(node)); return FALSE; } ex = ni_extension_new(list, name); /* If the updater has a format type, extract. */ ni_string_dup(&ex->format, xml_node_get_attr(node, "format")); return ni_config_parse_extension(ex, node); }
static ni_bool_t ni_config_extension_statedir(const char *extension_dirname, const int mode) { static ni_bool_t res = FALSE; char pathname[PATH_MAX]; if (!res) { snprintf(pathname, sizeof(pathname), "%s/%s", ni_config_statedir(), extension_dirname); if (ni_mkdir_maybe(pathname, mode) < 0) { ni_error("Cannot create extension state directory \"%s\": %m", pathname); res = FALSE; } else { res = TRUE; } } return res; }
/* * Connect the subprocess output to our I/O handling loop */ static void __ni_process_output_recv(ni_socket_t *sock) { ni_process_t *pi = sock->user_data; ni_buffer_t *rbuf = &sock->rbuf; int cnt; ni_assert(pi); if (ni_buffer_tailroom(rbuf) < 256) ni_buffer_ensure_tailroom(rbuf, 4096); cnt = recv(sock->__fd, ni_buffer_tail(rbuf), ni_buffer_tailroom(rbuf), MSG_DONTWAIT); if (cnt >= 0) { rbuf->tail += cnt; } else if (errno != EWOULDBLOCK) { ni_error("read error on subprocess pipe: %m"); ni_socket_deactivate(sock); } }
/* * Run the netif firmware discovery scripts and return their output * as an XML document. * The optional from parameter allow to specify the firmware extension * type (e.g. ibft) and a firmware type specific path (e.g. ethernet0), * passed as last argument to the discovery script. */ xml_document_t * ni_netconfig_firmware_discovery(const char *root, const char *from) { ni_buffer_t *buffer; xml_document_t *doc; char *path = NULL; char *type = NULL; /* sanity adjustments... */ if (ni_string_empty(root)) root = NULL; if (ni_string_empty(from)) from = NULL; else { ni_string_dup(&type, from); if ((path = strchr(type, ':'))) *path++ = '\0'; if (ni_string_empty(path)) path = NULL; } buffer = __ni_netconfig_firmware_discovery(root, type, path); if (buffer == NULL) { ni_string_free(&type); return NULL; } ni_debug_ifconfig("%s: %s%sbuffer has %u bytes", __func__, (from ? from : ""), (from ? " ": ""), ni_buffer_count(buffer)); doc = xml_document_from_buffer(buffer, from); ni_buffer_free(buffer); ni_string_free(&type); if (doc == NULL) ni_error("%s: error processing document", __func__); return doc; }
/* * LLDP.lldpUp */ static dbus_bool_t ni_objectmodel_lldp_up(ni_dbus_object_t *object, const ni_dbus_method_t *method, unsigned int argc, const ni_dbus_variant_t *argv, ni_dbus_message_t *reply, DBusError *error) { ni_netdev_t *dev, *cfg; dbus_bool_t rv = FALSE; /* we've already checked that argv matches our signature */ ni_assert(argc == 1); if (!(dev = ni_objectmodel_unwrap_netif(object, error))) return FALSE; ni_debug_lldp("ni_objectmodel_lldp_up(%s -> %s)", object->path, dev->name); if (!ni_system_lldp_available(dev)) { ni_error("Cannot enable LLDP for device %s: incompatible layer 2 protocol", dev->name); return TRUE; } if (!(cfg = __ni_objectmodel_protocol_arg(&argv[0], &ni_objectmodel_lldp_service))) { ni_dbus_error_invalid_args(error, object->path, method->name); goto out; } if (cfg->lldp && !__ni_objectmodel_lldp_verify(object, method, dev, cfg->lldp, error)) goto out; if (ni_system_lldp_up(dev, cfg->lldp) < 0) { dbus_set_error(error, DBUS_ERROR_FAILED, "failed to set up LLDP on device %s", dev->name); goto out; } rv = TRUE; out: if (cfg) ni_netdev_put(cfg); return rv; }
/* * Disconnect */ int ni_wireless_disconnect(ni_netdev_t *dev) { ni_wireless_t *wlan; ni_wpa_interface_t *wpa_dev; if ((wlan = ni_netdev_get_wireless(dev)) == NULL) { ni_error("%s: no wireless info for device", dev->name); return -1; } if (ni_rfkill_disabled(NI_RFKILL_TYPE_WIRELESS)) return -NI_ERROR_RADIO_DISABLED; if (!(wpa_dev = ni_wireless_bind_supplicant(dev))) return -1; ni_wireless_set_assoc_network(wlan, NULL); return ni_wpa_interface_disassociate(wpa_dev, wlan->conf.ap_scan); }
static int __ni_dhcp4_build_msg_put_server_id(const ni_dhcp4_device_t *dev, const ni_addrconf_lease_t *lease, unsigned int msg_code, ni_buffer_t *msgbuf) { ni_sockaddr_t addr; ni_sockaddr_set_ipv4(&addr, lease->dhcp4.server_id, 0); if (!ni_sockaddr_is_ipv4_specified(&addr)) { ni_error("%s: cannot construct %s without server-id", dev->ifname, ni_dhcp4_message_name(msg_code)); return -1; } ni_dhcp4_option_put_ipv4(msgbuf, DHCP4_SERVERIDENTIFIER, lease->dhcp4.server_id); ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP, "%s: using server-id: %s", dev->ifname, ni_sockaddr_print(&addr)); return 0; }
/* * This specifies sources of client configuration. * * The ifconfig source specifies the type, location and the * priority / load order of the interface configurations. * * <sources> * <ifconfig location="firmware:" /> * <ifconfig location="compat:" /> * <ifconfig location="wicked:/etc/wicked/ifconfig" /> * </sources> * */ static ni_bool_t __ni_config_parse_ifconfig_source(ni_string_array_t *sources, xml_node_t *node) { const char *attrval = NULL; unsigned int i; if ((attrval = xml_node_get_attr(node, "location")) != NULL && *attrval) { const char **p = __ni_ifconfig_source_types; for (i = 0; p[i]; i++) { if (!strncasecmp(attrval, p[i], ni_string_len(p[i]))) { ni_debug_readwrite("%s: Adding ifconfig %s", __func__, attrval); ni_string_array_append(sources, attrval); return TRUE; } } } ni_error("Unknown ifconfig location: %s", attrval); return FALSE; }
/* * Bring up the device */ void ni_managed_device_down(ni_managed_device_t *mdev) { ni_fsm_t *fsm = mdev->nanny->fsm; ni_ifworker_t *w = mdev->worker; int rv; ni_ifworker_set_completion_callback(w, ni_managed_device_down_done, mdev->nanny); ni_ifworker_set_config(w, mdev->selected_config, w->config.meta.origin); w->target_range.min = NI_FSM_STATE_NONE; w->target_range.max = NI_FSM_STATE_DEVICE_DOWN; if ((rv = ni_ifworker_start(fsm, w, fsm->worker_timeout)) >= 0) { mdev->state = NI_MANAGED_STATE_STOPPING; } else { ni_error("%s: cannot stop device: %s", w->name, ni_strerror(rv)); mdev->state = NI_MANAGED_STATE_FAILED; } }
int ni_dhcp4_fsm_arp_validate(ni_dhcp4_device_t *dev) { struct in_addr null = { 0 }; struct in_addr claim; if (!dev || !dev->lease) return -1; claim = dev->lease->dhcp4.address; if (dev->arp.handle == NULL) { dev->arp.handle = ni_arp_socket_open(&dev->system, ni_dhcp4_fsm_process_arp_packet, dev); if (!dev->arp.handle->user_data) { ni_error("%s: unable to create ARP handle", dev->ifname); return -1; } } if (dev->arp.nprobes) { ni_debug_dhcp("%s: arp validate: probing for %s", dev->ifname, inet_ntoa(claim)); ni_arp_send_request(dev->arp.handle, null, claim); dev->arp.nprobes--; } else if (dev->arp.nclaims) { ni_debug_dhcp("%s: arp validate: claiming %s", dev->ifname, inet_ntoa(claim)); ni_arp_send_grat_request(dev->arp.handle, claim); dev->arp.nclaims--; } else { /* Wow, we're done! */ ni_info("%s: Successfully validated DHCPv4 address %s", dev->ifname, inet_ntoa(claim)); ni_dhcp4_fsm_commit_lease(dev, dev->lease); ni_dhcp4_device_arp_close(dev); return 0; } ni_dhcp4_fsm_set_timeout_msec(dev, NI_DHCP4_ARP_TIMEOUT); return 0; }
/* * Request association */ int ni_wireless_set_network(ni_netdev_t *dev, ni_wireless_network_t *net) { ni_wireless_t *wlan; ni_wpa_interface_t *wpa_dev; if ((wlan = ni_netdev_get_wireless(dev)) == NULL) { ni_error("%s: no wireless info for device", dev->name); return -1; } if (ni_rfkill_disabled(NI_RFKILL_TYPE_WIRELESS)) return -NI_ERROR_RADIO_DISABLED; if (!(wpa_dev = ni_wireless_bind_supplicant(dev))) return -1; if (net->keymgmt_proto == NI_WIRELESS_KEY_MGMT_EAP) { if (net->wpa_eap.tls.ca_cert) { /* FIXME: store this as a blob */ } if (net->wpa_eap.tls.client_cert) { /* FIXME: store this as a blob */ } if (net->wpa_eap.tls.client_key) { /* FIXME: store this as a blob */ } /* Copied from NetworkManager */ net->fragment_size = 1300; } /* Make sure we drop our exsting association */ /* FIXME: we should only do this if the new association * request is different. */ if (wlan->assoc.state != NI_WIRELESS_NOT_ASSOCIATED) ni_wpa_interface_disassociate(wpa_dev, wlan->conf.ap_scan); ni_wireless_set_assoc_network(wlan, net); return ni_wpa_interface_associate(wpa_dev, net, wlan->conf.ap_scan); }
int __ni_wireless_process_ie(ni_wireless_network_t *net, void *ptr, size_t len) { ni_buffer_t data; ni_buffer_init_reader(&data, ptr, len); while (ni_buffer_count(&data) >= 2) { unsigned char type, len; int rv = -1; if (ni_buffer_get(&data, &type, 1) < 0 || ni_buffer_get(&data, &len, 1) < 0) goto format_error; if (ni_buffer_count(&data) < len) goto format_error; ptr = ni_buffer_head(&data); data.head += len; switch (type) { case 0xdd: rv = __ni_wireless_process_wpa1(net, ptr, len); break; case 0x30: rv = __ni_wireless_process_wpa2(net, ptr, len); break; default: ni_debug_wireless("Skipping unsupported Informaton Element 0x%02x", type); continue; } if (rv < 0) return -1; } return 0; format_error: ni_error("error processing wireless Information Elements"); return -1; }
static int __ni_dhcp4_build_msg_put_hwspec(const ni_dhcp4_device_t *dev, ni_dhcp4_message_t *message) { switch (dev->system.hwaddr.type) { case ARPHRD_ETHER: case ARPHRD_IEEE802: if (dev->system.hwaddr.len && dev->system.hwaddr.len <= sizeof(message->chaddr)) { message->hwlen = dev->system.hwaddr.len; memcpy(&message->chaddr, dev->system.hwaddr.data, dev->system.hwaddr.len); } break; case ARPHRD_IEEE1394: case ARPHRD_INFINIBAND: /* See http://tools.ietf.org/html/rfc4390 * * Note: set the ciaddr before if needed. */ message->hwlen = 0; if (message->ciaddr == 0) message->flags = htons(BROADCAST_FLAG); break; default: ni_error("%s: dhcp4 unsupported hardware type %s (0x%x)", dev->ifname, ni_arphrd_type_to_name(dev->system.hwaddr.type), dev->system.hwaddr.type); return -1; } if (message->hwlen) { ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP, "%s: using hw-address[%u]: %s", dev->ifname, message->hwtype, ni_print_hex(message->chaddr, message->hwlen)); } if (message->flags & htons(BROADCAST_FLAG)) { ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP, "%s: using broadcast response flag", dev->ifname); } return 0; }
static ni_bool_t ni_system_update_remove_matching_leases(ni_updater_t *updater, const ni_addrconf_lease_t *lease, const unsigned int ifindex, const char *ifname) { ni_updater_source_t *src = NULL; unsigned int i; if (!updater || !lease) { ni_error("Unintialized updater sources or lease."); return FALSE; } for (i = 0; i < updater->sources.count; ) { src = updater->sources.data[i]; if (src && src->lease && src->d_ref.index == ifindex && src->lease->type == lease->type && src->lease->family == lease->family) { /* Found an existing lease of interest to remove/replace with 'lease.' * If lease is not in granted state (ie. it's a removal request) or if * the interface name has changed, actually remove the existing src->lease. * Otherwise, it's a simple replacement/overwrite so no need to remove lease * information from the system. */ if (!ni_string_eq(src->d_ref.name, ifname) || lease->state != NI_ADDRCONF_STATE_GRANTED) { ni_system_updater_remove(updater, src->lease, src->d_ref.name); } if (ni_updater_source_array_delete(&updater->sources, i)) continue; } i++; } return TRUE; }
/* * Create a temporary file */ FILE * ni_mkstemp(char **namep) { char namebuf[PATH_MAX]; char *tmpdir; int fd; if (namep == NULL) return tmpfile(); if ((tmpdir = getenv("TMPDIR")) == NULL) tmpdir = "/tmp"; snprintf(namebuf, sizeof(namebuf), "%s/wicked.XXXXXX", tmpdir); if ((fd = mkstemp(namebuf)) < 0) { ni_error("unable to create unique tempfile in %s", tmpdir); return NULL; } ni_string_dup(namep, namebuf); return fdopen(fd, "w"); }
static xml_node_t * __ni_compat_generate_static_address_list(xml_node_t *ifnode, ni_address_t *addr_list, unsigned int af) { ni_address_t *ap; const char *afname; xml_node_t *aconf = NULL; afname = ni_addrfamily_type_to_name(af); if (!afname) { ni_error("%s: unknown address family %u", __func__, af); return NULL; } for (ap = addr_list; ap; ap = ap->next) { xml_node_t *anode; if (ap->family != af) continue; if (aconf == NULL) { char buffer[64]; snprintf(buffer, sizeof(buffer), "%s:static", afname); aconf = xml_node_create(ifnode, buffer); } anode = xml_node_new("address", aconf); xml_node_new_element("local", anode, ni_sockaddr_prefix_print(&ap->local_addr, ap->prefixlen)); if (ap->peer_addr.ss_family != AF_UNSPEC) xml_node_new_element("peer", anode, ni_sockaddr_print(&ap->peer_addr)); if (ap->bcast_addr.ss_family != AF_UNSPEC) xml_node_new_element("broadcast", anode, ni_sockaddr_print(&ap->bcast_addr)); if (ap->label) xml_node_new_element("label", anode, ap->label); } return aconf; }
static int __do_arp_validate_init(struct arp_handle *handle, ni_capture_devinfo_t *dev_info) { ni_netconfig_t *nc; ni_netdev_t *dev; if (ni_server_listen_interface_events(NULL) < 0) { ni_error("unable to initialize netlink link listener"); return NI_LSB_RC_ERROR; } if (ni_server_enable_interface_addr_events(NULL) < 0) { ni_error("unable to initialize netlink addr listener"); return NI_LSB_RC_ERROR; } if (!(nc = ni_global_state_handle(1))) { ni_error("Cannot refresh interface list!"); return NI_LSB_RC_ERROR; } if (!(dev = ni_netdev_by_name(nc, handle->ifname))) { ni_error("Cannot find interface with name '%s'", handle->ifname); return NI_LSB_RC_ERROR; } if (!ni_netdev_supports_arp(dev)) { ni_error("%s: arp is not supported/enabled", dev->name); return NI_LSB_RC_ERROR; } if (!ni_netdev_link_is_up(dev)) { ni_error("%s: link is not up", dev->name); return NI_LSB_RC_ERROR; } if (ni_capture_devinfo_init(dev_info, dev->name, &dev->link) < 0) { ni_error("%s: cannot initialize capture", dev->name); return NI_LSB_RC_ERROR; } return 0; }
static ni_bool_t __ni_rtevent_join_group(ni_rtevent_handle_t *handle, unsigned int group) { int ret; if (!group || !handle || !handle->nlsock) return FALSE; if (ni_uint_array_contains(&handle->groups, group)) return TRUE; if (!ni_uint_array_append(&handle->groups, group)) return FALSE; ret = nl_socket_add_membership(handle->nlsock, group); if (ret != NLE_SUCCESS) { /* remove from array? */ ni_error("Cannot add rtnetlink group %u membership: %s", group, nl_geterror(ret)); return FALSE; } return TRUE; }
char * xml_document_sprint(const xml_document_t *doc) { char *string = NULL; size_t size = 0; FILE *fp; int rv; if ((fp = open_memstream(&string, &size)) == NULL) { ni_error("%s: unable to open memstream", __func__); return NULL; } rv = xml_document_print(doc, fp); fclose(fp); if (rv < 0) { free(string); return NULL; } return string; }
/* * Register all naming services specified in the config file. * These naming services are supposed to be provided by shared libraries. * The symbol specified by the C binding element must refer to a * ni_objectmodel_ns struct. */ void ni_objectmodel_register_ns_dynamic(void) { ni_config_t *config = ni_global.config; ni_extension_t *ex; ni_assert(config); for (ex = config->ns_extensions; ex; ex = ex->next) { ni_c_binding_t *binding; void *addr; for (binding = ex->c_bindings; binding; binding = binding->next) { if ((addr = ni_c_binding_get_address(binding)) == NULL) { ni_error("cannot bind %s name service - invalid C binding", binding->name); continue; } ni_debug_objectmodel("trying to bind netif naming service \"%s\"", binding->name); ni_objectmodel_register_ns((ni_objectmodel_ns_t *) addr); } } }