xref: /titanic_41/usr/src/lib/libadm/common/pkgparam.c (revision 70025d765b044c6d8594bb965a2247a61e991a99)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 /*
26  * Copyright (c) 1995-1998 by Sun Microsystems, Inc.
27  * All rights reserved.
28  */
29 
30 #pragma	ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.1 */
31 /*LINTLIBRARY*/
32 
33 /*   5-20-92   newroot support added  */
34 
35 #include <stdio.h>
36 #include <limits.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <string.h>
40 #include <sys/types.h>
41 #include <pkgstrct.h>
42 #include <pkginfo.h>
43 #include <pkglocs.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include "libadm.h"
47 
48 #define	VALSIZ	128
49 #define	NEWLINE	'\n'
50 #define	ESCAPE	'\\'
51 
52 static char sepset[] =	":=\n";
53 static char qset[] = 	"'\"";
54 static char *pkg_inst_root = NULL;
55 
56 char *pkgdir = NULL;
57 char *pkgfile = NULL;
58 
59 static char Adm_pkgold[PATH_MAX] = { 0 }; /* added for newroot */
60 static char Adm_pkgloc[PATH_MAX] = { 0 }; /* added for newroot */
61 static char Adm_pkgadm[PATH_MAX] = { 0 }; /* added for newroot */
62 
63 /*
64  * This looks in a directory that might be the top level directory of a
65  * package. It tests a temporary install directory first and then for a
66  * standard directory. This looks a little confusing, so here's what's
67  * happening. If this pkginfo is being openned in a script during a pkgadd
68  * which is updating an existing package, the original pkginfo file is in a
69  * directory that has been renamed from <pkginst> to .save.<pkginst>. If the
70  * pkgadd fails it will be renamed back to <pkginst>. We are always interested
71  * in the OLD pkginfo data because the new pkginfo data is already in our
72  * environment. For that reason, we try to open the backup first - that has
73  * the old data. This returns the first accessible path in "path" and a "1"
74  * if an appropriate pkginfo file was found. It returns a 0 if no type of
75  * pkginfo was located.
76  */
77 int
78 pkginfofind(char *path, char *pkg_dir, char *pkginst)
79 {
80 	/* Construct the temporary pkginfo file name. */
81 	(void) sprintf(path, "%s/.save.%s/pkginfo", pkg_dir, pkginst);
82 	if (access(path, 0)) {
83 		/*
84 		 * This isn't a temporary directory, so we look for a
85 		 * regular one.
86 		 */
87 		(void) sprintf(path, "%s/%s/pkginfo", pkg_dir, pkginst);
88 		if (access(path, 0))
89 			return (0); /* doesn't appear to be a package */
90 	}
91 
92 	return (1);
93 }
94 
95 /*
96  * This opens the appropriate pkginfo file for a particular package.
97  */
98 FILE *
99 pkginfopen(char *pkg_dir, char *pkginst)
100 {
101 	FILE *fp = NULL;
102 	char temp[PATH_MAX];
103 
104 	if (pkginfofind(temp, pkg_dir, pkginst))
105 		fp = fopen(temp, "r");
106 
107 	return (fp);
108 }
109 
110 
111 char *
112 fpkgparam(FILE *fp, char *param)
113 {
114 	char	ch, buffer[VALSIZ];
115 	char	*mempt, *copy;
116 	int	c, n, escape, begline, quoted;
117 
118 	if (param == NULL) {
119 		errno = ENOENT;
120 		return (NULL);
121 	}
122 
123 	mempt = NULL;
124 
125 	for (;;) {		/* for each entry in the file fp */
126 		copy = buffer;
127 		n = 0;
128 
129 		/* Get the next token. */
130 		while ((c = getc(fp)) != EOF) {
131 			ch = (char) c;
132 			if (strchr(sepset, ch))
133 				break;
134 			if (++n < VALSIZ)
135 				*copy++ = ch;
136 		}
137 
138 		/* If it's the end of the file, exit the for() loop */
139 		if (c == EOF) {
140 			errno = EINVAL;
141 			return (NULL); /* no more entries left */
142 
143 		/* If it's end of line, look for the next parameter. */
144 		} else if (c == NEWLINE)
145 			continue;
146 
147 		/* At this point copy points to the end of a valid parameter. */
148 		*copy = '\0';		/* Terminate the string. */
149 		if (buffer[0] == '#')	/* If it's a comment, drop thru. */
150 			copy = NULL;	/* Comments don't get buffered. */
151 		else {
152 			/* If parameter is NULL, we return whatever we got. */
153 			if (param[0] == '\0') {
154 				(void) strcpy(param, buffer);
155 				copy = buffer;
156 
157 			/* If this doesn't match the parameter, drop thru. */
158 			} else if (strcmp(param, buffer))
159 				copy = NULL;
160 
161 			/* Otherwise, this is our boy. */
162 			else
163 				copy = buffer;
164 		}
165 
166 		n = quoted = escape = 0;
167 		begline = 1;
168 
169 		/* Now read the parameter value. */
170 		while ((c = getc(fp)) != EOF) {
171 			ch = (char) c;
172 			if (begline && ((ch == ' ') || (ch == '\t')))
173 				continue; /* ignore leading white space */
174 
175 			if (ch == NEWLINE) {
176 				if (!escape)
177 					break; /* end of entry */
178 				if (copy) {
179 					if (escape) {
180 						copy--; /* eat previous esc */
181 						n--;
182 					}
183 					*copy++ = NEWLINE;
184 				}
185 				escape = 0;
186 				begline = 1; /* new input line */
187 			} else {
188 				if (!escape && strchr(qset, ch)) {
189 					/* handle quotes */
190 					if (begline) {
191 						quoted++;
192 						begline = 0;
193 						continue;
194 					} else if (quoted) {
195 						quoted = 0;
196 						continue;
197 					}
198 				}
199 				if (ch == ESCAPE)
200 					escape++;
201 				else if (escape)
202 					escape = 0;
203 				if (copy) *copy++ = ch;
204 				begline = 0;
205 			}
206 
207 			if (copy && ((++n % VALSIZ) == 0)) {
208 				if (mempt) {
209 					mempt = realloc(mempt,
210 						(n+VALSIZ)*sizeof (char));
211 					if (!mempt)
212 						return (NULL);
213 				} else {
214 					mempt = calloc((size_t)(2*VALSIZ),
215 					    sizeof (char));
216 					if (!mempt)
217 						return (NULL);
218 					(void) strncpy(mempt, buffer, n);
219 				}
220 				copy = &mempt[n];
221 			}
222 		}
223 
224 		/*
225 		 * Don't allow trailing white space.
226 		 * NOTE : White space in the middle is OK, since this may
227 		 * be a list. At some point it would be a good idea to let
228 		 * this function know how to validate such a list. -- JST
229 		 *
230 		 * Now while there's a parametric value and it ends in a
231 		 * space and the actual remaining string length is still
232 		 * greater than 0, back over the space.
233 		 */
234 		while (copy && isspace((unsigned char)*(copy - 1)) && n-- > 0)
235 			copy--;
236 
237 		if (quoted) {
238 			if (mempt)
239 				(void) free(mempt);
240 			errno = EFAULT; /* missing closing quote */
241 			return (NULL);
242 		}
243 		if (copy) {
244 			*copy = '\0';
245 			break;
246 		}
247 		if (c == EOF) {
248 			errno = EINVAL; /* parameter not found */
249 			return (NULL);
250 		}
251 	}
252 
253 	if (!mempt)
254 		mempt = strdup(buffer);
255 	else
256 		mempt = realloc(mempt, (strlen(mempt)+1)*sizeof (char));
257 	return (mempt);
258 }
259 
260 char *
261 pkgparam(char *pkg, char *param)
262 {
263 	static char lastfname[PATH_MAX];
264 	static FILE *fp = NULL;
265 	char *pt, *copy, *value, line[PATH_MAX];
266 
267 	if (!pkgdir)
268 		pkgdir = get_PKGLOC();
269 
270 	if (!pkg) {
271 		/* request to close file */
272 		if (fp) {
273 			(void) fclose(fp);
274 			fp = NULL;
275 		}
276 		return (NULL);
277 	}
278 
279 	if (!param) {
280 		errno = ENOENT;
281 		return (NULL);
282 	}
283 
284 	if (pkgfile)
285 		(void) strcpy(line, pkgfile); /* filename was passed */
286 	else
287 		(void) pkginfofind(line, pkgdir, pkg);
288 
289 	if (fp && strcmp(line, lastfname)) {
290 		/* different filename implies need for different fp */
291 		(void) fclose(fp);
292 		fp = NULL;
293 	}
294 	if (!fp) {
295 		(void) strcpy(lastfname, line);
296 		if ((fp = fopen(lastfname, "r")) == NULL)
297 			return (NULL);
298 	}
299 
300 	/*
301 	 * if parameter is a null string, then the user is requesting us
302 	 * to find the value of the next available parameter for this
303 	 * package and to copy the parameter name into the provided string;
304 	 * if it is not, then it is a request for a specified parameter, in
305 	 * which case we rewind the file to start search from beginning
306 	 */
307 	if (param[0]) {
308 		/* new parameter request, so reset file position */
309 		if (fseek(fp, 0L, 0))
310 			return (NULL);
311 	}
312 
313 	if (pt = fpkgparam(fp, param)) {
314 		if (strcmp(param, "ARCH") == NULL ||
315 		    strcmp(param, "CATEGORY") == NULL) {
316 			/* remove all whitespace from value */
317 			value = copy = pt;
318 			while (*value) {
319 				if (!isspace((unsigned char)*value))
320 					*copy++ = *value;
321 				value++;
322 			}
323 			*copy = '\0';
324 		}
325 		return (pt);
326 	}
327 	return (NULL);
328 }
329 /*
330  * This routine sets adm_pkgloc and adm_pkgadm which are the
331  * replacement location for PKGLOC and PKGADM.
332  */
333 
334 static void canonize_name(char *);
335 
336 void
337 set_PKGpaths(char *path)
338 {
339 	if (path && *path) {
340 		(void) sprintf(Adm_pkgloc, "%s%s", path, PKGLOC);
341 		(void) sprintf(Adm_pkgold, "%s%s", path, PKGOLD);
342 		(void) sprintf(Adm_pkgadm, "%s%s", path, PKGADM);
343 		set_install_root(path);
344 	} else {
345 		(void) sprintf(Adm_pkgloc, "%s", PKGLOC);
346 		(void) sprintf(Adm_pkgold, "%s", PKGOLD);
347 		(void) sprintf(Adm_pkgadm, "%s", PKGADM);
348 	}
349 	canonize_name(Adm_pkgloc);
350 	canonize_name(Adm_pkgold);
351 	canonize_name(Adm_pkgadm);
352 	pkgdir = Adm_pkgloc;
353 }
354 
355 char *
356 get_PKGLOC(void)
357 {
358 	if (Adm_pkgloc[0] == NULL)
359 		return (PKGLOC);
360 	else
361 		return (Adm_pkgloc);
362 }
363 
364 char *
365 get_PKGOLD(void)
366 {
367 	if (Adm_pkgold[0] == NULL)
368 		return (PKGOLD);
369 	else
370 		return (Adm_pkgold);
371 }
372 
373 char *
374 get_PKGADM(void)
375 {
376 	if (Adm_pkgadm[0] == NULL)
377 		return (PKGADM);
378 	else
379 		return (Adm_pkgadm);
380 }
381 
382 void
383 set_PKGADM(char *newpath)
384 {
385 	(void) strcpy(Adm_pkgadm, newpath);
386 }
387 
388 void
389 set_PKGLOC(char *newpath)
390 {
391 	(void) strcpy(Adm_pkgloc, newpath);
392 }
393 
394 #define	isdot(x)	((x[0] == '.')&&(!x[1]||(x[1] == '/')))
395 #define	isdotdot(x)	((x[0] == '.')&&(x[1] == '.')&&(!x[2]||(x[2] == '/')))
396 
397 static void
398 canonize_name(char *file)
399 {
400 	char *pt, *last;
401 	int level;
402 
403 	/* Remove references such as "./" and "../" and "//" */
404 
405 	for (pt = file; *pt; ) {
406 		if (isdot(pt))
407 			(void) strcpy(pt, pt[1] ? pt+2 : pt+1);
408 		else if (isdotdot(pt)) {
409 			level = 0;
410 			last = pt;
411 			do {
412 				level++;
413 				last += 2;
414 				if (*last)
415 					last++;
416 			} while (isdotdot(last));
417 			--pt; /* point to previous '/' */
418 			while (level--) {
419 				if (pt <= file)
420 					return;
421 				while ((*--pt != '/') && (pt > file))
422 					;
423 			}
424 			if (*pt == '/')
425 				pt++;
426 			(void) strcpy(pt, last);
427 		} else {
428 			while (*pt && (*pt != '/'))
429 				pt++;
430 			if (*pt == '/') {
431 				while (pt[1] == '/')
432 					(void) strcpy(pt, pt+1);
433 				pt++;
434 			}
435 		}
436 	}
437 	if ((--pt > file) && (*pt == '/'))
438 		*pt = '\0';
439 }
440 
441 void
442 set_install_root(char *path)
443 {
444 	pkg_inst_root = strdup(path);
445 }
446 
447 char *
448 get_install_root()
449 {
450 	return (pkg_inst_root);
451 }
452