VirtualBox

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

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

Created kmk_redirect.

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