VirtualBox

source: kBuild/trunk/src/lib/quoted_spawn.c@ 2661

Last change on this file since 2661 was 2413, checked in by bird, 14 years ago

copyright year update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.9 KB
Line 
1/* $Id: quoted_spawn.c 2413 2010-09-11 17:43:04Z bird $ */
2/** @file
3 * quote_spawn - Correctly Quote The _spawnvp arguments, windows specific.
4 */
5
6/*
7 * Copyright (c) 2010 knut st. osmundsen <[email protected]>
8 *
9 * This file is part of kBuild.
10 *
11 * kBuild is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * kBuild is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#include "quoted_spawn.h"
30
31#include <process.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <errno.h>
36#include <assert.h>
37
38
39/**
40 * Tests if a strings needs quoting.
41 *
42 * @returns 1 if needs, 0 if it doesn't.
43 * @param pszArg The string in question.
44 */
45static int quoted_spawn_need_quoting(const char *pszArg)
46{
47 for (;;)
48 switch (*pszArg++)
49 {
50 case 0:
51 return 0;
52
53 case ' ':
54 case '"':
55 case '&':
56 case '>':
57 case '<':
58 case '|':
59 case '%':
60 /* Quote the control chars (tab is included). */
61 case 1:
62 case 2:
63 case 3:
64 case 4:
65 case 5:
66 case 6:
67 case 7:
68 case 8:
69 case 9:
70 case 10:
71 case 11:
72 case 13:
73 case 14:
74 case 15:
75 case 16:
76 case 17:
77 case 18:
78 case 19:
79 case 20:
80 case 21:
81 case 22:
82 case 23:
83 case 24:
84 case 25:
85 case 26:
86 case 27:
87 case 28:
88 case 29:
89 case 30:
90 case 31:
91 return 1;
92 }
93}
94
95/**
96 * Frees any quoted arguments.
97 *
98 * @returns NULL.
99 * @param papszArgsOrg The original argument vector.
100 * @param papszArgsQuoted The quoted argument vector.
101 * @param cArgs The number of arguments in the vector.
102 */
103static const char * const *
104quoted_spawn_free(const char * const *papszArgsOrg, const char * const *papszArgsQuoted, unsigned cArgs)
105{
106 if ( papszArgsOrg != papszArgsQuoted
107 && papszArgsQuoted != NULL)
108 {
109 int iSavedErrno = errno; /* A bit of paranoia. */
110 unsigned i = cArgs;
111 while (i-- > 0)
112 if (papszArgsQuoted[i] != papszArgsOrg[i])
113 free((char *)papszArgsQuoted[i]);
114 free((void *)papszArgsQuoted);
115 errno = iSavedErrno;
116 }
117 return NULL;
118}
119
120/**
121 * Quote an argument string.
122 *
123 * @returns Quoted argument string (new).
124 * @param pszArgOrg The original string.
125 */
126static const char *quoted_spawn_quote_arg(const char *pszArgOrg)
127{
128 size_t cchArgOrg = strlen(pszArgOrg);
129 size_t cchArgNew = 1 + cchArgOrg * 2 + 1 + 1;
130 char *pszArgNew = malloc(cchArgNew);
131 if (pszArgNew)
132 {
133 char ch;
134 char *pszDst = pszArgNew;
135 *pszDst++ = '"';
136 while ((ch = *pszArgOrg++))
137 {
138 if (ch == '\\')
139 {
140 size_t cSlashes = 1;
141 for (;;)
142 {
143 *pszDst++ = '\\';
144 ch = *pszArgOrg;
145 if (ch != '\\')
146 break;
147 pszArgOrg++;
148 cSlashes++;
149 }
150 if (ch == '"' || ch == '\0')
151 {
152 while (cSlashes-- > 0)
153 *pszDst++ = '\\';
154 if (ch == '\0')
155 break;
156 *pszDst++ = '\\';
157 *pszDst++ = '"';
158 }
159 }
160 else if (ch == '"')
161 {
162 *pszDst++ = '\\';
163 *pszDst++ = '"';
164 }
165 else
166 *pszDst++ = ch;
167 }
168 *pszDst++ = '"';
169 *pszDst = '\0';
170 assert((size_t)(pszDst - pszArgNew) < cchArgNew - 1);
171 }
172 return pszArgNew;
173}
174
175/**
176 * Quotes the arguments in an argument vector, producing a new vector.
177 *
178 * @returns The quoted argument vector.
179 * @param papszArgsOrg The vector which arguments to quote.
180 * @param iFirstArg The first argument that needs quoting.
181 * @param pcArgs Where to return the argument count.
182 */
183static const char * const *
184quoted_spawn_quote_vector(const char * const *papszArgsOrg, unsigned iFirstArg, unsigned *pcArgs)
185{
186 const char **papszArgsQuoted;
187 unsigned cArgs;
188 unsigned iArg;
189
190 /* finish counting them and allocate the result array. */
191 cArgs = iFirstArg;
192 while (papszArgsOrg[cArgs])
193 cArgs++;
194 *pcArgs = cArgs;
195
196 papszArgsQuoted = (const char **)calloc(sizeof(const char *), cArgs + 1);
197 if (!papszArgsQuoted)
198 return NULL;
199
200 /* Process the arguments up to the first quoted one (no need to
201 re-examine them). */
202 for (iArg = 0; iArg < iFirstArg; iArg++)
203 papszArgsQuoted[iArg] = papszArgsOrg[iArg];
204
205 papszArgsQuoted[iArg] = quoted_spawn_quote_arg(papszArgsOrg[iArg]);
206 if (!papszArgsQuoted[iArg])
207 return quoted_spawn_free(papszArgsOrg, papszArgsQuoted, cArgs);
208
209 /* Process the remaining arguments. */
210 while (iArg < cArgs)
211 {
212 if (!quoted_spawn_need_quoting(papszArgsOrg[iArg]))
213 papszArgsQuoted[iArg] = papszArgsOrg[iArg];
214 else
215 {
216 papszArgsQuoted[iArg] = quoted_spawn_quote_arg(papszArgsOrg[iArg]);
217 if (!papszArgsQuoted[iArg])
218 return quoted_spawn_free(papszArgsOrg, papszArgsQuoted, cArgs);
219 }
220 iArg++;
221 }
222
223 return papszArgsQuoted;
224}
225
226/**
227 * Checks if any of the arguments in the vector needs quoting and does the job.
228 *
229 * @returns If anything needs quoting a new vector is returned, otherwise the
230 * original is returned.
231 * @param papszArgsOrg The argument vector to check.
232 * @param pcArgs Where to return the argument count.
233 */
234static const char * const *
235quoted_spawn_maybe_quote(const char * const *papszArgsOrg, unsigned *pcArgs)
236{
237 unsigned iArg;
238 for (iArg = 0; papszArgsOrg[iArg]; iArg++)
239 if (quoted_spawn_need_quoting(papszArgsOrg[iArg]))
240 return quoted_spawn_quote_vector(papszArgsOrg, iArg, pcArgs);
241 *pcArgs = iArg;
242 return papszArgsOrg;
243}
244
245/**
246 * Wrapper for _spawnvp.
247 *
248 * @returns The process handle, see _spawnvp for details.
249 * @param fMode The spawn mode, see _spawnvp for details.
250 * @param pszExecPath The path to the executable, or just the name
251 * if a PATH search is desired.
252 * @param papszArgs The arguments to pass to the new process.
253 */
254intptr_t quoted_spawnvp(int fMode, const char *pszExecPath, const char * const *papszArgs)
255{
256 intptr_t hProcess;
257 unsigned cArgs;
258 const char * const *papszArgsQuoted = quoted_spawn_maybe_quote(papszArgs, &cArgs);
259 if (papszArgsQuoted)
260 {
261//unsigned i;
262//fprintf(stderr, "debug: spawning '%s'\n", pszExecPath);
263//for (i = 0; i < cArgs; i++)
264// fprintf(stderr, "debug: #%02u: '%s'\n", i, papszArgsQuoted[i]);
265 hProcess = _spawnvp(fMode, pszExecPath, papszArgsQuoted);
266 quoted_spawn_free(papszArgs, papszArgsQuoted, cArgs);
267 }
268 else
269 {
270 errno = ENOMEM;
271 hProcess = -1;
272 }
273
274 return hProcess;
275}
276
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