/** * Get the full program path. * * @return a newly allocated string (through halloc()) that points to the * path of the program being run, NULL if we can't compute a suitable path. */ char * file_program_path(const char *argv0) { filestat_t buf; char *file = deconstify_char(argv0); char filepath[MAX_PATH_LEN + 1]; if (is_running_on_mingw() && !is_strsuffix(argv0, (size_t) -1, ".exe")) { concat_strings(filepath, sizeof filepath, argv0, ".exe", NULL_PTR); } else { clamp_strcpy(filepath, sizeof filepath, argv0); } if (-1 == stat(filepath, &buf)) { int saved_errno = errno; file = file_locate_from_path(argv0); if (NULL == file) { errno = saved_errno; s_warning("%s(): could not stat() \"%s\": %m", G_STRFUNC, filepath); return NULL; } } if (file != NULL && file != argv0) return file; /* Allocated by file_locate_from_path() */ return h_strdup(filepath); }
/** * Search executable within the user's PATH. * * @return full path if found, NULL otherwise. * The returned string is allocated with halloc(). */ char * file_locate_from_path(const char *argv0) { static bool already_done; char *path; char *tok; char filepath[MAX_PATH_LEN + 1]; char *result = NULL; char *ext = ""; if (is_running_on_mingw() && !is_strsuffix(argv0, (size_t) -1, ".exe")) { ext = ".exe"; } if (filepath_basename(argv0) != argv0) { if (!already_done) { s_warning("can't locate \"%s\" in PATH: name contains '%c' already", argv0, strchr(argv0, G_DIR_SEPARATOR) != NULL ? G_DIR_SEPARATOR : '/'); } goto done; } path = getenv("PATH"); if (NULL == path) { if (!already_done) { s_warning("can't locate \"%s\" in PATH: " "no such environment variable", argv0); } goto done; } path = h_strdup(path); tok = strtok(path, G_SEARCHPATH_SEPARATOR_S); while (NULL != tok) { const char *dir = tok; filestat_t buf; if ('\0' == *dir) dir = "."; concat_strings(filepath, sizeof filepath, dir, G_DIR_SEPARATOR_S, argv0, ext, NULL); if (-1 != stat(filepath, &buf)) { if (S_ISREG(buf.st_mode) && -1 != access(filepath, X_OK)) { result = h_strdup(filepath); break; } } tok = strtok(NULL, G_SEARCHPATH_SEPARATOR_S); } hfree(path); done: already_done = TRUE; /* No warning on subsequent invocation */ return result; }
/** * Search executable within the user's PATH. * * @return full path if found, NULL otherwise. * The returned string is allocated with halloc(). */ char * file_locate_from_path(const char *argv0) { static bool already_done; char *path; char *tok; char filepath[MAX_PATH_LEN + 1]; char *result = NULL; char *ext = ""; if (is_running_on_mingw() && !is_strsuffix(argv0, (size_t) -1, ".exe")) { ext = ".exe"; } if (filepath_basename(argv0) != argv0) { if (!already_done) { s_warning("can't locate \"%s\" in PATH: name contains '%c' already", argv0, strchr(argv0, G_DIR_SEPARATOR) != NULL ? G_DIR_SEPARATOR : '/'); } result = h_strdup(argv0); goto done; } path = getenv("PATH"); if (NULL == path) { if (!already_done) { s_warning("can't locate \"%s\" in PATH: " "no such environment variable", argv0); } goto done; } /* * On Windows, we need to implicitly add "." to the path if not already * present -- this is done by appending a separator and a dot, not by * checking whether "." is already part of the path. * * The reason is that "." is implied, and also because one may omit the * ".exe" extension when launching a program. This means checks done * in crash_init() for instance to see whether the file listed in * argv[0] exists and which do not account for a missing ".exe" will * attempt to locate the program in the PATH to get a full name and will * fail if we do not add ".". * * On UNIX this cannot happen because there is no hidden extension and * the "." is never made part of the PATH implictly. * * --RAM, 2015-12-06 */ if (is_running_on_mingw()) path = h_strdup_printf("%s%c.", path, *G_SEARCHPATH_SEPARATOR_S); else path = h_strdup(path); path = h_strdup(path); /* FIXME: strtok() is not thread-safe --RAM, 2015-12-06 */ tok = strtok(path, G_SEARCHPATH_SEPARATOR_S); while (NULL != tok) { const char *dir = tok; filestat_t buf; if ('\0' == *dir) dir = "."; concat_strings(filepath, sizeof filepath, dir, G_DIR_SEPARATOR_S, argv0, ext, NULL_PTR); if (-1 != stat(filepath, &buf)) { if (S_ISREG(buf.st_mode) && -1 != access(filepath, X_OK)) { result = h_strdup(filepath); break; } } tok = strtok(NULL, G_SEARCHPATH_SEPARATOR_S); } hfree(path); done: already_done = TRUE; /* No warning on subsequent invocation */ return result; }