VBoxGuestR3LibDaemonize.cpp revision bd659c83e4074140e6f02eed6e2ef011121ab60d
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** $Id$ */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @file
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, daemonize a process.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2007 innotek GmbH
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * available from http://www.virtualbox.org. This file is free software;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * General Public License (GPL) as published by the Free Software
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*******************************************************************************
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync* Header Files *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync*******************************************************************************/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if defined(RT_OS_DARWIN)
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync# error "PORTME"
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#elif defined(RT_OS_OS2)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync# define INCL_BASE
b0db50948c349fa76655abf252f7946b515e8204vboxsync# define INCL_ERRORS
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync# include <os2.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync# include <iprt/alloca.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <iprt/string.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#elif defined(RT_OS_WINDOWS)
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync# error "PORTME"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f5e53763b0a581b0299e98028c6c52192eb06785vboxsync#else /* the unices */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <sys/types.h>
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync# include <sys/stat.h>
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync# include <stdio.h>
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync# include <fcntl.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <stdlib.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <unistd.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync# include <signal.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync# include <errno.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#endif
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <iprt/string.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <VBox/VBoxGuest.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Daemonize the process for running in the background.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This is supposed to do the same job as the BSD daemon() call.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns 0 on success
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param fNoChDir Pass false to change working directory to root.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param fNoClose Pass false to redirect standard file streams to /dev/null.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncVBGLR3DECL(int) VbglR3Daemonize(bool fNoChDir, bool fNoClose)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if defined(RT_OS_DARWIN)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# error "PORTME"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#elif defined(RT_OS_OS2)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPIB pPib;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PTIB pTib;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync DosGetInfoBlocks(&pTib, &pPib);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Get the full path to the executable. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync char szExe[CCHMAXPATH];
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync APIRET rc = DosQueryModuleName(pPib->pib_hmte, sizeof(szExe), szExe);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return RTErrConvertFromOS2(rc);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /* calc the length of the command line. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync char *pch = pPib->pib_pchcmd;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync size_t cch0 = strlen(pch);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync pch += cch0 + 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync size_t cch1 = strlen(pch);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pch += cch1 + 1;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync char *pchArgs;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (cch1 && *pch)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync do pch = strchr(pch, '\0') + 1;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync while (*pch);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync size_t cchTotal = pch - pPib->pib_pchcmd;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pchArgs = (char *)alloca(cchTotal + sizeof("--daemonized\0\0"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memcpy(pchArgs, pPib->pib_pchcmd, cchTotal - 1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memcpy(pchArgs + cchTotal - 1, "--daemonized\0\0", sizeof("--daemonized\0\0"));
36411046d85fccaa66061120a064225fd1b5ae01vboxsync }
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync else
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync {
0c4004948fca34f2db87e7b38013137e9472c306vboxsync size_t cchTotal = pch - pPib->pib_pchcmd + 1;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync pchArgs = (char *)alloca(cchTotal + sizeof(" --daemonized "));
0c4004948fca34f2db87e7b38013137e9472c306vboxsync memcpy(pchArgs, pPib->pib_pchcmd, cch0 + 1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pch = pchArgs + cch0 + 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memcpy(pch, " --daemonized ", sizeof(" --daemonized ") - 1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pch += sizeof(" --daemonized ") - 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cch1)
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync memcpy(pch, pPib->pib_pchcmd + cch0 + 1, cch1 + 2);
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync else
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync pch[0] = pch[1] = '\0';
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync }
65697a26b524640b83828b715160c798c43a0424vboxsync
65697a26b524640b83828b715160c798c43a0424vboxsync /* spawn a detach process */
6f76f373e9274aa29ec1485be3bfebafb670af0evboxsync char szObj[128];
6f76f373e9274aa29ec1485be3bfebafb670af0evboxsync RESULTCODES ResCodes = { 0, 0 };
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync szObj[0] = '\0';
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = DosExecPgm(szObj, sizeof(szObj), EXEC_BACKGROUND, (PCSZ)pchArgs, NULL, &ResCodes, (PCSZ)szExe);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (rc)
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** @todo Change this to some standard log/print error?? */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /* VBoxServiceError("DosExecPgm failed with rc=%d and szObj='%s'\n", rc, szObj); */
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync return RTErrConvertFromOS2(rc);
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync DosExit(EXIT_PROCESS, 0);
0381007ae929f1a0885e69644b7d586a1dbb3a2avboxsync return VERR_GENERAL_FAILURE;
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync#elif defined(RT_OS_WINDOWS)
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync# error "PORTME"
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync#else /* the unices */
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync /*
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync * Fork the child process and quit the parent.
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync *
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync * On Linux we'll fork once more at the end of it all just to be sure that
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync * we're not leaving any zombies behind. The SIGHUP stuff is ignored because
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * the parent may throw us one before we get to the setsid stuff one some
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * systems (BSD).
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync struct sigaction OldSigAct;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync struct sigaction SigAct;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync memset(&SigAct, 0, sizeof(SigAct));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SigAct.sa_handler = SIG_IGN;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync int rcSigAct = sigaction(SIGHUP, &SigAct, &OldSigAct);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync pid_t pid = fork();
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (pid == -1)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync return RTErrConvertFromErrno(errno);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pid != 0)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync exit(0);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /*
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * The orphaned child becomes is reparented to the init process.
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync * We create a new session for it (setsid), point the standard
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync * file descriptors to /dev/null, and change to the root directory.
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync */
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync pid_t newpgid = setsid();
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync int SavedErrno = errno;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rcSigAct != -1)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync sigaction(SIGHUP, &OldSigAct, NULL);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (newpgid == -1)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync return RTErrConvertFromErrno(SavedErrno);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (!fNoClose)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /* Open stdin(0), stdout(1) and stderr(2) as /dev/null. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int fd = open("/dev/null", O_RDWR);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (fd == -1) /* paranoia */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync close(STDIN_FILENO);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync close(STDOUT_FILENO);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync close(STDERR_FILENO);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync fd = open("/dev/null", O_RDWR);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync }
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (fd != -1)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync {
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync dup2(fd, STDIN_FILENO);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync dup2(fd, STDOUT_FILENO);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync dup2(fd, STDERR_FILENO);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (fd > 2)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync close(fd);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync }
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync }
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (!fNoChDir)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync chdir("/");
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /*
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * Change the umask - this is non-standard daemon() behavior.
93f91841f87620d1cb6d0238b3d0d5e52cd3b9a4vboxsync */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /** @todo why is umask set to 0 on linux? the solaris value is more sensible... */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync# ifdef RT_OS_SOLARIS
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync umask(027);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync# else
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync umask(0);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync# endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync# ifdef RT_OS_LINUX
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /*
65697a26b524640b83828b715160c798c43a0424vboxsync * And fork again to avoid zomibies and stuff (non-standard daemon() behaviour).
65697a26b524640b83828b715160c798c43a0424vboxsync */
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync pid = fork();
65697a26b524640b83828b715160c798c43a0424vboxsync if (pid == -1)
65697a26b524640b83828b715160c798c43a0424vboxsync return RTErrConvertFromErrno(errno);
65697a26b524640b83828b715160c798c43a0424vboxsync if (pid != 0)
65697a26b524640b83828b715160c798c43a0424vboxsync exit(0);
65697a26b524640b83828b715160c798c43a0424vboxsync# endif /* RT_OS_LINUX */
65697a26b524640b83828b715160c798c43a0424vboxsync
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync return VINF_SUCCESS;
65697a26b524640b83828b715160c798c43a0424vboxsync#endif
65697a26b524640b83828b715160c798c43a0424vboxsync}
65697a26b524640b83828b715160c798c43a0424vboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync