summaryrefslogtreecommitdiffstats
path: root/dbus/dbus-sysdeps.c
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-04-04 01:55:28 +0000
committerHavoc Pennington <hp@redhat.com>2003-04-04 01:55:28 +0000
commit45d1479fad0fb55f1775c394e696643dad3e8e4d (patch)
tree3697b7dc26dde5a2aa25cab5a3d719d917d9a76b /dbus/dbus-sysdeps.c
parent1b08036103a70159e7a67b2349306710edcd6654 (diff)
2003-04-03 Havoc Pennington <hp@pobox.com>
* dbus/dbus-spawn.c: Move dbus-spawn into a separate file in preparation for modifying it, dbus-sysdeps is getting a bit unmanageable.
Diffstat (limited to 'dbus/dbus-sysdeps.c')
-rw-r--r--dbus/dbus-sysdeps.c301
1 files changed, 1 insertions, 300 deletions
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index 17da1fbe..7e635d9d 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -2,6 +2,7 @@
/* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation)
*
* Copyright (C) 2002, 2003 Red Hat, Inc.
+ * Copyright (C) 2003 CodeFactory AB
*
* Licensed under the Academic Free License version 1.2
*
@@ -32,7 +33,6 @@
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
-#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <dirent.h>
@@ -2596,305 +2596,6 @@ _dbus_strerror (int error_number)
return msg;
}
-/* Avoids a danger in threaded situations (calling close()
- * on a file descriptor twice, and another thread has
- * re-opened it since the first close)
- */
-static int
-close_and_invalidate (int *fd)
-{
- int ret;
-
- if (*fd < 0)
- return -1;
- else
- {
- ret = close (*fd);
- *fd = -1;
- }
-
- return ret;
-}
-
-static dbus_bool_t
-make_pipe (int p[2],
- DBusError *error)
-{
- _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
- if (pipe (p) < 0)
- {
- dbus_set_error (error,
- DBUS_ERROR_SPAWN_FAILED,
- "Failed to create pipe for communicating with child process (%s)",
- _dbus_errno_to_string (errno));
- return FALSE;
- }
- else
- {
- _dbus_fd_set_close_on_exec (p[0]);
- _dbus_fd_set_close_on_exec (p[1]);
- return TRUE;
- }
-}
-
-enum
-{
- CHILD_CHDIR_FAILED,
- CHILD_EXEC_FAILED,
- CHILD_DUP2_FAILED,
- CHILD_FORK_FAILED
-};
-
-static void
-write_err_and_exit (int fd, int msg)
-{
- int en = errno;
-
- write (fd, &msg, sizeof(msg));
- write (fd, &en, sizeof(en));
-
- _exit (1);
-}
-
-static dbus_bool_t
-read_ints (int fd,
- int *buf,
- int n_ints_in_buf,
- int *n_ints_read,
- DBusError *error)
-{
- size_t bytes = 0;
-
- _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
- while (TRUE)
- {
- size_t chunk;
-
- if (bytes >= sizeof(int)*2)
- break; /* give up, who knows what happened, should not be
- * possible.
- */
-
- again:
- chunk = read (fd,
- ((char*)buf) + bytes,
- sizeof(int) * n_ints_in_buf - bytes);
- if (chunk < 0 && errno == EINTR)
- goto again;
-
- if (chunk < 0)
- {
- /* Some weird shit happened, bail out */
-
- dbus_set_error (error,
- DBUS_ERROR_SPAWN_FAILED,
- "Failed to read from child pipe (%s)",
- _dbus_errno_to_string (errno));
-
- return FALSE;
- }
- else if (chunk == 0)
- break; /* EOF */
- else /* chunk > 0 */
- bytes += chunk;
- }
-
- *n_ints_read = (int)(bytes / sizeof(int));
-
- return TRUE;
-}
-
-static void
-do_exec (int child_err_report_fd,
- char **argv,
- DBusSpawnChildSetupFunc child_setup,
- void *user_data)
-{
-#ifdef DBUS_BUILD_TESTS
- int i, max_open;
-#endif
-
- if (child_setup)
- (* child_setup) (user_data);
-
-#ifdef DBUS_BUILD_TESTS
- max_open = sysconf (_SC_OPEN_MAX);
-
- for (i = 3; i < max_open; i++)
- {
- int retval;
-
- retval = fcntl (i, F_GETFD);
-
- if (retval != -1 && !(retval & FD_CLOEXEC))
- _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
- }
-#endif
-
- execv (argv[0], argv);
-
- /* Exec failed */
- write_err_and_exit (child_err_report_fd,
- CHILD_EXEC_FAILED);
-
-}
-
-/**
- * Spawns a new process. The executable name and argv[0]
- * are the same, both are provided in argv[0]. The child_setup
- * function is passed the given user_data and is run in the child
- * just before calling exec().
- *
- * @todo this code should be reviewed/double-checked as it's fairly
- * complex and no one has reviewed it yet.
- *
- * @param argv the executable and arguments
- * @param child_setup function to call in child pre-exec()
- * @param user_data user data for setup function
- * @param error error object to be filled in if function fails
- * @returns #TRUE on success, #FALSE if error is filled in
- */
-dbus_bool_t
-_dbus_spawn_async (char **argv,
- DBusSpawnChildSetupFunc child_setup,
- void *user_data,
- DBusError *error)
-{
- int pid = -1, grandchild_pid;
- int child_err_report_pipe[2] = { -1, -1 };
- int status;
-
- _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
- if (!make_pipe (child_err_report_pipe, error))
- return FALSE;
-
- pid = fork ();
-
- if (pid < 0)
- {
- dbus_set_error (error,
- DBUS_ERROR_SPAWN_FORK_FAILED,
- "Failed to fork (%s)",
- _dbus_errno_to_string (errno));
- return FALSE;
- }
- else if (pid == 0)
- {
- /* Immediate child. */
-
- /* Be sure we crash if the parent exits
- * and we write to the err_report_pipe
- */
- signal (SIGPIPE, SIG_DFL);
-
- /* Close the parent's end of the pipes;
- * not needed in the close_descriptors case,
- * though
- */
- close_and_invalidate (&child_err_report_pipe[0]);
-
- /* We need to fork an intermediate child that launches the
- * final child. The purpose of the intermediate child
- * is to exit, so we can waitpid() it immediately.
- * Then the grandchild will not become a zombie.
- */
- grandchild_pid = fork ();
-
- if (grandchild_pid < 0)
- {
- write_err_and_exit (child_err_report_pipe[1],
- CHILD_FORK_FAILED);
- }
- else if (grandchild_pid == 0)
- {
- do_exec (child_err_report_pipe[1],
- argv,
- child_setup, user_data);
- }
- else
- {
- _exit (0);
- }
- }
- else
- {
- /* Parent */
-
- int buf[2];
- int n_ints = 0;
-
- /* Close the uncared-about ends of the pipes */
- close_and_invalidate (&child_err_report_pipe[1]);
-
- wait_again:
- if (waitpid (pid, &status, 0) < 0)
- {
- if (errno == EINTR)
- goto wait_again;
- else if (errno == ECHILD)
- ; /* do nothing, child already reaped */
- else
- _dbus_warn ("waitpid() should not fail in "
- "'_dbus_spawn_async'");
- }
-
- if (!read_ints (child_err_report_pipe[0],
- buf, 2, &n_ints,
- error))
- goto cleanup_and_fail;
-
- if (n_ints >= 2)
- {
- /* Error from the child. */
- switch (buf[0])
- {
- default:
- dbus_set_error (error,
- DBUS_ERROR_SPAWN_FAILED,
- "Unknown error executing child process \"%s\"",
- argv[0]);
- break;
- }
-
- goto cleanup_and_fail;
- }
-
-
- /* Success against all odds! return the information */
- close_and_invalidate (&child_err_report_pipe[0]);
-
- return TRUE;
- }
-
- cleanup_and_fail:
-
- /* There was an error from the Child, reap the child to avoid it being
- a zombie.
- */
- if (pid > 0)
- {
- wait_failed:
- if (waitpid (pid, NULL, 0) < 0)
- {
- if (errno == EINTR)
- goto wait_failed;
- else if (errno == ECHILD)
- ; /* do nothing, child already reaped */
- else
- _dbus_warn ("waitpid() should not fail in "
- "'_dbus_spawn_async'");
- }
- }
-
- close_and_invalidate (&child_err_report_pipe[0]);
- close_and_invalidate (&child_err_report_pipe[1]);
-
- return FALSE;
-}
-
/**
* signal (SIGPIPE, SIG_IGN);
*/