VirtualBox

source: kBuild/trunk/src/kmk_redirect/kmk_redirect.c@ 1278

Last change on this file since 1278 was 1278, checked in by bird, 17 years ago

execvp screws up wrt to anyone waiting on us on window.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.3 KB
Line 
1/* $Id: kmk_redirect.c 1278 2007-11-29 23:46:50Z bird $ */
2/** @file
3 *
4 * kmk_redirect - Do simple program <-> file redirection.
5 *
6 * Copyright (c) 2007 knut st. osmundsen <bird-kBuild-spam@anduin.net>
7 *
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 2 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, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <errno.h>
35#include <fcntl.h>
36#if defined(_MSC_VER)
37# include <io.h>
38# include <direct.h>
39# include <process.h>
40#else
41# include <unistd.h>
42#endif
43
44
45
46static int usage(FILE *pOut, const char *argv0)
47{
48 fprintf(pOut,
49 "usage: %s [-[rwa+tb]<fd> <file>] -- <program> [args]\n"
50 " or: %s --help\n"
51 " or: %s --version\n"
52 "\n"
53 "The rwa+tb is like for fopen, if not specified it defaults to w+.\n"
54 "The <fd> is either a number or an alias for the standard handles;\n"
55 "i - stdin, o - stdout, e - stderr.\n"
56 ,
57 argv0, argv0, argv0);
58 return 1;
59}
60
61
62int main(int argc, char **argv)
63{
64 int i;
65#if defined(_MSC_VER)
66 intptr_t rc;
67#endif
68 FILE *pStdErr = stderr;
69 FILE *pStdOut = stdout;
70
71
72 /*
73 * Parse arguments.
74 */
75 if (argc <= 1)
76 return usage(pStdErr, argv[0]);
77 for (i = 1; i < argc; i++)
78 {
79 if (argv[i][0] == '-')
80 {
81 int fd;
82 int fdOpened;
83 int fOpen;
84 char *psz = &argv[i][1];
85 if (*psz == '-')
86 {
87 /* '--' ? */
88 if (!psz[1])
89 {
90 i++;
91 break;
92 }
93
94 /* convert to short. */
95 if (!strcmp(psz, "-help"))
96 psz = "h";
97 else if (!strcmp(psz, "-version"))
98 psz = "V";
99 }
100
101 /*
102 * Deal with the obligatory help and version switches first.
103 */
104 if (*psz == 'h')
105 {
106 usage(pStdOut, argv[0]);
107 return 0;
108 }
109 if (*psz == 'V')
110 {
111 printf("kmk_redirect - kBuild version %d.%d.%d\n"
112 "Copyright (C) 2007 Knut St. Osmundsen\n",
113 KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH);
114 return 0;
115 }
116
117 /*
118 * Parse a file descriptor argument.
119 */
120
121 /* mode */
122 switch (*psz)
123 {
124 case 'r':
125 psz++;
126 if (*psz == '+')
127 {
128 fOpen = O_RDWR;
129 psz++;
130 }
131 else
132 fOpen = O_RDONLY;
133 break;
134
135 case 'w':
136 psz++;
137 if (*psz == '+')
138 {
139 psz++;
140 fOpen = O_RDWR | O_CREAT | O_TRUNC;
141 }
142 else
143 fOpen = O_WRONLY | O_CREAT | O_TRUNC;
144 break;
145
146 case 'a':
147 psz++;
148 if (*psz == '+')
149 {
150 psz++;
151 fOpen = O_RDWR | O_CREAT | O_APPEND;
152 }
153 else
154 fOpen = O_WRONLY | O_CREAT | O_APPEND;
155 break;
156
157 case '+':
158 fprintf(pStdErr, "%s: syntax error: Unexpected '+' in '%s'\n", argv[0], argv[i]);
159 return 1;
160
161 default:
162 fOpen = O_RDWR | O_CREAT | O_TRUNC;
163 break;
164 }
165
166 /* binary / text modifiers */
167 switch (*psz)
168 {
169 case 'b':
170#ifdef O_BINARY
171 fOpen |= O_BINARY;
172#endif
173 psz++;
174 break;
175
176 case 't':
177#ifdef O_TEXT
178 fOpen |= O_TEXT;
179#endif
180 psz++;
181 break;
182
183 default:
184#ifdef O_BINARY
185 fOpen |= O_BINARY;
186#endif
187 break;
188
189 }
190
191 /* convert to file descriptor number */
192 switch (*psz)
193 {
194 case 'o':
195 fd = 1;
196 psz++;
197 break;
198
199 case 'e':
200 fd = 2;
201 psz++;
202 break;
203
204 case '0':
205 if (!psz[1])
206 {
207 fd = 0;
208 psz++;
209 break;
210 }
211 case '1':
212 case '2':
213 case '3':
214 case '4':
215 case '5':
216 case '6':
217 case '7':
218 case '8':
219 case '9':
220 fd = (int)strtol(psz, &psz, 0);
221 if (!fd)
222 {
223 fprintf(pStdErr, "%s: error: failed to convert '%s' to a number\n", argv[0], argv[i]);
224 return 1;
225
226 }
227 if (fd < 0)
228 {
229 fprintf(pStdErr, "%s: error: negative fd %d (%s)\n", argv[0], fd, argv[i]);
230 return 1;
231 }
232 break;
233
234 /*
235 * Invalid argument.
236 */
237 default:
238 fprintf(pStdErr, "%s: error: failed to convert '%s' ('%s') to a file descriptor\n", argv[0], psz, argv[i]);
239 return 1;
240 }
241
242 /*
243 * Check for the filename.
244 */
245 if (*psz)
246 {
247 fprintf(pStdErr, "%s: syntax error: characters following the file descriptor: '%s' ('%s')\n", argv[0], psz, argv[i]);
248 return 1;
249 }
250 i++;
251 if (i >= argc )
252 {
253 fprintf(pStdErr, "%s: syntax error: missing filename argument.\n", argv[0]);
254 return 1;
255 }
256 psz = argv[i];
257
258 /*
259 * Setup the redirection.
260 */
261 if (fd == fileno(pStdErr))
262 {
263 /*
264 * Move stderr to a new location, making it close on exec.
265 * If pStdOut has already teamed up with pStdErr, update it too.
266 */
267 FILE *pNew;
268 fdOpened = dup(fileno(pStdErr));
269 if (fdOpened == -1)
270 {
271 fprintf(pStdErr, "%s: error: failed to dup stderr (%d): %s\n", argv[0], fileno(pStdErr), strerror(errno));
272 return 1;
273 }
274#ifdef _MSC_VER
275 /** @todo figure out how to make the handle close-on-exec. We'll simply close it for now.
276 * SetHandleInformation + set FNOINHERIT in CRT.
277 */
278#else
279 if (fcntl(fdOpened, F_SETFD, FD_CLOEXEC) == -1)
280 {
281 fprintf(pStdErr, "%s: error: failed to make stderr (%d) close-on-exec: %s\n", argv[0], fdOpened, strerror(errno));
282 return 1;
283 }
284#endif
285
286 pNew = fdopen(fdOpened, "w");
287 if (!pNew)
288 {
289 fprintf(pStdErr, "%s: error: failed to fdopen the new stderr (%d): %s\n", argv[0], fdOpened, strerror(errno));
290 return 1;
291 }
292 if (pStdOut == pStdErr)
293 pStdOut = pNew;
294 pStdErr = pNew;
295 }
296 else if (fd == 1 && pStdOut != pStdErr)
297 pStdOut = pStdErr;
298
299 /*
300 * Close and open the new file descriptor.
301 */
302 close(fd);
303#if defined(_MSC_VER)
304 if (!strcmp(psz, "/dev/null"))
305 psz = (char *)"nul";
306#endif
307 fdOpened = open(psz, fOpen, 0666);
308 if (fdOpened == -1)
309 {
310 fprintf(pStdErr, "%s: error: failed to open '%s' as %d: %s\n", argv[0], psz, fd, strerror(errno));
311 return 1;
312 }
313 if (fdOpened != fd)
314 {
315 /* move it (dup2 returns 0 on MSC). */
316 if (dup2(fdOpened, fd) == -1)
317 {
318 fprintf(pStdErr, "%s: error: failed to dup '%s' as %d: %s\n", argv[0], psz, fd, strerror(errno));
319 return 1;
320 }
321 close(fdOpened);
322 }
323 }
324 else
325 {
326 fprintf(pStdErr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
327 return usage(pStdErr, argv[0]);
328 }
329 }
330
331 /*
332 * Make sure there's something to execute.
333 */
334 if (i >= argc)
335 {
336 fprintf(pStdErr, "%s: syntax error: nothing to execute!\n", argv[0]);
337 return usage(pStdErr, argv[0]);
338 }
339
340#if defined(_MSC_VER)
341 /** @todo
342 * We'll have to find the '--' in the commandline and pass that
343 * on to CreateProcess or spawn. Otherwise, the argument qouting
344 * is gonna be messed up.
345 */
346 if (fileno(pStdErr) != 2)
347 fclose(pStdErr);
348 rc = _spawnvp(_P_WAIT, argv[i], &argv[i]);
349 if (rc == -1 && fileno(pStdErr) != 2)
350 {
351 fprintf(pStdErr, "%s: error: _spawnvp(_P_WAIT,%s,..) failed: %s\n", argv[0], argv[i], strerror(errno));
352 rc = 1;
353 }
354 return rc;
355#else
356 execvp(argv[i], &argv[i]);
357 return 1;
358#endif
359}
360
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