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]
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.
35 /* 5-20-92 newroot support added */
42 #include <sys/types.h>
54 static char sepset
[] = ":=\n";
55 static char qset
[] = "'\"";
56 static char *pkg_inst_root
= 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.
79 pkginfofind(char *path
, char *pkg_dir
, char *pkginst
)
83 /* Construct the temporary pkginfo file name. */
84 len
= snprintf(path
, PATH_MAX
, "%s/.save.%s/pkginfo", pkg_dir
,
88 if (access(path
, 0)) {
90 * This isn't a temporary directory, so we look for a
93 len
= snprintf(path
, PATH_MAX
, "%s/%s/pkginfo", pkg_dir
,
98 return (0); /* doesn't appear to be a package */
105 * This opens the appropriate pkginfo file for a particular package.
108 pkginfopen(char *pkg_dir
, char *pkginst
)
113 if (pkginfofind(temp
, pkg_dir
, pkginst
))
114 fp
= fopen(temp
, "r");
121 fpkgparam(FILE *fp
, char *param
)
123 char ch
, buffer
[VALSIZ
];
126 boolean_t check_end_quote
= B_FALSE
;
127 boolean_t begline
, quoted
, escape
;
137 for (;;) { /* For each entry in the file fp */
141 /* Get the next token. */
142 while ((c
= getc(fp
)) != EOF
) {
144 if (strchr(sepset
, ch
))
150 /* If it's the end of the file, exit the for() loop */
153 return (NULL
); /* No more entries left */
155 /* If it's end of line, look for the next parameter. */
156 } else if (c
== NEWLINE
)
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. */
164 /* If parameter is NULL, we return whatever we got. */
165 if (param
[0] == '\0') {
166 (void) strcpy(param
, buffer
);
169 /* If this doesn't match the parameter, drop thru. */
170 } else if (strcmp(param
, buffer
))
173 /* Otherwise, this is our boy. */
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
) {
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.
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
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
;
211 * The end quote candidate qualifies.
212 * Eat any trailing spaces.
214 if (check_end_quote
) {
217 check_end_quote
= 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
) {
230 check_end_quote
= B_FALSE
;
232 copy
--; /* Eat previous esc */
236 begline
= B_TRUE
; /* New input line */
239 if (!escape
&& strchr(qset
, ch
)) {
248 * This is the candidate
249 * for end quote. Check
250 * to see it qualifies.
252 check_end_quote
= B_TRUE
;
260 if (copy
) *copy
++ = ch
;
264 if (copy
&& ((++n
% VALSIZ
) == 0)) {
266 mempt
= realloc(mempt
,
267 (n
+VALSIZ
)*sizeof (char));
271 mempt
= calloc((size_t)(2*VALSIZ
),
275 (void) strncpy(mempt
, buffer
, 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)
297 errno
= EFAULT
; /* missing closing quote */
305 errno
= EINVAL
; /* parameter not found */
311 mempt
= strdup(buffer
);
313 mempt
= realloc(mempt
, (strlen(mempt
)+1)*sizeof (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
];
325 pkgdir
= get_PKGLOC();
328 /* request to close file */
342 (void) strcpy(line
, pkgfile
); /* filename was passed */
344 (void) pkginfofind(line
, pkgdir
, pkg
);
346 if (fp
&& strcmp(line
, lastfname
)) {
347 /* different filename implies need for different fp */
352 (void) strcpy(lastfname
, line
);
353 if ((fp
= fopen(lastfname
, "r")) == 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
365 /* new parameter request, so reset file position */
366 if (fseek(fp
, 0L, 0))
370 if (pt
= fpkgparam(fp
, param
)) {
371 if (strcmp(param
, "ARCH") == NULL
||
372 strcmp(param
, "CATEGORY") == NULL
) {
373 /* remove all whitespace from value */
376 if (!isspace((unsigned char)*value
))
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 *);
394 set_PKGpaths(char *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
);
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
);
414 if (Adm_pkgloc
[0] == NULL
)
423 if (Adm_pkgadm
[0] == NULL
)
430 set_PKGADM(char *newpath
)
432 (void) strcpy(Adm_pkgadm
, newpath
);
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] == '/')))
445 canonize_name(char *file
)
450 /* Remove references such as "./" and "../" and "//" */
452 for (pt
= file
; *pt
; ) {
454 (void) strcpy(pt
, pt
[1] ? pt
+2 : pt
+1);
455 else if (isdotdot(pt
)) {
463 } while (isdotdot(last
));
464 --pt
; /* point to previous '/' */
468 while ((*--pt
!= '/') && (pt
> file
))
473 (void) strcpy(pt
, last
);
475 while (*pt
&& (*pt
!= '/'))
479 (void) strcpy(pt
, pt
+1);
484 if ((--pt
> file
) && (*pt
== '/'))
489 set_install_root(char *path
)
491 pkg_inst_root
= strdup(path
);
497 return (pkg_inst_root
);