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., 675 Mass Ave, Cambridge, MA 02139, USA. */
26 #include <sys/types.h>
27 #ifdef HAVE_SYS_WAIT_H
28 # include <sys/wait.h>
35 #include <sys/param.h>
45 * We currenlty only support one way of comunicating the background
46 * and foreground process by using the socketpair system call
49 # include <sys/socket.h>
55 #include "background.h"
57 #include "key.h" /* For add_select_channel(), delete_select_channel() */
59 /* If true, this is a background process */
60 int we_are_background
= 0;
64 extern int recursive_result
;
66 #ifdef WITH_BACKGROUND
67 /* If set background tasks wait to be attached */
68 int background_wait
= 0;
70 #ifndef HAVE_SOCKETPAIR
71 int socketpair(int, int, int, int fd
[2]);
74 /* File descriptor for talking to our parent */
77 #define MAXCALLARGS 4 /* Number of arguments supported */
78 #define mymsg "Desde el hijo\n\r"
80 struct TaskList
*task_list
= NULL
;
83 register_task_running (pid_t pid
, int fd
, char *info
)
87 new = xmalloc (sizeof (TaskList
), "note_task_running");
90 new->state
= Task_Running
;
91 new->next
= task_list
;
95 add_select_channel (fd
, background_attention
, (void *) pid
);
99 unregister_task_running (pid_t pid
, int fd
)
101 TaskList
*p
= task_list
;
107 prev
->next
= p
->next
;
117 delete_select_channel (fd
);
121 * Try to make the Midnight Commander a background job
129 do_background (char *info
)
131 int comm
[2]; /* control connection stream */
134 if (socketpair (AF_UNIX
, SOCK_STREAM
, 0, comm
) == -1)
137 if ((pid
= fork ()) == -1)
143 parent_fd
= comm
[1];
144 we_are_background
= 1;
146 /* Make stdin/stdout/stderr point somewhere */
151 if ((nullfd
= open ("/dev/null", O_RDONLY
)) != -1){
157 /* To make it obvious if it fails, there is a bug report on this */
158 write (2, mymsg
, sizeof (mymsg
));
159 write (1, mymsg
, sizeof (mymsg
));
161 /* Just for debugging the background back end */
162 if (background_wait
){
171 register_task_running (pid
, comm
[0], info
);
177 background_title (char *str
)
179 char *result
= copy_strings (_("Background process:"), str
, NULL
);
184 /* {{{ Routines that do the real job */
186 real_message_1s (enum OperationMode mode
, int *flags
, char *title
, char *str1
)
190 if (mode
== Background
)
191 full_title
= background_title (title
);
195 message (*flags
, title
, str1
);
197 if (title
!= full_title
)
202 real_message_2s (enum OperationMode mode
, int *flags
, char *title
, char *str1
, char *str2
)
206 if (mode
== Background
)
207 full_title
= background_title (title
);
211 message (*flags
, title
, str1
, str2
);
213 if (title
!= full_title
)
218 real_message_3s (enum OperationMode mode
, int *flags
, char *title
, char *str1
, char *str2
, const char *str3
)
222 if (mode
== Background
)
223 full_title
= background_title (title
);
227 message (*flags
, title
, str1
, str2
, str3
);
229 if (title
!= full_title
)
234 /* {{{ Parent handlers */
236 /* Parent/child protocol
238 * the child (the background) process send the following:
239 * void *routine -- routine to be invoked in the parent
240 * int nargc -- number of arguments
241 * int type -- Return argument type.
243 * If the routine is zero, then it is a way to tell the parent
244 * that the process is dying.
246 * nargc arguments in the following format:
247 * int size of the coming block
248 * size bytes with the block
250 * Now, the parent loads all those and then invokes
251 * the routine with pointers to the information passed
252 * (we just support pointers).
254 * If the return type is integer:
256 * the parent then writes an int to the child with
257 * the return value from the routine and the values
258 * of any global variable that is modified in the parent
259 * currently: do_append and recursive_result.
261 * If the return type is a string:
263 * the parent writes the resulting string lenght
264 * if the result string was NULL or the empty string,
265 * then the lenght is zero.
266 * The parent then writes the string lenght and frees
270 * Receive requests from background process and invoke the
275 background_attention (int fd
, void *xpid
)
278 int argc
, i
, result
, status
;
279 char *data
[MAXCALLARGS
];
281 pid_t pid
= (pid_t
) xpid
;
283 enum ReturnType type
;
284 char *background_process_error
= _(" Background process error ");
286 bytes
= read (fd
, &routine
, sizeof (routine
));
287 if (bytes
< (sizeof (routine
))){
289 message (1, background_process_error
, _(" Child died unexpectedly "));
291 message (1, background_process_error
, _(" Unknown error in child "));
292 unregister_task_running (pid
, fd
);
293 waitpid (pid
, &status
, 0);
297 /* If the routine is zero, then the child is telling us that he is dying */
298 if ((int) routine
== MSG_CHILD_EXITING
){
299 unregister_task_running (pid
, fd
);
300 waitpid (pid
, &status
, 0);
304 read (fd
, &argc
, sizeof (argc
));
305 if (argc
> MAXCALLARGS
){
306 message (1, _(" Background protocol error "),
307 _(" Background process sent us a request for more arguments \n"
308 " than we can handle. \n"));
310 read (fd
, &type
, sizeof (type
));
312 for (i
= 0; i
< argc
; i
++){
315 read (fd
, &size
, sizeof (size
));
316 data
[i
] = xmalloc (size
+1, "RPC Arguments");
317 read (fd
, data
[i
], size
);
319 data
[i
][size
] = 0; /* NULL terminate the blocks (they could be strings) */
322 /* Handle the call */
323 if (type
== Return_Integer
){
326 result
= (*(int (*)(int, char *))routine
)(Background
, data
[0]);
329 result
= (*(int (*)(int, char *, char *))routine
)
330 (Background
, data
[0], data
[1]);
333 result
= (*(int (*)(int, char *, char *, char *))routine
)
334 (Background
, data
[0], data
[1], data
[2]);
337 result
= (*(int (*)(int, char *, char *, char *, char *))routine
)
338 (Background
, data
[0], data
[1], data
[2], data
[3]);
342 /* Send the result code and the value for shared variables */
343 write (fd
, &result
, sizeof (int));
344 write (fd
, &do_append
, sizeof (do_append
));
345 write (fd
, &recursive_result
, sizeof (recursive_result
));
347 } else if (type
== Return_String
) {
350 /* FIXME: string routines should also use the Foreground/Background
351 * parameter. Currently, this is not used here
355 resstr
= (*(char * (*)(char *))routine
)(data
[0]);
358 resstr
= (*(char * (*)(char *, char *))routine
)
359 (data
[0], data
[1]);
362 resstr
= (*(char * (*)(char *, char *, char *))routine
)
363 (data
[0], data
[1], data
[2]);
366 resstr
= (*(char * (*)(char *, char *, char *, char *))routine
)
367 (data
[0], data
[1], data
[2], data
[3]);
371 len
= strlen (resstr
);
372 write (fd
, &len
, sizeof (len
));
374 write (fd
, resstr
, len
);
379 write (fd
, &len
, sizeof (len
));
382 for (i
= 0; i
< argc
; i
++)
396 /* {{{ client RPC routines */
398 parent_call_header (void *routine
, int argc
, enum ReturnType type
)
400 write (parent_fd
, &routine
, sizeof (routine
));
401 write (parent_fd
, &argc
, sizeof (int));
402 write (parent_fd
, &type
, sizeof (type
));
406 parent_call (void *routine
, int argc
, ...)
412 parent_call_header (routine
, argc
, Return_Integer
);
413 for (i
= 0; i
< argc
; i
++){
417 len
= va_arg (ap
, int);
418 value
= va_arg (ap
, void *);
419 write (parent_fd
, &len
, sizeof (int));
420 write (parent_fd
, value
, len
);
422 /* Besides the regular result, get the value for
423 * variables that may be modified in the parent that affect our behaviour
425 read (parent_fd
, &i
, sizeof (int));
426 read (parent_fd
, &do_append
, sizeof (do_append
));
427 read (parent_fd
, &recursive_result
, sizeof (recursive_result
));
432 parent_call_string (void *routine
, int argc
, ...)
439 parent_call_header (routine
, argc
, Return_String
);
440 for (i
= 0; i
< argc
; i
++){
444 len
= va_arg (ap
, int);
445 value
= va_arg (ap
, void *);
446 write (parent_fd
, &len
, sizeof (int));
447 write (parent_fd
, value
, len
);
449 read (parent_fd
, &i
, sizeof (int));
452 str
= xmalloc (i
+ 1, "parent_return");
453 read (parent_fd
, str
, i
);
459 tell_parent (int msg
)
461 write (parent_fd
, &msg
, sizeof (int));
465 call_1s (int (*routine
)(enum OperationMode
, char *), char *str
)
467 if (we_are_background
)
468 return parent_call ((void *)routine
, 1, strlen (str
), str
);
470 return (*routine
)(Foreground
, str
);
474 message_1s (int flags
, char *title
, char *str1
)
476 if (we_are_background
)
477 parent_call ((void *)real_message_1s
, 3, sizeof (flags
), &flags
,
478 strlen (title
), title
, strlen (str1
), str1
);
480 real_message_1s (Foreground
, &flags
, title
, str1
);
484 message_2s (int flags
, char *title
, char *str1
, char *str2
)
486 if (we_are_background
)
487 parent_call ((void *)real_message_2s
, 4, sizeof (flags
), &flags
,
488 strlen (title
), title
, strlen (str1
), str1
,
489 strlen (str2
), str2
);
491 real_message_2s (Foreground
, &flags
, title
, str1
, str2
);
495 message_3s (int flags
, char *title
, char *str1
, char *str2
, const char *str3
)
497 if (we_are_background
)
498 parent_call ((void *)real_message_3s
, 3, sizeof (flags
), &flags
,
499 strlen (title
), title
, strlen (str1
), str1
,
500 strlen (str2
), str2
, strlen (str3
), str3
);
502 real_message_3s (Foreground
, &flags
, title
, str1
, str2
, str3
);
506 input_dialog_help (char *header
, char *text
, char *help
, char *def_text
)
508 extern char *real_input_dialog_help (char *header
, char *text
, char *help
, char *def_text
);
509 if (we_are_background
)
510 return parent_call_string ((void *)real_input_dialog_help
, 4,
511 strlen (header
), header
,
514 strlen (def_text
), def_text
);
516 return real_input_dialog_help (header
, text
, help
, def_text
);
519 #else /* Else => No background code support */
521 /* {{{ Stubs if background code is not supported */
523 message_1s (int flags
, char *title
, char *str1
)
525 message (flags
, title
, str1
);
529 message_2s (int flags
, char *title
, char *str1
, char *str2
)
531 message (flags
, title
, str1
, str2
);
535 message_3s (int flags
, char *title
, char *str1
, char *str2
, const char *str3
)
537 message (flags
, title
, str1
, str2
, str3
);
541 input_dialog_help (char *header
, char *text
, char *help
, char *def_text
)
543 return real_input_dialog_help (header
, text
, help
, def_text
);
549 /* {{{ Functions shared between background and foreground */
552 message_1s1d (int flags
, char *title
, char *str
, int d
)
556 p
= xmalloc (strlen (str
) + 30, "1s1d");
558 message_1s (flags
, title
, p
);