D-Bus 1.13.18

dbus-spawn-unix.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-spawn-unix.c — Wrapper around fork/exec
3 *
4 * Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
5 * Copyright (C) 2003 CodeFactory AB
6 *
7 * Licensed under the Academic Free License version 2.1
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 */
24
25 #include <config.h>
26
27 #if defined(DBUS_WIN) || !defined(DBUS_UNIX)
28 #error "This file only makes sense on Unix OSs"
29 #endif
30
31 #include "dbus-spawn.h"
32 #include "dbus-sysdeps-unix.h"
33 #include "dbus-internals.h"
34 #include "dbus-test.h"
35 #include "dbus-protocol.h"
36
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <signal.h>
40 #include <sys/wait.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #ifdef HAVE_ERRNO_H
44 #include <errno.h>
45 #endif
46 #ifdef HAVE_SYSTEMD
47 #ifdef HAVE_SYSLOG_H
48 #include <syslog.h>
49 #endif
50 #include <systemd/sd-journal.h>
51 #endif
52
53 #if defined(__APPLE__)
54 # include <crt_externs.h>
55 # define environ (*_NSGetEnviron ())
56 #elif !HAVE_DECL_ENVIRON
57 extern char **environ;
58 #endif
59
65 /*
66 * I'm pretty sure this whole spawn file could be made simpler,
67 * if you thought about it a bit.
68 */
69
73 typedef enum
74 {
75 READ_STATUS_OK,
76 READ_STATUS_ERROR,
77 READ_STATUS_EOF
78 } ReadStatus;
79
80 static ReadStatus
81 read_ints (int fd,
82 int *buf,
83 int n_ints_in_buf,
84 int *n_ints_read,
85 DBusError *error)
86 {
87 size_t bytes = 0;
88 ReadStatus retval;
89
90 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
91
92 retval = READ_STATUS_OK;
93
94 while (TRUE)
95 {
96 ssize_t chunk;
97 size_t to_read;
98
99 to_read = sizeof (int) * n_ints_in_buf - bytes;
100
101 if (to_read == 0)
102 break;
103
104 again:
105
106 chunk = read (fd,
107 ((char*)buf) + bytes,
108 to_read);
109
110 if (chunk < 0 && errno == EINTR)
111 goto again;
112
113 if (chunk < 0)
114 {
115 dbus_set_error (error,
116 DBUS_ERROR_SPAWN_FAILED,
117 "Failed to read from child pipe (%s)",
118 _dbus_strerror (errno));
119
120 retval = READ_STATUS_ERROR;
121 break;
122 }
123 else if (chunk == 0)
124 {
125 retval = READ_STATUS_EOF;
126 break; /* EOF */
127 }
128 else /* chunk > 0 */
129 bytes += chunk;
130 }
131
132 *n_ints_read = (int)(bytes / sizeof(int));
133
134 return retval;
135 }
136
137 static ReadStatus
138 read_pid (int fd,
139 pid_t *buf,
140 DBusError *error)
141 {
142 size_t bytes = 0;
143 ReadStatus retval;
144
145 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
146
147 retval = READ_STATUS_OK;
148
149 while (TRUE)
150 {
151 ssize_t chunk;
152 size_t to_read;
153
154 to_read = sizeof (pid_t) - bytes;
155
156 if (to_read == 0)
157 break;
158
159 again:
160
161 chunk = read (fd,
162 ((char*)buf) + bytes,
163 to_read);
164 if (chunk < 0 && errno == EINTR)
165 goto again;
166
167 if (chunk < 0)
168 {
169 dbus_set_error (error,
170 DBUS_ERROR_SPAWN_FAILED,
171 "Failed to read from child pipe (%s)",
172 _dbus_strerror (errno));
173
174 retval = READ_STATUS_ERROR;
175 break;
176 }
177 else if (chunk == 0)
178 {
179 retval = READ_STATUS_EOF;
180 break; /* EOF */
181 }
182 else /* chunk > 0 */
183 bytes += chunk;
184 }
185
186 return retval;
187 }
188
189 /* The implementation uses an intermediate child between the main process
190 * and the grandchild. The grandchild is our spawned process. The intermediate
191 * child is a babysitter process; it keeps track of when the grandchild
192 * exits/crashes, and reaps the grandchild.
193 *
194 * We automatically reap the babysitter process, killing it if necessary,
195 * when the DBusBabysitter's refcount goes to zero.
196 *
197 * Processes:
198 *
199 * main process
200 * | fork() A
201 * \- babysitter
202 * | fork () B
203 * \- grandchild --> exec --> spawned process
204 *
205 * IPC:
206 * child_err_report_pipe
207 * /-----------<---------<--------------\
208 * | ^
209 * v |
210 * main process babysitter grandchild
211 * ^ ^
212 * v v
213 * \-------<->-------/
214 * babysitter_pipe
215 *
216 * child_err_report_pipe is genuinely a pipe.
217 * The READ_END (also called error_pipe_from_child) is used in the main
218 * process. The WRITE_END (also called child_err_report_fd) is used in
219 * the grandchild process.
220 *
221 * On failure, the grandchild process sends CHILD_EXEC_FAILED + errno.
222 * On success, the pipe just closes (because it's close-on-exec) without
223 * sending any bytes.
224 *
225 * babysitter_pipe is mis-named: it's really a bidirectional socketpair.
226 * The [0] end (also called socket_to_babysitter) is used in the main
227 * process, the [1] end (also called parent_pipe) is used in the babysitter.
228 *
229 * If the fork() labelled B in the diagram above fails, the babysitter sends
230 * CHILD_FORK_FAILED + errno.
231 * On success, the babysitter sends CHILD_PID + the grandchild's pid.
232 * On SIGCHLD, the babysitter sends CHILD_EXITED + the exit status.
233 * The main process doesn't explicitly send anything, but when it exits,
234 * the babysitter gets POLLHUP or POLLERR.
235 */
236
237 /* Messages from children to parents */
238 enum
239 {
240 CHILD_EXITED, /* This message is followed by the exit status int */
241 CHILD_FORK_FAILED, /* Followed by errno */
242 CHILD_EXEC_FAILED, /* Followed by errno */
243 CHILD_PID /* Followed by pid_t */
244 };
245
249 struct DBusBabysitter
250 {
251 int refcount;
253 char *log_name;
256 DBusSocket socket_to_babysitter;
257 int error_pipe_from_child;
259 pid_t sitter_pid;
260 pid_t grandchild_pid;
262 DBusWatchList *watches;
264 DBusWatch *error_watch;
265 DBusWatch *sitter_watch;
267 DBusBabysitterFinishedFunc finished_cb;
268 void *finished_data;
269
270 int errnum;
271 int status;
272 unsigned int have_child_status : 1;
273 unsigned int have_fork_errnum : 1;
274 unsigned int have_exec_errnum : 1;
275 };
276
277 static DBusBabysitter*
278 _dbus_babysitter_new (void)
279 {
280 DBusBabysitter *sitter;
281
282 sitter = dbus_new0 (DBusBabysitter, 1);
283 if (sitter == NULL)
284 return NULL;
285
286 sitter->refcount = 1;
287
288 sitter->socket_to_babysitter.fd = -1;
289 sitter->error_pipe_from_child = -1;
290
291 sitter->sitter_pid = -1;
292 sitter->grandchild_pid = -1;
293
294 sitter->watches = _dbus_watch_list_new ();
295 if (sitter->watches == NULL)
296 goto failed;
297
298 return sitter;
299
300 failed:
301 _dbus_babysitter_unref (sitter);
302 return NULL;
303 }
304
311 DBusBabysitter *
312 _dbus_babysitter_ref (DBusBabysitter *sitter)
313 {
314 _dbus_assert (sitter != NULL);
315 _dbus_assert (sitter->refcount > 0);
316
317 sitter->refcount += 1;
318
319 return sitter;
320 }
321
322 static void close_socket_to_babysitter (DBusBabysitter *sitter);
323 static void close_error_pipe_from_child (DBusBabysitter *sitter);
324
333 void
334 _dbus_babysitter_unref (DBusBabysitter *sitter)
335 {
336 _dbus_assert (sitter != NULL);
337 _dbus_assert (sitter->refcount > 0);
338
339 sitter->refcount -= 1;
340 if (sitter->refcount == 0)
341 {
342 /* If we haven't forked other babysitters
343 * since this babysitter and socket were
344 * created then this close will cause the
345 * babysitter to wake up from poll with
346 * a hangup and then the babysitter will
347 * quit itself.
348 */
349 close_socket_to_babysitter (sitter);
350
351 close_error_pipe_from_child (sitter);
352
353 if (sitter->sitter_pid > 0)
354 {
355 int status;
356 int ret;
357
358 /* It's possible the babysitter died on its own above
359 * from the close, or was killed randomly
360 * by some other process, so first try to reap it
361 */
362 ret = waitpid (sitter->sitter_pid, &status, WNOHANG);
363
364 /* If we couldn't reap the child then kill it, and
365 * try again
366 */
367 if (ret == 0)
368 kill (sitter->sitter_pid, SIGKILL);
369
370 if (ret == 0)
371 {
372 do
373 {
374 ret = waitpid (sitter->sitter_pid, &status, 0);
375 }
376 while (_DBUS_UNLIKELY (ret < 0 && errno == EINTR));
377 }
378
379 if (ret < 0)
380 {
381 if (errno == ECHILD)
382 _dbus_warn ("Babysitter process not available to be reaped; should not happen");
383 else
384 _dbus_warn ("Unexpected error %d in waitpid() for babysitter: %s",
385 errno, _dbus_strerror (errno));
386 }
387 else
388 {
389 _dbus_verbose ("Reaped %ld, waiting for babysitter %ld\n",
390 (long) ret, (long) sitter->sitter_pid);
391
392 if (WIFEXITED (sitter->status))
393 _dbus_verbose ("Babysitter exited with status %d\n",
394 WEXITSTATUS (sitter->status));
395 else if (WIFSIGNALED (sitter->status))
396 _dbus_verbose ("Babysitter received signal %d\n",
397 WTERMSIG (sitter->status));
398 else
399 _dbus_verbose ("Babysitter exited abnormally\n");
400 }
401
402 sitter->sitter_pid = -1;
403 }
404
405 if (sitter->watches)
406 _dbus_watch_list_free (sitter->watches);
407
408 dbus_free (sitter->log_name);
409
410 dbus_free (sitter);
411 }
412 }
413
414 static ReadStatus
415 read_data (DBusBabysitter *sitter,
416 int fd)
417 {
418 int what;
419 int got;
420 DBusError error = DBUS_ERROR_INIT;
421 ReadStatus r;
422
423 r = read_ints (fd, &what, 1, &got, &error);
424
425 switch (r)
426 {
427 case READ_STATUS_ERROR:
428 _dbus_warn ("Failed to read data from fd %d: %s", fd, error.message);
429 dbus_error_free (&error);
430 return r;
431
432 case READ_STATUS_EOF:
433 return r;
434
435 case READ_STATUS_OK:
436 break;
437
438 default:
439 _dbus_assert_not_reached ("invalid ReadStatus");
440 break;
441 }
442
443 if (got == 1)
444 {
445 switch (what)
446 {
447 case CHILD_EXITED:
448 case CHILD_FORK_FAILED:
449 case CHILD_EXEC_FAILED:
450 {
451 int arg;
452
453 r = read_ints (fd, &arg, 1, &got, &error);
454
455 switch (r)
456 {
457 case READ_STATUS_ERROR:
458 _dbus_warn ("Failed to read arg from fd %d: %s", fd, error.message);
459 dbus_error_free (&error);
460 return r;
461 case READ_STATUS_EOF:
462 return r;
463 case READ_STATUS_OK:
464 break;
465 default:
466 _dbus_assert_not_reached ("invalid ReadStatus");
467 break;
468 }
469
470 if (got == 1)
471 {
472 if (what == CHILD_EXITED)
473 {
474 /* Do not reset sitter->errnum to 0 here. We get here if
475 * the babysitter reports that the grandchild process has
476 * exited, and there are two ways that can happen:
477 *
478 * 1. grandchild successfully exec()s the desired process,
479 * but then the desired process exits or is terminated
480 * by a signal. The babysitter observes this and reports
481 * CHILD_EXITED.
482 *
483 * 2. grandchild fails to exec() the desired process,
484 * attempts to report the exec() failure (which
485 * we will receive as CHILD_EXEC_FAILED), and then
486 * exits itself (which will prompt the babysitter to
487 * send CHILD_EXITED). We want the CHILD_EXEC_FAILED
488 * to take precedence (and have its errno logged),
489 * which _dbus_babysitter_set_child_exit_error() does.
490 */
491 sitter->have_child_status = TRUE;
492 sitter->status = arg;
493 _dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n",
494 WIFEXITED (sitter->status), WIFSIGNALED (sitter->status),
495 WEXITSTATUS (sitter->status), WTERMSIG (sitter->status));
496 }
497 else if (what == CHILD_FORK_FAILED)
498 {
499 sitter->have_fork_errnum = TRUE;
500 sitter->errnum = arg;
501 _dbus_verbose ("recorded fork errnum %d\n", sitter->errnum);
502 }
503 else if (what == CHILD_EXEC_FAILED)
504 {
505 sitter->have_exec_errnum = TRUE;
506 sitter->errnum = arg;
507 _dbus_verbose ("recorded exec errnum %d\n", sitter->errnum);
508 }
509 }
510 }
511 break;
512 case CHILD_PID:
513 {
514 pid_t pid = -1;
515
516 r = read_pid (fd, &pid, &error);
517
518 switch (r)
519 {
520 case READ_STATUS_ERROR:
521 _dbus_warn ("Failed to read PID from fd %d: %s", fd, error.message);
522 dbus_error_free (&error);
523 return r;
524 case READ_STATUS_EOF:
525 return r;
526 case READ_STATUS_OK:
527 break;
528 default:
529 _dbus_assert_not_reached ("invalid ReadStatus");
530 break;
531 }
532
533 sitter->grandchild_pid = pid;
534
535 _dbus_verbose ("recorded grandchild pid %d\n", sitter->grandchild_pid);
536 }
537 break;
538 default:
539 _dbus_warn ("Unknown message received from babysitter process");
540 break;
541 }
542 }
543
544 return r;
545 }
546
547 static void
548 close_socket_to_babysitter (DBusBabysitter *sitter)
549 {
550 _dbus_verbose ("Closing babysitter\n");
551
552 if (sitter->sitter_watch != NULL)
553 {
554 _dbus_assert (sitter->watches != NULL);
555 _dbus_watch_list_remove_watch (sitter->watches, sitter->sitter_watch);
556 _dbus_watch_invalidate (sitter->sitter_watch);
557 _dbus_watch_unref (sitter->sitter_watch);
558 sitter->sitter_watch = NULL;
559 }
560
561 if (sitter->socket_to_babysitter.fd >= 0)
562 {
563 _dbus_close_socket (sitter->socket_to_babysitter, NULL);
564 sitter->socket_to_babysitter.fd = -1;
565 }
566 }
567
568 static void
569 close_error_pipe_from_child (DBusBabysitter *sitter)
570 {
571 _dbus_verbose ("Closing child error\n");
572
573 if (sitter->error_watch != NULL)
574 {
575 _dbus_assert (sitter->watches != NULL);
576 _dbus_watch_list_remove_watch (sitter->watches, sitter->error_watch);
577 _dbus_watch_invalidate (sitter->error_watch);
578 _dbus_watch_unref (sitter->error_watch);
579 sitter->error_watch = NULL;
580 }
581
582 if (sitter->error_pipe_from_child >= 0)
583 {
584 _dbus_close (sitter->error_pipe_from_child, NULL);
585 sitter->error_pipe_from_child = -1;
586 }
587 }
588
589 static void
590 handle_babysitter_socket (DBusBabysitter *sitter,
591 int revents)
592 {
593 /* Even if we have POLLHUP, we want to keep reading
594 * data until POLLIN goes away; so this function only
595 * looks at HUP/ERR if no IN is set.
596 */
597 if (revents & _DBUS_POLLIN)
598 {
599 _dbus_verbose ("Reading data from babysitter\n");
600 if (read_data (sitter, sitter->socket_to_babysitter.fd) != READ_STATUS_OK)
601 close_socket_to_babysitter (sitter);
602 }
603 else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
604 {
605 close_socket_to_babysitter (sitter);
606 }
607 }
608
609 static void
610 handle_error_pipe (DBusBabysitter *sitter,
611 int revents)
612 {
613 if (revents & _DBUS_POLLIN)
614 {
615 _dbus_verbose ("Reading data from child error\n");
616 if (read_data (sitter, sitter->error_pipe_from_child) != READ_STATUS_OK)
617 close_error_pipe_from_child (sitter);
618 }
619 else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
620 {
621 close_error_pipe_from_child (sitter);
622 }
623 }
624
625 /* returns whether there were any poll events handled */
626 static dbus_bool_t
627 babysitter_iteration (DBusBabysitter *sitter,
628 dbus_bool_t block)
629 {
630 DBusPollFD fds[2];
631 int i;
632 dbus_bool_t descriptors_ready;
633
634 descriptors_ready = FALSE;
635
636 i = 0;
637
638 if (sitter->error_pipe_from_child >= 0)
639 {
640 fds[i].fd = sitter->error_pipe_from_child;
641 fds[i].events = _DBUS_POLLIN;
642 fds[i].revents = 0;
643 ++i;
644 }
645
646 if (sitter->socket_to_babysitter.fd >= 0)
647 {
648 fds[i].fd = sitter->socket_to_babysitter.fd;
649 fds[i].events = _DBUS_POLLIN;
650 fds[i].revents = 0;
651 ++i;
652 }
653
654 if (i > 0)
655 {
656 int ret;
657
658 do
659 {
660 ret = _dbus_poll (fds, i, 0);
661 }
662 while (ret < 0 && errno == EINTR);
663
664 if (ret == 0 && block)
665 {
666 do
667 {
668 ret = _dbus_poll (fds, i, -1);
669 }
670 while (ret < 0 && errno == EINTR);
671 }
672
673 if (ret > 0)
674 {
675 descriptors_ready = TRUE;
676
677 while (i > 0)
678 {
679 --i;
680 if (fds[i].fd == sitter->error_pipe_from_child)
681 handle_error_pipe (sitter, fds[i].revents);
682 else if (fds[i].fd == sitter->socket_to_babysitter.fd)
683 handle_babysitter_socket (sitter, fds[i].revents);
684 }
685 }
686 }
687
688 return descriptors_ready;
689 }
690
695 #define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter.fd >= 0 || (sitter)->error_pipe_from_child >= 0)
696
703 void
704 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
705 {
706 /* be sure we have the PID of the child */
707 while (LIVE_CHILDREN (sitter) &&
708 sitter->grandchild_pid == -1)
709 babysitter_iteration (sitter, TRUE);
710
711 _dbus_verbose ("Got child PID %ld for killing\n",
712 (long) sitter->grandchild_pid);
713
714 if (sitter->grandchild_pid == -1)
715 return; /* child is already dead, or we're so hosed we'll never recover */
716
717 kill (sitter->grandchild_pid, SIGKILL);
718 }
719
725 dbus_bool_t
726 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
727 {
728
729 /* Be sure we're up-to-date */
730 while (LIVE_CHILDREN (sitter) &&
731 babysitter_iteration (sitter, FALSE))
732 ;
733
734 /* We will have exited the babysitter when the child has exited */
735 return sitter->socket_to_babysitter.fd < 0;
736 }
737
750 dbus_bool_t
751 _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter,
752 int *status)
753 {
754 if (!_dbus_babysitter_get_child_exited (sitter))
755 _dbus_assert_not_reached ("Child has not exited");
756
757 if (!sitter->have_child_status ||
758 !(WIFEXITED (sitter->status)))
759 return FALSE;
760
761 *status = WEXITSTATUS (sitter->status);
762 return TRUE;
763 }
764
774 void
775 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
776 DBusError *error)
777 {
778 if (!_dbus_babysitter_get_child_exited (sitter))
779 return;
780
781 /* Note that if exec fails, we will also get a child status
782 * from the babysitter saying the child exited,
783 * so we need to give priority to the exec error
784 */
785 if (sitter->have_exec_errnum)
786 {
787 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
788 "Failed to execute program %s: %s",
789 sitter->log_name, _dbus_strerror (sitter->errnum));
790 }
791 else if (sitter->have_fork_errnum)
792 {
793 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
794 "Failed to fork a new process %s: %s",
795 sitter->log_name, _dbus_strerror (sitter->errnum));
796 }
797 else if (sitter->have_child_status)
798 {
799 if (WIFEXITED (sitter->status))
800 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
801 "Process %s exited with status %d",
802 sitter->log_name, WEXITSTATUS (sitter->status));
803 else if (WIFSIGNALED (sitter->status))
804 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED,
805 "Process %s received signal %d",
806 sitter->log_name, WTERMSIG (sitter->status));
807 else
808 dbus_set_error (error, DBUS_ERROR_FAILED,
809 "Process %s exited abnormally",
810 sitter->log_name);
811 }
812 else
813 {
814 dbus_set_error (error, DBUS_ERROR_FAILED,
815 "Process %s exited, reason unknown",
816 sitter->log_name);
817 }
818 }
819
832 dbus_bool_t
833 _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter,
834 DBusAddWatchFunction add_function,
835 DBusRemoveWatchFunction remove_function,
836 DBusWatchToggledFunction toggled_function,
837 void *data,
838 DBusFreeFunction free_data_function)
839 {
840 return _dbus_watch_list_set_functions (sitter->watches,
841 add_function,
842 remove_function,
843 toggled_function,
844 data,
845 free_data_function);
846 }
847
848 static dbus_bool_t
849 handle_watch (DBusWatch *watch,
850 unsigned int condition,
851 void *data)
852 {
853 DBusBabysitter *sitter = _dbus_babysitter_ref (data);
854 int revents;
855 int fd;
856
857 revents = 0;
858 if (condition & DBUS_WATCH_READABLE)
859 revents |= _DBUS_POLLIN;
860 if (condition & DBUS_WATCH_ERROR)
861 revents |= _DBUS_POLLERR;
862 if (condition & DBUS_WATCH_HANGUP)
863 revents |= _DBUS_POLLHUP;
864
865 fd = dbus_watch_get_socket (watch);
866
867 if (fd == sitter->error_pipe_from_child)
868 handle_error_pipe (sitter, revents);
869 else if (fd == sitter->socket_to_babysitter.fd)
870 handle_babysitter_socket (sitter, revents);
871
872 while (LIVE_CHILDREN (sitter) &&
873 babysitter_iteration (sitter, FALSE))
874 ;
875
876 /* fd.o #32992: if the handle_* methods closed their sockets, they previously
877 * didn't always remove the watches. Check that we don't regress. */
878 _dbus_assert (sitter->socket_to_babysitter.fd != -1 || sitter->sitter_watch == NULL);
879 _dbus_assert (sitter->error_pipe_from_child != -1 || sitter->error_watch == NULL);
880
881 if (_dbus_babysitter_get_child_exited (sitter) &&
882 sitter->finished_cb != NULL)
883 {
884 sitter->finished_cb (sitter, sitter->finished_data);
885 sitter->finished_cb = NULL;
886 }
887
888 _dbus_babysitter_unref (sitter);
889 return TRUE;
890 }
891
893 #define READ_END 0
894
895 #define WRITE_END 1
896
897
898 /* Avoids a danger in re-entrant situations (calling close()
899 * on a file descriptor twice, and another module has
900 * re-opened it since the first close).
901 *
902 * This previously claimed to be relevant for threaded situations, but by
903 * trivial inspection, it is not thread-safe. It doesn't actually
904 * matter, since this module is only used in the -util variant of the
905 * library, which is only used in single-threaded situations.
906 */
907 static int
908 close_and_invalidate (int *fd)
909 {
910 int ret;
911
912 if (*fd < 0)
913 return -1;
914 else
915 {
916 ret = _dbus_close (*fd, NULL);
917 *fd = -1;
918 }
919
920 return ret;
921 }
922
923 static dbus_bool_t
924 make_pipe (int p[2],
925 DBusError *error)
926 {
927 int retval;
928
929 #ifdef HAVE_PIPE2
930 dbus_bool_t cloexec_done;
931
932 retval = pipe2 (p, O_CLOEXEC);
933 cloexec_done = retval >= 0;
934
935 /* Check if kernel seems to be too old to know pipe2(). We assume
936 that if pipe2 is available, O_CLOEXEC is too. */
937 if (retval < 0 && errno == ENOSYS)
938 #endif
939 {
940 retval = pipe(p);
941 }
942
943 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
944
945 if (retval < 0)
946 {
947 dbus_set_error (error,
948 DBUS_ERROR_SPAWN_FAILED,
949 "Failed to create pipe for communicating with child process (%s)",
950 _dbus_strerror (errno));
951 return FALSE;
952 }
953
954 #ifdef HAVE_PIPE2
955 if (!cloexec_done)
956 #endif
957 {
958 _dbus_fd_set_close_on_exec (p[0]);
959 _dbus_fd_set_close_on_exec (p[1]);
960 }
961
962 return TRUE;
963 }
964
965 static void
966 do_write (int fd, const void *buf, size_t count)
967 {
968 size_t bytes_written;
969 int ret;
970
971 bytes_written = 0;
972
973 again:
974
975 ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written);
976
977 if (ret < 0)
978 {
979 if (errno == EINTR)
980 goto again;
981 else
982 {
983 _dbus_warn ("Failed to write data to pipe!");
984 exit (1); /* give up, we suck */
985 }
986 }
987 else
988 bytes_written += ret;
989
990 if (bytes_written < count)
991 goto again;
992 }
993
994 static void write_err_and_exit (int fd, int msg) _DBUS_GNUC_NORETURN;
995
996 static void
997 write_err_and_exit (int fd, int msg)
998 {
999 int en = errno;
1000
1001 do_write (fd, &msg, sizeof (msg));
1002 do_write (fd, &en, sizeof (en));
1003
1004 exit (1);
1005 }
1006
1007 static void
1008 write_pid (int fd, pid_t pid)
1009 {
1010 int msg = CHILD_PID;
1011
1012 do_write (fd, &msg, sizeof (msg));
1013 do_write (fd, &pid, sizeof (pid));
1014 }
1015
1016 static void write_status_and_exit (int fd, int status) _DBUS_GNUC_NORETURN;
1017
1018 static void
1019 write_status_and_exit (int fd, int status)
1020 {
1021 int msg = CHILD_EXITED;
1022
1023 do_write (fd, &msg, sizeof (msg));
1024 do_write (fd, &status, sizeof (status));
1025
1026 exit (0);
1027 }
1028
1029 static void do_exec (int child_err_report_fd,
1030 char * const *argv,
1031 char * const *envp,
1032 DBusSpawnChildSetupFunc child_setup,
1033 void *user_data) _DBUS_GNUC_NORETURN;
1034
1035 static void
1036 do_exec (int child_err_report_fd,
1037 char * const *argv,
1038 char * const *envp,
1039 DBusSpawnChildSetupFunc child_setup,
1040 void *user_data)
1041 {
1042 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1043 int i, max_open;
1044 #endif
1045
1046 _dbus_verbose_reset ();
1047 _dbus_verbose ("Child process has PID " DBUS_PID_FORMAT "\n",
1048 _dbus_getpid ());
1049
1050 if (child_setup)
1051 (* child_setup) (user_data);
1052
1053 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1054 max_open = sysconf (_SC_OPEN_MAX);
1055
1056 for (i = 3; i < max_open; i++)
1057 {
1058 int retval;
1059
1060 if (i == child_err_report_fd)
1061 continue;
1062
1063 retval = fcntl (i, F_GETFD);
1064
1065 if (retval != -1 && !(retval & FD_CLOEXEC))
1066 {
1067 char description[256] = { 0 };
1068 char proc_self_fd[256] = { 0 };
1069 size_t description_length = sizeof (description) - 1;
1070
1071 snprintf (proc_self_fd, sizeof (proc_self_fd) - 1,
1072 "/proc/self/fd/%d", i);
1073 proc_self_fd[sizeof (proc_self_fd) - 1] = '\0';
1074
1075 if (readlink (proc_self_fd, description, description_length) <= 0)
1076 snprintf (description, sizeof (description) - 1, "(unknown)");
1077
1078 description[sizeof (description) - 1] = '\0';
1079 _dbus_warn ("Fd %d \"%s\" did not have the close-on-exec flag set!",
1080 i, description);
1081 }
1082 }
1083 #endif
1084
1085 if (envp == NULL)
1086 {
1087 _dbus_assert (environ != NULL);
1088
1089 envp = environ;
1090 }
1091
1092 execve (argv[0], argv, envp);
1093
1094 /* Exec failed */
1095 write_err_and_exit (child_err_report_fd,
1096 CHILD_EXEC_FAILED);
1097 }
1098
1099 static void
1100 check_babysit_events (pid_t grandchild_pid,
1101 int parent_pipe,
1102 int revents)
1103 {
1104 pid_t ret;
1105 int status;
1106
1107 do
1108 {
1109 ret = waitpid (grandchild_pid, &status, WNOHANG);
1110 /* The man page says EINTR can't happen with WNOHANG,
1111 * but there are reports of it (maybe only with valgrind?)
1112 */
1113 }
1114 while (ret < 0 && errno == EINTR);
1115
1116 if (ret == 0)
1117 {
1118 _dbus_verbose ("no child exited\n");
1119
1120 ; /* no child exited */
1121 }
1122 else if (ret < 0)
1123 {
1124 /* This isn't supposed to happen. */
1125 _dbus_warn ("unexpected waitpid() failure in check_babysit_events(): %s",
1126 _dbus_strerror (errno));
1127 exit (1);
1128 }
1129 else if (ret == grandchild_pid)
1130 {
1131 /* Child exited */
1132 _dbus_verbose ("reaped child pid %ld\n", (long) ret);
1133
1134 write_status_and_exit (parent_pipe, status);
1135 }
1136 else
1137 {
1138 _dbus_warn ("waitpid() reaped pid %d that we've never heard of",
1139 (int) ret);
1140 exit (1);
1141 }
1142
1143 if (revents & _DBUS_POLLIN)
1144 {
1145 _dbus_verbose ("babysitter got POLLIN from parent pipe\n");
1146 }
1147
1148 if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
1149 {
1150 /* Parent is gone, so we just exit */
1151 _dbus_verbose ("babysitter got POLLERR or POLLHUP from parent\n");
1152 exit (0);
1153 }
1154 }
1155
1156 /* Only used in a single-threaded child process, does not need to be
1157 * thread-safe */
1158 static int babysit_sigchld_pipe = -1;
1159
1160 static void
1161 babysit_signal_handler (int signo)
1162 {
1163 /* Signal handlers that might set errno must save and restore the errno
1164 * that the interrupted function might have been relying on. */
1165 int saved_errno = errno;
1166 char b = '\0';
1167
1168 again:
1169 if (write (babysit_sigchld_pipe, &b, 1) <= 0)
1170 if (errno == EINTR)
1171 goto again;
1172
1173 errno = saved_errno;
1174 }
1175
1176 static void babysit (pid_t grandchild_pid,
1177 int parent_pipe) _DBUS_GNUC_NORETURN;
1178
1179 static void
1180 babysit (pid_t grandchild_pid,
1181 int parent_pipe)
1182 {
1183 int sigchld_pipe[2];
1184
1185 /* We don't exec, so we keep parent state, such as the pid that
1186 * _dbus_verbose() uses. Reset the pid here.
1187 */
1188 _dbus_verbose_reset ();
1189
1190 /* I thought SIGCHLD would just wake up the poll, but
1191 * that didn't seem to work, so added this pipe.
1192 * Probably the pipe is more likely to work on busted
1193 * operating systems anyhow.
1194 */
1195 if (pipe (sigchld_pipe) < 0)
1196 {
1197 _dbus_warn ("Not enough file descriptors to create pipe in babysitter process");
1198 exit (1);
1199 }
1200
1201 babysit_sigchld_pipe = sigchld_pipe[WRITE_END];
1202
1203 _dbus_set_signal_handler (SIGCHLD, babysit_signal_handler);
1204
1205 write_pid (parent_pipe, grandchild_pid);
1206
1207 check_babysit_events (grandchild_pid, parent_pipe, 0);
1208
1209 while (TRUE)
1210 {
1211 DBusPollFD pfds[2];
1212
1213 pfds[0].fd = parent_pipe;
1214 pfds[0].events = _DBUS_POLLIN;
1215 pfds[0].revents = 0;
1216
1217 pfds[1].fd = sigchld_pipe[READ_END];
1218 pfds[1].events = _DBUS_POLLIN;
1219 pfds[1].revents = 0;
1220
1221 if (_dbus_poll (pfds, _DBUS_N_ELEMENTS (pfds), -1) < 0 && errno != EINTR)
1222 {
1223 _dbus_warn ("_dbus_poll() error: %s", strerror (errno));
1224 exit (1);
1225 }
1226
1227 if (pfds[0].revents != 0)
1228 {
1229 check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents);
1230 }
1231 else if (pfds[1].revents & _DBUS_POLLIN)
1232 {
1233 char b;
1234 if (read (sigchld_pipe[READ_END], &b, 1) == -1)
1235 {
1236 /* ignore */
1237 }
1238 /* do waitpid check */
1239 check_babysit_events (grandchild_pid, parent_pipe, 0);
1240 }
1241 }
1242
1243 exit (1);
1244 }
1245
1270 dbus_bool_t
1271 _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
1272 const char *log_name,
1273 char * const *argv,
1274 char * const *env,
1275 DBusSpawnFlags flags,
1276 DBusSpawnChildSetupFunc child_setup,
1277 void *user_data,
1278 DBusError *error)
1279 {
1280 DBusBabysitter *sitter;
1281 int child_err_report_pipe[2] = { -1, -1 };
1282 DBusSocket babysitter_pipe[2] = { DBUS_SOCKET_INIT, DBUS_SOCKET_INIT };
1283 pid_t pid;
1284 int fd_out = -1;
1285 int fd_err = -1;
1286
1287 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1288 _dbus_assert (argv[0] != NULL);
1289
1290 if (sitter_p != NULL)
1291 *sitter_p = NULL;
1292
1293 sitter = NULL;
1294
1295 sitter = _dbus_babysitter_new ();
1296 if (sitter == NULL)
1297 {
1298 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1299 return FALSE;
1300 }
1301
1302 sitter->log_name = _dbus_strdup (log_name);
1303 if (sitter->log_name == NULL && log_name != NULL)
1304 {
1305 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1306 goto cleanup_and_fail;
1307 }
1308
1309 if (sitter->log_name == NULL)
1310 sitter->log_name = _dbus_strdup (argv[0]);
1311
1312 if (sitter->log_name == NULL)
1313 {
1314 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1315 goto cleanup_and_fail;
1316 }
1317
1318 if (!make_pipe (child_err_report_pipe, error))
1319 goto cleanup_and_fail;
1320
1321 if (!_dbus_socketpair (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
1322 goto cleanup_and_fail;
1323
1324 /* Setting up the babysitter is only useful in the parent,
1325 * but we don't want to run out of memory and fail
1326 * after we've already forked, since then we'd leak
1327 * child processes everywhere.
1328 */
1329 sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
1330 DBUS_WATCH_READABLE,
1331 TRUE, handle_watch, sitter, NULL);
1332 if (sitter->error_watch == NULL)
1333 {
1334 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1335 goto cleanup_and_fail;
1336 }
1337
1338 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->error_watch))
1339 {
1340 /* we need to free it early so the destructor won't try to remove it
1341 * without it having been added, which DBusLoop doesn't allow */
1342 _dbus_watch_invalidate (sitter->error_watch);
1343 _dbus_watch_unref (sitter->error_watch);
1344 sitter->error_watch = NULL;
1345
1346 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1347 goto cleanup_and_fail;
1348 }
1349
1350 sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0].fd,
1351 DBUS_WATCH_READABLE,
1352 TRUE, handle_watch, sitter, NULL);
1353 if (sitter->sitter_watch == NULL)
1354 {
1355 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1356 goto cleanup_and_fail;
1357 }
1358
1359 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
1360 {
1361 /* we need to free it early so the destructor won't try to remove it
1362 * without it having been added, which DBusLoop doesn't allow */
1363 _dbus_watch_invalidate (sitter->sitter_watch);
1364 _dbus_watch_unref (sitter->sitter_watch);
1365 sitter->sitter_watch = NULL;
1366
1367 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1368 goto cleanup_and_fail;
1369 }
1370
1371 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1372
1373 if (flags & DBUS_SPAWN_SILENCE_OUTPUT)
1374 {
1375 fd_out = open ("/dev/null", O_RDONLY);
1376
1377 if (fd_out < 0)
1378 {
1379 dbus_set_error (error, _dbus_error_from_errno (errno),
1380 "Failed to open /dev/null: %s",
1381 _dbus_strerror (errno));
1382 goto cleanup_and_fail;
1383 }
1384
1385 _dbus_fd_set_close_on_exec (fd_out);
1386
1387 fd_err = _dbus_dup (fd_out, error);
1388
1389 if (fd_err < 0)
1390 goto cleanup_and_fail;
1391 }
1392 #ifdef HAVE_SYSTEMD
1393 else if (flags & DBUS_SPAWN_REDIRECT_OUTPUT)
1394 {
1395 /* This may fail, but it's not critical.
1396 * In particular, if we were compiled with journald support but are now
1397 * running on a non-systemd system, this is going to fail, so we
1398 * have to cope gracefully. */
1399 fd_out = sd_journal_stream_fd (sitter->log_name, LOG_INFO, FALSE);
1400 fd_err = sd_journal_stream_fd (sitter->log_name, LOG_WARNING, FALSE);
1401 }
1402 #endif
1403
1404 /* Make sure our output buffers aren't redundantly printed by both the
1405 * parent and the child */
1406 fflush (stdout);
1407 fflush (stderr);
1408
1409 pid = fork ();
1410
1411 if (pid < 0)
1412 {
1413 dbus_set_error (error,
1414 DBUS_ERROR_SPAWN_FORK_FAILED,
1415 "Failed to fork (%s)",
1416 _dbus_strerror (errno));
1417 goto cleanup_and_fail;
1418 }
1419 else if (pid == 0)
1420 {
1421 /* Immediate child, this is the babysitter process. */
1422 int grandchild_pid;
1423
1424 /* Be sure we crash if the parent exits
1425 * and we write to the err_report_pipe
1426 */
1427 signal (SIGPIPE, SIG_DFL);
1428
1429 /* Close the parent's end of the pipes. */
1430 close_and_invalidate (&child_err_report_pipe[READ_END]);
1431 close_and_invalidate (&babysitter_pipe[0].fd);
1432
1433 fflush (stdout);
1434 fflush (stderr);
1435
1436 /* Create the child that will exec () */
1437 grandchild_pid = fork ();
1438
1439 if (grandchild_pid < 0)
1440 {
1441 write_err_and_exit (babysitter_pipe[1].fd,
1442 CHILD_FORK_FAILED);
1443 _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
1444 }
1445 else if (grandchild_pid == 0)
1446 {
1447 #ifdef __linux__
1448 int fd = -1;
1449
1450 #ifdef O_CLOEXEC
1451 fd = open ("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
1452 #endif
1453
1454 if (fd < 0)
1455 {
1456 fd = open ("/proc/self/oom_score_adj", O_WRONLY);
1457 _dbus_fd_set_close_on_exec (fd);
1458 }
1459
1460 if (fd >= 0)
1461 {
1462 if (write (fd, "0", sizeof (char)) < 0)
1463 _dbus_warn ("writing oom_score_adj error: %s", strerror (errno));
1464 _dbus_close (fd, NULL);
1465 }
1466 #endif
1467 /* Go back to ignoring SIGPIPE, since it's evil
1468 */
1469 signal (SIGPIPE, SIG_IGN);
1470
1471 close_and_invalidate (&babysitter_pipe[1].fd);
1472
1473 /* Redirect stdout, stderr to systemd Journal or /dev/null
1474 * as requested, if possible */
1475 if (fd_out >= 0)
1476 dup2 (fd_out, STDOUT_FILENO);
1477 if (fd_err >= 0)
1478 dup2 (fd_err, STDERR_FILENO);
1479 close_and_invalidate (&fd_out);
1480 close_and_invalidate (&fd_err);
1481
1482 do_exec (child_err_report_pipe[WRITE_END],
1483 argv,
1484 env,
1485 child_setup, user_data);
1486 _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
1487 }
1488 else
1489 {
1490 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
1491 close_and_invalidate (&fd_out);
1492 close_and_invalidate (&fd_err);
1493 babysit (grandchild_pid, babysitter_pipe[1].fd);
1494 _dbus_assert_not_reached ("Got to code after babysit()");
1495 }
1496 }
1497 else
1498 {
1499 /* Close the uncared-about ends of the pipes */
1500 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
1501 close_and_invalidate (&babysitter_pipe[1].fd);
1502 close_and_invalidate (&fd_out);
1503 close_and_invalidate (&fd_err);
1504
1505 sitter->socket_to_babysitter = babysitter_pipe[0];
1506 babysitter_pipe[0].fd = -1;
1507
1508 sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
1509 child_err_report_pipe[READ_END] = -1;
1510
1511 sitter->sitter_pid = pid;
1512
1513 if (sitter_p != NULL)
1514 *sitter_p = sitter;
1515 else
1516 _dbus_babysitter_unref (sitter);
1517
1518 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1519
1520 return TRUE;
1521 }
1522
1523 cleanup_and_fail:
1524
1525 _DBUS_ASSERT_ERROR_IS_SET (error);
1526
1527 close_and_invalidate (&child_err_report_pipe[READ_END]);
1528 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
1529 close_and_invalidate (&babysitter_pipe[0].fd);
1530 close_and_invalidate (&babysitter_pipe[1].fd);
1531 close_and_invalidate (&fd_out);
1532 close_and_invalidate (&fd_err);
1533
1534 if (sitter != NULL)
1535 _dbus_babysitter_unref (sitter);
1536
1537 return FALSE;
1538 }
1539
1540 void
1541 _dbus_babysitter_set_result_function (DBusBabysitter *sitter,
1542 DBusBabysitterFinishedFunc finished,
1543 void *user_data)
1544 {
1545 sitter->finished_cb = finished;
1546 sitter->finished_data = user_data;
1547 }
1548
1551 void
1552 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
1553 {
1554 while (LIVE_CHILDREN (sitter))
1555 babysitter_iteration (sitter, TRUE);
1556 }
_dbus_babysitter_ref
DBusBabysitter * _dbus_babysitter_ref(DBusBabysitter *sitter)
Increment the reference count on the babysitter object.
Definition: dbus-spawn-unix.c:312
_dbus_watch_list_add_watch
dbus_bool_t _dbus_watch_list_add_watch(DBusWatchList *watch_list, DBusWatch *watch)
Adds a new watch to the watch list, invoking the application DBusAddWatchFunction if appropriate.
Definition: dbus-watch.c:381
_dbus_watch_list_new
DBusWatchList * _dbus_watch_list_new(void)
Creates a new watch list.
Definition: dbus-watch.c:232
_DBUS_N_ELEMENTS
#define _DBUS_N_ELEMENTS(array)
Definition: dbus-internals.h:189
DBusBabysitter::have_exec_errnum
unsigned int have_exec_errnum
True if we have an error code from exec()
Definition: dbus-spawn-unix.c:274
DBusPollFD::revents
short revents
Events that occurred.
Definition: dbus-sysdeps.h:425
READ_STATUS_OK
@ READ_STATUS_OK
Read succeeded.
Definition: dbus-spawn-unix.c:75
_dbus_babysitter_get_child_exited
dbus_bool_t _dbus_babysitter_get_child_exited(DBusBabysitter *sitter)
Checks whether the child has exited, without blocking.
Definition: dbus-spawn-unix.c:726
DBusBabysitter::have_child_status
unsigned int have_child_status
True if child status has been reaped.
Definition: dbus-spawn-unix.c:272
DBusBabysitter::status
int status
Exit status code.
Definition: dbus-spawn-unix.c:271
_dbus_error_from_errno
const char * _dbus_error_from_errno(int error_number)
Converts a UNIX errno, or Windows errno or WinSock error value into a DBusError name.
Definition: dbus-sysdeps.c:599
_dbus_watch_list_remove_watch
void _dbus_watch_list_remove_watch(DBusWatchList *watch_list, DBusWatch *watch)
Removes a watch from the watch list, invoking the application's DBusRemoveWatchFunction if appropriat...
Definition: dbus-watch.c:414
_dbus_babysitter_set_child_exit_error
void _dbus_babysitter_set_child_exit_error(DBusBabysitter *sitter, DBusError *error)
Sets the DBusError with an explanation of why the spawned child process exited (on a signal,...
Definition: dbus-spawn-unix.c:775
DBusFreeFunction
void(* DBusFreeFunction)(void *memory)
Definition: dbus-memory.h:63
DBusPollFD::events
short events
Events to poll for.
Definition: dbus-sysdeps.h:424
DBusBabysitter::log_name
char * log_name
the name under which to log messages about this process being spawned
Definition: dbus-spawn-unix.c:253
DBUS_ERROR_SPAWN_CHILD_SIGNALED
#define DBUS_ERROR_SPAWN_CHILD_SIGNALED
While starting a new process, the child exited on a signal.
Definition: dbus-protocol.h:426
DBusWatch
Implementation of DBusWatch.
Definition: dbus-watch.c:41
DBUS_ERROR_SPAWN_CHILD_EXITED
#define DBUS_ERROR_SPAWN_CHILD_EXITED
While starting a new process, the child exited with a status code.
Definition: dbus-protocol.h:424
_dbus_babysitter_set_watch_functions
dbus_bool_t _dbus_babysitter_set_watch_functions(DBusBabysitter *sitter, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function)
Sets watch functions to notify us when the babysitter object needs to read/write file descriptors.
Definition: dbus-spawn-unix.c:833
READ_STATUS_ERROR
@ READ_STATUS_ERROR
Some kind of error.
Definition: dbus-spawn-unix.c:76
DBusBabysitter::sitter_pid
pid_t sitter_pid
PID Of the babysitter.
Definition: dbus-spawn-unix.c:259
DBUS_ERROR_SPAWN_FAILED
#define DBUS_ERROR_SPAWN_FAILED
While starting a new process, something went wrong.
Definition: dbus-protocol.h:428
_dbus_dup
int _dbus_dup(int fd, DBusError *error)
Duplicates a file descriptor.
Definition: dbus-sysdeps-unix.c:3594
TRUE
#define TRUE
DBUS_WATCH_READABLE
@ DBUS_WATCH_READABLE
As in POLLIN.
Definition: dbus-connection.h:61
WRITE_END
#define WRITE_END
Helps remember which end of the pipe is which.
Definition: dbus-spawn-unix.c:895
DBUS_WATCH_ERROR
@ DBUS_WATCH_ERROR
As in POLLERR (can't watch for this, but can be present in current state passed to dbus_watch_handle(...
Definition: dbus-connection.h:63
DBUS_ERROR_FAILED
#define DBUS_ERROR_FAILED
A generic error; "something went wrong" - see the error message for more.
Definition: dbus-protocol.h:359
DBUS_ERROR_SPAWN_EXEC_FAILED
#define DBUS_ERROR_SPAWN_EXEC_FAILED
While starting a new process, the exec() call failed.
Definition: dbus-protocol.h:420
READ_STATUS_EOF
@ READ_STATUS_EOF
EOF returned.
Definition: dbus-spawn-unix.c:77
DBusAddWatchFunction
dbus_bool_t(* DBusAddWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus needs a new watch to be monitored by the main loop.
Definition: dbus-connection.h:92
_dbus_watch_unref
void _dbus_watch_unref(DBusWatch *watch)
Decrements the reference count of a DBusWatch object and finalizes the object if the count reaches ze...
Definition: dbus-watch.c:138
DBusBabysitter::error_pipe_from_child
int error_pipe_from_child
Connection to the process that does the exec()
Definition: dbus-spawn-unix.c:257
dbus_free
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:704
_DBUS_POLLERR
#define _DBUS_POLLERR
Error condition.
Definition: dbus-sysdeps.h:435
_dbus_set_signal_handler
void _dbus_set_signal_handler(int sig, DBusSignalHandler handler)
Installs a UNIX signal handler.
Definition: dbus-sysdeps-util-unix.c:540
DBusPollFD::fd
DBusPollable fd
File descriptor.
Definition: dbus-sysdeps.h:423
dbus_watch_get_socket
DBUS_EXPORT int dbus_watch_get_socket(DBusWatch *watch)
Returns a socket to be watched, on UNIX this will return -1 if our transport is not socket-based so d...
Definition: dbus-watch.c:593
DBusSocket
Socket interface.
Definition: dbus-sysdeps.h:181
DBusBabysitter
Babysitter implementation details.
Definition: dbus-spawn-unix.c:250
FALSE
#define FALSE
DBusBabysitter::error_watch
DBusWatch * error_watch
Error pipe watch.
Definition: dbus-spawn-unix.c:264
DBusPollFD
Definition: dbus-sysdeps.h:422
DBUS_ERROR_NO_MEMORY
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
Definition: dbus-protocol.h:361
DBusBabysitter::have_fork_errnum
unsigned int have_fork_errnum
True if we have an error code from fork()
Definition: dbus-spawn-unix.c:273
DBUS_ERROR_INIT
#define DBUS_ERROR_INIT
Definition: dbus-errors.h:62
_dbus_fd_set_close_on_exec
void _dbus_fd_set_close_on_exec(int fd)
Sets the file descriptor to be close on exec.
Definition: dbus-sysdeps-unix.c:3522
_dbus_poll
int _dbus_poll(DBusPollFD *fds, int n_fds, int timeout_milliseconds)
Wrapper for poll().
Definition: dbus-sysdeps-unix.c:3142
_dbus_assert_not_reached
#define _dbus_assert_not_reached(explanation)
Definition: dbus-internals.h:164
ReadStatus
ReadStatus
Enumeration for status of a read()
Definition: dbus-spawn-unix.c:74
DBusBabysitter::watches
DBusWatchList * watches
Watches.
Definition: dbus-spawn-unix.c:262
DBusWatchList
DBusWatchList implementation details.
Definition: dbus-watch.c:215
DBusBabysitter::errnum
int errnum
Error number.
Definition: dbus-spawn-unix.c:270
DBusBabysitter::grandchild_pid
pid_t grandchild_pid
PID of the grandchild.
Definition: dbus-spawn-unix.c:260
DBUS_ERROR_SPAWN_FORK_FAILED
#define DBUS_ERROR_SPAWN_FORK_FAILED
While starting a new process, the fork() call failed.
Definition: dbus-protocol.h:422
_dbus_close_socket
dbus_bool_t _dbus_close_socket(DBusSocket fd, DBusError *error)
Closes a socket.
Definition: dbus-sysdeps-unix.c:286
READ_END
#define READ_END
Helps remember which end of the pipe is which.
Definition: dbus-spawn-unix.c:893
DBusWatchToggledFunction
void(* DBusWatchToggledFunction)(DBusWatch *watch, void *data)
Called when dbus_watch_get_enabled() may return a different value than it did before.
Definition: dbus-connection.h:98
_dbus_assert
#define _dbus_assert(condition)
Definition: dbus-internals.h:153
dbus_error_free
void dbus_error_free(DBusError *error)
Frees an error that's been set (or just initialized), then reinitializes the error as in dbus_error_i...
Definition: dbus-errors.c:211
_dbus_close
dbus_bool_t _dbus_close(int fd, DBusError *error)
Closes a file descriptor.
Definition: dbus-sysdeps-unix.c:3566
_dbus_babysitter_unref
void _dbus_babysitter_unref(DBusBabysitter *sitter)
Decrement the reference count on the babysitter object.
Definition: dbus-spawn-unix.c:334
_dbus_socketpair
dbus_bool_t _dbus_socketpair(DBusSocket *fd1, DBusSocket *fd2, dbus_bool_t blocking, DBusError *error)
Creates pair of connect sockets (as in socketpair()).
Definition: dbus-sysdeps-unix.c:3723
_dbus_warn
void _dbus_warn(const char *format,...)
Prints a warning message to stderr.
Definition: dbus-internals.c:238
_dbus_strdup
char * _dbus_strdup(const char *str)
Duplicates a string.
Definition: dbus-internals.c:589
_dbus_getpid
dbus_pid_t _dbus_getpid(void)
Gets our process ID.
Definition: dbus-sysdeps-unix.c:2983
_dbus_watch_list_free
void _dbus_watch_list_free(DBusWatchList *watch_list)
Frees a DBusWatchList.
Definition: dbus-watch.c:249
DBusError
Object representing an exception.
Definition: dbus-errors.h:49
_dbus_spawn_async_with_babysitter
dbus_bool_t _dbus_spawn_async_with_babysitter(DBusBabysitter **sitter_p, const char *log_name, char *const *argv, char *const *env, DBusSpawnFlags flags, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error)
Spawns a new process.
Definition: dbus-spawn-unix.c:1271
_dbus_watch_invalidate
void _dbus_watch_invalidate(DBusWatch *watch)
Clears the file descriptor from a now-invalid watch object so that no one tries to use it.
Definition: dbus-watch.c:169
_dbus_watch_list_set_functions
dbus_bool_t _dbus_watch_list_set_functions(DBusWatchList *watch_list, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function)
Sets the watch functions.
Definition: dbus-watch.c:295
DBusBabysitter::socket_to_babysitter
DBusSocket socket_to_babysitter
Connection to the babysitter process.
Definition: dbus-spawn-unix.c:256
dbus_set_error
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError.
Definition: dbus-errors.c:354
DBUS_PID_FORMAT
#define DBUS_PID_FORMAT
an appropriate printf format for dbus_pid_t
Definition: dbus-sysdeps.h:149
_DBUS_POLLIN
#define _DBUS_POLLIN
There is data to read.
Definition: dbus-sysdeps.h:429
DBusBabysitter::sitter_watch
DBusWatch * sitter_watch
Sitter pipe watch.
Definition: dbus-spawn-unix.c:265
DBusRemoveWatchFunction
void(* DBusRemoveWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus no longer needs a watch to be monitored by the main loop.
Definition: dbus-connection.h:104
DBusBabysitter::refcount
int refcount
Reference count.
Definition: dbus-spawn-unix.c:251
LIVE_CHILDREN
#define LIVE_CHILDREN(sitter)
Macro returns TRUE if the babysitter still has live sockets open to the babysitter child or the grand...
Definition: dbus-spawn-unix.c:695
DBusError::message
const char * message
public error message field
Definition: dbus-errors.h:51
_DBUS_POLLHUP
#define _DBUS_POLLHUP
Hung up.
Definition: dbus-sysdeps.h:437
_dbus_babysitter_kill_child
void _dbus_babysitter_kill_child(DBusBabysitter *sitter)
Blocks until the babysitter process gives us the PID of the spawned grandchild, then kills the spawne...
Definition: dbus-spawn-unix.c:704
dbus_new0
#define dbus_new0(type, count)
Definition: dbus-memory.h:58
_dbus_watch_new
DBusWatch * _dbus_watch_new(DBusPollable fd, unsigned int flags, dbus_bool_t enabled, DBusWatchHandler handler, void *data, DBusFreeFunction free_data_function)
Creates a new DBusWatch.
Definition: dbus-watch.c:88
DBUS_WATCH_HANGUP
@ DBUS_WATCH_HANGUP
As in POLLHUP (can't watch for it, but can be present in current state passed to dbus_watch_handle())...
Definition: dbus-connection.h:68
_dbus_babysitter_get_child_exit_status
dbus_bool_t _dbus_babysitter_get_child_exit_status(DBusBabysitter *sitter, int *status)
Gets the exit status of the child.
Definition: dbus-spawn-unix.c:751
dbus_bool_t
dbus_uint32_t dbus_bool_t
Definition: dbus-types.h:35
NULL
#define NULL