1*946379e7Schristos /* Locating a program in PATH.
2*946379e7Schristos Copyright (C) 2001-2004, 2006 Free Software Foundation, Inc.
3*946379e7Schristos Written by Bruno Haible <haible@clisp.cons.org>, 2001.
4*946379e7Schristos
5*946379e7Schristos This program is free software; you can redistribute it and/or modify
6*946379e7Schristos it under the terms of the GNU General Public License as published by
7*946379e7Schristos the Free Software Foundation; either version 2, or (at your option)
8*946379e7Schristos any later version.
9*946379e7Schristos
10*946379e7Schristos This program is distributed in the hope that it will be useful,
11*946379e7Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
12*946379e7Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*946379e7Schristos GNU General Public License for more details.
14*946379e7Schristos
15*946379e7Schristos You should have received a copy of the GNU General Public License
16*946379e7Schristos along with this program; if not, write to the Free Software Foundation,
17*946379e7Schristos Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18*946379e7Schristos
19*946379e7Schristos
20*946379e7Schristos #include <config.h>
21*946379e7Schristos
22*946379e7Schristos /* Specification. */
23*946379e7Schristos #include "findprog.h"
24*946379e7Schristos
25*946379e7Schristos #include <stdbool.h>
26*946379e7Schristos #include <stdlib.h>
27*946379e7Schristos #include <string.h>
28*946379e7Schristos #include <unistd.h>
29*946379e7Schristos
30*946379e7Schristos #include "xalloc.h"
31*946379e7Schristos #include "pathname.h"
32*946379e7Schristos
33*946379e7Schristos
34*946379e7Schristos const char *
find_in_path(const char * progname)35*946379e7Schristos find_in_path (const char *progname)
36*946379e7Schristos {
37*946379e7Schristos #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
38*946379e7Schristos /* Win32, Cygwin, OS/2, DOS */
39*946379e7Schristos /* The searching rules with .COM, .EXE, .BAT, .CMD etc. suffixes are
40*946379e7Schristos too complicated. Leave it to the OS. */
41*946379e7Schristos return progname;
42*946379e7Schristos #else
43*946379e7Schristos /* Unix */
44*946379e7Schristos char *path;
45*946379e7Schristos char *path_rest;
46*946379e7Schristos char *cp;
47*946379e7Schristos
48*946379e7Schristos if (strchr (progname, '/') != NULL)
49*946379e7Schristos /* If progname contains a slash, it is either absolute or relative to
50*946379e7Schristos the current directory. PATH is not used. */
51*946379e7Schristos return progname;
52*946379e7Schristos
53*946379e7Schristos path = getenv ("PATH");
54*946379e7Schristos if (path == NULL || *path == '\0')
55*946379e7Schristos /* If PATH is not set, the default search path is implementation
56*946379e7Schristos dependent. */
57*946379e7Schristos return progname;
58*946379e7Schristos
59*946379e7Schristos /* Make a copy, to prepare for destructive modifications. */
60*946379e7Schristos path = xstrdup (path);
61*946379e7Schristos for (path_rest = path; ; path_rest = cp + 1)
62*946379e7Schristos {
63*946379e7Schristos const char *dir;
64*946379e7Schristos bool last;
65*946379e7Schristos char *progpathname;
66*946379e7Schristos
67*946379e7Schristos /* Extract next directory in PATH. */
68*946379e7Schristos dir = path_rest;
69*946379e7Schristos for (cp = path_rest; *cp != '\0' && *cp != ':'; cp++)
70*946379e7Schristos ;
71*946379e7Schristos last = (*cp == '\0');
72*946379e7Schristos *cp = '\0';
73*946379e7Schristos
74*946379e7Schristos /* Empty PATH components designate the current directory. */
75*946379e7Schristos if (dir == cp)
76*946379e7Schristos dir = ".";
77*946379e7Schristos
78*946379e7Schristos /* Concatenate dir and progname. */
79*946379e7Schristos progpathname = concatenated_pathname (dir, progname, NULL);
80*946379e7Schristos
81*946379e7Schristos /* On systems which have the eaccess() system call, let's use it.
82*946379e7Schristos On other systems, let's hope that this program is not installed
83*946379e7Schristos setuid or setgid, so that it is ok to call access() despite its
84*946379e7Schristos design flaw. */
85*946379e7Schristos if (eaccess (progpathname, X_OK) == 0)
86*946379e7Schristos {
87*946379e7Schristos /* Found! */
88*946379e7Schristos if (strcmp (progpathname, progname) == 0)
89*946379e7Schristos {
90*946379e7Schristos free (progpathname);
91*946379e7Schristos
92*946379e7Schristos /* Add the "./" prefix for real, that concatenated_pathname()
93*946379e7Schristos optimized away. This avoids a second PATH search when the
94*946379e7Schristos caller uses execlp/execvp. */
95*946379e7Schristos progpathname = xmalloc (2 + strlen (progname) + 1);
96*946379e7Schristos progpathname[0] = '.';
97*946379e7Schristos progpathname[1] = '/';
98*946379e7Schristos memcpy (progpathname + 2, progname, strlen (progname) + 1);
99*946379e7Schristos }
100*946379e7Schristos
101*946379e7Schristos free (path);
102*946379e7Schristos return progpathname;
103*946379e7Schristos }
104*946379e7Schristos
105*946379e7Schristos free (progpathname);
106*946379e7Schristos
107*946379e7Schristos if (last)
108*946379e7Schristos break;
109*946379e7Schristos }
110*946379e7Schristos
111*946379e7Schristos /* Not found in PATH. An error will be signalled at the first call. */
112*946379e7Schristos free (path);
113*946379e7Schristos return progname;
114*946379e7Schristos #endif
115*946379e7Schristos }
116