VirtualBox

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

Last change on this file since 3007 was 2851, checked in by bird, 8 years ago

updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.4 KB
Line 
1/* $Id: quoted_spawn.c 2851 2016-08-31 17:30:52Z bird $ */
2/** @file
3 * quote_spawn - Correctly Quote The _spawnvp arguments, windows specific.
4 */
5
6/*
7 * Copyright (c) 2010-2016 knut st. osmundsen <[email protected]>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 * IN THE SOFTWARE.
26 *
27 * Alternatively, the content of this file may be used under the terms of the
28 * GPL version 2 or later, or LGPL version 2.1 or later.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include "quoted_spawn.h"
36
37#include <process.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <errno.h>
42#include <assert.h>
43
44
45/**
46 * Tests if a strings needs quoting.
47 *
48 * @returns 1 if needs, 0 if it doesn't.
49 * @param pszArg The string in question.
50 */
51static int quoted_spawn_need_quoting(const char *pszArg)
52{
53 for (;;)
54 switch (*pszArg++)
55 {
56 case 0:
57 return 0;
58
59 case ' ':
60 case '"':
61 case '&':
62 case '>':
63 case '<':
64 case '|':
65 case '%':
66 /* Quote the control chars (tab is included). */
67 case 1:
68 case 2:
69 case 3:
70 case 4:
71 case 5:
72 case 6:
73 case 7:
74 case 8:
75 case 9:
76 case 10:
77 case 11:
78 case 13:
79 case 14:
80 case 15:
81 case 16:
82 case 17:
83 case 18:
84 case 19:
85 case 20:
86 case 21:
87 case 22:
88 case 23:
89 case 24:
90 case 25:
91 case 26:
92 case 27:
93 case 28:
94 case 29:
95 case 30:
96 case 31:
97 return 1;
98 }
99}
100
101/**
102 * Frees any quoted arguments.
103 *
104 * @returns NULL.
105 * @param papszArgsOrg The original argument vector.
106 * @param papszArgsQuoted The quoted argument vector.
107 * @param cArgs The number of arguments in the vector.
108 */
109static const char * const *
110quoted_spawn_free(const char * const *papszArgsOrg, const char * const *papszArgsQuoted, unsigned cArgs)
111{
112 if ( papszArgsOrg != papszArgsQuoted
113 && papszArgsQuoted != NULL)
114 {
115 int iSavedErrno = errno; /* A bit of paranoia. */
116 unsigned i = cArgs;
117 while (i-- > 0)
118 if (papszArgsQuoted[i] != papszArgsOrg[i])
119 free((char *)papszArgsQuoted[i]);
120 free((void *)papszArgsQuoted);
121 errno = iSavedErrno;
122 }
123 return NULL;
124}
125
126/**
127 * Quote an argument string.
128 *
129 * @returns Quoted argument string (new).
130 * @param pszArgOrg The original string.
131 */
132static const char *quoted_spawn_quote_arg(const char *pszArgOrg)
133{
134 size_t cchArgOrg = strlen(pszArgOrg);
135 size_t cchArgNew = 1 + cchArgOrg * 2 + 1 + 1;
136 char *pszArgNew = malloc(cchArgNew);
137 if (pszArgNew)
138 {
139 char ch;
140 char *pszDst = pszArgNew;
141 *pszDst++ = '"';
142 while ((ch = *pszArgOrg++))
143 {
144 if (ch == '\\')
145 {
146 size_t cSlashes = 1;
147 for (;;)
148 {
149 *pszDst++ = '\\';
150 ch = *pszArgOrg;
151 if (ch != '\\')
152 break;
153 pszArgOrg++;
154 cSlashes++;
155 }
156 if (ch == '"' || ch == '\0')
157 {
158 while (cSlashes-- > 0)
159 *pszDst++ = '\\';
160 if (ch == '\0')
161 break;
162 *pszDst++ = '\\';
163 *pszDst++ = '"';
164 }
165 }
166 else if (ch == '"')
167 {
168 *pszDst++ = '\\';
169 *pszDst++ = '"';
170 }
171 else
172 *pszDst++ = ch;
173 }
174 *pszDst++ = '"';
175 *pszDst = '\0';
176 assert((size_t)(pszDst - pszArgNew) < cchArgNew - 1);
177 }
178 return pszArgNew;
179}
180
181/**
182 * Quotes the arguments in an argument vector, producing a new vector.
183 *
184 * @returns The quoted argument vector.
185 * @param papszArgsOrg The vector which arguments to quote.
186 * @param iFirstArg The first argument that needs quoting.
187 * @param pcArgs Where to return the argument count.
188 */
189static const char * const *
190quoted_spawn_quote_vector(const char * const *papszArgsOrg, unsigned iFirstArg, unsigned *pcArgs)
191{
192 const char **papszArgsQuoted;
193 unsigned cArgs;
194 unsigned iArg;
195
196 /* finish counting them and allocate the result array. */
197 cArgs = iFirstArg;
198 while (papszArgsOrg[cArgs])
199 cArgs++;
200 *pcArgs = cArgs;
201
202 papszArgsQuoted = (const char **)calloc(sizeof(const char *), cArgs + 1);
203 if (!papszArgsQuoted)
204 return NULL;
205
206 /* Process the arguments up to the first quoted one (no need to
207 re-examine them). */
208 for (iArg = 0; iArg < iFirstArg; iArg++)
209 papszArgsQuoted[iArg] = papszArgsOrg[iArg];
210
211 papszArgsQuoted[iArg] = quoted_spawn_quote_arg(papszArgsOrg[iArg]);
212 if (!papszArgsQuoted[iArg])
213 return quoted_spawn_free(papszArgsOrg, papszArgsQuoted, cArgs);
214
215 /* Process the remaining arguments. */
216 while (iArg < cArgs)
217 {
218 if (!quoted_spawn_need_quoting(papszArgsOrg[iArg]))
219 papszArgsQuoted[iArg] = papszArgsOrg[iArg];
220 else
221 {
222 papszArgsQuoted[iArg] = quoted_spawn_quote_arg(papszArgsOrg[iArg]);
223 if (!papszArgsQuoted[iArg])
224 return quoted_spawn_free(papszArgsOrg, papszArgsQuoted, cArgs);
225 }
226 iArg++;
227 }
228
229 return papszArgsQuoted;
230}
231
232/**
233 * Checks if any of the arguments in the vector needs quoting and does the job.
234 *
235 * @returns If anything needs quoting a new vector is returned, otherwise the
236 * original is returned.
237 * @param papszArgsOrg The argument vector to check.
238 * @param pcArgs Where to return the argument count.
239 */
240static const char * const *
241quoted_spawn_maybe_quote(const char * const *papszArgsOrg, unsigned *pcArgs)
242{
243 unsigned iArg;
244 for (iArg = 0; papszArgsOrg[iArg]; iArg++)
245 if (quoted_spawn_need_quoting(papszArgsOrg[iArg]))
246 return quoted_spawn_quote_vector(papszArgsOrg, iArg, pcArgs);
247 *pcArgs = iArg;
248 return papszArgsOrg;
249}
250
251/**
252 * Wrapper for _spawnvp.
253 *
254 * @returns The process handle, see _spawnvp for details.
255 * @param fMode The spawn mode, see _spawnvp for details.
256 * @param pszExecPath The path to the executable, or just the name
257 * if a PATH search is desired.
258 * @param papszArgs The arguments to pass to the new process.
259 */
260intptr_t quoted_spawnvp(int fMode, const char *pszExecPath, const char * const *papszArgs)
261{
262 intptr_t hProcess;
263 unsigned cArgs;
264 const char * const *papszArgsQuoted = quoted_spawn_maybe_quote(papszArgs, &cArgs);
265 if (papszArgsQuoted)
266 {
267//unsigned i;
268//fprintf(stderr, "debug: spawning '%s'\n", pszExecPath);
269//for (i = 0; i < cArgs; i++)
270// fprintf(stderr, "debug: #%02u: '%s'\n", i, papszArgsQuoted[i]);
271 hProcess = _spawnvp(fMode, pszExecPath, papszArgsQuoted);
272 quoted_spawn_free(papszArgs, papszArgsQuoted, cArgs);
273 }
274 else
275 {
276 errno = ENOMEM;
277 hProcess = -1;
278 }
279
280 return hProcess;
281}
282
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