]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/inhibit.c
shared: add formats-util.h
[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>
eecd1362
LP
23#include <stdlib.h>
24#include <stdio.h>
eecd1362 25#include <unistd.h>
0fb0c56f 26#include <fcntl.h>
eecd1362 27
0fb0c56f 28#include "sd-bus.h"
0fb0c56f
TG
29#include "bus-util.h"
30#include "bus-error.h"
eecd1362
LP
31#include "util.h"
32#include "build.h"
33#include "strv.h"
6482f626 34#include "formats-util.h"
eecd1362 35
4943c1c9 36static const char* arg_what = "idle:sleep:shutdown";
eecd1362
LP
37static const char* arg_who = NULL;
38static const char* arg_why = "Unknown reason";
ca5447c0 39static const char* arg_mode = NULL;
eecd1362
LP
40
41static enum {
42 ACTION_INHIBIT,
43 ACTION_LIST
44} arg_action = ACTION_INHIBIT;
45
0fb0c56f
TG
46static int inhibit(sd_bus *bus, sd_bus_error *error) {
47 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
3137e0bd 48 int r;
0fb0c56f 49 int fd;
eecd1362 50
0fb0c56f 51 r = sd_bus_call_method(
b9c26b41 52 bus,
eecd1362
LP
53 "org.freedesktop.login1",
54 "/org/freedesktop/login1",
55 "org.freedesktop.login1.Manager",
b9c26b41 56 "Inhibit",
0fb0c56f 57 error,
b9c26b41 58 &reply,
0fb0c56f 59 "ssss", arg_what, arg_who, arg_why, arg_mode);
3137e0bd
LP
60 if (r < 0)
61 return r;
eecd1362 62
0fb0c56f
TG
63 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_UNIX_FD, &fd);
64 if (r < 0)
5b30bef8 65 return r;
eecd1362 66
ead34950 67 r = fcntl(fd, F_DUPFD_CLOEXEC, 3);
0fb0c56f
TG
68 if (r < 0)
69 return -errno;
70
3137e0bd 71 return r;
eecd1362
LP
72}
73
0fb0c56f
TG
74static 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;
eecd1362 78 unsigned n = 0;
eecd1362
LP
79 int r;
80
0fb0c56f 81 r = sd_bus_call_method(
b9c26b41 82 bus,
eecd1362
LP
83 "org.freedesktop.login1",
84 "/org/freedesktop/login1",
85 "org.freedesktop.login1.Manager",
b9c26b41 86 "ListInhibitors",
0fb0c56f 87 error,
b9c26b41 88 &reply,
0fb0c56f 89 "");
3137e0bd 90 if (r < 0)
4654e558 91 return r;
eecd1362 92
0fb0c56f
TG
93 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
94 if (r < 0)
40be0704 95 return bus_log_parse_error(r);
eecd1362 96
0fb0c56f 97 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
391a4f72 98 _cleanup_free_ char *comm = NULL, *u = NULL;
eecd1362 99
ca5447c0
MM
100 if (arg_mode && !streq(mode, arg_mode))
101 continue;
102
391a4f72
LP
103 get_process_comm(pid, &comm);
104 u = uid_to_name(uid);
105
de0671ee 106 printf(" Who: %s (UID "UID_FMT"/%s, PID "PID_FMT"/%s)\n"
41330ddb
MM
107 " What: %s\n"
108 " Why: %s\n"
109 " Mode: %s\n\n",
de0671ee 110 who, uid, strna(u), pid, strna(comm),
41330ddb
MM
111 what,
112 why,
113 mode);
eecd1362 114
eecd1362
LP
115 n++;
116 }
0fb0c56f 117 if (r < 0)
40be0704 118 return bus_log_parse_error(r);
0fb0c56f
TG
119
120 r = sd_bus_message_exit_container(reply);
121 if (r < 0)
40be0704 122 return bus_log_parse_error(r);
eecd1362 123
41330ddb 124 printf("%u inhibitors listed.\n", n);
4654e558 125 return 0;
eecd1362
LP
126}
127
601185b4 128static void help(void) {
eecd1362 129 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4943c1c9 130 "Execute a process while inhibiting shutdown/sleep/idle.\n\n"
eecd1362
LP
131 " -h --help Show this help\n"
132 " --version Show package version\n"
12a1309e
LP
133 " --what=WHAT Operations to inhibit, colon separated list of:\n"
134 " shutdown, sleep, idle, handle-power-key,\n"
2f1bb513
СНА
135 " handle-suspend-key, handle-hibernate-key,\n"
136 " handle-lid-switch\n"
eecd1362
LP
137 " --who=STRING A descriptive string who is inhibiting\n"
138 " --why=STRING A descriptive string why is being inhibited\n"
139 " --mode=MODE One of block or delay\n"
601185b4
ZJS
140 " --list List active inhibitors\n"
141 , program_invocation_short_name);
eecd1362
LP
142}
143
144static int parse_argv(int argc, char *argv[]) {
145
146 enum {
147 ARG_VERSION = 0x100,
148 ARG_WHAT,
149 ARG_WHO,
150 ARG_WHY,
151 ARG_MODE,
152 ARG_LIST,
153 };
154
155 static const struct option options[] = {
156 { "help", no_argument, NULL, 'h' },
157 { "version", no_argument, NULL, ARG_VERSION },
158 { "what", required_argument, NULL, ARG_WHAT },
159 { "who", required_argument, NULL, ARG_WHO },
160 { "why", required_argument, NULL, ARG_WHY },
161 { "mode", required_argument, NULL, ARG_MODE },
162 { "list", no_argument, NULL, ARG_LIST },
eb9da376 163 {}
eecd1362
LP
164 };
165
166 int c;
167
168 assert(argc >= 0);
169 assert(argv);
170
601185b4 171 while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0)
eecd1362
LP
172
173 switch (c) {
174
175 case 'h':
601185b4
ZJS
176 help();
177 return 0;
eecd1362
LP
178
179 case ARG_VERSION:
180 puts(PACKAGE_STRING);
eecd1362
LP
181 puts(SYSTEMD_FEATURES);
182 return 0;
183
184 case ARG_WHAT:
185 arg_what = optarg;
186 break;
187
188 case ARG_WHO:
189 arg_who = optarg;
190 break;
191
192 case ARG_WHY:
193 arg_why = optarg;
194 break;
195
196 case ARG_MODE:
197 arg_mode = optarg;
198 break;
199
200 case ARG_LIST:
201 arg_action = ACTION_LIST;
202 break;
203
eb9da376 204 case '?':
eecd1362 205 return -EINVAL;
eb9da376
LP
206
207 default:
208 assert_not_reached("Unhandled option");
eecd1362 209 }
eecd1362 210
d9130355 211 if (arg_action == ACTION_INHIBIT && optind == argc)
2f2343c6
KS
212 arg_action = ACTION_LIST;
213
214 else if (arg_action == ACTION_INHIBIT && optind >= argc) {
eecd1362
LP
215 log_error("Missing command line to execute.");
216 return -EINVAL;
217 }
218
219 return 1;
220}
221
222int main(int argc, char *argv[]) {
0fb0c56f 223 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
24996861 224 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
5220a6f3 225 int r;
eecd1362
LP
226
227 log_parse_environment();
228 log_open();
229
230 r = parse_argv(argc, argv);
45a7c6b5 231 if (r < 0)
0fb0c56f 232 return EXIT_FAILURE;
45a7c6b5
LP
233 if (r == 0)
234 return EXIT_SUCCESS;
eecd1362 235
76b54375 236 r = sd_bus_default_system(&bus);
0fb0c56f 237 if (r < 0) {
da927ba9 238 log_error_errno(r, "Failed to connect to bus: %m");
0fb0c56f 239 return EXIT_FAILURE;
eecd1362
LP
240 }
241
242 if (arg_action == ACTION_LIST) {
243
244 r = print_inhibitors(bus, &error);
245 if (r < 0) {
0fb0c56f
TG
246 log_error("Failed to list inhibitors: %s", bus_error_message(&error, -r));
247 return EXIT_FAILURE;
eecd1362
LP
248 }
249
250 } else {
5220a6f3
LP
251 _cleanup_close_ int fd = -1;
252 _cleanup_free_ char *w = NULL;
eecd1362
LP
253 pid_t pid;
254
255 if (!arg_who)
256 arg_who = w = strv_join(argv + optind, " ");
257
ca5447c0
MM
258 if (!arg_mode)
259 arg_mode = "block";
260
eecd1362 261 fd = inhibit(bus, &error);
eecd1362 262 if (fd < 0) {
dcee0112 263 log_error("Failed to inhibit: %s", bus_error_message(&error, fd));
0fb0c56f 264 return EXIT_FAILURE;
eecd1362
LP
265 }
266
267 pid = fork();
268 if (pid < 0) {
56f64d95 269 log_error_errno(errno, "Failed to fork: %m");
0fb0c56f 270 return EXIT_FAILURE;
eecd1362
LP
271 }
272
273 if (pid == 0) {
274 /* Child */
275
77030bd6
LP
276 close_all_fds(NULL, 0);
277
eecd1362 278 execvp(argv[optind], argv + optind);
56f64d95 279 log_error_errno(errno, "Failed to execute %s: %m", argv[optind]);
eecd1362
LP
280 _exit(EXIT_FAILURE);
281 }
282
820d3acf 283 r = wait_for_terminate_and_warn(argv[optind], pid, true);
5220a6f3 284 return r < 0 ? EXIT_FAILURE : r;
eecd1362
LP
285 }
286
0fb0c56f 287 return 0;
eecd1362 288}