void ni_addrconf_lease_destroy(ni_addrconf_lease_t *lease) { ni_addrconf_updater_free(&lease->updater); if (lease->old) { ni_addrconf_lease_free(lease->old); lease->old = NULL; } ni_string_free(&lease->owner); ni_string_free(&lease->hostname); ni_address_list_destroy(&lease->addrs); ni_route_tables_destroy(&lease->routes); if (lease->nis) { ni_nis_info_free(lease->nis); lease->nis = NULL; } if (lease->resolver) { ni_resolver_info_free(lease->resolver); lease->resolver = NULL; } ni_string_array_destroy(&lease->ntp_servers); ni_string_array_destroy(&lease->nds_servers); ni_string_array_destroy(&lease->nds_context); ni_string_free(&lease->nds_tree); ni_string_array_destroy(&lease->netbios_name_servers); ni_string_array_destroy(&lease->netbios_dd_servers); ni_string_free(&lease->netbios_scope); ni_string_array_destroy(&lease->slp_servers); ni_string_array_destroy(&lease->slp_scopes); ni_string_array_destroy(&lease->sip_servers); ni_string_array_destroy(&lease->lpr_servers); ni_string_array_destroy(&lease->log_servers); ni_string_free(&lease->posix_tz_string); ni_string_free(&lease->posix_tz_dbname); switch (lease->type) { case NI_ADDRCONF_DHCP: switch (lease->family) { case AF_INET: ni_addrconf_lease_dhcp4_destroy(&lease->dhcp4); break; case AF_INET6: ni_addrconf_lease_dhcp6_destroy(&lease->dhcp6); break; default: ; } break; default: ; } }
static void __ni_shellcmd_free(ni_shellcmd_t *cmd) { ni_string_free(&cmd->command); ni_string_array_destroy(&cmd->argv); ni_string_array_destroy(&cmd->environ); free(cmd); }
static void get_ethtool_link_advertising(const char *type, ni_bitfield_t *bitfield) { ni_string_array_t tmp = NI_STRING_ARRAY_INIT; char *hexstr = NULL; unsigned int n; if (!ni_bitfield_isset(bitfield) || !type) return; printf("\t%s:\n", type); printf("\t\tautoneg: %s\n", ni_format_boolean(ni_ethtool_link_adv_autoneg(bitfield))); ni_ethtool_link_adv_set_autoneg(bitfield, FALSE); if (get_ethtool_link_adv_name_array(&tmp, bitfield, ni_ethtool_link_adv_port_name)) { printf("\t\tport-types:\n"); for (n = 0; n < tmp.count; ++n) { printf("\t\t\ttype: %s\n", tmp.data[n]); } } ni_string_array_destroy(&tmp); if (get_ethtool_link_adv_name_array(&tmp, bitfield, ni_ethtool_link_adv_speed_name)) { printf("\t\tspeed-modes:\n"); for (n = 0; n < tmp.count; ++n) { printf("\t\t\tmode: %s\n", tmp.data[n]); } } ni_string_array_destroy(&tmp); if (get_ethtool_link_adv_name_array(&tmp, bitfield, ni_ethtool_link_adv_pause_name)) { printf("\t\tpause-frames:\n"); for (n = 0; n < tmp.count; ++n) { printf("\t\t\ttype: %s\n", tmp.data[n]); } } ni_string_array_destroy(&tmp); if (get_ethtool_link_adv_name_array(&tmp, bitfield, ni_ethtool_link_adv_fec_name)) { printf("\t\tfec-modes:\n"); for (n = 0; n < tmp.count; ++n) { printf("\t\t\tmode: %s\n", tmp.data[n]); } } ni_string_array_destroy(&tmp); if (get_ethtool_link_adv_name_array(&tmp, bitfield, ni_ethtool_link_adv_port_name)) { printf("\t\tport-types:\n"); for (n = 0; n < tmp.count; ++n) { printf("\t\t\ttype: %s\n", tmp.data[n]); } } ni_string_array_destroy(&tmp); if (ni_bitfield_isset(bitfield) && ni_bitfield_format(bitfield, &hexstr, TRUE)) printf("\t\tunknown: %s\n", hexstr); ni_string_free(&hexstr); }
void ni_string_array_move(ni_string_array_t *dst, ni_string_array_t *src) { ni_string_array_destroy(dst); *dst = *src; memset(src, 0, sizeof(*src)); }
/* * priv-flags (GPFLAGS,SPFLAGS) */ void ni_ethtool_priv_flags_free(ni_ethtool_priv_flags_t *priv_flags) { if (priv_flags) { ni_string_array_destroy(&priv_flags->names); free(priv_flags); } }
/* * Compare string arrays, much the same way comm(1) works * We ignore order of the input arrays, but expect values to be * unique. * * Mode of operations: first duplicate string arrays. * Then sort array A into common or uniq_a - we can do this by simply * moving the string pointer, no need to further clone it. * When we find a common string, we also clear out the corresponding * value in B. * As a last step, we know that any strings left in the copy of array B * must be unique to B. */ void ni_string_array_comm(const ni_string_array_t *a, const ni_string_array_t *b, ni_string_array_t *uniq_a, ni_string_array_t *uniq_b, ni_string_array_t *common) { ni_string_array_t copy_a, copy_b; unsigned int i, j; ni_string_array_init(©_a); ni_string_array_copy(©_a, a); ni_string_array_init(©_b); ni_string_array_copy(©_b, b); for (i = 0; i < copy_a.count; ++i) { char *val_a = copy_a.data[i]; for (j = 0; j < copy_b.count && val_a; ++j) { char *val_b = copy_b.data[j]; if (val_b && !strcmp(val_a, val_b)) { __ni_string_array_append(common, val_a); ni_string_free(©_b.data[j]); val_a = NULL; } } if (val_a) __ni_string_array_append(uniq_a, val_a); copy_a.data[i] = NULL; } for (j = 0; j < copy_b.count; ++j) { char *val_b = copy_b.data[j]; if (val_b) __ni_string_array_append(uniq_b, val_b); copy_b.data[j] = NULL; } ni_string_array_destroy(©_a); ni_string_array_destroy(©_b); }
static void ni_addrconf_lease_dhcp6_destroy(struct ni_addrconf_lease_dhcp6 *dhcp6) { if (dhcp6) { ni_dhcp6_status_destroy(&dhcp6->status); ni_dhcp6_ia_list_destroy(&dhcp6->ia_list); ni_string_free(&dhcp6->boot_url); ni_string_array_destroy(&dhcp6->boot_params); } }
int ni_string_array_copy(ni_string_array_t *dst, const ni_string_array_t *src) { unsigned int i; ni_string_array_destroy(dst); for (i = 0; i < src->count; ++i) { if (ni_string_array_append(dst, src->data[i]) < 0) return -1; } return 0; }
static dbus_bool_t ni_objectmodel_ethtool_link_adv_fec_modes_into_dict(ni_dbus_variant_t *dict, ni_bitfield_t *bitfield) { ni_string_array_t tmp = NI_STRING_ARRAY_INIT; ni_dbus_variant_t *ent; if (!dict || !ni_bitfield_words(bitfield)) return FALSE; if (!ni_objectmodel_ethtool_link_adv_bitfield_into_array(&tmp, bitfield, ni_ethtool_link_adv_fec_name)) return FALSE; if (!(ent = ni_dbus_dict_add(dict, "fec-modes"))) { ni_string_array_destroy(&tmp); return FALSE; } ni_dbus_variant_set_string_array(ent, (const char **)tmp.data, tmp.count); ni_string_array_destroy(&tmp); return TRUE; }
void ni_process_free(ni_process_t *pi) { if (pi->pid) { if (kill(pi->pid, SIGKILL) < 0) ni_error("Unable to kill process %d (%s): %m", pi->pid, pi->process->command); } if (pi->socket != NULL) { ni_socket_close(pi->socket); pi->socket = NULL; } if (pi->temp_state != NULL) { ni_tempstate_finish(pi->temp_state); pi->temp_state = NULL; } ni_string_array_destroy(&pi->argv); ni_string_array_destroy(&pi->environ); ni_shellcmd_release(pi->process); free(pi); }
static dbus_bool_t __ni_objectmodel_bonding_set_arpmon(ni_dbus_object_t *object, const ni_dbus_property_t *property, const ni_dbus_variant_t *result, DBusError *error) { ni_bonding_t *bond; ni_dbus_variant_t *var; if (!(bond = __ni_objectmodel_bonding_write_handle(object, error))) return FALSE; bond->monitoring |= NI_BOND_MONITOR_ARP; ni_dbus_dict_get_uint32(result, "interval", &bond->arpmon.interval); ni_dbus_dict_get_uint32(result, "validate", &bond->arpmon.validate); if ((var = ni_dbus_dict_get(result, "targets")) != NULL) { ni_bool_t valid = TRUE; unsigned int i; if (!ni_dbus_variant_is_string_array(var)) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s.%s property - expected string array for attribute targets", object->path, property->name); return FALSE; } for (i = 0; i < var->array.len; ++i) { const char *s = var->string_array_value[i]; if (!ni_bonding_is_valid_arp_ip_target(s)) { valid = FALSE; break; } ni_string_array_append(&bond->arpmon.targets, s); } if (!valid) { ni_string_array_destroy(&bond->arpmon.targets); dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s.%s property - invalid arp ip target adddress", object->path, property->name); return FALSE; } } return TRUE; }
void ni_config_free(ni_config_t *conf) { ni_string_array_destroy(&conf->sources.ifconfig); ni_extension_list_destroy(&conf->dbus_extensions); ni_extension_list_destroy(&conf->ns_extensions); ni_extension_list_destroy(&conf->fw_extensions); ni_extension_list_destroy(&conf->updater_extensions); ni_string_free(&conf->dbus_name); ni_string_free(&conf->dbus_type); ni_string_free(&conf->dbus_xml_schema_file); ni_config_fslocation_destroy(&conf->piddir); ni_config_fslocation_destroy(&conf->storedir); ni_config_fslocation_destroy(&conf->statedir); ni_config_fslocation_destroy(&conf->backupdir); free(conf); }
static inline int ni_ethtool_get_priv_flags_names(const char *ifname, ni_ethtool_t *ethtool, ni_string_array_t *names) { struct ethtool_gstrings *gstrings; unsigned int count, i; ni_stringbuf_t buf; const char *name; count = ni_ethtool_get_gstring_count(ifname, " priv-flags count", ETH_SS_PRIV_FLAGS); if (!count) { if (errno == EOPNOTSUPP && ethtool->driver_info) count = ethtool->driver_info->supports.n_priv_flags; if (!count) { ni_ethtool_set_supported(ethtool, NI_ETHTOOL_SUPP_GET_PRIV_FLAGS, FALSE); return -EOPNOTSUPP; } } if (count > 32) count = 32; gstrings = ni_ethtool_get_gstrings(ifname, " priv-flags names", ETH_SS_PRIV_FLAGS, count); if (!gstrings) { if (errno == EOPNOTSUPP) ni_ethtool_set_supported(ethtool, NI_ETHTOOL_SUPP_GET_PRIV_FLAGS, FALSE); free(gstrings); return errno ? -errno : -1; } ni_stringbuf_init(&buf); for (i = 0; i < gstrings->len; ++i) { name = (const char *)(gstrings->data + i * ETH_GSTRING_LEN); ni_stringbuf_put(&buf, name, ETH_GSTRING_LEN); ni_stringbuf_trim_head(&buf, " \t\n"); ni_stringbuf_trim_tail(&buf, " \t\n"); ni_string_array_append(names, buf.string); ni_stringbuf_destroy(&buf); } free(gstrings); if (names->count == count) return 0; ni_string_array_destroy(names); return -ENOMEM; /* array append */ }
static ni_bool_t set_ethtool_wake_on_lan_options(ni_ethtool_wake_on_lan_t *wol, const char *value) { ni_string_array_t tmp = NI_STRING_ARRAY_INIT; unsigned int i, flag; unsigned int options; ni_bool_t ret = TRUE; if (!ni_string_split(&tmp, value, ",|", 0)) return FALSE; if (tmp.count == 1) { value = tmp.data[0]; if (set_ethtool_wake_on_lan_letterjam(wol, value)) goto cleanup; } options = NI_ETHTOOL_WOL_DISABLE; for (i = 0; i < tmp.count; ++i) { value = tmp.data[i]; if (ni_string_eq(value, "d") || ni_string_eq(value, "disable") || ni_string_eq(value, "disabled")) { wol->options = NI_ETHTOOL_WOL_DISABLE; break; } if (ni_ethtool_wol_flag_type(value, &flag)) options |= NI_BIT(flag); else ret = FALSE; } if (ret && wol->options == NI_ETHTOOL_WOL_DEFAULT) wol->options = options; cleanup: ni_string_array_destroy(&tmp); return ret; }
void ni_tempstate_finish(ni_tempstate_t *ts) { unsigned int i; for (i = 0; i < ts->files.count; ++i) { const char *filename = ts->files.data[i]; if (unlink(filename) < 0) ni_warn("failed to remove %s: %m", filename); } if (ts->dirpath) { ni_file_remove_recursively(ts->dirpath); ni_string_free(&ts->dirpath); } ni_string_array_destroy(&ts->files); ni_string_free(&ts->ident); free(ts); }
static int ni_dhcp4_option_get_domain_list(ni_buffer_t *bp, ni_string_array_t *var, const char *what) { ni_string_array_t list = NI_STRING_ARRAY_INIT; unsigned int len, i; char *tmp = NULL; if (ni_dhcp4_option_get_string(bp, &tmp, &len) < 0) return -1; /* * Hack to accept "compatibility abuse" of dns domain name * option containing multiple domains instead to send them * using a dns-search option... */ if (!ni_string_split(&list, tmp, " ", 0)) { ni_warn("Discarded suspect %s: '%s'", what, ni_print_suspect(tmp, len)); free(tmp); return -1; } for (i = 0; i < list.count; ++i) { const char *dom = list.data[i]; if (!ni_check_domain_name(dom, ni_string_len(dom), 0)) { ni_warn("Discarded suspect %s: '%s'", what, ni_print_suspect(tmp, len)); ni_string_array_destroy(&list); free(tmp); return -1; } } if (list.count != 1) { ni_warn("Abuse of %s option to provide a list: '%s'", what, tmp); } free(tmp); ni_string_array_move(var, &list); return 0; }
static inline ni_bool_t set_ethtool_link_advertise(const char *value, ni_bitfield_t *bitfield) { ni_string_array_t tmp = NI_STRING_ARRAY_INIT; unsigned int i, bit; ni_bool_t ret = FALSE; if (ni_string_split(&tmp, value, ",", 0)) { ret = tmp.count > 0; for (i = 0; i < tmp.count; ++i) { value = tmp.data[i]; if (ni_ethtool_link_adv_type(value, &bit)) ni_bitfield_setbit(bitfield, bit); else if (!(ret = ni_bitfield_parse(bitfield, value, 0))) break; } } ni_string_array_destroy(&tmp); return ret; }
/* * eee */ static void get_ethtool_eee_advertising(const char *type, ni_bitfield_t *bitfield) { ni_string_array_t tmp = NI_STRING_ARRAY_INIT; unsigned int n; char * hexstr = NULL; if (!ni_bitfield_isset(bitfield) || !type) return; printf("\t%s:\n", type); if (get_ethtool_link_adv_name_array(&tmp, bitfield, ni_ethtool_link_adv_speed_name)) { printf("\t\tspeed-modes:\n"); for (n = 0; n < tmp.count; ++n) { printf("\t\t\tmode: %s\n", tmp.data[n]); } } ni_string_array_destroy(&tmp); if (ni_bitfield_isset(bitfield) && ni_bitfield_format(bitfield, &hexstr, TRUE)) printf("\t\tunknown: %s\n", hexstr); ni_string_free(&hexstr); }
int ni_do_ifdown(int argc, char **argv) { enum { OPT_HELP, OPT_FORCE, OPT_DELETE, OPT_NO_DELETE, OPT_TIMEOUT }; static struct option ifdown_options[] = { { "help", no_argument, NULL, OPT_HELP }, { "force", required_argument, NULL, OPT_FORCE }, { "delete", no_argument, NULL, OPT_DELETE }, { "no-delete", no_argument, NULL, OPT_NO_DELETE }, { "timeout", required_argument, NULL, OPT_TIMEOUT }, { NULL } }; ni_ifmatcher_t ifmatch; ni_ifmarker_t ifmarker; ni_ifworker_array_t ifmarked; ni_string_array_t ifnames = NI_STRING_ARRAY_INIT; unsigned int nmarked, max_state = NI_FSM_STATE_DEVICE_DOWN; unsigned int timeout = NI_IFWORKER_DEFAULT_TIMEOUT; ni_stringbuf_t sb = NI_STRINGBUF_INIT_DYNAMIC; ni_fsm_t *fsm; int c, status = NI_WICKED_RC_USAGE; fsm = ni_fsm_new(); ni_assert(fsm); ni_fsm_require_register_type("reachable", ni_ifworker_reachability_check_new); /* Allow ifdown only on non-persistent interfaces previously configured by ifup */ memset(&ifmatch, 0, sizeof(ifmatch)); memset(&ifmarker, 0, sizeof(ifmarker)); memset(&ifmarked, 0, sizeof(ifmarked)); ifmatch.require_configured = TRUE; ifmatch.allow_persistent = FALSE; ifmatch.require_config = FALSE; ifmarker.target_range.min = NI_FSM_STATE_DEVICE_DOWN; ifmarker.target_range.max = __NI_FSM_STATE_MAX - 2; optind = 1; while ((c = getopt_long(argc, argv, "", ifdown_options, NULL)) != EOF) { switch (c) { case OPT_FORCE: if (!ni_ifworker_state_from_name(optarg, &max_state) || !ni_ifworker_state_in_range(&ifmarker.target_range, max_state)) { ni_error("ifdown: wrong force option \"%s\"", optarg); goto usage; } /* Allow ifdown on persistent, unconfigured interfaces */ ifmatch.require_configured = FALSE; ifmatch.allow_persistent = TRUE; ifmatch.require_config = FALSE; break; case OPT_DELETE: max_state = NI_FSM_STATE_DEVICE_DOWN; /* Allow ifdown on persistent, unconfigured interfaces */ ifmatch.require_configured = FALSE; ifmatch.allow_persistent = TRUE; ifmatch.require_config = FALSE; break; case OPT_NO_DELETE: max_state = NI_FSM_STATE_DEVICE_READY; /* Allow ifdown only on non-persistent interfaces previously configured by ifup */ ifmatch.require_configured = TRUE; ifmatch.allow_persistent = FALSE; ifmatch.require_config = FALSE; break; case OPT_TIMEOUT: if (!strcmp(optarg, "infinite")) { timeout = NI_IFWORKER_INFINITE_TIMEOUT; } else if (ni_parse_uint(optarg, &timeout, 10) >= 0) { timeout *= 1000; /* sec -> msec */ } else { ni_error("ifdown: cannot parse timeout option \"%s\"", optarg); goto usage; } break; default: case OPT_HELP: usage: ni_client_get_state_strings(&sb, &ifmarker.target_range); fprintf(stderr, "wicked [options] ifdown [ifdown-options] <ifname ...>|all\n" "\nSupported ifdown-options:\n" " --help\n" " Show this help text.\n" " --force <state>\n" " Force putting interface into the <state> state. Despite of persistent mode being set. Possible states:\n" " %s\n" " --delete\n" " Delete device. Despite of persistent mode being set\n" " --no-delete\n" " Do not attempt to delete a device, neither physical nor virtual\n" " --timeout <nsec>\n" " Timeout after <nsec> seconds\n", sb.string ); ni_stringbuf_destroy(&sb); return status; } } if (optind >= argc) { fprintf(stderr, "Missing interface argument\n"); goto usage; } ifmarker.target_range.min = NI_FSM_STATE_NONE; ifmarker.target_range.max = max_state; fsm->worker_timeout = ni_fsm_find_max_timeout(fsm, timeout); if (!ni_fsm_create_client(fsm)) { /* Severe error we always explicitly return */ return NI_WICKED_RC_ERROR; } if (!ni_fsm_refresh_state(fsm)) { /* Severe error we always explicitly return */ return NI_WICKED_RC_ERROR; } /* Get workers that match given criteria */ nmarked = 0; while (optind < argc) { ifmatch.name = argv[optind++]; ifmatch.ifdown = TRUE; ni_fsm_get_matching_workers(fsm, &ifmatch, &ifmarked); if (ni_string_eq(ifmatch.name, "all") || ni_string_empty(ifmatch.name)) { ni_string_array_destroy(&ifnames); break; } if (ni_string_array_index(&ifnames, ifmatch.name) == -1) ni_string_array_append(&ifnames, ifmatch.name); } /* Mark and start selected workers */ if (ifmarked.count) { if (ni_config_use_nanny()) { /* Disable devices and delete all related policies from nanny */ ni_ifdown_fire_nanny(&ifmarked); } /* Start workers to perform actual ifdown */ nmarked = ni_fsm_mark_matching_workers(fsm, &ifmarked, &ifmarker); } if (nmarked == 0) { ni_note("ifdown: no matching interfaces"); status = NI_WICKED_RC_SUCCESS; } else { if (ni_fsm_schedule(fsm) != 0) ni_fsm_mainloop(fsm); status = ni_ifstatus_shutdown_result(fsm, &ifnames, &ifmarked); } ni_string_array_destroy(&ifnames); ni_ifworker_array_destroy(&ifmarked); return status; }
/* * Remove information from a lease which has been released and already detached * from a device. */ static ni_bool_t ni_system_updater_remove(ni_updater_t *updater, const ni_addrconf_lease_t *lease, const char *ifname) { ni_string_array_t arguments = NI_STRING_ARRAY_INIT; ni_bool_t result = FALSE; ni_debug_ifconfig("Removing system %s settings from %s %s/%s lease", ni_updater_name(updater->kind), ifname, ni_addrconf_type_to_name(lease->type), ni_addrfamily_type_to_name(lease->family)); if (!updater->proc_remove) return TRUE; ni_string_array_append(&arguments, "-i"); ni_string_array_append(&arguments, ifname); ni_string_array_append(&arguments, "-t"); ni_string_array_append(&arguments, ni_addrconf_type_to_name(lease->type)); ni_string_array_append(&arguments, "-f"); ni_string_array_append(&arguments, ni_addrfamily_type_to_name(lease->family)); switch (updater->kind) { case NI_ADDRCONF_UPDATER_GENERIC: switch (updater->format) { case NI_ADDRCONF_UPDATER_FORMAT_INFO: ni_leaseinfo_remove(ifname, lease->type, lease->family); break; default: ni_error("Unsupported %s updater data format.", ni_updater_name(updater->kind)); break; } break; case NI_ADDRCONF_UPDATER_RESOLVER: case NI_ADDRCONF_UPDATER_HOSTNAME: break; default: ni_error("cannot remove old %s settings - file format not understood", ni_updater_name(updater->kind)); goto done; } if (!ni_system_updater_run(updater->proc_remove, &arguments)) { ni_error("failed to remove %s settings", ni_updater_name(updater->kind)); goto done; } result = TRUE; switch (updater->kind) { case NI_ADDRCONF_UPDATER_RESOLVER: if (ni_global.other_event) ni_global.other_event(NI_EVENT_RESOLVER_UPDATED); break; case NI_ADDRCONF_UPDATER_HOSTNAME: if (ni_global.other_event) ni_global.other_event(NI_EVENT_HOSTNAME_UPDATED); break; case NI_ADDRCONF_UPDATER_GENERIC: if (ni_global.other_event) ni_global.other_event(NI_EVENT_GENERIC_UPDATED); break; default: break; } done: ni_string_array_destroy(&arguments); return result; }
static dbus_bool_t __ni_objectmodel_bonding_set_slaves(ni_dbus_object_t *object, const ni_dbus_property_t *property, const ni_dbus_variant_t *result, DBusError *error) { ni_bonding_t *bond; ni_dbus_variant_t *var; unsigned int i; if (!(bond = __ni_objectmodel_bonding_write_handle(object, error))) return FALSE; if (!ni_dbus_variant_is_dict_array(result)) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s.%s property - expected dict array", object->path, property->name); return FALSE; } ni_string_free(&bond->primary_slave); ni_string_free(&bond->active_slave); ni_string_array_destroy(&bond->slave_names); for (i = 0, var = result->variant_array_value; i < result->array.len; ++i, ++var) { dbus_bool_t is_primary = FALSE; dbus_bool_t is_active = FALSE; const char *slave_name; if (!ni_dbus_dict_get_string(var, "device", &slave_name)) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s.%s property - missing device attribute", object->path, property->name); return FALSE; } if (ni_string_array_index(&bond->slave_names, slave_name) != -1) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s.%s property - duplicate slave devices", object->path, property->name); return FALSE; } if (ni_dbus_dict_get_bool(var, "primary", &is_primary) && is_primary) { if (bond->primary_slave) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s.%s property - duplicate primary device", object->path, property->name); return FALSE; } ni_string_dup(&bond->primary_slave, slave_name); } if (ni_dbus_dict_get_bool(var, "active", &is_active) && is_active) { if (bond->active_slave) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s.%s property - duplicate active device", object->path, property->name); return FALSE; } ni_string_dup(&bond->active_slave, slave_name); } ni_string_array_append(&bond->slave_names, slave_name); } return TRUE; }
ni_bool_t ni_config_parse_addrconf_dhcp6(struct ni_config_dhcp6 *dhcp6, xml_node_t *node) { xml_node_t *child; for (child = node->children; child; child = child->next) { const char *attrval; if (!strcmp(child->name, "default-duid") && !ni_string_empty(child->cdata)) { ni_string_dup(&dhcp6->default_duid, child->cdata); } else if (!strcmp(child->name, "user-class")) { ni_string_array_destroy(&dhcp6->user_class_data); if (__ni_config_parse_dhcp6_class_data_nodes(child, &dhcp6->user_class_data) < 0) { ni_string_array_destroy(&dhcp6->user_class_data); return FALSE; } if (dhcp6->user_class_data.count == 0) { ni_warn("config: discarding <user-class> without any <class-data>"); } } else if (!strcmp(child->name, "vendor-class") && (attrval = xml_node_get_attr(child, "enterprise-number")) != NULL) { char * err; long num; num = strtol(attrval, &err, 0); if (*err != '\0' || num < 0 || num >= 0xffffffff) { ni_error("config: unable to parse <vendor-class enterprise-number=\"%s\"", attrval); return FALSE; } ni_string_array_destroy(&dhcp6->vendor_class_data); if (__ni_config_parse_dhcp6_class_data_nodes(child, &dhcp6->vendor_class_data) < 0) { ni_string_array_destroy(&dhcp6->vendor_class_data); return FALSE; } if (dhcp6->vendor_class_data.count == 0) { ni_warn("config: discarding <vendor-class> without any <class-data>"); } else { dhcp6->vendor_class_en = num; } } else if (!strcmp(child->name, "vendor-opts") && (attrval = xml_node_get_attr(child, "enterprise-number")) != NULL) { char * err; long num; num = strtol(attrval, &err, 0); if (*err != '\0' || num < 0 || num >= 0xffffffff) { ni_error("config: unable to parse <vendor-class enterprise-number=\"%s\"", attrval); return FALSE; } ni_var_array_destroy(&dhcp6->vendor_opts_data); if (__ni_config_parse_dhcp6_vendor_opts_nodes(child, &dhcp6->vendor_opts_data) < 0) { ni_var_array_destroy(&dhcp6->vendor_opts_data); } if (dhcp6->vendor_opts_data.count == 0) { ni_warn("config: discarding <vendor-opts> without any <option>"); } else { dhcp6->vendor_opts_en = num; } } else if (!strcmp(child->name, "lease-time") && child->cdata) { dhcp6->lease_time = strtoul(child->cdata, NULL, 0); } else if (!strcmp(child->name, "ignore-server") && (attrval = xml_node_get_attr(child, "ip")) != NULL) { ni_string_array_append(&dhcp6->ignore_servers, attrval); } else if (!strcmp(child->name, "prefer-server")) { ni_server_preference_t *pref; const char *id, *ip; ip = xml_node_get_attr(child, "ip"); id = xml_node_get_attr(child, "id"); if (ip == NULL && id == NULL) continue; if (dhcp6->num_preferred_servers >= NI_DHCP_SERVER_PREFERENCES_MAX) { ni_warn("config: too many <prefer-server> elements"); continue; } pref = &dhcp6->preferred_server[dhcp6->num_preferred_servers++]; if (ip && ni_sockaddr_parse(&pref->address, ip, AF_INET6) < 0) { ni_error("config: unable to parse <prefer-server ip=\"%s\"", ip); return FALSE; } if (id) { int len; /* DUID is "opaque", but has 2 bytes type + up to 128 bytes */ if ((len = sizeof(pref->serverid.data)) > 130) len = 130; /* DUID-LL has 2+2 fixed bytes + variable length hwaddress * and seems to be the shortest one I'm aware of ... */ if ((len = ni_parse_hex(id, pref->serverid.data, len)) <= 4) { ni_error("config: unable to parse <prefer-server id=\"%s\"", id); return FALSE; } pref->serverid.len = (size_t)len; } pref->weight = 255; if ((attrval = xml_node_get_attr(child, "weight")) != NULL) { if (!strcmp(attrval, "always")) { pref->weight = 255; } else if (!strcmp(attrval, "never")) { pref->weight = -1; } else { pref->weight = strtol(attrval, NULL, 0); if (pref->weight > 255) { pref->weight = 255; ni_warn("preferred dhcp server weight exceeds max, " "clamping to %d", pref->weight); } } } } else if (!strcmp(child->name, "allow-update")) { ni_config_parse_update_targets(&dhcp6->allow_update, child); } } return TRUE; }
/* * Decode an RFC3397 DNS search order option. */ static int ni_dhcp_decode_dnssearch(ni_buffer_t *optbuf, ni_string_array_t *list, const char *what) { ni_stringbuf_t namebuf = NI_STRINGBUF_INIT_DYNAMIC; unsigned char *base = ni_buffer_head(optbuf); unsigned int base_offset = optbuf->head; size_t len; ni_string_array_destroy(list); while (ni_buffer_count(optbuf) && !optbuf->underflow) { ni_buffer_t *bp = optbuf; ni_buffer_t jumpbuf; while (1) { unsigned int pos = bp->head - base_offset; unsigned int pointer; char label[64]; int length; if ((length = ni_buffer_getc(bp)) < 0) goto failure; /* unexpected EOF */ if (length == 0) break; /* end of this name */ switch (length & 0xC0) { case 0: /* Plain name component */ if (ni_buffer_get(bp, label, length) < 0) goto failure; label[length] = '\0'; if (!ni_stringbuf_empty(&namebuf)) ni_stringbuf_putc(&namebuf, '.'); ni_stringbuf_puts(&namebuf, label); break; case 0xC0: /* Pointer */ pointer = (length & 0x3F) << 8; if ((length = ni_buffer_getc(bp)) < 0) goto failure; pointer |= length; if (pointer >= pos) goto failure; ni_buffer_init_reader(&jumpbuf, base, pos); jumpbuf.head = pointer; bp = &jumpbuf; break; default: goto failure; } } if (!ni_stringbuf_empty(&namebuf)) { len = ni_string_len(namebuf.string); if (ni_check_domain_name(namebuf.string, len, 0)) { ni_string_array_append(list, namebuf.string); } else { ni_debug_dhcp("Discarded suspect %s: %s", what, ni_print_suspect(namebuf.string, len)); } } ni_stringbuf_destroy(&namebuf); } return 0; failure: ni_stringbuf_destroy(&namebuf); ni_string_array_destroy(list); return -1; }
int ni_do_ifreload(int argc, char **argv) { enum { OPT_HELP, OPT_IFCONFIG, OPT_PERSISTENT, OPT_TRANSIENT, #ifdef NI_TEST_HACKS OPT_IGNORE_PRIO, OPT_IGNORE_STARTMODE, #endif }; static struct option ifreload_options[] = { { "help", no_argument, NULL, OPT_HELP }, { "transient", no_argument, NULL, OPT_TRANSIENT }, { "ifconfig", required_argument, NULL, OPT_IFCONFIG }, #ifdef NI_TEST_HACKS { "ignore-prio",no_argument, NULL, OPT_IGNORE_PRIO }, { "ignore-startmode",no_argument, NULL, OPT_IGNORE_STARTMODE }, #endif { "persistent", no_argument, NULL, OPT_PERSISTENT }, { NULL, no_argument, NULL, 0 } }; ni_string_array_t opt_ifconfig = NI_STRING_ARRAY_INIT; ni_ifworker_array_t marked = { 0, NULL }; ni_ifmatcher_t ifmatch; ni_bool_t check_prio = TRUE; ni_bool_t opt_persistent = FALSE; ni_bool_t opt_transient = FALSE; int c, status = NI_WICKED_RC_USAGE; unsigned int nmarked, i; const ni_uint_range_t up_range = { .min = NI_FSM_STATE_ADDRCONF_UP, .max = __NI_FSM_STATE_MAX }; const char *ptr; ni_fsm_t *fsm; /* Allow ifreload on all interfaces with a changed config */ memset(&ifmatch, 0, sizeof(ifmatch)); ifmatch.require_configured = FALSE; ifmatch.allow_persistent = TRUE; ifmatch.require_config = FALSE; fsm = ni_fsm_new(); ni_assert(fsm); ni_fsm_require_register_type("reachable", ni_ifworker_reachability_check_new); /* * Workaround to consider WAIT_FOR_INTERFACES variable * in network/config (bnc#863371, bnc#862530 timeouts). * Correct would be to get it from compat layer, but * the network/config is sourced in systemd service... */ if ((ptr = getenv("WAIT_FOR_INTERFACES"))) { unsigned int sec; if (ni_parse_uint(ptr, &sec, 10) == 0 && (sec * 1000 > fsm->worker_timeout)) { ni_debug_application("wait %u sec for interfaces", sec); fsm->worker_timeout = sec * 1000; } } optind = 1; while ((c = getopt_long(argc, argv, "", ifreload_options, NULL)) != EOF) { switch (c) { case OPT_IFCONFIG: ni_string_array_append(&opt_ifconfig, optarg); break; #ifdef NI_TEST_HACKS case OPT_IGNORE_PRIO: check_prio = FALSE; break; case OPT_IGNORE_STARTMODE: ifmatch.ignore_startmode = TRUE; break; #endif case OPT_PERSISTENT: opt_persistent = TRUE; break; case OPT_TRANSIENT: opt_transient = TRUE; break; default: case OPT_HELP: usage: fprintf(stderr, "wicked [options] ifreload [ifreload-options] <ifname ...>|all\n" "\nSupported ifreload-options:\n" " --help\n" " Show this help text.\n" " --transient\n" " Enable transient interface return codes\n" " --ifconfig <filename>\n" " Read interface configuration(s) from file\n" #ifdef NI_TEST_HACKS " --ignore-prio\n" " Ignore checking the config origin priorities\n" " --ignore-startmode\n" " Ignore checking the STARTMODE=off and STARTMODE=manual configs\n" #endif " --persistent\n" " Set interface into persistent mode (no regular ifdown allowed)\n" ); goto cleanup; } } /* at least one argument is required */ if (optind >= argc) { fprintf(stderr, "Missing interface argument\n"); goto usage; } else for (c = optind; c < argc; ++c) { if (ni_string_empty(argv[c])) { printf("ARG: %s\n", argv[c]); goto usage; } } if (!ni_fsm_create_client(fsm)) { /* Severe error we always explicitly return */ status = NI_WICKED_RC_ERROR; goto cleanup; } if (!ni_fsm_refresh_state(fsm)) { /* Severe error we always explicitly return */ status = NI_WICKED_RC_ERROR; goto cleanup; } if (opt_ifconfig.count == 0) { const ni_string_array_t *sources = ni_config_sources("ifconfig"); if (sources && sources->count) ni_string_array_copy(&opt_ifconfig, sources); if (opt_ifconfig.count == 0) { ni_error("ifreload: unable to load interface config source list"); status = NI_WICKED_RC_NOT_CONFIGURED; goto cleanup; } } if (!ni_ifconfig_load(fsm, opt_global_rootdir, &opt_ifconfig, check_prio, TRUE)) { status = NI_WICKED_RC_NOT_CONFIGURED; goto cleanup; } status = NI_WICKED_RC_SUCCESS; nmarked = 0; for (c = optind; c < argc; ++c) { ni_ifworker_array_t temp = { 0, NULL }; /* Getting an array of ifworkers matching argument */ ifmatch.name = argv[c]; if (!ni_fsm_get_matching_workers(fsm, &ifmatch, &temp)) continue; for (i = 0; i < temp.count; ++i) { ni_ifworker_t *w = temp.data[i]; ni_netdev_t *dev = w->device; /* skip duplicate matches */ if (ni_ifworker_array_index(&marked, w) != -1) continue; /* skip unused devices without config */ if (!ni_ifcheck_worker_config_exists(w) && !ni_ifcheck_device_configured(dev)) continue; /* skip if config changed somehow */ if (ni_ifcheck_worker_config_matches(w)) continue; /* Mark persistend when requested */ if (opt_persistent) w->client_state.persistent = TRUE; /* Remember all changed devices */ ni_ifworker_array_append(&marked, w); /* Persistent do not go down but up only */ if (!dev || ni_ifcheck_device_is_persistent(dev)) continue; /* Decide how much down we go */ if (ni_ifcheck_worker_config_exists(w)) { if (!ni_ifcheck_device_configured(dev)) continue; w->target_range.min = NI_FSM_STATE_NONE; w->target_range.max = NI_FSM_STATE_DEVICE_READY; nmarked++; } else if (ni_ifcheck_device_configured(dev)) { w->target_range.min = NI_FSM_STATE_NONE; w->target_range.max = NI_FSM_STATE_DEVICE_DOWN; nmarked++; } } ni_ifworker_array_destroy(&temp); } if (nmarked) { /* Run ifdown part of the reload */ ni_debug_application("Shutting down unneeded devices"); ni_fsm_start_matching_workers(fsm, &marked); /* Execute the down run */ if (ni_fsm_schedule(fsm) != 0) ni_fsm_mainloop(fsm); } if (marked.count) { /* Drop deleted or apply the up range */ ni_fsm_reset_matching_workers(fsm, &marked, &up_range, FALSE); /* And trigger up */ ni_debug_application("Reloading all changed devices"); ni_ifup_pull_in_children(&marked); nmarked = ni_fsm_start_matching_workers(fsm, &marked); ni_ifworker_array_destroy(&marked); } if (nmarked) { /* Build the up tree */ if (ni_fsm_build_hierarchy(fsm) < 0) { ni_error("ifreload: unable to build device hierarchy"); /* Severe error we always explicitly return */ status = NI_WICKED_RC_ERROR; goto cleanup; } /* Execute the up run */ if (ni_fsm_schedule(fsm) != 0) ni_fsm_mainloop(fsm); /* No error if all interfaces were good */ status = ni_fsm_fail_count(fsm) ? NI_WICKED_RC_ERROR : NI_WICKED_RC_SUCCESS; /* Do not report any transient errors to systemd (e.g. dhcp * or whatever not ready in time) -- returning an error may * cause to stop the network completely. */ if (!opt_transient) status = NI_LSB_RC_SUCCESS; } cleanup: ni_string_array_destroy(&opt_ifconfig); ni_ifworker_array_destroy(&marked); return status; }
static int ni_do_ifup_direct(int argc, char **argv) { enum { OPT_HELP, OPT_IFCONFIG, OPT_CONTROL_MODE, OPT_STAGE, OPT_TIMEOUT, OPT_SKIP_ACTIVE, OPT_SKIP_ORIGIN, OPT_PERSISTENT, OPT_TRANSIENT, #ifdef NI_TEST_HACKS OPT_IGNORE_PRIO, OPT_IGNORE_STARTMODE, #endif }; static struct option ifup_options[] = { { "help", no_argument, NULL, OPT_HELP }, { "ifconfig", required_argument, NULL, OPT_IFCONFIG }, { "mode", required_argument, NULL, OPT_CONTROL_MODE }, { "boot-stage", required_argument, NULL, OPT_STAGE }, { "skip-active",required_argument, NULL, OPT_SKIP_ACTIVE }, { "skip-origin",required_argument, NULL, OPT_SKIP_ORIGIN }, { "timeout", required_argument, NULL, OPT_TIMEOUT }, { "transient", no_argument, NULL, OPT_TRANSIENT }, #ifdef NI_TEST_HACKS { "ignore-prio",no_argument, NULL, OPT_IGNORE_PRIO }, { "ignore-startmode",no_argument, NULL, OPT_IGNORE_STARTMODE }, #endif { "persistent", no_argument, NULL, OPT_PERSISTENT }, { NULL } }; ni_ifmatcher_t ifmatch; ni_ifmarker_t ifmarker; ni_ifworker_array_t ifmarked; ni_string_array_t opt_ifconfig = NI_STRING_ARRAY_INIT; ni_bool_t check_prio = TRUE; ni_bool_t opt_transient = FALSE; unsigned int nmarked; ni_fsm_t *fsm; int c, status = NI_WICKED_RC_USAGE; unsigned int timeout = 0; const char *ptr; fsm = ni_fsm_new(); ni_assert(fsm); ni_fsm_require_register_type("reachable", ni_ifworker_reachability_check_new); memset(&ifmatch, 0, sizeof(ifmatch)); memset(&ifmarker, 0, sizeof(ifmarker)); memset(&ifmarked, 0, sizeof(ifmarked)); /* Allow ifup on all interfaces we have config for */ ifmatch.require_configured = FALSE; ifmatch.allow_persistent = TRUE; ifmatch.require_config = TRUE; ifmarker.target_range.min = NI_FSM_STATE_ADDRCONF_UP; ifmarker.target_range.max = __NI_FSM_STATE_MAX; /* * Workaround to consider WAIT_FOR_INTERFACES variable * in network/config (bnc#863371, bnc#862530 timeouts). * Correct would be to get it from compat layer, but * the network/config is sourced in systemd service... */ if ((ptr = getenv("WAIT_FOR_INTERFACES"))) { unsigned int sec; if (ni_parse_uint(ptr, &sec, 10) == 0 && (sec * 1000 > fsm->worker_timeout)) { ni_debug_application("wait %u sec for interfaces", sec); timeout = sec * 1000; } } optind = 1; while ((c = getopt_long(argc, argv, "", ifup_options, NULL)) != EOF) { switch (c) { case OPT_IFCONFIG: ni_string_array_append(&opt_ifconfig, optarg); break; case OPT_CONTROL_MODE: ifmatch.mode = optarg; break; case OPT_STAGE: ifmatch.boot_stage= optarg; break; case OPT_TIMEOUT: if (!strcmp(optarg, "infinite")) { timeout = NI_IFWORKER_INFINITE_TIMEOUT; } else if (ni_parse_uint(optarg, &timeout, 10) >= 0) { timeout *= 1000; /* sec -> msec */ } else { ni_error("ifup: cannot parse timeout option \"%s\"", optarg); goto usage; } break; case OPT_SKIP_ORIGIN: ifmatch.skip_origin = optarg; break; case OPT_SKIP_ACTIVE: ifmatch.skip_active = TRUE; break; #ifdef NI_TEST_HACKS case OPT_IGNORE_PRIO: check_prio = FALSE; break; case OPT_IGNORE_STARTMODE: ifmatch.ignore_startmode = TRUE; break; #endif case OPT_PERSISTENT: ifmarker.persistent = TRUE; break; case OPT_TRANSIENT: opt_transient = TRUE; break; default: case OPT_HELP: usage: fprintf(stderr, "wicked [options] ifup [ifup-options] <ifname ...>|all\n" "\nSupported ifup-options:\n" " --help\n" " Show this help text.\n" " --transient\n" " Enable transient interface return codes\n" " --ifconfig <pathname>\n" " Read interface configuration(s) from file/directory rather than using system config\n" " --mode <label>\n" " Only touch interfaces with matching control <mode>\n" " --boot-stage <label>\n" " Only touch interfaces with matching <boot-stage>\n" " --skip-active\n" " Do not touch running interfaces\n" " --skip-origin <name>\n" " Skip interfaces that have a configuration origin of <name>\n" " Usually, you would use this with the name \"firmware\" to avoid\n" " touching interfaces that have been set up via firmware (like iBFT) previously\n" " --timeout <nsec>\n" " Timeout after <nsec> seconds\n" #ifdef NI_TEST_HACKS " --ignore-prio\n" " Ignore checking the config origin priorities\n" " --ignore-startmode\n" " Ignore checking the STARTMODE=off and STARTMODE=manual configs\n" #endif " --persistent\n" " Set interface into persistent mode (no regular ifdown allowed)\n" ); goto cleanup; } } if (optind >= argc) { fprintf(stderr, "Missing interface argument\n"); goto usage; } if (!ni_fsm_create_client(fsm)) { /* Severe error we always explicitly return */ status = NI_WICKED_RC_ERROR; goto cleanup; } if (!ni_fsm_refresh_state(fsm)) { /* Severe error we always explicitly return */ status = NI_WICKED_RC_ERROR; goto cleanup; } if (opt_ifconfig.count == 0) { const ni_string_array_t *sources = ni_config_sources("ifconfig"); if (sources && sources->count) ni_string_array_copy(&opt_ifconfig, sources); if (opt_ifconfig.count == 0) { ni_error("ifup: unable to load interface config source list"); status = NI_WICKED_RC_NOT_CONFIGURED; goto cleanup; } } if (!ni_ifconfig_load(fsm, opt_global_rootdir, &opt_ifconfig, check_prio, TRUE)) { status = NI_WICKED_RC_NOT_CONFIGURED; goto cleanup; } /* Client waits for device-up events for WAIT_FOR_INTERFACES */ if (timeout) ni_wait_for_interfaces = timeout; /* One set by user */ else ni_wait_for_interfaces *= 1000; /* in msec */ if (ni_fsm_build_hierarchy(fsm) < 0) { ni_error("ifup: unable to build device hierarchy"); /* Severe error we always explicitly return */ status = NI_WICKED_RC_ERROR; goto cleanup; } /* Get workers that match given criteria */ nmarked = 0; while (optind < argc) { ifmatch.name = argv[optind++]; if (!strcmp(ifmatch.name, "boot")) { ifmatch.name = "all"; ifmatch.mode = "boot"; } ni_fsm_get_matching_workers(fsm, &ifmatch, &ifmarked); } ni_ifup_pull_in_children(&ifmarked); /* Mark and start selected workers */ if (ifmarked.count) nmarked = ni_fsm_mark_matching_workers(fsm, &ifmarked, &ifmarker); if (nmarked == 0) { printf("ifup: no matching interfaces\n"); status = NI_WICKED_RC_SUCCESS; } else { if (ni_fsm_schedule(fsm) != 0) ni_fsm_mainloop(fsm); /* No error if all interfaces were good */ status = ni_fsm_fail_count(fsm) ? NI_WICKED_RC_ERROR : NI_WICKED_RC_SUCCESS; /* Do not report any transient errors to systemd (e.g. dhcp * or whatever not ready in time) -- returning an error may * cause to stop the network completely. */ if (!opt_transient) status = NI_LSB_RC_SUCCESS; } cleanup: ni_ifworker_array_destroy(&ifmarked); ni_string_array_destroy(&opt_ifconfig); return status; }
/* * Install information from a lease, and remember that we did */ static ni_bool_t ni_system_updater_install(ni_updater_t *updater, const ni_addrconf_lease_t *lease, const char *ifname) { ni_string_array_t arguments = NI_STRING_ARRAY_INIT; const char *statedir = NULL; char *file = NULL; ni_bool_t result = FALSE; int rv = 0; ni_debug_ifconfig("Updating system %s settings from %s/%s lease", ni_updater_name(updater->kind), ni_addrconf_type_to_name(lease->type), ni_addrfamily_type_to_name(lease->family)); if (!updater->proc_install) return TRUE; if (!ifname || (!updater->have_backup && !ni_system_updater_backup(updater, ifname))) return FALSE; ni_string_array_append(&arguments, "-i"); ni_string_array_append(&arguments, ifname); ni_string_array_append(&arguments, "-t"); ni_string_array_append(&arguments, ni_addrconf_type_to_name(lease->type)); ni_string_array_append(&arguments, "-f"); ni_string_array_append(&arguments, ni_addrfamily_type_to_name(lease->family)); switch (updater->kind) { case NI_ADDRCONF_UPDATER_GENERIC: switch (updater->format) { case NI_ADDRCONF_UPDATER_FORMAT_INFO: ni_leaseinfo_dump(NULL, lease, ifname, NULL); if (!(file = ni_leaseinfo_path(ifname, lease->type, lease->family))) { ni_error("Unable to determine leaseinfo file path."); goto done; } ni_string_array_append(&arguments, file); break; default: ni_error("Unsupported %s updater data format.", ni_updater_name(updater->kind)); goto done; } ni_string_array_append(&arguments, ni_updater_format_name(updater->format)); break; case NI_ADDRCONF_UPDATER_RESOLVER: statedir = ni_extension_statedir(ni_updater_name(updater->kind)); if (!statedir) { ni_error("failed to get %s statedir", ni_updater_name(updater->kind)); goto done; } ni_string_printf(&file, "%s/resolv.conf.%s.%s.%s", statedir, ifname, ni_addrconf_type_to_name(lease->type), ni_addrfamily_type_to_name(lease->family)); ni_string_array_append(&arguments, file); if ((rv = ni_resolver_write_resolv_conf(file, lease->resolver, NULL)) < 0) { ni_error("failed to write resolver info to file: %s", ni_strerror(rv)); goto done; } break; case NI_ADDRCONF_UPDATER_HOSTNAME: if (!ni_string_empty(lease->hostname)) { ni_string_array_append(&arguments, lease->hostname); } else { const ni_address_t *ap; char *name = NULL; unsigned int count; /* bnc#861476 workaround */ if (!can_try_reverse_lookup(lease)) goto done; for (count = 0, ap = lease->addrs; ap; ap = ap->next) { if (!ni_sockaddr_is_specified(&ap->local_addr)) continue; if (!ni_resolve_reverse_timed(&ap->local_addr, &name, NI_UPDATER_REVERSE_TIMEOUT)) break; ni_info("Unable to resolve %s to hostname", ni_sockaddr_print(&ap->local_addr)); if (++count >= NI_UPDATER_REVERSE_MAX_CNT) break; } if (ni_string_empty(name)) { ni_note("Skipping hostname update, none available"); goto done; } ni_string_array_append(&arguments, name); ni_string_free(&name); } break; default: ni_error("cannot install new %s settings - file format not understood", ni_updater_name(updater->kind)); goto done; } if (!ni_system_updater_run(updater->proc_install, &arguments)) { ni_error("failed to install %s settings", ni_updater_name(updater->kind)); goto done; } result = TRUE; switch (updater->kind) { case NI_ADDRCONF_UPDATER_RESOLVER: if (ni_global.other_event) ni_global.other_event(NI_EVENT_RESOLVER_UPDATED); break; case NI_ADDRCONF_UPDATER_HOSTNAME: if (ni_global.other_event) ni_global.other_event(NI_EVENT_HOSTNAME_UPDATED); break; case NI_ADDRCONF_UPDATER_GENERIC: if (ni_global.other_event) ni_global.other_event(NI_EVENT_GENERIC_UPDATED); break; default: break; } done: if (file) free(file); ni_string_array_destroy(&arguments); return result; }