VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDaemonize.cpp@ 11179

Last change on this file since 11179 was 11179, checked in by vboxsync, 16 years ago

Typo (prevented the OS/2 build).

  • Property svn:eol-style set to native
  • Property svn:keyword set to Id
  • Property svn:keywords set to Id
File size: 7.7 KB
Line 
1/** $Id: VBoxGuestR3LibDaemonize.cpp 11179 2008-08-06 14:45:17Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, daemonize a process.
4 */
5
6/*
7 * Copyright (C) 2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#if defined(RT_OS_DARWIN)
27# error "PORTME"
28
29#elif defined(RT_OS_OS2)
30# define INCL_BASE
31# define INCL_ERRORS
32# include <os2.h>
33
34# include <iprt/alloca.h>
35# include <iprt/string.h>
36
37#elif defined(RT_OS_WINDOWS)
38# error "PORTME"
39
40#else /* the unices */
41# include <sys/types.h>
42# include <sys/stat.h>
43# include <stdio.h>
44# include <fcntl.h>
45# include <stdlib.h>
46# include <unistd.h>
47# include <signal.h>
48# include <errno.h>
49#endif
50
51#include <iprt/string.h>
52#include <iprt/file.h>
53#include <VBox/VBoxGuest.h>
54
55
56/**
57 * Daemonize the process for running in the background.
58 *
59 * This is supposed to do the same job as the BSD daemon() call.
60 *
61 * @returns 0 on success
62 *
63 * @param fNoChDir Pass false to change working directory to root.
64 * @param fNoClose Pass false to redirect standard file streams to /dev/null.
65 * @param pszPidfile Path to a file to write the pid of the daemon process
66 * to. Daemonising will fail if this file already exists
67 * or cannot be written. Optional.
68 */
69VBGLR3DECL(int) VbglR3Daemonize(bool fNoChDir, bool fNoClose,
70 char const *pszPidfile)
71{
72#if defined(RT_OS_DARWIN)
73# error "PORTME"
74
75#elif defined(RT_OS_OS2)
76 /** @todo create a pidfile if this is (/was :) ) usual on OS/2 */
77 NOREF(pszPidfile);
78 PPIB pPib;
79 PTIB pTib;
80 DosGetInfoBlocks(&pTib, &pPib);
81
82 /* Get the full path to the executable. */
83 char szExe[CCHMAXPATH];
84 APIRET rc = DosQueryModuleName(pPib->pib_hmte, sizeof(szExe), szExe);
85 if (rc)
86 return RTErrConvertFromOS2(rc);
87
88 /* calc the length of the command line. */
89 char *pch = pPib->pib_pchcmd;
90 size_t cch0 = strlen(pch);
91 pch += cch0 + 1;
92 size_t cch1 = strlen(pch);
93 pch += cch1 + 1;
94 char *pchArgs;
95 if (cch1 && *pch)
96 {
97 do pch = strchr(pch, '\0') + 1;
98 while (*pch);
99
100 size_t cchTotal = pch - pPib->pib_pchcmd;
101 pchArgs = (char *)alloca(cchTotal + sizeof("--daemonized\0\0"));
102 memcpy(pchArgs, pPib->pib_pchcmd, cchTotal - 1);
103 memcpy(pchArgs + cchTotal - 1, "--daemonized\0\0", sizeof("--daemonized\0\0"));
104 }
105 else
106 {
107 size_t cchTotal = pch - pPib->pib_pchcmd + 1;
108 pchArgs = (char *)alloca(cchTotal + sizeof(" --daemonized "));
109 memcpy(pchArgs, pPib->pib_pchcmd, cch0 + 1);
110 pch = pchArgs + cch0 + 1;
111 memcpy(pch, " --daemonized ", sizeof(" --daemonized ") - 1);
112 pch += sizeof(" --daemonized ") - 1;
113 if (cch1)
114 memcpy(pch, pPib->pib_pchcmd + cch0 + 1, cch1 + 2);
115 else
116 pch[0] = pch[1] = '\0';
117 }
118
119 /* spawn a detach process */
120 char szObj[128];
121 RESULTCODES ResCodes = { 0, 0 };
122 szObj[0] = '\0';
123 rc = DosExecPgm(szObj, sizeof(szObj), EXEC_BACKGROUND, (PCSZ)pchArgs, NULL, &ResCodes, (PCSZ)szExe);
124 if (rc)
125 {
126 /** @todo Change this to some standard log/print error?? */
127 /* VBoxServiceError("DosExecPgm failed with rc=%d and szObj='%s'\n", rc, szObj); */
128 return RTErrConvertFromOS2(rc);
129 }
130 DosExit(EXIT_PROCESS, 0);
131 return VERR_GENERAL_FAILURE;
132
133#elif defined(RT_OS_WINDOWS)
134# error "PORTME"
135
136#else /* the unices */
137 /*
138 * Fork the child process in a new session and quit the parent.
139 *
140 * - fork once and create a new session (setsid). This will detach us
141 * from the controlling tty meaning that we won't receive the SIGHUP
142 * (or any other signal) sent to that session.
143 * - The SIGHUP signal is ignored because the session/parent may throw
144 * us one before we get to the setsid.
145 * - When the parent exit(0) we will become an orphan and re-parented to
146 * the init process.
147 * - Because of the Linux / System V sematics of assigning the controlling
148 * tty automagically when a session leader first opens a tty, we will
149 * fork() once more on Linux to get rid of the session leadership role.
150 */
151
152 /* We start off by opening the pidfile, so that we can fail straight away
153 * if it already exists. */
154 RTFILE hPidfile = NIL_RTFILE;
155 if (pszPidfile != NULL)
156 {
157 /* @note the exclusive create is not guaranteed on all file
158 * systems (e.g. NFSv2) */
159 int rc = RTFileOpen(&hPidfile, pszPidfile,
160 RTFILE_O_READWRITE | RTFILE_O_CREATE
161 | (0644 << RTFILE_O_CREATE_MODE_SHIFT));
162 if (!RT_SUCCESS(rc))
163 return rc;
164 }
165
166 struct sigaction OldSigAct;
167 struct sigaction SigAct;
168 memset(&SigAct, 0, sizeof(SigAct));
169 SigAct.sa_handler = SIG_IGN;
170 int rcSigAct = sigaction(SIGHUP, &SigAct, &OldSigAct);
171
172 pid_t pid = fork();
173 if (pid == -1)
174 return RTErrConvertFromErrno(errno);
175 if (pid != 0)
176 {
177# ifndef RT_OS_LINUX /* On Linux we do another fork later */
178 if (hPidfile != NIL_RTFILE)
179 {
180 char szBuf[256];
181 size_t cbPid = RTStrPrintf(szBuf, sizeof(szBuf), "%d\n", pid);
182 RTFileWrite(hPidfile, szBuf, cbPid, NULL);
183 RTFileClose(hPidfile);
184 }
185# endif
186 exit(0);
187 }
188
189 /*
190 * The orphaned child becomes is reparented to the init process.
191 * We create a new session for it (setsid), point the standard
192 * file descriptors to /dev/null, and change to the root directory.
193 */
194 pid_t newpgid = setsid();
195 int SavedErrno = errno;
196 if (rcSigAct != -1)
197 sigaction(SIGHUP, &OldSigAct, NULL);
198 if (newpgid == -1)
199 return RTErrConvertFromErrno(SavedErrno);
200
201 if (!fNoClose)
202 {
203 /* Open stdin(0), stdout(1) and stderr(2) as /dev/null. */
204 int fd = open("/dev/null", O_RDWR);
205 if (fd == -1) /* paranoia */
206 {
207 close(STDIN_FILENO);
208 close(STDOUT_FILENO);
209 close(STDERR_FILENO);
210 fd = open("/dev/null", O_RDWR);
211 }
212 if (fd != -1)
213 {
214 dup2(fd, STDIN_FILENO);
215 dup2(fd, STDOUT_FILENO);
216 dup2(fd, STDERR_FILENO);
217 if (fd > 2)
218 close(fd);
219 }
220 }
221
222 if (!fNoChDir)
223 chdir("/");
224
225 /*
226 * Change the umask - this is non-standard daemon() behavior.
227 */
228 umask(027);
229
230# ifdef RT_OS_LINUX
231 /*
232 * And fork again to lose session leader status (non-standard daemon()
233 * behaviour).
234 */
235 pid = fork();
236 if (pid == -1)
237 return RTErrConvertFromErrno(errno);
238 if (pid != 0)
239 {
240 if (hPidfile != NIL_RTFILE)
241 {
242 char szBuf[256];
243 size_t cbPid = RTStrPrintf(szBuf, sizeof(szBuf), "%d\n", pid);
244 RTFileWrite(hPidfile, szBuf, cbPid, NULL);
245 RTFileClose(hPidfile);
246 }
247 exit(0);
248 }
249# endif /* RT_OS_LINUX */
250
251 return VINF_SUCCESS;
252#endif
253}
254
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette