VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/redirect.c@ 2812

Last change on this file since 2812 was 2812, checked in by bird, 9 years ago

kmk_redirect: Extended the watcom brain damage hacks. Added verbose option to see what's being passed on to the child.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.4 KB
Line 
1/* $Id: redirect.c 2812 2016-03-13 11:22:53Z bird $ */
2/** @file
3 * kmk_redirect - Do simple program <-> file redirection (++).
4 */
5
6/*
7 * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
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 3 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, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#include "config.h"
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <errno.h>
34#include <fcntl.h>
35#if defined(_MSC_VER)
36# include <ctype.h>
37# include <io.h>
38# include <direct.h>
39# include <process.h>
40#else
41# include <unistd.h>
42#endif
43
44#ifdef __OS2__
45# define INCL_BASE
46# include <os2.h>
47# ifndef LIBPATHSTRICT
48# define LIBPATHSTRICT 3
49# endif
50#endif
51
52
53/*********************************************************************************************************************************
54* Global Variables *
55*********************************************************************************************************************************/
56/** Number of times the '-v' switch was seen. */
57static unsigned g_cVerbosity = 0;
58
59
60#if defined(_MSC_VER)
61
62/**
63 * Checks if this is an Watcom option where we must just pass thru the string
64 * as-is.
65 *
66 * This is currnetly only used for -d (defining macros).
67 *
68 * @returns 1 if pass-thru, 0 if not.
69 * @param pszArg The argument to consider.
70 */
71static int isWatcomPassThruOption(const char *pszArg)
72{
73 char ch = *pszArg++;
74 if (ch != '-' && ch != '/')
75 return 0;
76 ch = *pszArg++;
77 switch (ch)
78 {
79 /* Example: -d+VAR="string-value" */
80 case 'd':
81 if (ch == '+')
82 ch = *pszArg++;
83 if (!isalpha(ch) && ch != '_')
84 return 0;
85 return 1;
86
87 default:
88 return 0;
89 }
90}
91
92
93/**
94 * Replaces arguments in need of quoting.
95 *
96 * This will "leak" the original and/or the replacement string, depending on
97 * how you look at it.
98 *
99 * For details on how MSC parses the command line, see "Parsing C Command-Line
100 * Arguments": http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
101 *
102 * @param argc The argument count.
103 * @param argv The argument vector.
104 * @param fWatcomBrainDamage Set if we're catering for wcc, wcc386 or similar
105 * OpenWatcom tools. They seem to follow some
106 * ancient or home made quoting convention.
107 * @param pStdErr For verbose debug info.
108 */
109static void quoteArguments(int argc, char **argv, int fWatcomBrainDamage, FILE *pStdErr)
110{
111 int i;
112 for (i = 0; i < argc; i++)
113 {
114 const char *pszOrgOrg = argv[i];
115 const char *pszOrg = pszOrgOrg;
116 size_t cchOrg = strlen(pszOrg);
117 const char *pszQuotes = (const char *)memchr(pszOrg, '"', cchOrg);
118 const char *pszProblem = NULL;
119 if ( pszQuotes
120 || cchOrg == 0
121 || (pszProblem = (const char *)memchr(pszOrg, ' ', cchOrg)) != NULL
122 || (pszProblem = (const char *)memchr(pszOrg, '\t', cchOrg)) != NULL
123 || (pszProblem = (const char *)memchr(pszOrg, '\n', cchOrg)) != NULL
124 || (pszProblem = (const char *)memchr(pszOrg, '\r', cchOrg)) != NULL
125 || (pszProblem = (const char *)memchr(pszOrg, '&', cchOrg)) != NULL
126 || (pszProblem = (const char *)memchr(pszOrg, '>', cchOrg)) != NULL
127 || (pszProblem = (const char *)memchr(pszOrg, '<', cchOrg)) != NULL
128 || (pszProblem = (const char *)memchr(pszOrg, '|', cchOrg)) != NULL
129 || (pszProblem = (const char *)memchr(pszOrg, '%', cchOrg)) != NULL
130 || (pszProblem = (const char *)memchr(pszOrg, '\'', cchOrg)) != NULL
131 || ( !fWatcomBrainDamage
132 && (pszProblem = (const char *)memchr(pszOrg, '=', cchOrg)) != NULL)
133 )
134 {
135 char ch;
136 int fComplicated = pszQuotes || (cchOrg > 0 && pszOrg[cchOrg - 1] == '\\');
137 size_t cchNew = fComplicated ? cchOrg * 2 + 2 : cchOrg + 2;
138 char *pszNew = (char *)malloc(cchNew + 1 /*term*/ + 3 /*passthru hack*/);
139
140 argv[i] = pszNew;
141
142 /* Watcom does not grok stuff like "-i=c:\program files\watcom\h",
143 it think it's a source specification. In that case the quote
144 must follow the equal sign. */
145 if (fWatcomBrainDamage)
146 {
147 size_t cchUnquoted = 0;
148 if (pszOrg[0] == '@') /* Response file quoting: @"file name.rsp" */
149 cchUnquoted = 1;
150 else if (pszOrg[0] == '-' || pszOrg[0] == '/') /* Switch quoting. */
151 {
152 if (isWatcomPassThruOption(pszOrg))
153 cchUnquoted = strlen(pszOrg) + 1;
154 else
155 {
156 const char *pszNeedQuoting = (const char *)memchr(pszOrg, '=', cchOrg); /* For -i=dir and similar. */
157 if ( pszNeedQuoting == NULL
158 || (uintptr_t)pszNeedQuoting > (uintptr_t)(pszProblem ? pszProblem : pszQuotes))
159 pszNeedQuoting = pszProblem ? pszProblem : pszQuotes;
160 else
161 pszNeedQuoting++;
162 cchUnquoted = pszNeedQuoting - pszOrg;
163 }
164 }
165 if (cchUnquoted)
166 {
167 memcpy(pszNew, pszOrg, cchUnquoted);
168 pszNew += cchUnquoted;
169 pszOrg += cchUnquoted;
170 cchOrg -= cchUnquoted;
171 }
172 }
173
174 *pszNew++ = '"';
175 if (fComplicated)
176 {
177 while ((ch = *pszOrg++) != '\0')
178 {
179 if (ch == '"')
180 {
181 *pszNew++ = '\\';
182 *pszNew++ = '"';
183 }
184 else if (ch == '\\')
185 {
186 /* Backslashes are a bit complicated, they depends on
187 whether a quotation mark follows them or not. They
188 only require escaping if one does. */
189 unsigned cSlashes = 1;
190 while ((ch = *pszOrg) == '\\')
191 {
192 pszOrg++;
193 cSlashes++;
194 }
195 if (ch == '"' || ch == '\0') /* We put a " at the EOS. */
196 {
197 while (cSlashes-- > 0)
198 {
199 *pszNew++ = '\\';
200 *pszNew++ = '\\';
201 }
202 }
203 else
204 while (cSlashes-- > 0)
205 *pszNew++ = '\\';
206 }
207 else
208 *pszNew++ = ch;
209 }
210 }
211 else
212 {
213 memcpy(pszNew, pszOrg, cchOrg);
214 pszNew += cchOrg;
215 }
216 *pszNew++ = '"';
217 *pszNew = '\0';
218 }
219
220 if (g_cVerbosity > 0)
221 {
222 if (argv[i] == pszOrgOrg)
223 fprintf(pStdErr, "kmk_redirect: debug: argv[%i]=%s<eos>\n", i, pszOrgOrg);
224 else
225 {
226 fprintf(pStdErr, "kmk_redirect: debug: argv[%i]=%s<eos>\n", i, argv[i]);
227 fprintf(pStdErr, "kmk_redirect: debug:(orig[%i]=%s<eos>)\n", i, pszOrgOrg);
228 }
229 }
230 }
231
232 /*for (i = 0; i < argc; i++) fprintf(stderr, "argv[%u]=%s;;\n", i, argv[i]);*/
233}
234
235
236/** Used by safeCloseFd. */
237static void __cdecl ignore_invalid_parameter(const wchar_t *a, const wchar_t *b, const wchar_t *c, unsigned d, uintptr_t e)
238{
239}
240
241#endif /* _MSC_VER */
242
243
244/**
245 * Safely works around MS CRT's pedantic close() function.
246 *
247 * @param fd The file handle.
248 */
249static void safeCloseFd(int fd)
250{
251#ifdef _MSC_VER
252 _invalid_parameter_handler pfnOld = _get_invalid_parameter_handler();
253 _set_invalid_parameter_handler(ignore_invalid_parameter);
254 close(fd);
255 _set_invalid_parameter_handler(pfnOld);
256#else
257 close(fd);
258#endif
259}
260
261
262static const char *name(const char *pszName)
263{
264 const char *psz = strrchr(pszName, '/');
265#if defined(_MSC_VER) || defined(__OS2__)
266 const char *psz2 = strrchr(pszName, '\\');
267 if (!psz2)
268 psz2 = strrchr(pszName, ':');
269 if (psz2 && (!psz || psz2 > psz))
270 psz = psz2;
271#endif
272 return psz ? psz + 1 : pszName;
273}
274
275
276static int usage(FILE *pOut, const char *argv0)
277{
278 fprintf(pOut,
279 "usage: %s [-[rwa+tb]<fd> <file>] [-c<fd>] [-Z] [-E <var=val>] [-C <dir>] [--wcc-brain-damage] [-v] -- <program> [args]\n"
280 " or: %s --help\n"
281 " or: %s --version\n"
282 "\n"
283 "The rwa+tb is like for fopen, if not specified it defaults to w+.\n"
284 "The <fd> is either a number or an alias for the standard handles:\n"
285 " i = stdin\n"
286 " o = stdout\n"
287 " e = stderr\n"
288 "\n"
289 "The -c switch will close the specified file descriptor.\n"
290 "\n"
291 "The -Z switch zaps the environment.\n"
292 "\n"
293 "The -E switch is for making changes to the environment in a putenv\n"
294 "fashion.\n"
295 "\n"
296 "The -C switch is for changing the current directory. This takes immediate\n"
297 "effect, so be careful where you put it.\n"
298 "\n"
299 "The --wcc-brain-damage switch is to work around wcc and wcc386 (Open Watcom)\n"
300 "not following normal quoting conventions on Windows, OS/2, and DOS.\n"
301 "\n"
302 "The -v switch is for making the thing more verbose.\n"
303 "\n"
304 "This command was originally just a quick hack to avoid invoking the shell\n"
305 "on Windows (cygwin) where forking is very expensive and has exhibited\n"
306 "stability issues on SMP machines. It has since grown into something like\n"
307 "/usr/bin/env on steroids.\n"
308 ,
309 argv0, argv0, argv0);
310 return 1;
311}
312
313
314int main(int argc, char **argv, char **envp)
315{
316 int i;
317#if defined(_MSC_VER)
318 intptr_t rc;
319#else
320 int j;
321#endif
322 FILE *pStdErr = stderr;
323 FILE *pStdOut = stdout;
324 int fWatcomBrainDamage = 0;
325
326 /*
327 * Parse arguments.
328 */
329 if (argc <= 1)
330 return usage(pStdErr, name(argv[0]));
331 for (i = 1; i < argc; i++)
332 {
333 if (argv[i][0] == '-')
334 {
335 int fd;
336 int fdOpened;
337 int fOpen;
338 char *psz = &argv[i][1];
339 if (*psz == '-')
340 {
341 /* '--' ? */
342 if (!psz[1])
343 {
344 i++;
345 break;
346 }
347
348 /* convert to short. */
349 if (!strcmp(psz, "-help"))
350 psz = "h";
351 else if (!strcmp(psz, "-version"))
352 psz = "V";
353 else if (!strcmp(psz, "-env"))
354 psz = "E";
355 else if (!strcmp(psz, "-chdir"))
356 psz = "C";
357 else if (!strcmp(psz, "-zap-env"))
358 psz = "Z";
359 else if (!strcmp(psz, "-close"))
360 psz = "c";
361 else if (!strcmp(psz, "-wcc-brain-damage"))
362 {
363 fWatcomBrainDamage = 1;
364 continue;
365 }
366 }
367
368 /*
369 * Deal with the obligatory help and version switches first.
370 */
371 if (*psz == 'h')
372 {
373 usage(pStdOut, name(argv[0]));
374 return 0;
375 }
376 if (*psz == 'V')
377 {
378 printf("kmk_redirect - kBuild version %d.%d.%d (r%u)\n"
379 "Copyright (C) 2007-2012 knut st. osmundsen\n",
380 KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH,
381 KBUILD_SVN_REV);
382 return 0;
383 }
384
385 /*
386 * Environment switch?
387 */
388 if (*psz == 'E')
389 {
390 psz++;
391 if (*psz == ':' || *psz == '=')
392 psz++;
393 else
394 {
395 if (i + 1 >= argc)
396 {
397 fprintf(pStdErr, "%s: syntax error: no argument for %s\n", name(argv[0]), argv[i]);
398 return 1;
399 }
400 psz = argv[++i];
401 }
402#ifdef __OS2__
403 if ( !strncmp(psz, "BEGINLIBPATH=", sizeof("BEGINLIBPATH=") - 1)
404 || !strncmp(psz, "ENDLIBPATH=", sizeof("ENDLIBPATH=") - 1)
405 || !strncmp(psz, "LIBPATHSTRICT=", sizeof("LIBPATHSTRICT=") - 1))
406 {
407 ULONG ulVar = *psz == 'B' ? BEGIN_LIBPATH
408 : *psz == 'E' ? END_LIBPATH
409 : LIBPATHSTRICT;
410 const char *pszVal = strchr(psz, '=') + 1;
411 APIRET rc = DosSetExtLIBPATH(pszVal, ulVar);
412 if (rc)
413 {
414 fprintf(pStdErr, "%s: error: DosSetExtLibPath(\"%s\", %.*s (%lu)): %lu\n",
415 name(argv[0]), pszVal, pszVal - psz - 1, psz, ulVar, rc);
416 return 1;
417 }
418 }
419 else
420#endif /* __OS2__ */
421 {
422 const char *pchEqual = strchr(psz, '=');
423 if (pchEqual && pchEqual[1] != '\0')
424 {
425 if (putenv(psz))
426 {
427 fprintf(pStdErr, "%s: error: putenv(\"%s\"): %s\n", name(argv[0]), psz, strerror(errno));
428 return 1;
429 }
430 }
431 else
432 {
433 size_t cchVar = pchEqual ? (size_t)(pchEqual - psz) : strlen(psz);
434 char *pszCopy = (char *)malloc(cchVar + 2);
435 memcpy(pszCopy, psz, cchVar);
436
437#if defined(_MSC_VER) || defined(__OS2__)
438 pszCopy[cchVar] = '=';
439 pszCopy[cchVar + 1] = '\0';
440 if (putenv(pszCopy))
441 {
442 fprintf(pStdErr, "%s: error: putenv(\"%s\"): %s\n", name(argv[0]), pszCopy, strerror(errno));
443 return 1;
444 }
445#else
446 pszCopy[cchVar] = '\0';
447 if (unsetenv(pszCopy))
448 {
449 fprintf(pStdErr, "%s: error: unsetenv(\"%s\"): %s\n", name(argv[0]), pszCopy, strerror(errno));
450 return 1;
451 }
452#endif
453 free(pszCopy);
454 }
455 }
456 continue;
457 }
458
459 /*
460 * Change directory switch?
461 */
462 if (*psz == 'C')
463 {
464 psz++;
465 if (*psz == ':' || *psz == '=')
466 psz++;
467 else
468 {
469 if (i + 1 >= argc)
470 {
471 fprintf(pStdErr, "%s: syntax error: no argument for %s\n", name(argv[0]), argv[i]);
472 return 1;
473 }
474 psz = argv[++i];
475 }
476 if (!chdir(psz))
477 continue;
478#ifdef _MSC_VER
479 {
480 /* drop trailing slash if any. */
481 size_t cch = strlen(psz);
482 if ( cch > 2
483 && (psz[cch - 1] == '/' || psz[cch - 1] == '\\')
484 && psz[cch - 1] != ':')
485 {
486 int rc2;
487 char *pszCopy = strdup(psz);
488 do pszCopy[--cch] = '\0';
489 while ( cch > 2
490 && (pszCopy[cch - 1] == '/' || pszCopy[cch - 1] == '\\')
491 && pszCopy[cch - 1] != ':');
492 rc2 = chdir(pszCopy);
493 free(pszCopy);
494 if (!rc2)
495 continue;
496 }
497 }
498#endif
499 fprintf(pStdErr, "%s: error: chdir(\"%s\"): %s\n", name(argv[0]), psz, strerror(errno));
500 return 1;
501 }
502
503 /*
504 * Zap environment switch?
505 * This is a bit of a hack.
506 */
507 if (*psz == 'Z')
508 {
509 unsigned j = 0;
510 while (envp[j] != NULL)
511 j++;
512 while (j-- > 0)
513 {
514 char *pszEqual = strchr(envp[j], '=');
515 char *pszCopy;
516
517 if (pszEqual)
518 *pszEqual = '\0';
519 pszCopy = strdup(envp[j]);
520 if (pszEqual)
521 *pszEqual = '=';
522
523#if defined(_MSC_VER) || defined(__OS2__)
524 putenv(pszCopy);
525#else
526 unsetenv(pszCopy);
527#endif
528 free(pszCopy);
529 }
530 continue;
531 }
532
533 /*
534 * Verbose operation switch?
535 */
536 if (*psz == 'v')
537 {
538 g_cVerbosity++;
539 continue;
540 }
541
542 /*
543 * Close the specified file descriptor (no stderr/out/in aliases).
544 */
545 if (*psz == 'c')
546 {
547 psz++;
548 if (!*psz)
549 {
550 i++;
551 if (i >= argc)
552 {
553 fprintf(pStdErr, "%s: syntax error: missing filename argument.\n", name(argv[0]));
554 return 1;
555 }
556 psz = argv[i];
557 }
558
559 fd = (int)strtol(psz, &psz, 0);
560 if (!fd || *psz)
561 {
562 fprintf(pStdErr, "%s: error: failed to convert '%s' to a number\n", name(argv[0]), argv[i]);
563 return 1;
564
565 }
566 if (fd < 0)
567 {
568 fprintf(pStdErr, "%s: error: negative fd %d (%s)\n", name(argv[0]), fd, argv[i]);
569 return 1;
570 }
571 /** @todo deal with stderr */
572 safeCloseFd(fd);
573 continue;
574 }
575
576 /*
577 * Parse a file descriptor argument.
578 */
579
580 /* mode */
581 switch (*psz)
582 {
583 case 'r':
584 psz++;
585 if (*psz == '+')
586 {
587 fOpen = O_RDWR;
588 psz++;
589 }
590 else
591 fOpen = O_RDONLY;
592 break;
593
594 case 'w':
595 psz++;
596 if (*psz == '+')
597 {
598 psz++;
599 fOpen = O_RDWR | O_CREAT | O_TRUNC;
600 }
601 else
602 fOpen = O_WRONLY | O_CREAT | O_TRUNC;
603 break;
604
605 case 'a':
606 psz++;
607 if (*psz == '+')
608 {
609 psz++;
610 fOpen = O_RDWR | O_CREAT | O_APPEND;
611 }
612 else
613 fOpen = O_WRONLY | O_CREAT | O_APPEND;
614 break;
615
616 case 'i': /* make sure stdin is read-only. */
617 fOpen = O_RDONLY;
618 break;
619
620 case '+':
621 fprintf(pStdErr, "%s: syntax error: Unexpected '+' in '%s'\n", name(argv[0]), argv[i]);
622 return 1;
623
624 default:
625 fOpen = O_RDWR | O_CREAT | O_TRUNC;
626 break;
627 }
628
629 /* binary / text modifiers */
630 switch (*psz)
631 {
632 case 'b':
633#ifdef O_BINARY
634 fOpen |= O_BINARY;
635#endif
636 psz++;
637 break;
638
639 case 't':
640#ifdef O_TEXT
641 fOpen |= O_TEXT;
642#endif
643 psz++;
644 break;
645
646 default:
647#ifdef O_BINARY
648 fOpen |= O_BINARY;
649#endif
650 break;
651
652 }
653
654 /* convert to file descriptor number */
655 switch (*psz)
656 {
657 case 'i':
658 fd = 0;
659 psz++;
660 break;
661
662 case 'o':
663 fd = 1;
664 psz++;
665 break;
666
667 case 'e':
668 fd = 2;
669 psz++;
670 break;
671
672 case '0':
673 if (!psz[1])
674 {
675 fd = 0;
676 psz++;
677 break;
678 }
679 case '1':
680 case '2':
681 case '3':
682 case '4':
683 case '5':
684 case '6':
685 case '7':
686 case '8':
687 case '9':
688 fd = (int)strtol(psz, &psz, 0);
689 if (!fd)
690 {
691 fprintf(pStdErr, "%s: error: failed to convert '%s' to a number\n", name(argv[0]), argv[i]);
692 return 1;
693
694 }
695 if (fd < 0)
696 {
697 fprintf(pStdErr, "%s: error: negative fd %d (%s)\n", name(argv[0]), fd, argv[i]);
698 return 1;
699 }
700 break;
701
702 /*
703 * Invalid argument.
704 */
705 default:
706 fprintf(pStdErr, "%s: error: failed to convert '%s' ('%s') to a file descriptor\n", name(argv[0]), psz, argv[i]);
707 return 1;
708 }
709
710 /*
711 * Check for the filename.
712 */
713 if (*psz)
714 {
715 if (*psz != ':' && *psz != '=')
716 {
717 fprintf(pStdErr, "%s: syntax error: characters following the file descriptor: '%s' ('%s')\n", name(argv[0]), psz, argv[i]);
718 return 1;
719 }
720 psz++;
721 }
722 else
723 {
724 i++;
725 if (i >= argc)
726 {
727 fprintf(pStdErr, "%s: syntax error: missing filename argument.\n", name(argv[0]));
728 return 1;
729 }
730 psz = argv[i];
731 }
732
733 /*
734 * Setup the redirection.
735 */
736 if (fd == fileno(pStdErr))
737 {
738 /*
739 * Move stderr to a new location, making it close on exec.
740 * If pStdOut has already teamed up with pStdErr, update it too.
741 */
742 FILE *pNew;
743 fdOpened = dup(fileno(pStdErr));
744 if (fdOpened == -1)
745 {
746 fprintf(pStdErr, "%s: error: failed to dup stderr (%d): %s\n", name(argv[0]), fileno(pStdErr), strerror(errno));
747 return 1;
748 }
749#ifdef _MSC_VER
750 /** @todo figure out how to make the handle close-on-exec. We'll simply close it for now.
751 * SetHandleInformation + set FNOINHERIT in CRT.
752 */
753#else
754 if (fcntl(fdOpened, F_SETFD, FD_CLOEXEC) == -1)
755 {
756 fprintf(pStdErr, "%s: error: failed to make stderr (%d) close-on-exec: %s\n", name(argv[0]), fdOpened, strerror(errno));
757 return 1;
758 }
759#endif
760
761 pNew = fdopen(fdOpened, "w");
762 if (!pNew)
763 {
764 fprintf(pStdErr, "%s: error: failed to fdopen the new stderr (%d): %s\n", name(argv[0]), fdOpened, strerror(errno));
765 return 1;
766 }
767 if (pStdOut == pStdErr)
768 pStdOut = pNew;
769 pStdErr = pNew;
770 }
771 else if (fd == 1 && pStdOut != pStdErr)
772 pStdOut = pStdErr;
773
774 /*
775 * Close and open the new file descriptor.
776 */
777 safeCloseFd(fd);
778#if defined(_MSC_VER)
779 if (!strcmp(psz, "/dev/null"))
780 psz = (char *)"nul";
781#endif
782 fdOpened = open(psz, fOpen, 0666);
783 if (fdOpened == -1)
784 {
785 fprintf(pStdErr, "%s: error: failed to open '%s' as %d: %s\n", name(argv[0]), psz, fd, strerror(errno));
786 return 1;
787 }
788 if (fdOpened != fd)
789 {
790 /* move it (dup2 returns 0 on MSC). */
791 if (dup2(fdOpened, fd) == -1)
792 {
793 fprintf(pStdErr, "%s: error: failed to dup '%s' as %d: %s\n", name(argv[0]), psz, fd, strerror(errno));
794 return 1;
795 }
796 close(fdOpened);
797 }
798 }
799 else
800 {
801 fprintf(pStdErr, "%s: syntax error: Invalid argument '%s'.\n", name(argv[0]), argv[i]);
802 return usage(pStdErr, name(argv[0]));
803 }
804 }
805
806 /*
807 * Make sure there's something to execute.
808 */
809 if (i >= argc)
810 {
811 fprintf(pStdErr, "%s: syntax error: nothing to execute!\n", name(argv[0]));
812 return usage(pStdErr, name(argv[0]));
813 }
814
815#if defined(_MSC_VER)
816 if (fileno(pStdErr) != 2) /* no close-on-exec flag on windows */
817 {
818 fclose(pStdErr);
819 pStdErr = NULL;
820 }
821
822 /* MSC is a PITA since it refuses to quote the arguments... */
823 quoteArguments(argc - i, &argv[i], fWatcomBrainDamage, pStdErr);
824 rc = _spawnvp(_P_WAIT, argv[i], &argv[i]);
825 if (rc == -1 && pStdErr)
826 {
827 fprintf(pStdErr, "%s: error: _spawnvp(_P_WAIT, \"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
828 rc = 1;
829 }
830 return rc;
831#else
832 if (g_cVerbosity > 0)
833 for (j = i; j < argc; j++)
834 fprintf(pStdErr, "kmk_redirect: debug: argv[%i]=%s<eos>\n", j - i, argv[j]);
835 execvp(argv[i], &argv[i]);
836 fprintf(pStdErr, "%s: error: _execvp(_P_WAIT, \"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
837 return 1;
838#endif
839}
840
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