chiark / gitweb /
dbus: minor coding style fixes
[elogind.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 }