xref: /titanic_50/usr/src/cmd/svr4pkg/pkgmk/main.c (revision cdcc71c09dccd8c66f98c710f068f0722fe6de56)
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 <signal.h>
34 #include <errno.h>
35 #include <malloc.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <time.h>
39 #include <fcntl.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <sys/param.h>
43 #include <ctype.h>
44 #include <sys/mman.h>
45 #include <sys/sysmacros.h>
46 #include <strings.h>
47 #include <pkgstrct.h>
48 #include <pkgdev.h>
49 #include <pkginfo.h>
50 #include <pkglocs.h>
51 #include <locale.h>
52 #include <libintl.h>
53 #include <sys/statvfs.h>
54 #include <sys/utsname.h>
55 #include <instzones_api.h>
56 #include <pkglib.h>
57 #include <libadm.h>
58 #include <libinst.h>
59 
60 extern char	**environ, *pkgdir;
61 
62 /* mkpkgmap.c */
63 extern int	mkpkgmap(char *outfile, char *protofile, char **cmdparam);
64 /* splpkgmap.c */
65 extern int	splpkgmap(struct cfent **eptlist, unsigned int eptnum,
66     char *order[], ulong_t bsize, ulong_t frsize, fsblkcnt_t *plimit,
67     fsfilcnt_t *pilimit, fsblkcnt_t *pllimit);
68 /* scriptvfy.c */
69 extern int	checkscripts(char *inst_dir, int silent);
70 
71 /* libpkg/gpkgmap.c */
72 extern void	setmapmode(int mode_no);
73 
74 static boolean_t valid_zone_attr(struct cfent **eptlist);
75 
76 #define	MALSIZ	16
77 #define	NROOT	8
78 #define	SPOOLDEV	"spool"
79 
80 #define	MSG_PROTOTYPE	"## Building pkgmap from package prototype file.\n"
81 #define	MSG_PKGINFO	"## Processing pkginfo file.\n"
82 #define	MSG_VOLUMIZE	"## Attempting to volumize %d entries in pkgmap.\n"
83 #define	MSG_PACKAGE1	"## Packaging one part.\n"
84 #define	MSG_PACKAGEM	"## Packaging %d parts.\n"
85 #define	MSG_VALSCRIPTS	"## Validating control scripts.\n"
86 
87 /* Other problems */
88 #define	ERR_MEMORY	"memory allocation failure, errno=%d"
89 #define	ERR_NROOT	"too many paths listed with -r option, limit is %d"
90 #define	ERR_PKGINST	"invalid package instance identifier <%s>"
91 #define	ERR_PKGABRV	"invalid package abbreviation <%s>"
92 #define	ERR_BADDEV	"unknown or invalid device specified <%s>"
93 #define	ERR_TEMP	"unable to obtain temporary file resources, errno=%d"
94 #define	ERR_DSTREAM	"invalid device specified (datastream) <%s>"
95 #define	ERR_SPLIT	"unable to volumize package"
96 #define	ERR_MKDIR	"unable to make directory <%s>"
97 #define	ERR_SYMLINK	"unable to create symbolic link for <%s>"
98 #define	ERR_OVERWRITE	"must use -o option to overwrite <%s>"
99 #define	ERR_UMOUNT	"unable to unmount device <%s>"
100 #define	ERR_NOPKGINFO	"required pkginfo file is not specified in prototype " \
101 			"file"
102 #define	ERR_RDPKGINFO	"unable to process pkginfo file <%s>"
103 #define	ERR_PROTOTYPE	"unable to locate prototype file"
104 #define	ERR_STATVFS	"unable to stat filesystem <%s>"
105 #define	ERR_WHATVFS	"unable to determine or access output filesystem for " \
106 			"device <%s>"
107 #define	ERR_DEVICE	"unable to find info for device <%s>"
108 #define	ERR_BUILD	"unable to build pkgmap from prototype file"
109 #define	ERR_ONEVOL	"other packages found - package must fit on a single " \
110 			"volume"
111 #define	ERR_NOPARAM	"parameter <%s> is not defined in <%s>"
112 #define	ERR_PKGMTCH	"PKG parameter <%s> does not match instance <%s>"
113 #define	ERR_NO_PKG_INFOFILE	"unable to open pkginfo file <%s>: %s"
114 #define	ERR_ALLZONES_AND_THISZONE	"The package <%s> has <%s> = true " \
115 					"and <%s> = true: the package may " \
116 					"set either parameter to true, but " \
117 					"may not set both parameters to " \
118 					"true. NOTE: if the package " \
119 					"contains a request script, it is " \
120 					"treated as though it has " \
121 					"<SUNW_PKG_THISZONE> = true"
122 #define	ERR_NO_ALLZONES_AND_HOLLOW	"The package <%s> has <%s> = false " \
123 					"and <%s> = true: a hollow package " \
124 					"must also be set to install in all " \
125 					"zones"
126 #define	ERR_PKGINFO_INVALID_OPTION_COMB	"Invalid combinations of zone " \
127 					"parameters in pkginfo file"
128 
129 #define	ERR_USAGE	"usage: %s [options] [VAR=value [VAR=value]] " \
130 			"[pkginst]\n" \
131 			"   where options may include:\n" \
132 			"\t-o\n" \
133 			"\t-a arch\n" \
134 			"\t-v version\n" \
135 			"\t-p pstamp\n" \
136 			"\t-l limit\n" \
137 			"\t-r rootpath\n" \
138 			"\t-b basedir\n" \
139 			"\t-d device\n" \
140 			"\t-f protofile\n"
141 #define	WRN_MISSINGDIR	"WARNING: missing directory entry for <%s>"
142 #define	WRN_SETPARAM	"WARNING: parameter <%s> set to \"%s\""
143 #define	WRN_CLASSES	"WARNING: unreferenced class <%s> in prototype file"
144 
145 #define	LINK    1
146 
147 struct pkgdev pkgdev; 	/* holds info about the installation device */
148 int	started;
149 char	pkgloc[PATH_MAX];
150 char	*basedir;
151 char	*root;
152 char	*rootlist[NROOT];
153 char	*t_pkgmap;
154 char	*t_pkginfo;
155 
156 static struct cfent *svept;
157 static char	*protofile,
158 		*device;
159 static fsblkcnt_t limit = 0;
160 static fsblkcnt_t llimit = 0;
161 static fsfilcnt_t ilimit = 0;
162 static int	overwrite,
163 		nflag,
164 		sflag;
165 static void	ckmissing(char *path, char type);
166 static void	outvol(struct cfent **eptlist, unsigned int eptnum, int part,
167 			int nparts);
168 static void	trap(int n);
169 static void	usage(void);
170 
171 static int	slinkf(char *from, char *to);
172 
173 int
174 main(int argc, char *argv[])
175 {
176 	struct utsname utsbuf;
177 	struct statvfs64 svfsb;
178 	struct cfent	**eptlist;
179 	FILE	*fp;
180 	VFP_T	*vfp;
181 	int	c, n, found;
182 	int	part, nparts, npkgs, objects;
183 	char	buf[MAX_PKG_PARAM_LENGTH];
184 	char	temp[MAX_PKG_PARAM_LENGTH];
185 	char	param[MAX_PKG_PARAM_LENGTH];
186 	char	*pt, *value, *pkginst, *tmpdir, *abi_sym_ptr,
187 		**cmdparam;
188 	char	*pkgname;
189 	char	*pkgvers;
190 	char	*pkgarch;
191 	char	*pkgcat;
192 	void	(*func)();
193 	time_t	clock;
194 	ulong_t	bsize = 0;
195 	ulong_t	frsize = 0;
196 	struct cl_attr	**allclass = NULL;
197 	struct cl_attr	**order;
198 	unsigned int eptnum, i;
199 
200 	/* initialize locale environment */
201 
202 	(void) setlocale(LC_ALL, "");
203 
204 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
205 #define	TEXT_DOMAIN "SYS_TEST"
206 #endif
207 	(void) textdomain(TEXT_DOMAIN);
208 
209 	/* initialize program name */
210 
211 	(void) set_prog_name(argv[0]);
212 
213 	/* tell spmi zones interface how to access package output functions */
214 
215 	z_set_output_functions(echo, echoDebug, progerr);
216 
217 	func = sigset(SIGINT, trap);
218 	if (func != SIG_DFL)
219 		func = sigset(SIGINT, func);
220 	func = sigset(SIGHUP, trap);
221 	setmapmode(MAPBUILD);	/* variable binding */
222 	if (func != SIG_DFL)
223 		func = sigset(SIGHUP, func);
224 
225 	environ = NULL;
226 	while ((c = getopt(argc, argv, "osnp:l:r:b:d:f:a:v:?")) != EOF) {
227 		switch (c) {
228 		    case 'n':
229 			nflag++;
230 			break;
231 
232 		    case 's':
233 			sflag++;
234 			break;
235 
236 		    case 'o':
237 			overwrite++;
238 			break;
239 
240 		    case 'p':
241 			putparam("PSTAMP", optarg);
242 			break;
243 
244 		    case 'l':
245 			llimit = strtoull(optarg, NULL, 10);
246 			break;
247 
248 		    case 'r':
249 			pt = strtok(optarg, " \t\n, ");
250 			n = 0;
251 			do {
252 				rootlist[n++] = flex_device(pt, 0);
253 				if (n >= NROOT) {
254 					progerr(gettext(ERR_NROOT), NROOT);
255 					quit(1);
256 				}
257 			} while (pt = strtok(NULL, " \t\n, "));
258 			rootlist[n] = NULL;
259 			break;
260 
261 		    case 'b':
262 			basedir = optarg;
263 			break;
264 
265 		    case 'f':
266 			protofile = optarg;
267 			break;
268 
269 		    case 'd':
270 			device = flex_device(optarg, 1);
271 			break;
272 
273 		    case 'a':
274 			putparam("ARCH", optarg);
275 			break;
276 
277 		    case 'v':
278 			putparam("VERSION", optarg);
279 			break;
280 
281 		    default:
282 			usage();
283 			/*NOTREACHED*/
284 			/*
285 			 * Although usage() calls a noreturn function,
286 			 * needed to add return (1);  so that main() would
287 			 * pass compilation checks. The statement below
288 			 * should never be executed.
289 			 */
290 			return (1);
291 		}
292 	}
293 
294 	/*
295 	 * Store command line variable assignments for later
296 	 * incorporation into the environment.
297 	 */
298 	cmdparam = &argv[optind];
299 
300 	/* Skip past equates. */
301 	while (argv[optind] && strchr(argv[optind], '='))
302 		optind++;
303 
304 	/* Confirm that the instance name is valid */
305 	if ((pkginst = argv[optind]) != NULL) {
306 		if (pkgnmchk(pkginst, "all", 0)) {
307 			progerr(gettext(ERR_PKGINST), pkginst);
308 			quit(1);
309 		}
310 		argv[optind++] = NULL;
311 	}
312 	if (optind != argc)
313 		usage();
314 
315 	tmpdir = getenv("TMPDIR");
316 	if (tmpdir == NULL)
317 		tmpdir = P_tmpdir;
318 
319 	/* bug id 4244631, not ABI compliant */
320 	abi_sym_ptr = getenv("PKG_NONABI_SYMLINKS");
321 	if (abi_sym_ptr && (strncasecmp(abi_sym_ptr, "TRUE", 4) == 0)) {
322 		set_nonABI_symlinks();
323 	}
324 
325 	if (device == NULL) {
326 		device = devattr(SPOOLDEV, "pathname");
327 		if (device == NULL) {
328 			progerr(gettext(ERR_DEVICE), SPOOLDEV);
329 			exit(99);
330 		}
331 	}
332 
333 	if (protofile == NULL) {
334 		if (access("prototype", 0) == 0)
335 			protofile = "prototype";
336 		else if (access("Prototype", 0) == 0)
337 			protofile = "Prototype";
338 		else {
339 			progerr(gettext(ERR_PROTOTYPE));
340 			quit(1);
341 		}
342 	}
343 
344 	if (devtype(device, &pkgdev)) {
345 		progerr(gettext(ERR_BADDEV), device);
346 		quit(1);
347 	}
348 	if (pkgdev.norewind) {
349 		/* initialize datastream */
350 		progerr(gettext(ERR_DSTREAM), device);
351 		quit(1);
352 	}
353 	if (pkgdev.mount) {
354 		if (n = pkgmount(&pkgdev, NULL, 0, 0, 1))
355 			quit(n);
356 	}
357 
358 	/*
359 	 * convert prototype file to a pkgmap, while locating
360 	 * package objects in the current environment
361 	 */
362 	t_pkgmap = tempnam(tmpdir, "tmpmap");
363 	if (t_pkgmap == NULL) {
364 		progerr(gettext(ERR_TEMP), errno);
365 		exit(99);
366 	}
367 
368 	(void) fprintf(stderr, gettext(MSG_PROTOTYPE));
369 	if (n = mkpkgmap(t_pkgmap, protofile, cmdparam)) {
370 		progerr(gettext(ERR_BUILD));
371 		quit(1);
372 	}
373 
374 	setmapmode(MAPNONE);	/* All appropriate variables are now bound */
375 
376 	if (vfpOpen(&vfp, t_pkgmap, "r", VFP_NEEDNOW) != 0) {
377 		progerr(gettext(ERR_TEMP), errno);
378 		quit(99);
379 	}
380 
381 	eptlist = procmap(vfp, 0, NULL);
382 
383 	if (eptlist == NULL) {
384 		quit(1);
385 	}
386 
387 	(void) vfpClose(&vfp);
388 
389 	/* Validate the zone attributes in pkginfo, before creation */
390 	if (!valid_zone_attr(eptlist)) {
391 		progerr(ERR_PKGINFO_INVALID_OPTION_COMB);
392 		quit(1);
393 	}
394 
395 	(void) fprintf(stderr, gettext(MSG_PKGINFO));
396 	pt = NULL;
397 	for (i = 0; eptlist[i]; i++) {
398 		ckmissing(eptlist[i]->path, eptlist[i]->ftype);
399 		if (eptlist[i]->ftype != 'i')
400 			continue;
401 		if (strcmp(eptlist[i]->path, "pkginfo") == 0)
402 			svept = eptlist[i];
403 	}
404 	if (svept == NULL) {
405 		progerr(gettext(ERR_NOPKGINFO));
406 		quit(99);
407 	}
408 	eptnum = i;
409 
410 	/*
411 	 * process all parameters from the pkginfo file
412 	 * and place them in the execution environment
413 	 */
414 
415 	if ((fp = fopen(svept->ainfo.local, "r")) == NULL) {
416 		progerr(gettext(ERR_RDPKGINFO), svept->ainfo.local);
417 		quit(99);
418 	}
419 	param[0] = '\0';
420 	while (value = fpkgparam(fp, param)) {
421 		if (getenv(param) == NULL)
422 			putparam(param, value);
423 		free((void *)value);
424 		param[0] = '\0';
425 	}
426 	(void) fclose(fp);
427 
428 	/* add command line variables */
429 	while (*cmdparam && (value = strchr(*cmdparam, '=')) != NULL) {
430 		*value = NULL;	/* terminate the parameter */
431 		value++;	/* value is now the value (not '=') */
432 		putparam(*cmdparam++, value);  /* store it in environ */
433 	}
434 
435 	/* make sure parameters are valid */
436 	(void) time(&clock);
437 	if (pt = getenv("PKG")) {
438 		if (pkgnmchk(pt, NULL, 0) || strchr(pt, '.')) {
439 			progerr(gettext(ERR_PKGABRV), pt);
440 			quit(1);
441 		}
442 		if (pkginst == NULL)
443 			pkginst = pt;
444 	} else {
445 		progerr(gettext(ERR_NOPARAM), "PKG", svept->path);
446 		quit(1);
447 	}
448 	/*
449 	 * verify consistency between PKG parameter and pkginst
450 	 */
451 	(void) snprintf(param, sizeof (param), "%s.*", pt);
452 	if (pkgnmchk(pkginst, param, 0)) {
453 		progerr(gettext(ERR_PKGMTCH), pt, pkginst);
454 		quit(1);
455 	}
456 
457 	/*
458 	 * *********************************************************************
459 	 * this feature is removed starting with Solaris 10 - there is no built
460 	 * in list of packages that should be run "the old way"
461 	 * *********************************************************************
462 	 */
463 
464 #ifdef	ALLOW_EXCEPTION_PKG_LIST
465 	/* Until 2.9, set it from the execption list */
466 	if (exception_pkg(pkginst, LINK))
467 		set_nonABI_symlinks();
468 #endif
469 
470 	if ((pkgname = getenv("NAME")) == NULL) {
471 		progerr(gettext(ERR_NOPARAM), "NAME", svept->path);
472 		quit(1);
473 	}
474 	if (ckparam("NAME", pkgname))
475 		quit(1);
476 	if ((pkgvers = getenv("VERSION")) == NULL) {
477 		/* XXX - I18n */
478 		/* LINTED do not use cftime(); use strftime instead */
479 		(void) cftime(buf, "\045m/\045d/\045Y", &clock);
480 		(void) snprintf(temp, sizeof (temp),
481 			gettext("Dev Release %s"), buf);
482 		putparam("VERSION", temp);
483 		pkgvers = getenv("VERSION");
484 		logerr(gettext(WRN_SETPARAM), "VERSION", temp);
485 	}
486 	if (ckparam("VERSION", pkgvers))
487 		quit(1);
488 	if ((pkgarch = getenv("ARCH")) == NULL) {
489 		(void) uname(&utsbuf);
490 		putparam("ARCH", utsbuf.machine);
491 		pkgarch = getenv("ARCH");
492 		logerr(gettext(WRN_SETPARAM), "ARCH", utsbuf.machine);
493 	}
494 	if (ckparam("ARCH", pkgarch))
495 		quit(1);
496 	if (getenv("PSTAMP") == NULL) {
497 		/* use octal value of '%' to fight sccs expansion */
498 		/* XXX - I18n */
499 		/* LINTED do not use cftime(); use strftime instead */
500 		(void) cftime(buf, "\045Y\045m\045d\045H\045M\045S", &clock);
501 		(void) uname(&utsbuf);
502 		(void) snprintf(temp, sizeof (temp), "%s%s",
503 			utsbuf.nodename, buf);
504 		putparam("PSTAMP", temp);
505 		logerr(gettext(WRN_SETPARAM), "PSTAMP", temp);
506 	}
507 	if ((pkgcat = getenv("CATEGORY")) == NULL) {
508 		progerr(gettext(ERR_NOPARAM), "CATEGORY", svept->path);
509 		quit(1);
510 	}
511 	if (ckparam("CATEGORY", pkgcat))
512 		quit(1);
513 
514 	/*
515 	 * warn user of classes listed in package which do
516 	 * not appear in CLASSES variable in pkginfo file
517 	 */
518 	objects = 0;
519 	for (i = 0; eptlist[i]; i++) {
520 		if (eptlist[i]->ftype != 'i') {
521 			objects++;
522 			addlist(&allclass, eptlist[i]->pkg_class);
523 		}
524 	}
525 
526 	if ((pt = getenv("CLASSES")) == NULL) {
527 		if (allclass && *allclass) {
528 			cl_setl(allclass);
529 			cl_putl("CLASSES", allclass);
530 			logerr(gettext(WRN_SETPARAM), "CLASSES",
531 			    getenv("CLASSES"));
532 		}
533 	} else {
534 		cl_sets(qstrdup(pt));
535 		if (allclass && *allclass) {
536 			for (i = 0; allclass[i]; i++) {
537 				found = 0;
538 				if (cl_idx(allclass[i]->name) != -1) {
539 					found++;
540 					break;
541 				}
542 				if (!found) {
543 					logerr(gettext(WRN_CLASSES),
544 					    (char *)allclass[i]);
545 				}
546 			}
547 		}
548 	}
549 
550 	(void) fprintf(stderr, gettext(MSG_VOLUMIZE), objects);
551 	order = (struct cl_attr **)0;
552 	if (pt = getenv("ORDER")) {
553 		pt = qstrdup(pt);
554 		(void) setlist(&order, pt);
555 		cl_putl("ORDER", order);
556 	}
557 
558 	/* stat the intended output filesystem to get blocking information */
559 	if (pkgdev.dirname == NULL) {
560 		progerr(gettext(ERR_WHATVFS), device);
561 		quit(99);
562 	}
563 	if (statvfs64(pkgdev.dirname, &svfsb)) {
564 		progerr(gettext(ERR_STATVFS), pkgdev.dirname);
565 		quit(99);
566 	}
567 
568 	if (bsize == 0) {
569 		bsize = svfsb.f_bsize;
570 	}
571 	if (frsize == 0) {
572 		frsize = svfsb.f_frsize;
573 	}
574 
575 	if (limit == 0)
576 		/*
577 		 * bavail is in terms of fragment size blocks - change
578 		 * to 512 byte blocks
579 		 */
580 		limit = (fsblkcnt_t)(((fsblkcnt_t)frsize > 0) ?
581 			howmany(frsize, DEV_BSIZE) :
582 			howmany(bsize, DEV_BSIZE)) * svfsb.f_bavail;
583 
584 	if (ilimit == 0) {
585 		ilimit = (svfsb.f_favail > 0) ?
586 		    svfsb.f_favail : svfsb.f_ffree;
587 	}
588 
589 	nparts = splpkgmap(eptlist, eptnum, (char **)order, bsize, frsize,
590 	    &limit, &ilimit, &llimit);
591 
592 	if (nparts <= 0) {
593 		progerr(gettext(ERR_SPLIT));
594 		quit(1);
595 	}
596 
597 	if (nflag) {
598 		for (i = 0; eptlist[i]; i++)
599 			(void) ppkgmap(eptlist[i], stdout);
600 		exit(0);
601 		/*NOTREACHED*/
602 	}
603 
604 	(void) snprintf(pkgloc, sizeof (pkgloc), "%s/%s",
605 			pkgdev.dirname, pkginst);
606 	if (!isdir(pkgloc) && !overwrite) {
607 		progerr(gettext(ERR_OVERWRITE), pkgloc);
608 		quit(1);
609 	}
610 
611 	/* output all environment install parameters */
612 	t_pkginfo = tempnam(tmpdir, "pkginfo");
613 	if ((fp = fopen(t_pkginfo, "w")) == NULL) {
614 		progerr(gettext(ERR_TEMP), errno);
615 		exit(99);
616 	}
617 	for (i = 0; environ[i]; i++) {
618 		if (isupper(*environ[i])) {
619 			(void) fputs(environ[i], fp);
620 			(void) fputc('\n', fp);
621 		}
622 	}
623 	(void) fclose(fp);
624 
625 	started++;
626 	(void) rrmdir(pkgloc);
627 	if (mkdir(pkgloc, 0755)) {
628 		progerr(gettext(ERR_MKDIR), pkgloc);
629 		quit(1);
630 	}
631 
632 	/* determine how many packages already reside on the medium */
633 	pkgdir = pkgdev.dirname;
634 	npkgs = 0;
635 	while (pt = fpkginst("all", NULL, NULL))
636 		npkgs++;
637 	(void) fpkginst(NULL); /* free resource usage */
638 
639 	if (nparts > 1) {
640 		if (pkgdev.mount && npkgs) {
641 			progerr(gettext(ERR_ONEVOL));
642 			quit(1);
643 		}
644 	}
645 
646 	/*
647 	 *  update pkgmap entry for pkginfo file, since it may
648 	 *  have changed due to command line or failure to
649 	 *  specify all neccessary parameters
650 	 */
651 	for (i = 0; eptlist[i]; i++) {
652 		if (eptlist[i]->ftype != 'i')
653 			continue;
654 		if (strcmp(eptlist[i]->path, "pkginfo") == 0) {
655 			svept = eptlist[i];
656 			svept->ftype = '?';
657 			svept->ainfo.local = t_pkginfo;
658 			(void) cverify(0, &svept->ftype, t_pkginfo,
659 				&svept->cinfo, 1);
660 			svept->ftype = 'i';
661 			break;
662 		}
663 	}
664 
665 	if (nparts > 1)
666 		(void) fprintf(stderr, gettext(MSG_PACKAGEM), nparts);
667 	else
668 		(void) fprintf(stderr, gettext(MSG_PACKAGE1));
669 
670 	for (part = 1; part <= nparts; part++) {
671 		if ((part > 1) && pkgdev.mount) {
672 			if (pkgumount(&pkgdev)) {
673 				progerr(gettext(ERR_UMOUNT), pkgdev.mount);
674 				quit(99);
675 			}
676 			if (n = pkgmount(&pkgdev, NULL, part, nparts, 1))
677 				quit(n);
678 			(void) rrmdir(pkgloc);
679 			if (mkdir(pkgloc, 0555)) {
680 				progerr(gettext(ERR_MKDIR), pkgloc);
681 				quit(99);
682 			}
683 		}
684 		outvol(eptlist, eptnum, part, nparts);
685 
686 		/* Validate (as much as possible) the control scripts. */
687 		if (part == 1) {
688 			char inst_path[PATH_MAX];
689 
690 			(void) fprintf(stderr, gettext(MSG_VALSCRIPTS));
691 			(void) snprintf(inst_path, sizeof (inst_path),
692 					"%s/install", pkgloc);
693 			checkscripts(inst_path, 0);
694 		}
695 	}
696 
697 	quit(0);
698 	/* LINTED: no return */
699 }
700 
701 static void
702 trap(int n)
703 {
704 	(void) signal(SIGINT, SIG_IGN);
705 	(void) signal(SIGHUP, SIG_IGN);
706 
707 	if (n == SIGINT)
708 		quit(3);
709 	else {
710 		(void) fprintf(stderr, gettext("%s terminated (signal %d).\n"),
711 				get_prog_name(), n);
712 		quit(99);
713 	}
714 }
715 
716 static void
717 outvol(struct cfent **eptlist, unsigned int eptnum, int part, int nparts)
718 {
719 	FILE	*fp;
720 	char	*svpt, *path, temp[PATH_MAX];
721 	unsigned int	i;
722 
723 
724 	if (nparts > 1)
725 		(void) fprintf(stderr, gettext(" -- part %2d:\n"), part);
726 	if (part == 1) {
727 		/* re-write pkgmap, but exclude local pathnames */
728 		(void) snprintf(temp, sizeof (temp), "%s/pkgmap", pkgloc);
729 		if ((fp = fopen(temp, "w")) == NULL) {
730 			progerr(gettext(ERR_TEMP), errno);
731 			quit(99);
732 		}
733 		(void) fprintf(fp, ": %d %ld\n", nparts, limit);
734 		for (i = 0; eptlist[i]; i++) {
735 			svpt = eptlist[i]->ainfo.local;
736 			if (!strchr("sl", eptlist[i]->ftype))
737 				eptlist[i]->ainfo.local = NULL;
738 			if (ppkgmap(eptlist[i], fp)) {
739 				progerr(gettext(ERR_TEMP), errno);
740 				quit(99);
741 			}
742 			eptlist[i]->ainfo.local = svpt;
743 		}
744 		(void) fclose(fp);
745 		(void) fprintf(stderr, "%s\n", temp);
746 	}
747 
748 	(void) snprintf(temp, sizeof (temp), "%s/pkginfo", pkgloc);
749 	if (copyf(svept->ainfo.local, temp, svept->cinfo.modtime))
750 		quit(1);
751 	(void) fprintf(stderr, "%s\n", temp);
752 
753 	for (i = 0; i < eptnum; i++) {
754 		if (eptlist[i]->volno != part)
755 			continue;
756 		if (strchr("dxslcbp", eptlist[i]->ftype))
757 			continue;
758 		if (eptlist[i]->ftype == 'i') {
759 			if (eptlist[i] == svept)
760 				continue; /* don't copy pkginfo file */
761 			(void) snprintf(temp, sizeof (temp),
762 				"%s/install/%s", pkgloc,
763 				eptlist[i]->path);
764 			path = temp;
765 		} else
766 			path = srcpath(pkgloc, eptlist[i]->path, part, nparts);
767 		if (sflag) {
768 			if (slinkf(eptlist[i]->ainfo.local, path))
769 				quit(1);
770 		} else if (copyf(eptlist[i]->ainfo.local, path,
771 				eptlist[i]->cinfo.modtime)) {
772 			quit(1);
773 		}
774 
775 		/*
776 		 * If the package file attributes can be sync'd up with
777 		 * the pkgmap, we fix the attributes here.
778 		 */
779 		if (*(eptlist[i]->ainfo.owner) != '$' &&
780 		    *(eptlist[i]->ainfo.group) != '$') {
781 			/* Clear dangerous bits. */
782 			eptlist[i]->ainfo.mode=
783 			    (eptlist[i]->ainfo.mode & S_IAMB);
784 			/*
785 			 * Make sure it can be read by the world and written
786 			 * by the owner.
787 			 */
788 			eptlist[i]->ainfo.mode |= 0644;
789 			if (!strchr("in", eptlist[i]->ftype)) {
790 				/* Set the safe attributes. */
791 				averify(1, &(eptlist[i]->ftype),
792 				    path, &(eptlist[i]->ainfo));
793 			}
794 		}
795 
796 		(void) fprintf(stderr, "%s\n", path);
797 	}
798 }
799 
800 static void
801 ckmissing(char *path, char type)
802 {
803 	static char	**dir;
804 	static int	ndir;
805 	char	*pt;
806 	int	i, found;
807 
808 	if (dir == NULL) {
809 		dir = (char **)calloc(MALSIZ, sizeof (char *));
810 		if (dir == NULL) {
811 			progerr(gettext(ERR_MEMORY), errno);
812 			quit(99);
813 		}
814 	}
815 
816 	if (strchr("dx", type)) {
817 		dir[ndir] = path;
818 		if ((++ndir % MALSIZ) == 0) {
819 			dir = (char **)realloc((void *)dir,
820 				(ndir+MALSIZ)*sizeof (char *));
821 			if (dir == NULL) {
822 				progerr(gettext(ERR_MEMORY), errno);
823 				quit(99);
824 			}
825 		}
826 		dir[ndir] = (char *)NULL;
827 	}
828 
829 	pt = path;
830 	if (*pt == '/')
831 		pt++;
832 	while (pt = strchr(pt, '/')) {
833 		*pt = '\0';
834 		found = 0;
835 		for (i = 0; i < ndir; i++) {
836 			if (strcmp(path, dir[i]) == 0) {
837 				found++;
838 				break;
839 			}
840 		}
841 		if (!found) {
842 			logerr(gettext(WRN_MISSINGDIR), path);
843 			ckmissing(qstrdup(path), 'd');
844 		}
845 		*pt++ = '/';
846 	}
847 }
848 
849 static int
850 slinkf(char *from, char *to)
851 {
852 	char	*pt;
853 
854 	pt = to;
855 	while (pt = strchr(pt+1, '/')) {
856 		*pt = '\0';
857 		if (isdir(to) && mkdir(to, 0755)) {
858 			progerr(gettext(ERR_MKDIR), to);
859 			*pt = '/';
860 			return (-1);
861 		}
862 		*pt = '/';
863 	}
864 	if (symlink(from, to)) {
865 		progerr(gettext(ERR_SYMLINK), to);
866 		return (-1);
867 	}
868 	return (0);
869 }
870 
871 static void
872 usage(void)
873 {
874 	(void) fprintf(stderr, gettext(ERR_USAGE), get_prog_name());
875 	exit(1);
876 	/*NOTREACHED*/
877 }
878 
879 /*
880  * valid_zone_attr:	Validates the zone attributes specified in
881  *			pkginfo file for this package. The package
882  *			can not be created with certain combinations
883  *			of the attributes.
884  */
885 static boolean_t
886 valid_zone_attr(struct cfent **eptlist)
887 {
888 	FILE		*pkginfoFP;
889 	boolean_t	all_zones;	/* pkg is "all zones" only */
890 	boolean_t	is_hollow;	/* pkg is "hollow" */
891 	boolean_t	this_zone;	/* pkg is "this zone" only */
892 	char 		pkginfoPath[PATH_MAX];	/* pkginfo file path */
893 	char		*pkgInst;
894 	int i;
895 
896 	/* Path to pkginfo file within the package to be installed */
897 
898 	this_zone = B_FALSE;
899 	for (i = 0; eptlist[i]; i++) {
900 		if (eptlist[i]->ftype != 'i')
901 			continue;
902 		if (strcmp(eptlist[i]->path, "pkginfo") == 0)
903 			(void) strcpy(pkginfoPath, eptlist[i]->ainfo.local);
904 
905 		/*
906 		 * Check to see if this package has a request script. If this
907 		 * package does have a request script, then mark the package
908 		 * for installation in this zone only. Any package with a
909 		 * request script cannot be installed outside of the zone the
910 		 * pkgadd command is being run in, nor can such a package be
911 		 * installed as part of a new zone install. A new zone install
912 		 * must be non-interactive, which is required by all packages
913 		 * integrated into the Solaris WOS.
914 		 * If request file is set in prototype, then this_zone is TRUE.
915 		 */
916 		if (strcmp(eptlist[i]->path, "request") == 0)
917 			this_zone = B_TRUE;
918 	}
919 
920 	/* Gather information from the pkginfo file */
921 
922 	pkginfoFP = fopen(pkginfoPath, "r");
923 
924 	if (pkginfoFP == NULL) {
925 		progerr(ERR_NO_PKG_INFOFILE, pkginfoPath, strerror(errno));
926 		return (B_FALSE);
927 	}
928 
929 	if ((pkgInst = fpkgparam(pkginfoFP, "PKG")) == NULL) {
930 		progerr(gettext(ERR_NOPARAM), "PKG", pkginfoPath);
931 		return (B_FALSE);
932 	}
933 
934 
935 	/* Determine "HOLLOW" setting for this package */
936 	is_hollow = pkginfoParamTruth(pkginfoFP, PKG_HOLLOW_VARIABLE,
937 			"true", B_FALSE);
938 
939 	/* Determine "ALLZONES" setting for this package */
940 	all_zones = pkginfoParamTruth(pkginfoFP, PKG_ALLZONES_VARIABLE,
941 			"true", B_FALSE);
942 
943 	/* Determine "THISZONE" setting for this package, if no request file */
944 	if (!this_zone)
945 		this_zone = pkginfoParamTruth(pkginfoFP, PKG_THISZONE_VARIABLE,
946 			"true", B_FALSE);
947 
948 	/* Close pkginfo file */
949 	(void) fclose(pkginfoFP);
950 
951 	/*
952 	 * Validate zone attributes based on information gathered,
953 	 * and validate the three SUNW_PKG_ options:
954 	 *
955 	 * -----------------------------|---------------|
956 	 * <ALLZONES><HOLLOW><THISZONE> |  If Allowed   |
957 	 * ----1------------------------|---------------|
958 	 *		F F F		|	OK	|
959 	 *		F F T		|	OK	|
960 	 *		F T *		|	NO	|
961 	 * ----2------------------------|---------------|
962 	 *		T F F		|	OK	|
963 	 *		T T F		|	OK	|
964 	 *		T * T		|	NO	|
965 	 * -----------------------------|---------------|
966 	 */
967 
968 	/* pkg "all zones" && "this zone" (#2) */
969 
970 	if (all_zones && this_zone) {
971 		progerr(ERR_ALLZONES_AND_THISZONE, pkgInst,
972 		    PKG_ALLZONES_VARIABLE, PKG_THISZONE_VARIABLE);
973 		return (B_FALSE);
974 	}
975 
976 	/* pkg "!all zones" && "hollow" (#1) */
977 
978 	if ((!all_zones) && is_hollow) {
979 		progerr(ERR_NO_ALLZONES_AND_HOLLOW, pkgInst,
980 		    PKG_ALLZONES_VARIABLE, PKG_HOLLOW_VARIABLE);
981 		return (B_FALSE);
982 	}
983 
984 	return (B_TRUE);
985 }
986