ReactOS  0.4.14-dev-317-g96040ec
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
4 static 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 
39 EXPORT char *searchfileinpath __PR((char *name, int mode,
40  int file_mode,
41  char *path));
42 LOCAL 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__)
48 LOCAL 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  */
67 EXPORT 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 
185 LOCAL char *
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 */
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)
224  seterrno(EACCES);
225  }
226  return (NULL);
227 }
228 
229 #ifdef __DJGPP__
230 LOCAL char *
231 strbs2s(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
#define SIP_NO_STRIPBIN
Definition: schily.h:432
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
superblock * sb
Definition: btrfs.c:4137
#define SIP_PLAIN_FILE
Definition: schily.h:429
GLsizei const GLchar ** path
Definition: glext.h:7234
#define free
Definition: debug_ros.c:5
size_t strlcpy(char *d, const char *s, size_t bufsize)
Definition: compat.c:3
#define UConst
Definition: ccomdefs.h:72
EXPORT int streql(char *a, const char *b) const
Definition: streql.c:23
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
unsigned int BOOL
Definition: ntddk_ex.h:94
_Check_return_ _CRTIMP char *__cdecl strdup(_In_opt_z_ const char *_Src)
LOCAL char * searchonefile(char *name, int mode, BOOL plain_file, char *xn, char *nbuf, char *np, char *ep)
Definition: searchinpath.c:186
smooth NULL
Definition: ftsmooth.c:416
#define LOCAL(type)
Definition: jmorecfg.h:289
static UConst char sccsid[]
Definition: searchinpath.c:4
EXPORT int seterrno(int err)
Definition: seterrno.c:34
EXPORT char * searchfileinpath(char *name, int mode, int file_mode, char *path)
Definition: searchinpath.c:68
Definition: pbuf.h:79
EXPORT int geterrno()
Definition: geterrno.c:34
Definition: arc.h:34
#define SIP_ONLY_PATH
Definition: schily.h:431
Definition: stat.h:55
GLdouble s
Definition: gl.h:2039
#define err(...)
GLenum mode
Definition: glext.h:6217
EXPORT char *searchfileinpath __PR((char *name, int mode, int file_mode, char *path))
EXPORT char * get_progname()
Definition: saveargs.c:151
EXPORT char * getexecpath()
Definition: getexecpath.c:55
_CRTIMP int __cdecl stat(const char *_Filename, struct stat *_Stat)
Definition: stat.h:345
#define enofile(t)
Definition: searchinpath.c:57
_Check_return_ char *__cdecl getenv(_In_z_ const char *_VarName)
#define NAMEMAX
Definition: searchinpath.c:37
Definition: services.c:325
#define PATH_ENV_DELIM
Definition: mconfig.h:525
char * strchr(const char *String, int ch)
Definition: utclib.c:501
Definition: name.c:36
#define SIP_NO_PATH
Definition: schily.h:430
EXPORT int eaccess(char *name, int mode) const
Definition: eaccess.c:35
#define S_ISREG(mode)
Definition: various.h:17
GLuint const GLchar * name
Definition: glext.h:6031