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;
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 int status;
229
230 unregister_task_running (ctx->pid, fd);
231
232 if (waitpid (ctx->pid, &status, WNOHANG) == 0)
233 {
234
235 kill (ctx->pid, SIGTERM);
236 message (D_ERROR, background_process_error, "%s", _ ("Unknown error in child"));
237 return 0;
238 }
239
240
241 if (WIFEXITED (status) && (WEXITSTATUS (status) == 0))
242 return 0;
243
244 message (D_ERROR, background_process_error, "%s", _ ("Child died unexpectedly"));
245
246 return 0;
247 }
248
249 if (read (fd, &argc, sizeof (argc)) != sizeof (argc)
250 || read (fd, &type, sizeof (type)) != sizeof (type)
251 || read (fd, &have_ctx, sizeof (have_ctx)) != sizeof (have_ctx))
252 return reading_failed (-1, data);
253
254 if (argc > MAXCALLARGS)
255 message (D_ERROR, _ ("Background protocol error"), "%s",
256 _ ("Background process sent us a request for more arguments\n"
257 "than we can handle."));
258
259 if (have_ctx != 0 && read (fd, ctx, sizeof (*ctx)) != sizeof (*ctx))
260 return reading_failed (-1, data);
261
262 for (int i = 0; i < argc; i++)
263 {
264 int size;
265
266 if (read (fd, &size, sizeof (size)) != sizeof (size))
267 return reading_failed (i - 1, data);
268
269 data[i] = g_malloc (size + 1);
270
271 if (read (fd, data[i], size) != size)
272 return reading_failed (i, data);
273
274 data[i][size] = '\0';
275 }
276
277
278
279 for (p = task_list; p != NULL; p = p->next)
280 if (p->fd == fd)
281 break;
282
283 if (p != NULL)
284 to_child_fd = p->to_child_fd;
285
286 if (to_child_fd == -1)
287 message (D_ERROR, background_process_error, "%s", _ ("Unknown error in child"));
288 else if (type == Return_Integer)
289 {
290
291
292 int result = 0;
293
294 if (have_ctx == 0)
295 switch (argc)
296 {
297 case 0:
298 result = routine.have_ctx0 (Background);
299 break;
300 case 1:
301 result = routine.have_ctx1 (Background, data[0]);
302 break;
303 case 2:
304 result = routine.have_ctx2 (Background, data[0], data[1]);
305 break;
306 case 3:
307 result = routine.have_ctx3 (Background, data[0], data[1], data[2]);
308 break;
309 case 4:
310 result = routine.have_ctx4 (Background, data[0], data[1], data[2], data[3]);
311 break;
312 default:
313 break;
314 }
315 else
316 switch (argc)
317 {
318 case 0:
319 result = routine.non_have_ctx0 (ctx, Background);
320 break;
321 case 1:
322 result = routine.non_have_ctx1 (ctx, Background, data[0]);
323 break;
324 case 2:
325 result = routine.non_have_ctx2 (ctx, Background, data[0], data[1]);
326 break;
327 case 3:
328 result = routine.non_have_ctx3 (ctx, Background, data[0], data[1], data[2]);
329 break;
330 case 4:
331 result =
332 routine.non_have_ctx4 (ctx, Background, data[0], data[1], data[2], data[3]);
333 break;
334 default:
335 break;
336 }
337
338
339 ret = write (to_child_fd, &result, sizeof (result));
340 if (have_ctx != 0)
341 ret = write (to_child_fd, ctx, sizeof (*ctx));
342 }
343 else if (type == Return_String)
344 {
345 int len = 0;
346 char *resstr = NULL;
347
348
349
350
351 switch (argc)
352 {
353 case 0:
354 resstr = routine.ret_str0 ();
355 break;
356 case 1:
357 resstr = routine.ret_str1 (data[0]);
358 break;
359 case 2:
360 resstr = routine.ret_str2 (data[0], data[1]);
361 break;
362 case 3:
363 resstr = routine.ret_str3 (data[0], data[1], data[2]);
364 break;
365 case 4:
366 resstr = routine.ret_str4 (data[0], data[1], data[2], data[3]);
367 break;
368 default:
369 g_assert_not_reached ();
370 }
371
372 if (resstr == NULL)
373 ret = write (to_child_fd, &len, sizeof (len));
374 else
375 {
376 len = (int) strlen (resstr);
377 ret = write (to_child_fd, &len, sizeof (len));
378 if (len != 0)
379 ret = write (to_child_fd, resstr, len);
380 g_free (resstr);
381 }
382 }
383
384 for (int i = 0; i < argc; i++)
385 g_free (data[i]);
386
387 repaint_screen ();
388
389 (void) ret;
390
391 return 0;
392 }
393
394
395
396
397
398
399
400
401
402
403
404 static void
405 parent_call_header (void *routine, int argc, enum ReturnType type, file_op_context_t *ctx)
406 {
407 int have_ctx;
408 ssize_t ret;
409
410 have_ctx = ctx != NULL ? 1 : 0;
411
412 ret = write (parent_fd, &routine, sizeof (routine));
413 ret = write (parent_fd, &argc, sizeof (argc));
414 ret = write (parent_fd, &type, sizeof (type));
415 ret = write (parent_fd, &have_ctx, sizeof (have_ctx));
416 if (have_ctx != 0)
417 ret = write (parent_fd, ctx, sizeof (*ctx));
418
419 (void) ret;
420 }
421
422
423
424 static int
425 parent_va_call (void *routine, gpointer data, int argc, va_list ap)
426 {
427 int i;
428 ssize_t ret;
429 file_op_context_t *ctx = (file_op_context_t *) data;
430
431 parent_call_header (routine, argc, Return_Integer, ctx);
432 for (i = 0; i < argc; i++)
433 {
434 int len;
435 void *value;
436
437 len = va_arg (ap, int);
438 value = va_arg (ap, void *);
439 ret = write (parent_fd, &len, sizeof (len));
440 ret = write (parent_fd, value, len);
441 }
442
443 ret = read (from_parent_fd, &i, sizeof (i));
444 if (ctx != NULL)
445 ret = read (from_parent_fd, ctx, sizeof (*ctx));
446
447 (void) ret;
448
449 return i;
450 }
451
452
453
454 static char *
455 parent_va_call_string (void *routine, int argc, va_list ap)
456 {
457 char *str;
458 int i;
459
460 parent_call_header (routine, argc, Return_String, NULL);
461 for (i = 0; i < argc; i++)
462 {
463 int len;
464 void *value;
465
466 len = va_arg (ap, int);
467 value = va_arg (ap, void *);
468 if (write (parent_fd, &len, sizeof (len)) != sizeof (len)
469 || write (parent_fd, value, len) != len)
470 return NULL;
471 }
472
473 if (read (from_parent_fd, &i, sizeof (i)) != sizeof (i) || i == 0)
474 return NULL;
475
476 str = g_malloc (i + 1);
477 if (read (from_parent_fd, str, i) != i)
478 {
479 g_free (str);
480 return NULL;
481 }
482 str[i] = '\0';
483 return str;
484 }
485
486
487
488
489
490 void
491 unregister_task_running (pid_t pid, int fd)
492 {
493 destroy_task (pid);
494 delete_select_channel (fd);
495 }
496
497
498
499 void
500 unregister_task_with_pid (pid_t pid)
501 {
502 int fd;
503
504 fd = destroy_task (pid);
505 if (fd != -1)
506 delete_select_channel (fd);
507 }
508
509
510
511
512
513
514
515
516
517
518 int
519 do_background (file_op_context_t *ctx, char *info)
520 {
521 int comm[2];
522 int back_comm[2];
523 pid_t pid;
524
525 if (pipe (comm) == -1)
526 return (-1);
527
528 if (pipe (back_comm) == -1)
529 {
530 (void) close (comm[0]);
531 (void) close (comm[1]);
532
533 return (-1);
534 }
535
536 pid = my_fork ();
537 if (pid == -1)
538 {
539 int saved_errno = errno;
540
541 (void) close (comm[0]);
542 (void) close (comm[1]);
543 (void) close (back_comm[0]);
544 (void) close (back_comm[1]);
545 errno = saved_errno;
546
547 return (-1);
548 }
549
550 if (pid == 0)
551 {
552 int nullfd;
553
554 (void) close (comm[0]);
555 parent_fd = comm[1];
556
557 (void) close (back_comm[1]);
558 from_parent_fd = back_comm[0];
559
560 mc_global.we_are_background = TRUE;
561 top_dlg = NULL;
562
563
564 close (STDIN_FILENO);
565 close (STDOUT_FILENO);
566 close (STDERR_FILENO);
567
568 nullfd = open ("/dev/null", O_RDWR);
569 if (nullfd != -1)
570 {
571 while (dup2 (nullfd, STDIN_FILENO) == -1 && errno == EINTR)
572 ;
573 while (dup2 (nullfd, STDOUT_FILENO) == -1 && errno == EINTR)
574 ;
575 while (dup2 (nullfd, STDERR_FILENO) == -1 && errno == EINTR)
576 ;
577 close (nullfd);
578 }
579
580 return 0;
581 }
582 else
583 {
584 (void) close (comm[1]);
585 (void) close (back_comm[0]);
586 ctx->pid = pid;
587 register_task_running (ctx, pid, comm[0], back_comm[1], info);
588 return 1;
589 }
590 }
591
592
593
594 int
595 parent_call (void *routine, file_op_context_t *ctx, int argc, ...)
596 {
597 int ret;
598 va_list ap;
599
600 va_start (ap, argc);
601 ret = parent_va_call (routine, (gpointer) ctx, argc, ap);
602 va_end (ap);
603
604 return ret;
605 }
606
607
608
609 char *
610 parent_call_string (void *routine, int argc, ...)
611 {
612 va_list ap;
613 char *str;
614
615 va_start (ap, argc);
616 str = parent_va_call_string (routine, argc, ap);
617 va_end (ap);
618
619 return str;
620 }
621
622
623
624
625 gboolean
626 background_parent_call (const gchar *event_group_name, const gchar *event_name, gpointer init_data,
627 gpointer data)
628 {
629 ev_background_parent_call_t *event_data = (ev_background_parent_call_t *) data;
630
631 (void) event_group_name;
632 (void) event_name;
633 (void) init_data;
634
635 event_data->ret.i =
636 parent_va_call (event_data->routine, event_data->ctx, event_data->argc, event_data->ap);
637
638 return TRUE;
639 }
640
641
642
643
644 gboolean
645 background_parent_call_string (const gchar *event_group_name, const gchar *event_name,
646 gpointer init_data, gpointer data)
647 {
648 ev_background_parent_call_t *event_data = (ev_background_parent_call_t *) data;
649
650 (void) event_group_name;
651 (void) event_name;
652 (void) init_data;
653
654 event_data->ret.s =
655 parent_va_call_string (event_data->routine, event_data->argc, event_data->ap);
656
657 return TRUE;
658 }
659
660