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