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>
43 * We currenlty only support one way of comunicating the background
44 * and foreground process by using the socketpair system call
46 #ifdef WITH_BACKGROUND
47 # include <sys/socket.h>
50 #include "fileopctx.h"
51 #include "key.h" /* For add_select_channel(), delete_select_channel() */
56 /* If true, this is a background process */
57 int we_are_background
= 0;
59 #ifdef WITH_BACKGROUND
60 /* If set background tasks wait to be attached */
61 int background_wait
= 0;
63 #ifndef HAVE_SOCKETPAIR
64 int socketpair(int, int, int, int fd
[2]);
67 /* File descriptor for talking to our parent */
70 #define MAXCALLARGS 4 /* Number of arguments supported */
71 #define mymsg "Desde el hijo\n\r"
73 struct TaskList
*task_list
= NULL
;
75 static int background_attention (int fd
, void *closure
);
78 register_task_running (FileOpContext
*ctx
, pid_t pid
, int fd
, char *info
)
82 new = g_new (TaskList
, 1);
85 new->state
= Task_Running
;
86 new->next
= task_list
;
90 add_select_channel (fd
, background_attention
, ctx
);
94 unregister_task_running (pid_t pid
, int fd
)
96 TaskList
*p
= task_list
;
102 prev
->next
= p
->next
;
112 delete_select_channel (fd
);
116 * Try to make the Midnight Commander a background job
124 do_background (FileOpContext
*ctx
, char *info
)
126 int comm
[2]; /* control connection stream */
129 if (socketpair (AF_UNIX
, SOCK_STREAM
, 0, comm
) == -1)
132 if ((pid
= fork ()) == -1)
138 parent_fd
= comm
[1];
139 we_are_background
= 1;
141 /* Make stdin/stdout/stderr point somewhere */
146 if ((nullfd
= open ("/dev/null", O_RDONLY
)) != -1){
147 while (dup2 (nullfd
, 0) == -1 && errno
== EINTR
)
149 while (dup2 (nullfd
, 1) == -1 && errno
== EINTR
)
151 while (dup2 (nullfd
, 2) == -1 && errno
== EINTR
)
155 /* To make it obvious if it fails, there is a bug report on this */
156 write (2, mymsg
, sizeof (mymsg
));
157 write (1, mymsg
, sizeof (mymsg
));
159 /* Just for debugging the background back end */
160 if (background_wait
){
170 register_task_running (ctx
, pid
, comm
[0], info
);
176 background_title (char *str
)
178 return g_strconcat (_("Background process:"), str
, NULL
);
181 /* {{{ Routines that do the real job */
183 real_message_1s (enum OperationMode mode
, int *flags
, char *title
, const char *str1
)
185 if (mode
== Background
)
186 title
= background_title (title
);
188 message (*flags
, title
, "%s", str1
);
190 if (mode
== Background
)
195 real_message_2s (enum OperationMode mode
, int *flags
, char *title
,
196 const char *str1
, const char *str2
)
198 if (mode
== Background
)
199 title
= background_title (title
);
201 message (*flags
, title
, str1
, str2
);
203 if (mode
== Background
)
208 real_message_3s (enum OperationMode mode
, int *flags
, char *title
,
209 const char *str1
, const char *str2
, const char *str3
)
211 if (mode
== Background
)
212 title
= background_title (title
);
214 message (*flags
, title
, str1
, str2
, str3
);
216 if (mode
== Background
)
221 /* {{{ Parent handlers */
223 /* Parent/child protocol
225 * the child (the background) process send the following:
226 * void *routine -- routine to be invoked in the parent
227 * int nargc -- number of arguments
228 * int type -- Return argument type.
230 * If the routine is zero, then it is a way to tell the parent
231 * that the process is dying.
233 * nargc arguments in the following format:
234 * int size of the coming block
235 * size bytes with the block
237 * Now, the parent loads all those and then invokes
238 * the routine with pointers to the information passed
239 * (we just support pointers).
241 * If the return type is integer:
243 * the parent then writes an int to the child with
244 * the return value from the routine and the values
245 * of any global variable that is modified in the parent
246 * currently: do_append and recursive_result.
248 * If the return type is a string:
250 * the parent writes the resulting string lenght
251 * if the result string was NULL or the empty string,
252 * then the lenght is zero.
253 * The parent then writes the string lenght and frees
257 * Receive requests from background process and invoke the
262 background_attention (int fd
, void *closure
)
267 int argc
, i
, result
, status
;
268 char *data
[MAXCALLARGS
];
270 enum ReturnType type
;
274 bytes
= read (fd
, &routine
, sizeof (routine
));
275 if (bytes
< (sizeof (routine
))){
276 char *background_process_error
= _(" Background process error ");
279 message (1, background_process_error
, _(" Child died unexpectedly "));
281 message (1, background_process_error
, _(" Unknown error in child "));
282 unregister_task_running (ctx
->pid
, fd
);
283 waitpid (ctx
->pid
, &status
, 0);
287 /* If the routine is zero, then the child is telling us that he is dying */
288 if ((long) routine
== MSG_CHILD_EXITING
){
289 unregister_task_running (ctx
->pid
, fd
);
290 waitpid (ctx
->pid
, &status
, 0);
294 read (fd
, &argc
, sizeof (argc
));
295 if (argc
> MAXCALLARGS
){
296 message (1, _(" Background protocol error "),
297 _(" Background process sent us a request for more arguments \n"
298 " than we can handle. \n"));
300 read (fd
, &type
, sizeof (type
));
301 read (fd
, &have_ctx
, sizeof (have_ctx
));
303 read (fd
, ctx
, sizeof (FileOpContext
));
305 for (i
= 0; i
< argc
; i
++){
308 read (fd
, &size
, sizeof (size
));
309 data
[i
] = g_malloc (size
+1);
310 read (fd
, data
[i
], size
);
312 data
[i
][size
] = 0; /* NULL terminate the blocks (they could be strings) */
315 /* Handle the call */
316 if (type
== Return_Integer
){
320 result
= (*(int (*)(int, char *))routine
)(Background
, data
[0]);
323 result
= (*(int (*)(int, char *, char *))routine
)
324 (Background
, data
[0], data
[1]);
327 result
= (*(int (*)(int, char *, char *, char *))routine
)
328 (Background
, data
[0], data
[1], data
[2]);
331 result
= (*(int (*)(int, char *, char *, char *, char *))routine
)
332 (Background
, data
[0], data
[1], data
[2], data
[3]);
338 result
= (*(int (*)(FileOpContext
*, int, char *))routine
)
339 (ctx
, Background
, data
[0]);
342 result
= (*(int (*)(FileOpContext
*, int, char *, char *))routine
)
343 (ctx
, Background
, data
[0], data
[1]);
346 result
= (*(int (*)(FileOpContext
*, int, char *, char *, char *))routine
)
347 (ctx
, Background
, data
[0], data
[1], data
[2]);
350 result
= (*(int (*)(FileOpContext
*, int, char *, char *, char *, char *))routine
)
351 (ctx
, Background
, data
[0], data
[1], data
[2], data
[3]);
355 /* Send the result code and the value for shared variables */
356 write (fd
, &result
, sizeof (int));
358 write (fd
, ctx
, sizeof (FileOpContext
));
359 } else if (type
== Return_String
) {
363 /* FIXME: string routines should also use the Foreground/Background
364 * parameter. Currently, this is not used here
368 resstr
= (*(char * (*)(char *))routine
)(data
[0]);
371 resstr
= (*(char * (*)(char *, char *))routine
)
372 (data
[0], data
[1]);
375 resstr
= (*(char * (*)(char *, char *, char *))routine
)
376 (data
[0], data
[1], data
[2]);
379 resstr
= (*(char * (*)(char *, char *, char *, char *))routine
)
380 (data
[0], data
[1], data
[2], data
[3]);
382 default: g_assert_not_reached();
385 len
= strlen (resstr
);
386 write (fd
, &len
, sizeof (len
));
388 write (fd
, resstr
, len
);
393 write (fd
, &len
, sizeof (len
));
396 for (i
= 0; i
< argc
; i
++)
408 /* {{{ client RPC routines */
410 /* Sends the header for a call to a routine in the parent process. If the file
411 * operation context is not NULL, then it requests that the first parameter of
412 * the call be a file operation context.
415 parent_call_header (void *routine
, int argc
, enum ReturnType type
, FileOpContext
*ctx
)
419 have_ctx
= (ctx
!= NULL
);
421 write (parent_fd
, &routine
, sizeof (routine
));
422 write (parent_fd
, &argc
, sizeof (int));
423 write (parent_fd
, &type
, sizeof (type
));
424 write (parent_fd
, &have_ctx
, sizeof (have_ctx
));
427 write (parent_fd
, ctx
, sizeof (FileOpContext
));
431 parent_call (void *routine
, FileOpContext
*ctx
, int argc
, ...)
437 parent_call_header (routine
, argc
, Return_Integer
, ctx
);
438 for (i
= 0; i
< argc
; i
++) {
442 len
= va_arg (ap
, int);
443 value
= va_arg (ap
, void *);
444 write (parent_fd
, &len
, sizeof (int));
445 write (parent_fd
, value
, len
);
447 read (parent_fd
, &i
, sizeof (int));
449 read (parent_fd
, ctx
, sizeof (FileOpContext
));
455 parent_call_string (void *routine
, int argc
, ...)
462 parent_call_header (routine
, argc
, Return_String
, NULL
);
463 for (i
= 0; i
< argc
; i
++){
467 len
= va_arg (ap
, int);
468 value
= va_arg (ap
, void *);
469 write (parent_fd
, &len
, sizeof (int));
470 write (parent_fd
, value
, len
);
472 read (parent_fd
, &i
, sizeof (int));
475 str
= g_malloc (i
+ 1);
476 read (parent_fd
, str
, i
);
482 tell_parent (int msg
)
484 write (parent_fd
, &msg
, sizeof (int));
488 message_1s (int flags
, char *title
, const char *str1
)
490 if (we_are_background
)
491 parent_call ((void *)real_message_1s
, NULL
, 3, sizeof (flags
), &flags
,
492 strlen (title
), title
, strlen (str1
), str1
);
494 real_message_1s (Foreground
, &flags
, title
, str1
);
498 message_2s (int flags
, char *title
, const char *str1
, const char *str2
)
500 if (we_are_background
)
501 parent_call ((void *)real_message_2s
, NULL
, 4, sizeof (flags
), &flags
,
502 strlen (title
), title
, strlen (str1
), str1
,
503 strlen (str2
), str2
);
505 real_message_2s (Foreground
, &flags
, title
, str1
, str2
);
509 message_3s (int flags
, char *title
, const char *str1
,
510 const char *str2
, const char *str3
)
512 if (we_are_background
)
513 parent_call ((void *)real_message_3s
, NULL
, 3, sizeof (flags
), &flags
,
514 strlen (title
), title
, strlen (str1
), str1
,
515 strlen (str2
), str2
, strlen (str3
), str3
);
517 real_message_3s (Foreground
, &flags
, title
, str1
, str2
, str3
);
521 input_dialog_help (char *header
, char *text
, char *help
, char *def_text
)
523 if (we_are_background
)
524 return parent_call_string ((void *)real_input_dialog_help
, 4,
525 strlen (header
), header
,
528 strlen (def_text
), def_text
);
530 return real_input_dialog_help (header
, text
, help
, def_text
);
533 #else /* Else => No background code support */
535 /* {{{ Stubs if background code is not supported */
537 message_1s (int flags
, char *title
, const char *str1
)
539 message (flags
, title
, "%s", str1
);
543 message_2s (int flags
, char *title
, const char *str1
, const char *str2
)
545 message (flags
, title
, str1
, str2
);
549 message_3s (int flags
, char *title
, const char *str1
,
550 const char *str2
, const char *str3
)
552 message (flags
, title
, str1
, str2
, str3
);
556 input_dialog_help (char *header
, char *text
, char *help
, char *def_text
)
558 return real_input_dialog_help (header
, text
, help
, def_text
);
562 #endif /* !WITH_BACKGROUND */
564 /* {{{ Functions shared between background and foreground */
567 message_1s1d (int flags
, char *title
, const char *str
, int d
)
569 char *p
= g_strdup_printf (str
, d
);
570 message_1s (flags
, title
, p
);