xref: /illumos-gate/usr/src/cmd/svr4pkg/pkgchk/checkmap.c (revision e4d060fb4c00d44cd578713eb9a921f594b733b8)
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
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
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] == NULL) {
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
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
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
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