fixpath.c revision 1789:11b31df300ae
190075Sobrien/*
2132718Skan * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
3169689Skan * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4169689Skan *
590075Sobrien * This code is free software; you can redistribute it and/or modify it
690075Sobrien * under the terms of the GNU General Public License version 2 only, as
7132718Skan * published by the Free Software Foundation.  Oracle designates this
890075Sobrien * particular file as subject to the "Classpath" exception as provided
9132718Skan * by Oracle in the LICENSE file that accompanied this code.
10132718Skan *
11132718Skan * This code is distributed in the hope that it will be useful, but WITHOUT
12132718Skan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1390075Sobrien * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14132718Skan * version 2 for more details (a copy is included in the LICENSE file that
15132718Skan * accompanied this code).
16132718Skan *
17132718Skan * You should have received a copy of the GNU General Public License version
1890075Sobrien * 2 along with this work; if not, write to the Free Software Foundation,
1990075Sobrien * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20132718Skan *
21169689Skan * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22169689Skan * or visit www.oracle.com if you need additional information or have any
2390075Sobrien * questions.
2490075Sobrien */
2590075Sobrien
26132718Skan#include <Windows.h>
27132718Skan#include <io.h>
28132718Skan#include <stdio.h>
29132718Skan#include <string.h>
30132718Skan#include <malloc.h>
31132718Skan
32132718Skanvoid report_error(char const * msg)
33132718Skan{
34132718Skan  LPVOID lpMsgBuf;
35132718Skan  DWORD dw = GetLastError();
36132718Skan
37132718Skan  FormatMessage(
38169689Skan      FORMAT_MESSAGE_ALLOCATE_BUFFER |
39169689Skan      FORMAT_MESSAGE_FROM_SYSTEM |
40169689Skan      FORMAT_MESSAGE_IGNORE_INSERTS,
41169689Skan      NULL,
42132718Skan      dw,
43132718Skan      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
44132718Skan      (LPTSTR) &lpMsgBuf,
45132718Skan      0,
46132718Skan      NULL);
47132718Skan
48132718Skan  fprintf(stderr,
49132718Skan          "%s  Failed with error %d: %s\n",
50132718Skan          msg, dw, lpMsgBuf);
51132718Skan
52132718Skan  LocalFree(lpMsgBuf);
53132718Skan}
54132718Skan
55132718Skan/*
56132718Skan * Test if pos points to /cygdrive/_/ where _ can
57132718Skan * be any character.
58169689Skan */
59169689Skanint is_cygdrive_here(int pos, char const *in, int len)
60169689Skan{
61169689Skan  // Length of /cygdrive/c/ is 12
62169689Skan  if (pos+12 > len) return 0;
63169689Skan  if (in[pos+11]=='/' &&
64169689Skan      in[pos+9]=='/' &&
65169689Skan      in[pos+8]=='e' &&
66169689Skan      in[pos+7]=='v' &&
67169689Skan      in[pos+6]=='i' &&
68169689Skan      in[pos+5]=='r' &&
69169689Skan      in[pos+4]=='d' &&
70169689Skan      in[pos+3]=='g' &&
71169689Skan      in[pos+2]=='y' &&
72169689Skan      in[pos+1]=='c' &&
73169689Skan      in[pos+0]=='/') {
74169689Skan    return 1;
75132718Skan  }
76132718Skan  return 0;
77132718Skan}
78132718Skan
79132718Skan/*
80132718Skan * Replace /cygdrive/_/ with _:/
81132718Skan * Works in place since drive letter is always
82132718Skan * shorter than /cygdrive/
83169689Skan */
84169689Skanchar *replace_cygdrive_cygwin(char const *in)
85132718Skan{
86132718Skan  size_t len = strlen(in);
8790075Sobrien  char *out = (char*) malloc(len+1);
8890075Sobrien  int i,j;
8990075Sobrien
90169689Skan  if (len < 12) {
9190075Sobrien    memmove(out, in, len + 1);
9290075Sobrien    return out;
9390075Sobrien  }
94169689Skan
9590075Sobrien  for (i = 0, j = 0; i<len;) {
9690075Sobrien    if (is_cygdrive_here(i, in, len)) {
9790075Sobrien      out[j++] = in[i+10];
9890075Sobrien      out[j++] = ':';
9990075Sobrien      i+=11;
10090075Sobrien    } else {
10190075Sobrien      out[j] = in[i];
10290075Sobrien      i++;
10390075Sobrien      j++;
10490075Sobrien    }
10590075Sobrien  }
10690075Sobrien  out[j] = '\0';
10790075Sobrien  return out;
10890075Sobrien}
109132718Skan
11090075Sobrienvoid append(char **b, size_t *bl, size_t *u, char *add, size_t addlen)
11190075Sobrien{
112132718Skan  while ((addlen+*u+1) > *bl) {
11390075Sobrien    *bl *= 2;
114132718Skan    *b = (char*) realloc(*b, *bl);
115132718Skan  }
116132718Skan  memcpy(*b+*u, add, addlen);
117132718Skan  *u += addlen;
118132718Skan}
119132718Skan
120132718Skan/*
121132718Skan * Creates a new string from in where the first occurrence of sub is
122132718Skan * replaced by rep.
123132718Skan */
124132718Skanchar *replace_substring(char *in, char *sub, char *rep)
125132718Skan{
126132718Skan  int in_len = strlen(in);
12790075Sobrien  int sub_len = strlen(sub);
128169689Skan  int rep_len = strlen(rep);
129169689Skan  char *out = (char *) malloc(in_len - sub_len + rep_len + 1);
130169689Skan  char *p;
131169689Skan
132169689Skan  if (!(p = strstr(in, sub))) {
13390075Sobrien    // If sub isn't a substring of in, just return in.
134169689Skan    return in;
135169689Skan  }
136169689Skan
137169689Skan  // Copy characters from beginning of in to start of sub.
138169689Skan  strncpy(out, in, p - in);
139169689Skan  out[p - in] = '\0';
140169689Skan
141169689Skan  sprintf(out + (p - in), "%s%s", rep, p + sub_len);
142169689Skan
143169689Skan  return out;
144169689Skan}
145169689Skan
146169689Skanchar* msys_path_list; // @-separated list of paths prefix to look for
147169689Skanchar* msys_path_list_end; // Points to last \0 in msys_path_list.
148169689Skan
149169689Skanvoid setup_msys_path_list(char const * argument)
150169689Skan{
151169689Skan  char* p;
152169689Skan  char* drive_letter_pos;
153169689Skan
154169689Skan  msys_path_list = strdup(&argument[2]);
155169689Skan  msys_path_list_end = &msys_path_list[strlen(msys_path_list)];
156169689Skan
157169689Skan  // Convert all at-sign (@) in path list to \0.
158169689Skan  // @ was chosen as separator to minimize risk of other tools messing around with it
159169689Skan  p = msys_path_list;
160169689Skan  do {
161169689Skan    if (p[1] == ':') {
162169689Skan      // msys has mangled our path list, restore it from c:/... to /c/...
163169689Skan      drive_letter_pos = p+1;
164169689Skan      *drive_letter_pos = *p;
165169689Skan      *p = '/';
166169689Skan    }
167169689Skan
168169689Skan    // Look for an @ in the list
169169689Skan    p = strchr(p, '@');
17090075Sobrien    if (p != NULL) {
17190075Sobrien      *p = '\0';
17290075Sobrien      p++;
173169689Skan    }
17490075Sobrien  } while (p != NULL);
175169689Skan}
17690075Sobrien
17790075Sobrienchar *replace_cygdrive_msys(char const *in)
17890075Sobrien{
179169689Skan  char* str;
18090075Sobrien  char* prefix;
181169689Skan  char* p;
18290075Sobrien
18390075Sobrien  str = strdup(in);
184169689Skan
185169689Skan  // For each prefix in the path list, search for it and replace /c/... with c:/...
18690075Sobrien  for (prefix = msys_path_list; prefix < msys_path_list_end && prefix != NULL; prefix += strlen(prefix)+1) {
18790075Sobrien    p=str;
188169689Skan    while ((p = strstr(p, prefix))) {
18990075Sobrien      char* drive_letter = p+1;
190169689Skan      *p = *drive_letter;
19190075Sobrien      *drive_letter = ':';
19290075Sobrien      p++;
193132718Skan    }
19490075Sobrien  }
195169689Skan
19690075Sobrien  return str;
19790075Sobrien}
19890075Sobrien
19990075Sobrienchar*(*replace_cygdrive)(char const *in) = NULL;
20090075Sobrien
20190075Sobrienchar *files_to_delete[1024];
202169689Skanint num_files_to_delete = 0;
20390075Sobrien
20490075Sobrienchar *fix_at_file(char const *in)
20590075Sobrien{
20690075Sobrien  char *tmpdir;
20790075Sobrien  char name[2048];
20890075Sobrien  char *atname;
20990075Sobrien  char *buffer;
21090075Sobrien  size_t buflen=65536;
21190075Sobrien  size_t used=0;
21290075Sobrien  size_t len;
213169689Skan  int rc;
21490075Sobrien  FILE *atout;
215169689Skan  FILE *atin;
21690075Sobrien  char block[2048];
21790075Sobrien  size_t blocklen;
21890075Sobrien  char *fixed;
219132718Skan
22090075Sobrien  atin = fopen(in+1, "r");
221169689Skan  if (atin == NULL) {
22290075Sobrien    fprintf(stderr, "Could not read at file %s\n", in+1);
22390075Sobrien    exit(-1);
22490075Sobrien  }
22590075Sobrien
22690075Sobrien  tmpdir = getenv("TEMP");
22790075Sobrien  if (tmpdir == NULL) {
228169689Skan#if _WIN64
22990075Sobrien    tmpdir = "c:/cygwin64/tmp";
23090075Sobrien#else
23190075Sobrien    tmpdir = "c:/cygwin/tmp";
23290075Sobrien#endif
23390075Sobrien  }
23490075Sobrien  _snprintf(name, sizeof(name), "%s\\atfile_XXXXXX", tmpdir);
23590075Sobrien
23690075Sobrien  rc = _mktemp_s(name, strlen(name)+1);
23790075Sobrien  if (rc) {
23890075Sobrien    fprintf(stderr, "Could not create temporary file name for at file!\n");
23990075Sobrien    exit(-1);
24090075Sobrien  }
24190075Sobrien
24290075Sobrien  atout = fopen(name, "w");
24390075Sobrien  if (atout == NULL) {
24490075Sobrien    fprintf(stderr, "Could not open temporary file for writing! %s\n", name);
24590075Sobrien    exit(-1);
24690075Sobrien  }
24790075Sobrien
24890075Sobrien  buffer = (char*) malloc(buflen);
24990075Sobrien  while ((blocklen = fread(block, 1, sizeof(block), atin)) > 0) {
25090075Sobrien    append(&buffer, &buflen, &used, block, blocklen);
251132718Skan  }
25290075Sobrien  buffer[used] = 0;
25390075Sobrien  if (getenv("DEBUG_FIXPATH") != NULL) {
25490075Sobrien    fprintf(stderr, "fixpath input from @-file %s: %s\n", &in[1], buffer);
25590075Sobrien  }
25690075Sobrien  fixed = replace_cygdrive(buffer);
25790075Sobrien  if (getenv("DEBUG_FIXPATH") != NULL) {
25890075Sobrien    fprintf(stderr, "fixpath converted to @-file %s is: %s\n", name, fixed);
25990075Sobrien  }
26090075Sobrien  fwrite(fixed, strlen(fixed), 1, atout);
26190075Sobrien  fclose(atin);
26290075Sobrien  fclose(atout);
26390075Sobrien  free(fixed);
26490075Sobrien  free(buffer);
26590075Sobrien  files_to_delete[num_files_to_delete] = (char*) malloc(strlen(name)+1);
26690075Sobrien  strcpy(files_to_delete[num_files_to_delete], name);
26790075Sobrien  num_files_to_delete++;
26890075Sobrien  atname = (char*) malloc(strlen(name)+2);
26990075Sobrien  atname[0] = '@';
27090075Sobrien  strcpy(atname+1, name);
27190075Sobrien  return atname;
27290075Sobrien}
27390075Sobrien
27490075Sobrien// given an argument, convert it to the windows command line safe quoted version
27590075Sobrien// using rules from:
27690075Sobrien// http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx
277132718Skan// caller is responsible for freeing both input and output.
27890075Sobrienchar * quote_arg(char const * in_arg) {
27990075Sobrien  char *quoted = NULL;
28090075Sobrien  char *current = quoted;
28190075Sobrien  int pass;
28290075Sobrien
28390075Sobrien  if (strlen(in_arg) == 0) {
28490075Sobrien     // empty string? explicitly quote it.
28590075Sobrien     return _strdup("\"\"");
28690075Sobrien  }
28790075Sobrien
28890075Sobrien  if (strpbrk(in_arg, " \t\n\v\r\\\"") == NULL) {
28990075Sobrien     return _strdup(in_arg);
29090075Sobrien  }
29190075Sobrien
29290075Sobrien  // process the arg twice. Once to calculate the size and then to copy it.
29390075Sobrien  for (pass=1; pass<=2; pass++) {
29490075Sobrien    char const *arg = in_arg;
29590075Sobrien
29690075Sobrien    // initial "
29790075Sobrien    if (pass == 2) {
29890075Sobrien      *current = '\"';
29990075Sobrien    }
30090075Sobrien    current++;
30190075Sobrien
30290075Sobrien    // process string to be quoted until NUL
30390075Sobrien    do {
30490075Sobrien      int escapes = 0;
30590075Sobrien
30690075Sobrien      while (*arg == '\\') {
30790075Sobrien        // count escapes.
30890075Sobrien        escapes++;
30990075Sobrien        arg++;
31090075Sobrien      }
311132718Skan
31290075Sobrien      if (*arg == '\0') {
31390075Sobrien         // escape the escapes before final "
31490075Sobrien         escapes *= 2;
31590075Sobrien      } else if (*arg == '"') {
31690075Sobrien        // escape the escapes and the "
31790075Sobrien        escapes = escapes * 2 + 1;
318132718Skan      } else {
31990075Sobrien         // escapes aren't special, just echo them.
32090075Sobrien      }
32190075Sobrien
32290075Sobrien      // emit some escapes
32390075Sobrien      while (escapes > 0) {
32490075Sobrien        if (pass == 2) {
32590075Sobrien          *current = '\\';
32690075Sobrien        }
32790075Sobrien        current++;
32890075Sobrien        escapes--;
32990075Sobrien      }
33090075Sobrien
33190075Sobrien      // and the current char
33290075Sobrien      if (pass == 2) {
33390075Sobrien        *current = *arg;
33490075Sobrien      }
33590075Sobrien      current++;
33690075Sobrien    } while (*arg++ != '\0');
33790075Sobrien
33890075Sobrien    // allocate the buffer
33990075Sobrien    if (pass == 1) {
34090075Sobrien      size_t alloc = (size_t) (current - quoted + (ptrdiff_t) 2);
34190075Sobrien      current = quoted = (char*) calloc(alloc, sizeof(char));
34290075Sobrien    }
34390075Sobrien  }
344132718Skan
34590075Sobrien  // final " and \0
34690075Sobrien  *(current - 1) = '"';
34790075Sobrien  *current = '\0';
34890075Sobrien
34990075Sobrien  return quoted;
35090075Sobrien}
35190075Sobrien
35290075Sobrienint main(int argc, char const ** argv)
35390075Sobrien{
35490075Sobrien    STARTUPINFO si;
35590075Sobrien    PROCESS_INFORMATION pi;
35690075Sobrien    unsigned short rc;
35790075Sobrien
35890075Sobrien    char *line;
35990075Sobrien    char *current;
36090075Sobrien    int i, cmd;
36190075Sobrien    DWORD exitCode = 0;
36290075Sobrien    DWORD processFlags = 0;
36390075Sobrien    BOOL processInheritHandles = TRUE;
36490075Sobrien    BOOL waitForChild = TRUE;
36590075Sobrien
36690075Sobrien    if (argc<2 || argv[1][0] != '-' || (argv[1][1] != 'c' && argv[1][1] != 'm')) {
36790075Sobrien        fprintf(stderr, "Usage: fixpath -c|m<path@path@...> [--detach] /cygdrive/c/WINDOWS/notepad.exe [/cygdrive/c/x/test.txt|@/cygdrive/c/x/atfile]\n");
36890075Sobrien        exit(0);
36990075Sobrien    }
37090075Sobrien
37190075Sobrien    if (getenv("DEBUG_FIXPATH") != NULL) {
37290075Sobrien      char const * cmdline = GetCommandLine();
37390075Sobrien      fprintf(stderr, "fixpath input line >%s<\n", strstr(cmdline, argv[1]));
37490075Sobrien    }
37590075Sobrien
37690075Sobrien    if (argv[1][1] == 'c' && argv[1][2] == '\0') {
37790075Sobrien      if (getenv("DEBUG_FIXPATH") != NULL) {
378132718Skan        fprintf(stderr, "fixpath using cygwin mode\n");
37990075Sobrien      }
38090075Sobrien      replace_cygdrive = replace_cygdrive_cygwin;
38190075Sobrien    } else if (argv[1][1] == 'm') {
38290075Sobrien      if (getenv("DEBUG_FIXPATH") != NULL) {
38390075Sobrien        fprintf(stderr, "fixpath using msys mode, with path list: %s\n", &argv[1][2]);
38490075Sobrien      }
385132718Skan      setup_msys_path_list(argv[1]);
38690075Sobrien      replace_cygdrive = replace_cygdrive_msys;
38790075Sobrien    } else {
38890075Sobrien      fprintf(stderr, "fixpath Unknown mode: %s\n", argv[1]);
38990075Sobrien      exit(-1);
39090075Sobrien    }
39190075Sobrien
39290075Sobrien    if (argv[2][0] == '-') {
39390075Sobrien      if (strcmp(argv[2], "--detach") == 0) {
39490075Sobrien        if (getenv("DEBUG_FIXPATH") != NULL) {
39590075Sobrien          fprintf(stderr, "fixpath in detached mode\n");
39690075Sobrien        }
39790075Sobrien        processFlags |= DETACHED_PROCESS;
39890075Sobrien        processInheritHandles = FALSE;
39990075Sobrien        waitForChild = FALSE;
40090075Sobrien      } else {
40190075Sobrien        fprintf(stderr, "fixpath Unknown argument: %s\n", argv[2]);
40290075Sobrien        exit(-1);
40390075Sobrien      }
40490075Sobrien      i = 3;
40590075Sobrien    } else {
40690075Sobrien      i = 2;
40790075Sobrien    }
40890075Sobrien
40990075Sobrien    // handle assignments
41090075Sobrien    while (i < argc) {
411132718Skan      char const * assignment = strchr(argv[i], '=');
41290075Sobrien      if (assignment != NULL && assignment != argv[i]) {
41390075Sobrien        size_t var_len = (size_t) (assignment - argv[i] + (ptrdiff_t) 1);
41490075Sobrien        char *var = (char *) calloc(var_len, sizeof(char));
41590075Sobrien        char *val = replace_cygdrive(assignment + 1);
41690075Sobrien        memmove(var, argv[i], var_len);
41790075Sobrien        var[var_len - 1] = '\0';
41890075Sobrien        strupr(var);
41990075Sobrien
42090075Sobrien        if (getenv("DEBUG_FIXPATH") != NULL) {
42190075Sobrien          fprintf(stderr, "fixpath setting var >%s< to >%s<\n", var, val);
42290075Sobrien        }
42390075Sobrien
42490075Sobrien        rc = SetEnvironmentVariable(var, val);
42590075Sobrien        if (!rc) {
42690075Sobrien          // Could not set var for some reason.  Try to report why.
42790075Sobrien          const int msg_len = 80 + var_len + strlen(val);
42890075Sobrien          char * msg = (char *) alloca(msg_len);
42990075Sobrien          _snprintf_s(msg, msg_len, _TRUNCATE, "Could not set environment variable [%s=%s]", var, val);
43090075Sobrien          report_error(msg);
43190075Sobrien          exit(1);
43290075Sobrien        }
43390075Sobrien        free(var);
43490075Sobrien        free(val);
43590075Sobrien      } else {
43690075Sobrien        // no more assignments;
43790075Sobrien        break;
43890075Sobrien      }
43990075Sobrien      i++;
44090075Sobrien    }
44190075Sobrien
44290075Sobrien    // remember index of the command
44390075Sobrien    cmd = i;
44490075Sobrien
44590075Sobrien    // handle command and it's args.
44690075Sobrien    while (i < argc) {
44790075Sobrien      char const *replaced = replace_cygdrive(argv[i]);
44890075Sobrien      if (replaced[0] == '@') {
44990075Sobrien        if (waitForChild == FALSE) {
45090075Sobrien          fprintf(stderr, "fixpath Cannot use @-files in detached mode: %s\n", replaced);
45190075Sobrien          exit(1);
45290075Sobrien        }
45390075Sobrien        // Found at-file! Fix it!
45490075Sobrien        replaced = fix_at_file(replaced);
45590075Sobrien      }
45690075Sobrien      argv[i] = quote_arg(replaced);
45790075Sobrien      i++;
45890075Sobrien    }
45990075Sobrien
46090075Sobrien    // determine the length of the line
46190075Sobrien    line = NULL;
46290075Sobrien    // args
46390075Sobrien    for (i = cmd; i < argc; i++) {
46490075Sobrien      line += (ptrdiff_t) strlen(argv[i]);
46590075Sobrien    }
46690075Sobrien    // spaces and null
46790075Sobrien    line += (ptrdiff_t) (argc - cmd + 1);
46890075Sobrien    // allocate
46990075Sobrien    line = (char*) calloc(line - (char*) NULL, sizeof(char));
47090075Sobrien
47190075Sobrien    // copy in args.
47290075Sobrien    current = line;
47390075Sobrien    for (i = cmd; i < argc; i++) {
47490075Sobrien      ptrdiff_t len = strlen(argv[i]);
47590075Sobrien      if (i != cmd) {
47690075Sobrien        *current++ = ' ';
47790075Sobrien      }
47890075Sobrien      memmove(current, argv[i], len);
47990075Sobrien      current += len;
48090075Sobrien    }
48190075Sobrien    *current = '\0';
48290075Sobrien
48390075Sobrien    if (getenv("DEBUG_FIXPATH") != NULL) {
48490075Sobrien      fprintf(stderr, "fixpath converted line >%s<\n", line);
48590075Sobrien    }
48690075Sobrien
48790075Sobrien    if (cmd == argc) {
48890075Sobrien       if (getenv("DEBUG_FIXPATH") != NULL) {
48990075Sobrien         fprintf(stderr, "fixpath no command provided!\n");
49090075Sobrien       }
49190075Sobrien       exit(0);
49290075Sobrien    }
49390075Sobrien
49490075Sobrien    ZeroMemory(&si, sizeof(si));
49590075Sobrien    si.cb=sizeof(si);
49690075Sobrien    ZeroMemory(&pi, sizeof(pi));
49790075Sobrien
49890075Sobrien    fflush(stderr);
49990075Sobrien    fflush(stdout);
50090075Sobrien
50190075Sobrien    rc = CreateProcess(NULL,
50290075Sobrien                       line,
50390075Sobrien                       0,
50490075Sobrien                       0,
50590075Sobrien                       processInheritHandles,
50690075Sobrien                       processFlags,
50790075Sobrien                       NULL,
50890075Sobrien                       NULL,
50990075Sobrien                       &si,
51090075Sobrien                       &pi);
51190075Sobrien    if (!rc) {
51290075Sobrien      // Could not start process for some reason.  Try to report why:
51390075Sobrien      report_error("Could not start process!");
51490075Sobrien      exit(126);
51590075Sobrien    }
51690075Sobrien
51790075Sobrien    if (waitForChild == TRUE) {
51890075Sobrien      WaitForSingleObject(pi.hProcess, INFINITE);
51990075Sobrien      GetExitCodeProcess(pi.hProcess, &exitCode);
52090075Sobrien
52190075Sobrien      if (getenv("DEBUG_FIXPATH") != NULL) {
52290075Sobrien        for (i=0; i<num_files_to_delete; ++i) {
52390075Sobrien          fprintf(stderr, "fixpath Not deleting temporary file %s\n",
52490075Sobrien                  files_to_delete[i]);
52590075Sobrien        }
52690075Sobrien      } else {
52790075Sobrien        for (i=0; i<num_files_to_delete; ++i) {
52890075Sobrien          remove(files_to_delete[i]);
52990075Sobrien        }
53090075Sobrien      }
53190075Sobrien
53290075Sobrien      if (exitCode != 0) {
53390075Sobrien        if (getenv("DEBUG_FIXPATH") != NULL) {
53490075Sobrien          fprintf(stderr, "fixpath exit code %d\n",
53590075Sobrien                  exitCode);
53690075Sobrien        }
53790075Sobrien      }
53890075Sobrien    } else {
53990075Sobrien      if (getenv("DEBUG_FIXPATH") != NULL) {
54090075Sobrien        fprintf(stderr, "fixpath Not waiting for child process");
54190075Sobrien      }
54290075Sobrien    }
54390075Sobrien
54490075Sobrien    exit(exitCode);
54590075Sobrien}
54690075Sobrien