File copy/move: make ETA accurate.
[midnight-commander.git] / src / background.c
blob85763daf7a548a61d1951ffee46dfb3d9c8f7769
1 /* {{{ Copyright */
3 /* Background support.
5 Copyright (C) 1996-2024
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() */
46 #include "lib/global.h"
48 #include "lib/unixcompat.h"
49 #include "lib/tty/key.h" /* add_select_channel(), delete_select_channel() */
50 #include "lib/widget.h" /* message() */
51 #include "lib/event-types.h"
52 #include "lib/util.h" /* my_fork() */
54 #include "background.h"
56 /*** global variables ****************************************************************************/
58 #define MAXCALLARGS 4 /* Number of arguments supported */
60 /*** file scope macro definitions ****************************************************************/
62 /*** file scope type declarations ****************************************************************/
64 enum ReturnType
66 Return_String,
67 Return_Integer
70 /*** forward declarations (file scope functions) *************************************************/
72 static int background_attention (int fd, void *closure);
74 /*** file scope variables ************************************************************************/
76 /* File descriptor for talking to our parent */
77 static int parent_fd;
79 /* File descriptor for messages from our parent */
80 static int from_parent_fd;
82 TaskList *task_list = NULL;
84 /* --------------------------------------------------------------------------------------------- */
85 /*** file scope functions ************************************************************************/
86 /* --------------------------------------------------------------------------------------------- */
88 static void
89 register_task_running (file_op_context_t *ctx, pid_t pid, int fd, int to_child, char *info)
91 TaskList *new;
93 new = g_new (TaskList, 1);
94 new->pid = pid;
95 new->info = info;
96 new->state = Task_Running;
97 new->next = task_list;
98 new->fd = fd;
99 new->to_child_fd = to_child;
100 task_list = new;
102 add_select_channel (fd, background_attention, ctx);
105 /* --------------------------------------------------------------------------------------------- */
107 static int
108 destroy_task (pid_t pid)
110 TaskList *p = task_list;
111 TaskList *prev = NULL;
113 while (p != NULL)
115 if (p->pid == pid)
117 int fd = p->fd;
119 if (prev != NULL)
120 prev->next = p->next;
121 else
122 task_list = p->next;
123 g_free (p->info);
124 g_free (p);
125 return fd;
127 prev = p;
128 p = p->next;
131 /* pid not found */
132 return (-1);
135 /* --------------------------------------------------------------------------------------------- */
136 /* {{{ Parent handlers */
138 /* Parent/child protocol
140 * the child (the background) process send the following:
141 * void *routine -- routine to be invoked in the parent
142 * int nargc -- number of arguments
143 * int type -- Return argument type.
145 * If the routine is zero, then it is a way to tell the parent
146 * that the process is dying.
148 * nargc arguments in the following format:
149 * int size of the coming block
150 * size bytes with the block
152 * Now, the parent loads all those and then invokes
153 * the routine with pointers to the information passed
154 * (we just support pointers).
156 * If the return type is integer:
158 * the parent then writes an int to the child with
159 * the return value from the routine and the values
160 * of any global variable that is modified in the parent
161 * currently: do_append and recursive_result.
163 * If the return type is a string:
165 * the parent writes the resulting string length
166 * if the result string was NULL or the empty string,
167 * then the length is zero.
168 * The parent then writes the string length and frees
169 * the result string.
172 * Receive requests from background process and invoke the
173 * specified routine
176 static int
177 reading_failed (int i, char **data)
179 while (i >= 0)
180 g_free (data[i--]);
181 message (D_ERROR, _("Background protocol error"), "%s", _("Reading failed"));
182 return 0;
185 /* --------------------------------------------------------------------------------------------- */
187 static int
188 background_attention (int fd, void *closure)
190 file_op_context_t *ctx;
191 int have_ctx;
192 union
194 int (*have_ctx0) (int);
195 int (*have_ctx1) (int, char *);
196 int (*have_ctx2) (int, char *, char *);
197 int (*have_ctx3) (int, char *, char *, char *);
198 int (*have_ctx4) (int, char *, char *, char *, char *);
200 int (*non_have_ctx0) (file_op_context_t *, int);
201 int (*non_have_ctx1) (file_op_context_t *, int, char *);
202 int (*non_have_ctx2) (file_op_context_t *, int, char *, char *);
203 int (*non_have_ctx3) (file_op_context_t *, int, char *, char *, char *);
204 int (*non_have_ctx4) (file_op_context_t *, int, char *, char *, char *, char *);
206 char *(*ret_str0) (void);
207 char *(*ret_str1) (char *);
208 char *(*ret_str2) (char *, char *);
209 char *(*ret_str3) (char *, char *, char *);
210 char *(*ret_str4) (char *, char *, char *, char *);
212 void *pointer;
213 } routine;
214 /* void *routine; */
215 int argc, i, status;
216 char *data[MAXCALLARGS];
217 ssize_t bytes, ret;
218 TaskList *p;
219 int to_child_fd = -1;
220 enum ReturnType type;
221 const char *background_process_error = _("Background process error");
223 ctx = closure;
225 bytes = read (fd, &routine.pointer, sizeof (routine));
226 if (bytes == -1 || (size_t) bytes < (sizeof (routine)))
228 unregister_task_running (ctx->pid, fd);
230 if (waitpid (ctx->pid, &status, WNOHANG) == 0)
232 /* the process is still running, but it misbehaves - kill it */
233 kill (ctx->pid, SIGTERM);
234 message (D_ERROR, background_process_error, "%s", _("Unknown error in child"));
235 return 0;
238 /* 0 means happy end */
239 if (WIFEXITED (status) && (WEXITSTATUS (status) == 0))
240 return 0;
242 message (D_ERROR, background_process_error, "%s", _("Child died unexpectedly"));
244 return 0;
247 if (read (fd, &argc, sizeof (argc)) != sizeof (argc) ||
248 read (fd, &type, sizeof (type)) != sizeof (type) ||
249 read (fd, &have_ctx, sizeof (have_ctx)) != sizeof (have_ctx))
250 return reading_failed (-1, data);
252 if (argc > MAXCALLARGS)
253 message (D_ERROR, _("Background protocol error"), "%s",
254 _("Background process sent us a request for more arguments\n"
255 "than we can handle."));
257 if (have_ctx != 0 && read (fd, ctx, sizeof (*ctx)) != sizeof (*ctx))
258 return reading_failed (-1, data);
260 for (i = 0; i < argc; i++)
262 int size;
264 if (read (fd, &size, sizeof (size)) != sizeof (size))
265 return reading_failed (i - 1, data);
267 data[i] = g_malloc (size + 1);
269 if (read (fd, data[i], size) != size)
270 return reading_failed (i, data);
272 data[i][size] = '\0'; /* NULL terminate the blocks (they could be strings) */
275 /* Find child task info by descriptor */
276 /* Find before call, because process can destroy self after */
277 for (p = task_list; p != NULL; p = p->next)
278 if (p->fd == fd)
279 break;
281 if (p != NULL)
282 to_child_fd = p->to_child_fd;
284 if (to_child_fd == -1)
285 message (D_ERROR, background_process_error, "%s", _("Unknown error in child"));
286 else if (type == Return_Integer)
288 /* Handle the call */
290 int result = 0;
292 if (have_ctx == 0)
293 switch (argc)
295 case 0:
296 result = routine.have_ctx0 (Background);
297 break;
298 case 1:
299 result = routine.have_ctx1 (Background, data[0]);
300 break;
301 case 2:
302 result = routine.have_ctx2 (Background, data[0], data[1]);
303 break;
304 case 3:
305 result = routine.have_ctx3 (Background, data[0], data[1], data[2]);
306 break;
307 case 4:
308 result = routine.have_ctx4 (Background, data[0], data[1], data[2], data[3]);
309 break;
310 default:
311 break;
313 else
314 switch (argc)
316 case 0:
317 result = routine.non_have_ctx0 (ctx, Background);
318 break;
319 case 1:
320 result = routine.non_have_ctx1 (ctx, Background, data[0]);
321 break;
322 case 2:
323 result = routine.non_have_ctx2 (ctx, Background, data[0], data[1]);
324 break;
325 case 3:
326 result = routine.non_have_ctx3 (ctx, Background, data[0], data[1], data[2]);
327 break;
328 case 4:
329 result =
330 routine.non_have_ctx4 (ctx, Background, data[0], data[1], data[2], data[3]);
331 break;
332 default:
333 break;
336 /* Send the result code and the value for shared variables */
337 ret = write (to_child_fd, &result, sizeof (result));
338 if (have_ctx != 0 && to_child_fd != -1)
339 ret = write (to_child_fd, ctx, sizeof (*ctx));
341 else if (type == Return_String)
343 int len;
344 char *resstr = NULL;
346 /* FIXME: string routines should also use the Foreground/Background
347 * parameter. Currently, this is not used here
349 switch (argc)
351 case 0:
352 resstr = routine.ret_str0 ();
353 break;
354 case 1:
355 resstr = routine.ret_str1 (data[0]);
356 break;
357 case 2:
358 resstr = routine.ret_str2 (data[0], data[1]);
359 break;
360 case 3:
361 resstr = routine.ret_str3 (data[0], data[1], data[2]);
362 break;
363 case 4:
364 resstr = routine.ret_str4 (data[0], data[1], data[2], data[3]);
365 break;
366 default:
367 g_assert_not_reached ();
370 if (resstr != NULL)
372 len = strlen (resstr);
373 ret = write (to_child_fd, &len, sizeof (len));
374 if (len != 0)
375 ret = write (to_child_fd, resstr, len);
376 g_free (resstr);
378 else
380 len = 0;
381 ret = write (to_child_fd, &len, sizeof (len));
385 for (i = 0; i < argc; i++)
386 g_free (data[i]);
388 repaint_screen ();
390 (void) ret;
392 return 0;
395 /* --------------------------------------------------------------------------------------------- */
396 /* }}} */
398 /* {{{ client RPC routines */
400 /* Sends the header for a call to a routine in the parent process. If the file
401 * operation context is not NULL, then it requests that the first parameter of
402 * the call be a file operation context.
405 static void
406 parent_call_header (void *routine, int argc, enum ReturnType type, file_op_context_t *ctx)
408 int have_ctx;
409 ssize_t ret;
411 have_ctx = ctx != NULL ? 1 : 0;
413 ret = write (parent_fd, &routine, sizeof (routine));
414 ret = write (parent_fd, &argc, sizeof (argc));
415 ret = write (parent_fd, &type, sizeof (type));
416 ret = write (parent_fd, &have_ctx, sizeof (have_ctx));
417 if (have_ctx != 0)
418 ret = write (parent_fd, ctx, sizeof (*ctx));
420 (void) ret;
423 /* --------------------------------------------------------------------------------------------- */
425 static int
426 parent_va_call (void *routine, gpointer data, int argc, va_list ap)
428 int i;
429 ssize_t ret;
430 file_op_context_t *ctx = (file_op_context_t *) data;
432 parent_call_header (routine, argc, Return_Integer, ctx);
433 for (i = 0; i < argc; i++)
435 int len;
436 void *value;
438 len = va_arg (ap, int);
439 value = va_arg (ap, void *);
440 ret = write (parent_fd, &len, sizeof (len));
441 ret = write (parent_fd, value, len);
444 ret = read (from_parent_fd, &i, sizeof (i));
445 if (ctx != NULL)
446 ret = read (from_parent_fd, ctx, sizeof (*ctx));
448 (void) ret;
450 return i;
453 /* --------------------------------------------------------------------------------------------- */
455 static char *
456 parent_va_call_string (void *routine, int argc, va_list ap)
458 char *str;
459 int i;
461 parent_call_header (routine, argc, Return_String, NULL);
462 for (i = 0; i < argc; i++)
464 int len;
465 void *value;
467 len = va_arg (ap, int);
468 value = va_arg (ap, void *);
469 if (write (parent_fd, &len, sizeof (len)) != sizeof (len) ||
470 write (parent_fd, value, len) != len)
471 return NULL;
474 if (read (from_parent_fd, &i, sizeof (i)) != sizeof (i) || i == 0)
475 return NULL;
477 str = g_malloc (i + 1);
478 if (read (from_parent_fd, str, i) != i)
480 g_free (str);
481 return NULL;
483 str[i] = '\0';
484 return str;
487 /* --------------------------------------------------------------------------------------------- */
488 /*** public functions ****************************************************************************/
489 /* --------------------------------------------------------------------------------------------- */
491 void
492 unregister_task_running (pid_t pid, int fd)
494 destroy_task (pid);
495 delete_select_channel (fd);
498 /* --------------------------------------------------------------------------------------------- */
500 void
501 unregister_task_with_pid (pid_t pid)
503 int fd;
505 fd = destroy_task (pid);
506 if (fd != -1)
507 delete_select_channel (fd);
510 /* --------------------------------------------------------------------------------------------- */
512 * Try to make the Midnight Commander a background job
514 * Returns:
515 * 1 for parent
516 * 0 for child
517 * -1 on failure
520 do_background (file_op_context_t *ctx, char *info)
522 int comm[2]; /* control connection stream */
523 int back_comm[2]; /* back connection */
524 pid_t pid;
526 if (pipe (comm) == -1)
527 return (-1);
529 if (pipe (back_comm) == -1)
531 (void) close (comm[0]);
532 (void) close (comm[1]);
534 return (-1);
537 pid = my_fork ();
538 if (pid == -1)
540 int saved_errno = errno;
542 (void) close (comm[0]);
543 (void) close (comm[1]);
544 (void) close (back_comm[0]);
545 (void) close (back_comm[1]);
546 errno = saved_errno;
548 return (-1);
551 if (pid == 0)
553 int nullfd;
555 (void) close (comm[0]);
556 parent_fd = comm[1];
558 (void) close (back_comm[1]);
559 from_parent_fd = back_comm[0];
561 mc_global.we_are_background = TRUE;
562 top_dlg = NULL;
564 /* Make stdin/stdout/stderr point somewhere */
565 close (STDIN_FILENO);
566 close (STDOUT_FILENO);
567 close (STDERR_FILENO);
569 nullfd = open ("/dev/null", O_RDWR);
570 if (nullfd != -1)
572 while (dup2 (nullfd, STDIN_FILENO) == -1 && errno == EINTR)
574 while (dup2 (nullfd, STDOUT_FILENO) == -1 && errno == EINTR)
576 while (dup2 (nullfd, STDERR_FILENO) == -1 && errno == EINTR)
578 close (nullfd);
581 return 0;
583 else
585 (void) close (comm[1]);
586 (void) close (back_comm[0]);
587 ctx->pid = pid;
588 register_task_running (ctx, pid, comm[0], back_comm[1], info);
589 return 1;
593 /* --------------------------------------------------------------------------------------------- */
596 parent_call (void *routine, file_op_context_t *ctx, int argc, ...)
598 int ret;
599 va_list ap;
601 va_start (ap, argc);
602 ret = parent_va_call (routine, (gpointer) ctx, argc, ap);
603 va_end (ap);
605 return ret;
608 /* --------------------------------------------------------------------------------------------- */
610 char *
611 parent_call_string (void *routine, int argc, ...)
613 va_list ap;
614 char *str;
616 va_start (ap, argc);
617 str = parent_va_call_string (routine, argc, ap);
618 va_end (ap);
620 return str;
623 /* --------------------------------------------------------------------------------------------- */
625 /* event callback */
626 gboolean
627 background_parent_call (const gchar *event_group_name, const gchar *event_name,
628 gpointer init_data, gpointer data)
630 ev_background_parent_call_t *event_data = (ev_background_parent_call_t *) data;
632 (void) event_group_name;
633 (void) event_name;
634 (void) init_data;
636 event_data->ret.i =
637 parent_va_call (event_data->routine, event_data->ctx, event_data->argc, event_data->ap);
639 return TRUE;
642 /* --------------------------------------------------------------------------------------------- */
644 /* event callback */
645 gboolean
646 background_parent_call_string (const gchar *event_group_name, const gchar *event_name,
647 gpointer init_data, gpointer data)
649 ev_background_parent_call_t *event_data = (ev_background_parent_call_t *) data;
651 (void) event_group_name;
652 (void) event_name;
653 (void) init_data;
655 event_data->ret.s =
656 parent_va_call_string (event_data->routine, event_data->argc, event_data->ap);
658 return TRUE;
661 /* --------------------------------------------------------------------------------------------- */