~lightdm-team/lightdm/1.4

« back to all changes in this revision

Viewing changes to src/child-process.c

  • Committer: robert.ancell at canonical
  • Date: 2011-02-20 10:27:53 UTC
  • Revision ID: robert.ancell@canonical.com-20110220102753-2kehwju1amzcpoag
Use a private pipe for greeter<->server communication instead of D-Bus (needs to be fixed in liblightdm-qt)

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
#include "child-process.h"
24
24
 
25
25
enum {
 
26
    GOT_DATA,
26
27
    GOT_SIGNAL,  
27
28
    EXITED,
28
29
    TERMINATED,
42
43
 
43
44
    /* Path of file to log to */
44
45
    gchar *log_file;
 
46
  
 
47
    /* Pipes to communicate with */
 
48
    GIOChannel *to_child_channel;
 
49
    GIOChannel *from_child_channel;
45
50
 
46
51
    /* Process ID */
47
52
    GPid pid;
111
116
}
112
117
 
113
118
static void
114
 
child_process_fork_cb (gpointer data)
 
119
run_child_process (ChildProcess *process, char *const argv[])
115
120
{
116
 
    ChildProcess *process = data;
117
121
    GHashTableIter iter;
118
122
    gpointer key, value;
119
123
    int fd;
120
124
 
 
125
    /* FIXME: Close existing file descriptors */
 
126
 
121
127
    /* Make input non-blocking */
122
128
    fd = g_open ("/dev/null", O_RDONLY);
123
129
    dup2 (fd, STDIN_FILENO);
171
177
             close (fd);
172
178
         }
173
179
    }
 
180
  
 
181
    execvp (argv[0], argv);
 
182
}
 
183
 
 
184
static gboolean
 
185
from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
 
186
{
 
187
    ChildProcess *process = data;
 
188
    g_signal_emit (process, signals[GOT_DATA], 0);
 
189
    return TRUE;
174
190
}
175
191
 
176
192
gboolean
178
194
                     const gchar *username,
179
195
                     const gchar *working_dir,
180
196
                     const gchar *command,
 
197
                     gboolean create_pipe,
181
198
                     GError **error)
182
199
{
183
200
    gboolean result;
186
203
    GString *string;
187
204
    gpointer key, value;
188
205
    GHashTableIter iter;
189
 
    //gint child_process_stdin, child_process_stdout, child_process_stderr;
 
206
    pid_t pid;
 
207
    int from_server_fd = -1, to_server_fd = -1;
190
208
 
191
209
    g_return_val_if_fail (process->priv->pid == 0, FALSE);
192
210
 
215
233
        gint fd = g_open (process->priv->log_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
216
234
        close (fd);
217
235
        if (chown (process->priv->log_file, process->priv->uid, process->priv->gid) != 0)
218
 
            g_warning ("Failed to set greeter log file ownership: %s", strerror (errno));
219
 
    }
 
236
            g_warning ("Failed to set process log file ownership: %s", strerror (errno));
 
237
    }
 
238
 
 
239
    if (create_pipe)
 
240
    {
 
241
        gchar *fd;
 
242
        int to_child_pipe[2];
 
243
        int from_child_pipe[2];
 
244
 
 
245
        if (pipe (to_child_pipe) != 0 || 
 
246
            pipe (from_child_pipe) != 0)
 
247
        {
 
248
            g_warning ("Failed to create pipes: %s", strerror (errno));            
 
249
            return FALSE;
 
250
        }
 
251
 
 
252
        process->priv->to_child_channel = g_io_channel_unix_new (to_child_pipe[1]);
 
253
        g_io_channel_set_encoding (process->priv->to_child_channel, NULL, NULL);
 
254
 
 
255
        /* Watch for data from the child process */
 
256
        process->priv->from_child_channel = g_io_channel_unix_new (from_child_pipe[0]);
 
257
        g_io_channel_set_encoding (process->priv->from_child_channel, NULL, NULL);
 
258
        g_io_add_watch (process->priv->from_child_channel, G_IO_IN, from_child_cb, process);
 
259
 
 
260
        to_server_fd = from_child_pipe[1];
 
261
        from_server_fd = to_child_pipe[0];
 
262
 
 
263
        fd = g_strdup_printf ("%d", to_server_fd);
 
264
        child_process_set_env (process, "LDM_TO_SERVER_FD", fd);
 
265
        g_free (fd);
 
266
        fd = g_strdup_printf ("%d", from_server_fd);
 
267
        child_process_set_env (process, "LDM_FROM_SERVER_FD", fd);
 
268
        g_free (fd);
 
269
    }
 
270
 
 
271
    result = g_shell_parse_argv (command, &argc, &argv, error);
 
272
    if (!result)
 
273
        return FALSE;
 
274
 
 
275
    pid = fork ();
 
276
    if (pid < 0)
 
277
    {
 
278
        g_warning ("Failed to fork: %s", strerror (errno));
 
279
        return FALSE;
 
280
    }
 
281
 
 
282
    if (pid == 0)
 
283
    {
 
284
        /* Close pipes */
 
285
        // TEMP: Remove this when have more generic file closing
 
286
        if (process->priv->to_child_channel)
 
287
            close (g_io_channel_unix_get_fd (process->priv->to_child_channel));
 
288
        if (process->priv->from_child_channel)
 
289
            close (g_io_channel_unix_get_fd (process->priv->from_child_channel));
 
290
 
 
291
        run_child_process (process, argv);
 
292
        _exit (EXIT_FAILURE);
 
293
    }
 
294
    close (from_server_fd);
 
295
    close (to_server_fd);
220
296
 
221
297
    string = g_string_new ("");
222
298
    g_hash_table_iter_init (&iter, process->priv->env);
223
 
    if (g_hash_table_iter_next (&iter, &key, &value))
 
299
    while (g_hash_table_iter_next (&iter, &key, &value))
224
300
        g_string_append_printf (string, "%s=%s ", (gchar *)key, (gchar *)value);
225
301
    g_string_append (string, command);
226
 
    g_debug ("Launching process: %s", string->str);
 
302
    g_debug ("Launching process %d: %s", pid, string->str);
227
303
    g_string_free (string, TRUE);
228
304
 
229
 
    result = g_shell_parse_argv (command, &argc, &argv, error);
230
 
    if (!result)
231
 
        return FALSE;
 
305
    process->priv->pid = pid;
232
306
 
233
 
    process->priv->pid = 0;
234
 
    result = g_spawn_async (working_dir,
235
 
                            argv,
236
 
                            NULL,
237
 
                            G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
238
 
                            child_process_fork_cb, process,
239
 
                            &process->priv->pid,
240
 
                            error);
241
307
    g_strfreev (argv);
242
308
    if (!result)
243
309
        return FALSE;
262
328
        kill (process->priv->pid, signum);
263
329
}
264
330
 
 
331
guint32
 
332
child_process_read_int (ChildProcess *process)
 
333
{
 
334
    guint32 value;
 
335
    g_io_channel_read_chars (process->priv->from_child_channel, (gchar *) &value, sizeof (value), NULL, NULL);
 
336
    return value;
 
337
}
 
338
 
 
339
gchar *
 
340
child_process_read_string (ChildProcess *process)
 
341
{
 
342
    guint32 length;
 
343
    gchar *value;
 
344
 
 
345
    length = child_process_read_int (process);
 
346
    value = g_malloc (sizeof (gchar *) * (length + 1));
 
347
    g_io_channel_read_chars (process->priv->from_child_channel, value, length, NULL, NULL);    
 
348
    value[length] = '\0';
 
349
 
 
350
    return value;
 
351
}
 
352
 
 
353
void
 
354
child_process_write_int (ChildProcess *process, guint32 value)
 
355
{
 
356
    g_io_channel_write_chars (process->priv->to_child_channel, (const gchar *) &value, sizeof (value), NULL, NULL);
 
357
}
 
358
 
 
359
void
 
360
child_process_write_string (ChildProcess *process, const gchar *value)
 
361
{
 
362
    child_process_write_int (process, strlen (value));
 
363
    g_io_channel_write_chars (process->priv->to_child_channel, value, -1, NULL, NULL);  
 
364
}
 
365
 
 
366
void
 
367
child_process_flush (ChildProcess *process)
 
368
{
 
369
    g_io_channel_flush (process->priv->to_child_channel, NULL);
 
370
}
 
371
 
265
372
static void
266
373
child_process_init (ChildProcess *process)
267
374
{
323
430
 
324
431
    g_type_class_add_private (klass, sizeof (ChildProcessPrivate));
325
432
 
 
433
    signals[GOT_DATA] =
 
434
        g_signal_new ("got-data",
 
435
                      G_TYPE_FROM_CLASS (klass),
 
436
                      G_SIGNAL_RUN_LAST,
 
437
                      G_STRUCT_OFFSET (ChildProcessClass, got_data),
 
438
                      NULL, NULL,
 
439
                      g_cclosure_marshal_VOID__VOID,
 
440
                      G_TYPE_NONE, 0); 
326
441
    signals[GOT_SIGNAL] =
327
442
        g_signal_new ("got-signal",
328
443
                      G_TYPE_FROM_CLASS (klass),