/* CYG_PATH is a pointer to a Cygwin path. This function converts the Cygwin path to a Windows path, storing the result in WIN32_PATH. Returns true if the conversion was successful; false otherwise. */ int cygpath (const char *cyg_path, char win32_path[MAX_PATH + 1]) { bool ok; bool retrying; /* Special-case the empty path. cygpath cannot handle the empty path correctly. It ignores the empty line, waiting for a non-empty line, which in turn causes an application using this function to appear stuck. */ if (cyg_path[0] == '\0') { win32_path[0] = '\0'; return true; } retrying = false; retry: if (!cygpath_initialized) { const char *argv[] = { "cygpath", "-w", "-f", "-", NULL }; const char *cygpath_path; const char *log; int err; /* If we are unable to invoke cygpath, we do not want to try again. So, we set the initialized flag at this point; if errors occur during the invocation, it will remain set. */ cygpath_initialized = 1; /* Check to see if the user wants cygpath support. */ cygpath_path = getenv ("CYGPATH"); if (!cygpath_path) /* The user doesn't need to support Cygwin paths. */ goto error; /* If debugging, open the log file. */ log = getenv ("CSL_DEBUG_CYGPATH"); if (log && log[0]) { /* The log file is opened for "append" so that multiple processes (perhaps invoked from "make") can share it. */ cygpath_log = fopen (log, "a"); if (cygpath_log) cygpath_log_msg ("begin"); } /* If the environment variable is set to a non-empty string, use that string as the path to cygpath. */ if (cygpath_path[0] != '\0') argv[0] = cygpath_path; /* Create the pex object. */ cygpath_pex = pex_init (PEX_SEARCH | PEX_USE_PIPES, "cygpath", NULL); if (!cygpath_pex) goto error; /* Get the FILE we will use to write to the child. */ cygpath_in = pex_input_pipe (cygpath_pex, /*binary=*/0); if (!cygpath_in) goto error; /* Start the child process. */ if (pex_run (cygpath_pex, PEX_SEARCH | PEX_USE_PIPES, argv[0], (char**) argv, NULL, NULL, &err) != NULL) goto error; /* Get the FILE we will use to read from the child. */ cygpath_out = pex_read_output (cygpath_pex, /*binary=*/1); if (!cygpath_out) goto error; } else if (!cygpath_pex) /* We previously tried to use cygpath, but something went wrong. */ return false; /* Write CYG_PATH to the child, on a line by itself. */ cygpath_log_msg_arg ("-> %s", cyg_path); if (fprintf (cygpath_in, "%s\n", cyg_path) < 0) { cygpath_perror ("write failed"); goto error; } /* Flush the output. (We cannot set the stream into line-buffered mode with setvbuf because Windows treats _IOLBF as a synonym for _IOFBF.) */ if (fflush (cygpath_in)) cygpath_perror ("flush failed"); /* Read the output. */ ok = true; while (1) { size_t pathlen; if (!fgets (win32_path, MAX_PATH, cygpath_out)) { if (ferror (cygpath_out)) cygpath_perror ("read failed"); else { cygpath_log_msg ("error: EOF"); /* Unfortunately, cygpath sometimes crashes for no apparent reason. We give it two chances... */ if (!retrying) { retrying = true; cygpath_log_msg ("retrying"); cygpath_close (); cygpath_initialized = 0; goto retry; } } goto error; } pathlen = strlen (win32_path); if (pathlen == 0 && ok) /* This isn't a well-formed response from cygpath. */ goto error; if (win32_path[pathlen - 1] == '\n') { win32_path[pathlen - 1] = '\0'; cygpath_log_msg_arg ("<- %s", win32_path); break; } /* We didn't reach the end of the line. There's no point in trying to use this output, since we know the length of paths are limited to MAX_PATH characters, but we read the entire line so that we are still in sync with cygpath. */ ok = false; if (cygpath_log) cygpath_log_msg_arg ("error: invalid response: %s", win32_path); } return ok; error: cygpath_close(); return false; }
static void exec_lto_wrapper (char *argv[]) { int t, i; int status; char *at_args; FILE *args; FILE *wrapper_output; char *new_argv[3]; struct pex_obj *pex; const char *errmsg; /* Write argv to a file to avoid a command line that is too long. */ arguments_file_name = make_temp_file (""); check (arguments_file_name, LDPL_FATAL, "Failed to generate a temorary file name"); args = fopen (arguments_file_name, "w"); check (args, LDPL_FATAL, "could not open arguments file"); t = writeargv (&argv[1], args); check (t == 0, LDPL_FATAL, "could not write arguments"); t = fclose (args); check (t == 0, LDPL_FATAL, "could not close arguments file"); at_args = concat ("@", arguments_file_name, NULL); check (at_args, LDPL_FATAL, "could not allocate"); for (i = 1; argv[i]; i++) { char *a = argv[i]; if (a[0] == '-' && a[1] == 'v' && a[2] == '\0') { for (i = 0; argv[i]; i++) fprintf (stderr, "%s ", argv[i]); fprintf (stderr, "\n"); break; } } new_argv[0] = argv[0]; new_argv[1] = at_args; new_argv[2] = NULL; if (debug) { for (i = 0; new_argv[i]; i++) fprintf (stderr, "%s ", new_argv[i]); fprintf (stderr, "\n"); } pex = pex_init (PEX_USE_PIPES, "lto-wrapper", NULL); check (pex != NULL, LDPL_FATAL, "could not pex_init lto-wrapper"); errmsg = pex_run (pex, 0, new_argv[0], new_argv, NULL, NULL, &t); check (errmsg == NULL, LDPL_FATAL, "could not run lto-wrapper"); check (t == 0, LDPL_FATAL, "could not run lto-wrapper"); wrapper_output = pex_read_output (pex, 0); check (wrapper_output, LDPL_FATAL, "could not read lto-wrapper output"); add_output_files (wrapper_output); t = pex_get_status (pex, 1, &status); check (t == 1, LDPL_FATAL, "could not get lto-wrapper exit status"); check (WIFEXITED (status) && WEXITSTATUS (status) == 0, LDPL_FATAL, "lto-wrapper failed"); pex_free (pex); free (at_args); }