~elementary-os/elementaryos/os-patch-file-roller-xenial

« back to all changes in this revision

Viewing changes to src/fr-process.c

  • Committer: RabbitBot
  • Date: 2015-12-16 18:53:44 UTC
  • Revision ID: rabbitbot@elementary.io-20151216185344-kgvkd3u6x1abvw3a
Initial import, version 3.16.4-1ubuntu3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 
2
 
 
3
/*
 
4
 *  File-Roller
 
5
 *
 
6
 *  Copyright (C) 2001, 2003, 2008, 2012 Free Software Foundation, Inc.
 
7
 *
 
8
 *  This program is free software; you can redistribute it and/or modify
 
9
 *  it under the terms of the GNU General Public License as published by
 
10
 *  the Free Software Foundation; either version 2 of the License, or
 
11
 *  (at your option) any later version.
 
12
 *
 
13
 *  This program is distributed in the hope that it will be useful,
 
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 *  GNU General Public License for more details.
 
17
 *
 
18
 *  You should have received a copy of the GNU General Public License
 
19
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
 */
 
21
 
 
22
#include <config.h>
 
23
#include <errno.h>
 
24
#include <fcntl.h>
 
25
#include <stdio.h>
 
26
#include <signal.h>
 
27
#include <stdlib.h>
 
28
#include <string.h>
 
29
#include <sys/types.h>
 
30
#include <sys/wait.h>
 
31
#include <unistd.h>
 
32
#include <glib.h>
 
33
#include "file-utils.h"
 
34
#include "fr-process.h"
 
35
#include "glib-utils.h"
 
36
 
 
37
#define REFRESH_RATE 20
 
38
#define BUFFER_SIZE 16384
 
39
 
 
40
 
 
41
/* -- FrCommandInfo --  */
 
42
 
 
43
 
 
44
typedef struct {
 
45
        GList        *args;              /* command to execute */
 
46
        char         *dir;               /* working directory */
 
47
        guint         sticky : 1;        /* whether the command must be
 
48
                                          * executed even if a previous
 
49
                                          * command has failed. */
 
50
        guint         ignore_error : 1;  /* whether to continue to execute
 
51
                                          * other commands if this command
 
52
                                          * fails. */
 
53
        ContinueFunc  continue_func;
 
54
        gpointer      continue_data;
 
55
        ProcFunc      begin_func;
 
56
        gpointer      begin_data;
 
57
        ProcFunc      end_func;
 
58
        gpointer      end_data;
 
59
} FrCommandInfo;
 
60
 
 
61
 
 
62
static FrCommandInfo *
 
63
fr_command_info_new (void)
 
64
{
 
65
        FrCommandInfo *info;
 
66
 
 
67
        info = g_new0 (FrCommandInfo, 1);
 
68
        info->args = NULL;
 
69
        info->dir = NULL;
 
70
        info->sticky = FALSE;
 
71
        info->ignore_error = FALSE;
 
72
 
 
73
        return info;
 
74
}
 
75
 
 
76
 
 
77
static void
 
78
fr_command_info_free (FrCommandInfo *info)
 
79
{
 
80
        if (info == NULL)
 
81
                return;
 
82
 
 
83
        if (info->args != NULL) {
 
84
                g_list_foreach (info->args, (GFunc) g_free, NULL);
 
85
                g_list_free (info->args);
 
86
                info->args = NULL;
 
87
        }
 
88
 
 
89
        if (info->dir != NULL) {
 
90
                g_free (info->dir);
 
91
                info->dir = NULL;
 
92
        }
 
93
 
 
94
        g_free (info);
 
95
}
 
96
 
 
97
 
 
98
/* -- FrChannelData -- */
 
99
 
 
100
 
 
101
static void
 
102
fr_channel_data_init (FrChannelData *channel)
 
103
{
 
104
        channel->source = NULL;
 
105
        channel->raw = NULL;
 
106
        channel->status = G_IO_STATUS_NORMAL;
 
107
        channel->error = NULL;
 
108
}
 
109
 
 
110
 
 
111
static void
 
112
fr_channel_data_close_source (FrChannelData *channel)
 
113
{
 
114
        if (channel->source != NULL) {
 
115
                g_io_channel_shutdown (channel->source, FALSE, NULL);
 
116
                g_io_channel_unref (channel->source);
 
117
                channel->source = NULL;
 
118
        }
 
119
}
 
120
 
 
121
 
 
122
static GIOStatus
 
123
fr_channel_data_read (FrChannelData *channel)
 
124
{
 
125
        char  *line;
 
126
        gsize  length;
 
127
        gsize  terminator_pos;
 
128
 
 
129
        channel->status = G_IO_STATUS_NORMAL;
 
130
        g_clear_error (&channel->error);
 
131
 
 
132
        while ((channel->status = g_io_channel_read_line (channel->source,
 
133
                                                          &line,
 
134
                                                          &length,
 
135
                                                          &terminator_pos,
 
136
                                                          &channel->error)) == G_IO_STATUS_NORMAL)
 
137
        {
 
138
                line[terminator_pos] = 0;
 
139
                channel->raw = g_list_prepend (channel->raw, line);
 
140
                if (channel->line_func != NULL)
 
141
                        (*channel->line_func) (line, channel->line_data);
 
142
        }
 
143
 
 
144
        return channel->status;
 
145
}
 
146
 
 
147
 
 
148
static GIOStatus
 
149
fr_channel_data_flush (FrChannelData *channel)
 
150
{
 
151
        GIOStatus status;
 
152
 
 
153
        while (((status = fr_channel_data_read (channel)) != G_IO_STATUS_ERROR) && (status != G_IO_STATUS_EOF))
 
154
                /* void */;
 
155
        fr_channel_data_close_source (channel);
 
156
 
 
157
        return status;
 
158
}
 
159
 
 
160
 
 
161
static void
 
162
fr_channel_data_reset (FrChannelData *channel)
 
163
{
 
164
        fr_channel_data_close_source (channel);
 
165
 
 
166
        if (channel->raw != NULL) {
 
167
                g_list_foreach (channel->raw, (GFunc) g_free, NULL);
 
168
                g_list_free (channel->raw);
 
169
                channel->raw = NULL;
 
170
        }
 
171
}
 
172
 
 
173
 
 
174
static void
 
175
fr_channel_data_free (FrChannelData *channel)
 
176
{
 
177
        fr_channel_data_reset (channel);
 
178
}
 
179
 
 
180
 
 
181
static void
 
182
fr_channel_data_set_fd (FrChannelData *channel,
 
183
                        int            fd,
 
184
                        const char    *charset)
 
185
{
 
186
        fr_channel_data_reset (channel);
 
187
 
 
188
        channel->source = g_io_channel_unix_new (fd);
 
189
        g_io_channel_set_flags (channel->source, G_IO_FLAG_NONBLOCK, NULL);
 
190
        g_io_channel_set_buffer_size (channel->source, BUFFER_SIZE);
 
191
        if (charset != NULL)
 
192
                g_io_channel_set_encoding (channel->source, charset, NULL);
 
193
}
 
194
 
 
195
 
 
196
/* -- ExecData -- */
 
197
 
 
198
 
 
199
typedef struct {
 
200
        FrProcess          *process;
 
201
        GCancellable       *cancellable;
 
202
        GSimpleAsyncResult *result;
 
203
        gulong              cancel_id;
 
204
        int                 error_command;       /* command that caused an error. */
 
205
        FrError            *error;
 
206
        FrError            *first_error;
 
207
        GList              *first_error_stdout;
 
208
        GList              *first_error_stderr;
 
209
} ExecuteData;
 
210
 
 
211
 
 
212
static void
 
213
execute_data_free (ExecuteData *exec_data)
 
214
{
 
215
        if (exec_data == NULL)
 
216
                return;
 
217
 
 
218
        if (exec_data->cancel_id != 0)
 
219
                g_cancellable_disconnect (exec_data->cancellable, exec_data->cancel_id);
 
220
 
 
221
        _g_object_unref (exec_data->process);
 
222
        _g_object_unref (exec_data->cancellable);
 
223
        _g_object_unref (exec_data->result);
 
224
        fr_error_free (exec_data->error);
 
225
        fr_error_free (exec_data->first_error);
 
226
        _g_string_list_free (exec_data->first_error_stdout);
 
227
        _g_string_list_free (exec_data->first_error_stderr);
 
228
        g_free (exec_data);
 
229
}
 
230
 
 
231
 
 
232
/* -- FrProcess  -- */
 
233
 
 
234
 
 
235
G_DEFINE_TYPE (FrProcess, fr_process, G_TYPE_OBJECT)
 
236
 
 
237
 
 
238
enum {
 
239
        STICKY_ONLY,
 
240
        LAST_SIGNAL
 
241
};
 
242
 
 
243
 
 
244
static guint       fr_process_signals[LAST_SIGNAL] = { 0 };
 
245
static const char *try_charsets[] = { "UTF-8", "ISO-8859-1", "WINDOW-1252" };
 
246
static int         n_charsets = G_N_ELEMENTS (try_charsets);
 
247
 
 
248
 
 
249
struct _FrProcessPrivate {
 
250
        GPtrArray   *comm;                /* FrCommandInfo elements. */
 
251
        gint         n_comm;              /* total number of commands */
 
252
        gint         current_comm;        /* currently editing command. */
 
253
 
 
254
        GPid         command_pid;
 
255
        guint        check_timeout;
 
256
 
 
257
        gboolean     running;
 
258
        gboolean     stopping;
 
259
        gint         current_command;
 
260
 
 
261
        gboolean     use_standard_locale;
 
262
        gboolean     sticky_only;         /* whether to execute only sticky
 
263
                                           * commands. */
 
264
        int          current_charset;
 
265
 
 
266
        ExecuteData *exec_data;
 
267
};
 
268
 
 
269
 
 
270
static void
 
271
fr_process_finalize (GObject *object)
 
272
{
 
273
        FrProcess *process;
 
274
 
 
275
        g_return_if_fail (object != NULL);
 
276
        g_return_if_fail (FR_IS_PROCESS (object));
 
277
 
 
278
        process = FR_PROCESS (object);
 
279
 
 
280
        execute_data_free (process->priv->exec_data);
 
281
        fr_process_clear (process);
 
282
        g_ptr_array_free (process->priv->comm, FALSE);
 
283
        fr_channel_data_free (&process->out);
 
284
        fr_channel_data_free (&process->err);
 
285
 
 
286
        if (G_OBJECT_CLASS (fr_process_parent_class)->finalize)
 
287
                G_OBJECT_CLASS (fr_process_parent_class)->finalize (object);
 
288
}
 
289
 
 
290
 
 
291
static void
 
292
fr_process_class_init (FrProcessClass *klass)
 
293
{
 
294
        GObjectClass *gobject_class;
 
295
 
 
296
        fr_process_parent_class = g_type_class_peek_parent (klass);
 
297
        g_type_class_add_private (klass, sizeof (FrProcessPrivate));
 
298
 
 
299
        fr_process_signals[STICKY_ONLY] =
 
300
                g_signal_new ("sticky_only",
 
301
                              G_TYPE_FROM_CLASS (klass),
 
302
                              G_SIGNAL_RUN_LAST,
 
303
                              G_STRUCT_OFFSET (FrProcessClass, sticky_only),
 
304
                              NULL, NULL,
 
305
                              g_cclosure_marshal_VOID__VOID,
 
306
                              G_TYPE_NONE, 0);
 
307
 
 
308
        gobject_class = G_OBJECT_CLASS (klass);
 
309
        gobject_class->finalize = fr_process_finalize;
 
310
}
 
311
 
 
312
 
 
313
static void
 
314
fr_process_init (FrProcess *process)
 
315
{
 
316
        process->priv = G_TYPE_INSTANCE_GET_PRIVATE (process, FR_TYPE_PROCESS, FrProcessPrivate);
 
317
 
 
318
        process->priv->comm = g_ptr_array_new ();
 
319
        process->priv->n_comm = -1;
 
320
        process->priv->current_comm = -1;
 
321
 
 
322
        process->priv->command_pid = 0;
 
323
        fr_channel_data_init (&process->out);
 
324
        fr_channel_data_init (&process->err);
 
325
 
 
326
        process->priv->check_timeout = 0;
 
327
        process->priv->running = FALSE;
 
328
        process->priv->stopping = FALSE;
 
329
        process->restart = FALSE;
 
330
 
 
331
        process->priv->current_charset = -1;
 
332
        process->priv->use_standard_locale = FALSE;
 
333
        process->priv->exec_data = NULL;
 
334
}
 
335
 
 
336
 
 
337
FrProcess *
 
338
fr_process_new (void)
 
339
{
 
340
        return FR_PROCESS (g_object_new (FR_TYPE_PROCESS, NULL));
 
341
}
 
342
 
 
343
 
 
344
void
 
345
fr_process_clear (FrProcess *process)
 
346
{
 
347
        gint i;
 
348
 
 
349
        g_return_if_fail (process != NULL);
 
350
 
 
351
        for (i = 0; i <= process->priv->n_comm; i++) {
 
352
                FrCommandInfo *info;
 
353
 
 
354
                info = g_ptr_array_index (process->priv->comm, i);
 
355
                fr_command_info_free (info);
 
356
                g_ptr_array_index (process->priv->comm, i) = NULL;
 
357
        }
 
358
 
 
359
        for (i = 0; i <= process->priv->n_comm; i++)
 
360
                g_ptr_array_remove_index_fast (process->priv->comm, 0);
 
361
 
 
362
        process->priv->n_comm = -1;
 
363
        process->priv->current_comm = -1;
 
364
}
 
365
 
 
366
 
 
367
void
 
368
fr_process_begin_command (FrProcess  *process,
 
369
                          const char *arg)
 
370
{
 
371
        FrCommandInfo *info;
 
372
 
 
373
        g_return_if_fail (process != NULL);
 
374
 
 
375
        info = fr_command_info_new ();
 
376
        info->args = g_list_prepend (NULL, g_strdup (arg));
 
377
 
 
378
        g_ptr_array_add (process->priv->comm, info);
 
379
 
 
380
        process->priv->n_comm++;
 
381
        process->priv->current_comm = process->priv->n_comm;
 
382
}
 
383
 
 
384
 
 
385
void
 
386
fr_process_begin_command_at (FrProcess  *process,
 
387
                             const char *arg,
 
388
                             int         index)
 
389
{
 
390
        FrCommandInfo *info, *old_c_info;
 
391
 
 
392
        g_return_if_fail (process != NULL);
 
393
        g_return_if_fail (index >= 0 && index <= process->priv->n_comm);
 
394
 
 
395
        process->priv->current_comm = index;
 
396
 
 
397
        old_c_info = g_ptr_array_index (process->priv->comm, index);
 
398
 
 
399
        if (old_c_info != NULL)
 
400
                fr_command_info_free (old_c_info);
 
401
 
 
402
        info = fr_command_info_new ();
 
403
        info->args = g_list_prepend (NULL, g_strdup (arg));
 
404
 
 
405
        g_ptr_array_index (process->priv->comm, index) = info;
 
406
}
 
407
 
 
408
 
 
409
void
 
410
fr_process_set_working_dir (FrProcess  *process,
 
411
                            const char *dir)
 
412
{
 
413
        FrCommandInfo *info;
 
414
 
 
415
        g_return_if_fail (process != NULL);
 
416
        g_return_if_fail (process->priv->current_comm >= 0);
 
417
 
 
418
        info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
 
419
        if (info->dir != NULL)
 
420
                g_free (info->dir);
 
421
        info->dir = g_strdup (dir);
 
422
}
 
423
 
 
424
 
 
425
void
 
426
fr_process_set_working_dir_file (FrProcess *process,
 
427
                                 GFile     *folder)
 
428
{
 
429
        char *path;
 
430
 
 
431
        path = g_file_get_path (folder);
 
432
        fr_process_set_working_dir (process, path);
 
433
 
 
434
        g_free (path);
 
435
}
 
436
 
 
437
void
 
438
fr_process_set_sticky (FrProcess *process,
 
439
                       gboolean   sticky)
 
440
{
 
441
        FrCommandInfo *info;
 
442
 
 
443
        g_return_if_fail (process != NULL);
 
444
        g_return_if_fail (process->priv->current_comm >= 0);
 
445
 
 
446
        info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
 
447
        info->sticky = sticky;
 
448
}
 
449
 
 
450
 
 
451
void
 
452
fr_process_set_ignore_error (FrProcess *process,
 
453
                             gboolean   ignore_error)
 
454
{
 
455
        FrCommandInfo *info;
 
456
 
 
457
        g_return_if_fail (process != NULL);
 
458
        g_return_if_fail (process->priv->current_comm >= 0);
 
459
 
 
460
        info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
 
461
        info->ignore_error = ignore_error;
 
462
}
 
463
 
 
464
 
 
465
void
 
466
fr_process_add_arg (FrProcess  *process,
 
467
                    const char *arg)
 
468
{
 
469
        FrCommandInfo *info;
 
470
 
 
471
        g_return_if_fail (process != NULL);
 
472
        g_return_if_fail (process->priv->current_comm >= 0);
 
473
 
 
474
        info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
 
475
        info->args = g_list_prepend (info->args, g_strdup (arg));
 
476
}
 
477
 
 
478
 
 
479
void
 
480
fr_process_add_arg_concat (FrProcess  *process,
 
481
                           const char *arg1,
 
482
                           ...)
 
483
{
 
484
        GString *arg;
 
485
        va_list  args;
 
486
        char    *s;
 
487
 
 
488
        arg = g_string_new (arg1);
 
489
 
 
490
        va_start (args, arg1);
 
491
        while ((s = va_arg (args, char*)) != NULL)
 
492
                g_string_append (arg, s);
 
493
        va_end (args);
 
494
 
 
495
        fr_process_add_arg (process, arg->str);
 
496
        g_string_free (arg, TRUE);
 
497
}
 
498
 
 
499
 
 
500
void
 
501
fr_process_add_arg_printf (FrProcess    *fr_proc,
 
502
                           const char   *format,
 
503
                           ...)
 
504
{
 
505
        va_list  args;
 
506
        char    *arg;
 
507
 
 
508
        va_start (args, format);
 
509
        arg = g_strdup_vprintf (format, args);
 
510
        va_end (args);
 
511
 
 
512
        fr_process_add_arg (fr_proc, arg);
 
513
 
 
514
        g_free (arg);
 
515
}
 
516
 
 
517
 
 
518
void
 
519
fr_process_add_arg_file (FrProcess *process,
 
520
                         GFile     *file)
 
521
{
 
522
        char *path;
 
523
 
 
524
        path = g_file_get_path (file);
 
525
        fr_process_add_arg (process, path);
 
526
 
 
527
        g_free (path);
 
528
}
 
529
 
 
530
 
 
531
void
 
532
fr_process_set_arg_at (FrProcess  *process,
 
533
                       int         n_comm,
 
534
                       int         n_arg,
 
535
                       const char *arg_value)
 
536
{
 
537
        FrCommandInfo *info;
 
538
        GList         *arg;
 
539
 
 
540
        g_return_if_fail (process != NULL);
 
541
 
 
542
        info = g_ptr_array_index (process->priv->comm, n_comm);
 
543
        arg = g_list_nth (info->args, n_arg);
 
544
        g_return_if_fail (arg != NULL);
 
545
 
 
546
        g_free (arg->data);
 
547
        arg->data = g_strdup (arg_value);
 
548
}
 
549
 
 
550
 
 
551
void
 
552
fr_process_set_begin_func (FrProcess    *process,
 
553
                           ProcFunc      func,
 
554
                           gpointer      func_data)
 
555
{
 
556
        FrCommandInfo *info;
 
557
 
 
558
        g_return_if_fail (process != NULL);
 
559
 
 
560
        info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
 
561
        info->begin_func = func;
 
562
        info->begin_data = func_data;
 
563
}
 
564
 
 
565
 
 
566
void
 
567
fr_process_set_end_func (FrProcess    *process,
 
568
                         ProcFunc      func,
 
569
                         gpointer      func_data)
 
570
{
 
571
        FrCommandInfo *info;
 
572
 
 
573
        g_return_if_fail (process != NULL);
 
574
 
 
575
        info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
 
576
        info->end_func = func;
 
577
        info->end_data = func_data;
 
578
}
 
579
 
 
580
 
 
581
void
 
582
fr_process_set_continue_func (FrProcess    *process,
 
583
                              ContinueFunc  func,
 
584
                              gpointer      func_data)
 
585
{
 
586
        FrCommandInfo *info;
 
587
 
 
588
        g_return_if_fail (process != NULL);
 
589
 
 
590
        if (process->priv->current_comm < 0)
 
591
                return;
 
592
 
 
593
        info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
 
594
        info->continue_func = func;
 
595
        info->continue_data = func_data;
 
596
}
 
597
 
 
598
 
 
599
void
 
600
fr_process_end_command (FrProcess *process)
 
601
{
 
602
        FrCommandInfo *info;
 
603
 
 
604
        g_return_if_fail (process != NULL);
 
605
 
 
606
        info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
 
607
        info->args = g_list_reverse (info->args);
 
608
}
 
609
 
 
610
 
 
611
void
 
612
fr_process_use_standard_locale (FrProcess *process,
 
613
                                gboolean   use_stand_locale)
 
614
{
 
615
        g_return_if_fail (process != NULL);
 
616
        process->priv->use_standard_locale = use_stand_locale;
 
617
}
 
618
 
 
619
 
 
620
void
 
621
fr_process_set_out_line_func (FrProcess *process,
 
622
                              LineFunc   func,
 
623
                              gpointer   data)
 
624
{
 
625
        g_return_if_fail (process != NULL);
 
626
 
 
627
        process->out.line_func = func;
 
628
        process->out.line_data = data;
 
629
}
 
630
 
 
631
 
 
632
void
 
633
fr_process_set_err_line_func (FrProcess *process,
 
634
                              LineFunc   func,
 
635
                              gpointer   data)
 
636
{
 
637
        g_return_if_fail (process != NULL);
 
638
 
 
639
        process->err.line_func = func;
 
640
        process->err.line_data = data;
 
641
}
 
642
 
 
643
 
 
644
/* fr_process_execute */
 
645
 
 
646
 
 
647
static gboolean
 
648
command_is_sticky (FrProcess *process,
 
649
                   int        i)
 
650
{
 
651
        FrCommandInfo *info;
 
652
 
 
653
        info = g_ptr_array_index (process->priv->comm, i);
 
654
        return info->sticky;
 
655
}
 
656
 
 
657
 
 
658
static void
 
659
allow_sticky_processes_only (ExecuteData *exec_data)
 
660
{
 
661
        FrProcess *process = exec_data->process;
 
662
 
 
663
        if (! process->priv->sticky_only) {
 
664
                /* Remember the first error. */
 
665
 
 
666
                exec_data->error_command = process->priv->current_command;
 
667
                exec_data->first_error = fr_error_copy (exec_data->error);
 
668
                exec_data->first_error_stdout = g_list_reverse (_g_string_list_dup (process->out.raw));
 
669
                exec_data->first_error_stderr = g_list_reverse (_g_string_list_dup (process->err.raw));
 
670
        }
 
671
 
 
672
        process->priv->sticky_only = TRUE;
 
673
 
 
674
        if (! process->priv->stopping)
 
675
                g_signal_emit (G_OBJECT (process),
 
676
                               fr_process_signals[STICKY_ONLY],
 
677
                               0);
 
678
}
 
679
 
 
680
 
 
681
static void
 
682
execute_cancelled_cb (GCancellable *cancellable,
 
683
                      gpointer      user_data)
 
684
{
 
685
        ExecuteData *exec_data = user_data;
 
686
        FrProcess   *process = exec_data->process;
 
687
 
 
688
        if (! process->priv->running)
 
689
                return;
 
690
 
 
691
        if (process->priv->stopping)
 
692
                return;
 
693
 
 
694
        process->priv->stopping = TRUE;
 
695
        exec_data->error = fr_error_new (FR_ERROR_STOPPED, 0, NULL);
 
696
 
 
697
        if (command_is_sticky (process, process->priv->current_command))
 
698
                allow_sticky_processes_only (exec_data);
 
699
 
 
700
        else if (process->priv->command_pid > 0)
 
701
                killpg (process->priv->command_pid, SIGTERM);
 
702
 
 
703
        else {
 
704
                if (process->priv->check_timeout != 0) {
 
705
                        g_source_remove (process->priv->check_timeout);
 
706
                        process->priv->check_timeout = 0;
 
707
                }
 
708
 
 
709
                process->priv->command_pid = 0;
 
710
                fr_channel_data_close_source (&process->out);
 
711
                fr_channel_data_close_source (&process->err);
 
712
 
 
713
                process->priv->running = FALSE;
 
714
 
 
715
                if (exec_data->cancel_id != 0) {
 
716
                        g_signal_handler_disconnect (exec_data->cancellable, exec_data->cancel_id);
 
717
                        exec_data->cancel_id = 0;
 
718
                }
 
719
                g_simple_async_result_complete_in_idle (exec_data->result);
 
720
        }
 
721
}
 
722
 
 
723
 
 
724
static void _fr_process_start (ExecuteData *exec_data);
 
725
 
 
726
 
 
727
static void
 
728
_fr_process_restart (ExecuteData *exec_data)
 
729
{
 
730
        exec_data->process->restart = TRUE;
 
731
        _fr_process_start (exec_data);
 
732
}
 
733
 
 
734
 
 
735
static void  execute_current_command (ExecuteData *exec_data);
 
736
 
 
737
 
 
738
static void
 
739
child_setup (gpointer user_data)
 
740
{
 
741
        FrProcess *process = user_data;
 
742
 
 
743
        if (process->priv->use_standard_locale)
 
744
                putenv ("LC_MESSAGES=C");
 
745
 
 
746
        /* detach from the tty */
 
747
 
 
748
        setsid ();
 
749
 
 
750
        /* create a process group to kill all the child processes when
 
751
         * canceling the operation. */
 
752
 
 
753
        setpgid (0, 0);
 
754
}
 
755
 
 
756
 
 
757
static const char *
 
758
_fr_process_get_charset (FrProcess *process)
 
759
{
 
760
        const char *charset = NULL;
 
761
 
 
762
        if (process->priv->current_charset >= 0)
 
763
                charset = try_charsets[process->priv->current_charset];
 
764
        else if (g_get_charset (&charset))
 
765
                charset = NULL;
 
766
 
 
767
        return charset;
 
768
}
 
769
 
 
770
 
 
771
static void
 
772
_fr_process_execute_complete_in_idle (ExecuteData *exec_data)
 
773
{
 
774
        if (exec_data->cancel_id != 0) {
 
775
                g_cancellable_disconnect (exec_data->cancellable, exec_data->cancel_id);
 
776
                exec_data->cancel_id = 0;
 
777
        }
 
778
        g_simple_async_result_complete_in_idle (exec_data->result);
 
779
}
 
780
 
 
781
 
 
782
static gint
 
783
check_child (gpointer data)
 
784
{
 
785
        ExecuteData   *exec_data = data;
 
786
        FrProcess     *process = exec_data->process;
 
787
        FrCommandInfo *info;
 
788
        pid_t          pid;
 
789
        int            status;
 
790
        gboolean       continue_process;
 
791
 
 
792
        info = g_ptr_array_index (process->priv->comm, process->priv->current_command);
 
793
 
 
794
        /* Remove check. */
 
795
 
 
796
        g_source_remove (process->priv->check_timeout);
 
797
        process->priv->check_timeout = 0;
 
798
 
 
799
        if (fr_channel_data_read (&process->out) == G_IO_STATUS_ERROR) {
 
800
                exec_data->error = fr_error_new (FR_ERROR_IO_CHANNEL, 0, process->out.error);
 
801
        }
 
802
        else if (fr_channel_data_read (&process->err) == G_IO_STATUS_ERROR) {
 
803
                exec_data->error = fr_error_new (FR_ERROR_IO_CHANNEL, 0, process->err.error);
 
804
        }
 
805
        else {
 
806
                pid = waitpid (process->priv->command_pid, &status, WNOHANG);
 
807
                if (pid != process->priv->command_pid) {
 
808
                        /* Add check again. */
 
809
                        process->priv->check_timeout = g_timeout_add (REFRESH_RATE,
 
810
                                                                      check_child,
 
811
                                                                      exec_data);
 
812
                        return FALSE;
 
813
                }
 
814
        }
 
815
 
 
816
        if (info->ignore_error && (exec_data->error != NULL)) {
 
817
#ifdef DEBUG
 
818
                        {
 
819
                                GList *scan;
 
820
 
 
821
                                g_print ("** ERROR **\n");
 
822
                                g_print ("%s\n", exec_data->error->gerror->message);
 
823
                                for (scan = process->err.raw; scan; scan = scan->next)
 
824
                                        g_print ("%s\n", (char *)scan->data);
 
825
                        }
 
826
#endif
 
827
                fr_clear_error (&exec_data->error);
 
828
                debug (DEBUG_INFO, "[error ignored]\n");
 
829
        }
 
830
        else if (exec_data->error == NULL) {
 
831
                if (WIFEXITED (status)) {
 
832
                        if (WEXITSTATUS (status) == 255) {
 
833
                                exec_data->error = fr_error_new (FR_ERROR_COMMAND_NOT_FOUND, 0, NULL);
 
834
                        }
 
835
                        else if (WEXITSTATUS (status) != 0) {
 
836
                                exec_data->error = fr_error_new (FR_ERROR_COMMAND_ERROR, WEXITSTATUS (status), NULL);
 
837
                        }
 
838
                }
 
839
                else {
 
840
                        exec_data->error = fr_error_new (FR_ERROR_EXITED_ABNORMALLY, 255, NULL);
 
841
                }
 
842
        }
 
843
 
 
844
        process->priv->command_pid = 0;
 
845
 
 
846
        if (exec_data->error == NULL) {
 
847
                if (fr_channel_data_flush (&process->out) == G_IO_STATUS_ERROR)
 
848
                        exec_data->error = fr_error_new (FR_ERROR_IO_CHANNEL, 0, process->out.error);
 
849
                else if (fr_channel_data_flush (&process->err) == G_IO_STATUS_ERROR)
 
850
                        exec_data->error = fr_error_new (FR_ERROR_IO_CHANNEL, 0, process->err.error);
 
851
        }
 
852
 
 
853
        if (info->end_func != NULL)
 
854
                (*info->end_func) (info->end_data);
 
855
 
 
856
        /**/
 
857
 
 
858
        if ((exec_data->error != NULL)
 
859
            && (exec_data->error->type == FR_ERROR_IO_CHANNEL)
 
860
            && g_error_matches (exec_data->error->gerror, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
 
861
        {
 
862
                if (process->priv->current_charset < n_charsets - 1) {
 
863
                        /* try with another charset */
 
864
                        process->priv->current_charset++;
 
865
                        _fr_process_restart (exec_data);
 
866
                        return FALSE;
 
867
                }
 
868
                fr_error_free (exec_data->error);
 
869
                exec_data->error = fr_error_new (FR_ERROR_BAD_CHARSET, 0, exec_data->error->gerror);
 
870
        }
 
871
 
 
872
        /* Check whether to continue or stop the process */
 
873
 
 
874
        continue_process = TRUE;
 
875
        if (info->continue_func != NULL)
 
876
                continue_process = (*info->continue_func) (&exec_data->error, info->continue_data);
 
877
 
 
878
        /* Execute the next command. */
 
879
        if (continue_process) {
 
880
                if (exec_data->error != NULL) {
 
881
                        allow_sticky_processes_only (exec_data);
 
882
#ifdef DEBUG
 
883
                        {
 
884
                                GList *scan;
 
885
 
 
886
                                g_print ("** ERROR **\n");
 
887
                                for (scan = process->err.raw; scan; scan = scan->next)
 
888
                                        g_print ("%s\n", (char *)scan->data);
 
889
                        }
 
890
#endif
 
891
                }
 
892
 
 
893
                if (process->priv->sticky_only) {
 
894
                        do {
 
895
                                process->priv->current_command++;
 
896
                        }
 
897
                        while ((process->priv->current_command <= process->priv->n_comm)
 
898
                                && ! command_is_sticky (process, process->priv->current_command));
 
899
                }
 
900
                else
 
901
                        process->priv->current_command++;
 
902
 
 
903
                if (process->priv->current_command <= process->priv->n_comm) {
 
904
                        execute_current_command (exec_data);
 
905
                        return FALSE;
 
906
                }
 
907
        }
 
908
 
 
909
        /* Done */
 
910
 
 
911
        process->priv->current_command = -1;
 
912
        process->priv->use_standard_locale = FALSE;
 
913
 
 
914
        if (process->out.raw != NULL)
 
915
                process->out.raw = g_list_reverse (process->out.raw);
 
916
        if (process->err.raw != NULL)
 
917
                process->err.raw = g_list_reverse (process->err.raw);
 
918
 
 
919
        process->priv->running = FALSE;
 
920
        process->priv->stopping = FALSE;
 
921
 
 
922
        if (process->priv->sticky_only) {
 
923
                /* Restore the first error. */
 
924
 
 
925
                fr_error_free (exec_data->error);
 
926
                exec_data->error = fr_error_copy (exec_data->first_error);
 
927
 
 
928
                /* Restore the first error output as well. */
 
929
 
 
930
                _g_string_list_free (process->out.raw);
 
931
                process->out.raw = exec_data->first_error_stdout;
 
932
                exec_data->first_error_stdout = NULL;
 
933
 
 
934
                _g_string_list_free (process->err.raw);
 
935
                process->err.raw = exec_data->first_error_stderr;
 
936
                exec_data->first_error_stderr = NULL;
 
937
        }
 
938
 
 
939
        _fr_process_execute_complete_in_idle (exec_data);
 
940
 
 
941
        return FALSE;
 
942
}
 
943
 
 
944
 
 
945
static void
 
946
execute_current_command (ExecuteData *exec_data)
 
947
{
 
948
        FrProcess      *process = exec_data->process;
 
949
        FrCommandInfo  *info;
 
950
        GList          *scan;
 
951
        char          **argv;
 
952
        int             out_fd, err_fd;
 
953
        int             i = 0;
 
954
        GError         *error = NULL;
 
955
 
 
956
        debug (DEBUG_INFO, "%d/%d) ", process->priv->current_command, process->priv->n_comm);
 
957
 
 
958
        info = g_ptr_array_index (process->priv->comm, process->priv->current_command);
 
959
 
 
960
        argv = g_new (char *, g_list_length (info->args) + 1);
 
961
        for (scan = info->args; scan; scan = scan->next)
 
962
                argv[i++] = scan->data;
 
963
        argv[i] = NULL;
 
964
 
 
965
#ifdef DEBUG
 
966
        {
 
967
                int j;
 
968
 
 
969
                if (process->priv->use_standard_locale)
 
970
                        g_print ("\tLC_MESSAGES=C\n");
 
971
 
 
972
                if (info->dir != NULL)
 
973
                        g_print ("\tcd %s\n", info->dir);
 
974
 
 
975
                if (info->ignore_error)
 
976
                        g_print ("\t[ignore error]\n");
 
977
 
 
978
                g_print ("\t");
 
979
                for (j = 0; j < i; j++)
 
980
                        g_print ("%s ", argv[j]);
 
981
                g_print ("\n");
 
982
        }
 
983
#endif
 
984
 
 
985
        if (info->begin_func != NULL)
 
986
                (*info->begin_func) (info->begin_data);
 
987
 
 
988
        if (! g_spawn_async_with_pipes (info->dir,
 
989
                                        argv,
 
990
                                        NULL,
 
991
                                        (G_SPAWN_LEAVE_DESCRIPTORS_OPEN
 
992
                                         | G_SPAWN_SEARCH_PATH
 
993
                                         | G_SPAWN_DO_NOT_REAP_CHILD),
 
994
                                        child_setup,
 
995
                                        process,
 
996
                                        &process->priv->command_pid,
 
997
                                        NULL,
 
998
                                        &out_fd,
 
999
                                        &err_fd,
 
1000
                                        &error))
 
1001
        {
 
1002
                exec_data->error = fr_error_new (FR_ERROR_SPAWN, 0, error);
 
1003
                _fr_process_execute_complete_in_idle (exec_data);
 
1004
 
 
1005
                g_error_free (error);
 
1006
                g_free (argv);
 
1007
                return;
 
1008
        }
 
1009
 
 
1010
        g_free (argv);
 
1011
 
 
1012
        fr_channel_data_set_fd (&process->out, out_fd, _fr_process_get_charset (process));
 
1013
        fr_channel_data_set_fd (&process->err, err_fd, _fr_process_get_charset (process));
 
1014
 
 
1015
        process->priv->check_timeout = g_timeout_add (REFRESH_RATE,
 
1016
                                                      check_child,
 
1017
                                                      exec_data);
 
1018
}
 
1019
 
 
1020
 
 
1021
static void
 
1022
_fr_process_start (ExecuteData *exec_data)
 
1023
{
 
1024
        FrProcess *process = exec_data->process;
 
1025
 
 
1026
        _g_string_list_free (exec_data->first_error_stdout);
 
1027
        exec_data->first_error_stdout = NULL;
 
1028
 
 
1029
        _g_string_list_free (exec_data->first_error_stderr);
 
1030
        exec_data->first_error_stderr = NULL;
 
1031
 
 
1032
        fr_error_free (exec_data->error);
 
1033
        exec_data->error = NULL;
 
1034
 
 
1035
        fr_channel_data_reset (&process->out);
 
1036
        fr_channel_data_reset (&process->err);
 
1037
 
 
1038
        process->priv->sticky_only = FALSE;
 
1039
        process->priv->current_command = 0;
 
1040
        process->priv->stopping = FALSE;
 
1041
 
 
1042
        if (process->priv->n_comm == -1) {
 
1043
                process->priv->running = FALSE;
 
1044
                _fr_process_execute_complete_in_idle (exec_data);
 
1045
        }
 
1046
        else {
 
1047
                process->priv->running = TRUE;
 
1048
                execute_current_command (exec_data);
 
1049
        }
 
1050
}
 
1051
 
 
1052
 
 
1053
void
 
1054
fr_process_execute (FrProcess           *process,
 
1055
                    GCancellable        *cancellable,
 
1056
                    GAsyncReadyCallback  callback,
 
1057
                    gpointer             user_data)
 
1058
{
 
1059
        ExecuteData *exec_data;
 
1060
 
 
1061
        g_return_if_fail (! process->priv->running);
 
1062
 
 
1063
        execute_data_free (process->priv->exec_data);
 
1064
 
 
1065
        process->priv->exec_data = exec_data = g_new0 (ExecuteData, 1);
 
1066
        exec_data->process = g_object_ref (process);
 
1067
        exec_data->cancellable = _g_object_ref (cancellable);
 
1068
        exec_data->cancel_id = 0;
 
1069
        exec_data->result = g_simple_async_result_new (G_OBJECT (process),
 
1070
                                                       callback,
 
1071
                                                       user_data,
 
1072
                                                       fr_process_execute);
 
1073
 
 
1074
        g_simple_async_result_set_op_res_gpointer (exec_data->result, exec_data, NULL);
 
1075
 
 
1076
        if (! process->restart)
 
1077
                process->priv->current_charset = -1;
 
1078
 
 
1079
        if (cancellable != NULL) {
 
1080
                GError *error = NULL;
 
1081
 
 
1082
                if (g_cancellable_set_error_if_cancelled (cancellable, &error)) {
 
1083
                        exec_data->error = fr_error_new (FR_ERROR_STOPPED, 0, error);
 
1084
                        _fr_process_execute_complete_in_idle (exec_data);
 
1085
 
 
1086
                        g_error_free (error);
 
1087
                        return;
 
1088
                }
 
1089
 
 
1090
                exec_data->cancel_id = g_cancellable_connect (cancellable,
 
1091
                                                              G_CALLBACK (execute_cancelled_cb),
 
1092
                                                              exec_data,
 
1093
                                                              NULL);
 
1094
        }
 
1095
 
 
1096
        _fr_process_start (exec_data);
 
1097
}
 
1098
 
 
1099
 
 
1100
gboolean
 
1101
fr_process_execute_finish (FrProcess     *process,
 
1102
                           GAsyncResult  *result,
 
1103
                           FrError      **error)
 
1104
{
 
1105
        ExecuteData *exec_data;
 
1106
 
 
1107
        g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (process), fr_process_execute), FALSE);
 
1108
 
 
1109
        exec_data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
 
1110
        if (exec_data->error == NULL)
 
1111
                return TRUE;
 
1112
 
 
1113
        if (error != NULL) {
 
1114
                if (exec_data->error->gerror == NULL)
 
1115
                        exec_data->error->gerror = g_error_new_literal (FR_ERROR, exec_data->error->type, "");
 
1116
                *error = fr_error_copy (exec_data->error);
 
1117
        }
 
1118
 
 
1119
        return FALSE;
 
1120
}
 
1121
 
 
1122
 
 
1123
void
 
1124
fr_process_restart (FrProcess *process)
 
1125
{
 
1126
        if (process->priv->exec_data != NULL)
 
1127
                _fr_process_start (process->priv->exec_data);
 
1128
}
 
1129
 
 
1130
 
 
1131
void
 
1132
fr_process_cancel (FrProcess *process)
 
1133
{
 
1134
        if (! process->priv->running)
 
1135
                return;
 
1136
        if (process->priv->exec_data == NULL)
 
1137
                return;
 
1138
        if (process->priv->exec_data->cancellable == NULL)
 
1139
                return;
 
1140
        g_cancellable_cancel (process->priv->exec_data->cancellable);
 
1141
}