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