2
* Copyright 2013 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License version 3, as published
6
* by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranties of
10
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11
* PURPOSE. See the GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License along
14
* with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Ted Gould <ted.gould@canonical.com>
22
#include <cgmanager/cgmanager.h>
24
/* Check to make sure we have the sections and keys we want */
26
verify_keyfile (GKeyFile * inkeyfile, const gchar * desktop)
28
if (inkeyfile == NULL) return FALSE;
30
if (!g_key_file_has_group(inkeyfile, "Desktop Entry")) {
31
g_warning("Desktop file '%s' is missing the 'Desktop Entry' group", desktop);
35
if (!g_key_file_has_key(inkeyfile, "Desktop Entry", "Exec", NULL)) {
36
g_warning("Desktop file '%s' is missing the 'Exec' key", desktop);
43
/* Try to find a desktop file in a particular data directory */
45
try_dir (const char * dir, const gchar * desktop)
47
gchar * fullpath = g_build_filename(dir, "applications", desktop, NULL);
48
GKeyFile * keyfile = g_key_file_new();
50
/* NOTE: Leaving off the error here as we'll get a bunch of them,
51
so individuals aren't really useful */
52
gboolean loaded = g_key_file_load_from_file(keyfile, fullpath, G_KEY_FILE_NONE, NULL);
57
g_key_file_free(keyfile);
61
if (!verify_keyfile(keyfile, desktop)) {
62
g_key_file_free(keyfile);
69
/* Find the keyfile that we need for a particular AppID and return it.
70
Or NULL if we can't find it. */
72
keyfile_for_appid (const gchar * appid, gchar ** desktopfile)
74
gchar * desktop = g_strdup_printf("%s.desktop", appid);
76
const char * const * data_dirs = g_get_system_data_dirs();
77
GKeyFile * keyfile = NULL;
80
keyfile = try_dir(g_get_user_data_dir(), desktop);
81
if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
82
*desktopfile = g_build_filename(g_get_user_data_dir(), "applications", desktop, NULL);
85
for (i = 0; data_dirs[i] != NULL && keyfile == NULL; i++) {
86
keyfile = try_dir(data_dirs[i], desktop);
88
if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
89
*desktopfile = g_build_filename(data_dirs[i], "applications", desktop, NULL);
98
/* Get the connection to the cgroup manager */
100
cgroup_manager_connection (void)
102
GError * error = NULL;
104
GDBusConnection * cgmanager = NULL;
106
if (g_getenv("UBUNTU_APP_LAUNCH_CG_MANAGER_SESSION_BUS")) {
107
/* For working dbusmock */
108
g_debug("Connecting to CG Manager on session bus");
109
cgmanager = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
111
cgmanager = g_dbus_connection_new_for_address_sync(
113
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
114
NULL, /* Auth Observer */
115
NULL, /* Cancellable */
120
g_warning("Unable to connect to cgroup manager: %s", error->message);
128
/* Get the PIDs for a particular cgroup */
129
/* We're using the base cgroup 'freezer' in this code (and
130
in the Upstart jobs). Really the actual group is meaningless
131
we just need one that is in every kernel we need to support.
132
We're just using the cgroup as a bag of PIDs, not for
133
restricting any particular resource. */
135
pids_from_cgroup (GDBusConnection * cgmanager, const gchar * jobname, const gchar * instancename)
137
GError * error = NULL;
138
const gchar * name = g_getenv("UBUNTU_APP_LAUNCH_CG_MANAGER_NAME");
139
gchar * groupname = NULL;
140
if (jobname != NULL) {
141
groupname = g_strdup_printf("upstart/%s-%s", jobname, instancename);
144
g_debug("Looking for cg manager '%s' group '%s'", name, groupname);
146
GVariant * vtpids = g_dbus_connection_call_sync(cgmanager,
147
name, /* bus name for direct connection is NULL */
148
"/org/linuxcontainers/cgmanager",
149
"org.linuxcontainers.cgmanager0_0",
151
g_variant_new("(ss)", "freezer", groupname ? groupname : ""),
152
G_VARIANT_TYPE("(ai)"),
153
G_DBUS_CALL_FLAGS_NONE,
154
-1, /* default timeout */
155
NULL, /* cancellable */
161
g_warning("Unable to get PID list from cgroup manager: %s", error->message);
166
GVariant * vpids = g_variant_get_child_value(vtpids, 0);
168
g_variant_iter_init(&iter, vpids);
170
GList * retval = NULL;
172
while (g_variant_iter_loop(&iter, "i", &pid)) {
173
retval = g_list_prepend(retval, GINT_TO_POINTER(pid));
176
g_variant_unref(vpids);
177
g_variant_unref(vtpids);