VirtualBox

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

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

Fixed build issues.

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