systemctl: simplify argument parsing

This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2013-12-08 19:26:51 -05:00
parent 4f8f66cb42
commit d08e75edf9
+41 -54
View File
@@ -5813,9 +5813,13 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
} argc_cmp;
const int argc;
int (* const dispatch)(sd_bus *bus, char **args);
const enum {
NOBUS = 1,
FORCE,
} bus;
} verbs[] = {
{ "list-units", MORE, 0, list_units },
{ "list-unit-files", MORE, 1, list_unit_files },
{ "list-unit-files", MORE, 1, list_unit_files, NOBUS },
{ "list-sockets", MORE, 1, list_sockets },
{ "list-timers", MORE, 1, list_timers },
{ "list-jobs", MORE, 1, list_jobs },
@@ -5848,9 +5852,9 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
{ "show-environment", EQUAL, 1, show_environment },
{ "set-environment", MORE, 2, set_environment },
{ "unset-environment", MORE, 2, set_environment },
{ "halt", EQUAL, 1, start_special },
{ "poweroff", EQUAL, 1, start_special },
{ "reboot", EQUAL, 1, start_special },
{ "halt", EQUAL, 1, start_special, FORCE },
{ "poweroff", EQUAL, 1, start_special, FORCE },
{ "reboot", EQUAL, 1, start_special, FORCE },
{ "kexec", EQUAL, 1, start_special },
{ "suspend", EQUAL, 1, start_special },
{ "hibernate", EQUAL, 1, start_special },
@@ -5860,53 +5864,50 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
{ "emergency", EQUAL, 1, start_special },
{ "exit", EQUAL, 1, start_special },
{ "reset-failed", MORE, 1, reset_failed },
{ "enable", MORE, 2, enable_unit },
{ "disable", MORE, 2, enable_unit },
{ "is-enabled", MORE, 2, unit_is_enabled },
{ "reenable", MORE, 2, enable_unit },
{ "preset", MORE, 2, enable_unit },
{ "mask", MORE, 2, enable_unit },
{ "unmask", MORE, 2, enable_unit },
{ "link", MORE, 2, enable_unit },
{ "enable", MORE, 2, enable_unit, NOBUS },
{ "disable", MORE, 2, enable_unit, NOBUS },
{ "is-enabled", MORE, 2, unit_is_enabled, NOBUS },
{ "reenable", MORE, 2, enable_unit, NOBUS },
{ "preset", MORE, 2, enable_unit, NOBUS },
{ "mask", MORE, 2, enable_unit, NOBUS },
{ "unmask", MORE, 2, enable_unit, NOBUS },
{ "link", MORE, 2, enable_unit, NOBUS },
{ "switch-root", MORE, 2, switch_root },
{ "list-dependencies", LESS, 2, list_dependencies },
{ "set-default", EQUAL, 2, set_default },
{ "get-default", EQUAL, 1, get_default },
{ "set-default", EQUAL, 2, set_default, NOBUS },
{ "get-default", EQUAL, 1, get_default, NOBUS },
{ "set-property", MORE, 3, set_property },
};
{}
}, *verb = verbs;
int left;
unsigned i;
assert(argc >= 0);
assert(argv);
left = argc - optind;
if (left <= 0)
/* Special rule: no arguments means "list-units" */
i = 0;
else {
/* Special rule: no arguments (left == 0) means "list-units" */
if (left > 0) {
if (streq(argv[optind], "help") && !argv[optind+1]) {
log_error("This command expects one or more "
"unit names. Did you mean --help?");
return -EINVAL;
}
for (i = 0; i < ELEMENTSOF(verbs); i++)
if (streq(argv[optind], verbs[i].verb))
break;
for (; verb->verb; verb++)
if (streq(argv[optind], verb->verb))
goto found;
if (i >= ELEMENTSOF(verbs)) {
log_error("Unknown operation '%s'.", argv[optind]);
return -EINVAL;
}
log_error("Unknown operation '%s'.", argv[optind]);
return -EINVAL;
}
found:
switch (verbs[i].argc_cmp) {
switch (verb->argc_cmp) {
case EQUAL:
if (left != verbs[i].argc) {
if (left != verb->argc) {
log_error("Invalid number of arguments.");
return -EINVAL;
}
@@ -5914,7 +5915,7 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
break;
case MORE:
if (left < verbs[i].argc) {
if (left < verb->argc) {
log_error("Too few arguments.");
return -EINVAL;
}
@@ -5922,7 +5923,7 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
break;
case LESS:
if (left > verbs[i].argc) {
if (left > verb->argc) {
log_error("Too many arguments.");
return -EINVAL;
}
@@ -5935,39 +5936,25 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
/* Require a bus connection for all operations but
* enable/disable */
if (!streq(verbs[i].verb, "enable") &&
!streq(verbs[i].verb, "disable") &&
!streq(verbs[i].verb, "is-enabled") &&
!streq(verbs[i].verb, "list-unit-files") &&
!streq(verbs[i].verb, "reenable") &&
!streq(verbs[i].verb, "preset") &&
!streq(verbs[i].verb, "mask") &&
!streq(verbs[i].verb, "unmask") &&
!streq(verbs[i].verb, "link") &&
!streq(verbs[i].verb, "set-default") &&
!streq(verbs[i].verb, "get-default")) {
if (verb->bus == NOBUS) {
if (!bus && !avoid_bus()) {
log_error("Failed to get D-Bus connection: %s", strerror(-bus_error));
return -EIO;
}
} else {
if (running_in_chroot() > 0) {
log_info("Running in chroot, ignoring request.");
return 0;
}
if (((!streq(verbs[i].verb, "reboot") &&
!streq(verbs[i].verb, "halt") &&
!streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
log_error("Failed to get D-Bus connection: %s", strerror (-bus_error));
return -EIO;
}
} else {
if (!bus && !avoid_bus()) {
log_error("Failed to get D-Bus connection: %s", strerror (-bus_error));
if ((verb->bus != FORCE || arg_force <= 0) && !bus) {
log_error("Failed to get D-Bus connection: %s", strerror(-bus_error));
return -EIO;
}
}
return verbs[i].dispatch(bus, argv + optind);
return verb->dispatch(bus, argv + optind);
}
static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {