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 #pragma ident "%Z%%M% %I% %E% SMI"
31
32 /*
33 * Search the specified path for a file with the specified
34 * mode and type. Return a pointer to the path. If the
35 * file isn't found, return NULL.
36 */
37
38 #ifdef _REENTRANT
39 #include <thread.h>
40 #include <pthread.h>
41 #endif /* _REENTRANT */
42 #include <sys/types.h>
43 #include <libgen.h>
44 #include <stdlib.h>
45 #include <limits.h>
46 #include <string.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
49
50 /*
51 * Mode bit definitions -- see mknod(2)
52 * Names of flags duplicate those of test(1)
53 */
54
55
56 /* File type: 0170000 */
57 #define FFLAG S_IFREG /* normal file - also type 0 */
58 #define BFLAG S_IFBLK /* block special */
59 #define CFLAG S_IFCHR /* character special */
60 #define DFLAG S_IFDIR /* directory */
61 #define PFLAG S_IFIFO /* fifo */
62
63 #define UFLAG S_ISUID /* setuid */
64 #define GFLAG S_ISGID /* setgid */
65 #define KFLAG S_ISVTX /* sticky bit */
66
67 /*
68 * Perms: 0700 user, 070 group, 07 other
69 * Note that pathfind uses access(2), so no need to hassle
70 * with shifts and such
71 */
72 #define RFLAG 04 /* read */
73 #define WFLAG 02 /* write */
74 #define XFLAG 01 /* execute */
75
76 static int fullck(char *, mode_t, int);
77
78 #ifdef _REENTRANT
79 static char *
_get_cpath(thread_key_t * keyp)80 _get_cpath(thread_key_t *keyp)
81 {
82 char *str;
83
84 if (thr_keycreate_once(keyp, free) != 0)
85 return (NULL);
86 str = pthread_getspecific(*keyp);
87 if (str == NULL) {
88 str = calloc(PATH_MAX, sizeof (char));
89 if (thr_setspecific(*keyp, str) != 0) {
90 if (str)
91 (void) free(str);
92 str = NULL;
93 }
94 }
95 return (str);
96 }
97 #endif /* _REENTRANT */
98
99 char *
pathfind(const char * path,const char * name,const char * mode)100 pathfind(const char *path, const char *name, const char *mode)
101 {
102 #ifdef _REENTRANT
103 static thread_key_t key = THR_ONCE_KEY;
104 char *cpath = _get_cpath(&key);
105 #else /* _REENTRANT */
106 static char cpath[PATH_MAX];
107 #endif /* _REENTRANT */
108 char *cp;
109 mode_t imode;
110 int nzflag;
111
112 /* Build imode */
113 imode = 0; nzflag = 0;
114 if (mode == ((char *)0))
115 mode = "";
116 for (cp = (char *)mode; *cp; cp++) {
117 switch (*cp) {
118 case 'r':
119 imode |= RFLAG;
120 break;
121 case 'w':
122 imode |= WFLAG;
123 break;
124 case 'x':
125 imode |= XFLAG;
126 break;
127 case 'b':
128 imode |= BFLAG;
129 break;
130 case 'c':
131 imode |= CFLAG;
132 break;
133 case 'd':
134 imode |= DFLAG;
135 break;
136 case 'f':
137 imode |= FFLAG;
138 break;
139 case 'p':
140 imode |= PFLAG;
141 break;
142 case 'u':
143 imode |= UFLAG;
144 break;
145 case 'g':
146 imode |= GFLAG;
147 break;
148 case 'k':
149 imode |= KFLAG;
150 break;
151 case 's':
152 nzflag = 1;
153 break;
154 default:
155 return ((char *)0);
156 }
157 }
158
159 if (name[0] == '/' || path == ((char *)0) || *path == '\0')
160 path = ":";
161 while (*path) {
162 for (cp = cpath; (/* const */ char *) cp <
163 &cpath[PATH_MAX] && (*cp = *path); cp++) {
164 path++;
165 if (*cp == ':')
166 break;
167 }
168 if ((/* const */ char *) cp + strlen(name) + 2 >=
169 &cpath[PATH_MAX])
170 continue;
171 if (cp != cpath)
172 *cp++ = '/';
173 *cp = '\0';
174 (void) strcat(cp, name);
175 if (access(cpath, imode&07) == 0 &&
176 fullck(cpath, imode, nzflag))
177 return (cpath);
178 }
179
180 return ((char *)0);
181 }
182
183 static int
fullck(char * name,mode_t mode,int nzflag)184 fullck(char *name, mode_t mode, int nzflag)
185 {
186 struct stat64 sbuf;
187 int xor;
188
189 if ((mode & 0177000) == 0 && nzflag == 0) /* no special info wanted */
190 return (1);
191 if (stat64(name, &sbuf) == -1)
192 return (0);
193 xor = (sbuf.st_mode ^ mode) & 077000; /* see mknod(2) */
194 if ((mode & 0170000) == 0)
195 xor &= ~070000;
196 if ((mode & 07000) == 0)
197 xor &= ~07000;
198 if (xor)
199 return (0);
200 if (nzflag && sbuf.st_size == 0)
201 return (0);
202 return (1);
203 }
204