]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/inhibit.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / login / inhibit.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
eecd1362
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2012 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
3f6fd1ba 21#include <fcntl.h>
eecd1362 22#include <getopt.h>
eecd1362 23#include <stdio.h>
3f6fd1ba 24#include <stdlib.h>
eecd1362
LP
25#include <unistd.h>
26
0fb0c56f 27#include "sd-bus.h"
3f6fd1ba 28
b5efdb8a 29#include "alloc-util.h"
0fb0c56f 30#include "bus-error.h"
3f6fd1ba 31#include "bus-util.h"
3ffd4af2 32#include "fd-util.h"
f97b34a6 33#include "format-util.h"
0b452006 34#include "process-util.h"
ce30c8dc 35#include "signal-util.h"
3f6fd1ba 36#include "strv.h"
b1d4f8e1 37#include "user-util.h"
3f6fd1ba 38#include "util.h"
eecd1362 39
4943c1c9 40static const char* arg_what = "idle:sleep:shutdown";
eecd1362
LP
41static const char* arg_who = NULL;
42static const char* arg_why = "Unknown reason";
ca5447c0 43static const char* arg_mode = NULL;
eecd1362
LP
44
45static enum {
46 ACTION_INHIBIT,
47 ACTION_LIST
48} arg_action = ACTION_INHIBIT;
49
0fb0c56f 50static int inhibit(sd_bus *bus, sd_bus_error *error) {
4afd3348 51 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
3137e0bd 52 int r;
0fb0c56f 53 int fd;
eecd1362 54
0fb0c56f 55 r = sd_bus_call_method(
b9c26b41 56 bus,
eecd1362
LP
57 "org.freedesktop.login1",
58 "/org/freedesktop/login1",
59 "org.freedesktop.login1.Manager",
b9c26b41 60 "Inhibit",
0fb0c56f 61 error,
b9c26b41 62 &reply,
0fb0c56f 63 "ssss", arg_what, arg_who, arg_why, arg_mode);
3137e0bd
LP
64 if (r < 0)
65 return r;
eecd1362 66
0fb0c56f
TG
67 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_UNIX_FD, &fd);
68 if (r < 0)
5b30bef8 69 return r;
eecd1362 70
ead34950 71 r = fcntl(fd, F_DUPFD_CLOEXEC, 3);
0fb0c56f
TG
72 if (r < 0)
73 return -errno;
74
3137e0bd 75 return r;
eecd1362
LP
76}
77
0fb0c56f 78static int print_inhibitors(sd_bus *bus, sd_bus_error *error) {
4afd3348 79 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
0fb0c56f
TG
80 const char *what, *who, *why, *mode;
81 unsigned int uid, pid;
eecd1362 82 unsigned n = 0;
eecd1362
LP
83 int r;
84
0fb0c56f 85 r = sd_bus_call_method(
b9c26b41 86 bus,
eecd1362
LP
87 "org.freedesktop.login1",
88 "/org/freedesktop/login1",
89 "org.freedesktop.login1.Manager",
b9c26b41 90 "ListInhibitors",
0fb0c56f 91 error,
b9c26b41 92 &reply,
0fb0c56f 93 "");
3137e0bd 94 if (r < 0)
4654e558 95 return r;
eecd1362 96
0fb0c56f
TG
97 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
98 if (r < 0)
40be0704 99 return bus_log_parse_error(r);
eecd1362 100
0fb0c56f 101 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
391a4f72 102 _cleanup_free_ char *comm = NULL, *u = NULL;
eecd1362 103
ca5447c0
MM
104 if (arg_mode && !streq(mode, arg_mode))
105 continue;
106
391a4f72
LP
107 get_process_comm(pid, &comm);
108 u = uid_to_name(uid);
109
de0671ee 110 printf(" Who: %s (UID "UID_FMT"/%s, PID "PID_FMT"/%s)\n"
41330ddb
MM
111 " What: %s\n"
112 " Why: %s\n"
113 " Mode: %s\n\n",
de0671ee 114 who, uid, strna(u), pid, strna(comm),
41330ddb
MM
115 what,
116 why,
117 mode);
eecd1362 118
eecd1362
LP
119 n++;
120 }
0fb0c56f 121 if (r < 0)
40be0704 122 return bus_log_parse_error(r);
0fb0c56f
TG
123
124 r = sd_bus_message_exit_container(reply);
125 if (r < 0)
40be0704 126 return bus_log_parse_error(r);
eecd1362 127
41330ddb 128 printf("%u inhibitors listed.\n", n);
4654e558 129 return 0;
eecd1362
LP
130}
131
601185b4 132static void help(void) {
eecd1362 133 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4943c1c9 134 "Execute a process while inhibiting shutdown/sleep/idle.\n\n"
eecd1362
LP
135 " -h --help Show this help\n"
136 " --version Show package version\n"
12a1309e
LP
137 " --what=WHAT Operations to inhibit, colon separated list of:\n"
138 " shutdown, sleep, idle, handle-power-key,\n"
2f1bb513
СНА
139 " handle-suspend-key, handle-hibernate-key,\n"
140 " handle-lid-switch\n"
eecd1362
LP
141 " --who=STRING A descriptive string who is inhibiting\n"
142 " --why=STRING A descriptive string why is being inhibited\n"
143 " --mode=MODE One of block or delay\n"
601185b4
ZJS
144 " --list List active inhibitors\n"
145 , program_invocation_short_name);
eecd1362
LP
146}
147
148static int parse_argv(int argc, char *argv[]) {
149
150 enum {
151 ARG_VERSION = 0x100,
152 ARG_WHAT,
153 ARG_WHO,
154 ARG_WHY,
155 ARG_MODE,
156 ARG_LIST,
157 };
158
159 static const struct option options[] = {
160 { "help", no_argument, NULL, 'h' },
161 { "version", no_argument, NULL, ARG_VERSION },
162 { "what", required_argument, NULL, ARG_WHAT },
163 { "who", required_argument, NULL, ARG_WHO },
164 { "why", required_argument, NULL, ARG_WHY },
165 { "mode", required_argument, NULL, ARG_MODE },
166 { "list", no_argument, NULL, ARG_LIST },
eb9da376 167 {}
eecd1362
LP
168 };
169
170 int c;
171
172 assert(argc >= 0);
173 assert(argv);
174
601185b4 175 while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0)
eecd1362
LP
176
177 switch (c) {
178
179 case 'h':
601185b4
ZJS
180 help();
181 return 0;
eecd1362
LP
182
183 case ARG_VERSION:
3f6fd1ba 184 return version();
eecd1362
LP
185
186 case ARG_WHAT:
187 arg_what = optarg;
188 break;
189
190 case ARG_WHO:
191 arg_who = optarg;
192 break;
193
194 case ARG_WHY:
195 arg_why = optarg;
196 break;
197
198 case ARG_MODE:
199 arg_mode = optarg;
200 break;
201
202 case ARG_LIST:
203 arg_action = ACTION_LIST;
204 break;
205
eb9da376 206 case '?':
eecd1362 207 return -EINVAL;
eb9da376
LP
208
209 default:
210 assert_not_reached("Unhandled option");
eecd1362 211 }
eecd1362 212
d9130355 213 if (arg_action == ACTION_INHIBIT && optind == argc)
2f2343c6
KS
214 arg_action = ACTION_LIST;
215
216 else if (arg_action == ACTION_INHIBIT && optind >= argc) {
eecd1362
LP
217 log_error("Missing command line to execute.");
218 return -EINVAL;
219 }
220
221 return 1;
222}
223
224int main(int argc, char *argv[]) {
4afd3348
LP
225 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
226 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
5220a6f3 227 int r;
eecd1362
LP
228
229 log_parse_environment();
230 log_open();
231
232 r = parse_argv(argc, argv);
45a7c6b5 233 if (r < 0)
0fb0c56f 234 return EXIT_FAILURE;
45a7c6b5
LP
235 if (r == 0)
236 return EXIT_SUCCESS;
eecd1362 237
76b54375 238 r = sd_bus_default_system(&bus);
0fb0c56f 239 if (r < 0) {
da927ba9 240 log_error_errno(r, "Failed to connect to bus: %m");
0fb0c56f 241 return EXIT_FAILURE;
eecd1362
LP
242 }
243
244 if (arg_action == ACTION_LIST) {
245
246 r = print_inhibitors(bus, &error);
247 if (r < 0) {
0fb0c56f
TG
248 log_error("Failed to list inhibitors: %s", bus_error_message(&error, -r));
249 return EXIT_FAILURE;
eecd1362
LP
250 }
251
252 } else {
5220a6f3
LP
253 _cleanup_close_ int fd = -1;
254 _cleanup_free_ char *w = NULL;
eecd1362
LP
255 pid_t pid;
256
257 if (!arg_who)
258 arg_who = w = strv_join(argv + optind, " ");
259
ca5447c0
MM
260 if (!arg_mode)
261 arg_mode = "block";
262
eecd1362 263 fd = inhibit(bus, &error);
eecd1362 264 if (fd < 0) {
dcee0112 265 log_error("Failed to inhibit: %s", bus_error_message(&error, fd));
0fb0c56f 266 return EXIT_FAILURE;
eecd1362
LP
267 }
268
269 pid = fork();
270 if (pid < 0) {
56f64d95 271 log_error_errno(errno, "Failed to fork: %m");
0fb0c56f 272 return EXIT_FAILURE;
eecd1362
LP
273 }
274
275 if (pid == 0) {
276 /* Child */
277
ce30c8dc
LP
278 (void) reset_all_signal_handlers();
279 (void) reset_signal_mask();
280
77030bd6
LP
281 close_all_fds(NULL, 0);
282
eecd1362 283 execvp(argv[optind], argv + optind);
56f64d95 284 log_error_errno(errno, "Failed to execute %s: %m", argv[optind]);
eecd1362
LP
285 _exit(EXIT_FAILURE);
286 }
287
820d3acf 288 r = wait_for_terminate_and_warn(argv[optind], pid, true);
5220a6f3 289 return r < 0 ? EXIT_FAILURE : r;
eecd1362
LP
290 }
291
0fb0c56f 292 return 0;
eecd1362 293}