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 2010 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
main(int argc,char * argv[])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 if ((pkgname = getenv("NAME")) == NULL) {
458 progerr(gettext(ERR_NOPARAM), "NAME", svept->path);
459 quit(1);
460 }
461 if (ckparam("NAME", pkgname))
462 quit(1);
463 if ((pkgvers = getenv("VERSION")) == NULL) {
464 /* XXX - I18n */
465 /* LINTED do not use cftime(); use strftime instead */
466 (void) cftime(buf, "\045m/\045d/\045Y", &clock);
467 (void) snprintf(temp, sizeof (temp),
468 gettext("Dev Release %s"), buf);
469 putparam("VERSION", temp);
470 pkgvers = getenv("VERSION");
471 logerr(gettext(WRN_SETPARAM), "VERSION", temp);
472 }
473 if (ckparam("VERSION", pkgvers))
474 quit(1);
475 if ((pkgarch = getenv("ARCH")) == NULL) {
476 (void) uname(&utsbuf);
477 putparam("ARCH", utsbuf.machine);
478 pkgarch = getenv("ARCH");
479 logerr(gettext(WRN_SETPARAM), "ARCH", utsbuf.machine);
480 }
481 if (ckparam("ARCH", pkgarch))
482 quit(1);
483 if (getenv("PSTAMP") == NULL) {
484 /* use octal value of '%' to fight sccs expansion */
485 /* XXX - I18n */
486 /* LINTED do not use cftime(); use strftime instead */
487 (void) cftime(buf, "\045Y\045m\045d\045H\045M\045S", &clock);
488 (void) uname(&utsbuf);
489 (void) snprintf(temp, sizeof (temp), "%s%s",
490 utsbuf.nodename, buf);
491 putparam("PSTAMP", temp);
492 logerr(gettext(WRN_SETPARAM), "PSTAMP", temp);
493 }
494 if ((pkgcat = getenv("CATEGORY")) == NULL) {
495 progerr(gettext(ERR_NOPARAM), "CATEGORY", svept->path);
496 quit(1);
497 }
498 if (ckparam("CATEGORY", pkgcat))
499 quit(1);
500
501 /*
502 * warn user of classes listed in package which do
503 * not appear in CLASSES variable in pkginfo file
504 */
505 objects = 0;
506 for (i = 0; eptlist[i]; i++) {
507 if (eptlist[i]->ftype != 'i') {
508 objects++;
509 addlist(&allclass, eptlist[i]->pkg_class);
510 }
511 }
512
513 if ((pt = getenv("CLASSES")) == NULL) {
514 if (allclass && *allclass) {
515 cl_setl(allclass);
516 cl_putl("CLASSES", allclass);
517 logerr(gettext(WRN_SETPARAM), "CLASSES",
518 getenv("CLASSES"));
519 }
520 } else {
521 cl_sets(qstrdup(pt));
522 if (allclass && *allclass) {
523 for (i = 0; allclass[i]; i++) {
524 found = 0;
525 if (cl_idx(allclass[i]->name) != -1) {
526 found++;
527 break;
528 }
529 if (!found) {
530 logerr(gettext(WRN_CLASSES),
531 (char *)allclass[i]);
532 }
533 }
534 }
535 }
536
537 (void) fprintf(stderr, gettext(MSG_VOLUMIZE), objects);
538 order = (struct cl_attr **)0;
539 if (pt = getenv("ORDER")) {
540 pt = qstrdup(pt);
541 (void) setlist(&order, pt);
542 cl_putl("ORDER", order);
543 }
544
545 /* stat the intended output filesystem to get blocking information */
546 if (pkgdev.dirname == NULL) {
547 progerr(gettext(ERR_WHATVFS), device);
548 quit(99);
549 }
550 if (statvfs64(pkgdev.dirname, &svfsb)) {
551 progerr(gettext(ERR_STATVFS), pkgdev.dirname);
552 quit(99);
553 }
554
555 if (bsize == 0) {
556 bsize = svfsb.f_bsize;
557 }
558 if (frsize == 0) {
559 frsize = svfsb.f_frsize;
560 }
561
562 if (limit == 0)
563 /*
564 * bavail is in terms of fragment size blocks - change
565 * to 512 byte blocks
566 */
567 limit = (fsblkcnt_t)(((fsblkcnt_t)frsize > 0) ?
568 howmany(frsize, DEV_BSIZE) :
569 howmany(bsize, DEV_BSIZE)) * svfsb.f_bavail;
570
571 if (ilimit == 0) {
572 ilimit = (svfsb.f_favail > 0) ?
573 svfsb.f_favail : svfsb.f_ffree;
574 }
575
576 nparts = splpkgmap(eptlist, eptnum, (char **)order, bsize, frsize,
577 &limit, &ilimit, &llimit);
578
579 if (nparts <= 0) {
580 progerr(gettext(ERR_SPLIT));
581 quit(1);
582 }
583
584 if (nflag) {
585 for (i = 0; eptlist[i]; i++)
586 (void) ppkgmap(eptlist[i], stdout);
587 exit(0);
588 /*NOTREACHED*/
589 }
590
591 (void) snprintf(pkgloc, sizeof (pkgloc), "%s/%s",
592 pkgdev.dirname, pkginst);
593 if (!isdir(pkgloc) && !overwrite) {
594 progerr(gettext(ERR_OVERWRITE), pkgloc);
595 quit(1);
596 }
597
598 /* output all environment install parameters */
599 t_pkginfo = tempnam(tmpdir, "pkginfo");
600 if ((fp = fopen(t_pkginfo, "w")) == NULL) {
601 progerr(gettext(ERR_TEMP), errno);
602 exit(99);
603 }
604 for (i = 0; environ[i]; i++) {
605 if (isupper(*environ[i])) {
606 (void) fputs(environ[i], fp);
607 (void) fputc('\n', fp);
608 }
609 }
610 (void) fclose(fp);
611
612 started++;
613 (void) rrmdir(pkgloc);
614 if (mkdir(pkgloc, 0755)) {
615 progerr(gettext(ERR_MKDIR), pkgloc);
616 quit(1);
617 }
618
619 /* determine how many packages already reside on the medium */
620 pkgdir = pkgdev.dirname;
621 npkgs = 0;
622 while (pt = fpkginst("all", NULL, NULL))
623 npkgs++;
624 (void) fpkginst(NULL); /* free resource usage */
625
626 if (nparts > 1) {
627 if (pkgdev.mount && npkgs) {
628 progerr(gettext(ERR_ONEVOL));
629 quit(1);
630 }
631 }
632
633 /*
634 * update pkgmap entry for pkginfo file, since it may
635 * have changed due to command line or failure to
636 * specify all neccessary parameters
637 */
638 for (i = 0; eptlist[i]; i++) {
639 if (eptlist[i]->ftype != 'i')
640 continue;
641 if (strcmp(eptlist[i]->path, "pkginfo") == 0) {
642 svept = eptlist[i];
643 svept->ftype = '?';
644 svept->ainfo.local = t_pkginfo;
645 (void) cverify(0, &svept->ftype, t_pkginfo,
646 &svept->cinfo, 1);
647 svept->ftype = 'i';
648 break;
649 }
650 }
651
652 if (nparts > 1)
653 (void) fprintf(stderr, gettext(MSG_PACKAGEM), nparts);
654 else
655 (void) fprintf(stderr, gettext(MSG_PACKAGE1));
656
657 for (part = 1; part <= nparts; part++) {
658 if ((part > 1) && pkgdev.mount) {
659 if (pkgumount(&pkgdev)) {
660 progerr(gettext(ERR_UMOUNT), pkgdev.mount);
661 quit(99);
662 }
663 if (n = pkgmount(&pkgdev, NULL, part, nparts, 1))
664 quit(n);
665 (void) rrmdir(pkgloc);
666 if (mkdir(pkgloc, 0555)) {
667 progerr(gettext(ERR_MKDIR), pkgloc);
668 quit(99);
669 }
670 }
671 outvol(eptlist, eptnum, part, nparts);
672
673 /* Validate (as much as possible) the control scripts. */
674 if (part == 1) {
675 char inst_path[PATH_MAX];
676
677 (void) fprintf(stderr, gettext(MSG_VALSCRIPTS));
678 (void) snprintf(inst_path, sizeof (inst_path),
679 "%s/install", pkgloc);
680 checkscripts(inst_path, 0);
681 }
682 }
683
684 quit(0);
685 /* LINTED: no return */
686 }
687
688 static void
trap(int n)689 trap(int n)
690 {
691 (void) signal(SIGINT, SIG_IGN);
692 (void) signal(SIGHUP, SIG_IGN);
693
694 if (n == SIGINT)
695 quit(3);
696 else {
697 (void) fprintf(stderr, gettext("%s terminated (signal %d).\n"),
698 get_prog_name(), n);
699 quit(99);
700 }
701 }
702
703 static void
outvol(struct cfent ** eptlist,unsigned int eptnum,int part,int nparts)704 outvol(struct cfent **eptlist, unsigned int eptnum, int part, int nparts)
705 {
706 FILE *fp;
707 char *svpt, *path, temp[PATH_MAX];
708 unsigned int i;
709
710
711 if (nparts > 1)
712 (void) fprintf(stderr, gettext(" -- part %2d:\n"), part);
713 if (part == 1) {
714 /* re-write pkgmap, but exclude local pathnames */
715 (void) snprintf(temp, sizeof (temp), "%s/pkgmap", pkgloc);
716 if ((fp = fopen(temp, "w")) == NULL) {
717 progerr(gettext(ERR_TEMP), errno);
718 quit(99);
719 }
720 (void) fprintf(fp, ": %d %llu\n", nparts, limit);
721 for (i = 0; eptlist[i]; i++) {
722 svpt = eptlist[i]->ainfo.local;
723 if (!strchr("sl", eptlist[i]->ftype))
724 eptlist[i]->ainfo.local = NULL;
725 if (ppkgmap(eptlist[i], fp)) {
726 progerr(gettext(ERR_TEMP), errno);
727 quit(99);
728 }
729 eptlist[i]->ainfo.local = svpt;
730 }
731 (void) fclose(fp);
732 (void) fprintf(stderr, "%s\n", temp);
733 }
734
735 (void) snprintf(temp, sizeof (temp), "%s/pkginfo", pkgloc);
736 if (copyf(svept->ainfo.local, temp, svept->cinfo.modtime))
737 quit(1);
738 (void) fprintf(stderr, "%s\n", temp);
739
740 for (i = 0; i < eptnum; i++) {
741 if (eptlist[i]->volno != part)
742 continue;
743 if (strchr("dxslcbp", eptlist[i]->ftype))
744 continue;
745 if (eptlist[i]->ftype == 'i') {
746 if (eptlist[i] == svept)
747 continue; /* don't copy pkginfo file */
748 (void) snprintf(temp, sizeof (temp),
749 "%s/install/%s", pkgloc,
750 eptlist[i]->path);
751 path = temp;
752 } else
753 path = srcpath(pkgloc, eptlist[i]->path, part, nparts);
754 if (sflag) {
755 if (slinkf(eptlist[i]->ainfo.local, path))
756 quit(1);
757 } else if (copyf(eptlist[i]->ainfo.local, path,
758 eptlist[i]->cinfo.modtime)) {
759 quit(1);
760 }
761
762 /*
763 * If the package file attributes can be sync'd up with
764 * the pkgmap, we fix the attributes here.
765 */
766 if (*(eptlist[i]->ainfo.owner) != '$' &&
767 *(eptlist[i]->ainfo.group) != '$') {
768 /* Clear dangerous bits. */
769 eptlist[i]->ainfo.mode=
770 (eptlist[i]->ainfo.mode & S_IAMB);
771 /*
772 * Make sure it can be read by the world and written
773 * by the owner.
774 */
775 eptlist[i]->ainfo.mode |= 0644;
776 if (!strchr("in", eptlist[i]->ftype)) {
777 /* Set the safe attributes. */
778 averify(1, &(eptlist[i]->ftype),
779 path, &(eptlist[i]->ainfo));
780 }
781 }
782
783 (void) fprintf(stderr, "%s\n", path);
784 }
785 }
786
787 static void
ckmissing(char * path,char type)788 ckmissing(char *path, char type)
789 {
790 static char **dir;
791 static int ndir;
792 char *pt;
793 int i, found;
794
795 if (dir == NULL) {
796 dir = (char **)calloc(MALSIZ, sizeof (char *));
797 if (dir == NULL) {
798 progerr(gettext(ERR_MEMORY), errno);
799 quit(99);
800 }
801 }
802
803 if (strchr("dx", type)) {
804 dir[ndir] = path;
805 if ((++ndir % MALSIZ) == 0) {
806 dir = (char **)realloc((void *)dir,
807 (ndir+MALSIZ)*sizeof (char *));
808 if (dir == NULL) {
809 progerr(gettext(ERR_MEMORY), errno);
810 quit(99);
811 }
812 }
813 dir[ndir] = (char *)NULL;
814 }
815
816 pt = path;
817 if (*pt == '/')
818 pt++;
819 while (pt = strchr(pt, '/')) {
820 *pt = '\0';
821 found = 0;
822 for (i = 0; i < ndir; i++) {
823 if (strcmp(path, dir[i]) == 0) {
824 found++;
825 break;
826 }
827 }
828 if (!found) {
829 logerr(gettext(WRN_MISSINGDIR), path);
830 ckmissing(qstrdup(path), 'd');
831 }
832 *pt++ = '/';
833 }
834 }
835
836 static int
slinkf(char * from,char * to)837 slinkf(char *from, char *to)
838 {
839 char *pt;
840
841 pt = to;
842 while (pt = strchr(pt+1, '/')) {
843 *pt = '\0';
844 if (isdir(to) && mkdir(to, 0755)) {
845 progerr(gettext(ERR_MKDIR), to);
846 *pt = '/';
847 return (-1);
848 }
849 *pt = '/';
850 }
851 if (symlink(from, to)) {
852 progerr(gettext(ERR_SYMLINK), to);
853 return (-1);
854 }
855 return (0);
856 }
857
858 static void
usage(void)859 usage(void)
860 {
861 (void) fprintf(stderr, gettext(ERR_USAGE), get_prog_name());
862 exit(1);
863 /*NOTREACHED*/
864 }
865
866 /*
867 * valid_zone_attr: Validates the zone attributes specified in
868 * pkginfo file for this package. The package
869 * can not be created with certain combinations
870 * of the attributes.
871 */
872 static boolean_t
valid_zone_attr(struct cfent ** eptlist)873 valid_zone_attr(struct cfent **eptlist)
874 {
875 FILE *pkginfoFP;
876 boolean_t all_zones; /* pkg is "all zones" only */
877 boolean_t is_hollow; /* pkg is "hollow" */
878 boolean_t this_zone; /* pkg is "this zone" only */
879 char pkginfoPath[PATH_MAX]; /* pkginfo file path */
880 char *pkgInst;
881 int i;
882
883 /* Path to pkginfo file within the package to be installed */
884
885 this_zone = B_FALSE;
886 for (i = 0; eptlist[i]; i++) {
887 if (eptlist[i]->ftype != 'i')
888 continue;
889 if (strcmp(eptlist[i]->path, "pkginfo") == 0)
890 (void) strcpy(pkginfoPath, eptlist[i]->ainfo.local);
891
892 /*
893 * Check to see if this package has a request script. If this
894 * package does have a request script, then mark the package
895 * for installation in this zone only. Any package with a
896 * request script cannot be installed outside of the zone the
897 * pkgadd command is being run in, nor can such a package be
898 * installed as part of a new zone install. A new zone install
899 * must be non-interactive, which is required by all packages
900 * integrated into the Solaris WOS.
901 * If request file is set in prototype, then this_zone is TRUE.
902 */
903 if (strcmp(eptlist[i]->path, "request") == 0)
904 this_zone = B_TRUE;
905 }
906
907 /* Gather information from the pkginfo file */
908
909 pkginfoFP = fopen(pkginfoPath, "r");
910
911 if (pkginfoFP == NULL) {
912 progerr(ERR_NO_PKG_INFOFILE, pkginfoPath, strerror(errno));
913 return (B_FALSE);
914 }
915
916 if ((pkgInst = fpkgparam(pkginfoFP, "PKG")) == NULL) {
917 progerr(gettext(ERR_NOPARAM), "PKG", pkginfoPath);
918 return (B_FALSE);
919 }
920
921
922 /* Determine "HOLLOW" setting for this package */
923 is_hollow = pkginfoParamTruth(pkginfoFP, PKG_HOLLOW_VARIABLE,
924 "true", B_FALSE);
925
926 /* Determine "ALLZONES" setting for this package */
927 all_zones = pkginfoParamTruth(pkginfoFP, PKG_ALLZONES_VARIABLE,
928 "true", B_FALSE);
929
930 /* Determine "THISZONE" setting for this package, if no request file */
931 if (!this_zone)
932 this_zone = pkginfoParamTruth(pkginfoFP, PKG_THISZONE_VARIABLE,
933 "true", B_FALSE);
934
935 /* Close pkginfo file */
936 (void) fclose(pkginfoFP);
937
938 /*
939 * Validate zone attributes based on information gathered,
940 * and validate the three SUNW_PKG_ options:
941 *
942 * -----------------------------|---------------|
943 * <ALLZONES><HOLLOW><THISZONE> | If Allowed |
944 * ----1------------------------|---------------|
945 * F F F | OK |
946 * F F T | OK |
947 * F T * | NO |
948 * ----2------------------------|---------------|
949 * T F F | OK |
950 * T T F | OK |
951 * T * T | NO |
952 * -----------------------------|---------------|
953 */
954
955 /* pkg "all zones" && "this zone" (#2) */
956
957 if (all_zones && this_zone) {
958 progerr(ERR_ALLZONES_AND_THISZONE, pkgInst,
959 PKG_ALLZONES_VARIABLE, PKG_THISZONE_VARIABLE);
960 return (B_FALSE);
961 }
962
963 /* pkg "!all zones" && "hollow" (#1) */
964
965 if ((!all_zones) && is_hollow) {
966 progerr(ERR_NO_ALLZONES_AND_HOLLOW, pkgInst,
967 PKG_ALLZONES_VARIABLE, PKG_HOLLOW_VARIABLE);
968 return (B_FALSE);
969 }
970
971 return (B_TRUE);
972 }
973