1 /* @(#)searchinpath.c 1.5 16/08/01 Copyright 1999-2016 J. Schilling */
2 #include <schily/mconfig.h>
4 static UConst
char sccsid
[] =
5 "@(#)searchinpath.c 1.5 16/08/01 Copyright 1999-2016 J. Schilling";
8 * Search a file name in the PATH of the current exeecutable.
9 * Return the path to the file name in allocated space.
11 * Copyright (c) 1999-2016 J. Schilling
14 * The contents of this file are subject to the terms of the
15 * Common Development and Distribution License, Version 1.0 only
16 * (the "License"). You may not use this file except in compliance
19 * See the file CDDL.Schily.txt in this distribution for details.
20 * A copy of the CDDL is also available via the Internet at
21 * http://www.opensource.org/licenses/cddl1.txt
23 * When distributing Covered Code, include this CDDL HEADER in each
24 * file and include the License file CDDL.Schily.txt from this distribution.
27 #include <schily/mconfig.h>
28 #include <schily/string.h>
29 #include <schily/unistd.h>
30 #include <schily/stdlib.h> /* getexecname() */
31 #include <schily/stat.h>
32 #include <schily/standard.h>
33 #include <schily/schily.h>
34 #include <schily/errno.h>
39 EXPORT
char *searchfileinpath
__PR((char *name
, int mode
,
42 LOCAL
char *searchonefile
__PR((char *name
, int mode
,
47 #if defined(__DJGPP__)
48 LOCAL
char *strbs2s
__PR((char *s
));
52 #define enofile(t) ((t) == EMISSDIR || \
57 #define enofile(t) ((t) == ENOENT || \
64 * Search for the "name" file in the PATH of the user.
65 * Assume that the file is ... bin/../name.
68 searchfileinpath(name
, mode
, file_mode
, path
)
69 char *name
; /* Find <execname>/../name in PATH */
70 int mode
; /* Mode for access() e.g. X_OK */
71 int file_mode
; /* How to check files */
72 char *path
; /* PATH to use if not NULL */
79 int nlen
= strlen(name
);
80 int oerrno
= geterrno();
82 #ifdef HAVE_GETEXECNAME
83 char *pn
= (char *)getexecname(); /* pn is on the stack */
85 char *pn
= getexecpath(); /* pn is from strdup() */
89 strlcpy(ebuf
, pn
, sizeof (ebuf
));
99 if ((np
= strrchr(xn
, '/')) != NULL
)
103 * getexecname() is the best choice for our seach. getexecname()
104 * returns either "foo" (if called from the current directory) or
105 * an absolute path after symlinks have been resolved.
106 * If getexecname() returns a path with slashes, try to search
107 * first relatively to the known location of the current binary.
109 if ((file_mode
& SIP_ONLY_PATH
) == 0 &&
110 pn
!= NULL
&& strchr(pn
, '/') != NULL
) {
111 strlcpy(nbuf
, pn
, sizeof (pbuf
));
112 np
= nbuf
+ strlen(nbuf
);
114 while (np
> nbuf
&& np
[-1] != '/')
116 pn
= &nbuf
[sizeof (pbuf
) - 1];
117 if ((np
= searchonefile(name
, mode
,
118 file_mode
& (SIP_PLAIN_FILE
|SIP_NO_STRIPBIN
),
120 nbuf
, np
, pn
)) != NULL
) {
126 if (file_mode
& SIP_NO_PATH
)
130 path
= getenv("PATH");
139 strbs2s(path
); /* PATH under DJGPP can contain both slashes */
143 * A PATH name search should lead us to the path under which we
144 * called the binary, but not necessarily to the install path as
145 * we may have been called thorugh a symlink or hardlink. In case
146 * of a symlink, we can follow the link. In case of a hardlink, we
149 ep
= &nbuf
[sizeof (pbuf
) - 1];
152 while (*path
!= PATH_ENV_DELIM
&& *path
!= '\0' &&
153 np
< &nbuf
[sizeof (pbuf
) - nlen
])
156 if ((np
= searchonefile(name
, mode
,
157 file_mode
& (SIP_PLAIN_FILE
|SIP_NO_STRIPBIN
),
159 nbuf
, np
, ep
)) != NULL
) {
186 searchonefile(name
, mode
, plain_file
, xn
, nbuf
, np
, ep
)
187 register char *name
; /* Find <execname>/../name in PATH */
188 int mode
; /* Mode for access() e.g. X_OK */
189 BOOL plain_file
; /* Whether to check only plain files */
190 char *xn
; /* The basename of the executable */
191 register char *nbuf
; /* Name buffer base */
192 register char *np
; /* Where to append name to path */
193 register char *ep
; /* Point to last valid char in nbuf */
197 while (np
> nbuf
&& np
[-1] == '/')
201 strlcpy(np
, xn
, ep
- np
);
202 if (stat(nbuf
, &sb
) < 0)
204 if (!S_ISREG(sb
.st_mode
))
208 if ((plain_file
& SIP_NO_STRIPBIN
) == 0) {
209 if (np
>= &nbuf
[4] && streql(&np
[-4], "/bin"))
212 plain_file
&= SIP_PLAIN_FILE
;
215 strlcpy(np
, name
, ep
- np
);
218 if (stat(nbuf
, &sb
) >= 0) {
219 if ((!plain_file
|| S_ISREG(sb
.st_mode
)) &&
220 (eaccess(nbuf
, mode
) >= 0)) {
221 return (strdup(nbuf
));