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 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 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 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 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 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 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 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