]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/inhibit.c
Make systemd-inhibit --list work
[thirdparty/systemd.git] / src / login / inhibit.c
CommitLineData
eecd1362
LP
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 <dbus.h>
27#include <unistd.h>
28
29#include "dbus-common.h"
30#include "util.h"
31#include "build.h"
32#include "strv.h"
33
4943c1c9 34static const char* arg_what = "idle:sleep:shutdown";
eecd1362
LP
35static const char* arg_who = NULL;
36static const char* arg_why = "Unknown reason";
37static const char* arg_mode = "block";
38
39static enum {
40 ACTION_INHIBIT,
41 ACTION_LIST
42} arg_action = ACTION_INHIBIT;
43
44static int inhibit(DBusConnection *bus, DBusError *error) {
b9c26b41 45 DBusMessage *reply = NULL;
eecd1362
LP
46 int fd;
47
b9c26b41
SP
48 fd = bus_method_call_with_reply (
49 bus,
eecd1362
LP
50 "org.freedesktop.login1",
51 "/org/freedesktop/login1",
52 "org.freedesktop.login1.Manager",
b9c26b41
SP
53 "Inhibit",
54 &reply,
55 NULL,
56 DBUS_TYPE_STRING, &arg_what,
57 DBUS_TYPE_STRING, &arg_who,
58 DBUS_TYPE_STRING, &arg_why,
59 DBUS_TYPE_STRING, &arg_mode,
60 DBUS_TYPE_INVALID);
61 if (fd)
62 return fd;
eecd1362
LP
63
64 if (!dbus_message_get_args(reply, error,
65 DBUS_TYPE_UNIX_FD, &fd,
b9c26b41 66 DBUS_TYPE_INVALID))
eecd1362 67 fd = -EIO;
eecd1362 68
b9c26b41 69 dbus_message_unref(reply);
eecd1362
LP
70
71 return fd;
72}
73
74static int print_inhibitors(DBusConnection *bus, DBusError *error) {
b9c26b41 75 DBusMessage *reply;
eecd1362
LP
76 unsigned n = 0;
77 DBusMessageIter iter, sub, sub2;
78 int r;
79
b9c26b41
SP
80 r = bus_method_call_with_reply (
81 bus,
eecd1362
LP
82 "org.freedesktop.login1",
83 "/org/freedesktop/login1",
84 "org.freedesktop.login1.Manager",
b9c26b41
SP
85 "ListInhibitors",
86 &reply,
87 NULL,
88 DBUS_TYPE_INVALID);
680258b1
MC
89 if (r) {
90 r = -ENOMEM;
eecd1362 91 goto finish;
680258b1 92 }
eecd1362
LP
93
94 if (!dbus_message_iter_init(reply, &iter)) {
95 r = -ENOMEM;
96 goto finish;
97 }
98
99 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
100 r = -EIO;
101 goto finish;
102 }
103 dbus_message_iter_recurse(&iter, &sub);
104
105 printf("%-21s %-20s %-20s %-5s %6s %6s\n",
106 "WHAT",
107 "WHO",
108 "WHY",
109 "MODE",
110 "UID",
111 "PID");
112
113
114 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
115 const char *what, *who, *why, *mode;
116 char *ewho, *ewhy;
117 dbus_uint32_t uid, pid;
118
119 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
120 r = -EIO;
121 goto finish;
122 }
123
124 dbus_message_iter_recurse(&sub, &sub2);
125
126 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
127 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
128 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
129 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
130 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
131 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
132 r = -EIO;
133 goto finish;
134 }
135
136 ewho = ellipsize(who, 20, 66);
137 ewhy = ellipsize(why, 20, 66);
138
139 printf("%-21s %-20s %-20s %-5s %6lu %6lu\n",
140 what, ewho ? ewho : who, ewhy ? ewhy : why, mode, (unsigned long) uid, (unsigned long) pid);
141
142 free(ewho);
143 free(ewhy);
144
145 dbus_message_iter_next(&sub);
146
147 n++;
148 }
149
150 printf("\n%u inhibitors listed.\n", n);
151 r = 0;
152
153finish:
eecd1362
LP
154 if (reply)
155 dbus_message_unref(reply);
156
157 return r;
158}
159
160static int help(void) {
161
162 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4943c1c9 163 "Execute a process while inhibiting shutdown/sleep/idle.\n\n"
eecd1362
LP
164 " -h --help Show this help\n"
165 " --version Show package version\n"
166 " --what=WHAT Operations to inhibit, colon separated list of idle,\n"
4943c1c9 167 " sleep, shutdown\n"
eecd1362
LP
168 " --who=STRING A descriptive string who is inhibiting\n"
169 " --why=STRING A descriptive string why is being inhibited\n"
170 " --mode=MODE One of block or delay\n"
171 " --list List active inhibitors\n",
172 program_invocation_short_name);
173
174 return 0;
175}
176
177static int parse_argv(int argc, char *argv[]) {
178
179 enum {
180 ARG_VERSION = 0x100,
181 ARG_WHAT,
182 ARG_WHO,
183 ARG_WHY,
184 ARG_MODE,
185 ARG_LIST,
186 };
187
188 static const struct option options[] = {
189 { "help", no_argument, NULL, 'h' },
190 { "version", no_argument, NULL, ARG_VERSION },
191 { "what", required_argument, NULL, ARG_WHAT },
192 { "who", required_argument, NULL, ARG_WHO },
193 { "why", required_argument, NULL, ARG_WHY },
194 { "mode", required_argument, NULL, ARG_MODE },
195 { "list", no_argument, NULL, ARG_LIST },
196 { NULL, 0, NULL, 0 }
197 };
198
199 int c;
200
201 assert(argc >= 0);
202 assert(argv);
203
204 while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0) {
205
206 switch (c) {
207
208 case 'h':
209 help();
210 return 0;
211
212 case ARG_VERSION:
213 puts(PACKAGE_STRING);
214 puts(DISTRIBUTION);
215 puts(SYSTEMD_FEATURES);
216 return 0;
217
218 case ARG_WHAT:
219 arg_what = optarg;
220 break;
221
222 case ARG_WHO:
223 arg_who = optarg;
224 break;
225
226 case ARG_WHY:
227 arg_why = optarg;
228 break;
229
230 case ARG_MODE:
231 arg_mode = optarg;
232 break;
233
234 case ARG_LIST:
235 arg_action = ACTION_LIST;
236 break;
237
238 default:
239 log_error("Unknown option code %c", c);
240 return -EINVAL;
241 }
242 }
243
244 if (arg_action == ACTION_INHIBIT && optind >= argc) {
245 log_error("Missing command line to execute.");
246 return -EINVAL;
247 }
248
249 return 1;
250}
251
252int main(int argc, char *argv[]) {
253 int r, exit_code = 0;
254 DBusConnection *bus = NULL;
255 DBusError error;
256 int fd = -1;
257
258 dbus_error_init(&error);
259
260 log_parse_environment();
261 log_open();
262
263 r = parse_argv(argc, argv);
264 if (r <= 0)
265 goto finish;
266
267 bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
268 if (!bus) {
269 log_error("Failed to connect to bus: %s", bus_error_message(&error));
270 r = -EIO;
271 goto finish;
272 }
273
274 if (arg_action == ACTION_LIST) {
275
276 r = print_inhibitors(bus, &error);
277 if (r < 0) {
278 log_error("Failed to list inhibitors: %s", bus_error_message_or_strerror(&error, -r));
279 goto finish;
280 }
281
282 } else {
283 char *w = NULL;
284 pid_t pid;
285
286 if (!arg_who)
287 arg_who = w = strv_join(argv + optind, " ");
288
289 fd = inhibit(bus, &error);
290 free(w);
291
292 if (fd < 0) {
293 log_error("Failed to inhibit: %s", bus_error_message_or_strerror(&error, -r));
294 r = fd;
295 goto finish;
296 }
297
298 pid = fork();
299 if (pid < 0) {
300 log_error("Failed to fork: %m");
301 r = -errno;
302 goto finish;
303 }
304
305 if (pid == 0) {
306 /* Child */
307
308 close_nointr_nofail(fd);
309 execvp(argv[optind], argv + optind);
310 log_error("Failed to execute %s: %m", argv[optind]);
311 _exit(EXIT_FAILURE);
312 }
313
314 r = wait_for_terminate_and_warn(argv[optind], pid);
315 if (r >= 0)
316 exit_code = r;
317 }
318
319finish:
320 if (bus) {
321 dbus_connection_close(bus);
322 dbus_connection_unref(bus);
323 }
324
325 dbus_error_free(&error);
326
327 if (fd >= 0)
328 close_nointr_nofail(fd);
329
330 return r < 0 ? EXIT_FAILURE : exit_code;
331}