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