]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/inhibit.c
Make systemctl --root look for files in the proper places
[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>
23#include <assert.h>
24#include <stdlib.h>
25#include <stdio.h>
eecd1362 26#include <unistd.h>
0fb0c56f 27#include <fcntl.h>
eecd1362 28
0fb0c56f 29#include "sd-bus.h"
0fb0c56f
TG
30#include "bus-util.h"
31#include "bus-error.h"
eecd1362
LP
32#include "util.h"
33#include "build.h"
34#include "strv.h"
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";
39static const char* arg_mode = "block";
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
391a4f72
LP
100 get_process_comm(pid, &comm);
101 u = uid_to_name(uid);
102
103 printf(" Who: %s (UID %lu/%s, PID %lu/%s)\n"
41330ddb
MM
104 " What: %s\n"
105 " Why: %s\n"
106 " Mode: %s\n\n",
391a4f72 107 who, (unsigned long) uid, strna(u), (unsigned long) pid, strna(comm),
41330ddb
MM
108 what,
109 why,
110 mode);
eecd1362 111
eecd1362
LP
112 n++;
113 }
0fb0c56f 114 if (r < 0)
40be0704 115 return bus_log_parse_error(r);
0fb0c56f
TG
116
117 r = sd_bus_message_exit_container(reply);
118 if (r < 0)
40be0704 119 return bus_log_parse_error(r);
eecd1362 120
41330ddb 121 printf("%u inhibitors listed.\n", n);
4654e558 122 return 0;
eecd1362
LP
123}
124
125static int help(void) {
126
127 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4943c1c9 128 "Execute a process while inhibiting shutdown/sleep/idle.\n\n"
eecd1362
LP
129 " -h --help Show this help\n"
130 " --version Show package version\n"
12a1309e
LP
131 " --what=WHAT Operations to inhibit, colon separated list of:\n"
132 " shutdown, sleep, idle, handle-power-key,\n"
2f1bb513
СНА
133 " handle-suspend-key, handle-hibernate-key,\n"
134 " handle-lid-switch\n"
eecd1362
LP
135 " --who=STRING A descriptive string who is inhibiting\n"
136 " --why=STRING A descriptive string why is being inhibited\n"
137 " --mode=MODE One of block or delay\n"
138 " --list List active inhibitors\n",
139 program_invocation_short_name);
140
141 return 0;
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
171 while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0) {
172
173 switch (c) {
174
175 case 'h':
eb9da376 176 return help();
eecd1362
LP
177
178 case ARG_VERSION:
179 puts(PACKAGE_STRING);
eecd1362
LP
180 puts(SYSTEMD_FEATURES);
181 return 0;
182
183 case ARG_WHAT:
184 arg_what = optarg;
185 break;
186
187 case ARG_WHO:
188 arg_who = optarg;
189 break;
190
191 case ARG_WHY:
192 arg_why = optarg;
193 break;
194
195 case ARG_MODE:
196 arg_mode = optarg;
197 break;
198
199 case ARG_LIST:
200 arg_action = ACTION_LIST;
201 break;
202
eb9da376 203 case '?':
eecd1362 204 return -EINVAL;
eb9da376
LP
205
206 default:
207 assert_not_reached("Unhandled option");
eecd1362
LP
208 }
209 }
210
2f2343c6
KS
211 if (arg_action == ACTION_INHIBIT && argc == 1)
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;
5220a6f3
LP
224 _cleanup_bus_unref_ sd_bus *bus = NULL;
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
TG
237 if (r < 0) {
238 log_error("Failed to connect to bus: %s", strerror(-r));
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
258 fd = inhibit(bus, &error);
eecd1362 259 if (fd < 0) {
0fb0c56f
TG
260 log_error("Failed to inhibit: %s", bus_error_message(&error, -r));
261 return EXIT_FAILURE;
eecd1362
LP
262 }
263
264 pid = fork();
265 if (pid < 0) {
266 log_error("Failed to fork: %m");
0fb0c56f 267 return EXIT_FAILURE;
eecd1362
LP
268 }
269
270 if (pid == 0) {
271 /* Child */
272
77030bd6
LP
273 close_all_fds(NULL, 0);
274
eecd1362
LP
275 execvp(argv[optind], argv + optind);
276 log_error("Failed to execute %s: %m", argv[optind]);
277 _exit(EXIT_FAILURE);
278 }
279
280 r = wait_for_terminate_and_warn(argv[optind], pid);
5220a6f3 281 return r < 0 ? EXIT_FAILURE : r;
eecd1362
LP
282 }
283
0fb0c56f 284 return 0;
eecd1362 285}