xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/gnulib-lib/findprog.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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