source: proiecte/PPPP/gdm/daemon/gdm-session-worker-job.c @ 134

Last change on this file since 134 was 134, checked in by (none), 14 years ago

gdm sources with the modifications for webcam

File size: 15.0 KB
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 */
20
21#include "config.h"
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <fcntl.h>
26#include <unistd.h>
27#include <string.h>
28#include <sys/types.h>
29#include <sys/wait.h>
30#include <errno.h>
31#include <ctype.h>
32#include <pwd.h>
33#include <grp.h>
34#include <signal.h>
35
36#include <glib.h>
37#include <glib/gi18n.h>
38#include <glib-object.h>
39#define DBUS_API_SUBJECT_TO_CHANGE
40#include <dbus/dbus-glib.h>
41#include <dbus/dbus-glib-lowlevel.h>
42
43#include "gdm-common.h"
44
45#include "gdm-session-worker-job.h"
46
47#define GDM_SESSION_SERVER_DBUS_PATH      "/org/gnome/DisplayManager/SessionServer"
48#define GDM_SESSION_SERVER_DBUS_INTERFACE "org.gnome.DisplayManager.SessionServer"
49
50extern char **environ;
51
52#define GDM_SESSION_WORKER_JOB_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SESSION_WORKER_JOB, GdmSessionWorkerJobPrivate))
53
54struct GdmSessionWorkerJobPrivate
55{
56        char           *command;
57        GPid            pid;
58
59        guint           child_watch_id;
60
61        char           *server_address;
62};
63
64enum {
65        PROP_0,
66        PROP_SERVER_ADDRESS,
67};
68
69enum {
70        STARTED,
71        STOPPED,
72        EXITED,
73        DIED,
74        LAST_SIGNAL
75};
76
77static guint signals [LAST_SIGNAL] = { 0, };
78
79static void     gdm_session_worker_job_class_init       (GdmSessionWorkerJobClass *klass);
80static void     gdm_session_worker_job_init     (GdmSessionWorkerJob      *session_worker_job);
81static void     gdm_session_worker_job_finalize (GObject         *object);
82
83G_DEFINE_TYPE (GdmSessionWorkerJob, gdm_session_worker_job, G_TYPE_OBJECT)
84
85static void
86session_worker_job_child_setup (GdmSessionWorkerJob *session_worker_job)
87{
88}
89
90static void
91session_worker_job_child_watch (GPid                 pid,
92                                int                  status,
93                                GdmSessionWorkerJob *job)
94{
95        g_debug ("GdmSessionWorkerJob: child (pid:%d) done (%s:%d)",
96                 (int) pid,
97                 WIFEXITED (status) ? "status"
98                 : WIFSIGNALED (status) ? "signal"
99                 : "unknown",
100                 WIFEXITED (status) ? WEXITSTATUS (status)
101                 : WIFSIGNALED (status) ? WTERMSIG (status)
102                 : -1);
103
104        g_spawn_close_pid (job->priv->pid);
105        job->priv->pid = -1;
106
107        if (WIFEXITED (status)) {
108                int code = WEXITSTATUS (status);
109                g_signal_emit (job, signals [EXITED], 0, code);
110        } else if (WIFSIGNALED (status)) {
111                int num = WTERMSIG (status);
112                g_signal_emit (job, signals [DIED], 0, num);
113        }
114}
115
116static void
117listify_hash (const char *key,
118              const char *value,
119              GPtrArray  *env)
120{
121        char *str;
122
123        if (value == NULL)
124                value = "";
125
126        str = g_strdup_printf ("%s=%s", key, value);
127        g_ptr_array_add (env, str);
128}
129
130static void
131copy_environment_to_hash (GHashTable *hash)
132{
133        gchar **env_strv;
134        gint    i;
135
136        env_strv = g_listenv ();
137
138        for (i = 0; env_strv [i]; i++) {
139                gchar *key = env_strv [i];
140                const gchar *value;
141
142                value = g_getenv (key);
143                if (!value)
144                        continue;
145
146                g_hash_table_insert (hash, g_strdup (key), g_strdup (value));
147        }
148
149        g_strfreev (env_strv);
150}
151
152static GPtrArray *
153get_job_environment (GdmSessionWorkerJob *job)
154{
155        GPtrArray     *env;
156        GHashTable    *hash;
157
158        env = g_ptr_array_new ();
159
160        /* create a hash table of current environment, then update keys has necessary */
161        hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
162        copy_environment_to_hash (hash);
163
164        g_hash_table_insert (hash, g_strdup ("GDM_SESSION_DBUS_ADDRESS"), g_strdup (job->priv->server_address));
165
166        g_hash_table_foreach (hash, (GHFunc)listify_hash, env);
167        g_hash_table_destroy (hash);
168
169        g_ptr_array_add (env, NULL);
170
171        return env;
172}
173
174static gboolean
175gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job)
176{
177        gchar          **argv;
178        GError          *error;
179        gboolean         ret;
180        GPtrArray       *env;
181
182        ret = FALSE;
183
184        g_debug ("GdmSessionWorkerJob: Running session_worker_job process: %s", session_worker_job->priv->command);
185
186        argv = NULL;
187        if (! g_shell_parse_argv (session_worker_job->priv->command, NULL, &argv, &error)) {
188                g_warning ("Could not parse command: %s", error->message);
189                g_error_free (error);
190                goto out;
191        }
192
193        env = get_job_environment (session_worker_job);
194
195        error = NULL;
196        ret = g_spawn_async_with_pipes (NULL,
197                                        argv,
198                                        (char **)env->pdata,
199                                        G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
200                                        (GSpawnChildSetupFunc)session_worker_job_child_setup,
201                                        session_worker_job,
202                                        &session_worker_job->priv->pid,
203                                        NULL,
204                                        NULL,
205                                        NULL,
206                                        &error);
207
208        g_ptr_array_foreach (env, (GFunc)g_free, NULL);
209        g_ptr_array_free (env, TRUE);
210
211        if (! ret) {
212                g_warning ("Could not start command '%s': %s",
213                           session_worker_job->priv->command,
214                           error->message);
215                g_error_free (error);
216        } else {
217                g_debug ("GdmSessionWorkerJob: : SessionWorkerJob on pid %d", (int)session_worker_job->priv->pid);
218        }
219
220        session_worker_job->priv->child_watch_id = g_child_watch_add (session_worker_job->priv->pid,
221                                                                      (GChildWatchFunc)session_worker_job_child_watch,
222                                                                      session_worker_job);
223
224        g_strfreev (argv);
225 out:
226
227        return ret;
228}
229
230/**
231 * gdm_session_worker_job_start:
232 * @disp: Pointer to a GdmDisplay structure
233 *
234 * Starts a local X session_worker_job. Handles retries and fatal errors properly.
235 */
236gboolean
237gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job)
238{
239        gboolean    res;
240
241        g_debug ("GdmSessionWorkerJob: Starting worker...");
242
243        res = gdm_session_worker_job_spawn (session_worker_job);
244
245        if (res) {
246
247        }
248
249
250        return res;
251}
252
253static void
254session_worker_job_died (GdmSessionWorkerJob *session_worker_job)
255{
256        int exit_status;
257
258        g_debug ("GdmSessionWorkerJob: Waiting on process %d", session_worker_job->priv->pid);
259        exit_status = gdm_wait_on_pid (session_worker_job->priv->pid);
260
261        if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) {
262                g_debug ("GdmSessionWorkerJob: Wait on child process failed");
263        } else {
264                /* exited normally */
265        }
266
267        g_spawn_close_pid (session_worker_job->priv->pid);
268        session_worker_job->priv->pid = -1;
269
270        g_debug ("GdmSessionWorkerJob: SessionWorkerJob died");
271}
272
273gboolean
274gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job)
275{
276        int res;
277
278        if (session_worker_job->priv->pid <= 1) {
279                return TRUE;
280        }
281
282        /* remove watch source before we can wait on child */
283        if (session_worker_job->priv->child_watch_id > 0) {
284                g_source_remove (session_worker_job->priv->child_watch_id);
285                session_worker_job->priv->child_watch_id = 0;
286        }
287
288        g_debug ("GdmSessionWorkerJob: Stopping job pid:%d", session_worker_job->priv->pid);
289
290        res = gdm_signal_pid (session_worker_job->priv->pid, SIGTERM);
291        if (res < 0) {
292                g_warning ("Unable to kill session worker process");
293        } else {
294                session_worker_job_died (session_worker_job);
295        }
296
297        return TRUE;
298}
299
300void
301gdm_session_worker_job_set_server_address (GdmSessionWorkerJob *session_worker_job,
302                                           const char      *address)
303{
304        g_return_if_fail (GDM_IS_SESSION_WORKER_JOB (session_worker_job));
305
306        g_free (session_worker_job->priv->server_address);
307        session_worker_job->priv->server_address = g_strdup (address);
308}
309
310static void
311gdm_session_worker_job_set_property (GObject      *object,
312                                     guint         prop_id,
313                                     const GValue *value,
314                                     GParamSpec   *pspec)
315{
316        GdmSessionWorkerJob *self;
317
318        self = GDM_SESSION_WORKER_JOB (object);
319
320        switch (prop_id) {
321        case PROP_SERVER_ADDRESS:
322                gdm_session_worker_job_set_server_address (self, g_value_get_string (value));
323                break;
324        default:
325                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
326                break;
327        }
328}
329
330static void
331gdm_session_worker_job_get_property (GObject    *object,
332                                     guint       prop_id,
333                                     GValue     *value,
334                                     GParamSpec *pspec)
335{
336        GdmSessionWorkerJob *self;
337
338        self = GDM_SESSION_WORKER_JOB (object);
339
340        switch (prop_id) {
341        case PROP_SERVER_ADDRESS:
342                g_value_set_string (value, self->priv->server_address);
343                break;
344        default:
345                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
346                break;
347        }
348}
349
350static GObject *
351gdm_session_worker_job_constructor (GType                  type,
352                                    guint                  n_construct_properties,
353                                    GObjectConstructParam *construct_properties)
354{
355        GdmSessionWorkerJob      *session_worker_job;
356
357        session_worker_job = GDM_SESSION_WORKER_JOB (G_OBJECT_CLASS (gdm_session_worker_job_parent_class)->constructor (type,
358                                                                                       n_construct_properties,
359                                                                                       construct_properties));
360
361        return G_OBJECT (session_worker_job);
362}
363
364static void
365gdm_session_worker_job_class_init (GdmSessionWorkerJobClass *klass)
366{
367        GObjectClass    *object_class = G_OBJECT_CLASS (klass);
368
369        object_class->get_property = gdm_session_worker_job_get_property;
370        object_class->set_property = gdm_session_worker_job_set_property;
371        object_class->constructor = gdm_session_worker_job_constructor;
372        object_class->finalize = gdm_session_worker_job_finalize;
373
374        g_type_class_add_private (klass, sizeof (GdmSessionWorkerJobPrivate));
375
376        g_object_class_install_property (object_class,
377                                         PROP_SERVER_ADDRESS,
378                                         g_param_spec_string ("server-address",
379                                                              "server address",
380                                                              "server address",
381                                                              NULL,
382                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
383        signals [STARTED] =
384                g_signal_new ("started",
385                              G_OBJECT_CLASS_TYPE (object_class),
386                              G_SIGNAL_RUN_FIRST,
387                              G_STRUCT_OFFSET (GdmSessionWorkerJobClass, started),
388                              NULL,
389                              NULL,
390                              g_cclosure_marshal_VOID__VOID,
391                              G_TYPE_NONE,
392                              0);
393        signals [STOPPED] =
394                g_signal_new ("stopped",
395                              G_OBJECT_CLASS_TYPE (object_class),
396                              G_SIGNAL_RUN_FIRST,
397                              G_STRUCT_OFFSET (GdmSessionWorkerJobClass, stopped),
398                              NULL,
399                              NULL,
400                              g_cclosure_marshal_VOID__VOID,
401                              G_TYPE_NONE,
402                              0);
403        signals [EXITED] =
404                g_signal_new ("exited",
405                              G_OBJECT_CLASS_TYPE (object_class),
406                              G_SIGNAL_RUN_FIRST,
407                              G_STRUCT_OFFSET (GdmSessionWorkerJobClass, exited),
408                              NULL,
409                              NULL,
410                              g_cclosure_marshal_VOID__INT,
411                              G_TYPE_NONE,
412                              1,
413                              G_TYPE_INT);
414
415        signals [DIED] =
416                g_signal_new ("died",
417                              G_OBJECT_CLASS_TYPE (object_class),
418                              G_SIGNAL_RUN_FIRST,
419                              G_STRUCT_OFFSET (GdmSessionWorkerJobClass, died),
420                              NULL,
421                              NULL,
422                              g_cclosure_marshal_VOID__INT,
423                              G_TYPE_NONE,
424                              1,
425                              G_TYPE_INT);
426}
427
428static void
429gdm_session_worker_job_init (GdmSessionWorkerJob *session_worker_job)
430{
431
432        session_worker_job->priv = GDM_SESSION_WORKER_JOB_GET_PRIVATE (session_worker_job);
433
434        session_worker_job->priv->pid = -1;
435
436        session_worker_job->priv->command = g_strdup (LIBEXECDIR "/gdm-session-worker");
437}
438
439static void
440gdm_session_worker_job_finalize (GObject *object)
441{
442        GdmSessionWorkerJob *session_worker_job;
443
444        g_return_if_fail (object != NULL);
445        g_return_if_fail (GDM_IS_SESSION_WORKER_JOB (object));
446
447        session_worker_job = GDM_SESSION_WORKER_JOB (object);
448
449        g_return_if_fail (session_worker_job->priv != NULL);
450
451        gdm_session_worker_job_stop (session_worker_job);
452
453        G_OBJECT_CLASS (gdm_session_worker_job_parent_class)->finalize (object);
454}
455
456GdmSessionWorkerJob *
457gdm_session_worker_job_new (void)
458{
459        GObject *object;
460
461        object = g_object_new (GDM_TYPE_SESSION_WORKER_JOB,
462                               NULL);
463
464        return GDM_SESSION_WORKER_JOB (object);
465}
Note: See TracBrowser for help on using the repository browser.