1 /* Locating a program in PATH.
2 Copyright (C) 2001-2004, 2006-2024 Free Software Foundation, Inc.
3 Written by Bruno Haible <haible@clisp.cons.org>, 2001.
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
10 This file is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
27 #if !(defined _WIN32 || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__)
28 # include <sys/stat.h>
31 /* Avoid collision between findprog.c and findprog-lgpl.c. */
32 #if IN_FINDPROG_LGPL || ! GNULIB_FINDPROG_LGPL
37 #include "concat-filename.h"
41 find_in_path (const char *progname
)
43 #if defined _WIN32 || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
44 /* Native Windows, Cygwin, OS/2, DOS */
45 /* The searching rules with .COM, .EXE, .BAT, .CMD etc. suffixes are
46 too complicated. Leave it to the OS. */
54 if (strchr (progname
, '/') != NULL
)
55 /* If progname contains a slash, it is either absolute or relative to
56 the current directory. PATH is not used. */
59 path
= getenv ("PATH");
60 if (path
== NULL
|| *path
== '\0')
61 /* If PATH is not set, the default search path is implementation
65 /* Make a copy, to prepare for destructive modifications. */
66 # if !IN_FINDPROG_LGPL
67 path
= xstrdup (path
);
74 for (path_rest
= path
; ; path_rest
= cp
+ 1)
80 /* Extract next directory in PATH. */
82 for (cp
= path_rest
; *cp
!= '\0' && *cp
!= ':'; cp
++)
87 /* Empty PATH components designate the current directory. */
91 /* Concatenate dir and progname. */
92 # if !IN_FINDPROG_LGPL
93 progpathname
= xconcatenated_filename (dir
, progname
, NULL
);
95 progpathname
= concatenated_filename (dir
, progname
, NULL
);
96 if (progpathname
== NULL
)
104 /* On systems which have the eaccess() system call, let's use it.
105 On other systems, let's hope that this program is not installed
106 setuid or setgid, so that it is ok to call access() despite its
108 if (eaccess (progpathname
, X_OK
) == 0)
110 /* Check that the progpathname does not point to a directory. */
113 if (stat (progpathname
, &statbuf
) >= 0
114 && ! S_ISDIR (statbuf
.st_mode
))
117 if (strcmp (progpathname
, progname
) == 0)
121 /* Add the "./" prefix for real, that xconcatenated_filename()
122 optimized away. This avoids a second PATH search when the
123 caller uses execlp/execvp. */
124 # if !IN_FINDPROG_LGPL
125 progpathname
= XNMALLOC (2 + strlen (progname
) + 1, char);
127 progpathname
= (char *) malloc (2 + strlen (progname
) + 1);
128 if (progpathname
== NULL
)
135 progpathname
[0] = '.';
136 progpathname
[1] = '/';
137 memcpy (progpathname
+ 2, progname
, strlen (progname
) + 1);
151 /* Not found in PATH. An error will be signalled at the first call. */