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