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