1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
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.
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.
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/>.
29 #include "dbus-common.h"
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";
42 } arg_action = ACTION_INHIBIT;
44 static int inhibit(DBusConnection *bus, DBusError *error) {
45 DBusMessage *m = NULL, *reply = NULL;
50 m = dbus_message_new_method_call(
51 "org.freedesktop.login1",
52 "/org/freedesktop/login1",
53 "org.freedesktop.login1.Manager",
58 if (!dbus_message_append_args(m,
59 DBUS_TYPE_STRING, &arg_what,
60 DBUS_TYPE_STRING, &arg_who,
61 DBUS_TYPE_STRING, &arg_why,
62 DBUS_TYPE_STRING, &arg_mode,
68 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
74 if (!dbus_message_get_args(reply, error,
75 DBUS_TYPE_UNIX_FD, &fd,
83 dbus_message_unref(m);
86 dbus_message_unref(reply);
91 static int print_inhibitors(DBusConnection *bus, DBusError *error) {
92 DBusMessage *m, *reply;
94 DBusMessageIter iter, sub, sub2;
99 m = dbus_message_new_method_call(
100 "org.freedesktop.login1",
101 "/org/freedesktop/login1",
102 "org.freedesktop.login1.Manager",
107 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
113 if (!dbus_message_iter_init(reply, &iter)) {
118 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
122 dbus_message_iter_recurse(&iter, &sub);
124 printf("%-21s %-20s %-20s %-5s %6s %6s\n",
133 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
134 const char *what, *who, *why, *mode;
136 dbus_uint32_t uid, pid;
138 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
143 dbus_message_iter_recurse(&sub, &sub2);
145 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
146 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
147 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
148 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
149 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
150 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
155 ewho = ellipsize(who, 20, 66);
156 ewhy = ellipsize(why, 20, 66);
158 printf("%-21s %-20s %-20s %-5s %6lu %6lu\n",
159 what, ewho ? ewho : who, ewhy ? ewhy : why, mode, (unsigned long) uid, (unsigned long) pid);
164 dbus_message_iter_next(&sub);
169 printf("\n%u inhibitors listed.\n", n);
174 dbus_message_unref(m);
177 dbus_message_unref(reply);
182 static int help(void) {
184 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
185 "Execute a process while inhibiting shutdown/sleep/idle.\n\n"
186 " -h --help Show this help\n"
187 " --version Show package version\n"
188 " --what=WHAT Operations to inhibit, colon separated list of idle,\n"
190 " --who=STRING A descriptive string who is inhibiting\n"
191 " --why=STRING A descriptive string why is being inhibited\n"
192 " --mode=MODE One of block or delay\n"
193 " --list List active inhibitors\n",
194 program_invocation_short_name);
199 static int parse_argv(int argc, char *argv[]) {
210 static const struct option options[] = {
211 { "help", no_argument, NULL, 'h' },
212 { "version", no_argument, NULL, ARG_VERSION },
213 { "what", required_argument, NULL, ARG_WHAT },
214 { "who", required_argument, NULL, ARG_WHO },
215 { "why", required_argument, NULL, ARG_WHY },
216 { "mode", required_argument, NULL, ARG_MODE },
217 { "list", no_argument, NULL, ARG_LIST },
226 while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0) {
235 puts(PACKAGE_STRING);
237 puts(SYSTEMD_FEATURES);
257 arg_action = ACTION_LIST;
261 log_error("Unknown option code %c", c);
266 if (arg_action == ACTION_INHIBIT && optind >= argc) {
267 log_error("Missing command line to execute.");
274 int main(int argc, char *argv[]) {
275 int r, exit_code = 0;
276 DBusConnection *bus = NULL;
280 dbus_error_init(&error);
282 log_parse_environment();
285 r = parse_argv(argc, argv);
289 bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
291 log_error("Failed to connect to bus: %s", bus_error_message(&error));
296 if (arg_action == ACTION_LIST) {
298 r = print_inhibitors(bus, &error);
300 log_error("Failed to list inhibitors: %s", bus_error_message_or_strerror(&error, -r));
309 arg_who = w = strv_join(argv + optind, " ");
311 fd = inhibit(bus, &error);
315 log_error("Failed to inhibit: %s", bus_error_message_or_strerror(&error, -r));
322 log_error("Failed to fork: %m");
330 close_nointr_nofail(fd);
331 execvp(argv[optind], argv + optind);
332 log_error("Failed to execute %s: %m", argv[optind]);
336 r = wait_for_terminate_and_warn(argv[optind], pid);
343 dbus_connection_close(bus);
344 dbus_connection_unref(bus);
347 dbus_error_free(&error);
350 close_nointr_nofail(fd);
352 return r < 0 ? EXIT_FAILURE : exit_code;