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