source: proiecte/PPPP/gdm/daemon/gdm-slave-proxy.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: 12.7 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 <signal.h>
32
33#include <glib.h>
34#include <glib/gi18n.h>
35#include <glib/gstdio.h>
36#include <glib-object.h>
37
38#include "gdm-common.h"
39
40#include "gdm-slave-proxy.h"
41
42#define GDM_SLAVE_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SLAVE_PROXY, GdmSlaveProxyPrivate))
43
44#define MAX_LOGS 5
45
46struct GdmSlaveProxyPrivate
47{
48        char    *command;
49        char    *log_path;
50        GPid     pid;
51        guint    child_watch_id;
52};
53
54enum {
55        PROP_0,
56        PROP_COMMAND,
57        PROP_LOG_PATH,
58};
59
60enum {
61        EXITED,
62        DIED,
63        LAST_SIGNAL
64};
65
66static guint signals [LAST_SIGNAL] = { 0, };
67
68static void     gdm_slave_proxy_class_init      (GdmSlaveProxyClass *klass);
69static void     gdm_slave_proxy_init            (GdmSlaveProxy      *slave);
70static void     gdm_slave_proxy_finalize        (GObject            *object);
71
72G_DEFINE_TYPE (GdmSlaveProxy, gdm_slave_proxy, G_TYPE_OBJECT)
73
74static void
75child_watch (GPid           pid,
76             int            status,
77             GdmSlaveProxy *slave)
78{
79        g_debug ("GdmSlaveProxy: slave (pid:%d) done (%s:%d)",
80                 (int) pid,
81                 WIFEXITED (status) ? "status"
82                 : WIFSIGNALED (status) ? "signal"
83                 : "unknown",
84                 WIFEXITED (status) ? WEXITSTATUS (status)
85                 : WIFSIGNALED (status) ? WTERMSIG (status)
86                 : -1);
87
88        g_spawn_close_pid (slave->priv->pid);
89        slave->priv->pid = -1;
90        slave->priv->child_watch_id = 0;
91
92        if (WIFEXITED (status)) {
93                int code = WEXITSTATUS (status);
94                g_signal_emit (slave, signals [EXITED], 0, code);
95        } else if (WIFSIGNALED (status)) {
96                int num = WTERMSIG (status);
97                g_signal_emit (slave, signals [DIED], 0, num);
98        }
99}
100
101static void
102rotate_logs (const char *path,
103             guint       n_copies)
104{
105        int i;
106
107        for (i = n_copies - 1; i > 0; i--) {
108                char *name_n;
109                char *name_n1;
110
111                name_n = g_strdup_printf ("%s.%d", path, i);
112                if (i > 1) {
113                        name_n1 = g_strdup_printf ("%s.%d", path, i - 1);
114                } else {
115                        name_n1 = g_strdup (path);
116                }
117
118                VE_IGNORE_EINTR (g_unlink (name_n));
119                VE_IGNORE_EINTR (g_rename (name_n1, name_n));
120
121                g_free (name_n1);
122                g_free (name_n);
123        }
124
125        VE_IGNORE_EINTR (g_unlink (path));
126}
127
128typedef struct {
129        const char *log_file;
130} SpawnChildData;
131
132static void
133spawn_child_setup (SpawnChildData *data)
134{
135
136        if (data->log_file != NULL) {
137                int logfd;
138
139                rotate_logs (data->log_file, MAX_LOGS);
140
141                VE_IGNORE_EINTR (g_unlink (data->log_file));
142                VE_IGNORE_EINTR (logfd = open (data->log_file, O_CREAT|O_APPEND|O_TRUNC|O_WRONLY|O_EXCL, 0644));
143
144                if (logfd != -1) {
145                        VE_IGNORE_EINTR (dup2 (logfd, 1));
146                        VE_IGNORE_EINTR (dup2 (logfd, 2));
147                        close (logfd);
148                }
149        }
150}
151
152static gboolean
153spawn_command_line_async (const char *command_line,
154                          const char *log_file,
155                          char      **env,
156                          GPid       *child_pid,
157                          GError    **error)
158{
159        char           **argv;
160        GError          *local_error;
161        gboolean         ret;
162        gboolean         res;
163        SpawnChildData   data;
164
165        ret = FALSE;
166
167        argv = NULL;
168        local_error = NULL;
169        if (! g_shell_parse_argv (command_line, NULL, &argv, &local_error)) {
170                g_warning ("Could not parse command: %s", local_error->message);
171                g_propagate_error (error, local_error);
172                goto out;
173        }
174
175        data.log_file = log_file;
176
177        local_error = NULL;
178        res = g_spawn_async (NULL,
179                             argv,
180                             env,
181                             G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
182                             (GSpawnChildSetupFunc)spawn_child_setup,
183                             &data,
184                             child_pid,
185                             &local_error);
186
187        if (! res) {
188                g_warning ("Could not spawn command: %s", local_error->message);
189                g_propagate_error (error, local_error);
190                goto out;
191        }
192
193        ret = TRUE;
194 out:
195        g_strfreev (argv);
196
197        return ret;
198}
199
200static gboolean
201spawn_slave (GdmSlaveProxy *slave)
202{
203        gboolean    result;
204        GError     *error;
205
206        g_debug ("GdmSlaveProxy: Running command: %s", slave->priv->command);
207
208        error = NULL;
209        result = spawn_command_line_async (slave->priv->command,
210                                           slave->priv->log_path,
211                                           NULL,
212                                           &slave->priv->pid,
213                                           &error);
214        if (! result) {
215                g_warning ("Could not start command '%s': %s", slave->priv->command, error->message);
216                g_error_free (error);
217                goto out;
218        }
219
220        g_debug ("GdmSlaveProxy: Started slave with pid %d", slave->priv->pid);
221
222        slave->priv->child_watch_id = g_child_watch_add (slave->priv->pid,
223                                                         (GChildWatchFunc)child_watch,
224                                                         slave);
225
226        result = TRUE;
227
228 out:
229
230        return result;
231}
232
233static void
234kill_slave (GdmSlaveProxy *slave)
235{
236        int exit_status;
237        int res;
238
239        if (slave->priv->pid <= 1) {
240                return;
241        }
242
243        res = gdm_signal_pid (slave->priv->pid, SIGTERM);
244        if (res < 0) {
245                g_warning ("Unable to kill slave process");
246        } else {
247                exit_status = gdm_wait_on_pid (slave->priv->pid);
248                g_spawn_close_pid (slave->priv->pid);
249                slave->priv->pid = 0;
250        }
251}
252
253gboolean
254gdm_slave_proxy_start (GdmSlaveProxy *slave)
255{
256        spawn_slave (slave);
257
258        return TRUE;
259}
260
261gboolean
262gdm_slave_proxy_stop (GdmSlaveProxy *slave)
263{
264        g_debug ("GdmSlaveProxy: Killing slave");
265
266        if (slave->priv->child_watch_id > 0) {
267                g_source_remove (slave->priv->child_watch_id);
268                slave->priv->child_watch_id = 0;
269        }
270
271        kill_slave (slave);
272
273        return TRUE;
274}
275
276void
277gdm_slave_proxy_set_command (GdmSlaveProxy *slave,
278                             const char    *command)
279{
280        g_free (slave->priv->command);
281        slave->priv->command = g_strdup (command);
282}
283
284void
285gdm_slave_proxy_set_log_path (GdmSlaveProxy *slave,
286                              const char    *path)
287{
288        g_free (slave->priv->log_path);
289        slave->priv->log_path = g_strdup (path);
290}
291
292static void
293gdm_slave_proxy_set_property (GObject      *object,
294                              guint         prop_id,
295                              const GValue *value,
296                              GParamSpec   *pspec)
297{
298        GdmSlaveProxy *self;
299
300        self = GDM_SLAVE_PROXY (object);
301
302        switch (prop_id) {
303        case PROP_COMMAND:
304                gdm_slave_proxy_set_command (self, g_value_get_string (value));
305                break;
306        case PROP_LOG_PATH:
307                gdm_slave_proxy_set_log_path (self, g_value_get_string (value));
308                break;
309        default:
310                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
311                break;
312        }
313}
314
315static void
316gdm_slave_proxy_get_property (GObject    *object,
317                              guint       prop_id,
318                              GValue     *value,
319                              GParamSpec *pspec)
320{
321        GdmSlaveProxy *self;
322
323        self = GDM_SLAVE_PROXY (object);
324
325        switch (prop_id) {
326        case PROP_COMMAND:
327                g_value_set_string (value, self->priv->command);
328                break;
329        case PROP_LOG_PATH:
330                g_value_set_string (value, self->priv->log_path);
331                break;
332        default:
333                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
334                break;
335        }
336}
337
338static void
339gdm_slave_proxy_dispose (GObject *object)
340{
341        GdmSlaveProxy *slave;
342
343        slave = GDM_SLAVE_PROXY (object);
344
345        g_debug ("GdmSlaveProxy: Disposing slave proxy");
346        gdm_slave_proxy_stop (slave);
347
348        G_OBJECT_CLASS (gdm_slave_proxy_parent_class)->dispose (object);
349}
350
351static void
352gdm_slave_proxy_class_init (GdmSlaveProxyClass *klass)
353{
354        GObjectClass    *object_class = G_OBJECT_CLASS (klass);
355
356        object_class->get_property = gdm_slave_proxy_get_property;
357        object_class->set_property = gdm_slave_proxy_set_property;
358        object_class->dispose = gdm_slave_proxy_dispose;
359        object_class->finalize = gdm_slave_proxy_finalize;
360
361        g_type_class_add_private (klass, sizeof (GdmSlaveProxyPrivate));
362
363        g_object_class_install_property (object_class,
364                                         PROP_COMMAND,
365                                         g_param_spec_string ("command",
366                                                              "command",
367                                                              "command",
368                                                              NULL,
369                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
370        g_object_class_install_property (object_class,
371                                         PROP_LOG_PATH,
372                                         g_param_spec_string ("log-path",
373                                                              "log path",
374                                                              "log path",
375                                                              NULL,
376                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
377
378        signals [EXITED] =
379                g_signal_new ("exited",
380                              G_OBJECT_CLASS_TYPE (object_class),
381                              G_SIGNAL_RUN_FIRST,
382                              G_STRUCT_OFFSET (GdmSlaveProxyClass, exited),
383                              NULL,
384                              NULL,
385                              g_cclosure_marshal_VOID__INT,
386                              G_TYPE_NONE,
387                              1,
388                              G_TYPE_INT);
389
390        signals [DIED] =
391                g_signal_new ("died",
392                              G_OBJECT_CLASS_TYPE (object_class),
393                              G_SIGNAL_RUN_FIRST,
394                              G_STRUCT_OFFSET (GdmSlaveProxyClass, died),
395                              NULL,
396                              NULL,
397                              g_cclosure_marshal_VOID__INT,
398                              G_TYPE_NONE,
399                              1,
400                              G_TYPE_INT);
401}
402
403static void
404gdm_slave_proxy_init (GdmSlaveProxy *slave)
405{
406
407        slave->priv = GDM_SLAVE_PROXY_GET_PRIVATE (slave);
408
409        slave->priv->pid = -1;
410}
411
412static void
413gdm_slave_proxy_finalize (GObject *object)
414{
415        GdmSlaveProxy *slave;
416
417        g_return_if_fail (object != NULL);
418        g_return_if_fail (GDM_IS_SLAVE_PROXY (object));
419
420        slave = GDM_SLAVE_PROXY (object);
421
422        g_return_if_fail (slave->priv != NULL);
423
424        g_free (slave->priv->command);
425
426        G_OBJECT_CLASS (gdm_slave_proxy_parent_class)->finalize (object);
427}
428
429GdmSlaveProxy *
430gdm_slave_proxy_new (void)
431{
432        GObject *object;
433
434        object = g_object_new (GDM_TYPE_SLAVE_PROXY,
435                               NULL);
436
437        return GDM_SLAVE_PROXY (object);
438}
Note: See TracBrowser for help on using the repository browser.