VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/process-posix.cpp@ 11836

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

IPRT: Implemented RTR3Init*WithProgramPath. Added RTPathParse. Cleaned up the RTPathProgram and RTProcGetExecutableName implementations.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 9.9 KB
Line 
1/* $Id: process-posix.cpp 11836 2008-08-29 16:52:20Z vboxsync $ */
2/** @file
3 * IPRT - Process, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32
33/*******************************************************************************
34* Header Files *
35*******************************************************************************/
36#define LOG_GROUP RTLOGGROUP_PROCESS
37#include <unistd.h>
38#include <stdlib.h>
39#include <errno.h>
40#include <sys/types.h>
41#include <sys/stat.h>
42#include <sys/wait.h>
43#include <fcntl.h>
44#include <signal.h>
45#if defined(RT_OS_LINUX) || defined(RT_OS_OS2)
46# define HAVE_POSIX_SPAWN 1
47#endif
48#ifdef HAVE_POSIX_SPAWN
49# include <spawn.h>
50#endif
51#ifdef RT_OS_DARWIN
52# include <mach-o/dyld.h>
53#endif
54
55#include <iprt/process.h>
56#include <iprt/string.h>
57#include <iprt/assert.h>
58#include <iprt/err.h>
59#include <iprt/env.h>
60#include "internal/process.h"
61
62
63
64RTR3DECL(int) RTProcCreate(const char *pszExec, const char * const *papszArgs, RTENV Env, unsigned fFlags, PRTPROCESS pProcess)
65{
66 /*
67 * Validate input.
68 */
69 AssertPtrReturn(pszExec, VERR_INVALID_POINTER);
70 AssertReturn(*pszExec, VERR_INVALID_PARAMETER);
71 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
72 AssertReturn(Env != NIL_RTENV, VERR_INVALID_PARAMETER);
73 const char * const *papszEnv = RTEnvGetExecEnvP(Env);
74 AssertPtrReturn(papszEnv, VERR_INVALID_HANDLE);
75 /* later: path searching. */
76
77
78 /*
79 * Check for execute access to the file.
80 */
81 if (access(pszExec, X_OK))
82 {
83 int rc = RTErrConvertFromErrno(errno);
84 AssertMsgFailed(("'%s' %Vrc!\n", pszExec, rc));
85 return rc;
86 }
87
88#if 0
89 /*
90 * Squeeze gdb --args in front of what's being spawned.
91 */
92 unsigned cArgs = 0;
93 while (papszArgs[cArgs])
94 cArgs++;
95 cArgs += 3;
96 const char **papszArgsTmp = (const char **)alloca(cArgs * sizeof(char *));
97 papszArgsTmp[0] = "/usr/bin/gdb";
98 papszArgsTmp[1] = "--args";
99 papszArgsTmp[2] = pszExec;
100 for (unsigned i = 1; papszArgs[i]; i++)
101 papszArgsTmp[i + 2] = papszArgs[i];
102 papszArgsTmp[cArgs - 1] = NULL;
103 pszExec = papszArgsTmp[0];
104 papszArgs = papszArgsTmp;
105#endif
106
107 /*
108 * Spawn the child.
109 */
110 pid_t pid;
111#ifdef HAVE_POSIX_SPAWN
112 /** @todo check if it requires any of those two attributes, don't remember atm. */
113 int rc = posix_spawn(&pid, pszExec, NULL, NULL, (char * const *)papszArgs,
114 (char * const *)papszEnv);
115 if (!rc)
116 {
117 if (pProcess)
118 *pProcess = pid;
119 return VINF_SUCCESS;
120 }
121
122#else
123
124 pid = fork();
125 if (!pid)
126 {
127 int rc;
128 rc = execve(pszExec, (char * const *)papszArgs, (char * const *)papszEnv);
129 AssertReleaseMsgFailed(("execve returns %d errno=%d\n", rc, errno));
130 exit(127);
131 }
132 if (pid > 0)
133 {
134 if (pProcess)
135 *pProcess = pid;
136 return VINF_SUCCESS;
137 }
138 int rc = errno;
139#endif
140
141 /* failure, errno value in rc. */
142 AssertMsgFailed(("spawn/exec failed rc=%d\n", rc)); /* this migth be annoying... */
143 return RTErrConvertFromErrno(rc);
144}
145
146
147RTR3DECL(int) RTProcWait(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus)
148{
149 int rc;
150 do rc = RTProcWaitNoResume(Process, fFlags, pProcStatus);
151 while (rc == VERR_INTERRUPTED);
152 return rc;
153}
154
155RTR3DECL(int) RTProcWaitNoResume(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus)
156{
157 /*
158 * Validate input.
159 */
160 if (Process <= 0)
161 {
162 AssertMsgFailed(("Invalid Process=%d\n", Process));
163 return VERR_INVALID_PARAMETER;
164 }
165 if (fFlags & ~(RTPROCWAIT_FLAGS_NOBLOCK | RTPROCWAIT_FLAGS_BLOCK))
166 {
167 AssertMsgFailed(("Invalid flags %#x\n", fFlags));
168 return VERR_INVALID_PARAMETER;
169 }
170
171 /*
172 * Performe the wait.
173 */
174 int iStatus = 0;
175 int rc = waitpid(Process, &iStatus, fFlags & RTPROCWAIT_FLAGS_NOBLOCK ? WNOHANG : 0);
176 if (rc > 0)
177 {
178 /*
179 * Fill in the status structure.
180 */
181 if (pProcStatus)
182 {
183 if (WIFEXITED(iStatus))
184 {
185 pProcStatus->enmReason = RTPROCEXITREASON_NORMAL;
186 pProcStatus->iStatus = WEXITSTATUS(iStatus);
187 }
188 else if (WIFSIGNALED(iStatus))
189 {
190 pProcStatus->enmReason = RTPROCEXITREASON_SIGNAL;
191 pProcStatus->iStatus = WTERMSIG(iStatus);
192 }
193 else
194 {
195 Assert(!WIFSTOPPED(iStatus));
196 pProcStatus->enmReason = RTPROCEXITREASON_ABEND;
197 pProcStatus->iStatus = iStatus;
198 }
199 }
200 return VINF_SUCCESS;
201 }
202
203 /*
204 * Child running?
205 */
206 if (!rc)
207 {
208 Assert(fFlags & RTPROCWAIT_FLAGS_NOBLOCK);
209 return VERR_PROCESS_RUNNING;
210 }
211
212 /*
213 * Figure out which error to return.
214 */
215 int iErr = errno;
216 if (iErr == ECHILD)
217 return VERR_PROCESS_NOT_FOUND;
218 return RTErrConvertFromErrno(iErr);
219}
220
221
222RTR3DECL(int) RTProcTerminate(RTPROCESS Process)
223{
224 if (!kill(Process, SIGKILL))
225 return VINF_SUCCESS;
226 return RTErrConvertFromErrno(errno);
227}
228
229
230RTR3DECL(uint64_t) RTProcGetAffinityMask()
231{
232 // @todo
233 return 1;
234}
235
236
237/**
238 * Daemonize the current process, making it a background process. The current
239 * process will exit if daemonizing is successful.
240 *
241 * @returns iprt status code.
242 * @param fNoChDir Pass false to change working directory to "/".
243 * @param fNoClose Pass false to redirect standard file streams to the null device.
244 * @param pszPidfile Path to a file to write the process id of the daemon
245 * process to. Daemonizing will fail if this file already
246 * exists or cannot be written. May be NULL.
247 */
248RTR3DECL(int) RTProcDaemonize(bool fNoChDir, bool fNoClose, const char *pszPidfile)
249{
250 /*
251 * Fork the child process in a new session and quit the parent.
252 *
253 * - fork once and create a new session (setsid). This will detach us
254 * from the controlling tty meaning that we won't receive the SIGHUP
255 * (or any other signal) sent to that session.
256 * - The SIGHUP signal is ignored because the session/parent may throw
257 * us one before we get to the setsid.
258 * - When the parent exit(0) we will become an orphan and re-parented to
259 * the init process.
260 * - Because of the sometimes unexpected semantics of assigning the
261 * controlling tty automagically when a session leader first opens a tty,
262 * we will fork() once more to get rid of the session leadership role.
263 */
264
265 /* We start off by opening the pidfile, so that we can fail straight away
266 * if it already exists. */
267 int fdPidfile = -1;
268 if (pszPidfile != NULL)
269 {
270 /* @note the exclusive create is not guaranteed on all file
271 * systems (e.g. NFSv2) */
272 if ((fdPidfile = open(pszPidfile, O_RDWR | O_CREAT | O_EXCL, 0644)) == -1)
273 return RTErrConvertFromErrno(errno);
274 }
275
276 /* Ignore SIGHUP straight away. */
277 struct sigaction OldSigAct;
278 struct sigaction SigAct;
279 memset(&SigAct, 0, sizeof(SigAct));
280 SigAct.sa_handler = SIG_IGN;
281 int rcSigAct = sigaction(SIGHUP, &SigAct, &OldSigAct);
282
283 /* First fork, to become independent process. */
284 pid_t pid = fork();
285 if (pid == -1)
286 return RTErrConvertFromErrno(errno);
287 if (pid != 0)
288 {
289 /* Parent exits, no longer necessary. Child creates gets reparented
290 * to the init process. */
291 exit(0);
292 }
293
294 /* Create new session, fix up the standard file descriptors and the
295 * current working directory. */
296 pid_t newpgid = setsid();
297 int SavedErrno = errno;
298 if (rcSigAct != -1)
299 sigaction(SIGHUP, &OldSigAct, NULL);
300 if (newpgid == -1)
301 return RTErrConvertFromErrno(SavedErrno);
302
303 if (!fNoClose)
304 {
305 /* Open stdin(0), stdout(1) and stderr(2) as /dev/null. */
306 int fd = open("/dev/null", O_RDWR);
307 if (fd == -1) /* paranoia */
308 {
309 close(STDIN_FILENO);
310 close(STDOUT_FILENO);
311 close(STDERR_FILENO);
312 fd = open("/dev/null", O_RDWR);
313 }
314 if (fd != -1)
315 {
316 dup2(fd, STDIN_FILENO);
317 dup2(fd, STDOUT_FILENO);
318 dup2(fd, STDERR_FILENO);
319 if (fd > 2)
320 close(fd);
321 }
322 }
323
324 if (!fNoChDir)
325 chdir("/");
326
327 /* Second fork to lose session leader status. */
328 pid = fork();
329 if (pid == -1)
330 return RTErrConvertFromErrno(errno);
331 if (pid != 0)
332 {
333 /* Write the pid file, this is done in the parent, before exiting. */
334 if (fdPidfile != -1)
335 {
336 char szBuf[256];
337 size_t cbPid = RTStrPrintf(szBuf, sizeof(szBuf), "%d\n", pid);
338 write(fdPidfile, szBuf, cbPid);
339 close(fdPidfile);
340 }
341 exit(0);
342 }
343
344 return VINF_SUCCESS;
345}
346
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