4 Copyright (C) 1996 The Free Software Foundation
6 Written by: 1996 Miguel de Icaza
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, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
26 #include <sys/types.h>
42 * We currenlty only support one way of comunicating the background
43 * and foreground process by using the socketpair system call
45 #ifdef WITH_BACKGROUND
46 # include <sys/socket.h>
49 #include "fileopctx.h"
50 #include "key.h" /* For add_select_channel(), delete_select_channel() */
55 /* If true, this is a background process */
56 int we_are_background
= 0;
58 #ifdef WITH_BACKGROUND
59 /* If set background tasks wait to be attached */
60 int background_wait
= 0;
62 #ifndef HAVE_SOCKETPAIR
63 int socketpair(int, int, int, int fd
[2]);
66 /* File descriptor for talking to our parent */
69 #define MAXCALLARGS 4 /* Number of arguments supported */
70 #define mymsg "Desde el hijo\n\r"
72 struct TaskList
*task_list
= NULL
;
74 static int background_attention (int fd
, void *closure
);
77 register_task_running (FileOpContext
*ctx
, pid_t pid
, int fd
, char *info
)
81 new = g_new (TaskList
, 1);
84 new->state
= Task_Running
;
85 new->next
= task_list
;
89 add_select_channel (fd
, background_attention
, ctx
);
93 unregister_task_running (pid_t pid
, int fd
)
95 TaskList
*p
= task_list
;
101 prev
->next
= p
->next
;
111 delete_select_channel (fd
);
115 * Try to make the Midnight Commander a background job
123 do_background (FileOpContext
*ctx
, char *info
)
125 int comm
[2]; /* control connection stream */
128 if (socketpair (AF_UNIX
, SOCK_STREAM
, 0, comm
) == -1)
131 if ((pid
= fork ()) == -1)
137 parent_fd
= comm
[1];
138 we_are_background
= 1;
140 /* Make stdin/stdout/stderr point somewhere */
145 if ((nullfd
= open ("/dev/null", O_RDONLY
)) != -1){
146 while (dup2 (nullfd
, 0) == -1 && errno
== EINTR
)
148 while (dup2 (nullfd
, 1) == -1 && errno
== EINTR
)
150 while (dup2 (nullfd
, 2) == -1 && errno
== EINTR
)
154 /* To make it obvious if it fails, there is a bug report on this */
155 write (2, mymsg
, sizeof (mymsg
));
156 write (1, mymsg
, sizeof (mymsg
));
158 /* Just for debugging the background back end */
159 if (background_wait
){
169 register_task_running (ctx
, pid
, comm
[0], info
);
175 background_title (char *str
)
177 return g_strconcat (_("Background process:"), str
, NULL
);
180 /* {{{ Routines that do the real job */
182 real_message_1s (enum OperationMode mode
, int *flags
, char *title
, const char *str1
)
184 if (mode
== Background
)
185 title
= background_title (title
);
187 message (*flags
, title
, "%s", str1
);
189 if (mode
== Background
)
194 real_message_2s (enum OperationMode mode
, int *flags
, char *title
,
195 const char *str1
, const char *str2
)
197 if (mode
== Background
)
198 title
= background_title (title
);
200 message (*flags
, title
, str1
, str2
);
202 if (mode
== Background
)
207 real_message_3s (enum OperationMode mode
, int *flags
, char *title
,
208 const char *str1
, const char *str2
, const char *str3
)
210 if (mode
== Background
)
211 title
= background_title (title
);
213 message (*flags
, title
, str1
, str2
, str3
);
215 if (mode
== Background
)
220 /* {{{ Parent handlers */
222 /* Parent/child protocol
224 * the child (the background) process send the following:
225 * void *routine -- routine to be invoked in the parent
226 * int nargc -- number of arguments
227 * int type -- Return argument type.
229 * If the routine is zero, then it is a way to tell the parent
230 * that the process is dying.
232 * nargc arguments in the following format:
233 * int size of the coming block
234 * size bytes with the block
236 * Now, the parent loads all those and then invokes
237 * the routine with pointers to the information passed
238 * (we just support pointers).
240 * If the return type is integer:
242 * the parent then writes an int to the child with
243 * the return value from the routine and the values
244 * of any global variable that is modified in the parent
245 * currently: do_append and recursive_result.
247 * If the return type is a string:
249 * the parent writes the resulting string lenght
250 * if the result string was NULL or the empty string,
251 * then the lenght is zero.
252 * The parent then writes the string lenght and frees
256 * Receive requests from background process and invoke the
261 background_attention (int fd
, void *closure
)
266 int argc
, i
, result
, status
;
267 char *data
[MAXCALLARGS
];
269 enum ReturnType type
;
273 bytes
= read (fd
, &routine
, sizeof (routine
));
274 if (bytes
< (sizeof (routine
))){
275 char *background_process_error
= _(" Background process error ");
278 message (1, background_process_error
, _(" Child died unexpectedly "));
280 message (1, background_process_error
, _(" Unknown error in child "));
281 unregister_task_running (ctx
->pid
, fd
);
282 waitpid (ctx
->pid
, &status
, 0);
286 /* If the routine is zero, then the child is telling us that he is dying */
287 if ((long) routine
== MSG_CHILD_EXITING
){
288 unregister_task_running (ctx
->pid
, fd
);
289 waitpid (ctx
->pid
, &status
, 0);
293 read (fd
, &argc
, sizeof (argc
));
294 if (argc
> MAXCALLARGS
){
295 message (1, _(" Background protocol error "),
296 _(" Background process sent us a request for more arguments \n"
297 " than we can handle. \n"));
299 read (fd
, &type
, sizeof (type
));
300 read (fd
, &have_ctx
, sizeof (have_ctx
));
302 read (fd
, ctx
, sizeof (FileOpContext
));
304 for (i
= 0; i
< argc
; i
++){
307 read (fd
, &size
, sizeof (size
));
308 data
[i
] = g_malloc (size
+1);
309 read (fd
, data
[i
], size
);
311 data
[i
][size
] = 0; /* NULL terminate the blocks (they could be strings) */
314 /* Handle the call */
315 if (type
== Return_Integer
){
319 result
= (*(int (*)(int, char *))routine
)(Background
, data
[0]);
322 result
= (*(int (*)(int, char *, char *))routine
)
323 (Background
, data
[0], data
[1]);
326 result
= (*(int (*)(int, char *, char *, char *))routine
)
327 (Background
, data
[0], data
[1], data
[2]);
330 result
= (*(int (*)(int, char *, char *, char *, char *))routine
)
331 (Background
, data
[0], data
[1], data
[2], data
[3]);
337 result
= (*(int (*)(FileOpContext
*, int, char *))routine
)
338 (ctx
, Background
, data
[0]);
341 result
= (*(int (*)(FileOpContext
*, int, char *, char *))routine
)
342 (ctx
, Background
, data
[0], data
[1]);
345 result
= (*(int (*)(FileOpContext
*, int, char *, char *, char *))routine
)
346 (ctx
, Background
, data
[0], data
[1], data
[2]);
349 result
= (*(int (*)(FileOpContext
*, int, char *, char *, char *, char *))routine
)
350 (ctx
, Background
, data
[0], data
[1], data
[2], data
[3]);
354 /* Send the result code and the value for shared variables */
355 write (fd
, &result
, sizeof (int));
357 write (fd
, ctx
, sizeof (FileOpContext
));
358 } else if (type
== Return_String
) {
362 /* FIXME: string routines should also use the Foreground/Background
363 * parameter. Currently, this is not used here
367 resstr
= (*(char * (*)(char *))routine
)(data
[0]);
370 resstr
= (*(char * (*)(char *, char *))routine
)
371 (data
[0], data
[1]);
374 resstr
= (*(char * (*)(char *, char *, char *))routine
)
375 (data
[0], data
[1], data
[2]);
378 resstr
= (*(char * (*)(char *, char *, char *, char *))routine
)
379 (data
[0], data
[1], data
[2], data
[3]);
381 default: g_assert_not_reached();
384 len
= strlen (resstr
);
385 write (fd
, &len
, sizeof (len
));
387 write (fd
, resstr
, len
);
392 write (fd
, &len
, sizeof (len
));
395 for (i
= 0; i
< argc
; i
++)
407 /* {{{ client RPC routines */
409 /* Sends the header for a call to a routine in the parent process. If the file
410 * operation context is not NULL, then it requests that the first parameter of
411 * the call be a file operation context.
414 parent_call_header (void *routine
, int argc
, enum ReturnType type
, FileOpContext
*ctx
)
418 have_ctx
= (ctx
!= NULL
);
420 write (parent_fd
, &routine
, sizeof (routine
));
421 write (parent_fd
, &argc
, sizeof (int));
422 write (parent_fd
, &type
, sizeof (type
));
423 write (parent_fd
, &have_ctx
, sizeof (have_ctx
));
426 write (parent_fd
, ctx
, sizeof (FileOpContext
));
430 parent_call (void *routine
, FileOpContext
*ctx
, int argc
, ...)
436 parent_call_header (routine
, argc
, Return_Integer
, ctx
);
437 for (i
= 0; i
< argc
; i
++) {
441 len
= va_arg (ap
, int);
442 value
= va_arg (ap
, void *);
443 write (parent_fd
, &len
, sizeof (int));
444 write (parent_fd
, value
, len
);
446 read (parent_fd
, &i
, sizeof (int));
448 read (parent_fd
, ctx
, sizeof (FileOpContext
));
454 parent_call_string (void *routine
, int argc
, ...)
461 parent_call_header (routine
, argc
, Return_String
, NULL
);
462 for (i
= 0; i
< argc
; i
++){
466 len
= va_arg (ap
, int);
467 value
= va_arg (ap
, void *);
468 write (parent_fd
, &len
, sizeof (int));
469 write (parent_fd
, value
, len
);
471 read (parent_fd
, &i
, sizeof (int));
474 str
= g_malloc (i
+ 1);
475 read (parent_fd
, str
, i
);
481 tell_parent (int msg
)
483 write (parent_fd
, &msg
, sizeof (int));
487 message_1s (int flags
, char *title
, const char *str1
)
489 if (we_are_background
)
490 parent_call ((void *)real_message_1s
, NULL
, 3, sizeof (flags
), &flags
,
491 strlen (title
), title
, strlen (str1
), str1
);
493 real_message_1s (Foreground
, &flags
, title
, str1
);
497 message_2s (int flags
, char *title
, const char *str1
, const char *str2
)
499 if (we_are_background
)
500 parent_call ((void *)real_message_2s
, NULL
, 4, sizeof (flags
), &flags
,
501 strlen (title
), title
, strlen (str1
), str1
,
502 strlen (str2
), str2
);
504 real_message_2s (Foreground
, &flags
, title
, str1
, str2
);
508 message_3s (int flags
, char *title
, const char *str1
,
509 const char *str2
, const char *str3
)
511 if (we_are_background
)
512 parent_call ((void *)real_message_3s
, NULL
, 3, sizeof (flags
), &flags
,
513 strlen (title
), title
, strlen (str1
), str1
,
514 strlen (str2
), str2
, strlen (str3
), str3
);
516 real_message_3s (Foreground
, &flags
, title
, str1
, str2
, str3
);
520 input_dialog_help (char *header
, char *text
, char *help
, char *def_text
)
522 if (we_are_background
)
523 return parent_call_string ((void *)real_input_dialog_help
, 4,
524 strlen (header
), header
,
527 strlen (def_text
), def_text
);
529 return real_input_dialog_help (header
, text
, help
, def_text
);
532 #else /* Else => No background code support */
534 /* {{{ Stubs if background code is not supported */
536 message_1s (int flags
, char *title
, const char *str1
)
538 message (flags
, title
, "%s", str1
);
542 message_2s (int flags
, char *title
, const char *str1
, const char *str2
)
544 message (flags
, title
, str1
, str2
);
548 message_3s (int flags
, char *title
, const char *str1
,
549 const char *str2
, const char *str3
)
551 message (flags
, title
, str1
, str2
, str3
);
555 input_dialog_help (char *header
, char *text
, char *help
, char *def_text
)
557 return real_input_dialog_help (header
, text
, help
, def_text
);
561 #endif /* !WITH_BACKGROUND */
563 /* {{{ Functions shared between background and foreground */
566 message_1s1d (int flags
, char *title
, const char *str
, int d
)
568 char *p
= g_strdup_printf (str
, d
);
569 message_1s (flags
, title
, p
);