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 2007 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 <stdlib.h> 34 #include <unistd.h> 35 #include <dirent.h> 36 #include <locale.h> 37 #include <libintl.h> 38 #include <errno.h> 39 #include "pkglib.h" 40 #include "install.h" 41 #include "libadm.h" 42 #include "libinst.h" 43 #include "pkginstall.h" 44 #include "messages.h" 45 46 extern char instdir[], pkgbin[], pkgloc[], savlog[], *pkginst, **environ; 47 extern char saveSpoolInstallDir[]; 48 extern char pkgsav[]; /* pkginstall/main.c */ 49 static char *infoloc; 50 51 /* 52 * flag definitions for each entry in table 53 */ 54 55 typedef unsigned int TBL_FLAG_T; 56 57 /* no flag set */ 58 #define FLAG_NONE ((TBL_FLAG_T)0x0000) 59 60 /* exclude this attribute if found */ 61 #define FLAG_EXCLUDE ((TBL_FLAG_T)0x0001) 62 63 /* this attribute must not change if found */ 64 #define FLAG_IDENTICAL ((TBL_FLAG_T)0x0002) 65 66 /* 67 * macro to generate an entry in the table: 68 * TBL_ENTRY("PKGINFO_ATTRIBUTE=", FLAG_XXX) 69 * where: 70 * "PKGINFO_ATTRIBUTE=" is the attribute to look for 71 * FLAG_XXX is the action to perform when the attribute is found 72 */ 73 74 #define TBL_ENTRY(_Y_, _F_) { (_Y_), ((sizeof ((_Y_)))-1), (_F_) } 75 76 /* 77 * table containing attributes that require special handling 78 */ 79 80 struct _namelist { 81 char *_nlName; /* attribute name */ 82 int _nlLen; /* attribute length */ 83 TBL_FLAG_T _nlFlag; /* attribute disposition flag */ 84 }; 85 86 typedef struct _namelist NAMELIST_T; 87 88 /* 89 * These are attributes to be acted on in some way when a pkginfo file is 90 * merged. This table MUST be in alphabetical order because it is searched 91 * using a binary search algorithm. 92 */ 93 94 static NAMELIST_T attrTbl[] = { 95 TBL_ENTRY("BASEDIR=", FLAG_EXCLUDE), 96 TBL_ENTRY("CLASSES=", FLAG_EXCLUDE), 97 TBL_ENTRY("CLIENT_BASEDIR=", FLAG_EXCLUDE), 98 TBL_ENTRY("INST_DATADIR=", FLAG_EXCLUDE), 99 TBL_ENTRY("PKG_CAS_PASSRELATIVE=", FLAG_EXCLUDE), 100 TBL_ENTRY("PKG_DST_QKVERIFY=", FLAG_EXCLUDE), 101 TBL_ENTRY("PKG_INIT_INSTALL=", FLAG_EXCLUDE), 102 TBL_ENTRY("PKG_INSTALL_ROOT=", FLAG_EXCLUDE), 103 TBL_ENTRY("PKG_SRC_NOVERIFY=", FLAG_EXCLUDE), 104 TBL_ENTRY("SUNW_PKGCOND_GLOBAL_DATA=", FLAG_EXCLUDE), 105 TBL_ENTRY("SUNW_PKG_ALLZONES=", FLAG_IDENTICAL), 106 TBL_ENTRY("SUNW_PKG_DIR=", FLAG_EXCLUDE), 107 TBL_ENTRY("SUNW_PKG_HOLLOW=", FLAG_IDENTICAL), 108 TBL_ENTRY("SUNW_PKG_INSTALL_ZONENAME=", FLAG_EXCLUDE), 109 TBL_ENTRY("SUNW_PKG_THISZONE=", FLAG_IDENTICAL), 110 }; 111 112 #define ATTRTBL_SIZE (sizeof (attrTbl) / sizeof (NAMELIST_T)) 113 114 /* 115 * While pkgsav has to be set up with reference to the server for package 116 * scripts, it has to be client-relative in the pkginfo file. This function 117 * is used to set the client-relative value for use in the pkginfo file. 118 */ 119 void 120 set_infoloc(char *path) 121 { 122 if (path && *path) { 123 if (is_an_inst_root()) { 124 /* Strip the server portion of the path. */ 125 infoloc = orig_path(path); 126 } else { 127 infoloc = strdup(path); 128 } 129 } 130 } 131 132 void 133 merginfo(struct cl_attr **pclass, int install_from_pspool) 134 { 135 DIR *pdirfp; 136 FILE *fp; 137 FILE *pkginfoFP; 138 char path[PATH_MAX]; 139 char cmd[PATH_MAX]; 140 char pkginfoPath[PATH_MAX]; 141 char temp[PATH_MAX]; 142 int i; 143 int nc; 144 int out; 145 146 /* remove savelog from previous attempts */ 147 148 (void) unlink(savlog); 149 150 /* 151 * create path to appropriate pkginfo file for the package that is 152 * already installed - is_spool_create() will be set (!= 0) if the 153 * -t option is presented to pkginstall - the -t option is used to 154 * disable save spool area creation; do not spool any partial package 155 * contents, that is, suppress the creation and population of the 156 * package save spool area (var/sadm/pkg/PKG/save/pspool/PKG). This 157 * option is set only when a non-global zone is being created. 158 */ 159 160 if (is_spool_create() == 0) { 161 /* 162 * normal package install (not a non-global zone install); 163 * use the standard installed pkginfo file for this package: 164 * --> /var/sadm/pkg/PKGINST/pkginfo 165 * as the source pkginfo file to scan. 166 */ 167 i = snprintf(pkginfoPath, sizeof (pkginfoPath), 168 "%s/var/sadm/pkg/%s/%s", 169 ((get_inst_root()) && 170 (strcmp(get_inst_root(), "/") != 0)) ? 171 get_inst_root() : "", pkginst, 172 PKGINFO); 173 if (i > sizeof (pkginfoPath)) { 174 progerr(ERR_CREATE_PATH_2, 175 ((get_inst_root()) && 176 (strcmp(get_inst_root(), "/") != 0)) ? 177 get_inst_root() : "/", 178 pkginst); 179 quit(1); 180 } 181 } else { 182 /* 183 * non-global zone installation - use the "saved" pspool 184 * pkginfo file in the global zone for this package: 185 * --> /var/sadm/install/PKG/save/pspool/PKG/pkginfo 186 * as the source pkginfo file to scan. 187 */ 188 i = snprintf(pkginfoPath, sizeof (pkginfoPath), "%s/%s", 189 saveSpoolInstallDir, PKGINFO); 190 if (i > sizeof (pkginfoPath)) { 191 progerr(ERR_CREATE_PATH_2, 192 saveSpoolInstallDir, PKGINFO); 193 quit(1); 194 } 195 } 196 197 i = snprintf(path, PATH_MAX, "%s/%s", pkgloc, PKGINFO); 198 if (i > PATH_MAX) { 199 progerr(ERR_CREATE_PATH_2, pkgloc, PKGINFO); 200 quit(1); 201 } 202 203 /* entry debugging info */ 204 205 echoDebug(DBG_MERGINFO_ENTRY, 206 instdir ? instdir : "??", 207 ((get_inst_root()) && 208 (strcmp(get_inst_root(), "/") != 0)) ? 209 get_inst_root() : "??", 210 saveSpoolInstallDir ? saveSpoolInstallDir : "??", 211 pkgloc ? pkgloc : "??", is_spool_create(), 212 get_info_basedir() ? get_info_basedir() : "??", 213 pkginfoPath, path); 214 215 /* 216 * open the pkginfo file: 217 * if the source pkginfo file to check is the same as the merged one 218 * (e.g. /var/sadm/pkg/PKGINST/pkginfo) then do not open the source 219 * pkginfo file to "verify" 220 */ 221 222 if (strcmp(pkginfoPath, path) == 0) { 223 pkginfoFP = (FILE *)NULL; 224 echoDebug(DBG_MERGINFO_SAME, path); 225 } else { 226 echoDebug(DBG_MERGINFO_DIFFERENT, pkginfoPath, path); 227 pkginfoFP = fopen(pkginfoPath, "r"); 228 229 if (pkginfoFP == (FILE *)NULL) { 230 echoDebug(ERR_NO_PKG_INFOFILE, pkginst, pkginfoPath, 231 strerror(errno)); 232 } 233 } 234 235 /* 236 * output packaging environment to create a pkginfo file in pkgloc[] 237 */ 238 239 if ((fp = fopen(path, "w")) == NULL) { 240 progerr(ERR_CANNOT_OPEN_FOR_WRITING, path, strerror(errno)); 241 quit(99); 242 } 243 244 /* 245 * output CLASSES attribute 246 */ 247 248 out = 0; 249 (void) fputs("CLASSES=", fp); 250 if (pclass) { 251 (void) fputs(pclass[0]->name, fp); 252 out++; 253 for (i = 1; pclass[i]; i++) { 254 (void) putc(' ', fp); 255 (void) fputs(pclass[i]->name, fp); 256 out++; 257 } 258 } 259 nc = cl_getn(); 260 for (i = 0; i < nc; i++) { 261 int found = 0; 262 263 if (pclass) { 264 int j; 265 266 for (j = 0; pclass[j]; ++j) { 267 if (cl_nam(i) != NULL && 268 strcmp(cl_nam(i), 269 pclass[j]->name) == 0) { 270 found++; 271 break; 272 } 273 } 274 } 275 if (!found) { 276 if (out > 0) { 277 (void) putc(' ', fp); 278 } 279 (void) fputs(cl_nam(i), fp); 280 out++; 281 } 282 } 283 (void) putc('\n', fp); 284 285 /* 286 * NOTE : BASEDIR below is relative to the machine that 287 * *runs* the package. If there's an install root, this 288 * is actually the CLIENT_BASEDIR wrt the machine 289 * doing the pkgadd'ing here. -- JST 290 */ 291 292 if (is_a_basedir()) { 293 static char *txs1 = "BASEDIR="; 294 295 (void) fputs(txs1, fp); 296 (void) fputs(get_info_basedir(), fp); 297 (void) putc('\n', fp); 298 } else { 299 (void) fputs("BASEDIR=/", fp); 300 (void) putc('\n', fp); 301 } 302 303 /* 304 * output all other environment attributes except those which 305 * are relevant only to install. 306 */ 307 308 for (i = 0; environ[i] != (char *)NULL; i++) { 309 char *ep = environ[i]; 310 int attrPos = -1; 311 int incr = (ATTRTBL_SIZE >> 1)+1; /* searches possible */ 312 int pos = ATTRTBL_SIZE >> 1; /* start in middle */ 313 NAMELIST_T *pp = (NAMELIST_T *)NULL; 314 315 /* 316 * find this attribute in the table - accept the attribute if it 317 * is outside of the bounds of the table; otherwise, do a binary 318 * search looking for this attribute. 319 */ 320 321 if (strncmp(ep, attrTbl[0]._nlName, attrTbl[0]._nlLen) < 0) { 322 323 /* entry < first entry in attribute table */ 324 325 echoDebug(DBG_MERGINFO_LESS_THAN, ep, 326 attrTbl[0]._nlName); 327 328 } else if (strncmp(ep, attrTbl[ATTRTBL_SIZE-1]._nlName, 329 attrTbl[ATTRTBL_SIZE-1]._nlLen) > 0) { 330 331 /* entry > last entry in attribute table */ 332 333 echoDebug(DBG_MERGINFO_GREATER_THAN, ep, 334 attrTbl[ATTRTBL_SIZE-1]._nlName); 335 336 } else { 337 /* first entry < entry < last entry in table: search */ 338 339 echoDebug(DBG_MERGINFO_SEARCHING, ep, 340 attrTbl[0]._nlName, 341 attrTbl[ATTRTBL_SIZE-1]._nlName); 342 343 while (incr > 0) { /* while possible to divide */ 344 int r; 345 346 pp = &attrTbl[pos]; 347 348 /* compare current attr with this table entry */ 349 r = strncmp(pp->_nlName, ep, pp->_nlLen); 350 351 /* break out of loop if match */ 352 if (r == 0) { 353 /* save location/break if match found */ 354 attrPos = pos; 355 break; 356 } 357 358 /* no match search to next/prev half */ 359 incr = incr >> 1; 360 pos += (r < 0) ? incr : -incr; 361 continue; 362 } 363 } 364 365 /* handle excluded attribute found */ 366 367 if ((attrPos >= 0) && (pp->_nlFlag == FLAG_EXCLUDE)) { 368 /* attribute is excluded */ 369 echoDebug(DBG_MERGINFO_EXCLUDING, ep); 370 continue; 371 } 372 373 /* handle fixed attribute found */ 374 375 if ((pkginfoFP != (FILE *)NULL) && (attrPos >= 0) && 376 (pp->_nlFlag == FLAG_IDENTICAL)) { 377 /* attribute must not change */ 378 379 char *src = ep+pp->_nlLen; 380 char *trg; 381 char theAttr[PATH_MAX+1]; 382 383 /* isolate attribute name only without '=' at end */ 384 385 (void) strncpy(theAttr, pp->_nlName, pp->_nlLen-1); 386 theAttr[pp->_nlLen-1] = '\0'; 387 388 /* lookup attribute in installed package pkginfo file */ 389 390 rewind(pkginfoFP); 391 trg = fpkgparam(pkginfoFP, theAttr); 392 393 echoDebug(DBG_MERGINFO_ATTRCOMP, theAttr, 394 trg ? trg : ""); 395 396 /* if target not found attribute is being added */ 397 398 if (trg == (char *)NULL) { 399 progerr(ERR_PKGINFO_ATTR_ADDED, pkginst, ep); 400 quit(1); 401 } 402 403 /* error if two values are not the same */ 404 405 if (strcmp(src, trg) != 0) { 406 progerr(ERR_PKGINFO_ATTR_CHANGED, pkginst, 407 theAttr, src, trg); 408 quit(1); 409 } 410 } 411 412 /* attribute not excluded/has not changed - process */ 413 414 if ((strncmp(ep, "PKGSAV=", 7) == 0)) { 415 (void) fputs("PKGSAV=", fp); 416 (void) fputs(infoloc, fp); 417 (void) putc('/', fp); 418 (void) fputs(pkginst, fp); 419 (void) fputs("/save\n", fp); 420 continue; 421 } 422 423 if ((strncmp(ep, "UPDATE=", 7) == 0) && 424 install_from_pspool != 0 && 425 !isPatchUpdate() && 426 !isUpdate()) { 427 continue; 428 } 429 430 echoDebug(DBG_MERGINFO_FINAL, ep); 431 432 (void) fputs(ep, fp); 433 (void) putc('\n', fp); 434 } 435 436 (void) fclose(fp); 437 (void) fclose(pkginfoFP); 438 439 /* 440 * copy all packaging scripts to appropriate directory 441 */ 442 443 i = snprintf(path, PATH_MAX, "%s/install", instdir); 444 if (i > PATH_MAX) { 445 progerr(ERR_CREATE_PATH_2, instdir, "/install"); 446 quit(1); 447 } 448 449 if ((pdirfp = opendir(path)) != NULL) { 450 struct dirent *dp; 451 452 while ((dp = readdir(pdirfp)) != NULL) { 453 if (dp->d_name[0] == '.') 454 continue; 455 456 i = snprintf(path, PATH_MAX, "%s/install/%s", 457 instdir, dp->d_name); 458 if (i > PATH_MAX) { 459 progerr(ERR_CREATE_PATH_3, instdir, "/install/", 460 dp->d_name); 461 quit(1); 462 } 463 464 i = snprintf(temp, PATH_MAX, "%s/%s", pkgbin, 465 dp->d_name); 466 if (i > PATH_MAX) { 467 progerr(ERR_CREATE_PATH_2, pkgbin, dp->d_name); 468 quit(1); 469 } 470 471 if (cppath(MODE_SRC|DIR_DISPLAY, path, temp, 0644)) { 472 progerr(ERR_CANNOT_COPY, dp->d_name, pkgbin); 473 quit(99); 474 } 475 } 476 (void) closedir(pdirfp); 477 } 478 479 /* 480 * copy all packaging scripts to the partial spool directory 481 */ 482 483 if (!is_spool_create()) { 484 /* packages are being spooled to ../save/pspool/.. */ 485 i = snprintf(path, PATH_MAX, "%s/install", instdir); 486 if (i > PATH_MAX) { 487 progerr(ERR_CREATE_PATH_2, instdir, "/install"); 488 quit(1); 489 } 490 491 if (((pdirfp = opendir(path)) != NULL) && 492 !isPatchUpdate()) { 493 struct dirent *dp; 494 495 496 while ((dp = readdir(pdirfp)) != NULL) { 497 if (dp->d_name[0] == '.') 498 continue; 499 /* 500 * Don't copy i.none since if it exists it 501 * contains Class Archive Format procedure 502 * for installing archives. Only Directory 503 * Format packages can exist 504 * in a global spooled area. 505 */ 506 if (strcmp(dp->d_name, "i.none") == 0) 507 continue; 508 509 i = snprintf(path, PATH_MAX, "%s/install/%s", 510 instdir, dp->d_name); 511 512 if (i > PATH_MAX) { 513 progerr(ERR_CREATE_PATH_3, instdir, 514 "/install/", dp->d_name); 515 quit(1); 516 } 517 518 i = snprintf(temp, PATH_MAX, "%s/install/%s", 519 saveSpoolInstallDir, 520 dp->d_name); 521 522 if (i > PATH_MAX) { 523 progerr(ERR_CREATE_PATH_3, 524 saveSpoolInstallDir, 525 "/install/", dp->d_name); 526 quit(1); 527 } 528 529 if (cppath(MODE_SRC, path, temp, 0644)) { 530 progerr(ERR_CANNOT_COPY, path, temp); 531 (void) closedir(pdirfp); 532 quit(99); 533 } 534 } 535 (void) closedir(pdirfp); 536 } 537 538 /* 539 * Now copy the original pkginfo and pkgmap files from the 540 * installing package to the spooled directory. 541 */ 542 543 i = snprintf(path, sizeof (path), "%s/%s", instdir, PKGINFO); 544 if (i > sizeof (path)) { 545 progerr(ERR_CREATE_PATH_2, instdir, PKGINFO); 546 quit(1); 547 } 548 549 i = snprintf(temp, sizeof (temp), "%s/%s", 550 saveSpoolInstallDir, PKGINFO); 551 if (i > sizeof (temp)) { 552 progerr(ERR_CREATE_PATH_2, saveSpoolInstallDir, 553 PKGINFO); 554 quit(1); 555 } 556 557 if (cppath(MODE_SRC, path, temp, 0644)) { 558 progerr(ERR_CANNOT_COPY, path, temp); 559 quit(99); 560 } 561 562 /* 563 * Only want to copy the FCS pkgmap if this is not a 564 * patch installation. 565 */ 566 567 if (!isPatchUpdate()) { 568 i = snprintf(path, sizeof (path), "%s/pkgmap", instdir); 569 if (i > sizeof (path)) { 570 progerr(ERR_CREATE_PATH_2, instdir, "pkgmap"); 571 quit(1); 572 } 573 574 i = snprintf(temp, sizeof (temp), "%s/pkgmap", 575 saveSpoolInstallDir); 576 if (i > sizeof (path)) { 577 progerr(ERR_CREATE_PATH_2, saveSpoolInstallDir, 578 "pkgmap"); 579 quit(1); 580 } 581 582 if (cppath(MODE_SRC, path, temp, 0644)) { 583 progerr(ERR_CANNOT_COPY, path, temp); 584 quit(99); 585 } 586 } 587 } 588 589 /* 590 * If we are installing from a spool directory 591 * copy the save directory from it, it may have 592 * been patched. Duplicate it only if this 593 * installation isn't an update and is not to 594 * an alternate root. 595 */ 596 if (strstr(instdir, "pspool") != NULL) { 597 struct stat status; 598 599 i = snprintf(path, sizeof (path), "%s/save", instdir); 600 if (i > sizeof (path)) { 601 progerr(ERR_CREATE_PATH_2, instdir, "save"); 602 quit(1); 603 } 604 605 if ((stat(path, &status) == 0) && 606 (status.st_mode & S_IFDIR) && 607 !isPatchUpdate()) { 608 i = snprintf(cmd, sizeof (cmd), "cp -pr %s/* %s", 609 path, pkgsav); 610 if (i > sizeof (cmd)) { 611 progerr(ERR_SNPRINTF, "cp -pr %s/* %s"); 612 quit(1); 613 } 614 615 if (system(cmd)) { 616 progerr(ERR_PKGBINCP, path, pkgsav); 617 quit(99); 618 } 619 } 620 } 621 } 622