1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
6
* Copyright (C) 2001, 2003, 2008, 2012 Free Software Foundation, Inc.
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.
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.
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/>.
29
#include <sys/types.h>
33
#include "file-utils.h"
34
#include "fr-process.h"
35
#include "glib-utils.h"
37
#define REFRESH_RATE 20
38
#define BUFFER_SIZE 16384
41
/* -- FrCommandInfo -- */
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
53
ContinueFunc continue_func;
54
gpointer continue_data;
62
static FrCommandInfo *
63
fr_command_info_new (void)
67
info = g_new0 (FrCommandInfo, 1);
71
info->ignore_error = FALSE;
78
fr_command_info_free (FrCommandInfo *info)
83
if (info->args != NULL) {
84
g_list_foreach (info->args, (GFunc) g_free, NULL);
85
g_list_free (info->args);
89
if (info->dir != NULL) {
98
/* -- FrChannelData -- */
102
fr_channel_data_init (FrChannelData *channel)
104
channel->source = NULL;
106
channel->status = G_IO_STATUS_NORMAL;
107
channel->error = NULL;
112
fr_channel_data_close_source (FrChannelData *channel)
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;
123
fr_channel_data_read (FrChannelData *channel)
127
gsize terminator_pos;
129
channel->status = G_IO_STATUS_NORMAL;
130
g_clear_error (&channel->error);
132
while ((channel->status = g_io_channel_read_line (channel->source,
136
&channel->error)) == G_IO_STATUS_NORMAL)
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);
144
return channel->status;
149
fr_channel_data_flush (FrChannelData *channel)
153
while (((status = fr_channel_data_read (channel)) != G_IO_STATUS_ERROR) && (status != G_IO_STATUS_EOF))
155
fr_channel_data_close_source (channel);
162
fr_channel_data_reset (FrChannelData *channel)
164
fr_channel_data_close_source (channel);
166
if (channel->raw != NULL) {
167
g_list_foreach (channel->raw, (GFunc) g_free, NULL);
168
g_list_free (channel->raw);
175
fr_channel_data_free (FrChannelData *channel)
177
fr_channel_data_reset (channel);
182
fr_channel_data_set_fd (FrChannelData *channel,
186
fr_channel_data_reset (channel);
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);
192
g_io_channel_set_encoding (channel->source, charset, NULL);
201
GCancellable *cancellable;
202
GSimpleAsyncResult *result;
204
int error_command; /* command that caused an error. */
206
FrError *first_error;
207
GList *first_error_stdout;
208
GList *first_error_stderr;
213
execute_data_free (ExecuteData *exec_data)
215
if (exec_data == NULL)
218
if (exec_data->cancel_id != 0)
219
g_cancellable_disconnect (exec_data->cancellable, exec_data->cancel_id);
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);
232
/* -- FrProcess -- */
235
G_DEFINE_TYPE (FrProcess, fr_process, G_TYPE_OBJECT)
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);
249
struct _FrProcessPrivate {
250
GPtrArray *comm; /* FrCommandInfo elements. */
251
gint n_comm; /* total number of commands */
252
gint current_comm; /* currently editing command. */
259
gint current_command;
261
gboolean use_standard_locale;
262
gboolean sticky_only; /* whether to execute only sticky
266
ExecuteData *exec_data;
271
fr_process_finalize (GObject *object)
275
g_return_if_fail (object != NULL);
276
g_return_if_fail (FR_IS_PROCESS (object));
278
process = FR_PROCESS (object);
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);
286
if (G_OBJECT_CLASS (fr_process_parent_class)->finalize)
287
G_OBJECT_CLASS (fr_process_parent_class)->finalize (object);
292
fr_process_class_init (FrProcessClass *klass)
294
GObjectClass *gobject_class;
296
fr_process_parent_class = g_type_class_peek_parent (klass);
297
g_type_class_add_private (klass, sizeof (FrProcessPrivate));
299
fr_process_signals[STICKY_ONLY] =
300
g_signal_new ("sticky_only",
301
G_TYPE_FROM_CLASS (klass),
303
G_STRUCT_OFFSET (FrProcessClass, sticky_only),
305
g_cclosure_marshal_VOID__VOID,
308
gobject_class = G_OBJECT_CLASS (klass);
309
gobject_class->finalize = fr_process_finalize;
314
fr_process_init (FrProcess *process)
316
process->priv = G_TYPE_INSTANCE_GET_PRIVATE (process, FR_TYPE_PROCESS, FrProcessPrivate);
318
process->priv->comm = g_ptr_array_new ();
319
process->priv->n_comm = -1;
320
process->priv->current_comm = -1;
322
process->priv->command_pid = 0;
323
fr_channel_data_init (&process->out);
324
fr_channel_data_init (&process->err);
326
process->priv->check_timeout = 0;
327
process->priv->running = FALSE;
328
process->priv->stopping = FALSE;
329
process->restart = FALSE;
331
process->priv->current_charset = -1;
332
process->priv->use_standard_locale = FALSE;
333
process->priv->exec_data = NULL;
338
fr_process_new (void)
340
return FR_PROCESS (g_object_new (FR_TYPE_PROCESS, NULL));
345
fr_process_clear (FrProcess *process)
349
g_return_if_fail (process != NULL);
351
for (i = 0; i <= process->priv->n_comm; i++) {
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;
359
for (i = 0; i <= process->priv->n_comm; i++)
360
g_ptr_array_remove_index_fast (process->priv->comm, 0);
362
process->priv->n_comm = -1;
363
process->priv->current_comm = -1;
368
fr_process_begin_command (FrProcess *process,
373
g_return_if_fail (process != NULL);
375
info = fr_command_info_new ();
376
info->args = g_list_prepend (NULL, g_strdup (arg));
378
g_ptr_array_add (process->priv->comm, info);
380
process->priv->n_comm++;
381
process->priv->current_comm = process->priv->n_comm;
386
fr_process_begin_command_at (FrProcess *process,
390
FrCommandInfo *info, *old_c_info;
392
g_return_if_fail (process != NULL);
393
g_return_if_fail (index >= 0 && index <= process->priv->n_comm);
395
process->priv->current_comm = index;
397
old_c_info = g_ptr_array_index (process->priv->comm, index);
399
if (old_c_info != NULL)
400
fr_command_info_free (old_c_info);
402
info = fr_command_info_new ();
403
info->args = g_list_prepend (NULL, g_strdup (arg));
405
g_ptr_array_index (process->priv->comm, index) = info;
410
fr_process_set_working_dir (FrProcess *process,
415
g_return_if_fail (process != NULL);
416
g_return_if_fail (process->priv->current_comm >= 0);
418
info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
419
if (info->dir != NULL)
421
info->dir = g_strdup (dir);
426
fr_process_set_working_dir_file (FrProcess *process,
431
path = g_file_get_path (folder);
432
fr_process_set_working_dir (process, path);
438
fr_process_set_sticky (FrProcess *process,
443
g_return_if_fail (process != NULL);
444
g_return_if_fail (process->priv->current_comm >= 0);
446
info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
447
info->sticky = sticky;
452
fr_process_set_ignore_error (FrProcess *process,
453
gboolean ignore_error)
457
g_return_if_fail (process != NULL);
458
g_return_if_fail (process->priv->current_comm >= 0);
460
info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
461
info->ignore_error = ignore_error;
466
fr_process_add_arg (FrProcess *process,
471
g_return_if_fail (process != NULL);
472
g_return_if_fail (process->priv->current_comm >= 0);
474
info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
475
info->args = g_list_prepend (info->args, g_strdup (arg));
480
fr_process_add_arg_concat (FrProcess *process,
488
arg = g_string_new (arg1);
490
va_start (args, arg1);
491
while ((s = va_arg (args, char*)) != NULL)
492
g_string_append (arg, s);
495
fr_process_add_arg (process, arg->str);
496
g_string_free (arg, TRUE);
501
fr_process_add_arg_printf (FrProcess *fr_proc,
508
va_start (args, format);
509
arg = g_strdup_vprintf (format, args);
512
fr_process_add_arg (fr_proc, arg);
519
fr_process_add_arg_file (FrProcess *process,
524
path = g_file_get_path (file);
525
fr_process_add_arg (process, path);
532
fr_process_set_arg_at (FrProcess *process,
535
const char *arg_value)
540
g_return_if_fail (process != NULL);
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);
547
arg->data = g_strdup (arg_value);
552
fr_process_set_begin_func (FrProcess *process,
558
g_return_if_fail (process != NULL);
560
info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
561
info->begin_func = func;
562
info->begin_data = func_data;
567
fr_process_set_end_func (FrProcess *process,
573
g_return_if_fail (process != NULL);
575
info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
576
info->end_func = func;
577
info->end_data = func_data;
582
fr_process_set_continue_func (FrProcess *process,
588
g_return_if_fail (process != NULL);
590
if (process->priv->current_comm < 0)
593
info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
594
info->continue_func = func;
595
info->continue_data = func_data;
600
fr_process_end_command (FrProcess *process)
604
g_return_if_fail (process != NULL);
606
info = g_ptr_array_index (process->priv->comm, process->priv->current_comm);
607
info->args = g_list_reverse (info->args);
612
fr_process_use_standard_locale (FrProcess *process,
613
gboolean use_stand_locale)
615
g_return_if_fail (process != NULL);
616
process->priv->use_standard_locale = use_stand_locale;
621
fr_process_set_out_line_func (FrProcess *process,
625
g_return_if_fail (process != NULL);
627
process->out.line_func = func;
628
process->out.line_data = data;
633
fr_process_set_err_line_func (FrProcess *process,
637
g_return_if_fail (process != NULL);
639
process->err.line_func = func;
640
process->err.line_data = data;
644
/* fr_process_execute */
648
command_is_sticky (FrProcess *process,
653
info = g_ptr_array_index (process->priv->comm, i);
659
allow_sticky_processes_only (ExecuteData *exec_data)
661
FrProcess *process = exec_data->process;
663
if (! process->priv->sticky_only) {
664
/* Remember the first error. */
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));
672
process->priv->sticky_only = TRUE;
674
if (! process->priv->stopping)
675
g_signal_emit (G_OBJECT (process),
676
fr_process_signals[STICKY_ONLY],
682
execute_cancelled_cb (GCancellable *cancellable,
685
ExecuteData *exec_data = user_data;
686
FrProcess *process = exec_data->process;
688
if (! process->priv->running)
691
if (process->priv->stopping)
694
process->priv->stopping = TRUE;
695
exec_data->error = fr_error_new (FR_ERROR_STOPPED, 0, NULL);
697
if (command_is_sticky (process, process->priv->current_command))
698
allow_sticky_processes_only (exec_data);
700
else if (process->priv->command_pid > 0)
701
killpg (process->priv->command_pid, SIGTERM);
704
if (process->priv->check_timeout != 0) {
705
g_source_remove (process->priv->check_timeout);
706
process->priv->check_timeout = 0;
709
process->priv->command_pid = 0;
710
fr_channel_data_close_source (&process->out);
711
fr_channel_data_close_source (&process->err);
713
process->priv->running = FALSE;
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;
719
g_simple_async_result_complete_in_idle (exec_data->result);
724
static void _fr_process_start (ExecuteData *exec_data);
728
_fr_process_restart (ExecuteData *exec_data)
730
exec_data->process->restart = TRUE;
731
_fr_process_start (exec_data);
735
static void execute_current_command (ExecuteData *exec_data);
739
child_setup (gpointer user_data)
741
FrProcess *process = user_data;
743
if (process->priv->use_standard_locale)
744
putenv ("LC_MESSAGES=C");
746
/* detach from the tty */
750
/* create a process group to kill all the child processes when
751
* canceling the operation. */
758
_fr_process_get_charset (FrProcess *process)
760
const char *charset = NULL;
762
if (process->priv->current_charset >= 0)
763
charset = try_charsets[process->priv->current_charset];
764
else if (g_get_charset (&charset))
772
_fr_process_execute_complete_in_idle (ExecuteData *exec_data)
774
if (exec_data->cancel_id != 0) {
775
g_cancellable_disconnect (exec_data->cancellable, exec_data->cancel_id);
776
exec_data->cancel_id = 0;
778
g_simple_async_result_complete_in_idle (exec_data->result);
783
check_child (gpointer data)
785
ExecuteData *exec_data = data;
786
FrProcess *process = exec_data->process;
790
gboolean continue_process;
792
info = g_ptr_array_index (process->priv->comm, process->priv->current_command);
796
g_source_remove (process->priv->check_timeout);
797
process->priv->check_timeout = 0;
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);
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);
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,
816
if (info->ignore_error && (exec_data->error != NULL)) {
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);
827
fr_clear_error (&exec_data->error);
828
debug (DEBUG_INFO, "[error ignored]\n");
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);
835
else if (WEXITSTATUS (status) != 0) {
836
exec_data->error = fr_error_new (FR_ERROR_COMMAND_ERROR, WEXITSTATUS (status), NULL);
840
exec_data->error = fr_error_new (FR_ERROR_EXITED_ABNORMALLY, 255, NULL);
844
process->priv->command_pid = 0;
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);
853
if (info->end_func != NULL)
854
(*info->end_func) (info->end_data);
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))
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);
868
fr_error_free (exec_data->error);
869
exec_data->error = fr_error_new (FR_ERROR_BAD_CHARSET, 0, exec_data->error->gerror);
872
/* Check whether to continue or stop the process */
874
continue_process = TRUE;
875
if (info->continue_func != NULL)
876
continue_process = (*info->continue_func) (&exec_data->error, info->continue_data);
878
/* Execute the next command. */
879
if (continue_process) {
880
if (exec_data->error != NULL) {
881
allow_sticky_processes_only (exec_data);
886
g_print ("** ERROR **\n");
887
for (scan = process->err.raw; scan; scan = scan->next)
888
g_print ("%s\n", (char *)scan->data);
893
if (process->priv->sticky_only) {
895
process->priv->current_command++;
897
while ((process->priv->current_command <= process->priv->n_comm)
898
&& ! command_is_sticky (process, process->priv->current_command));
901
process->priv->current_command++;
903
if (process->priv->current_command <= process->priv->n_comm) {
904
execute_current_command (exec_data);
911
process->priv->current_command = -1;
912
process->priv->use_standard_locale = FALSE;
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);
919
process->priv->running = FALSE;
920
process->priv->stopping = FALSE;
922
if (process->priv->sticky_only) {
923
/* Restore the first error. */
925
fr_error_free (exec_data->error);
926
exec_data->error = fr_error_copy (exec_data->first_error);
928
/* Restore the first error output as well. */
930
_g_string_list_free (process->out.raw);
931
process->out.raw = exec_data->first_error_stdout;
932
exec_data->first_error_stdout = NULL;
934
_g_string_list_free (process->err.raw);
935
process->err.raw = exec_data->first_error_stderr;
936
exec_data->first_error_stderr = NULL;
939
_fr_process_execute_complete_in_idle (exec_data);
946
execute_current_command (ExecuteData *exec_data)
948
FrProcess *process = exec_data->process;
954
GError *error = NULL;
956
debug (DEBUG_INFO, "%d/%d) ", process->priv->current_command, process->priv->n_comm);
958
info = g_ptr_array_index (process->priv->comm, process->priv->current_command);
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;
969
if (process->priv->use_standard_locale)
970
g_print ("\tLC_MESSAGES=C\n");
972
if (info->dir != NULL)
973
g_print ("\tcd %s\n", info->dir);
975
if (info->ignore_error)
976
g_print ("\t[ignore error]\n");
979
for (j = 0; j < i; j++)
980
g_print ("%s ", argv[j]);
985
if (info->begin_func != NULL)
986
(*info->begin_func) (info->begin_data);
988
if (! g_spawn_async_with_pipes (info->dir,
991
(G_SPAWN_LEAVE_DESCRIPTORS_OPEN
992
| G_SPAWN_SEARCH_PATH
993
| G_SPAWN_DO_NOT_REAP_CHILD),
996
&process->priv->command_pid,
1002
exec_data->error = fr_error_new (FR_ERROR_SPAWN, 0, error);
1003
_fr_process_execute_complete_in_idle (exec_data);
1005
g_error_free (error);
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));
1015
process->priv->check_timeout = g_timeout_add (REFRESH_RATE,
1022
_fr_process_start (ExecuteData *exec_data)
1024
FrProcess *process = exec_data->process;
1026
_g_string_list_free (exec_data->first_error_stdout);
1027
exec_data->first_error_stdout = NULL;
1029
_g_string_list_free (exec_data->first_error_stderr);
1030
exec_data->first_error_stderr = NULL;
1032
fr_error_free (exec_data->error);
1033
exec_data->error = NULL;
1035
fr_channel_data_reset (&process->out);
1036
fr_channel_data_reset (&process->err);
1038
process->priv->sticky_only = FALSE;
1039
process->priv->current_command = 0;
1040
process->priv->stopping = FALSE;
1042
if (process->priv->n_comm == -1) {
1043
process->priv->running = FALSE;
1044
_fr_process_execute_complete_in_idle (exec_data);
1047
process->priv->running = TRUE;
1048
execute_current_command (exec_data);
1054
fr_process_execute (FrProcess *process,
1055
GCancellable *cancellable,
1056
GAsyncReadyCallback callback,
1059
ExecuteData *exec_data;
1061
g_return_if_fail (! process->priv->running);
1063
execute_data_free (process->priv->exec_data);
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),
1072
fr_process_execute);
1074
g_simple_async_result_set_op_res_gpointer (exec_data->result, exec_data, NULL);
1076
if (! process->restart)
1077
process->priv->current_charset = -1;
1079
if (cancellable != NULL) {
1080
GError *error = NULL;
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);
1086
g_error_free (error);
1090
exec_data->cancel_id = g_cancellable_connect (cancellable,
1091
G_CALLBACK (execute_cancelled_cb),
1096
_fr_process_start (exec_data);
1101
fr_process_execute_finish (FrProcess *process,
1102
GAsyncResult *result,
1105
ExecuteData *exec_data;
1107
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (process), fr_process_execute), FALSE);
1109
exec_data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
1110
if (exec_data->error == NULL)
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);
1124
fr_process_restart (FrProcess *process)
1126
if (process->priv->exec_data != NULL)
1127
_fr_process_start (process->priv->exec_data);
1132
fr_process_cancel (FrProcess *process)
1134
if (! process->priv->running)
1136
if (process->priv->exec_data == NULL)
1138
if (process->priv->exec_data->cancellable == NULL)
1140
g_cancellable_cancel (process->priv->exec_data->cancellable);