D-Bus 1.14.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 * 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
57extern char **environ;
58#endif
59
60#ifdef HAVE_PDPLINUX
61dbus_bool_t bus_activation_pdplinux_set_proc_label(void* actdata, DBusConnection* connection, pid_t pid);
62#endif
63
69/*
70 * I'm pretty sure this whole spawn file could be made simpler,
71 * if you thought about it a bit.
72 */
73
77typedef enum
78{
83
84static ReadStatus
85read_ints (int fd,
86 int *buf,
87 int n_ints_in_buf,
88 int *n_ints_read,
89 DBusError *error)
90{
91 size_t bytes = 0;
92 ReadStatus retval;
93
94 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
95
96 retval = READ_STATUS_OK;
97
98 while (TRUE)
99 {
100 ssize_t chunk;
101 size_t to_read;
102
103 to_read = sizeof (int) * n_ints_in_buf - bytes;
104
105 if (to_read == 0)
106 break;
107
108 again:
109
110 chunk = read (fd,
111 ((char*)buf) + bytes,
112 to_read);
113
114 if (chunk < 0 && errno == EINTR)
115 goto again;
116
117 if (chunk < 0)
118 {
119 dbus_set_error (error,
121 "Failed to read from child pipe (%s)",
122 _dbus_strerror (errno));
123
124 retval = READ_STATUS_ERROR;
125 break;
126 }
127 else if (chunk == 0)
128 {
129 retval = READ_STATUS_EOF;
130 break; /* EOF */
131 }
132 else /* chunk > 0 */
133 bytes += chunk;
134 }
135
136 *n_ints_read = (int)(bytes / sizeof(int));
137
138 return retval;
139}
140
141static ReadStatus
142read_pid (int fd,
143 pid_t *buf,
144 DBusError *error)
145{
146 size_t bytes = 0;
147 ReadStatus retval;
148
149 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
150
151 retval = READ_STATUS_OK;
152
153 while (TRUE)
154 {
155 ssize_t chunk;
156 size_t to_read;
157
158 to_read = sizeof (pid_t) - bytes;
159
160 if (to_read == 0)
161 break;
162
163 again:
164
165 chunk = read (fd,
166 ((char*)buf) + bytes,
167 to_read);
168 if (chunk < 0 && errno == EINTR)
169 goto again;
170
171 if (chunk < 0)
172 {
173 dbus_set_error (error,
175 "Failed to read from child pipe (%s)",
176 _dbus_strerror (errno));
177
178 retval = READ_STATUS_ERROR;
179 break;
180 }
181 else if (chunk == 0)
182 {
183 retval = READ_STATUS_EOF;
184 break; /* EOF */
185 }
186 else /* chunk > 0 */
187 bytes += chunk;
188 }
189
190 return retval;
191}
192
193/* The implementation uses an intermediate child between the main process
194 * and the grandchild. The grandchild is our spawned process. The intermediate
195 * child is a babysitter process; it keeps track of when the grandchild
196 * exits/crashes, and reaps the grandchild.
197 *
198 * We automatically reap the babysitter process, killing it if necessary,
199 * when the DBusBabysitter's refcount goes to zero.
200 *
201 * Processes:
202 *
203 * main process
204 * | fork() A
205 * \- babysitter
206 * | fork () B
207 * \- grandchild --> exec --> spawned process
208 *
209 * IPC:
210 * child_err_report_pipe
211 * /-----------<---------<--------------\
212 * | ^
213 * v |
214 * main process babysitter grandchild
215 * ^ ^
216 * v v
217 * \-------<->-------/
218 * babysitter_pipe
219 *
220 * child_err_report_pipe is genuinely a pipe.
221 * The READ_END (also called error_pipe_from_child) is used in the main
222 * process. The WRITE_END (also called child_err_report_fd) is used in
223 * the grandchild process.
224 *
225 * On failure, the grandchild process sends CHILD_EXEC_FAILED + errno.
226 * On success, the pipe just closes (because it's close-on-exec) without
227 * sending any bytes.
228 *
229 * babysitter_pipe is mis-named: it's really a bidirectional socketpair.
230 * The [0] end (also called socket_to_babysitter) is used in the main
231 * process, the [1] end (also called parent_pipe) is used in the babysitter.
232 *
233 * If the fork() labelled B in the diagram above fails, the babysitter sends
234 * CHILD_FORK_FAILED + errno.
235 * On success, the babysitter sends CHILD_PID + the grandchild's pid.
236 * On SIGCHLD, the babysitter sends CHILD_EXITED + the exit status.
237 * The main process doesn't explicitly send anything, but when it exits,
238 * the babysitter gets POLLHUP or POLLERR.
239 */
240
241/* Messages from children to parents */
242enum
243{
244 CHILD_EXITED, /* This message is followed by the exit status int */
245 CHILD_FORK_FAILED, /* Followed by errno */
246 CHILD_EXEC_FAILED, /* Followed by errno */
247 CHILD_PID /* Followed by pid_t */
248};
249
254{
257 char *log_name;
271 DBusBabysitterFinishedFunc finished_cb;
272 void *finished_data;
273
274 int errnum;
275 int status;
276 unsigned int have_child_status : 1;
277 unsigned int have_fork_errnum : 1;
278 unsigned int have_exec_errnum : 1;
279};
280
281static DBusBabysitter*
282_dbus_babysitter_new (void)
283{
284 DBusBabysitter *sitter;
285
286 sitter = dbus_new0 (DBusBabysitter, 1);
287 if (sitter == NULL)
288 return NULL;
289
290 sitter->refcount = 1;
291
292 sitter->socket_to_babysitter.fd = -1;
293 sitter->error_pipe_from_child = -1;
294
295 sitter->sitter_pid = -1;
296 sitter->grandchild_pid = -1;
297
298 sitter->watches = _dbus_watch_list_new ();
299 if (sitter->watches == NULL)
300 goto failed;
301
302 return sitter;
303
304 failed:
305 _dbus_babysitter_unref (sitter);
306 return NULL;
307}
308
317{
318 _dbus_assert (sitter != NULL);
319 _dbus_assert (sitter->refcount > 0);
320
321 sitter->refcount += 1;
322
323 return sitter;
324}
325
326static void close_socket_to_babysitter (DBusBabysitter *sitter);
327static void close_error_pipe_from_child (DBusBabysitter *sitter);
328
337void
339{
340 _dbus_assert (sitter != NULL);
341 _dbus_assert (sitter->refcount > 0);
342
343 sitter->refcount -= 1;
344 if (sitter->refcount == 0)
345 {
346 /* If we haven't forked other babysitters
347 * since this babysitter and socket were
348 * created then this close will cause the
349 * babysitter to wake up from poll with
350 * a hangup and then the babysitter will
351 * quit itself.
352 */
353 close_socket_to_babysitter (sitter);
354
355 close_error_pipe_from_child (sitter);
356
357 if (sitter->sitter_pid > 0)
358 {
359 int status;
360 int ret;
361
362 /* It's possible the babysitter died on its own above
363 * from the close, or was killed randomly
364 * by some other process, so first try to reap it
365 */
366 ret = waitpid (sitter->sitter_pid, &status, WNOHANG);
367
368 /* If we couldn't reap the child then kill it, and
369 * try again
370 */
371 if (ret == 0)
372 kill (sitter->sitter_pid, SIGKILL);
373
374 if (ret == 0)
375 {
376 do
377 {
378 ret = waitpid (sitter->sitter_pid, &status, 0);
379 }
380 while (_DBUS_UNLIKELY (ret < 0 && errno == EINTR));
381 }
382
383 if (ret < 0)
384 {
385 if (errno == ECHILD)
386 _dbus_warn ("Babysitter process not available to be reaped; should not happen");
387 else
388 _dbus_warn ("Unexpected error %d in waitpid() for babysitter: %s",
389 errno, _dbus_strerror (errno));
390 }
391 else
392 {
393 _dbus_verbose ("Reaped %ld, waiting for babysitter %ld\n",
394 (long) ret, (long) sitter->sitter_pid);
395
396 if (WIFEXITED (sitter->status))
397 _dbus_verbose ("Babysitter exited with status %d\n",
398 WEXITSTATUS (sitter->status));
399 else if (WIFSIGNALED (sitter->status))
400 _dbus_verbose ("Babysitter received signal %d\n",
401 WTERMSIG (sitter->status));
402 else
403 _dbus_verbose ("Babysitter exited abnormally\n");
404 }
405
406 sitter->sitter_pid = -1;
407 }
408
409 if (sitter->watches)
411
412 dbus_free (sitter->log_name);
413
414 dbus_free (sitter);
415 }
416}
417
418static ReadStatus
419read_data (DBusBabysitter *sitter,
420 int fd)
421{
422 int what;
423 int got;
425 ReadStatus r;
426
427 r = read_ints (fd, &what, 1, &got, &error);
428
429 switch (r)
430 {
432 _dbus_warn ("Failed to read data from fd %d: %s", fd, error.message);
433 dbus_error_free (&error);
434 return r;
435
436 case READ_STATUS_EOF:
437 return r;
438
439 case READ_STATUS_OK:
440 break;
441
442 default:
443 _dbus_assert_not_reached ("invalid ReadStatus");
444 break;
445 }
446
447 if (got == 1)
448 {
449 switch (what)
450 {
451 case CHILD_EXITED:
452 case CHILD_FORK_FAILED:
453 case CHILD_EXEC_FAILED:
454 {
455 int arg;
456
457 r = read_ints (fd, &arg, 1, &got, &error);
458
459 switch (r)
460 {
462 _dbus_warn ("Failed to read arg from fd %d: %s", fd, error.message);
463 dbus_error_free (&error);
464 return r;
465 case READ_STATUS_EOF:
466 return r;
467 case READ_STATUS_OK:
468 break;
469 default:
470 _dbus_assert_not_reached ("invalid ReadStatus");
471 break;
472 }
473
474 if (got == 1)
475 {
476 if (what == CHILD_EXITED)
477 {
478 /* Do not reset sitter->errnum to 0 here. We get here if
479 * the babysitter reports that the grandchild process has
480 * exited, and there are two ways that can happen:
481 *
482 * 1. grandchild successfully exec()s the desired process,
483 * but then the desired process exits or is terminated
484 * by a signal. The babysitter observes this and reports
485 * CHILD_EXITED.
486 *
487 * 2. grandchild fails to exec() the desired process,
488 * attempts to report the exec() failure (which
489 * we will receive as CHILD_EXEC_FAILED), and then
490 * exits itself (which will prompt the babysitter to
491 * send CHILD_EXITED). We want the CHILD_EXEC_FAILED
492 * to take precedence (and have its errno logged),
493 * which _dbus_babysitter_set_child_exit_error() does.
494 */
495 sitter->have_child_status = TRUE;
496 sitter->status = arg;
497 _dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n",
498 WIFEXITED (sitter->status), WIFSIGNALED (sitter->status),
499 WEXITSTATUS (sitter->status), WTERMSIG (sitter->status));
500 }
501 else if (what == CHILD_FORK_FAILED)
502 {
503 sitter->have_fork_errnum = TRUE;
504 sitter->errnum = arg;
505 _dbus_verbose ("recorded fork errnum %d\n", sitter->errnum);
506 }
507 else if (what == CHILD_EXEC_FAILED)
508 {
509 sitter->have_exec_errnum = TRUE;
510 sitter->errnum = arg;
511 _dbus_verbose ("recorded exec errnum %d\n", sitter->errnum);
512 }
513 }
514 }
515 break;
516 case CHILD_PID:
517 {
518 pid_t pid = -1;
519
520 r = read_pid (fd, &pid, &error);
521
522 switch (r)
523 {
525 _dbus_warn ("Failed to read PID from fd %d: %s", fd, error.message);
526 dbus_error_free (&error);
527 return r;
528 case READ_STATUS_EOF:
529 return r;
530 case READ_STATUS_OK:
531 break;
532 default:
533 _dbus_assert_not_reached ("invalid ReadStatus");
534 break;
535 }
536
537 sitter->grandchild_pid = pid;
538
539 _dbus_verbose ("recorded grandchild pid %d\n", sitter->grandchild_pid);
540 }
541 break;
542 default:
543 _dbus_warn ("Unknown message received from babysitter process");
544 break;
545 }
546 }
547
548 return r;
549}
550
551static void
552close_socket_to_babysitter (DBusBabysitter *sitter)
553{
554 _dbus_verbose ("Closing babysitter\n");
555
556 if (sitter->sitter_watch != NULL)
557 {
558 _dbus_assert (sitter->watches != NULL);
562 sitter->sitter_watch = NULL;
563 }
564
565 if (sitter->socket_to_babysitter.fd >= 0)
566 {
568 sitter->socket_to_babysitter.fd = -1;
569 }
570}
571
572static void
573close_error_pipe_from_child (DBusBabysitter *sitter)
574{
575 _dbus_verbose ("Closing child error\n");
576
577 if (sitter->error_watch != NULL)
578 {
579 _dbus_assert (sitter->watches != NULL);
583 sitter->error_watch = NULL;
584 }
585
586 if (sitter->error_pipe_from_child >= 0)
587 {
589 sitter->error_pipe_from_child = -1;
590 }
591}
592
593static void
594handle_babysitter_socket (DBusBabysitter *sitter,
595 int revents)
596{
597 /* Even if we have POLLHUP, we want to keep reading
598 * data until POLLIN goes away; so this function only
599 * looks at HUP/ERR if no IN is set.
600 */
601 if (revents & _DBUS_POLLIN)
602 {
603 _dbus_verbose ("Reading data from babysitter\n");
604 if (read_data (sitter, sitter->socket_to_babysitter.fd) != READ_STATUS_OK)
605 close_socket_to_babysitter (sitter);
606 }
607 else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
608 {
609 close_socket_to_babysitter (sitter);
610 }
611}
612
613static void
614handle_error_pipe (DBusBabysitter *sitter,
615 int revents)
616{
617 if (revents & _DBUS_POLLIN)
618 {
619 _dbus_verbose ("Reading data from child error\n");
620 if (read_data (sitter, sitter->error_pipe_from_child) != READ_STATUS_OK)
621 close_error_pipe_from_child (sitter);
622 }
623 else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
624 {
625 close_error_pipe_from_child (sitter);
626 }
627}
628
629/* returns whether there were any poll events handled */
630static dbus_bool_t
631babysitter_iteration (DBusBabysitter *sitter,
632 dbus_bool_t block)
633{
634 DBusPollFD fds[2];
635 int i;
636 dbus_bool_t descriptors_ready;
637
638 descriptors_ready = FALSE;
639
640 i = 0;
641
642 if (sitter->error_pipe_from_child >= 0)
643 {
644 fds[i].fd = sitter->error_pipe_from_child;
645 fds[i].events = _DBUS_POLLIN;
646 fds[i].revents = 0;
647 ++i;
648 }
649
650 if (sitter->socket_to_babysitter.fd >= 0)
651 {
652 fds[i].fd = sitter->socket_to_babysitter.fd;
653 fds[i].events = _DBUS_POLLIN;
654 fds[i].revents = 0;
655 ++i;
656 }
657
658 if (i > 0)
659 {
660 int ret;
661
662 do
663 {
664 ret = _dbus_poll (fds, i, 0);
665 }
666 while (ret < 0 && errno == EINTR);
667
668 if (ret == 0 && block)
669 {
670 do
671 {
672 ret = _dbus_poll (fds, i, -1);
673 }
674 while (ret < 0 && errno == EINTR);
675 }
676
677 if (ret > 0)
678 {
679 descriptors_ready = TRUE;
680
681 while (i > 0)
682 {
683 --i;
684 if (fds[i].fd == sitter->error_pipe_from_child)
685 handle_error_pipe (sitter, fds[i].revents);
686 else if (fds[i].fd == sitter->socket_to_babysitter.fd)
687 handle_babysitter_socket (sitter, fds[i].revents);
688 }
689 }
690 }
691
692 return descriptors_ready;
693}
694
699#define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter.fd >= 0 || (sitter)->error_pipe_from_child >= 0)
700
707void
709{
710 /* be sure we have the PID of the child */
711 while (LIVE_CHILDREN (sitter) &&
712 sitter->grandchild_pid == -1)
713 babysitter_iteration (sitter, TRUE);
714
715 _dbus_verbose ("Got child PID %ld for killing\n",
716 (long) sitter->grandchild_pid);
717
718 if (sitter->grandchild_pid == -1)
719 return; /* child is already dead, or we're so hosed we'll never recover */
720
721 kill (sitter->grandchild_pid, SIGKILL);
722}
723
731{
732
733 /* Be sure we're up-to-date */
734 while (LIVE_CHILDREN (sitter) &&
735 babysitter_iteration (sitter, FALSE))
736 ;
737
738 /* We will have exited the babysitter when the child has exited */
739 return sitter->socket_to_babysitter.fd < 0;
740}
741
756 int *status)
757{
759 _dbus_assert_not_reached ("Child has not exited");
760
761 if (!sitter->have_child_status ||
762 !(WIFEXITED (sitter->status)))
763 return FALSE;
764
765 *status = WEXITSTATUS (sitter->status);
766 return TRUE;
767}
768
778void
780 DBusError *error)
781{
783 return;
784
785 /* Note that if exec fails, we will also get a child status
786 * from the babysitter saying the child exited,
787 * so we need to give priority to the exec error
788 */
789 if (sitter->have_exec_errnum)
790 {
792 "Failed to execute program %s: %s",
793 sitter->log_name, _dbus_strerror (sitter->errnum));
794 }
795 else if (sitter->have_fork_errnum)
796 {
798 "Failed to fork a new process %s: %s",
799 sitter->log_name, _dbus_strerror (sitter->errnum));
800 }
801 else if (sitter->have_child_status)
802 {
803 if (WIFEXITED (sitter->status))
805 "Process %s exited with status %d",
806 sitter->log_name, WEXITSTATUS (sitter->status));
807 else if (WIFSIGNALED (sitter->status))
809 "Process %s received signal %d",
810 sitter->log_name, WTERMSIG (sitter->status));
811 else
813 "Process %s exited abnormally",
814 sitter->log_name);
815 }
816 else
817 {
819 "Process %s exited, reason unknown",
820 sitter->log_name);
821 }
822}
823
838 DBusAddWatchFunction add_function,
839 DBusRemoveWatchFunction remove_function,
840 DBusWatchToggledFunction toggled_function,
841 void *data,
842 DBusFreeFunction free_data_function)
843{
845 add_function,
846 remove_function,
847 toggled_function,
848 data,
849 free_data_function);
850}
851
852static dbus_bool_t
853handle_watch (DBusWatch *watch,
854 unsigned int condition,
855 void *data)
856{
857 DBusBabysitter *sitter = _dbus_babysitter_ref (data);
858 int revents;
859 int fd;
860
861 revents = 0;
862 if (condition & DBUS_WATCH_READABLE)
863 revents |= _DBUS_POLLIN;
864 if (condition & DBUS_WATCH_ERROR)
865 revents |= _DBUS_POLLERR;
866 if (condition & DBUS_WATCH_HANGUP)
867 revents |= _DBUS_POLLHUP;
868
869 fd = dbus_watch_get_socket (watch);
870
871 if (fd == sitter->error_pipe_from_child)
872 handle_error_pipe (sitter, revents);
873 else if (fd == sitter->socket_to_babysitter.fd)
874 handle_babysitter_socket (sitter, revents);
875
876 while (LIVE_CHILDREN (sitter) &&
877 babysitter_iteration (sitter, FALSE))
878 ;
879
880 /* fd.o #32992: if the handle_* methods closed their sockets, they previously
881 * didn't always remove the watches. Check that we don't regress. */
882 _dbus_assert (sitter->socket_to_babysitter.fd != -1 || sitter->sitter_watch == NULL);
883 _dbus_assert (sitter->error_pipe_from_child != -1 || sitter->error_watch == NULL);
884
886 sitter->finished_cb != NULL)
887 {
888 sitter->finished_cb (sitter, sitter->finished_data);
889 sitter->finished_cb = NULL;
890 }
891
892 _dbus_babysitter_unref (sitter);
893 return TRUE;
894}
895
897#define READ_END 0
899#define WRITE_END 1
900
901
902/* Avoids a danger in re-entrant situations (calling close()
903 * on a file descriptor twice, and another module has
904 * re-opened it since the first close).
905 *
906 * This previously claimed to be relevant for threaded situations, but by
907 * trivial inspection, it is not thread-safe. It doesn't actually
908 * matter, since this module is only used in the -util variant of the
909 * library, which is only used in single-threaded situations.
910 */
911static int
912close_and_invalidate (int *fd)
913{
914 int ret;
915
916 if (*fd < 0)
917 return -1;
918 else
919 {
920 ret = _dbus_close (*fd, NULL);
921 *fd = -1;
922 }
923
924 return ret;
925}
926
927static dbus_bool_t
928make_pipe (int p[2],
929 DBusError *error)
930{
931 int retval;
932
933#ifdef HAVE_PIPE2
934 dbus_bool_t cloexec_done;
935
936 retval = pipe2 (p, O_CLOEXEC);
937 cloexec_done = retval >= 0;
938
939 /* Check if kernel seems to be too old to know pipe2(). We assume
940 that if pipe2 is available, O_CLOEXEC is too. */
941 if (retval < 0 && errno == ENOSYS)
942#endif
943 {
944 retval = pipe(p);
945 }
946
947 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
948
949 if (retval < 0)
950 {
951 dbus_set_error (error,
953 "Failed to create pipe for communicating with child process (%s)",
954 _dbus_strerror (errno));
955 return FALSE;
956 }
957
958#ifdef HAVE_PIPE2
959 if (!cloexec_done)
960#endif
961 {
964 }
965
966 return TRUE;
967}
968
969static void
970do_write (int fd, const void *buf, size_t count)
971{
972 size_t bytes_written;
973 int ret;
974
975 bytes_written = 0;
976
977 again:
978
979 ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written);
980
981 if (ret < 0)
982 {
983 if (errno == EINTR)
984 goto again;
985 else
986 {
987 _dbus_warn ("Failed to write data to pipe!");
988 exit (1); /* give up, we suck */
989 }
990 }
991 else
992 bytes_written += ret;
993
994 if (bytes_written < count)
995 goto again;
996}
997
998static void write_err_and_exit (int fd, int msg) _DBUS_GNUC_NORETURN;
999
1000static void
1001write_err_and_exit (int fd, int msg)
1002{
1003 int en = errno;
1004
1005 do_write (fd, &msg, sizeof (msg));
1006 do_write (fd, &en, sizeof (en));
1007
1008 exit (1);
1009}
1010
1011static void
1012write_pid (int fd, pid_t pid)
1013{
1014 int msg = CHILD_PID;
1015
1016 do_write (fd, &msg, sizeof (msg));
1017 do_write (fd, &pid, sizeof (pid));
1018}
1019
1020static void write_status_and_exit (int fd, int status) _DBUS_GNUC_NORETURN;
1021
1022static void
1023write_status_and_exit (int fd, int status)
1024{
1025 int msg = CHILD_EXITED;
1026
1027 do_write (fd, &msg, sizeof (msg));
1028 do_write (fd, &status, sizeof (status));
1029
1030 exit (0);
1031}
1032
1033static void do_exec (int child_err_report_fd,
1034 char * const *argv,
1035 char * const *envp,
1036 DBusSpawnChildSetupFunc child_setup,
1037 void *user_data) _DBUS_GNUC_NORETURN;
1038
1039static void
1040do_exec (int child_err_report_fd,
1041 char * const *argv,
1042 char * const *envp,
1043 DBusSpawnChildSetupFunc child_setup,
1044 void *user_data)
1045{
1046#ifdef DBUS_ENABLE_EMBEDDED_TESTS
1047 int i, max_open;
1048#endif
1049
1050 _dbus_verbose_reset ();
1051 _dbus_verbose ("Child process has PID " DBUS_PID_FORMAT "\n",
1052 _dbus_getpid ());
1053
1054 if (child_setup)
1055 (* child_setup) (user_data);
1056
1057#ifdef DBUS_ENABLE_EMBEDDED_TESTS
1058 max_open = sysconf (_SC_OPEN_MAX);
1059
1060 for (i = 3; i < max_open; i++)
1061 {
1062 int retval;
1063
1064 if (i == child_err_report_fd)
1065 continue;
1066
1067 retval = fcntl (i, F_GETFD);
1068
1069 if (retval != -1 && !(retval & FD_CLOEXEC))
1070 {
1071 char description[256] = { 0 };
1072 char proc_self_fd[256] = { 0 };
1073 size_t description_length = sizeof (description) - 1;
1074
1075 snprintf (proc_self_fd, sizeof (proc_self_fd) - 1,
1076 "/proc/self/fd/%d", i);
1077 proc_self_fd[sizeof (proc_self_fd) - 1] = '\0';
1078
1079 if (readlink (proc_self_fd, description, description_length) <= 0)
1080 snprintf (description, sizeof (description) - 1, "(unknown)");
1081
1082 description[sizeof (description) - 1] = '\0';
1083 _dbus_warn ("Fd %d \"%s\" did not have the close-on-exec flag set!",
1084 i, description);
1085 }
1086 }
1087#endif
1088
1089 if (envp == NULL)
1090 {
1091 _dbus_assert (environ != NULL);
1092
1093 envp = environ;
1094 }
1095
1096#ifdef HAVE_PDPLINUX
1097 {
1098 PDPL_T* pdpl=NULL;
1099 pdpl=pdp_get_current();
1100
1101 if (pdpl){
1102 _dbus_pdplinux_show_text_label_info2("New process (i.e. current) label",pdpl);
1103 _dbus_verbose("New process UID=%d\n", getuid());
1104 pdpl_put(pdpl);
1105 }
1106
1107 _dbus_verbose("New process name %s\n", argv[0]);
1108 _dbus_verbose("parameter 1 for execve (%s)\n", argv[1]);
1109 }
1110#endif
1111
1112 execve (argv[0], argv, envp);
1113
1114 /* Exec failed */
1115#if defined HAVE_PDPLINUX && defined DBUS_ENABLE_VERBOSE_MODE
1116 _dbus_verbose("Exec failed\n");
1117#endif
1118
1119 write_err_and_exit (child_err_report_fd,
1120 CHILD_EXEC_FAILED);
1121}
1122
1123static void
1124check_babysit_events (pid_t grandchild_pid,
1125 int parent_pipe,
1126 int revents)
1127{
1128 pid_t ret;
1129 int status;
1130
1131 do
1132 {
1133 ret = waitpid (grandchild_pid, &status, WNOHANG);
1134 /* The man page says EINTR can't happen with WNOHANG,
1135 * but there are reports of it (maybe only with valgrind?)
1136 */
1137 }
1138 while (ret < 0 && errno == EINTR);
1139
1140 if (ret == 0)
1141 {
1142 _dbus_verbose ("no child exited\n");
1143
1144 ; /* no child exited */
1145 }
1146 else if (ret < 0)
1147 {
1148 /* This isn't supposed to happen. */
1149 _dbus_warn ("unexpected waitpid() failure in check_babysit_events(): %s",
1150 _dbus_strerror (errno));
1151 exit (1);
1152 }
1153 else if (ret == grandchild_pid)
1154 {
1155 /* Child exited */
1156 _dbus_verbose ("reaped child pid %ld\n", (long) ret);
1157
1158 write_status_and_exit (parent_pipe, status);
1159 }
1160 else
1161 {
1162 _dbus_warn ("waitpid() reaped pid %d that we've never heard of",
1163 (int) ret);
1164 exit (1);
1165 }
1166
1167 if (revents & _DBUS_POLLIN)
1168 {
1169 _dbus_verbose ("babysitter got POLLIN from parent pipe\n");
1170 }
1171
1172 if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
1173 {
1174 /* Parent is gone, so we just exit */
1175 _dbus_verbose ("babysitter got POLLERR or POLLHUP from parent\n");
1176 exit (0);
1177 }
1178}
1179
1180/* Only used in a single-threaded child process, does not need to be
1181 * thread-safe */
1182static int babysit_sigchld_pipe = -1;
1183
1184static void
1185babysit_signal_handler (int signo)
1186{
1187 /* Signal handlers that might set errno must save and restore the errno
1188 * that the interrupted function might have been relying on. */
1189 int saved_errno = errno;
1190 char b = '\0';
1191
1192 again:
1193 if (write (babysit_sigchld_pipe, &b, 1) <= 0)
1194 if (errno == EINTR)
1195 goto again;
1196
1197 errno = saved_errno;
1198}
1199
1200static void babysit (pid_t grandchild_pid,
1201 int parent_pipe) _DBUS_GNUC_NORETURN;
1202
1203static void
1204babysit (pid_t grandchild_pid,
1205 int parent_pipe)
1206{
1207 int sigchld_pipe[2];
1208
1209 /* We don't exec, so we keep parent state, such as the pid that
1210 * _dbus_verbose() uses. Reset the pid here.
1211 */
1212 _dbus_verbose_reset ();
1213
1214 /* I thought SIGCHLD would just wake up the poll, but
1215 * that didn't seem to work, so added this pipe.
1216 * Probably the pipe is more likely to work on busted
1217 * operating systems anyhow.
1218 */
1219 if (pipe (sigchld_pipe) < 0)
1220 {
1221 _dbus_warn ("Not enough file descriptors to create pipe in babysitter process");
1222 exit (1);
1223 }
1224
1225 babysit_sigchld_pipe = sigchld_pipe[WRITE_END];
1226
1227 _dbus_set_signal_handler (SIGCHLD, babysit_signal_handler);
1228
1229 write_pid (parent_pipe, grandchild_pid);
1230
1231 check_babysit_events (grandchild_pid, parent_pipe, 0);
1232
1233 while (TRUE)
1234 {
1235 DBusPollFD pfds[2];
1236
1237 pfds[0].fd = parent_pipe;
1238 pfds[0].events = _DBUS_POLLIN;
1239 pfds[0].revents = 0;
1240
1241 pfds[1].fd = sigchld_pipe[READ_END];
1242 pfds[1].events = _DBUS_POLLIN;
1243 pfds[1].revents = 0;
1244
1245 if (_dbus_poll (pfds, _DBUS_N_ELEMENTS (pfds), -1) < 0 && errno != EINTR)
1246 {
1247 _dbus_warn ("_dbus_poll() error: %s", strerror (errno));
1248 exit (1);
1249 }
1250
1251 if (pfds[0].revents != 0)
1252 {
1253 check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents);
1254 }
1255 else if (pfds[1].revents & _DBUS_POLLIN)
1256 {
1257 char b;
1258 if (read (sigchld_pipe[READ_END], &b, 1) == -1)
1259 {
1260 /* ignore */
1261 }
1262 /* do waitpid check */
1263 check_babysit_events (grandchild_pid, parent_pipe, 0);
1264 }
1265 }
1266
1267 exit (1);
1268}
1269
1296 const char *log_name,
1297 char * const *argv,
1298 char * const *env,
1299 DBusSpawnFlags flags,
1300 DBusSpawnChildSetupFunc child_setup,
1301 void *user_data,
1302 DBusError *error
1303#ifdef HAVE_PDPLINUX
1304 ,DBusConnection* connection)
1305#else
1306 )
1307#endif
1308{
1309 DBusBabysitter *sitter;
1310 int child_err_report_pipe[2] = { -1, -1 };
1311 DBusSocket babysitter_pipe[2] = { DBUS_SOCKET_INIT, DBUS_SOCKET_INIT };
1312 pid_t pid;
1313 int fd_out = -1;
1314 int fd_err = -1;
1315
1316 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1317 _dbus_assert (argv[0] != NULL);
1318
1319 if (sitter_p != NULL)
1320 *sitter_p = NULL;
1321
1322 sitter = NULL;
1323
1324 sitter = _dbus_babysitter_new ();
1325 if (sitter == NULL)
1326 {
1328 return FALSE;
1329 }
1330
1331 sitter->log_name = _dbus_strdup (log_name);
1332 if (sitter->log_name == NULL && log_name != NULL)
1333 {
1335 goto cleanup_and_fail;
1336 }
1337
1338 if (sitter->log_name == NULL)
1339 sitter->log_name = _dbus_strdup (argv[0]);
1340
1341 if (sitter->log_name == NULL)
1342 {
1344 goto cleanup_and_fail;
1345 }
1346
1347 if (!make_pipe (child_err_report_pipe, error))
1348 goto cleanup_and_fail;
1349
1350 if (!_dbus_socketpair (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
1351 goto cleanup_and_fail;
1352
1353 /* Setting up the babysitter is only useful in the parent,
1354 * but we don't want to run out of memory and fail
1355 * after we've already forked, since then we'd leak
1356 * child processes everywhere.
1357 */
1358 sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
1360 TRUE, handle_watch, sitter, NULL);
1361 if (sitter->error_watch == NULL)
1362 {
1364 goto cleanup_and_fail;
1365 }
1366
1367 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->error_watch))
1368 {
1369 /* we need to free it early so the destructor won't try to remove it
1370 * without it having been added, which DBusLoop doesn't allow */
1373 sitter->error_watch = NULL;
1374
1376 goto cleanup_and_fail;
1377 }
1378
1379 sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0].fd,
1381 TRUE, handle_watch, sitter, NULL);
1382 if (sitter->sitter_watch == NULL)
1383 {
1385 goto cleanup_and_fail;
1386 }
1387
1388 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
1389 {
1390 /* we need to free it early so the destructor won't try to remove it
1391 * without it having been added, which DBusLoop doesn't allow */
1394 sitter->sitter_watch = NULL;
1395
1397 goto cleanup_and_fail;
1398 }
1399
1400 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1401
1402 if (flags & DBUS_SPAWN_SILENCE_OUTPUT)
1403 {
1404 fd_out = open ("/dev/null", O_RDONLY);
1405
1406 if (fd_out < 0)
1407 {
1408 dbus_set_error (error, _dbus_error_from_errno (errno),
1409 "Failed to open /dev/null: %s",
1410 _dbus_strerror (errno));
1411 goto cleanup_and_fail;
1412 }
1413
1415
1416 fd_err = _dbus_dup (fd_out, error);
1417
1418 if (fd_err < 0)
1419 goto cleanup_and_fail;
1420 }
1421#ifdef HAVE_SYSTEMD
1422 else if (flags & DBUS_SPAWN_REDIRECT_OUTPUT)
1423 {
1424 /* This may fail, but it's not critical.
1425 * In particular, if we were compiled with journald support but are now
1426 * running on a non-systemd system, this is going to fail, so we
1427 * have to cope gracefully. */
1428 fd_out = sd_journal_stream_fd (sitter->log_name, LOG_INFO, FALSE);
1429 fd_err = sd_journal_stream_fd (sitter->log_name, LOG_WARNING, FALSE);
1430 }
1431#endif
1432
1433 /* Make sure our output buffers aren't redundantly printed by both the
1434 * parent and the child */
1435 fflush (stdout);
1436 fflush (stderr);
1437
1438 pid = fork ();
1439
1440 if (pid < 0)
1441 {
1442 dbus_set_error (error,
1444 "Failed to fork (%s)",
1445 _dbus_strerror (errno));
1446 goto cleanup_and_fail;
1447 }
1448 else if (pid == 0)
1449 {
1450 /* Immediate child, this is the babysitter process. */
1451 int grandchild_pid;
1452
1453 /* Be sure we crash if the parent exits
1454 * and we write to the err_report_pipe
1455 */
1456 signal (SIGPIPE, SIG_DFL);
1457
1458 /* Close the parent's end of the pipes. */
1459 close_and_invalidate (&child_err_report_pipe[READ_END]);
1460 close_and_invalidate (&babysitter_pipe[0].fd);
1461
1462 fflush (stdout);
1463 fflush (stderr);
1464
1465 /* Create the child that will exec () */
1466 grandchild_pid = fork ();
1467
1468 if (grandchild_pid < 0)
1469 {
1470 write_err_and_exit (babysitter_pipe[1].fd,
1471 CHILD_FORK_FAILED);
1472 _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
1473 }
1474 else if (grandchild_pid == 0)
1475 {
1476 /* This might not succeed in a dbus-daemon that started as root
1477 * and dropped privileges, so don't log an error on failure.
1478 * (Also, we can't safely log errors here anyway, because logging
1479 * is not async-signal safe). */
1481
1482 /* Go back to ignoring SIGPIPE, since it's evil
1483 */
1484 signal (SIGPIPE, SIG_IGN);
1485
1486 close_and_invalidate (&babysitter_pipe[1].fd);
1487
1488 /* Redirect stdout, stderr to systemd Journal or /dev/null
1489 * as requested, if possible */
1490 if (fd_out >= 0)
1491 dup2 (fd_out, STDOUT_FILENO);
1492 if (fd_err >= 0)
1493 dup2 (fd_err, STDERR_FILENO);
1494 close_and_invalidate (&fd_out);
1495 close_and_invalidate (&fd_err);
1496
1497 do_exec (child_err_report_pipe[WRITE_END],
1498 argv,
1499 env,
1500 child_setup, user_data);
1501 _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
1502 }
1503 else
1504 {
1505
1506#ifdef HAVE_PDPLINUX
1507 _dbus_verbose("We are on babysitter !\n");
1508 if(bus_activation_pdplinux_set_proc_label(user_data,connection,(pid_t)grandchild_pid))
1509 _dbus_verbose("Set process label success\n");
1510 else
1511 _dbus_verbose("Set process label failed or skipped\n");
1512#endif
1513
1514 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
1515 close_and_invalidate (&fd_out);
1516 close_and_invalidate (&fd_err);
1517 babysit (grandchild_pid, babysitter_pipe[1].fd);
1518 _dbus_assert_not_reached ("Got to code after babysit()");
1519 }
1520 }
1521 else
1522 {
1523 /* Close the uncared-about ends of the pipes */
1524 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
1525 close_and_invalidate (&babysitter_pipe[1].fd);
1526 close_and_invalidate (&fd_out);
1527 close_and_invalidate (&fd_err);
1528
1529 sitter->socket_to_babysitter = babysitter_pipe[0];
1530 babysitter_pipe[0].fd = -1;
1531
1532 sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
1533 child_err_report_pipe[READ_END] = -1;
1534
1535 sitter->sitter_pid = pid;
1536
1537 if (sitter_p != NULL)
1538 *sitter_p = sitter;
1539 else
1540 _dbus_babysitter_unref (sitter);
1541
1542 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1543
1544 return TRUE;
1545 }
1546
1547 cleanup_and_fail:
1548
1549 _DBUS_ASSERT_ERROR_IS_SET (error);
1550
1551 close_and_invalidate (&child_err_report_pipe[READ_END]);
1552 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
1553 close_and_invalidate (&babysitter_pipe[0].fd);
1554 close_and_invalidate (&babysitter_pipe[1].fd);
1555 close_and_invalidate (&fd_out);
1556 close_and_invalidate (&fd_err);
1557
1558 if (sitter != NULL)
1559 _dbus_babysitter_unref (sitter);
1560
1561 return FALSE;
1562}
1563
1564void
1565_dbus_babysitter_set_result_function (DBusBabysitter *sitter,
1566 DBusBabysitterFinishedFunc finished,
1567 void *user_data)
1568{
1569 sitter->finished_cb = finished;
1570 sitter->finished_data = user_data;
1571}
1572
1575void
1576_dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
1577{
1578 while (LIVE_CHILDREN (sitter))
1579 babysitter_iteration (sitter, TRUE);
1580}
1581
1582// ********************************PDP********************************
1583// Use option to set label from connection to activated process (conn -- LBL --> process)
1584//#define PDP_FORCE_SET_LABEL_AT_ACTIVATION_TIME
1585
1586#ifdef HAVE_PDPLINUX
1587dbus_bool_t bus_activation_pdplinux_set_proc_label(void* actdata, DBusConnection* connection, pid_t pid){
1588 // don't use functions from bus because linker: unresolved external on libdbus-1 occured!
1589
1590 dbus_bool_t res=FALSE;
1591 PDPL_T* pdpl=NULL;
1592 //BusActivation* pbsu_activation=(BusActivation*)actdata;
1593
1594 _dbus_verbose("Entry\n");
1595 _dbus_verbose("Try to set label to process from connection\n");
1596
1597 _dbus_verbose("actdata=%p, connection=%p, pid=%d\n",
1598 actdata,connection,pid);
1599
1600 pdpl=dbus_connection_pdplinux_get_pdpl(connection);
1601 _dbus_pdplinux_show_text_label_info2("Connection",pdpl);
1602
1603#ifdef PDP_FORCE_SET_LABEL_AT_ACTIVATION_TIME
1604 if (0!=pdp_set_pid(pid,pdpl))
1605 _dbus_verbose("pdp_set_pid failed!\n");
1606 else
1607 res=TRUE;
1608#else
1609 _dbus_verbose("Set label skipped by configuration\n");
1610 _dbus_verbose("Exit\n");
1611#endif
1612
1613 if (pdpl) pdpl_put(pdpl);
1614 return res;
1615}
1616#endif
1617
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_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:599
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:63
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:692
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
Definition: dbus-memory.h:58
#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:437
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:439
#define _DBUS_POLLIN
There is data to read.
Definition: dbus-sysdeps.h:431
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:155
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:381
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:295
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:414
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:593
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()
Implementation details of DBusConnection.
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:426
short revents
Events that occurred.
Definition: dbus-sysdeps.h:427
DBusPollable fd
File descriptor.
Definition: dbus-sysdeps.h:425
Socket interface.
Definition: dbus-sysdeps.h:187
DBusWatchList implementation details.
Definition: dbus-watch.c:215
Implementation of DBusWatch.
Definition: dbus-watch.c:41