Sync to Wine-0_9_5:
[reactos.git] / rosapps / mc / src / background.c
1 /* {{{ Copyright */
2
3 /* Background support.
4 Copyright (C) 1996 The Free Software Foundation
5
6 Written by: 1996 Miguel de Icaza
7
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.
12
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.
17
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. */
21
22 /* }}} */
23
24 #include <config.h>
25 #include <stdarg.h>
26 #include <sys/types.h>
27 #ifdef HAVE_SYS_WAIT_H
28 # include <sys/wait.h>
29 #endif
30 #include <errno.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 #include <sys/stat.h>
35 #include <sys/param.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include "dlg.h"
41 #include "widget.h"
42 #include "wtools.h"
43
44 /*
45 * We currenlty only support one way of comunicating the background
46 * and foreground process by using the socketpair system call
47 */
48 #ifdef USE_NETCODE
49 # include <sys/socket.h>
50 #endif
51 #include "tty.h"
52 #include "util.h"
53 #include "dialog.h"
54 #include "file.h"
55 #include "background.h"
56 #include "mad.h"
57 #include "key.h" /* For add_select_channel(), delete_select_channel() */
58
59 /* If true, this is a background process */
60 int we_are_background = 0;
61
62 /* Ugh, ugly hack */
63 extern int do_append;
64 extern int recursive_result;
65
66 #ifdef WITH_BACKGROUND
67 /* If set background tasks wait to be attached */
68 int background_wait = 0;
69
70 #ifndef HAVE_SOCKETPAIR
71 int socketpair(int, int, int, int fd[2]);
72 #endif
73
74 /* File descriptor for talking to our parent */
75 static int parent_fd;
76
77 #define MAXCALLARGS 4 /* Number of arguments supported */
78 #define mymsg "Desde el hijo\n\r"
79
80 struct TaskList *task_list = NULL;
81
82 void
83 register_task_running (pid_t pid, int fd, char *info)
84 {
85 TaskList *new;
86
87 new = xmalloc (sizeof (TaskList), "note_task_running");
88 new->pid = pid;
89 new->info = info;
90 new->state = Task_Running;
91 new->next = task_list;
92 new->fd = fd;
93 task_list = new;
94
95 add_select_channel (fd, background_attention, (void *) pid);
96 }
97
98 void
99 unregister_task_running (pid_t pid, int fd)
100 {
101 TaskList *p = task_list;
102 TaskList *prev = 0;
103
104 while (p){
105 if (p->pid == pid){
106 if (prev)
107 prev->next = p->next;
108 else
109 task_list = p->next;
110 free (p->info);
111 free (p);
112 break;
113 }
114 prev = p;
115 p = p->next;
116 }
117 delete_select_channel (fd);
118 }
119
120 /*
121 * Try to make the Midnight Commander a background job
122 *
123 * Returns:
124 * 1 for parent
125 * 0 for child
126 * -1 on failure
127 */
128 int
129 do_background (char *info)
130 {
131 int comm [2]; /* control connection stream */
132 int pid;
133
134 if (socketpair (AF_UNIX, SOCK_STREAM, 0, comm) == -1)
135 return -1;
136
137 if ((pid = fork ()) == -1)
138 return -1;
139
140 if (pid == 0){
141 int nullfd;
142
143 parent_fd = comm [1];
144 we_are_background = 1;
145
146 /* Make stdin/stdout/stderr point somewhere */
147 close (0);
148 close (1);
149 close (2);
150
151 if ((nullfd = open ("/dev/null", O_RDONLY)) != -1){
152 dup2 (nullfd, 0);
153 dup2 (nullfd, 1);
154 dup2 (nullfd, 2);
155 }
156
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));
160
161 /* Just for debugging the background back end */
162 if (background_wait){
163 volatile int i = 1;
164
165 while (i)
166 ;
167 }
168 return 0;
169 } else {
170 close (comm [1]);
171 register_task_running (pid, comm [0], info);
172 return 1;
173 }
174 }
175
176 char *
177 background_title (char *str)
178 {
179 char *result = copy_strings (_("Background process:"), str, NULL);
180
181 return result;
182 }
183
184 /* {{{ Routines that do the real job */
185 void
186 real_message_1s (enum OperationMode mode, int *flags, char *title, char *str1)
187 {
188 char *full_title;
189
190 if (mode == Background)
191 full_title = background_title (title);
192 else
193 full_title = title;
194
195 message (*flags, title, str1);
196
197 if (title != full_title)
198 free (full_title);
199 }
200
201 void
202 real_message_2s (enum OperationMode mode, int *flags, char *title, char *str1, char *str2)
203 {
204 char *full_title;
205
206 if (mode == Background)
207 full_title = background_title (title);
208 else
209 full_title = title;
210
211 message (*flags, title, str1, str2);
212
213 if (title != full_title)
214 free (full_title);
215 }
216
217 void
218 real_message_3s (enum OperationMode mode, int *flags, char *title, char *str1, char *str2, const char *str3)
219 {
220 char *full_title;
221
222 if (mode == Background)
223 full_title = background_title (title);
224 else
225 full_title = title;
226
227 message (*flags, title, str1, str2, str3);
228
229 if (title != full_title)
230 free (full_title);
231 }
232 /* }}} */
233
234 /* {{{ Parent handlers */
235
236 /* Parent/child protocol
237 *
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.
242 *
243 * If the routine is zero, then it is a way to tell the parent
244 * that the process is dying.
245 *
246 * nargc arguments in the following format:
247 * int size of the coming block
248 * size bytes with the block
249 *
250 * Now, the parent loads all those and then invokes
251 * the routine with pointers to the information passed
252 * (we just support pointers).
253 *
254 * If the return type is integer:
255 *
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.
260 *
261 * If the return type is a string:
262 *
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
267 * the result string.
268 */
269 /*
270 * Receive requests from background process and invoke the
271 * specified routine
272 */
273
274 int
275 background_attention (int fd, void *xpid)
276 {
277 void *routine;
278 int argc, i, result, status;
279 char *data [MAXCALLARGS];
280 char *resstr;
281 pid_t pid = (pid_t) xpid;
282 int bytes;
283 enum ReturnType type;
284 char *background_process_error = _(" Background process error ");
285
286 bytes = read (fd, &routine, sizeof (routine));
287 if (bytes < (sizeof (routine))){
288 if (errno == ECHILD)
289 message (1, background_process_error, _(" Child died unexpectedly "));
290 else
291 message (1, background_process_error, _(" Unknown error in child "));
292 unregister_task_running (pid, fd);
293 waitpid (pid, &status, 0);
294 return 0;
295 }
296
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);
301 return 0;
302 }
303
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"));
309 }
310 read (fd, &type, sizeof (type));
311
312 for (i = 0; i < argc; i++){
313 int size;
314
315 read (fd, &size, sizeof (size));
316 data [i] = xmalloc (size+1, "RPC Arguments");
317 read (fd, data [i], size);
318
319 data [i][size] = 0; /* NULL terminate the blocks (they could be strings) */
320 }
321
322 /* Handle the call */
323 if (type == Return_Integer){
324 switch (argc){
325 case 1:
326 result = (*(int (*)(int, char *))routine)(Background, data [0]);
327 break;
328 case 2:
329 result = (*(int (*)(int, char *, char *))routine)
330 (Background, data [0], data [1]);
331 break;
332 case 3:
333 result = (*(int (*)(int, char *, char *, char *))routine)
334 (Background, data [0], data [1], data [2]);
335 break;
336 case 4:
337 result = (*(int (*)(int, char *, char *, char *, char *))routine)
338 (Background, data [0], data [1], data [2], data [3]);
339 break;
340 }
341
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));
346
347 } else if (type == Return_String) {
348 int len;
349
350 /* FIXME: string routines should also use the Foreground/Background
351 * parameter. Currently, this is not used here
352 */
353 switch (argc){
354 case 1:
355 resstr = (*(char * (*)(char *))routine)(data [0]);
356 break;
357 case 2:
358 resstr = (*(char * (*)(char *, char *))routine)
359 (data [0], data [1]);
360 break;
361 case 3:
362 resstr = (*(char * (*)(char *, char *, char *))routine)
363 (data [0], data [1], data [2]);
364 break;
365 case 4:
366 resstr = (*(char * (*)(char *, char *, char *, char *))routine)
367 (data [0], data [1], data [2], data [3]);
368 break;
369 }
370 if (resstr){
371 len = strlen (resstr);
372 write (fd, &len, sizeof (len));
373 if (len){
374 write (fd, resstr, len);
375 free (resstr);
376 }
377 } else {
378 len = 0;
379 write (fd, &len, sizeof (len));
380 }
381 }
382 for (i = 0; i < argc; i++)
383 free (data [i]);
384
385 do_refresh ();
386 mc_refresh ();
387 #ifndef HAVE_X
388 doupdate ();
389 #endif
390 return 0;
391 }
392
393
394 /* }}} */
395
396 /* {{{ client RPC routines */
397 void
398 parent_call_header (void *routine, int argc, enum ReturnType type)
399 {
400 write (parent_fd, &routine, sizeof (routine));
401 write (parent_fd, &argc, sizeof (int));
402 write (parent_fd, &type, sizeof (type));
403 }
404
405 int
406 parent_call (void *routine, int argc, ...)
407 {
408 va_list ap;
409 int i;
410
411 va_start (ap, argc);
412 parent_call_header (routine, argc, Return_Integer);
413 for (i = 0; i < argc; i++){
414 int len;
415 void *value;
416
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);
421 }
422 /* Besides the regular result, get the value for
423 * variables that may be modified in the parent that affect our behaviour
424 */
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));
428 return i;
429 }
430
431 char *
432 parent_call_string (void *routine, int argc, ...)
433 {
434 va_list ap;
435 char *str;
436 int i;
437
438 va_start (ap, argc);
439 parent_call_header (routine, argc, Return_String);
440 for (i = 0; i < argc; i++){
441 int len;
442 void *value;
443
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);
448 }
449 read (parent_fd, &i, sizeof (int));
450 if (!i)
451 return NULL;
452 str = xmalloc (i + 1, "parent_return");
453 read (parent_fd, str, i);
454 str [i] = 0;
455 return str;
456 }
457
458 void
459 tell_parent (int msg)
460 {
461 write (parent_fd, &msg, sizeof (int));
462 }
463
464 int
465 call_1s (int (*routine)(enum OperationMode, char *), char *str)
466 {
467 if (we_are_background)
468 return parent_call ((void *)routine, 1, strlen (str), str);
469 else
470 return (*routine)(Foreground, str);
471 }
472
473 void
474 message_1s (int flags, char *title, char *str1)
475 {
476 if (we_are_background)
477 parent_call ((void *)real_message_1s, 3, sizeof (flags), &flags,
478 strlen (title), title, strlen (str1), str1);
479 else
480 real_message_1s (Foreground, &flags, title, str1);
481 }
482
483 void
484 message_2s (int flags, char *title, char *str1, char *str2)
485 {
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);
490 else
491 real_message_2s (Foreground, &flags, title, str1, str2);
492 }
493
494 void
495 message_3s (int flags, char *title, char *str1, char *str2, const char *str3)
496 {
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);
501 else
502 real_message_3s (Foreground, &flags, title, str1, str2, str3);
503 }
504
505 char *
506 input_dialog_help (char *header, char *text, char *help, char *def_text)
507 {
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,
512 strlen (text), text,
513 strlen (help), help,
514 strlen (def_text), def_text);
515 else
516 return real_input_dialog_help (header, text, help, def_text);
517 }
518
519 #else /* Else => No background code support */
520
521 /* {{{ Stubs if background code is not supported */
522 void
523 message_1s (int flags, char *title, char *str1)
524 {
525 message (flags, title, str1);
526 }
527
528 void
529 message_2s (int flags, char *title, char *str1, char *str2)
530 {
531 message (flags, title, str1, str2);
532 }
533
534 void
535 message_3s (int flags, char *title, char *str1, char *str2, const char *str3)
536 {
537 message (flags, title, str1, str2, str3);
538 }
539
540 char *
541 input_dialog_help (char *header, char *text, char *help, char *def_text)
542 {
543 return real_input_dialog_help (header, text, help, def_text);
544 }
545 /* }}} */
546
547 #endif
548
549 /* {{{ Functions shared between background and foreground */
550
551 void
552 message_1s1d (int flags, char *title, char *str, int d)
553 {
554 char *p;
555
556 p = xmalloc (strlen (str) + 30, "1s1d");
557 sprintf (p, str, d);
558 message_1s (flags, title, p);
559 free (p);
560 }
561
562 /* }}} */