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 <memory.h>
33 #include <string.h>
34 #include <limits.h>
35 #include <dirent.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <pkgstrct.h>
39 #include <locale.h>
40 #include <libintl.h>
41 #include <unistd.h>
42 #include <stdlib.h>
43 #include "pkglib.h"
44 #include "install.h"
45 #include "libadm.h"
46 #include "libinst.h"
47 
48 extern int	Lflag, lflag, aflag, cflag, fflag, qflag, nflag, xflag, vflag;
49 extern char	*basedir, *device, pkgspool[];
50 
51 #define	NXTENTRY(P, VFP) (gpkgmapvfp((P), (VFP)))
52 
53 #define	ERR_SPOOLED	"ERROR: unable to locate spooled object <%s>"
54 #define	MSG_NET_OBJ	"It is remote and may be available from the network."
55 #define	ERR_RMHIDDEN	"unable to remove hidden file"
56 #define	ERR_HIDDEN	"ERROR: hidden file in exclusive directory"
57 
58 static char	*findspool(struct cfent *ept);
59 static int	xdir(int maptyp, VFP_T *vfp, PKGserver server, char *dirname);
60 
61 int
62 ckentry(int envflag, int maptyp, struct cfent *ept, VFP_T *vfp,
63     PKGserver server)
64 {
65 	int	a_err, c_err,
66 		errflg;
67 	char	*path;
68 	char	*ir = get_inst_root();
69 
70 	if (ept->ftype != 'i') {
71 		if (envflag)
72 			mappath(2, ept->path);
73 		if (!device)
74 			basepath(ept->path, maptyp ? NULL : basedir, ir);
75 	}
76 	canonize(ept->path);
77 	if (strchr("sl", ept->ftype)) {
78 		if (envflag)				/* -e option */
79 			mappath(2, ept->ainfo.local);
80 		if (!RELATIVE(ept->ainfo.local)) {	/* Absolute Path */
81 			if (!device) {
82 				if (ept->ftype == 'l')	/* Hard Link */
83 					basepath(ept->ainfo.local, NULL, ir);
84 			}
85 		}
86 		if (!RELATIVE(ept->ainfo.local))	/* Absolute Path */
87 			canonize(ept->ainfo.local);
88 	}
89 	if (envflag) {
90 		if (!strchr("isl", ept->ftype)) {
91 			mapvar(2, ept->ainfo.owner);
92 			mapvar(2, ept->ainfo.group);
93 		}
94 	}
95 
96 	if (lflag) {
97 		tputcfent(ept, stdout);
98 		return (0);
99 	} else if (Lflag)
100 		return (putcfile(ept, stdout));
101 
102 	errflg = 0;
103 	if (device) {
104 		if (strchr("dxslcbp", ept->ftype))
105 			return (0);
106 		if ((path = findspool(ept)) == NULL) {
107 			logerr(gettext(ERR_SPOOLED), ept->path);
108 			return (-1);
109 		}
110 
111 		/*
112 		 * If the package file attributes are to be sync'd up with
113 		 * the pkgmap, we fix the attributes here.
114 		 */
115 		if (fflag) {
116 			a_err = 0;
117 			/* Clear dangerous bits. */
118 			ept->ainfo.mode = (ept->ainfo.mode & S_IAMB);
119 			/*
120 			 * Make sure the file is readable by the world and
121 			 * writeable by root.
122 			 */
123 			ept->ainfo.mode |= 0644;
124 			if (!strchr("in", ept->ftype)) {
125 				/* Set the safe attributes. */
126 				if (a_err = averify(fflag, &ept->ftype,
127 				    path, &ept->ainfo)) {
128 					errflg++;
129 					if (!qflag || (a_err != VE_EXIST)) {
130 						logerr(gettext("ERROR: %s"),
131 						    ept->path);
132 						logerr(getErrbufAddr());
133 					}
134 					if (a_err == VE_EXIST)
135 						return (-1);
136 				}
137 			}
138 		}
139 		/* Report invalid modtimes by passing cverify a -1 */
140 		c_err = cverify((!fflag ? (-1) : fflag),  &ept->ftype, path,
141 			&ept->cinfo, 1);
142 		if (c_err) {
143 			logerr(gettext("ERROR: %s"), path);
144 			logerr(getErrbufAddr());
145 			return (-1);
146 		}
147 	} else {
148 		a_err = 0;
149 		if (aflag && !strchr("in", ept->ftype)) {
150 			/* validate attributes */
151 			if (a_err = averify(fflag, &ept->ftype, ept->path,
152 			    &ept->ainfo)) {
153 				errflg++;
154 				if (!qflag || (a_err != VE_EXIST)) {
155 					logerr(gettext("ERROR: %s"),
156 					    ept->path);
157 					logerr(getErrbufAddr());
158 					if (maptyp && ept->pinfo->status ==
159 					    SERVED_FILE)
160 						logerr(gettext(MSG_NET_OBJ));
161 				}
162 				if (a_err == VE_EXIST)
163 					return (-1);
164 			}
165 		}
166 		if (cflag && strchr("fev", ept->ftype) &&
167 		    (!nflag || ept->ftype != 'v') && /* bug # 1082144 */
168 		    (!nflag || ept->ftype != 'e')) {
169 			/* validate contents */
170 			/* Report invalid modtimes by passing cverify a -1 */
171 			if (c_err = cverify((!fflag ? (-1) : fflag),
172 				&ept->ftype, ept->path, &ept->cinfo, 1)) {
173 				errflg++;
174 				if (!qflag || (c_err != VE_EXIST)) {
175 					if (!a_err)
176 						logerr(gettext("ERROR: %s"),
177 						    ept->path);
178 					logerr(getErrbufAddr());
179 					if (maptyp && ept->pinfo->status ==
180 					    SERVED_FILE)
181 						logerr(gettext(MSG_NET_OBJ));
182 				}
183 				if (c_err == VE_EXIST)
184 					return (-1);
185 			}
186 		}
187 		if (xflag && (ept->ftype == 'x')) {
188 			/* must do verbose here since ept->path will change */
189 			path = strdup(ept->path);
190 			if (xdir(maptyp, vfp, server, path))
191 				errflg++;
192 			(void) strcpy(ept->path, path);
193 			free(path);
194 		}
195 	}
196 	if (vflag)
197 		(void) fprintf(stderr, "%s\n", ept->path);
198 	return (errflg);
199 }
200 
201 static int
202 xdir(int maptyp, VFP_T *vfp, PKGserver server, char *dirname)
203 {
204 	DIR		*dirfp;
205 	char		badpath[PATH_MAX];
206 	int		dirfound;
207 	int		errflg;
208 	int		len;
209 	int		n;
210 	struct cfent	mine;
211 	struct dirent	*drp;
212 	struct pinfo	*pinfo;
213 	void		*pos;
214 
215 	if (!maptyp)
216 		pos = vfpGetCurrCharPtr(vfp); /* get current position in file */
217 
218 	if ((dirfp = opendir(dirname)) == NULL) {
219 		progerr(gettext("unable to open directory <%s>"), dirname);
220 		return (-1);
221 	}
222 	len = strlen(dirname);
223 
224 	errflg = 0;
225 	(void) memset((char *)&mine, '\0', sizeof (struct cfent));
226 	while ((drp = readdir(dirfp)) != NULL) {
227 		if (strcmp(drp->d_name, ".") == 0 ||
228 		    strcmp(drp->d_name, "..") == 0)
229 			continue;
230 		(void) snprintf(badpath, sizeof (badpath), "%s/%s",
231 		    dirname, drp->d_name);
232 		if (!maptyp) {
233 			dirfound = 0;
234 			while ((n = NXTENTRY(&mine, vfp)) != 0) {
235 				if (n < 0) {
236 					char	*errstr = getErrstr();
237 					logerr(gettext("ERROR: garbled entry"));
238 					logerr(gettext("pathname: %s"),
239 					    (mine.path && *mine.path) ?
240 					    mine.path : "Unknown");
241 					logerr(gettext("problem: %s"),
242 					    (errstr && *errstr) ? errstr :
243 					    "Unknown");
244 					exit(99);
245 				}
246 				if (strncmp(mine.path, dirname, len) ||
247 				    (mine.path[len] != '/'))
248 					break;
249 				if (strcmp(drp->d_name, &mine.path[len+1]) ==
250 				    0) {
251 					dirfound++;
252 					break;
253 				}
254 			}
255 
256 			vfpGetCurrCharPtr(vfp) = pos;
257 
258 			if (dirfound)
259 				continue;
260 		} else {
261 			if (srchcfile(&mine, badpath, server) == 1) {
262 				while ((pinfo = mine.pinfo) != NULL) {
263 					mine.pinfo = pinfo->next;
264 					free((char *)pinfo);
265 				}
266 				continue;
267 			}
268 		}
269 
270 		if (fflag) {
271 			if (unlink(badpath)) {
272 				errflg++;
273 				logerr(gettext("ERROR: %s"), badpath);
274 				logerr(gettext(ERR_RMHIDDEN));
275 			}
276 		} else {
277 			errflg++;
278 			logerr(gettext("ERROR: %s"), badpath);
279 			logerr(gettext(ERR_HIDDEN));
280 		}
281 	}
282 
283 	(void) closedir(dirfp);
284 	return (errflg);
285 }
286 
287 static char *
288 findspool(struct cfent *ept)
289 {
290 	static char	path[2*PATH_MAX+1];
291 	char		host[PATH_MAX+1];
292 
293 	(void) strcpy(host, pkgspool);
294 	if (ept->ftype == 'i') {
295 		if (strcmp(ept->path, "pkginfo"))
296 			(void) strcat(host, "/install");
297 	} else if (ept->path[0] == '/') {
298 		(void) strcat(host, "/root");
299 	} else {
300 		(void) strcat(host, "/reloc");
301 	}
302 
303 	(void) snprintf(path, sizeof (path), "%s/%s", host,
304 		ept->path + (ept->path[0] == '/'));
305 
306 	if (access(path, 0) == 0) {
307 		return (path);
308 	}
309 
310 	if ((ept->ftype != 'i') && (ept->volno > 0)) {
311 		(void) snprintf(path, sizeof (path),
312 				"%s.%d/%s", host, ept->volno,
313 			ept->path + (ept->path[0] == '/'));
314 		if (access(path, 0) == 0) {
315 			return (path);
316 		}
317 	}
318 	return (NULL);
319 }
320