1 /*
2  * CDDL HEADER START
3  *
4  * This file and its contents are supplied under the terms of the
5  * Common Development and Distribution License ("CDDL"), version 1.0.
6  * You may use this file only in accordance with the terms of version
7  * 1.0 of the CDDL.
8  *
9  * A full copy of the text of the CDDL should have accompanied this
10  * source.  A copy of the CDDL is also available via the Internet at
11  * http://www.opensource.org/licenses/cddl1.txt
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 /*
24  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
25  * Use is subject to license terms.
26  */
27 /*
28  * @(#)vroot.cc 1.11 06/12/12
29  */
30 
31 #pragma	ident	"@(#)vroot.cc	1.11	06/12/12"
32 
33 /*
34  * Copyright 2017-2021 J. Schilling
35  *
36  * @(#)vroot.cc	1.7 21/08/15 2017-2021 J. Schilling
37  */
38 #include <schily/mconfig.h>
39 #ifndef lint
40 static	UConst char sccsid[] =
41 	"@(#)vroot.cc	1.7 21/08/15 2017-2021 J. Schilling";
42 #endif
43 
44 #if defined(SCHILY_BUILD) || defined(SCHILY_INCLUDES)
45 #include <schily/stdlib.h>
46 #include <schily/string.h>
47 #else
48 #include <stdlib.h>
49 #include <string.h>
50 #endif
51 
52 #include <vroot/vroot.h>
53 #include <vroot/args.h>
54 
55 #if defined(SCHILY_BUILD) || defined(SCHILY_INCLUDES)
56 #include <schily/param.h>
57 #include <schily/maxpath.h>
58 #include <schily/fcntl.h>
59 #ifdef	HAVE_SYS_FILE_H
60 #include <sys/file.h>
61 #endif
62 #else
63 #include <sys/param.h>
64 #include <sys/file.h>
65 #endif
66 
67 #include <avo/intl.h>	/* for NOCATGETS */
68 
69 typedef struct {
70 	short		init;
71 	pathpt		vector;
72 	const char	*env_var;
73 } vroot_patht;
74 
75 typedef struct {
76 	vroot_patht	vroot;
77 	vroot_patht	path;
78 	char		full_path[MAXPATHLEN+1];
79 	char		*vroot_start;
80 	char		*path_start;
81 	char		*filename_start;
82 	int		scan_vroot_first;
83 	int		cpp_style_path;
84 } vroot_datat, *vroot_datapt;
85 
86 static vroot_datat	vroot_data= {
87 	{ 0, NULL, NOCATGETS("VIRTUAL_ROOT")},
88 	{ 0, NULL, NOCATGETS("PATH")},
89 	"", NULL, NULL, NULL, 0, 1};
90 
91 void
add_dir_to_path(register const char * path,register pathpt * pointer,register int position)92 add_dir_to_path(register const char *path, register pathpt *pointer, register int position)
93 {
94 	register int		size= 0;
95 	register int		length;
96 	register char		*name;
97 	register pathcellpt	p;
98 	pathpt			new_path;
99 
100 	if (*pointer != NULL) {
101 		for (p= &((*pointer)[0]); p->path != NULL; p++, size++);
102 		if (position < 0)
103 			position= size;}
104 	else
105 		if (position < 0)
106 			position= 0;
107 	if (position >= size) {
108 		new_path= (pathpt)calloc((unsigned)(position+2), sizeof(pathcellt));
109 		if (*pointer != NULL) {
110 			memcpy((char *)new_path,(char *)(*pointer),  size*sizeof(pathcellt));
111 			free((char *)(*pointer));};
112 		*pointer= new_path;};
113 	length= strlen(path);
114 	name= (char *)malloc((unsigned)(length+1));
115 	(void)strcpy(name, path);
116 	if ((*pointer)[position].path != NULL)
117 		free((*pointer)[position].path);
118 	(*pointer)[position].path= name;
119 	(*pointer)[position].length= length;
120 }
121 
122 pathpt
parse_path_string(register char * string,register int remove_slash)123 parse_path_string(register char *string, register int remove_slash)
124 {
125 	register char		*p;
126 	pathpt			result= NULL;
127 
128 	if (string != NULL)
129 		for (; 1; string= p+1) {
130 			if ((p = strchr(string, ':')) != NULL)
131 				*p = 0;
132 			if ((remove_slash == 1) && !strcmp(string, "/"))
133 				add_dir_to_path("", &result, -1);
134 			else
135 				add_dir_to_path(string, &result, -1);
136 			if (p) *p= ':';
137 			else return(result);};
138 	return((pathpt)NULL);
139 }
140 
141 const char *
get_vroot_name(void)142 get_vroot_name(void)
143 {
144 	return(vroot_data.vroot.env_var);
145 }
146 
147 const char *
get_path_name(void)148 get_path_name(void)
149 {
150 	return(vroot_data.path.env_var);
151 }
152 
153 void
flush_path_cache(void)154 flush_path_cache(void)
155 {
156 	vroot_data.path.init= 0;
157 }
158 
159 void
flush_vroot_cache(void)160 flush_vroot_cache(void)
161 {
162 	vroot_data.vroot.init= 0;
163 }
164 
165 void
scan_path_first(void)166 scan_path_first(void)
167 {
168 	vroot_data.scan_vroot_first= 0;
169 }
170 
171 void
scan_vroot_first(void)172 scan_vroot_first(void)
173 {
174 	vroot_data.scan_vroot_first= 1;
175 }
176 
177 void
set_path_style(int style)178 set_path_style(int style)
179 {
180 	vroot_data.cpp_style_path= style;
181 }
182 
183 char *
get_vroot_path(register char ** vroot,register char ** path,register char ** filename)184 get_vroot_path(register char **vroot, register char **path, register char **filename)
185 {
186 	if (vroot != NULL) {
187 		if ((*vroot= vroot_data.vroot_start) == NULL)
188 		if ((*vroot= vroot_data.path_start) == NULL)
189 		*vroot= vroot_data.filename_start;};
190 	if (path != NULL) {
191 		if ((*path= vroot_data.path_start) == NULL)
192 		*path= vroot_data.filename_start;};
193 	if (filename != NULL)
194 		*filename= vroot_data.filename_start;
195 	return(vroot_data.full_path);
196 }
197 
198 void
translate_with_thunk(register char * filename,int (* thunk)(char *),pathpt path_vector,pathpt vroot_vector,rwt rw)199 translate_with_thunk(register char *filename, int (*thunk) (char *), pathpt path_vector, pathpt vroot_vector, rwt rw)
200 {
201 	register pathcellt	*vp;
202 	pathcellt		*pp;
203 	register pathcellt	*pp1;
204 	register char		*p;
205 	int			flags[256];
206 
207 /* Setup path to use */
208 	if (rw == rw_write)
209 		pp1= NULL;		/* Do not use path when writing */
210 	else {
211 		if (path_vector == VROOT_DEFAULT) {
212 			if (!vroot_data.path.init) {
213 				vroot_data.path.init= 1;
214 				vroot_data.path.vector= parse_path_string(getenv(vroot_data.path.env_var), 0);};
215 			path_vector= vroot_data.path.vector;};
216 		pp1= path_vector == NULL ? NULL : &(path_vector)[0];};
217 
218 /* Setup vroot to use */
219 	if (vroot_vector == VROOT_DEFAULT) {
220 		if (!vroot_data.vroot.init) {
221 			vroot_data.vroot.init= 1;
222 			vroot_data.vroot.vector= parse_path_string(getenv(vroot_data.vroot.env_var), 1);};
223 		vroot_vector= vroot_data.vroot.vector;};
224 	vp= vroot_vector == NULL ? NULL : &(vroot_vector)[0];
225 
226 /* Setup to remember pieces */
227 	vroot_data.vroot_start= NULL;
228 	vroot_data.path_start= NULL;
229 	vroot_data.filename_start= NULL;
230 
231 	int flen = strlen(filename);
232 	if(flen >= MAXPATHLEN) {
233 		errno = ENAMETOOLONG;
234 		return;
235 	}
236 
237 	switch ((vp ?1:0) + (pp1 ? 2:0)) {
238 	    case 0:	/* No path. No vroot. */
239 	    use_name:
240 		(void)strcpy(vroot_data.full_path, filename);
241 		vroot_data.filename_start= vroot_data.full_path;
242 		(void)(*thunk)(vroot_data.full_path);
243 		return;
244 	    case 1:	/* No path. Vroot */
245 		if (filename[0] != '/') goto use_name;
246 		for (; vp->path != NULL; vp++) {
247 			if((1 + flen + vp->length) >= MAXPATHLEN) {
248 				errno = ENAMETOOLONG;
249 				continue;
250 			}
251 			p= vroot_data.full_path;
252 			(void)strcpy(vroot_data.vroot_start= p, vp->path);
253 			p+= vp->length;
254 			(void)strcpy(vroot_data.filename_start= p, filename);
255 			if ((*thunk)(vroot_data.full_path)) return;};
256 		(void)strcpy(vroot_data.full_path, filename);
257 		return;
258 	    case 2:	/* Path. No vroot. */
259 		if (vroot_data.cpp_style_path) {
260 			if (filename[0] == '/') goto use_name;
261 		} else {
262 			if (strchr(filename, '/') != NULL) goto use_name;
263 		};
264 		for (; pp1->path != NULL; pp1++) {
265 			p= vroot_data.full_path;
266 			if((1 + flen + pp1->length) >= MAXPATHLEN) {
267 				errno = ENAMETOOLONG;
268 				continue;
269 			}
270 			if (vroot_data.cpp_style_path) {
271 				(void)strcpy(vroot_data.path_start= p, pp1->path);
272 				p+= pp1->length;
273 				*p++= '/';
274 			} else {
275 				if (pp1->length != 0) {
276 					(void)strcpy(vroot_data.path_start= p,
277 					    pp1->path);
278 					p+= pp1->length;
279 					*p++= '/';
280 				};
281 			};
282 			(void)strcpy(vroot_data.filename_start= p, filename);
283 			if ((*thunk)(vroot_data.full_path)) return;};
284 		(void)strcpy(vroot_data.full_path, filename);
285 		return;
286 	    case 3: {	/* Path. Vroot. */
287 			int *rel_path, path_len= 1;
288 		if (vroot_data.scan_vroot_first == 0) {
289 			for (pp= pp1; pp->path != NULL; pp++) path_len++;
290 			rel_path= flags;
291 			for (path_len-= 2; path_len >= 0; path_len--) rel_path[path_len]= 0;
292 			for (; vp->path != NULL; vp++)
293 				for (pp= pp1, path_len= 0; pp->path != NULL; pp++, path_len++) {
294 					int len = 0;
295 					if (rel_path[path_len] == 1) continue;
296 					if (pp->path[0] != '/') rel_path[path_len]= 1;
297 					p= vroot_data.full_path;
298 					if ((filename[0] == '/') || (pp->path[0] == '/')) {
299 						if(vp->length >= MAXPATHLEN) {
300 							errno = ENAMETOOLONG;
301 							continue;
302 						}
303 						(void)strcpy(vroot_data.vroot_start= p, vp->path); p+= vp->length;
304 						len += vp->length;
305 					};
306 					if (vroot_data.cpp_style_path) {
307 						if (filename[0] != '/') {
308 							if(1 + len + pp->length >= MAXPATHLEN) {
309 								errno = ENAMETOOLONG;
310 								continue;
311 							}
312 							(void)strcpy(vroot_data.path_start= p, pp->path); p+= pp->length;
313 							*p++= '/';
314 							len += 1 + pp->length;
315 						};
316 					} else {
317 						if (strchr(filename, '/') == NULL) {
318 							if (pp->length != 0) {
319 								if(1 + len + pp->length >= MAXPATHLEN) {
320 									errno = ENAMETOOLONG;
321 									continue;
322 								}
323 								(void)strcpy(vroot_data.path_start= p,
324 								    pp->path);
325 								p+= pp->length;
326 								*p++= '/';
327 								len += 1 + pp->length;
328 							}
329 						}
330 					};
331 					(void)strcpy(vroot_data.filename_start= p, filename);
332 					if ((*thunk)(vroot_data.full_path)) return;};}
333 		else { pathcellt *vp1= vp;
334 			for (pp= pp1, path_len= 0; pp->path != NULL; pp++, path_len++)
335 				for (vp= vp1; vp->path != NULL; vp++) {
336 					int len = 0;
337 					p= vroot_data.full_path;
338 					if ((filename[0] == '/') || (pp->path[0] == '/')) {
339 						if(vp->length >= MAXPATHLEN) {
340 							errno = ENAMETOOLONG;
341 							continue;
342 						}
343 						(void)strcpy(vroot_data.vroot_start= p, vp->path); p+= vp->length;
344 						len += vp->length;
345 					}
346 					if (vroot_data.cpp_style_path) {
347 						if (filename[0] != '/') {
348 							if(1 + len + pp->length >= MAXPATHLEN) {
349 								errno = ENAMETOOLONG;
350 								continue;
351 							}
352 							(void)strcpy(vroot_data.path_start= p, pp->path); p+= pp->length;
353 							*p++= '/';
354 							len += 1 + pp->length;
355 						}
356 					} else {
357 						if (strchr(filename, '/') == NULL) {
358 							if(1 + len + pp->length >= MAXPATHLEN) {
359 								errno = ENAMETOOLONG;
360 								continue;
361 							}
362 							(void)strcpy(vroot_data.path_start= p, pp->path); p+= pp->length;
363 							*p++= '/';
364 							len += 1 + pp->length;
365 						}
366 					}
367 					(void)strcpy(vroot_data.filename_start= p, filename);
368 					if ((*thunk)(vroot_data.full_path)) return;};};
369 		(void)strcpy(vroot_data.full_path, filename);
370 		return;};};
371 }
372