This source file includes following definitions.
- register_task_running
- destroy_task
- reading_failed
- background_attention
- parent_call_header
- parent_va_call
- parent_va_call_string
- unregister_task_running
- unregister_task_with_pid
- do_background
- parent_call
- parent_call_string
- background_parent_call
- background_parent_call_string
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 #include <config.h>
34
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <string.h>
41
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/wait.h>
45
46 #include "lib/global.h"
47
48 #include "lib/unixcompat.h"
49 #include "lib/tty/key.h"
50 #include "lib/widget.h"
51 #include "lib/event-types.h"
52 #include "lib/util.h"
53
54 #include "background.h"
55
56
57
58 #define MAXCALLARGS 4
59
60
61
62
63
64 enum ReturnType
65 {
66 Return_String,
67 Return_Integer
68 };
69
70
71
72 static int background_attention (int fd, void *closure);
73
74
75
76
77 static int parent_fd;
78
79
80 static int from_parent_fd;
81
82 TaskList *task_list = NULL;
83
84
85
86
87
88 static void
89 register_task_running (file_op_context_t *ctx, pid_t pid, int fd, int to_child, char *info)
90 {
91 TaskList *new;
92
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;
101
102 add_select_channel (fd, background_attention, ctx);
103 }
104
105
106
107 static int
108 destroy_task (pid_t pid)
109 {
110 TaskList *p = task_list;
111 TaskList *prev = NULL;
112
113 while (p != NULL)
114 {
115 if (p->pid == pid)
116 {
117 int fd = p->fd;
118
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;
126 }
127 prev = p;
128 p = p->next;
129 }
130
131
132 return (-1);
133 }
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 static int
177 reading_failed (int i, char **data)
178 {
179 while (i >= 0)
180 g_free (data[i--]);
181 message (D_ERROR, _("Background protocol error"), "%s", _("Reading failed"));
182 return 0;
183 }
184
185
186
187 static int
188 background_attention (int fd, void *closure)
189 {
190 file_op_context_t *ctx;
191 int have_ctx;
192 union
193 {
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 *);
199
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 *);
205
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 *);
211
212 void *pointer;
213 } routine;
214
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");
222
223 ctx = closure;
224
225 bytes = read (fd, &routine.pointer, sizeof (routine));
226 if (bytes == -1 || (size_t) bytes < (sizeof (routine)))
227 {
228 unregister_task_running (ctx->pid, fd);
229
230 if (waitpid (ctx->pid, &status, WNOHANG) == 0)
231 {
232
233 kill (ctx->pid, SIGTERM);
234 message (D_ERROR, background_process_error, "%s", _("Unknown error in child"));
235 return 0;
236 }
237
238
239 if (WIFEXITED (status) && (WEXITSTATUS (status) == 0))
240 return 0;
241
242 message (D_ERROR, background_process_error, "%s", _("Child died unexpectedly"));
243
244 return 0;
245 }
246
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);
251
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."));
256
257 if (have_ctx != 0 && read (fd, ctx, sizeof (*ctx)) != sizeof (*ctx))
258 return reading_failed (-1, data);
259
260 for (i = 0; i < argc; i++)
261 {
262 int size;
263
264 if (read (fd, &size, sizeof (size)) != sizeof (size))
265 return reading_failed (i - 1, data);
266
267 data[i] = g_malloc (size + 1);
268
269 if (read (fd, data[i], size) != size)
270 return reading_failed (i, data);
271
272 data[i][size] = '\0';
273 }
274
275
276
277 for (p = task_list; p != NULL; p = p->next)
278 if (p->fd == fd)
279 break;
280
281 if (p != NULL)
282 to_child_fd = p->to_child_fd;
283
284 if (to_child_fd == -1)
285 message (D_ERROR, background_process_error, "%s", _("Unknown error in child"));
286 else if (type == Return_Integer)
287 {
288
289
290 int result = 0;
291
292 if (have_ctx == 0)
293 switch (argc)
294 {
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;
312 }
313 else
314 switch (argc)
315 {
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;
334 }
335
336
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));
340 }
341 else if (type == Return_String)
342 {
343 int len;
344 char *resstr = NULL;
345
346
347
348
349 switch (argc)
350 {
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 ();
368 }
369
370 if (resstr != NULL)
371 {
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);
377 }
378 else
379 {
380 len = 0;
381 ret = write (to_child_fd, &len, sizeof (len));
382 }
383 }
384
385 for (i = 0; i < argc; i++)
386 g_free (data[i]);
387
388 repaint_screen ();
389
390 (void) ret;
391
392 return 0;
393 }
394
395
396
397
398
399
400
401
402
403
404
405 static void
406 parent_call_header (void *routine, int argc, enum ReturnType type, file_op_context_t *ctx)
407 {
408 int have_ctx;
409 ssize_t ret;
410
411 have_ctx = ctx != NULL ? 1 : 0;
412
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));
419
420 (void) ret;
421 }
422
423
424
425 static int
426 parent_va_call (void *routine, gpointer data, int argc, va_list ap)
427 {
428 int i;
429 ssize_t ret;
430 file_op_context_t *ctx = (file_op_context_t *) data;
431
432 parent_call_header (routine, argc, Return_Integer, ctx);
433 for (i = 0; i < argc; i++)
434 {
435 int len;
436 void *value;
437
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);
442 }
443
444 ret = read (from_parent_fd, &i, sizeof (i));
445 if (ctx != NULL)
446 ret = read (from_parent_fd, ctx, sizeof (*ctx));
447
448 (void) ret;
449
450 return i;
451 }
452
453
454
455 static char *
456 parent_va_call_string (void *routine, int argc, va_list ap)
457 {
458 char *str;
459 int i;
460
461 parent_call_header (routine, argc, Return_String, NULL);
462 for (i = 0; i < argc; i++)
463 {
464 int len;
465 void *value;
466
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;
472 }
473
474 if (read (from_parent_fd, &i, sizeof (i)) != sizeof (i) || i == 0)
475 return NULL;
476
477 str = g_malloc (i + 1);
478 if (read (from_parent_fd, str, i) != i)
479 {
480 g_free (str);
481 return NULL;
482 }
483 str[i] = '\0';
484 return str;
485 }
486
487
488
489
490
491 void
492 unregister_task_running (pid_t pid, int fd)
493 {
494 destroy_task (pid);
495 delete_select_channel (fd);
496 }
497
498
499
500 void
501 unregister_task_with_pid (pid_t pid)
502 {
503 int fd;
504
505 fd = destroy_task (pid);
506 if (fd != -1)
507 delete_select_channel (fd);
508 }
509
510
511
512
513
514
515
516
517
518
519 int
520 do_background (file_op_context_t *ctx, char *info)
521 {
522 int comm[2];
523 int back_comm[2];
524 pid_t pid;
525
526 if (pipe (comm) == -1)
527 return (-1);
528
529 if (pipe (back_comm) == -1)
530 {
531 (void) close (comm[0]);
532 (void) close (comm[1]);
533
534 return (-1);
535 }
536
537 pid = my_fork ();
538 if (pid == -1)
539 {
540 int saved_errno = errno;
541
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;
547
548 return (-1);
549 }
550
551 if (pid == 0)
552 {
553 int nullfd;
554
555 (void) close (comm[0]);
556 parent_fd = comm[1];
557
558 (void) close (back_comm[1]);
559 from_parent_fd = back_comm[0];
560
561 mc_global.we_are_background = TRUE;
562 top_dlg = NULL;
563
564
565 close (STDIN_FILENO);
566 close (STDOUT_FILENO);
567 close (STDERR_FILENO);
568
569 nullfd = open ("/dev/null", O_RDWR);
570 if (nullfd != -1)
571 {
572 while (dup2 (nullfd, STDIN_FILENO) == -1 && errno == EINTR)
573 ;
574 while (dup2 (nullfd, STDOUT_FILENO) == -1 && errno == EINTR)
575 ;
576 while (dup2 (nullfd, STDERR_FILENO) == -1 && errno == EINTR)
577 ;
578 close (nullfd);
579 }
580
581 return 0;
582 }
583 else
584 {
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;
590 }
591 }
592
593
594
595 int
596 parent_call (void *routine, file_op_context_t *ctx, int argc, ...)
597 {
598 int ret;
599 va_list ap;
600
601 va_start (ap, argc);
602 ret = parent_va_call (routine, (gpointer) ctx, argc, ap);
603 va_end (ap);
604
605 return ret;
606 }
607
608
609
610 char *
611 parent_call_string (void *routine, int argc, ...)
612 {
613 va_list ap;
614 char *str;
615
616 va_start (ap, argc);
617 str = parent_va_call_string (routine, argc, ap);
618 va_end (ap);
619
620 return str;
621 }
622
623
624
625
626 gboolean
627 background_parent_call (const gchar *event_group_name, const gchar *event_name,
628 gpointer init_data, gpointer data)
629 {
630 ev_background_parent_call_t *event_data = (ev_background_parent_call_t *) data;
631
632 (void) event_group_name;
633 (void) event_name;
634 (void) init_data;
635
636 event_data->ret.i =
637 parent_va_call (event_data->routine, event_data->ctx, event_data->argc, event_data->ap);
638
639 return TRUE;
640 }
641
642
643
644
645 gboolean
646 background_parent_call_string (const gchar *event_group_name, const gchar *event_name,
647 gpointer init_data, gpointer data)
648 {
649 ev_background_parent_call_t *event_data = (ev_background_parent_call_t *) data;
650
651 (void) event_group_name;
652 (void) event_name;
653 (void) init_data;
654
655 event_data->ret.s =
656 parent_va_call_string (event_data->routine, event_data->argc, event_data->ap);
657
658 return TRUE;
659 }
660
661