435 lines
11 KiB
C
435 lines
11 KiB
C
/*
|
|
* Copyright (C) 2012 Red Hat, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <locale.h>
|
|
|
|
#include <glib.h>
|
|
#include <glib/gi18n.h>
|
|
#include <gio/gio.h>
|
|
|
|
#include "gnome-session/gsm-inhibitor-flag.h"
|
|
|
|
static GsmInhibitorFlag parse_flags (const gchar *arg)
|
|
{
|
|
GsmInhibitorFlag flags;
|
|
gchar **args;
|
|
gint i;
|
|
|
|
flags = 0;
|
|
|
|
args = g_strsplit (arg, ":", 0);
|
|
for (i = 0; args[i]; i++)
|
|
{
|
|
if (strcmp (args[i], "logout") == 0)
|
|
flags |= GSM_INHIBITOR_FLAG_LOGOUT;
|
|
else if (strcmp (args[i], "switch-user") == 0)
|
|
flags |= GSM_INHIBITOR_FLAG_SWITCH_USER;
|
|
else if (strcmp (args[i], "suspend") == 0)
|
|
flags |= GSM_INHIBITOR_FLAG_SUSPEND;
|
|
else if (strcmp (args[i], "idle") == 0)
|
|
flags |= GSM_INHIBITOR_FLAG_IDLE;
|
|
else if (strcmp (args[i], "automount") == 0)
|
|
flags |= GSM_INHIBITOR_FLAG_AUTOMOUNT;
|
|
else
|
|
g_print ("Ignoring inhibit argument: %s\n", args[i]);
|
|
}
|
|
|
|
g_strfreev (args);
|
|
|
|
return flags;
|
|
}
|
|
|
|
static gboolean inhibit (const gchar *app_id,
|
|
const gchar *reason,
|
|
GsmInhibitorFlag flags)
|
|
{
|
|
GDBusConnection *bus;
|
|
GVariant *ret;
|
|
GError *error = NULL;
|
|
|
|
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
|
|
|
if (bus == NULL)
|
|
{
|
|
g_warning ("Failed to connect to session bus: %s", error->message);
|
|
g_error_free (error);
|
|
return FALSE;
|
|
}
|
|
|
|
ret = g_dbus_connection_call_sync (bus,
|
|
"org.gnome.SessionManager",
|
|
"/org/gnome/SessionManager",
|
|
"org.gnome.SessionManager",
|
|
"Inhibit",
|
|
g_variant_new ("(susu)",
|
|
app_id, 0, reason, flags),
|
|
G_VARIANT_TYPE ("(u)"),
|
|
0,
|
|
G_MAXINT,
|
|
NULL,
|
|
&error);
|
|
|
|
if (ret == NULL)
|
|
{
|
|
g_warning ("Failed to call Inhibit: %s\n", error->message);
|
|
g_error_free (error);
|
|
return FALSE;
|
|
}
|
|
|
|
g_variant_unref (ret);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void usage (void)
|
|
{
|
|
g_print (_("%s [OPTION…] COMMAND\n"
|
|
"\n"
|
|
"Execute COMMAND while inhibiting some session functionality.\n"
|
|
"\n"
|
|
" -h, --help Show this help\n"
|
|
" --version Show program version\n"
|
|
" --app-id ID The application id to use\n"
|
|
" when inhibiting (optional)\n"
|
|
" --reason REASON The reason for inhibiting (optional)\n"
|
|
" --inhibit ARG Things to inhibit, colon-separated list of:\n"
|
|
" logout, switch-user, suspend, idle, automount\n"
|
|
" --inhibit-only Do not launch COMMAND and wait forever instead\n"
|
|
" -l, --list List the existing inhibitions, and exit\n"
|
|
"\n"
|
|
"If no --inhibit option is specified, idle is assumed.\n"),
|
|
g_get_prgname ());
|
|
}
|
|
|
|
static void version (void)
|
|
{
|
|
g_print ("%s %s\n", g_get_prgname (), PACKAGE_VERSION);
|
|
}
|
|
|
|
static GVariant *
|
|
get_inhibitor_prop (GDBusProxy *inhibitor,
|
|
const char *method_name)
|
|
{
|
|
g_autoptr(GVariant) variant = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
variant = g_dbus_proxy_call_sync (inhibitor,
|
|
method_name,
|
|
NULL,
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1,
|
|
NULL,
|
|
&error);
|
|
|
|
if (variant == NULL) {
|
|
g_debug ("Failed to get property via '%s': %s",
|
|
method_name, error->message);
|
|
return NULL;
|
|
}
|
|
|
|
return g_variant_get_child_value (variant, 0);
|
|
}
|
|
|
|
static void
|
|
string_append_comma (GString *s,
|
|
const char *value)
|
|
{
|
|
if (s->len != 0)
|
|
g_string_append (s, ", ");
|
|
g_string_append (s, value);
|
|
}
|
|
|
|
static char *
|
|
flags_to_str (guint32 flags)
|
|
{
|
|
GString *s;
|
|
|
|
s = g_string_new (NULL);
|
|
if (flags & GSM_INHIBITOR_FLAG_LOGOUT)
|
|
string_append_comma (s, "logout");
|
|
if (flags & GSM_INHIBITOR_FLAG_SWITCH_USER)
|
|
string_append_comma (s, "switch-user");
|
|
if (flags & GSM_INHIBITOR_FLAG_SUSPEND)
|
|
string_append_comma (s, "suspend");
|
|
if (flags & GSM_INHIBITOR_FLAG_IDLE)
|
|
string_append_comma (s, "idle");
|
|
if (flags & GSM_INHIBITOR_FLAG_AUTOMOUNT)
|
|
string_append_comma (s, "automount");
|
|
|
|
return g_string_free (s, FALSE);
|
|
}
|
|
|
|
static void list (void)
|
|
{
|
|
g_autoptr(GDBusConnection) bus = NULL;
|
|
g_autoptr(GVariant) ret = NULL;
|
|
g_autoptr(GVariant) array = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
guint num_children;
|
|
g_autoptr(GVariantIter) iter = NULL;
|
|
const char *inhibitor_path;
|
|
|
|
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
|
|
|
if (bus == NULL)
|
|
{
|
|
g_warning ("Failed to connect to session bus: %s", error->message);
|
|
g_error_free (error);
|
|
return;
|
|
}
|
|
|
|
ret = g_dbus_connection_call_sync (bus,
|
|
"org.gnome.SessionManager",
|
|
"/org/gnome/SessionManager",
|
|
"org.gnome.SessionManager",
|
|
"GetInhibitors",
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
G_MAXINT,
|
|
NULL,
|
|
&error);
|
|
|
|
if (ret == NULL)
|
|
{
|
|
g_warning ("Failed to call GetInhibitors: %s\n", error->message);
|
|
g_error_free (error);
|
|
return;
|
|
}
|
|
|
|
array = g_variant_get_child_value (ret, 0);
|
|
|
|
num_children = g_variant_n_children (array);
|
|
if (num_children == 0)
|
|
{
|
|
g_print ("No inhibitors\n");
|
|
return;
|
|
}
|
|
|
|
g_variant_get (array, "ao", &iter);
|
|
while (g_variant_iter_loop (iter, "&o", &inhibitor_path))
|
|
{
|
|
g_autoptr(GDBusProxy) inhibitor = NULL;
|
|
g_autoptr(GVariant) app_id = NULL;
|
|
g_autoptr(GVariant) reason = NULL;
|
|
g_autoptr(GVariant) flags = NULL;
|
|
g_autofree char *flags_str = NULL;
|
|
|
|
inhibitor = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
|
NULL,
|
|
"org.gnome.SessionManager",
|
|
inhibitor_path,
|
|
"org.gnome.SessionManager.Inhibitor",
|
|
NULL,
|
|
&error);
|
|
|
|
/* Skip inhibitors that might have disappeared */
|
|
if (!inhibitor)
|
|
{
|
|
g_debug ("Failed to get proxy for %s: %s",
|
|
inhibitor_path,
|
|
error->message);
|
|
continue;
|
|
}
|
|
|
|
app_id = get_inhibitor_prop (inhibitor, "GetAppId");
|
|
reason = get_inhibitor_prop (inhibitor, "GetReason");
|
|
flags = get_inhibitor_prop (inhibitor, "GetFlags");
|
|
if (!app_id || !reason || !flags)
|
|
continue;
|
|
flags_str = flags_to_str (g_variant_get_uint32 (flags));
|
|
|
|
g_print ("%s: %s (%s)\n",
|
|
g_variant_get_string (app_id, NULL),
|
|
g_variant_get_string (reason, NULL),
|
|
flags_str);
|
|
}
|
|
}
|
|
|
|
static void
|
|
wait_for_child_app (char **argv)
|
|
{
|
|
pid_t pid;
|
|
int status;
|
|
int pipefd[2];
|
|
|
|
if (pipe(pipefd) != 0)
|
|
{
|
|
int error = errno;
|
|
g_print (_("Error while creating pipe: %s\n"), g_strerror (error));
|
|
exit (1);
|
|
}
|
|
|
|
pid = fork ();
|
|
if (pid < 0)
|
|
{
|
|
g_print ("fork failed\n");
|
|
exit (1);
|
|
}
|
|
|
|
if (pid == 0)
|
|
{
|
|
char c;
|
|
close(pipefd[1]);
|
|
if (read(pipefd[0], &c, 1) == -1)
|
|
{
|
|
g_print (_("Failure reading pipe\n"));
|
|
}
|
|
close(pipefd[0]);
|
|
execvp (*argv, argv);
|
|
g_print (_("Failed to execute %s\n"), *argv);
|
|
exit (1);
|
|
}
|
|
|
|
close(pipefd[0]);
|
|
|
|
do
|
|
{
|
|
setpgid (pid, pid);
|
|
if (isatty (0))
|
|
{
|
|
tcsetpgrp (0, pid);
|
|
}
|
|
write(pipefd[1], "\0", 1);
|
|
close(pipefd[1]);
|
|
if (waitpid (pid, &status, 0) == -1)
|
|
{
|
|
g_print ("waitpid failed\n");
|
|
exit (1);
|
|
}
|
|
|
|
if (WIFEXITED (status))
|
|
exit (WEXITSTATUS (status));
|
|
|
|
} while (!WIFEXITED (status) && ! WIFSIGNALED(status));
|
|
}
|
|
|
|
static void
|
|
wait_forever (void)
|
|
{
|
|
g_print ("Inhibiting until Ctrl+C is pressed...\n");
|
|
while (1)
|
|
sleep (UINT32_MAX);
|
|
}
|
|
|
|
int main (int argc, char *argv[])
|
|
{
|
|
gchar *prgname;
|
|
GsmInhibitorFlag inhibit_flags = 0;
|
|
gboolean show_help = FALSE;
|
|
gboolean show_version = FALSE;
|
|
gboolean show_list = FALSE;
|
|
gboolean no_launch = FALSE;
|
|
gint i;
|
|
const gchar *app_id = "unknown";
|
|
const gchar *reason = "not specified";
|
|
|
|
prgname = g_path_get_basename (argv[0]);
|
|
g_set_prgname (prgname);
|
|
g_free (prgname);
|
|
|
|
setlocale (LC_ALL, "");
|
|
bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
|
|
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
|
textdomain (GETTEXT_PACKAGE);
|
|
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
if (strcmp (argv[i], "--help") == 0 ||
|
|
strcmp (argv[i], "-h") == 0)
|
|
show_help = TRUE;
|
|
if (strcmp (argv[i], "--list") == 0 ||
|
|
strcmp (argv[i], "-l") == 0)
|
|
show_list = TRUE;
|
|
else if (strcmp (argv[i], "--version") == 0)
|
|
show_version = TRUE;
|
|
else if (strcmp (argv[i], "--inhibit-only") == 0)
|
|
no_launch = TRUE;
|
|
else if (strcmp (argv[i], "--app-id") == 0)
|
|
{
|
|
i++;
|
|
if (i == argc)
|
|
{
|
|
g_print (_("%s requires an argument\n"), argv[i]);
|
|
exit (1);
|
|
}
|
|
app_id = argv[i];
|
|
}
|
|
else if (strcmp (argv[i], "--reason") == 0)
|
|
{
|
|
i++;
|
|
if (i == argc)
|
|
{
|
|
g_print (_("%s requires an argument\n"), argv[i]);
|
|
exit (1);
|
|
}
|
|
reason = argv[i];
|
|
}
|
|
else if (strcmp (argv[i], "--inhibit") == 0)
|
|
{
|
|
i++;
|
|
if (i == argc)
|
|
{
|
|
g_print (_("%s requires an argument\n"), argv[i]);
|
|
exit (1);
|
|
}
|
|
inhibit_flags |= parse_flags (argv[i]);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (show_version)
|
|
{
|
|
version ();
|
|
return 0;
|
|
}
|
|
|
|
if (show_list)
|
|
{
|
|
list ();
|
|
return 0;
|
|
}
|
|
|
|
if (show_help || (i == argc && !no_launch))
|
|
{
|
|
usage ();
|
|
return 0;
|
|
}
|
|
|
|
if (inhibit_flags == 0)
|
|
inhibit_flags = GSM_INHIBITOR_FLAG_IDLE;
|
|
|
|
if (inhibit (app_id, reason, inhibit_flags) == FALSE)
|
|
return 1;
|
|
|
|
if (!no_launch)
|
|
wait_for_child_app (argv + i);
|
|
else
|
|
wait_forever ();
|
|
|
|
return 0;
|
|
}
|