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
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <limits.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <dirent.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/param.h>
41 #include <sys/mman.h>
42 #include <pkgstrct.h>
43 #include <pkglocs.h>
44 #include <locale.h>
45 #include <libintl.h>
46 #include <pkglib.h>
47 #include "libadm.h"
48 #include "libinst.h"
49
50 extern int qflag, lflag, Lflag, pkgcnt;
51 extern short npaths;
52
53 extern char *basedir, *pathlist[], *ppathlist[], **pkg, **environ;
54
55 extern short used[];
56 extern struct cfent **eptlist;
57
58 /* ckentry.c */
59 extern int ckentry(int, int, struct cfent *, VFP_T *, PKGserver);
60
61 #define NXTENTRY(P, VFP, SRV) \
62 (maptyp ? srchcfile((P), "*", (SRV)) : \
63 gpkgmapvfp((P), (VFP)))
64
65 #define MSG_ARCHIVE "NOTE: some pathnames are in private formats " \
66 "and cannot be verified"
67 #define WRN_NOPKG "WARNING: no pathnames were associated with <%s>"
68 #define WRN_NOPATH "WARNING: no information associated with pathname <%s>"
69 #define EMPTY_PKG "WARNING: Package <%s> is installed but empty"
70 #define ERR_NOMEM "unable to allocate dynamic memory, errno=%d"
71 #define ERR_PKGMAP "unable to open pkgmap file <%s>"
72 #define ERR_ENVFILE "unable to open environment file <%s>"
73
74 static struct cfent entry;
75
76 static int shellmatch(char *, char *);
77 static int is_partial_path_in_DB(char *, char *);
78
79 int selpath(char *, int);
80 int selpkg(char *);
81
82 /*
83 * This routine checks all files which are referenced in the pkgmap which is
84 * identified by the mapfile arg. When the package is installed, the mapfile
85 * may be the contents file or a separate pkgmap (maptyp tells the function
86 * which it is). The variable uninst tells the function whether the package
87 * is in the installed state or not. The envfile entry is usually a pkginfo
88 * file, but it could be any environment parameter list.
89 */
90
91 int
checkmap(int maptyp,int uninst,char * mapfile,char * envfile,char * pkginst,char * path,int pathtype)92 checkmap(int maptyp, int uninst, char *mapfile, char *envfile,
93 char *pkginst, char *path, int pathtype)
94 {
95 FILE *fp;
96 char *cl = NULL;
97 char *value;
98 char param[MAX_PKG_PARAM_LENGTH];
99 int count;
100 int errflg;
101 int n;
102 int selected;
103 struct pinfo *pinfo;
104 VFP_T *vfp = (VFP_T *)NULL;
105 PKGserver server;
106
107 if (envfile != NULL) {
108 if ((fp = fopen(envfile, "r")) == NULL) {
109 progerr(gettext(ERR_ENVFILE), envfile);
110 return (-1);
111 }
112 param[0] = '\0';
113 while (value = fpkgparam(fp, param)) {
114 if (strcmp("PATH", param) != 0) {
115 /*
116 * If checking an uninstalled package, we
117 * only want two parameters. If we took all
118 * of them, including path definitions, we
119 * wouldn't be looking in the right places in
120 * the reloc and root directories.
121 */
122 if (uninst) {
123 if ((strncmp("PKG_SRC_NOVERIFY", param,
124 16) == 0) && value) {
125 logerr(gettext(MSG_ARCHIVE));
126 putparam(param, value);
127 }
128 if ((strncmp("CLASSES", param,
129 7) == 0) && value)
130 putparam(param, value);
131 } else
132 putparam(param, value);
133 }
134
135 free(value);
136
137 param[0] = '\0';
138 }
139 (void) fclose(fp);
140 basedir = getenv("BASEDIR");
141 }
142
143 /*
144 * If we are using a contents file for the map, this locks the
145 * contents file in order to freeze the database and assure it
146 * remains synchronized with the file system against which it is
147 * being compared. There is no practical way to lock another pkgmap
148 * on some unknown medium so we don't bother.
149 */
150 if (maptyp) { /* If this is the contents file */
151 if (!socfile(&server, B_FALSE) ||
152 pkgopenfilter(server, pkgcnt == 1 ? pkginst : NULL) != 0) {
153 progerr(gettext(ERR_PKGMAP), "contents");
154 return (-1);
155 }
156 } else {
157 if (vfpOpen(&vfp, mapfile, "r", VFP_NONE) != 0) {
158 progerr(gettext(ERR_PKGMAP), mapfile);
159 return (-1);
160 }
161 }
162
163 if ((cl = getenv("CLASSES")) != NULL)
164 cl_sets(qstrdup(cl));
165
166 errflg = count = 0;
167
168 do {
169 if ((n = NXTENTRY(&entry, vfp, server)) == 0) {
170 break;
171 }
172 /*
173 * Search for partial paths in the ext DB.
174 */
175 if (pathtype) {
176 /* LINTED warning: statement has no consequent: if */
177 if (is_partial_path_in_DB(entry.path, path)) {
178 /* Check this entry */
179 ;
180 } else if (entry.ftype == 's' || entry.ftype == 'l') {
181 if (is_partial_path_in_DB(
182 /* LINTED warning: statement has no consequen */
183 entry.ainfo.local, path)) {
184 /* Check this entry */
185 ;
186 } else {
187 continue;
188 }
189 } else {
190 /* Skip to next DB entry */
191 continue;
192 }
193 }
194
195 if (n < 0) {
196 char *errstr = getErrstr();
197 logerr(gettext("ERROR: garbled entry"));
198 logerr(gettext("pathname: %s"),
199 (entry.path && *entry.path) ? entry.path :
200 "Unknown");
201 logerr(gettext("problem: %s"),
202 (errstr && *errstr) ? errstr : "Unknown");
203 exit(99);
204 }
205 if (n == 0)
206 break; /* done with file */
207
208 /*
209 * The class list may not be complete for good reason, so
210 * there's no complaining if this returns an index of -1.
211 */
212 if (cl != NULL)
213 entry.pkg_class_idx = cl_idx(entry.pkg_class);
214
215 if (maptyp && pkginst != NULL) {
216 /*
217 * check to see if the entry we just read
218 * is associated with one of the packages
219 * we have listed on the command line
220 */
221 selected = 0;
222 pinfo = entry.pinfo;
223 while (pinfo) {
224 if (selpkg(pinfo->pkg)) {
225 selected++;
226 break;
227 }
228 pinfo = pinfo->next;
229 }
230 if (!selected)
231 continue; /* not selected */
232 }
233
234 /*
235 * Check to see if the pathname associated with the entry
236 * we just read is associated with the list of paths we
237 * supplied on the command line
238 */
239 if (!selpath(entry.path, pathtype))
240 continue; /* not selected */
241
242 /*
243 * Determine if this is a package object wanting
244 * verification. Metafiles are always checked, otherwise, we
245 * rely on the class to discriminate.
246 */
247 if (entry.ftype != 'i')
248 /* If there's no class list... */
249 if (cl != NULL)
250 /*
251 * ... or this entry isn't in that class list
252 * or it's in a private format, then don't
253 * check it.
254 */
255 if (entry.pkg_class_idx == -1 ||
256 cl_svfy(entry.pkg_class_idx) == NOVERIFY)
257 continue;
258
259 count++;
260 if (ckentry((envfile ? 1 : 0), maptyp, &entry, vfp, server))
261 errflg++;
262 } while (n != 0);
263
264 if (maptyp)
265 relslock();
266 else
267 (void) vfpClose(&vfp);
268
269 if (environ) {
270 /* free up environment resources */
271 for (n = 0; environ[n]; n++)
272 free(environ[n]);
273 free(environ);
274 environ = NULL;
275 }
276
277 if (maptyp) {
278 /*
279 * make sure each listed package was associated with
280 * an entry from the prototype or pkgmap
281 */
282 (void) selpkg(NULL);
283 }
284 if (!qflag && !lflag && !Lflag) {
285 /*
286 * make sure each listed pathname was associated with an entry
287 * from the prototype or pkgmap
288 */
289 (void) selpath(NULL, pathtype);
290 }
291 return (errflg);
292 }
293
294 int
selpkg(char * p)295 selpkg(char *p)
296 {
297 static char *selected;
298 char buf[80];
299 char *root;
300 register int i;
301
302 if (p == NULL) {
303 if (selected == NULL) {
304 if (pkgcnt) {
305 for (i = 0; i < pkgcnt; ++i) {
306 /* bugid 1227628 */
307 root = get_inst_root();
308 if (root)
309 (void) snprintf(buf,
310 sizeof (buf),
311 "%s/var/sadm/pkg/%s/pkginfo",
312 root, pkg[i]);
313 else
314 (void) snprintf(buf,
315 sizeof (buf),
316 "/var/sadm/pkg/%s/pkginfo",
317 pkg[i]);
318
319 if (access(buf, F_OK))
320 logerr(gettext(WRN_NOPKG),
321 pkg[i]);
322 else
323 logerr(gettext(EMPTY_PKG),
324 pkg[i]);
325 }
326 }
327 } else {
328 for (i = 0; i < pkgcnt; ++i) {
329 if (selected[i] == '\0') {
330 root = get_inst_root();
331 if (root)
332 (void) snprintf(buf,
333 sizeof (buf),
334 "%s/var/sadm/pkg/%s/pkginfo",
335 root, pkg[i]);
336 else
337 (void) snprintf(buf,
338 sizeof (buf),
339 "/var/sadm/pkg/%s/pkginfo",
340 pkg[i]);
341
342 if (access(buf, F_OK))
343 logerr(gettext(WRN_NOPKG),
344 pkg[i]);
345 else
346 logerr(gettext(EMPTY_PKG),
347 pkg[i]);
348 }
349 }
350 }
351 return (0); /* return value not important */
352 } else if (pkgcnt == 0)
353 return (1);
354 else if (selected == NULL) {
355 selected =
356 (char *)calloc((unsigned)(pkgcnt+1), sizeof (char));
357 if (selected == NULL) {
358 progerr(gettext(ERR_NOMEM), errno);
359 exit(99);
360 /*NOTREACHED*/
361 }
362 }
363
364 for (i = 0; i < pkgcnt; ++i) {
365 if (pkgnmchk(p, pkg[i], 0) == 0) {
366 if (selected != NULL)
367 selected[i] = 'b';
368 return (1);
369 }
370 }
371 return (0);
372 }
373
374 int
selpath(char * path,int partial_path)375 selpath(char *path, int partial_path)
376 {
377 int n;
378
379 if (!npaths)
380 return (1); /* everything is selectable */
381
382 for (n = 0; n < npaths; n++) {
383 if (path == NULL) {
384 if (!used[n])
385 logerr(gettext(WRN_NOPATH),
386 partial_path ? ppathlist[n] :
387 pathlist[n]);
388 } else if (partial_path) {
389 used[n] = 1;
390 return (1);
391 } else if (!shellmatch(pathlist[n], path)) {
392 used[n] = 1;
393 return (1);
394 }
395 }
396 return (0); /* not selected */
397 }
398
399 static int
shellmatch(char * spec,char * path)400 shellmatch(char *spec, char *path)
401 {
402 /* Check if the value is NULL */
403 if (spec == NULL || path == NULL)
404 return (1);
405
406 while (*spec && (*spec == *path)) {
407 spec++, path++;
408 }
409 if ((*spec == *path) || (*spec == '*'))
410 return (0);
411 return (1);
412 }
413
414 static int
is_partial_path_in_DB(char * srcpath,char * trgtpath)415 is_partial_path_in_DB(char *srcpath, char *trgtpath)
416 {
417 if (strstr(srcpath, trgtpath) == NULL) {
418 return (0);
419 } else {
420 return (1);
421 }
422 }
423