VirtualBox

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

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

docs, and separator alternatives.

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