int execute (const char *name, const char **argv, const char *input, const char *output, const char **errmsg, int *waitstatus) { int errnum; if(input != NULL || output != NULL) { *errmsg = "execute input/output NYI"; return -1; } struct pex_obj *pex = pex_init(0, name, NULL); if (pex == NULL) { *errmsg = "pex_init failed"; return -1; } *errmsg = pex_run(pex, PEX_LAST, name, (char * const *)argv, output, NULL, &errnum); if (*errmsg != NULL || !pex_get_status(pex, 1, waitstatus)) { if (&errmsg == NULL) { *errmsg = "can't get program status"; } pex_free(pex); return -1; } pex_free(pex); return 0; }
int pexecute (const char *program, char * const *argv, const char *pname, const char *temp_base, char **errmsg_fmt, char **errmsg_arg, int flags) { const char *errmsg; int err; if ((flags & PEXECUTE_FIRST) != 0) { if (pex != NULL) { *errmsg_fmt = (char *) "pexecute already in progress"; *errmsg_arg = NULL; return -1; } pex = pex_init (PEX_USE_PIPES, pname, temp_base); idx = 0; } else { if (pex == NULL) { *errmsg_fmt = (char *) "pexecute not in progress"; *errmsg_arg = NULL; return -1; } } errmsg = pex_run (pex, (((flags & PEXECUTE_LAST) != 0 ? PEX_LAST : 0) | ((flags & PEXECUTE_SEARCH) != 0 ? PEX_SEARCH : 0)), program, argv, NULL, NULL, &err); if (errmsg != NULL) { *errmsg_fmt = (char *) errmsg; *errmsg_arg = NULL; return -1; } /* Instead of a PID, we just return a one-based index into the status values. We avoid zero just because the old pexecute would never return it. */ return ++idx; }
struct pex_obj * collect_execute (const char *prog, char **argv, const char *outname, const char *errname, int flags, bool use_atfile) { struct pex_obj *pex; const char *errmsg; int err; char *response_arg = NULL; char *response_argv[3]; if (use_atfile && argv[0] != NULL) { /* If using @file arguments, create a temporary file and put the contents of argv into it. Then change argv to an array corresponding to a single argument @FILE, where FILE is the temporary filename. */ char **current_argv = argv + 1; char *argv0 = argv[0]; int status; FILE *f; /* Note: we assume argv contains at least one element; this is checked above. */ response_file = make_temp_file (""); f = fopen (response_file, "w"); if (f == NULL) fatal_error (input_location, "could not open response file %s", response_file); status = writeargv (current_argv, f); if (status) fatal_error (input_location, "could not write to response file %s", response_file); status = fclose (f); if (EOF == status) fatal_error (input_location, "could not close response file %s", response_file); response_arg = concat ("@", response_file, NULL); response_argv[0] = argv0; response_argv[1] = response_arg; response_argv[2] = NULL; argv = response_argv; } if (verbose || debug) { char **p_argv; const char *str; if (argv[0]) fprintf (stderr, "%s", argv[0]); else notice ("[cannot find %s]", prog); for (p_argv = &argv[1]; (str = *p_argv) != (char *) 0; p_argv++) fprintf (stderr, " %s", str); fprintf (stderr, "\n"); } fflush (stdout); fflush (stderr); /* If we cannot find a program we need, complain error. Do this here since we might not end up needing something that we could not find. */ if (argv[0] == 0) fatal_error (input_location, "cannot find '%s'", prog); pex = pex_init (0, "collect2", NULL); if (pex == NULL) fatal_error (input_location, "pex_init failed: %m"); errmsg = pex_run (pex, flags, argv[0], argv, outname, errname, &err); if (errmsg != NULL) { if (err != 0) { errno = err; fatal_error (input_location, "%s: %m", _(errmsg)); } else fatal_error (input_location, errmsg); } free (response_arg); return pex; }
/* 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); }