VirtualBox

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

Last change on this file since 7689 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.4 KB
Line 
1/* $Id: process-posix.cpp 5999 2007-12-07 15:05:06Z vboxsync $ */
2/** @file
3 * innotek Portable Runtime - Process, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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
27
28
29/*******************************************************************************
30* Header Files *
31*******************************************************************************/
32#define LOG_GROUP RTLOGGROUP_PROCESS
33#include <unistd.h>
34#include <stdlib.h>
35#include <errno.h>
36#include <sys/stat.h>
37#include <sys/wait.h>
38#include <signal.h>
39#if defined(RT_OS_LINUX) || defined(RT_OS_OS2)
40# define HAVE_POSIX_SPAWN 1
41#endif
42#ifdef HAVE_POSIX_SPAWN
43# include <spawn.h>
44#endif
45#ifdef RT_OS_DARWIN
46# include <mach-o/dyld.h>
47#endif
48
49#include <iprt/process.h>
50#include <iprt/string.h>
51#include <iprt/assert.h>
52#include <iprt/err.h>
53#include <iprt/env.h>
54#include "internal/process.h"
55
56
57
58RTR3DECL(int) RTProcCreate(const char *pszExec, const char * const *papszArgs, RTENV Env, unsigned fFlags, PRTPROCESS pProcess)
59{
60 /*
61 * Validate input.
62 */
63 AssertPtrReturn(pszExec, VERR_INVALID_POINTER);
64 AssertReturn(*pszExec, VERR_INVALID_PARAMETER);
65 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
66 AssertReturn(Env != NIL_RTENV, VERR_INVALID_PARAMETER);
67 const char * const *papszEnv = RTEnvGetExecEnvP(Env);
68 AssertPtrReturn(papszEnv, VERR_INVALID_HANDLE);
69 /* later: path searching. */
70
71
72 /*
73 * Check for execute access to the file.
74 */
75 if (access(pszExec, X_OK))
76 {
77 int rc = RTErrConvertFromErrno(errno);
78 AssertMsgFailed(("'%s' %Vrc!\n", pszExec, rc));
79 return rc;
80 }
81
82#if 0
83 /*
84 * Squeeze gdb --args in front of what's being spawned.
85 */
86 unsigned cArgs = 0;
87 while (papszArgs[cArgs])
88 cArgs++;
89 cArgs += 3;
90 const char **papszArgsTmp = (const char **)alloca(cArgs * sizeof(char *));
91 papszArgsTmp[0] = "/usr/bin/gdb";
92 papszArgsTmp[1] = "--args";
93 papszArgsTmp[2] = pszExec;
94 for (unsigned i = 1; papszArgs[i]; i++)
95 papszArgsTmp[i + 2] = papszArgs[i];
96 papszArgsTmp[cArgs - 1] = NULL;
97 pszExec = papszArgsTmp[0];
98 papszArgs = papszArgsTmp;
99#endif
100
101 /*
102 * Spawn the child.
103 */
104 pid_t pid;
105#ifdef HAVE_POSIX_SPAWN
106 /** @todo check if it requires any of those two attributes, don't remember atm. */
107 int rc = posix_spawn(&pid, pszExec, NULL, NULL, (char * const *)papszArgs,
108 (char * const *)papszEnv);
109 if (!rc)
110 {
111 if (pProcess)
112 *pProcess = pid;
113 return VINF_SUCCESS;
114 }
115
116#else
117
118 pid = fork();
119 if (!pid)
120 {
121 int rc;
122 rc = execve(pszExec, (char * const *)papszArgs, (char * const *)papszEnv);
123 AssertReleaseMsgFailed(("execve returns %d errno=%d\n", rc, errno));
124 exit(127);
125 }
126 if (pid > 0)
127 {
128 if (pProcess)
129 *pProcess = pid;
130 return VINF_SUCCESS;
131 }
132 int rc = errno;
133#endif
134
135 /* failure, errno value in rc. */
136 AssertMsgFailed(("spawn/exec failed rc=%d\n", rc)); /* this migth be annoying... */
137 return RTErrConvertFromErrno(rc);
138}
139
140
141RTR3DECL(int) RTProcWait(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus)
142{
143 int rc;
144 do rc = RTProcWaitNoResume(Process, fFlags, pProcStatus);
145 while (rc == VERR_INTERRUPTED);
146 return rc;
147}
148
149RTR3DECL(int) RTProcWaitNoResume(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus)
150{
151 /*
152 * Validate input.
153 */
154 if (Process <= 0)
155 {
156 AssertMsgFailed(("Invalid Process=%d\n", Process));
157 return VERR_INVALID_PARAMETER;
158 }
159 if (fFlags & ~(RTPROCWAIT_FLAGS_NOBLOCK | RTPROCWAIT_FLAGS_BLOCK))
160 {
161 AssertMsgFailed(("Invalid flags %#x\n", fFlags));
162 return VERR_INVALID_PARAMETER;
163 }
164
165 /*
166 * Performe the wait.
167 */
168 int iStatus = 0;
169 int rc = waitpid(Process, &iStatus, fFlags & RTPROCWAIT_FLAGS_NOBLOCK ? WNOHANG : 0);
170 if (rc > 0)
171 {
172 /*
173 * Fill in the status structure.
174 */
175 if (pProcStatus)
176 {
177 if (WIFEXITED(iStatus))
178 {
179 pProcStatus->enmReason = RTPROCEXITREASON_NORMAL;
180 pProcStatus->iStatus = WEXITSTATUS(iStatus);
181 }
182 else if (WIFSIGNALED(iStatus))
183 {
184 pProcStatus->enmReason = RTPROCEXITREASON_SIGNAL;
185 pProcStatus->iStatus = WTERMSIG(iStatus);
186 }
187 else
188 {
189 Assert(!WIFSTOPPED(iStatus));
190 pProcStatus->enmReason = RTPROCEXITREASON_ABEND;
191 pProcStatus->iStatus = iStatus;
192 }
193 }
194 return VINF_SUCCESS;
195 }
196
197 /*
198 * Child running?
199 */
200 if (!rc)
201 {
202 Assert(fFlags & RTPROCWAIT_FLAGS_NOBLOCK);
203 return VERR_PROCESS_RUNNING;
204 }
205
206 /*
207 * Figure out which error to return.
208 */
209 int iErr = errno;
210 if (iErr == ECHILD)
211 return VERR_PROCESS_NOT_FOUND;
212 return RTErrConvertFromErrno(iErr);
213}
214
215
216RTR3DECL(int) RTProcTerminate(RTPROCESS Process)
217{
218 if (!kill(Process, SIGKILL))
219 return VINF_SUCCESS;
220 return RTErrConvertFromErrno(errno);
221}
222
223
224RTR3DECL(uint64_t) RTProcGetAffinityMask()
225{
226 // @todo
227 return 1;
228}
229
230
231RTR3DECL(char *) RTProcGetExecutableName(char *pszExecName, size_t cchExecName)
232{
233 /*
234 * I don't think there is a posix API for this, but
235 * because I'm lazy I'm not creating OS specific code
236 * files and code for this.
237 */
238#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_SOLARIS)
239# ifdef RT_OS_LINUX
240 int cchLink = readlink("/proc/self/exe", pszExecName, cchExecName - 1);
241# elif defined(RT_OS_SOLARIS)
242 char szFileBuf[80];
243 RTStrPrintf(szFileBuf, sizeof(szFileBuf), "/proc/%ld/path/a.out", (long)getpid());
244 int cchLink = readlink(szFileBuf, pszExecName, cchExecName - 1);
245# else
246 int cchLink = readlink("/proc/curproc/file", pszExecName, cchExecName - 1);
247# endif
248 if (cchLink > 0 && (size_t)cchLink <= cchExecName - 1)
249 {
250 pszExecName[cchLink] = '\0';
251 return pszExecName;
252 }
253
254#elif defined(RT_OS_OS2) || defined(RT_OS_L4)
255 if (!_execname(pszExecName, cchExecName))
256 return pszExecName;
257
258#elif defined(RT_OS_DARWIN)
259 const char *pszImageName = _dyld_get_image_name(0);
260 if (pszImageName)
261 {
262 size_t cchImageName = strlen(pszImageName);
263 if (cchImageName < cchExecName)
264 return (char *)memcpy(pszExecName, pszImageName, cchImageName + 1);
265 }
266
267#else
268# error "Port me!"
269#endif
270 return NULL;
271}
272
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