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
53 #include "filemanager/fileopctx.h"
54
55 #include "background.h"
56
57
58
59 #define MAXCALLARGS 4
60
61
62
63
64
65 enum ReturnType
66 {
67 Return_String,
68 Return_Integer
69 };
70
71
72
73 static int background_attention (int fd, void *closure);
74
75
76
77
78 static int parent_fd;
79
80
81 static int from_parent_fd;
82
83 TaskList *task_list = NULL;
84
85
86
87
88
89 static void
90 register_task_running (file_op_context_t * ctx, pid_t pid, int fd, int to_child, char *info)
91 {
92 TaskList *new;
93
94 new = g_new (TaskList, 1);
95 new->pid = pid;
96 new->info = info;
97 new->state = Task_Running;
98 new->next = task_list;
99 new->fd = fd;
100 new->to_child_fd = to_child;
101 task_list = new;
102
103 add_select_channel (fd, background_attention, ctx);
104 }
105
106
107
108 static int
109 destroy_task (pid_t pid)
110 {
111 TaskList *p = task_list;
112 TaskList *prev = NULL;
113
114 while (p != NULL)
115 {
116 if (p->pid == pid)
117 {
118 int fd = p->fd;
119
120 if (prev != NULL)
121 prev->next = p->next;
122 else
123 task_list = p->next;
124 g_free (p->info);
125 g_free (p);
126 return fd;
127 }
128 prev = p;
129 p = p->next;
130 }
131
132
133 return (-1);
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
177 static int
178 reading_failed (int i, char **data)
179 {
180 while (i >= 0)
181 g_free (data[i--]);
182 message (D_ERROR, _("Background protocol error"), "%s", _("Reading failed"));
183 return 0;
184 }
185
186
187
188 static int
189 background_attention (int fd, void *closure)
190 {
191 file_op_context_t *ctx;
192 int have_ctx;
193 union
194 {
195 int (*have_ctx0) (int);
196 int (*have_ctx1) (int, char *);
197 int (*have_ctx2) (int, char *, char *);
198 int (*have_ctx3) (int, char *, char *, char *);
199 int (*have_ctx4) (int, char *, char *, char *, char *);
200
201 int (*non_have_ctx0) (file_op_context_t *, int);
202 int (*non_have_ctx1) (file_op_context_t *, int, char *);
203 int (*non_have_ctx2) (file_op_context_t *, int, char *, char *);
204 int (*non_have_ctx3) (file_op_context_t *, int, char *, char *, char *);
205 int (*non_have_ctx4) (file_op_context_t *, int, char *, char *, char *, char *);
206
207 char *(*ret_str0) (void);
208 char *(*ret_str1) (char *);
209 char *(*ret_str2) (char *, char *);
210 char *(*ret_str3) (char *, char *, char *);
211 char *(*ret_str4) (char *, char *, char *, char *);
212
213 void *pointer;
214 } routine;
215
216 int argc, i, status;
217 char *data[MAXCALLARGS];
218 ssize_t bytes, ret;
219 TaskList *p;
220 int to_child_fd = -1;
221 enum ReturnType type;
222 const char *background_process_error = _("Background process error");
223
224 ctx = closure;
225
226 bytes = read (fd, &routine.pointer, sizeof (routine));
227 if (bytes == -1 || (size_t) bytes < (sizeof (routine)))
228 {
229 unregister_task_running (ctx->pid, fd);
230
231 if (waitpid (ctx->pid, &status, WNOHANG) == 0)
232 {
233
234 kill (ctx->pid, SIGTERM);
235 message (D_ERROR, background_process_error, "%s", _("Unknown error in child"));
236 return 0;
237 }
238
239
240 if (WIFEXITED (status) && (WEXITSTATUS (status) == 0))
241 return 0;
242
243 message (D_ERROR, background_process_error, "%s", _("Child died unexpectedly"));
244
245 return 0;
246 }
247
248 if (read (fd, &argc, sizeof (argc)) != sizeof (argc) ||
249 read (fd, &type, sizeof (type)) != sizeof (type) ||
250 read (fd, &have_ctx, sizeof (have_ctx)) != sizeof (have_ctx))
251 return reading_failed (-1, data);
252
253 if (argc > MAXCALLARGS)
254 message (D_ERROR, _("Background protocol error"), "%s",
255 _("Background process sent us a request for more arguments\n"
256 "than we can handle."));
257
258 if (have_ctx != 0 && read (fd, ctx, sizeof (*ctx)) != sizeof (*ctx))
259 return reading_failed (-1, data);
260
261 for (i = 0; i < argc; i++)
262 {
263 int size;
264
265 if (read (fd, &size, sizeof (size)) != sizeof (size))
266 return reading_failed (i - 1, data);
267
268 data[i] = g_malloc (size + 1);
269
270 if (read (fd, data[i], size) != size)
271 return reading_failed (i, data);
272
273 data[i][size] = '\0';
274 }
275
276
277
278 for (p = task_list; p != NULL; p = p->next)
279 if (p->fd == fd)
280 break;
281
282 if (p != NULL)
283 to_child_fd = p->to_child_fd;
284
285 if (to_child_fd == -1)
286 message (D_ERROR, background_process_error, "%s", _("Unknown error in child"));
287 else if (type == Return_Integer)
288 {
289
290
291 int result = 0;
292
293 if (have_ctx == 0)
294 switch (argc)
295 {
296 case 0:
297 result = routine.have_ctx0 (Background);
298 break;
299 case 1:
300 result = routine.have_ctx1 (Background, data[0]);
301 break;
302 case 2:
303 result = routine.have_ctx2 (Background, data[0], data[1]);
304 break;
305 case 3:
306 result = routine.have_ctx3 (Background, data[0], data[1], data[2]);
307 break;
308 case 4:
309 result = routine.have_ctx4 (Background, data[0], data[1], data[2], data[3]);
310 break;
311 default:
312 break;
313 }
314 else
315 switch (argc)
316 {
317 case 0:
318 result = routine.non_have_ctx0 (ctx, Background);
319 break;
320 case 1:
321 result = routine.non_have_ctx1 (ctx, Background, data[0]);
322 break;
323 case 2:
324 result = routine.non_have_ctx2 (ctx, Background, data[0], data[1]);
325 break;
326 case 3:
327 result = routine.non_have_ctx3 (ctx, Background, data[0], data[1], data[2]);
328 break;
329 case 4:
330 result =
331 routine.non_have_ctx4 (ctx, Background, data[0], data[1], data[2], data[3]);
332 break;
333 default:
334 break;
335 }
336
337
338 ret = write (to_child_fd, &result, sizeof (result));
339 if (have_ctx != 0 && to_child_fd != -1)
340 ret = write (to_child_fd, ctx, sizeof (*ctx));
341 }
342 else if (type == Return_String)
343 {
344 int len;
345 char *resstr = NULL;
346
347
348
349
350 switch (argc)
351 {
352 case 0:
353 resstr = routine.ret_str0 ();
354 break;
355 case 1:
356 resstr = routine.ret_str1 (data[0]);
357 break;
358 case 2:
359 resstr = routine.ret_str2 (data[0], data[1]);
360 break;
361 case 3:
362 resstr = routine.ret_str3 (data[0], data[1], data[2]);
363 break;
364 case 4:
365 resstr = routine.ret_str4 (data[0], data[1], data[2], data[3]);
366 break;
367 default:
368 g_assert_not_reached ();
369 }
370
371 if (resstr != NULL)
372 {
373 len = strlen (resstr);
374 ret = write (to_child_fd, &len, sizeof (len));
375 if (len != 0)
376 ret = write (to_child_fd, resstr, len);
377 g_free (resstr);
378 }
379 else
380 {
381 len = 0;
382 ret = write (to_child_fd, &len, sizeof (len));
383 }
384 }
385
386 for (i = 0; i < argc; i++)
387 g_free (data[i]);
388
389 repaint_screen ();
390
391 (void) ret;
392
393 return 0;
394 }
395
396
397
398
399
400
401
402
403
404
405
406 static void
407 parent_call_header (void *routine, int argc, enum ReturnType type, file_op_context_t * ctx)
408 {
409 int have_ctx;
410 ssize_t ret;
411
412 have_ctx = ctx != NULL ? 1 : 0;
413
414 ret = write (parent_fd, &routine, sizeof (routine));
415 ret = write (parent_fd, &argc, sizeof (argc));
416 ret = write (parent_fd, &type, sizeof (type));
417 ret = write (parent_fd, &have_ctx, sizeof (have_ctx));
418 if (have_ctx != 0)
419 ret = write (parent_fd, ctx, sizeof (*ctx));
420
421 (void) ret;
422 }
423
424
425
426 static int
427 parent_va_call (void *routine, gpointer data, int argc, va_list ap)
428 {
429 int i;
430 ssize_t ret;
431 file_op_context_t *ctx = (file_op_context_t *) data;
432
433 parent_call_header (routine, argc, Return_Integer, ctx);
434 for (i = 0; i < argc; i++)
435 {
436 int len;
437 void *value;
438
439 len = va_arg (ap, int);
440 value = va_arg (ap, void *);
441 ret = write (parent_fd, &len, sizeof (len));
442 ret = write (parent_fd, value, len);
443 }
444
445 ret = read (from_parent_fd, &i, sizeof (i));
446 if (ctx != NULL)
447 ret = read (from_parent_fd, ctx, sizeof (*ctx));
448
449 (void) ret;
450
451 return i;
452 }
453
454
455
456 static char *
457 parent_va_call_string (void *routine, int argc, va_list ap)
458 {
459 char *str;
460 int i;
461
462 parent_call_header (routine, argc, Return_String, NULL);
463 for (i = 0; i < argc; i++)
464 {
465 int len;
466 void *value;
467
468 len = va_arg (ap, int);
469 value = va_arg (ap, void *);
470 if (write (parent_fd, &len, sizeof (len)) != sizeof (len) ||
471 write (parent_fd, value, len) != len)
472 return NULL;
473 }
474
475 if (read (from_parent_fd, &i, sizeof (i)) != sizeof (i) || i == 0)
476 return NULL;
477
478 str = g_malloc (i + 1);
479 if (read (from_parent_fd, str, i) != i)
480 {
481 g_free (str);
482 return NULL;
483 }
484 str[i] = '\0';
485 return str;
486 }
487
488
489
490
491
492 void
493 unregister_task_running (pid_t pid, int fd)
494 {
495 destroy_task (pid);
496 delete_select_channel (fd);
497 }
498
499
500
501 void
502 unregister_task_with_pid (pid_t pid)
503 {
504 int fd;
505
506 fd = destroy_task (pid);
507 if (fd != -1)
508 delete_select_channel (fd);
509 }
510
511
512
513
514
515
516
517
518
519
520 int
521 do_background (file_op_context_t * ctx, char *info)
522 {
523 int comm[2];
524 int back_comm[2];
525 pid_t pid;
526
527 if (pipe (comm) == -1)
528 return (-1);
529
530 if (pipe (back_comm) == -1)
531 {
532 (void) close (comm[0]);
533 (void) close (comm[1]);
534
535 return (-1);
536 }
537
538 pid = fork ();
539 if (pid == -1)
540 {
541 int saved_errno = errno;
542
543 (void) close (comm[0]);
544 (void) close (comm[1]);
545 (void) close (back_comm[0]);
546 (void) close (back_comm[1]);
547 errno = saved_errno;
548
549 return (-1);
550 }
551
552 if (pid == 0)
553 {
554 int nullfd;
555
556 (void) close (comm[0]);
557 parent_fd = comm[1];
558
559 (void) close (back_comm[1]);
560 from_parent_fd = back_comm[0];
561
562 mc_global.we_are_background = TRUE;
563 top_dlg = NULL;
564
565
566 close (STDIN_FILENO);
567 close (STDOUT_FILENO);
568 close (STDERR_FILENO);
569
570 nullfd = open ("/dev/null", O_RDWR);
571 if (nullfd != -1)
572 {
573 while (dup2 (nullfd, STDIN_FILENO) == -1 && errno == EINTR)
574 ;
575 while (dup2 (nullfd, STDOUT_FILENO) == -1 && errno == EINTR)
576 ;
577 while (dup2 (nullfd, STDERR_FILENO) == -1 && errno == EINTR)
578 ;
579 close (nullfd);
580 }
581
582 return 0;
583 }
584 else
585 {
586 (void) close (comm[1]);
587 (void) close (back_comm[0]);
588 ctx->pid = pid;
589 register_task_running (ctx, pid, comm[0], back_comm[1], info);
590 return 1;
591 }
592 }
593
594
595
596 int
597 parent_call (void *routine, file_op_context_t * ctx, int argc, ...)
598 {
599 int ret;
600 va_list ap;
601
602 va_start (ap, argc);
603 ret = parent_va_call (routine, (gpointer) ctx, argc, ap);
604 va_end (ap);
605
606 return ret;
607 }
608
609
610
611 char *
612 parent_call_string (void *routine, int argc, ...)
613 {
614 va_list ap;
615 char *str;
616
617 va_start (ap, argc);
618 str = parent_va_call_string (routine, argc, ap);
619 va_end (ap);
620
621 return str;
622 }
623
624
625
626
627 gboolean
628 background_parent_call (const gchar * event_group_name, const gchar * event_name,
629 gpointer init_data, gpointer data)
630 {
631 ev_background_parent_call_t *event_data = (ev_background_parent_call_t *) data;
632
633 (void) event_group_name;
634 (void) event_name;
635 (void) init_data;
636
637 event_data->ret.i =
638 parent_va_call (event_data->routine, event_data->ctx, event_data->argc, event_data->ap);
639
640 return TRUE;
641 }
642
643
644
645
646 gboolean
647 background_parent_call_string (const gchar * event_group_name, const gchar * event_name,
648 gpointer init_data, gpointer data)
649 {
650 ev_background_parent_call_t *event_data = (ev_background_parent_call_t *) data;
651
652 (void) event_group_name;
653 (void) event_name;
654 (void) init_data;
655
656 event_data->ret.s =
657 parent_va_call_string (event_data->routine, event_data->argc, event_data->ap);
658
659 return TRUE;
660 }
661
662