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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
36 #include <sys/types.h>
40 #include "pkglocale.h"
41 #include "pkglibmsgs.h"
44 * Forward declarations
47 static int getend(char **cp
);
48 static int getstr(char **cp
, int n
, char *str
, int separator
[]);
51 int getnumvfp(char **cp
, int base
, long *d
, long bad
);
52 int getlnumvfp(char **cp
, int base
, fsblkcnt_t
*d
, long bad
);
58 static char lpath
[PATH_MAX
]; /* for ept->path */
59 static char mylocal
[PATH_MAX
]; /* for ept->ainfo.local */
60 static int decisionTableInit
= 0;
63 * These arrays must be indexable by an unsigned char.
66 static int ISWORDSEP
[UCHAR_MAX
+1];
67 static int ISPKGNAMESEP
[UCHAR_MAX
+1];
71 * Description: copy path limiting size to destination capacity
72 * Arguments: DEST - (char []) - [RW]
73 * SRC - (char *) - [RO, *RO]
74 * Pointer to first byte of path to copy
76 * Number of bytes to copy
79 #define COPYPATH(DEST, SRC, LEN) \
81 /* assure return path does not overflow */ \
82 if ((LEN) > sizeof ((DEST))) { \
83 (LEN) = sizeof ((DEST))-1; \
85 /* copy return path to local storage */ \
86 (void) memcpy((DEST), (SRC), (LEN)); \
87 (DEST)[(LEN)] = '\0'; \
92 * Description: search contents file looking for closest match to entry,
93 * creating a new contents file if output contents file specified
94 * Arguments: ept - (struct cfent *) - [RO, *RW]
95 * - contents file entry, describing last item found
96 * path - (char *) - [RO, *RO]
97 * - path to search for in contents file
98 * - If path is "*", then the next entry is returned;
99 * the next entry always matches this path
101 * - our door to the database server.
104 * < 0 - error occurred
105 * - Use getErrstr to retrieve character-string describing
106 * the reason for failure
107 * == 0 - no match found
108 * - specified path not in the contents file
109 * == 1 - exact match found
110 * - specified path found in contents file
111 * - this value is always returned if path is "*" and the
112 * next entry is returned - 0 is returned when no more
113 * entries are left to process
115 * - The ept structure supplied is filled in with a description of
116 * the item that caused the search to terminate, except in the
117 * case of '0' in which case the contents of 'ept' is undefined.
118 * - NOTE: the ept->path item points to a path that is statically
119 * allocated and will be overwritten on the next call.
120 * - NOTE: the ept->ainfo.local item points to a path that is
121 * statically allocated and will be overwritten on the next call.
125 srchcfile(struct cfent
*ept
, char *path
, PKGserver server
)
127 char *cpath_start
= NULL
;
128 char classname
[CLSSIZ
+1];
129 char pkgname
[PKGSIZ
+1];
133 struct pinfo
*lastpinfo
;
137 int linelen
; /* includes NUL */
140 * this code does not use nested subroutines because execution time
141 * of this routine is especially critical to installation and upgrade
144 /* initialize local variables */
146 setErrstr(NULL
); /* no error message currently cached */
148 lpath
[sizeof (lpath
)-1] = '\0';
150 /* initialize ept structure values */
152 (void) strlcpy(ept
->ainfo
.group
, BADGROUP
, sizeof (ept
->ainfo
.group
));
153 (void) strlcpy(ept
->ainfo
.owner
, BADOWNER
, sizeof (ept
->ainfo
.owner
));
154 (void) strlcpy(ept
->pkg_class
, BADCLASS
, sizeof (ept
->pkg_class
));
155 ept
->ainfo
.local
= (char *)NULL
;
156 ept
->ainfo
.mode
= BADMODE
;
157 ept
->cinfo
.cksum
= BADCONT
;
158 ept
->cinfo
.modtime
= BADCONT
;
159 ept
->cinfo
.size
= (fsblkcnt_t
)BADCONT
;
160 ept
->ftype
= BADFTYPE
;
162 ept
->path
= (char *)NULL
;
163 ept
->pinfo
= (struct pinfo
*)NULL
;
164 ept
->pkg_class_idx
= -1;
168 * populate decision tables that implement fast character checking;
169 * this is much faster than the equivalent strpbrk() call or a
170 * while() loop checking for the characters. It is only faster if
171 * there are at least 3 characters to scan for - when checking for
172 * one or two characters (such as '\n' or '\0') its faster to do
173 * a simple while() loop.
176 if (decisionTableInit
== 0) {
178 * any chars listed stop scan;
179 * scan stops on first byte found that is set to '1' below
183 * Separators for normal words
185 bzero(ISWORDSEP
, sizeof (ISWORDSEP
));
192 * Separators for list of packages, includes \\ for
193 * alternate ftype and : for classname
195 bzero(ISPKGNAMESEP
, sizeof (ISPKGNAMESEP
));
196 ISPKGNAMESEP
[' '] = 1;
197 ISPKGNAMESEP
['\t'] = 1;
198 ISPKGNAMESEP
['\n'] = 1;
199 ISPKGNAMESEP
[':'] = 1;
200 ISPKGNAMESEP
['\\'] = 1;
201 ISPKGNAMESEP
['\0'] = 1;
203 decisionTableInit
= 1;
206 /* if the path to scan for is empty, act like no path was specified */
208 if ((path
!= NULL
) && (*path
== '\0')) {
213 * if path to search for is "*", then we will return the first path
214 * we encounter as a match, otherwise we return an error
217 if ((path
!= NULL
) && (path
[0] != '/')) {
218 if (strcmp(path
, "*") != 0) {
219 setErrstr(pkg_gt(ERR_ILLEGAL_SEARCH_PATH
));
225 /* attempt to narrow down the search for the specified path */
227 if (anypath
== 0 && path
== NULL
)
230 /* determine first character of the next entry */
232 curbuf
= pkggetentry_named(server
, path
, &linelen
, &cpath_len
);
234 curbuf
= pkggetentry(server
, &linelen
, &cpath_len
);
240 * current entry DOES start with absolute path
241 * set ept->path to point to lpath
242 * set cpath_start/cpath_len to point to the file name
245 /* copy first token into path element of passed structure */
247 cpath_start
= curbuf
;
249 p
= cpath_start
+ cpath_len
;
253 /* copy path found to 'lpath' */
254 COPYPATH(lpath
, cpath_start
, cpath_len
);
256 /* get first character following the end of the path */
261 * we want to return information about this path in
262 * the structure provided, so parse any local path
263 * and jump to code which parses rest of the input line
266 /* parse local path specification */
267 if (getstr(&p
, PATH_MAX
, mylocal
, ISWORDSEP
)) {
268 setErrstr(ERR_CANNOT_READ_LL_PATH
);
271 ept
->ainfo
.local
= mylocal
;
275 * if an exact match and processing a new style entry, read the
276 * remaining information from the new style entry.
279 while (isspace((c
= *p
++)))
283 case '?': case 'f': case 'v': case 'e': case 'l':
284 case 's': case 'p': case 'c': case 'b': case 'd':
287 ept
->ftype
= (char)c
;
290 if (getstr(&p
, CLSSIZ
, ept
->pkg_class
, ISWORDSEP
)) {
291 setErrstr(ERR_CANNOT_READ_CLASS_TOKEN
);
294 break; /* we already read the pathname */
297 /* end of line before new-line seen */
298 setErrstr(ERR_INCOMPLETE_ENTRY
);
301 case '0': case '1': case '2': case '3': case '4':
302 case '5': case '6': case '7': case '8': case '9':
303 setErrstr(ERR_VOLUMENO_UNEXPECTED
);
307 setErrstr(ERR_FTYPE_I_UNEXPECTED
);
312 setErrstr(ERR_UNKNOWN_FTYPE
);
316 /* link/symbolic link must have link destination */
318 if (((ept
->ftype
== 's') || (ept
->ftype
== 'l')) &&
319 (ept
->ainfo
.local
== NULL
)) {
320 setErrstr(ERR_NO_LINK_SOURCE_SPECIFIED
);
324 /* character/block devices have major/minor device numbers */
326 if (((ept
->ftype
== 'c') || (ept
->ftype
== 'b'))) {
327 ept
->ainfo
.major
= BADMAJOR
;
328 ept
->ainfo
.minor
= BADMINOR
;
329 if (getnumvfp(&p
, 10, (long *)&ept
->ainfo
.major
, BADMAJOR
) ||
330 getnumvfp(&p
, 10, (long *)&ept
->ainfo
.minor
, BADMINOR
)) {
331 setErrstr(pkg_gt(ERR_CANNOT_READ_MM_NUMS
));
336 /* most types have mode, owner, group identification components */
338 if ((ept
->ftype
== 'd') || (ept
->ftype
== 'x') || (ept
->ftype
== 'c') ||
339 (ept
->ftype
== 'b') || (ept
->ftype
== 'p') ||
340 (ept
->ftype
== 'f') || (ept
->ftype
== 'v') ||
341 (ept
->ftype
== 'e')) {
342 /* mode, owner, group should be here */
343 if (getnumvfp(&p
, 8, (long *)&ept
->ainfo
.mode
, BADMODE
) ||
344 getstr(&p
, sizeof (ept
->ainfo
.owner
), ept
->ainfo
.owner
,
346 getstr(&p
, sizeof (ept
->ainfo
.group
), ept
->ainfo
.group
,
348 setErrstr(ERR_CANNOT_READ_MOG
);
353 /* i/f/v/e have size, checksum, modification time components */
355 if ((ept
->ftype
== 'i') || (ept
->ftype
== 'f') ||
356 (ept
->ftype
== 'v') || (ept
->ftype
== 'e')) {
357 /* look for content description */
358 if (getlnumvfp(&p
, 10, (fsblkcnt_t
*)&ept
->cinfo
.size
,
360 getnumvfp(&p
, 10, (long *)&ept
->cinfo
.cksum
, BADCONT
) ||
361 getnumvfp(&p
, 10, (long *)&ept
->cinfo
.modtime
, BADCONT
)) {
362 setErrstr(ERR_CANNOT_READ_CONTENT_INFO
);
367 /* i files processing is completed - return 'exact match found' */
369 if (ept
->ftype
== 'i') {
374 * determine list of packages which reference this entry
377 lastpinfo
= (struct pinfo
*)NULL
;
378 while ((c
= getstr(&p
, sizeof (pkgname
), pkgname
, ISPKGNAMESEP
)) <= 0) {
379 /* if c < 0 the string was too long to fix in the buffer */
382 setErrstr(ERR_PACKAGE_NAME_TOO_LONG
);
386 /* a package is present - create and populate pinfo structure */
388 pinfo
= (struct pinfo
*)calloc(1, sizeof (struct pinfo
));
390 setErrstr(ERR_NO_MEMORY
);
394 ept
->pinfo
= pinfo
; /* first one */
396 lastpinfo
->next
= pinfo
; /* link list */
400 if ((pkgname
[0] == '-') || (pkgname
[0] == '+') ||
401 (pkgname
[0] == '*') || (pkgname
[0] == '~') ||
402 (pkgname
[0] == '!') || (pkgname
[0] == '%')) {
403 pinfo
->status
= pkgname
[0];
404 (void) strlcpy(pinfo
->pkg
, pkgname
+1,
405 sizeof (pinfo
->pkg
));
407 (void) strlcpy(pinfo
->pkg
, pkgname
,
408 sizeof (pinfo
->pkg
));
411 /* pkg/[:[ftype][:class] */
414 /* get alternate ftype */
420 /* get special classname */
421 (void) getstr(&p
, sizeof (classname
), classname
,
423 (void) strlcpy(pinfo
->aclass
, classname
,
424 sizeof (pinfo
->aclass
));
429 /* break out of while if at end of entry */
431 if ((c
== '\n') || (c
== '\0')) {
435 /* if package not separated by a space return an error */
438 setErrstr(ERR_BAD_ENTRY_END
);
444 * parsing of the entry is complete
447 /* if not at the end of the entry, make it so */
449 if ((c
!= '\n') && (c
!= '\0')) {
450 if (getend(&p
) && ept
->pinfo
) {
451 setErrstr(ERR_EXTRA_TOKENS
);
460 getstr(char **cp
, int n
, char *str
, int separator
[])
471 /* leading white space ignored */
473 while (((c
= *p
) != '\0') && (isspace(*p
++)))
475 if ((c
== '\0') || (c
== '\n')) {
478 return (1); /* nothing there */
483 /* compute length based on delimiter found or not */
486 while (separator
[(int)(*(unsigned char *)p1
)] == 0) {
490 len
= (ptrdiff_t)p1
- (ptrdiff_t)p
;
492 /* if string will fit in result buffer copy string and return success */
495 (void) memcpy(str
, p
, len
);
502 /* result buffer too small; copy partial string, return error */
503 (void) memcpy(str
, p
, n
-1);
518 /* if at end of buffer return no more characters left */
524 while ((*p
!= '\0') && (*p
!= '\n')) {