1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * Search the specified path for a file with the specified
32 * mode and type. Return a pointer to the path. If the
33 * file isn't found, return NULL.
34 */
35
36 #ifdef _REENTRANT
37 #include <thread.h>
38 #include <pthread.h>
39 #endif /* _REENTRANT */
40 #include <sys/types.h>
41 #include <libgen.h>
42 #include <stdlib.h>
43 #include <limits.h>
44 #include <string.h>
45 #include <sys/stat.h>
46 #include <unistd.h>
47
48 /*
49 * Mode bit definitions -- see mknod(2)
50 * Names of flags duplicate those of test(1)
51 */
52
53
54 /* File type: 0170000 */
55 #define FFLAG S_IFREG /* normal file - also type 0 */
56 #define BFLAG S_IFBLK /* block special */
57 #define CFLAG S_IFCHR /* character special */
58 #define DFLAG S_IFDIR /* directory */
59 #define PFLAG S_IFIFO /* fifo */
60
61 #define UFLAG S_ISUID /* setuid */
62 #define GFLAG S_ISGID /* setgid */
63 #define KFLAG S_ISVTX /* sticky bit */
64
65 /*
66 * Perms: 0700 user, 070 group, 07 other
67 * Note that pathfind uses access(2), so no need to hassle
68 * with shifts and such
69 */
70 #define RFLAG 04 /* read */
71 #define WFLAG 02 /* write */
72 #define XFLAG 01 /* execute */
73
74 static int fullck(char *, mode_t, int);
75
76 #ifdef _REENTRANT
77 static char *
_get_cpath(thread_key_t * keyp)78 _get_cpath(thread_key_t *keyp)
79 {
80 char *str;
81
82 if (thr_keycreate_once(keyp, free) != 0)
83 return (NULL);
84 str = pthread_getspecific(*keyp);
85 if (str == NULL) {
86 str = calloc(PATH_MAX, sizeof (char));
87 if (thr_setspecific(*keyp, str) != 0) {
88 if (str)
89 (void) free(str);
90 str = NULL;
91 }
92 }
93 return (str);
94 }
95 #endif /* _REENTRANT */
96
97 char *
pathfind(const char * path,const char * name,const char * mode)98 pathfind(const char *path, const char *name, const char *mode)
99 {
100 #ifdef _REENTRANT
101 static thread_key_t key = THR_ONCE_KEY;
102 char *cpath = _get_cpath(&key);
103 #else /* _REENTRANT */
104 static char cpath[PATH_MAX];
105 #endif /* _REENTRANT */
106 char *cp;
107 mode_t imode;
108 int nzflag;
109
110 /* Build imode */
111 imode = 0; nzflag = 0;
112 if (mode == ((char *)0))
113 mode = "";
114 for (cp = (char *)mode; *cp; cp++) {
115 switch (*cp) {
116 case 'r':
117 imode |= RFLAG;
118 break;
119 case 'w':
120 imode |= WFLAG;
121 break;
122 case 'x':
123 imode |= XFLAG;
124 break;
125 case 'b':
126 imode |= BFLAG;
127 break;
128 case 'c':
129 imode |= CFLAG;
130 break;
131 case 'd':
132 imode |= DFLAG;
133 break;
134 case 'f':
135 imode |= FFLAG;
136 break;
137 case 'p':
138 imode |= PFLAG;
139 break;
140 case 'u':
141 imode |= UFLAG;
142 break;
143 case 'g':
144 imode |= GFLAG;
145 break;
146 case 'k':
147 imode |= KFLAG;
148 break;
149 case 's':
150 nzflag = 1;
151 break;
152 default:
153 return ((char *)0);
154 }
155 }
156
157 if (name[0] == '/' || path == ((char *)0) || *path == '\0')
158 path = ":";
159 while (*path) {
160 for (cp = cpath; (/* const */ char *) cp <
161 &cpath[PATH_MAX] && (*cp = *path); cp++) {
162 path++;
163 if (*cp == ':')
164 break;
165 }
166 if ((/* const */ char *) cp + strlen(name) + 2 >=
167 &cpath[PATH_MAX])
168 continue;
169 if (cp != cpath)
170 *cp++ = '/';
171 *cp = '\0';
172 (void) strcat(cp, name);
173 if (access(cpath, imode&07) == 0 &&
174 fullck(cpath, imode, nzflag))
175 return (cpath);
176 }
177
178 return ((char *)0);
179 }
180
181 static int
fullck(char * name,mode_t mode,int nzflag)182 fullck(char *name, mode_t mode, int nzflag)
183 {
184 struct stat64 sbuf;
185 int xor;
186
187 if ((mode & 0177000) == 0 && nzflag == 0) /* no special info wanted */
188 return (1);
189 if (stat64(name, &sbuf) == -1)
190 return (0);
191 xor = (sbuf.st_mode ^ mode) & 077000; /* see mknod(2) */
192 if ((mode & 0170000) == 0)
193 xor &= ~070000;
194 if ((mode & 07000) == 0)
195 xor &= ~07000;
196 if (xor)
197 return (0);
198 if (nzflag && sbuf.st_size == 0)
199 return (0);
200 return (1);
201 }
202