]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/inhibit.c
Unify parse_argv style
[thirdparty/systemd.git] / src / login / inhibit.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <getopt.h>
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28
29 #include "sd-bus.h"
30 #include "bus-util.h"
31 #include "bus-error.h"
32 #include "util.h"
33 #include "build.h"
34 #include "strv.h"
35
36 static const char* arg_what = "idle:sleep:shutdown";
37 static const char* arg_who = NULL;
38 static const char* arg_why = "Unknown reason";
39 static const char* arg_mode = "block";
40
41 static enum {
42 ACTION_INHIBIT,
43 ACTION_LIST
44 } arg_action = ACTION_INHIBIT;
45
46 static int inhibit(sd_bus *bus, sd_bus_error *error) {
47 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
48 int r;
49 int fd;
50
51 r = sd_bus_call_method(
52 bus,
53 "org.freedesktop.login1",
54 "/org/freedesktop/login1",
55 "org.freedesktop.login1.Manager",
56 "Inhibit",
57 error,
58 &reply,
59 "ssss", arg_what, arg_who, arg_why, arg_mode);
60 if (r < 0)
61 return r;
62
63 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_UNIX_FD, &fd);
64 if (r < 0)
65 return r;
66
67 r = fcntl(fd, F_DUPFD_CLOEXEC, 3);
68 if (r < 0)
69 return -errno;
70
71 return r;
72 }
73
74 static int print_inhibitors(sd_bus *bus, sd_bus_error *error) {
75 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
76 const char *what, *who, *why, *mode;
77 unsigned int uid, pid;
78 unsigned n = 0;
79 int r;
80
81 r = sd_bus_call_method(
82 bus,
83 "org.freedesktop.login1",
84 "/org/freedesktop/login1",
85 "org.freedesktop.login1.Manager",
86 "ListInhibitors",
87 error,
88 &reply,
89 "");
90 if (r < 0)
91 return r;
92
93 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
94 if (r < 0)
95 return bus_log_parse_error(r);
96
97 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
98 _cleanup_free_ char *comm = NULL, *u = NULL;
99
100 get_process_comm(pid, &comm);
101 u = uid_to_name(uid);
102
103 printf(" Who: %s (UID "UID_FMT"/%s, PID "PID_FMT"/%s)\n"
104 " What: %s\n"
105 " Why: %s\n"
106 " Mode: %s\n\n",
107 who, uid, strna(u), pid, strna(comm),
108 what,
109 why,
110 mode);
111
112 n++;
113 }
114 if (r < 0)
115 return bus_log_parse_error(r);
116
117 r = sd_bus_message_exit_container(reply);
118 if (r < 0)
119 return bus_log_parse_error(r);
120
121 printf("%u inhibitors listed.\n", n);
122 return 0;
123 }
124
125 static void help(void) {
126 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
127 "Execute a process while inhibiting shutdown/sleep/idle.\n\n"
128 " -h --help Show this help\n"
129 " --version Show package version\n"
130 " --what=WHAT Operations to inhibit, colon separated list of:\n"
131 " shutdown, sleep, idle, handle-power-key,\n"
132 " handle-suspend-key, handle-hibernate-key,\n"
133 " handle-lid-switch\n"
134 " --who=STRING A descriptive string who is inhibiting\n"
135 " --why=STRING A descriptive string why is being inhibited\n"
136 " --mode=MODE One of block or delay\n"
137 " --list List active inhibitors\n"
138 , program_invocation_short_name);
139 }
140
141 static int parse_argv(int argc, char *argv[]) {
142
143 enum {
144 ARG_VERSION = 0x100,
145 ARG_WHAT,
146 ARG_WHO,
147 ARG_WHY,
148 ARG_MODE,
149 ARG_LIST,
150 };
151
152 static const struct option options[] = {
153 { "help", no_argument, NULL, 'h' },
154 { "version", no_argument, NULL, ARG_VERSION },
155 { "what", required_argument, NULL, ARG_WHAT },
156 { "who", required_argument, NULL, ARG_WHO },
157 { "why", required_argument, NULL, ARG_WHY },
158 { "mode", required_argument, NULL, ARG_MODE },
159 { "list", no_argument, NULL, ARG_LIST },
160 {}
161 };
162
163 int c;
164
165 assert(argc >= 0);
166 assert(argv);
167
168 while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0)
169
170 switch (c) {
171
172 case 'h':
173 help();
174 return 0;
175
176 case ARG_VERSION:
177 puts(PACKAGE_STRING);
178 puts(SYSTEMD_FEATURES);
179 return 0;
180
181 case ARG_WHAT:
182 arg_what = optarg;
183 break;
184
185 case ARG_WHO:
186 arg_who = optarg;
187 break;
188
189 case ARG_WHY:
190 arg_why = optarg;
191 break;
192
193 case ARG_MODE:
194 arg_mode = optarg;
195 break;
196
197 case ARG_LIST:
198 arg_action = ACTION_LIST;
199 break;
200
201 case '?':
202 return -EINVAL;
203
204 default:
205 assert_not_reached("Unhandled option");
206 }
207
208 if (arg_action == ACTION_INHIBIT && argc == 1)
209 arg_action = ACTION_LIST;
210
211 else if (arg_action == ACTION_INHIBIT && optind >= argc) {
212 log_error("Missing command line to execute.");
213 return -EINVAL;
214 }
215
216 return 1;
217 }
218
219 int main(int argc, char *argv[]) {
220 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
221 _cleanup_bus_unref_ sd_bus *bus = NULL;
222 int r;
223
224 log_parse_environment();
225 log_open();
226
227 r = parse_argv(argc, argv);
228 if (r < 0)
229 return EXIT_FAILURE;
230 if (r == 0)
231 return EXIT_SUCCESS;
232
233 r = sd_bus_default_system(&bus);
234 if (r < 0) {
235 log_error("Failed to connect to bus: %s", strerror(-r));
236 return EXIT_FAILURE;
237 }
238
239 if (arg_action == ACTION_LIST) {
240
241 r = print_inhibitors(bus, &error);
242 if (r < 0) {
243 log_error("Failed to list inhibitors: %s", bus_error_message(&error, -r));
244 return EXIT_FAILURE;
245 }
246
247 } else {
248 _cleanup_close_ int fd = -1;
249 _cleanup_free_ char *w = NULL;
250 pid_t pid;
251
252 if (!arg_who)
253 arg_who = w = strv_join(argv + optind, " ");
254
255 fd = inhibit(bus, &error);
256 if (fd < 0) {
257 log_error("Failed to inhibit: %s", bus_error_message(&error, -r));
258 return EXIT_FAILURE;
259 }
260
261 pid = fork();
262 if (pid < 0) {
263 log_error("Failed to fork: %m");
264 return EXIT_FAILURE;
265 }
266
267 if (pid == 0) {
268 /* Child */
269
270 close_all_fds(NULL, 0);
271
272 execvp(argv[optind], argv + optind);
273 log_error("Failed to execute %s: %m", argv[optind]);
274 _exit(EXIT_FAILURE);
275 }
276
277 r = wait_for_terminate_and_warn(argv[optind], pid);
278 return r < 0 ? EXIT_FAILURE : r;
279 }
280
281 return 0;
282 }