Merge branch '3416_find_accents'
[midnight-commander.git] / src / background.c
blob563d8a7fbc8b22fcb9d1a468a70f44017e7225e1
1 /* {{{ Copyright */
3 /* Background support.
5 Copyright (C) 1996-2015
6 Free Software Foundation, Inc.
8 Written by:
9 Miguel de Icaza, 1996
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 /* }}} */
29 /** \file background.c
30 * \brief Source: Background support
33 #include <config.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <string.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/wait.h> /* waitpid() */
45 #include <fcntl.h>
47 #include "lib/global.h"
49 #include "lib/unixcompat.h"
50 #include "lib/tty/key.h" /* add_select_channel(), delete_select_channel() */
51 #include "lib/widget.h" /* message() */
52 #include "lib/event-types.h"
54 #include "filemanager/fileopctx.h" /* file_op_context_t */
56 #include "background.h"
58 /*** global variables ****************************************************************************/
60 #define MAXCALLARGS 4 /* Number of arguments supported */
62 /*** file scope macro definitions ****************************************************************/
64 /*** file scope type declarations ****************************************************************/
66 enum ReturnType
68 Return_String,
69 Return_Integer
72 /*** file scope variables ************************************************************************/
74 /* File descriptor for talking to our parent */
75 static int parent_fd;
77 /* File descriptor for messages from our parent */
78 static int from_parent_fd;
80 struct TaskList *task_list = NULL;
82 static int background_attention (int fd, void *closure);
84 /*** file scope functions ************************************************************************/
85 /* --------------------------------------------------------------------------------------------- */
87 static void
88 register_task_running (file_op_context_t * ctx, pid_t pid, int fd, int to_child, char *info)
90 TaskList *new;
92 new = g_new (TaskList, 1);
93 new->pid = pid;
94 new->info = info;
95 new->state = Task_Running;
96 new->next = task_list;
97 new->fd = fd;
98 new->to_child_fd = to_child;
99 task_list = new;
101 add_select_channel (fd, background_attention, ctx);
104 /* --------------------------------------------------------------------------------------------- */
106 static int
107 destroy_task_and_return_fd (pid_t pid)
109 TaskList *p = task_list;
110 TaskList *prev = 0;
112 while (p)
114 if (p->pid == pid)
116 if (prev)
117 prev->next = p->next;
118 else
119 task_list = p->next;
120 g_free (p->info);
121 g_free (p);
122 return p->fd;
124 prev = p;
125 p = p->next;
128 /* pid not found */
129 return -1;
132 /* --------------------------------------------------------------------------------------------- */
133 /* {{{ Parent handlers */
135 /* Parent/child protocol
137 * the child (the background) process send the following:
138 * void *routine -- routine to be invoked in the parent
139 * int nargc -- number of arguments
140 * int type -- Return argument type.
142 * If the routine is zero, then it is a way to tell the parent
143 * that the process is dying.
145 * nargc arguments in the following format:
146 * int size of the coming block
147 * size bytes with the block
149 * Now, the parent loads all those and then invokes
150 * the routine with pointers to the information passed
151 * (we just support pointers).
153 * If the return type is integer:
155 * the parent then writes an int to the child with
156 * the return value from the routine and the values
157 * of any global variable that is modified in the parent
158 * currently: do_append and recursive_result.
160 * If the return type is a string:
162 * the parent writes the resulting string length
163 * if the result string was NULL or the empty string,
164 * then the length is zero.
165 * The parent then writes the string length and frees
166 * the result string.
169 * Receive requests from background process and invoke the
170 * specified routine
173 static int
174 reading_failed (int i, char **data)
176 while (i >= 0)
177 g_free (data[i--]);
178 message (D_ERROR, _("Background protocol error"), "%s", _("Reading failed"));
179 return 0;
182 /* --------------------------------------------------------------------------------------------- */
184 static int
185 background_attention (int fd, void *closure)
187 file_op_context_t *ctx;
188 int have_ctx;
189 union
191 int (*have_ctx0) (int);
192 int (*have_ctx1) (int, char *);
193 int (*have_ctx2) (int, char *, char *);
194 int (*have_ctx3) (int, char *, char *, char *);
195 int (*have_ctx4) (int, char *, char *, char *, char *);
197 int (*non_have_ctx0) (file_op_context_t *, int);
198 int (*non_have_ctx1) (file_op_context_t *, int, char *);
199 int (*non_have_ctx2) (file_op_context_t *, int, char *, char *);
200 int (*non_have_ctx3) (file_op_context_t *, int, char *, char *, char *);
201 int (*non_have_ctx4) (file_op_context_t *, int, char *, char *, char *, char *);
203 char *(*ret_str0) ();
204 char *(*ret_str1) (char *);
205 char *(*ret_str2) (char *, char *);
206 char *(*ret_str3) (char *, char *, char *);
207 char *(*ret_str4) (char *, char *, char *, char *);
209 void *pointer;
210 } routine;
211 /* void *routine; */
212 int argc, i, status;
213 char *data[MAXCALLARGS];
214 ssize_t bytes, ret;
215 struct TaskList *p;
216 int to_child_fd = -1;
217 enum ReturnType type;
219 ctx = closure;
221 bytes = read (fd, &routine.pointer, sizeof (routine));
222 if (bytes == -1 || (size_t) bytes < (sizeof (routine)))
224 const char *background_process_error = _("Background process error");
226 unregister_task_running (ctx->pid, fd);
227 if (!waitpid (ctx->pid, &status, WNOHANG))
229 /* the process is still running, but it misbehaves - kill it */
230 kill (ctx->pid, SIGTERM);
231 message (D_ERROR, background_process_error, _("Unknown error in child"));
232 return 0;
235 /* 0 means happy end */
236 if (WIFEXITED (status) && (WEXITSTATUS (status) == 0))
237 return 0;
239 message (D_ERROR, background_process_error, _("Child died unexpectedly"));
241 return 0;
244 if ((read (fd, &argc, sizeof (argc)) != sizeof (argc)) ||
245 (read (fd, &type, sizeof (type)) != sizeof (type)) ||
246 (read (fd, &have_ctx, sizeof (have_ctx)) != sizeof (have_ctx)))
248 return reading_failed (-1, data);
251 if (argc > MAXCALLARGS)
253 message (D_ERROR, _("Background protocol error"),
254 _("Background process sent us a request for more arguments\n"
255 "than we can handle."));
258 if (have_ctx)
260 if (read (fd, ctx, sizeof (file_op_context_t)) != sizeof (file_op_context_t))
262 return reading_failed (-1, data);
266 for (i = 0; i < argc; i++)
268 int size;
270 if (read (fd, &size, sizeof (size)) != sizeof (size))
272 return reading_failed (i - 1, data);
274 data[i] = g_malloc (size + 1);
275 if (read (fd, data[i], size) != size)
277 return reading_failed (i, data);
279 data[i][size] = 0; /* NULL terminate the blocks (they could be strings) */
282 /* Find child task info by descriptor */
283 /* Find before call, because process can destroy self after */
284 for (p = task_list; p; p = p->next)
286 if (p->fd == fd)
287 break;
290 if (p)
291 to_child_fd = p->to_child_fd;
293 if (to_child_fd == -1)
294 message (D_ERROR, _("Background process error"), _("Unknown error in child"));
296 /* Handle the call */
297 if (type == Return_Integer)
299 int result = 0;
301 if (!have_ctx)
302 switch (argc)
304 case 0:
305 result = routine.have_ctx0 (Background);
306 break;
307 case 1:
308 result = routine.have_ctx1 (Background, data[0]);
309 break;
310 case 2:
311 result = routine.have_ctx2 (Background, data[0], data[1]);
312 break;
313 case 3:
314 result = routine.have_ctx3 (Background, data[0], data[1], data[2]);
315 break;
316 case 4:
317 result = routine.have_ctx4 (Background, data[0], data[1], data[2], data[3]);
318 break;
320 else
321 switch (argc)
323 case 0:
324 result = routine.non_have_ctx0 (ctx, Background);
325 break;
326 case 1:
327 result = routine.non_have_ctx1 (ctx, Background, data[0]);
328 break;
329 case 2:
330 result = routine.non_have_ctx2 (ctx, Background, data[0], data[1]);
331 break;
332 case 3:
333 result = routine.non_have_ctx3 (ctx, Background, data[0], data[1], data[2]);
334 break;
335 case 4:
336 result =
337 routine.non_have_ctx4 (ctx, Background, data[0], data[1], data[2], data[3]);
338 break;
341 /* Send the result code and the value for shared variables */
342 ret = write (to_child_fd, &result, sizeof (int));
343 if (have_ctx && to_child_fd != -1)
344 ret = write (to_child_fd, ctx, sizeof (file_op_context_t));
346 else if (type == Return_String)
348 int len;
349 char *resstr = NULL;
351 /* FIXME: string routines should also use the Foreground/Background
352 * parameter. Currently, this is not used here
354 switch (argc)
356 case 0:
357 resstr = routine.ret_str0 ();
358 break;
359 case 1:
360 resstr = routine.ret_str1 (data[0]);
361 break;
362 case 2:
363 resstr = routine.ret_str2 (data[0], data[1]);
364 break;
365 case 3:
366 resstr = routine.ret_str3 (data[0], data[1], data[2]);
367 break;
368 case 4:
369 resstr = routine.ret_str4 (data[0], data[1], data[2], data[3]);
370 break;
371 default:
372 g_assert_not_reached ();
374 if (resstr)
376 len = strlen (resstr);
377 ret = write (to_child_fd, &len, sizeof (len));
378 if (len != 0)
379 ret = write (to_child_fd, resstr, len);
380 g_free (resstr);
382 else
384 len = 0;
385 ret = write (to_child_fd, &len, sizeof (len));
388 for (i = 0; i < argc; i++)
389 g_free (data[i]);
391 repaint_screen ();
392 (void) ret;
393 return 0;
397 /* --------------------------------------------------------------------------------------------- */
398 /* }}} */
400 /* {{{ client RPC routines */
402 /* Sends the header for a call to a routine in the parent process. If the file
403 * operation context is not NULL, then it requests that the first parameter of
404 * the call be a file operation context.
407 static void
408 parent_call_header (void *routine, int argc, enum ReturnType type, file_op_context_t * ctx)
410 int have_ctx;
411 ssize_t ret;
413 have_ctx = (ctx != NULL);
415 ret = write (parent_fd, &routine, sizeof (routine));
416 ret = write (parent_fd, &argc, sizeof (int));
417 ret = write (parent_fd, &type, sizeof (type));
418 ret = write (parent_fd, &have_ctx, sizeof (have_ctx));
420 if (have_ctx)
421 ret = write (parent_fd, ctx, sizeof (file_op_context_t));
422 (void) ret;
425 /* --------------------------------------------------------------------------------------------- */
427 static int
428 parent_va_call (void *routine, gpointer data, int argc, va_list ap)
430 int i;
431 ssize_t ret;
432 file_op_context_t *ctx = (file_op_context_t *) data;
434 parent_call_header (routine, argc, Return_Integer, ctx);
435 for (i = 0; i < argc; i++)
437 int len;
438 void *value;
440 len = va_arg (ap, int);
441 value = va_arg (ap, void *);
442 ret = write (parent_fd, &len, sizeof (int));
443 ret = write (parent_fd, value, len);
446 ret = read (from_parent_fd, &i, sizeof (int));
447 if (ctx)
448 ret = read (from_parent_fd, ctx, sizeof (file_op_context_t));
450 (void) ret;
451 return i;
454 /* --------------------------------------------------------------------------------------------- */
456 static char *
457 parent_va_call_string (void *routine, int argc, va_list ap)
459 char *str;
460 int i;
462 parent_call_header (routine, argc, Return_String, NULL);
463 for (i = 0; i < argc; i++)
465 int len;
466 void *value;
468 len = va_arg (ap, int);
469 value = va_arg (ap, void *);
470 if ((write (parent_fd, &len, sizeof (int)) != sizeof (int)) ||
471 (write (parent_fd, value, len) != len))
473 return NULL;
477 if (read (from_parent_fd, &i, sizeof (int)) != sizeof (int))
478 return NULL;
479 if (!i)
480 return NULL;
481 str = g_malloc (i + 1);
482 if (read (from_parent_fd, str, i) != i)
484 g_free (str);
485 return NULL;
487 str[i] = 0;
488 return str;
491 /* --------------------------------------------------------------------------------------------- */
492 /*** public functions ****************************************************************************/
493 /* --------------------------------------------------------------------------------------------- */
495 void
496 unregister_task_running (pid_t pid, int fd)
498 destroy_task_and_return_fd (pid);
499 delete_select_channel (fd);
502 /* --------------------------------------------------------------------------------------------- */
504 void
505 unregister_task_with_pid (pid_t pid)
507 int fd = destroy_task_and_return_fd (pid);
508 if (fd != -1)
509 delete_select_channel (fd);
513 /* --------------------------------------------------------------------------------------------- */
515 * Try to make the Midnight Commander a background job
517 * Returns:
518 * 1 for parent
519 * 0 for child
520 * -1 on failure
523 do_background (file_op_context_t * ctx, char *info)
525 int comm[2]; /* control connection stream */
526 int back_comm[2]; /* back connection */
527 pid_t pid;
529 if (pipe (comm) == -1)
530 return -1;
532 if (pipe (back_comm) == -1)
533 return -1;
535 pid = fork ();
536 if (pid == -1)
538 int saved_errno = errno;
540 (void) close (comm[0]);
541 (void) close (comm[1]);
542 (void) close (back_comm[0]);
543 (void) close (back_comm[1]);
544 errno = saved_errno;
545 return -1;
548 if (pid == 0)
550 int nullfd;
552 parent_fd = comm[1];
553 from_parent_fd = back_comm[0];
555 mc_global.we_are_background = TRUE;
556 top_dlg = NULL;
558 /* Make stdin/stdout/stderr point somewhere */
559 close (STDIN_FILENO);
560 close (STDOUT_FILENO);
561 close (STDERR_FILENO);
563 nullfd = open ("/dev/null", O_RDWR);
564 if (nullfd != -1)
566 while (dup2 (nullfd, STDIN_FILENO) == -1 && errno == EINTR)
568 while (dup2 (nullfd, STDOUT_FILENO) == -1 && errno == EINTR)
570 while (dup2 (nullfd, STDERR_FILENO) == -1 && errno == EINTR)
574 return 0;
576 else
578 ctx->pid = pid;
579 register_task_running (ctx, pid, comm[0], back_comm[1], info);
580 return 1;
584 /* --------------------------------------------------------------------------------------------- */
587 parent_call (void *routine, file_op_context_t * ctx, int argc, ...)
589 int ret;
590 va_list ap;
592 va_start (ap, argc);
593 ret = parent_va_call (routine, (gpointer) ctx, argc, ap);
594 va_end (ap);
596 return ret;
599 /* --------------------------------------------------------------------------------------------- */
601 char *
602 parent_call_string (void *routine, int argc, ...)
604 va_list ap;
605 char *str;
607 va_start (ap, argc);
608 str = parent_va_call_string (routine, argc, ap);
609 va_end (ap);
611 return str;
614 /* --------------------------------------------------------------------------------------------- */
616 /* event callback */
617 gboolean
618 background_parent_call (const gchar * event_group_name, const gchar * event_name,
619 gpointer init_data, gpointer data)
621 ev_background_parent_call_t *event_data = (ev_background_parent_call_t *) data;
623 (void) event_group_name;
624 (void) event_name;
625 (void) init_data;
627 event_data->ret.i =
628 parent_va_call (event_data->routine, event_data->ctx, event_data->argc, event_data->ap);
630 return TRUE;
633 /* --------------------------------------------------------------------------------------------- */
635 /* event callback */
636 gboolean
637 background_parent_call_string (const gchar * event_group_name, const gchar * event_name,
638 gpointer init_data, gpointer data)
640 ev_background_parent_call_t *event_data = (ev_background_parent_call_t *) data;
642 (void) event_group_name;
643 (void) event_name;
644 (void) init_data;
646 event_data->ret.s =
647 parent_va_call_string (event_data->routine, event_data->argc, event_data->ap);
649 return TRUE;
652 /* --------------------------------------------------------------------------------------------- */