static int ni_factory_device_up(ni_fsm_t *fsm, ni_ifworker_t *w) { ni_ifworker_array_t ifmarked = NI_IFWORKER_ARRAY_INIT; ni_ifmarker_t ifmarker; ni_assert(fsm && w); memset(&ifmarker, 0, sizeof(ifmarker)); ifmarker.target_range.min = NI_FSM_STATE_ADDRCONF_UP; ifmarker.target_range.max = __NI_FSM_STATE_MAX; ifmarker.persistent = w->control.persistent; ni_ifworker_array_append(&ifmarked, w); ni_fsm_pull_in_children(&ifmarked); ni_fsm_mark_matching_workers(fsm, &ifmarked, &ifmarker); ni_ifworker_array_destroy(&ifmarked); return 0; }
/* * Bring up the device */ static int ni_managed_device_up(ni_managed_device_t *mdev, const char *origin) { ni_fsm_t *fsm = mdev->nanny->fsm; ni_ifworker_t *w = mdev->worker; unsigned int previous_state; unsigned int target_state; ni_security_id_t security_id = NI_SECURITY_ID_INIT; ni_ifworker_array_t ifmarked = NI_IFWORKER_ARRAY_INIT; ni_ifmarker_t ifmarker; int rv = -NI_ERROR_DEVICE_NOT_COMPATIBLE; memset(&ifmarker, 0, sizeof(ifmarker)); switch (w->type) { case NI_IFWORKER_TYPE_NETDEV: mdev->max_fail_count = 3; if (w->device->link.type == NI_IFTYPE_WIRELESS) { const char *essid; ni_security_id_init(&security_id, "wireless"); if ((essid = ni_managed_device_get_essid(mdev->selected_config)) != NULL) ni_security_id_set_attr(&security_id, "essid", essid); } target_state = NI_FSM_STATE_ADDRCONF_UP; break; case NI_IFWORKER_TYPE_MODEM: mdev->max_fail_count = 1; ni_security_id_init(&security_id, "modem"); if (w->modem->identify.equipment) ni_security_id_set_attr(&security_id, "equipment-id", w->modem->identify.equipment); target_state = NI_FSM_STATE_LINK_UP; break; default: goto failed; } if (ni_security_id_valid(&security_id)) ni_managed_device_set_security_id(mdev, &security_id); ni_ifworker_set_completion_callback(w, ni_managed_device_up_done, mdev->nanny); ni_ifworker_set_config(w, mdev->selected_config, origin); ifmarker.target_range.min = target_state; ifmarker.target_range.max = __NI_FSM_STATE_MAX; ifmarker.persistent = w->control.persistent; ni_ifworker_array_append(&ifmarked, w); ni_fsm_pull_in_children(&ifmarked); /* Binding: this validates the XML configuration document, * resolves any references to other devices (if there are any), * and retrieves any keys/passwords etc via the prompt callback. * Inside the prompt callback, we record all secrets for tracking */ ni_secret_array_destroy(&mdev->secrets); previous_state = mdev->state; mdev->state = NI_MANAGED_STATE_BINDING; if ((rv = ni_ifworker_bind_early(w, fsm, TRUE)) < 0) goto failed; if (mdev->missing_secrets) { /* FIXME: Emit an event listing the secrets we're missing. */ mdev->state = previous_state; return -1; } mdev->state = NI_MANAGED_STATE_STARTING; ni_fsm_mark_matching_workers(fsm, &ifmarked, &ifmarker); ni_ifworker_array_destroy(&ifmarked); return 0; failed: ni_error("%s: cannot start device: %s", w->name, ni_strerror(rv)); mdev->state = NI_MANAGED_STATE_FAILED; return -1; }
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; }
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; }