ReactOS 0.4.16-dev-338-g34e76ad
searchinpath.c
Go to the documentation of this file.
1/* @(#)searchinpath.c 1.5 16/08/01 Copyright 1999-2016 J. Schilling */
2#include <schily/mconfig.h>
3#ifndef lint
4static UConst char sccsid[] =
5 "@(#)searchinpath.c 1.5 16/08/01 Copyright 1999-2016 J. Schilling";
6#endif
7/*
8 * Search a file name in the PATH of the current exeecutable.
9 * Return the path to the file name in allocated space.
10 *
11 * Copyright (c) 1999-2016 J. Schilling
12 */
13/*
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
17 * with the License.
18 *
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
22 *
23 * When distributing Covered Code, include this CDDL HEADER in each
24 * file and include the License file CDDL.Schily.txt from this distribution.
25 */
26
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>
35
36
37#define NAMEMAX 4096
38
40 int file_mode,
41 char *path));
42LOCAL char *searchonefile __PR((char *name, int mode,
43 BOOL plain_file,
44 char *xn,
45 char *nbuf,
46 char *np, char *ep));
47#if defined(__DJGPP__)
48LOCAL char *strbs2s __PR((char *s));
49#endif
50
51#ifdef JOS
52#define enofile(t) ((t) == EMISSDIR || \
53 (t) == ENOFILE || \
54 (t) == EISADIR || \
55 (t) == EIOERR)
56#else
57#define enofile(t) ((t) == ENOENT || \
58 (t) == ENOTDIR || \
59 (t) == EISDIR || \
60 (t) == EIO)
61#endif
62
63/*
64 * Search for the "name" file in the PATH of the user.
65 * Assume that the file is ... bin/../name.
66 */
67EXPORT char *
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 */
73{
74 char pbuf[NAMEMAX];
75 char *nbuf = pbuf;
76 char *np;
77 char *ep;
78 char *xn;
79 int nlen = strlen(name);
80 int oerrno = geterrno();
81 int err = 0;
82#ifdef HAVE_GETEXECNAME
83 char *pn = (char *)getexecname(); /* pn is on the stack */
84#else
85 char *pn = getexecpath(); /* pn is from strdup() */
86 char ebuf[NAMEMAX];
87
88 if (pn) {
89 strlcpy(ebuf, pn, sizeof (ebuf));
90 free(pn);
91 pn = ebuf;
92 }
93#endif
94
95 if (pn == NULL)
96 xn = get_progname();
97 else
98 xn = pn;
99 if ((np = strrchr(xn, '/')) != NULL)
100 xn = ++np;
101
102 /*
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.
108 */
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);
113
114 while (np > nbuf && np[-1] != '/')
115 *--np = '\0';
116 pn = &nbuf[sizeof (pbuf) - 1];
117 if ((np = searchonefile(name, mode,
118 file_mode & (SIP_PLAIN_FILE|SIP_NO_STRIPBIN),
119 xn,
120 nbuf, np, pn)) != NULL) {
121 seterrno(oerrno);
122 return (np);
123 }
124 }
125
126 if (file_mode & SIP_NO_PATH)
127 return (NULL);
128
129 if (path == NULL)
130 path = getenv("PATH");
131 if (path == NULL)
132 return (NULL);
133
134
135#ifdef __DJGPP__
136 path = strdup(path);
137 if (path == NULL)
138 return (NULL);
139 strbs2s(path); /* PATH under DJGPP can contain both slashes */
140#endif
141
142 /*
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
147 * are lost.
148 */
149 ep = &nbuf[sizeof (pbuf) - 1];
150 for (;;) {
151 np = nbuf;
152 while (*path != PATH_ENV_DELIM && *path != '\0' &&
153 np < &nbuf[sizeof (pbuf) - nlen])
154 *np++ = *path++;
155 *np = '\0';
156 if ((np = searchonefile(name, mode,
157 file_mode & (SIP_PLAIN_FILE|SIP_NO_STRIPBIN),
158 xn,
159 nbuf, np, ep)) != NULL) {
160#ifdef __DJGPP__
161 free(path);
162#endif
163 seterrno(oerrno);
164 return (np);
165 }
166 if (err == 0) {
167 err = geterrno();
168 if (enofile(err))
169 err = 0;
170 }
171 if (*path == '\0')
172 break;
173 path++;
174 }
175#ifdef __DJGPP__
176 free(path);
177#endif
178 if (err)
179 seterrno(err);
180 else
181 seterrno(oerrno);
182 return (NULL);
183}
184
185LOCAL char *
186searchonefile(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 */
194{
195 struct stat sb;
196
197 while (np > nbuf && np[-1] == '/')
198 *--np = '\0';
199 if (xn) {
200 *np++ = '/';
201 strlcpy(np, xn, ep - np);
202 if (stat(nbuf, &sb) < 0)
203 return (NULL);
204 if (!S_ISREG(sb.st_mode))
205 return (NULL);
206 *--np = '\0';
207 }
208 if ((plain_file & SIP_NO_STRIPBIN) == 0) {
209 if (np >= &nbuf[4] && streql(&np[-4], "/bin"))
210 np = &np[-4];
211 }
212 plain_file &= SIP_PLAIN_FILE;
213 *np++ = '/';
214 *np = '\0';
215 strlcpy(np, name, ep - np);
216
217 seterrno(0);
218 if (stat(nbuf, &sb) >= 0) {
219 if ((!plain_file || S_ISREG(sb.st_mode)) &&
220 (eaccess(nbuf, mode) >= 0)) {
221 return (strdup(nbuf));
222 }
223 if (geterrno() == 0)
225 }
226 return (NULL);
227}
228
229#ifdef __DJGPP__
230LOCAL char *
231strbs2s(s)
232 char *s;
233{
234 char *tmp = s;
235
236 if (tmp) {
237 while (*tmp) {
238 if (*tmp == '\\')
239 *tmp = '/';
240 tmp++;
241 }
242 }
243 return (s);
244}
245#endif
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define EACCES
Definition: acclib.h:85
char * strchr(const char *String, int ch)
Definition: utclib.c:501
#define stat
Definition: acwin.h:99
#define S_ISREG(mode)
Definition: various.h:17
size_t strlcpy(char *d, const char *s, size_t bufsize)
Definition: compat.c:3
#define UConst
Definition: ccomdefs.h:72
#define free
Definition: debug_ros.c:5
#define NULL
Definition: types.h:112
superblock * sb
Definition: btrfs.c:4261
EXPORT int eaccess(char *name, int mode) const
Definition: eaccess.c:35
unsigned int BOOL
Definition: ntddk_ex.h:94
EXPORT int geterrno()
Definition: geterrno.c:34
EXPORT char * getexecpath()
Definition: getexecpath.c:55
GLdouble s
Definition: gl.h:2039
GLenum mode
Definition: glext.h:6217
_Check_return_ char *__cdecl getenv(_In_z_ const char *_VarName)
#define LOCAL(type)
Definition: jmorecfg.h:289
#define PATH_ENV_DELIM
Definition: mconfig.h:525
static int pints_t pn[]
Definition: server.c:129
#define __PR(a)
Definition: prototyp.h:106
#define err(...)
EXPORT char * get_progname()
Definition: saveargs.c:151
#define SIP_NO_STRIPBIN
Definition: schily.h:432
#define SIP_NO_PATH
Definition: schily.h:430
#define SIP_ONLY_PATH
Definition: schily.h:431
#define SIP_PLAIN_FILE
Definition: schily.h:429
_Check_return_ _CRTIMP char *__cdecl strdup(_In_opt_z_ const char *_Src)
_CRT_RESTORE_GCC_WARNINGS _CRT_DISABLE_GCC_WARNINGS _Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
static UConst char sccsid[]
Definition: searchinpath.c:4
LOCAL char * searchonefile(char *name, int mode, BOOL plain_file, char *xn, char *nbuf, char *np, char *ep)
Definition: searchinpath.c:186
EXPORT char * searchfileinpath(char *name, int mode, int file_mode, char *path)
Definition: searchinpath.c:68
#define NAMEMAX
Definition: searchinpath.c:37
#define enofile(t)
Definition: searchinpath.c:57
EXPORT int seterrno(int err)
Definition: seterrno.c:34
EXPORT int streql(char *a, const char *b) const
Definition: streql.c:23
Definition: name.c:39
Definition: pbuf.h:186
Definition: stat.h:55