VirtualBox

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

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

The 'i' handling got lost...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.1 KB
Line 
1/* $Id: kmk_redirect.c 1300 2007-12-01 21:51:28Z 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 'i': /* make sure stdin is read-only. */
164 fOpen = O_RDONLY;
165 break;
166
167 case '+':
168 fprintf(pStdErr, "%s: syntax error: Unexpected '+' in '%s'\n", argv[0], argv[i]);
169 return 1;
170
171 default:
172 fOpen = O_RDWR | O_CREAT | O_TRUNC;
173 break;
174 }
175
176 /* binary / text modifiers */
177 switch (*psz)
178 {
179 case 'b':
180#ifdef O_BINARY
181 fOpen |= O_BINARY;
182#endif
183 psz++;
184 break;
185
186 case 't':
187#ifdef O_TEXT
188 fOpen |= O_TEXT;
189#endif
190 psz++;
191 break;
192
193 default:
194#ifdef O_BINARY
195 fOpen |= O_BINARY;
196#endif
197 break;
198
199 }
200
201 /* convert to file descriptor number */
202 switch (*psz)
203 {
204 case 'i':
205 fd = 0;
206 psz++;
207 break;
208
209 case 'o':
210 fd = 1;
211 psz++;
212 break;
213
214 case 'e':
215 fd = 2;
216 psz++;
217 break;
218
219 case '0':
220 if (!psz[1])
221 {
222 fd = 0;
223 psz++;
224 break;
225 }
226 case '1':
227 case '2':
228 case '3':
229 case '4':
230 case '5':
231 case '6':
232 case '7':
233 case '8':
234 case '9':
235 fd = (int)strtol(psz, &psz, 0);
236 if (!fd)
237 {
238 fprintf(pStdErr, "%s: error: failed to convert '%s' to a number\n", argv[0], argv[i]);
239 return 1;
240
241 }
242 if (fd < 0)
243 {
244 fprintf(pStdErr, "%s: error: negative fd %d (%s)\n", argv[0], fd, argv[i]);
245 return 1;
246 }
247 break;
248
249 /*
250 * Invalid argument.
251 */
252 default:
253 fprintf(pStdErr, "%s: error: failed to convert '%s' ('%s') to a file descriptor\n", argv[0], psz, argv[i]);
254 return 1;
255 }
256
257 /*
258 * Check for the filename.
259 */
260 if (*psz)
261 {
262 if (*psz != ':' && *psz != '=')
263 {
264 fprintf(pStdErr, "%s: syntax error: characters following the file descriptor: '%s' ('%s')\n", argv[0], psz, argv[i]);
265 return 1;
266 }
267 psz++;
268 }
269 else
270 {
271 i++;
272 if (i >= argc)
273 {
274 fprintf(pStdErr, "%s: syntax error: missing filename argument.\n", argv[0]);
275 return 1;
276 }
277 psz = argv[i];
278 }
279
280 /*
281 * Setup the redirection.
282 */
283 if (fd == fileno(pStdErr))
284 {
285 /*
286 * Move stderr to a new location, making it close on exec.
287 * If pStdOut has already teamed up with pStdErr, update it too.
288 */
289 FILE *pNew;
290 fdOpened = dup(fileno(pStdErr));
291 if (fdOpened == -1)
292 {
293 fprintf(pStdErr, "%s: error: failed to dup stderr (%d): %s\n", argv[0], fileno(pStdErr), strerror(errno));
294 return 1;
295 }
296#ifdef _MSC_VER
297 /** @todo figure out how to make the handle close-on-exec. We'll simply close it for now.
298 * SetHandleInformation + set FNOINHERIT in CRT.
299 */
300#else
301 if (fcntl(fdOpened, F_SETFD, FD_CLOEXEC) == -1)
302 {
303 fprintf(pStdErr, "%s: error: failed to make stderr (%d) close-on-exec: %s\n", argv[0], fdOpened, strerror(errno));
304 return 1;
305 }
306#endif
307
308 pNew = fdopen(fdOpened, "w");
309 if (!pNew)
310 {
311 fprintf(pStdErr, "%s: error: failed to fdopen the new stderr (%d): %s\n", argv[0], fdOpened, strerror(errno));
312 return 1;
313 }
314 if (pStdOut == pStdErr)
315 pStdOut = pNew;
316 pStdErr = pNew;
317 }
318 else if (fd == 1 && pStdOut != pStdErr)
319 pStdOut = pStdErr;
320
321 /*
322 * Close and open the new file descriptor.
323 */
324 close(fd);
325#if defined(_MSC_VER)
326 if (!strcmp(psz, "/dev/null"))
327 psz = (char *)"nul";
328#endif
329 fdOpened = open(psz, fOpen, 0666);
330 if (fdOpened == -1)
331 {
332 fprintf(pStdErr, "%s: error: failed to open '%s' as %d: %s\n", argv[0], psz, fd, strerror(errno));
333 return 1;
334 }
335 if (fdOpened != fd)
336 {
337 /* move it (dup2 returns 0 on MSC). */
338 if (dup2(fdOpened, fd) == -1)
339 {
340 fprintf(pStdErr, "%s: error: failed to dup '%s' as %d: %s\n", argv[0], psz, fd, strerror(errno));
341 return 1;
342 }
343 close(fdOpened);
344 }
345 }
346 else
347 {
348 fprintf(pStdErr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
349 return usage(pStdErr, argv[0]);
350 }
351 }
352
353 /*
354 * Make sure there's something to execute.
355 */
356 if (i >= argc)
357 {
358 fprintf(pStdErr, "%s: syntax error: nothing to execute!\n", argv[0]);
359 return usage(pStdErr, argv[0]);
360 }
361
362#if defined(_MSC_VER)
363 /** @todo
364 * We'll have to find the '--' in the commandline and pass that
365 * on to CreateProcess or spawn. Otherwise, the argument qouting
366 * is gonna be messed up.
367 */
368 if (fileno(pStdErr) != 2)
369 fclose(pStdErr);
370 rc = _spawnvp(_P_WAIT, argv[i], &argv[i]);
371 if (rc == -1 && fileno(pStdErr) != 2)
372 {
373 fprintf(pStdErr, "%s: error: _spawnvp(_P_WAIT,%s,..) failed: %s\n", argv[0], argv[i], strerror(errno));
374 rc = 1;
375 }
376 return rc;
377#else
378 execvp(argv[i], &argv[i]);
379 return 1;
380#endif
381}
382
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