1 /* @(#)findinpath.c 1.7 19/07/31 Copyright 2004-2019 J. Schilling */
2 #define USE_LARGEFILES
3 #include <schily/mconfig.h>
4 #ifndef lint
5 static UConst char sccsid[] =
6 "@(#)findinpath.c 1.7 19/07/31 Copyright 2004-2019 J. Schilling";
7 #endif
8 /*
9 * Search a file name in the PATH and return the path name in allocated space.
10 *
11 * Copyright 2004-2019 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 /*
28 * Since we need to call stat() and since this is not a predictable call,
29 * we always compile this module in largefile mode.
30 * See #define USE_LARGEFILES before #include <schily/mconfig.h>
31 */
32
33 #include <schily/stdlib.h>
34 #include <schily/stat.h>
35 #include <schily/errno.h>
36 #include <schily/string.h>
37 #include <schily/standard.h>
38 #include <schily/schily.h>
39
40 EXPORT char *findinpath __PR((char *name, int mode, BOOL plain_file,
41 char *path));
42
43 #ifdef JOS
44 #define enofile(t) ((t) == EMISSDIR || \
45 (t) == ENOFILE || \
46 (t) == EISADIR || \
47 (t) == EIOERR)
48 #else
49 #define enofile(t) ((t) == ENOENT || \
50 (t) == ENOTDIR || \
51 (t) == EISDIR || \
52 (t) == EIO)
53 #endif
54
55 EXPORT char *
findinpath(name,mode,plain_file,path)56 findinpath(name, mode, plain_file, path)
57 char *name; /* The name to execute */
58 int mode; /* Mode for access() e.g. X_OK */
59 BOOL plain_file; /* Whether to check only plain files */
60 char *path; /* PATH to use if not NULL */
61 {
62 char *pathlist;
63 char *p1;
64 char *p2;
65 char *tmp;
66 int err = 0;
67 int exerr = 0;
68 struct stat sb;
69
70 if (name == NULL)
71 return (NULL);
72 if (strchr(name, '/'))
73 return (strdup(name));
74
75 if (path != NULL)
76 pathlist = path;
77 else if ((pathlist = getenv("PATH")) == NULL)
78 pathlist = "/bin";
79 p2 = pathlist = strdup(pathlist);
80 if (pathlist == NULL)
81 return (NULL);
82
83 for (;;) {
84 p1 = p2;
85 if ((p2 = strchr(p2, PATH_ENV_DELIM)) != NULL)
86 *p2++ = '\0';
87 if (*p1 == '\0') {
88 tmp = strdup(name);
89 if (tmp == NULL) {
90 free(pathlist);
91 return (NULL);
92 }
93 } else {
94 size_t len = strlen(p1) + strlen(name) + 2;
95
96 tmp = malloc(len);
97 if (tmp == NULL) {
98 free(pathlist);
99 return (strdup(name));
100 }
101 strcatl(tmp, p1, PATH_DELIM_STR, name, (char *)NULL);
102 }
103
104 seterrno(0);
105 if (stat(tmp, &sb) >= 0) {
106 if ((!plain_file || S_ISREG(sb.st_mode)) &&
107 (eaccess(tmp, mode) >= 0)) {
108 free(pathlist);
109 return (tmp);
110 }
111 if ((err = geterrno()) == 0)
112 err = ENOEXEC;
113 } else {
114 err = geterrno();
115 }
116 free(tmp);
117 if (exerr == 0 && !enofile(err))
118 exerr = err;
119 if ((!enofile(err) && !(err == EACCES)) || p2 == NULL)
120 break;
121 }
122 free(pathlist);
123 seterrno(exerr);
124 return (NULL);
125 }
126