Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */ 2 : 3 : #include <errno.h> 4 : #include <getopt.h> 5 : #include <stdbool.h> 6 : #include <stddef.h> 7 : #include <string.h> 8 : 9 : #include "env-util.h" 10 : #include "log.h" 11 : #include "macro.h" 12 : #include "process-util.h" 13 : #include "string-util.h" 14 : #include "verbs.h" 15 : #include "virt.h" 16 : 17 : /* Wraps running_in_chroot() which is used in various places, but also adds an environment variable check so external 18 : * processes can reliably force this on. 19 : */ 20 0 : bool running_in_chroot_or_offline(void) { 21 : int r; 22 : 23 : /* Added to support use cases like rpm-ostree, where from %post scripts we only want to execute "preset", but 24 : * not "start"/"restart" for example. 25 : * 26 : * See docs/ENVIRONMENT.md for docs. 27 : */ 28 0 : r = getenv_bool("SYSTEMD_OFFLINE"); 29 0 : if (r < 0 && r != -ENXIO) 30 0 : log_debug_errno(r, "Failed to parse $SYSTEMD_OFFLINE: %m"); 31 0 : else if (r >= 0) 32 0 : return r > 0; 33 : 34 : /* We've had this condition check for a long time which basically checks for legacy chroot case like Fedora's 35 : * "mock", which is used for package builds. We don't want to try to start systemd services there, since 36 : * without --new-chroot we don't even have systemd running, and even if we did, adding a concept of background 37 : * daemons to builds would be an enormous change, requiring considering things like how the journal output is 38 : * handled, etc. And there's really not a use case today for a build talking to a service. 39 : * 40 : * Note this call itself also looks for a different variable SYSTEMD_IGNORE_CHROOT=1. 41 : */ 42 0 : r = running_in_chroot(); 43 0 : if (r < 0) 44 0 : log_debug_errno(r, "running_in_chroot(): %m"); 45 : 46 0 : return r > 0; 47 : } 48 : 49 9 : int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) { 50 : const Verb *verb; 51 : const char *name; 52 : unsigned i; 53 : int left; 54 : 55 9 : assert(verbs); 56 9 : assert(verbs[0].dispatch); 57 9 : assert(argc >= 0); 58 9 : assert(argv); 59 9 : assert(argc >= optind); 60 : 61 9 : left = argc - optind; 62 9 : argv += optind; 63 9 : optind = 0; 64 9 : name = argv[0]; 65 : 66 41 : for (i = 0;; i++) { 67 : bool found; 68 : 69 : /* At the end of the list? */ 70 41 : if (!verbs[i].dispatch) { 71 2 : if (name) 72 1 : log_error("Unknown operation %s.", name); 73 : else 74 1 : log_error("Requires operation parameter."); 75 2 : return -EINVAL; 76 : } 77 : 78 39 : if (name) 79 35 : found = streq(name, verbs[i].verb); 80 : else 81 4 : found = verbs[i].flags & VERB_DEFAULT; 82 : 83 39 : if (found) { 84 7 : verb = &verbs[i]; 85 7 : break; 86 : } 87 : } 88 : 89 7 : assert(verb); 90 : 91 7 : if (!name) 92 1 : left = 1; 93 : 94 7 : if (verb->min_args != VERB_ANY && 95 5 : (unsigned) left < verb->min_args) 96 1 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL), 97 : "Too few arguments."); 98 : 99 6 : if (verb->max_args != VERB_ANY && 100 4 : (unsigned) left > verb->max_args) 101 1 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL), 102 : "Too many arguments."); 103 : 104 5 : if ((verb->flags & VERB_ONLINE_ONLY) && running_in_chroot_or_offline()) { 105 0 : if (name) 106 0 : log_info("Running in chroot, ignoring request: %s", name); 107 : else 108 0 : log_info("Running in chroot, ignoring request."); 109 0 : return 0; 110 : } 111 : 112 5 : if (name) 113 4 : return verb->dispatch(left, argv, userdata); 114 : else { 115 1 : char* fake[2] = { 116 1 : (char*) verb->verb, 117 : NULL 118 : }; 119 : 120 1 : return verb->dispatch(1, fake, userdata); 121 : } 122 : }