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