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 28 #include <stdio.h> 29 #include <limits.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 #include <string.h> 33 #include <fcntl.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <signal.h> 37 #include <errno.h> 38 #include <assert.h> 39 #include <pkgdev.h> 40 #include <pkginfo.h> 41 #include <pkglocs.h> 42 #include <locale.h> 43 #include <libintl.h> 44 #include <instzones_api.h> 45 #include <pkglib.h> 46 #include <install.h> 47 #include <libinst.h> 48 #include <libadm.h> 49 #include <messages.h> 50 51 /* commands to execute */ 52 53 #define PKGINFO_CMD "/usr/bin/pkginfo" 54 55 #define GLOBALZONE_ONLY_PACKAGE_FILE_PATH \ 56 "/var/sadm/install/gz-only-packages" 57 58 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 59 #define TEXT_DOMAIN "SYS_TEST" 60 #endif 61 62 /* 63 * forward declarations 64 */ 65 66 static void _pkginfoInit(struct pkginfo *a_info); 67 static struct pkginfo *_pkginfoFactory(void); 68 static char **thisZonePackages; 69 static int numThisZonePackages; 70 71 /* 72 * ***************************************************************************** 73 * global external (public) functions 74 * ***************************************************************************** 75 */ 76 77 /* 78 * Name: pkginfoFree 79 * Description: free pkginfo structure returned from various functions 80 * Arguments: r_info - pointer to pointer to pkginfo structure to free 81 * Returns: void 82 */ 83 84 void 85 pkginfoFree(struct pkginfo **r_info) 86 { 87 struct pkginfo *pinfo; 88 89 /* entry assertions */ 90 91 assert(r_info != (struct pkginfo **)NULL); 92 93 /* localize reference to info structure to free */ 94 95 pinfo = *r_info; 96 97 /* reset callers handle to info structure */ 98 99 *r_info = (struct pkginfo *)NULL; 100 101 assert(pinfo != (struct pkginfo *)NULL); 102 103 /* free up contents of the structure */ 104 105 _pkginfoInit(pinfo); 106 107 /* free up structure itself */ 108 109 (void) free(pinfo); 110 } 111 112 /* 113 * Name: pkginfoIsPkgInstalled 114 * Description: determine if specified package is installed, return pkginfo 115 * structure describing package if package is installed 116 * Arguments: r_pinfo - pointer to pointer to pkginfo structure 117 * If this pointer is NOT null: 118 * -On success, this handle is filled in with a pointer 119 * --to a newly allocated pkginfo structure describing 120 * --the package discovered 121 * -On failure, this handle is filled with NULL 122 * If this pointer is NULL: 123 * -no pkginfo structure is returned on success. 124 * a_pkgInst - package instance (name) to lookup 125 * Returns: boolean_t 126 * B_TRUE - package installed, pkginfo returned 127 * B_FALSE - package not installed, no pkginfo returned 128 * NOTE: This function returns the first instance of package that 129 * is installed - see pkginfo() function for details 130 * NOTE: Any pkginfo structure returned is placed in new storage for the 131 * calling function. The caller must use 'pkginfoFree' to dispose 132 * of the storage once the pkginfo structure is no longer needed. 133 */ 134 135 boolean_t 136 pkginfoIsPkgInstalled(struct pkginfo **r_pinfo, char *a_pkgInst) 137 { 138 int r; 139 struct pkginfo *pinf; 140 141 /* entry assertions */ 142 143 assert(a_pkgInst != (char *)NULL); 144 assert(*a_pkgInst != '\0'); 145 146 /* reset returned pkginfo structure handle */ 147 148 if (r_pinfo != (struct pkginfo **)NULL) { 149 *r_pinfo = (struct pkginfo *)NULL; 150 } 151 152 /* allocate a new pinfo structure for use in the call to pkginfo */ 153 154 pinf = _pkginfoFactory(); 155 156 /* lookup the specified package */ 157 158 /* NOTE: required 'pkgdir' set to spool directory or NULL */ 159 r = pkginfo(pinf, a_pkgInst, NULL, NULL); 160 echoDebug(DBG_PKGOPS_PKGINFO_RETURNED, a_pkgInst, r); 161 162 if (r_pinfo != (struct pkginfo **)NULL) { 163 *r_pinfo = pinf; 164 } else { 165 /* free pkginfo structure */ 166 pkginfoFree(&pinf); 167 } 168 169 return (r == 0 ? B_TRUE : B_FALSE); 170 } 171 172 /* 173 * Name: pkgOpenInGzOnlyFile 174 * Description: Open the global zone only package list file 175 * Arguments: a_rootPath - pointer to string representing the root path 176 * where the global zone only package list file is 177 * located - NULL is the same as "/" 178 * Returns: FILE * 179 * == NULL - failure - file not open 180 * != NULL - success - file pointer returned 181 * NOTE: This function will create the file if it does not exist. 182 */ 183 184 FILE * 185 pkgOpenInGzOnlyFile(char *a_rootPath) 186 { 187 FILE *pkgingzonlyFP; 188 char pkgingzonlyPath[PATH_MAX]; 189 int len; 190 191 /* normalize root path */ 192 193 if (a_rootPath == (char *)NULL) { 194 a_rootPath = ""; 195 } 196 197 /* generate path to glocal zone only list file */ 198 199 len = snprintf(pkgingzonlyPath, sizeof (pkgingzonlyPath), "%s/%s", 200 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 201 if (len > sizeof (pkgingzonlyPath)) { 202 progerr(ERR_CREATE_PATH_2, a_rootPath, 203 GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 204 return ((FILE *)NULL); 205 } 206 207 /* open global zone only list file */ 208 209 pkgingzonlyFP = fopen(pkgingzonlyPath, "r+"); 210 if ((pkgingzonlyFP == (FILE *)NULL) && (errno == ENOENT)) { 211 pkgingzonlyFP = fopen(pkgingzonlyPath, "w+"); 212 } 213 214 if ((pkgingzonlyFP == (FILE *)NULL) && (errno != ENOENT)) { 215 progerr(ERR_PKGOPS_OPEN_GZONLY, pkgingzonlyPath, 216 strerror(errno)); 217 return ((FILE *)NULL); 218 } 219 220 /* success - return FILE pointer open on global zone only list file */ 221 222 return (pkgingzonlyFP); 223 } 224 225 /* 226 * Name: pkgIsPkgInGzOnly 227 * Description: determine if package is recorded as "in global zone only" 228 * by opening the appropriate files and searching for the 229 * specified package 230 * Arguments: a_rootPath - pointer to string representing the root path 231 * where the global zone only package list file is 232 * located - NULL is the same as "/" 233 * a_pkgInst - pointer to string representing the package instance 234 * (name) of the package to lookup 235 * Returns: boolean_t 236 * B_TRUE - package is recorded as "in global zone only" 237 * B_FALSE - package is NOT recorded as "in gz only" 238 * NOTE: This function will create the file if it does not exist. 239 */ 240 241 boolean_t 242 pkgIsPkgInGzOnly(char *a_rootPath, char *a_pkgInst) 243 { 244 FILE *fp; 245 boolean_t in_gz_only; 246 247 /* normalize root path */ 248 249 if (a_rootPath == (char *)NULL) { 250 a_rootPath = ""; 251 } 252 253 /* open the global zone only package list file */ 254 255 fp = pkgOpenInGzOnlyFile(a_rootPath); 256 if (fp == (FILE *)NULL) { 257 echoDebug(ERR_PKGOPS_CANNOT_OPEN_GZONLY, 258 a_rootPath ? a_rootPath : "/"); 259 return (B_FALSE); 260 } 261 262 /* is the package recorded as "in global zone only" ? */ 263 264 in_gz_only = pkgIsPkgInGzOnlyFP(fp, a_pkgInst); 265 266 /* close the global zone only package list file */ 267 268 (void) fclose(fp); 269 270 /* return results */ 271 272 return (in_gz_only); 273 } 274 275 /* 276 * Name: pkgIsPkgInGzOnly 277 * Description: determine if package is recorded as "in global zone only" 278 * by searching the specified open FILE for the specified package 279 * Arguments: a_fp - pointer to FILE handle open on file to search 280 * a_pkgInst - pointer to string representing the package instance 281 * (name) of the package to lookup 282 * Returns: boolean_t 283 * B_TRUE - package is recorded as "in global zone only" 284 * B_FALSE - package is NOT recorded as "in gz only" 285 */ 286 287 boolean_t 288 pkgIsPkgInGzOnlyFP(FILE *a_fp, char *a_pkgInst) 289 { 290 char line[PATH_MAX+1]; 291 292 /* entry assertions */ 293 294 assert(a_fp != (FILE *)NULL); 295 assert(a_pkgInst != (char *)NULL); 296 assert(*a_pkgInst != '\0'); 297 298 /* rewind the file to the beginning */ 299 300 rewind(a_fp); 301 302 /* read the file line by line searching for the specified package */ 303 304 while (fgets(line, sizeof (line), a_fp) != (char *)NULL) { 305 int len; 306 307 /* strip off trailing newlines */ 308 len = strlen(line); 309 while ((len > 0) && (line[len-1] == '\n')) { 310 line[--len] = '\0'; 311 } 312 313 /* ignore blank and comment lines */ 314 if ((line[0] == '#') || (line[0] == '\0')) { 315 continue; 316 } 317 318 /* return true if this is the package we are looking for */ 319 if (strcmp(a_pkgInst, line) == 0) { 320 echoDebug(DBG_PKGOPS_PKG_IS_GZONLY, a_pkgInst); 321 return (B_TRUE); 322 } 323 } 324 325 /* end of file - package not found */ 326 327 echoDebug(DBG_PKGOPS_PKG_NOT_GZONLY, a_pkgInst); 328 329 return (B_FALSE); 330 } 331 332 /* 333 * Name: pkgRemovePackageFromGzonlyList 334 * Description: Remove specified package from the global zone only package list 335 * file located at a specified root path 336 * Arguments: a_rootPath - pointer to string representing the root path 337 * where the global zone only package list file is 338 * located - NULL is the same as "/" 339 * a_pkgInst - pointer to string representing the package instance 340 * (name) of the package to remove 341 * Returns: boolean_t 342 * B_TRUE - package is successfully removed 343 * B_FALSE - failed to remove package from file 344 * NOTE: This function will create the file if it does not exist. 345 */ 346 347 boolean_t 348 pkgRemovePackageFromGzonlyList(char *a_rootPath, char *a_pkgInst) 349 { 350 FILE *destFP; 351 FILE *srcFP; 352 boolean_t pkgremoved = B_FALSE; 353 char destPath[PATH_MAX]; 354 char line[PATH_MAX+1]; 355 char savePath[PATH_MAX]; 356 char srcPath[PATH_MAX]; 357 char timeb[BUFSIZ]; 358 int len; 359 struct tm *timep; 360 time_t clock; 361 362 /* entry assertions */ 363 364 assert(a_pkgInst != (char *)NULL); 365 assert(*a_pkgInst != '\0'); 366 367 /* normalize root path */ 368 369 if (a_rootPath == (char *)NULL) { 370 a_rootPath = ""; 371 } 372 373 /* 374 * calculate paths to various objects 375 */ 376 377 /* path to current "source" ingzonly file */ 378 379 len = snprintf(srcPath, sizeof (srcPath), "%s/%s", 380 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 381 if (len > sizeof (srcPath)) { 382 progerr(ERR_CREATE_PATH_2, a_rootPath, 383 GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 384 return (B_FALSE); 385 } 386 387 /* path to new "destination" ingzonly file */ 388 389 len = snprintf(destPath, sizeof (destPath), "%s/%s.tmp", 390 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 391 if (len > sizeof (srcPath)) { 392 progerr(ERR_CREATE_PATH_2, a_rootPath, 393 GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 394 return (B_FALSE); 395 } 396 397 /* path to temporary "saved" ingzonly file */ 398 399 len = snprintf(savePath, sizeof (savePath), "%s/%s.save", 400 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 401 if (len > sizeof (srcPath)) { 402 progerr(ERR_CREATE_PATH_2, a_rootPath, 403 GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 404 return (B_FALSE); 405 } 406 407 /* open source file, creating if necessary */ 408 409 srcFP = fopen(srcPath, "r+"); 410 if ((srcFP == (FILE *)NULL) && (errno == ENOENT)) { 411 srcFP = fopen(srcPath, "w+"); 412 } 413 414 /* error if could not open/create file */ 415 416 if (srcFP == (FILE *)NULL) { 417 progerr(ERR_PKGOPS_OPEN_GZONLY, srcPath, strerror(errno)); 418 return (B_FALSE); 419 } 420 421 /* open/create new destination file */ 422 423 (void) remove(destPath); 424 destFP = fopen(destPath, "w"); 425 if (destFP == (FILE *)NULL) { 426 progerr(ERR_PKGOPS_TMPOPEN, destPath, strerror(errno)); 427 if (srcFP != (FILE *)NULL) { 428 (void) fclose(srcFP); 429 } 430 return (B_FALSE); 431 } 432 433 /* add standard comment to beginning of file */ 434 435 (void) time(&clock); 436 timep = localtime(&clock); 437 438 (void) strftime(timeb, sizeof (timeb), "%c\n", timep); 439 440 /* put standard header at the beginning of the file */ 441 442 (void) fprintf(destFP, MSG_GZONLY_FILE_HEADER, 443 get_prog_name(), "remove", a_pkgInst, timeb); 444 445 /* read source/write destination - removing specified package */ 446 447 while (fgets(line, sizeof (line), srcFP) != (char *)NULL) { 448 int len; 449 450 /* strip off trailing newlines */ 451 len = strlen(line); 452 while ((len > 0) && (line[len-1] == '\n')) { 453 line[--len] = '\0'; 454 } 455 456 /* ignore blank and comment lines */ 457 if ((line[0] == '#') || (line[0] == '\0')) { 458 continue; 459 } 460 461 /* add pkg if yet to add and pkg <= line */ 462 if ((pkgremoved == B_FALSE) && (strcmp(a_pkgInst, line) == 0)) { 463 pkgremoved = B_TRUE; 464 } else { 465 (void) fprintf(destFP, "%s\n", line); 466 } 467 } 468 469 /* close both files */ 470 471 (void) fclose(srcFP); 472 473 (void) fclose(destFP); 474 475 /* 476 * if package not found there is no need to update the original file 477 */ 478 479 if (pkgremoved == B_FALSE) { 480 (void) unlink(destPath); 481 return (B_TRUE); 482 } 483 484 /* 485 * Now we want to make a copy of the old gzonly file as a 486 * fail-safe. 487 */ 488 489 if ((access(savePath, F_OK) == 0) && remove(savePath)) { 490 progerr(ERR_REMOVE, savePath, strerror(errno)); 491 (void) remove(destPath); 492 return (B_FALSE); 493 } 494 495 if (link(srcPath, savePath) != 0) { 496 progerr(ERR_LINK, savePath, srcPath, strerror(errno)); 497 (void) remove(destPath); 498 return (B_FALSE); 499 } 500 501 if (rename(destPath, srcPath) != 0) { 502 progerr(ERR_RENAME, destPath, srcPath, strerror(errno)); 503 if (rename(savePath, srcPath)) { 504 progerr(ERR_RENAME, savePath, srcPath, strerror(errno)); 505 } 506 (void) remove(destPath); 507 return (B_FALSE); 508 } 509 510 if (remove(savePath) != 0) { 511 progerr(ERR_REMOVE, savePath, strerror(errno)); 512 } 513 514 /* successfully removed package */ 515 516 echoDebug(DBG_PKGOPS_REMOVED_GZPKG, a_pkgInst); 517 518 return (B_TRUE); 519 } 520 521 /* 522 * Name: pkgAddPackageFromGzonlyList 523 * Description: Add specified package to the global zone only package list 524 * file located at a specified root path 525 * Arguments: a_rootPath - pointer to string representing the root path 526 * where the global zone only package list file is 527 * located - NULL is the same as "/" 528 * a_pkgInst - pointer to string representing the package instance 529 * (name) of the package to add 530 * Returns: boolean_t 531 * B_TRUE - package is successfully added 532 * B_FALSE - failed to add package to the file 533 * NOTE: This function will create the file if it does not exist. 534 */ 535 536 boolean_t 537 pkgAddPackageToGzonlyList(char *a_pkgInst, char *a_rootPath) 538 { 539 FILE *destFP; 540 FILE *srcFP; 541 boolean_t pkgadded = B_FALSE; 542 char destPath[PATH_MAX]; 543 char line[PATH_MAX+1]; 544 char savePath[PATH_MAX]; 545 char srcPath[PATH_MAX]; 546 char timeb[BUFSIZ]; 547 int len; 548 struct tm *timep; 549 time_t clock; 550 551 /* entry assertions */ 552 553 assert(a_pkgInst != (char *)NULL); 554 assert(*a_pkgInst != '\0'); 555 556 /* normalize root path */ 557 558 if (a_rootPath == (char *)NULL) { 559 a_rootPath = ""; 560 } 561 562 /* entry debugging info */ 563 564 echoDebug(DBG_PKGOPS_ADDGZPKG, a_pkgInst, a_rootPath); 565 566 /* 567 * calculate paths to various objects 568 */ 569 570 /* path to current "source" ingzonly file */ 571 572 len = snprintf(srcPath, sizeof (srcPath), "%s/%s", 573 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 574 if (len > sizeof (srcPath)) { 575 progerr(ERR_CREATE_PATH_2, a_rootPath, 576 GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 577 return (B_FALSE); 578 } 579 580 /* path to new "destination" ingzonly file */ 581 582 len = snprintf(destPath, sizeof (destPath), "%s/%s.tmp", 583 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 584 if (len > sizeof (srcPath)) { 585 progerr(ERR_CREATE_PATH_2, a_rootPath, 586 GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 587 return (B_FALSE); 588 } 589 590 /* path to temporary "saved" ingzonly file */ 591 592 len = snprintf(savePath, sizeof (savePath), "%s/%s.save", 593 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 594 if (len > sizeof (srcPath)) { 595 progerr(ERR_CREATE_PATH_2, a_rootPath, 596 GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 597 return (B_FALSE); 598 } 599 600 /* open source file, creating if necessary */ 601 602 srcFP = fopen(srcPath, "r+"); 603 if ((srcFP == (FILE *)NULL) && (errno == ENOENT)) { 604 srcFP = fopen(srcPath, "w+"); 605 } 606 607 /* error if could not open/create file */ 608 609 if (srcFP == (FILE *)NULL) { 610 progerr(ERR_PKGOPS_OPEN_GZONLY, srcPath, strerror(errno)); 611 return (B_FALSE); 612 } 613 614 /* open/create new destination file */ 615 616 (void) remove(destPath); 617 destFP = fopen(destPath, "w"); 618 if (destFP == (FILE *)NULL) { 619 progerr(ERR_PKGOPS_TMPOPEN, destPath, strerror(errno)); 620 if (srcFP != (FILE *)NULL) { 621 (void) fclose(srcFP); 622 } 623 return (B_FALSE); 624 } 625 626 /* add standard comment to beginning of file */ 627 628 (void) time(&clock); 629 timep = localtime(&clock); 630 631 (void) strftime(timeb, sizeof (timeb), "%c\n", timep); 632 633 /* put standard header at the beginning of the file */ 634 635 (void) fprintf(destFP, MSG_GZONLY_FILE_HEADER, 636 get_prog_name(), "add", a_pkgInst, timeb); 637 638 /* read source/write destination; add package at appropriate location */ 639 640 while (fgets(line, sizeof (line), srcFP) != (char *)NULL) { 641 int len; 642 643 /* strip off trailing newlines */ 644 len = strlen(line); 645 while ((len > 0) && (line[len-1] == '\n')) { 646 line[--len] = '\0'; 647 } 648 649 /* ignore blank and comment lines */ 650 if ((line[0] == '#') || (line[0] == '\0')) { 651 continue; 652 } 653 654 /* add pkg if yet to add and pkg <= line */ 655 if ((pkgadded == B_FALSE) && (strcmp(a_pkgInst, line) <= 0)) { 656 if (strcmp(a_pkgInst, line) != 0) { 657 (void) fprintf(destFP, "%s\n", a_pkgInst); 658 } 659 pkgadded = B_TRUE; 660 } 661 662 (void) fprintf(destFP, "%s\n", line); 663 } 664 665 /* if package not added yet, add to end of the file */ 666 667 if (pkgadded == B_FALSE) { 668 (void) fprintf(destFP, "%s\n", a_pkgInst); 669 } 670 671 /* close both files */ 672 673 (void) fclose(srcFP); 674 675 (void) fclose(destFP); 676 677 /* 678 * Now we want to make a copy of the old gzonly file as a 679 * fail-safe. 680 */ 681 682 if ((access(savePath, F_OK) == 0) && remove(savePath)) { 683 progerr(ERR_REMOVE, savePath, strerror(errno)); 684 (void) remove(destPath); 685 return (B_FALSE); 686 } 687 688 if (link(srcPath, savePath) != 0) { 689 progerr(ERR_LINK, savePath, srcPath, strerror(errno)); 690 (void) remove(destPath); 691 return (B_FALSE); 692 } 693 694 if (rename(destPath, srcPath) != 0) { 695 progerr(ERR_RENAME, destPath, srcPath, strerror(errno)); 696 if (rename(savePath, srcPath)) { 697 progerr(ERR_RENAME, savePath, srcPath, strerror(errno)); 698 } 699 (void) remove(destPath); 700 return (B_FALSE); 701 } 702 703 if (remove(savePath) != 0) { 704 progerr(ERR_REMOVE, savePath, strerror(errno)); 705 } 706 707 /* successfully added package */ 708 709 echoDebug(DBG_PKGOPS_ADDED_GZPKG, a_pkgInst); 710 711 return (B_TRUE); 712 } 713 714 /* 715 * Name: pkginfoParamTruth 716 * Description: Search pkginfo file for specified parameter/value pair 717 * Arguments: a_fp - Pointer to FILE handle open on pkginfo file to search 718 * a_param - Pointer to string representing the parameter name 719 * to search for 720 * a_value - Pointer to string representing the "success" value 721 * being searched for 722 * a_default - determine results if parameter NOT found 723 * B_TRUE - parameter is TRUE if not found 724 * B_FALSE - parameter is FALSE if not found 725 * Returns: boolean_t 726 * B_TRUE - the parameter was found and matched the specified value 727 * OR the paramter was not found and a_default == B_TRUE 728 * B_FALSE - the parameter was found and did NOT match the value 729 * OR the paramter was not found and a_default == B_FALSE 730 */ 731 732 boolean_t 733 pkginfoParamTruth(FILE *a_fp, char *a_param, char *a_value, boolean_t a_default) 734 { 735 char *param; 736 boolean_t result; 737 738 /* entry assertions */ 739 740 assert(a_fp != (FILE *)NULL); 741 assert(a_param != (char *)NULL); 742 assert(*a_param != '\0'); 743 assert(a_value != (char *)NULL); 744 assert(*a_value != '\0'); 745 746 /* rewind the file to the beginning */ 747 748 rewind(a_fp); 749 750 /* search pkginfo file for the specified parameter */ 751 752 param = fpkgparam(a_fp, a_param); 753 754 if (param == (char *)NULL) { 755 /* parameter not found - return default */ 756 result = a_default; 757 } else if (*param == '\0') { 758 /* parameter found but no value - return default */ 759 result = a_default; 760 } else if (strcasecmp(param, a_value) == 0) { 761 /* paramter found - matches value */ 762 result = B_TRUE; 763 } else { 764 /* parameter found - does not match value */ 765 result = B_FALSE; 766 } 767 768 /* exit debugging info */ 769 770 echoDebug(DBG_PKGOPS_PARAMTRUTH_RESULTS, 771 a_param, a_value, a_default == B_TRUE ? "true" : "false", 772 param ? param : "?", result == B_TRUE ? "true" : "false"); 773 774 /* if parameter value found, free results */ 775 776 if (param != (char *)NULL) { 777 (void) free(param); 778 } 779 780 /* return results of search */ 781 782 return (result); 783 } 784 785 /* 786 * Name: pkgGetPackageList 787 * Description: Determine list of packages based on list of packages that are 788 * available, category of packages to select, and list of packages 789 * to select. 790 * Arguments: r_pkgList - pointer to pointer to string array where the list 791 * of selected packages will be returned 792 * a_argv - pointer to string array containing list of packages 793 * to select 794 * a_optind - index into string array of first package to select 795 * a_categories - pointer to string representing the categories of 796 * packages to select 797 * a_categoryList - pointer to string array representing a list 798 * of categories to select 799 * a_pkgdev - package dev containing packages that can be selected 800 * Returns: int 801 * == 0 - packages found r_pkgList contains results package list retrieved 802 * == -1 - no packages found (errno == ENOPKG) 803 * != 0 - "quit" value entered by user 804 * NOTE: If both a category and a list of packages to select are provided 805 * the category is used over the list of packages provided 806 * NOTE: If neither a category nor a list of packages to select are 807 * provided, an error is returned 808 */ 809 810 int 811 pkgGetPackageList(char ***r_pkgList, char **a_argv, int a_optind, 812 char *a_categories, char **a_categoryList, struct pkgdev *a_pkgdev) 813 { 814 char *all_pkgs[4] = {"all", NULL}; 815 816 /* entry assertions */ 817 818 assert(a_pkgdev != (struct pkgdev *)NULL); 819 assert(a_pkgdev->dirname != (char *)NULL); 820 assert(*a_pkgdev->dirname != '\0'); 821 assert(r_pkgList != (char ***)NULL); 822 assert(a_argv != (char **)NULL); 823 824 /* entry debugging info */ 825 826 echoDebug(DBG_PKGOPS_GETPKGLIST_ENTRY); 827 echoDebug(DBG_PKGOPS_GETPKGLIST_ARGS, a_pkgdev->dirname, 828 a_categories ? a_categories : "?"); 829 830 /* reset returned package list handle */ 831 832 *r_pkgList = (char **)NULL; 833 834 /* 835 * generate list of packages to be removed: if removing by category, 836 * then generate package list based on all packages by category, 837 * else generate package list based on all packages specified. 838 */ 839 840 if (a_categories != NULL) { 841 /* generate package list from all packages in given category */ 842 843 *r_pkgList = gpkglist(a_pkgdev->dirname, &all_pkgs[0], 844 a_categoryList); 845 846 if (*r_pkgList == NULL) { 847 echoDebug(DBG_PKGOPS_GPKGLIST_CATFAILED, a_categories); 848 progerr(ERR_CAT_FND, a_categories); 849 return (1); 850 } 851 852 echoDebug(DBG_PKGOPS_GPKGLIST_CATOK, a_categories); 853 854 return (0); 855 } 856 857 /* generate package list from specified packages */ 858 859 *r_pkgList = gpkglist(a_pkgdev->dirname, &a_argv[a_optind], NULL); 860 861 /* if list generated return results */ 862 863 if (*r_pkgList != NULL) { 864 echoDebug(DBG_PKGOPS_GPKGLIST_OK); 865 return (0); 866 } 867 868 /* handle error from gpkglist */ 869 870 switch (errno) { 871 case ENOPKG: /* no packages */ 872 echoDebug(DBG_PKGOPS_GPKGLIST_ENOPKG); 873 return (-1); 874 875 case ESRCH: 876 echoDebug(DBG_PKGOPS_GPKGLIST_ESRCH); 877 return (1); 878 879 case EINTR: 880 echoDebug(DBG_PKGOPS_GPKGLIST_EINTR); 881 return (3); 882 883 default: 884 echoDebug(DBG_PKGOPS_GPKGLIST_UNKNOWN, errno); 885 progerr(ERR_GPKGLIST_ERROR); 886 return (99); 887 } 888 } 889 890 /* 891 * Name: pkgMatchInherited 892 * Description: given a pointer to a "source" and a "destination" for an object, 893 * along with other attributes of the object, determine if the 894 * object is already installed and is current. 895 * Arguments: a_src - pointer to string representing the "source" file to 896 * verify - this would be the current temporary location of 897 * the file that would be installed 898 * a_dst - pointer to string representing the "destination" file to 899 * verify - this would be the ultimate destination for the 900 * file if installed 901 * a_rootDir - pointer to string representing the "root directory" 902 * where the package is being installed 903 * a_mode - final "mode" file should have when installed 904 * a_modtime - final "modtime" file should have when installed 905 * a_ftype - contents "type" of file (f/e/v/s/l) 906 * a_cksum - final "checksum" file should have when installed 907 * Returns: boolean_t 908 * B_TRUE - the specified source file MATCHES the file 909 * located at the specified destination 910 * B_FALSE - the specified source files does NOT match 911 * the file located at the specified destination 912 */ 913 914 boolean_t 915 pkgMatchInherited(char *a_src, char *a_dst, char *a_rootDir, 916 char a_mode, time_t a_modtime, char a_ftype, unsigned long a_cksum) 917 { 918 char cwd[PATH_MAX+1] = {'\0'}; 919 char dstpath[PATH_MAX+1]; 920 int cksumerr; 921 int n; 922 struct stat statbufDst; 923 struct stat statbufSrc; 924 unsigned long dstcksum; 925 unsigned long srcksum; 926 927 /* entry assertions */ 928 929 assert(a_src != (char *)NULL); 930 assert(*a_src != '\0'); 931 assert(a_dst != (char *)NULL); 932 assert(*a_dst != '\0'); 933 934 /* normalize root directory */ 935 936 if ((a_rootDir == (char *)NULL) || (*a_rootDir == '\0')) { 937 a_rootDir = "/"; 938 } 939 940 /* entry debugging */ 941 942 echoDebug(DBG_PKGOPS_MATCHINHERIT_ENTRY); 943 echoDebug(DBG_PKGOPS_MATCHINHERIT_ARGS, a_src, a_dst, a_rootDir, 944 a_mode, a_modtime, a_ftype, a_cksum); 945 946 /* save current working directory - resolvepath can change it */ 947 948 (void) getcwd(cwd, sizeof (cwd)); 949 950 n = resolvepath(a_dst, dstpath, sizeof (dstpath)); 951 if (n <= 0) { 952 if (errno != ENOENT) { 953 progerr(ERR_RESOLVEPATH, a_dst, strerror(errno)); 954 } 955 (void) chdir(cwd); 956 return (B_FALSE); 957 } 958 dstpath[n++] = '\0'; /* make sure string is terminated */ 959 960 /* return false if path is not in inherited file system space */ 961 962 if (!z_path_is_inherited(dstpath, a_ftype, a_rootDir)) { 963 return (B_FALSE); 964 } 965 966 /* 967 * path is in inherited file system space: verify existence 968 */ 969 970 /* return false if source file cannot be stat()ed */ 971 972 if (stat(a_src, &statbufSrc) != 0) { 973 progerr(ERR_STAT, a_src, strerror(errno)); 974 return (B_FALSE); 975 } 976 977 /* return false if destination file cannot be stat()ed */ 978 979 if (stat(dstpath, &statbufDst) != 0) { 980 progerr(ERR_STAT, dstpath, strerror(errno)); 981 return (B_FALSE); 982 } 983 984 /* 985 * if this is an editable or volatile file, then the only 986 * thing to guarantee is that the file exists - the file 987 * attributes do not need to match 988 */ 989 990 /* editable file only needs to exist */ 991 992 if (a_ftype == 'e') { 993 echoDebug(DBG_PKGOPS_EDITABLE_EXISTS, dstpath); 994 return (B_TRUE); 995 } 996 997 /* volatile file only needs to exist */ 998 999 if (a_ftype == 'v') { 1000 echoDebug(DBG_PKGOPS_VOLATILE_EXISTS, dstpath); 1001 return (B_TRUE); 1002 } 1003 1004 /* 1005 * verify modtime if file is not modifiable after install 1006 */ 1007 1008 /* return false if source and destination have different mod times */ 1009 1010 if (statbufSrc.st_mtim.tv_sec != statbufDst.st_mtim.tv_sec) { 1011 echoDebug(DBG_PKGOPS_MOD_MISMATCH, a_src, 1012 statbufSrc.st_mtim.tv_sec, dstpath, 1013 statbufDst.st_mtim.tv_sec); 1014 return (B_FALSE); 1015 } 1016 1017 /* return false if destination does not have required mod time */ 1018 1019 if (statbufDst.st_mtim.tv_sec != a_modtime) { 1020 echoDebug(DBG_PKGOPS_MOD_MISMATCH, dstpath, 1021 statbufDst.st_mtim.tv_sec, "source", a_modtime); 1022 return (B_FALSE); 1023 } 1024 1025 /* 1026 * verify checksums of both files 1027 */ 1028 1029 /* generate checksum of installed file */ 1030 1031 cksumerr = 0; 1032 dstcksum = compute_checksum(&cksumerr, dstpath); 1033 if (cksumerr != 0) { 1034 progerr(ERR_CANNOT_CKSUM_FILE, dstpath, strerror(errno)); 1035 return (B_FALSE); 1036 } 1037 1038 /* return false if destination does not match recorded checksum */ 1039 1040 if (dstcksum != a_cksum) { 1041 echoDebug(DBG_PKGOPS_CKSUM_MISMATCH, dstpath, dstcksum, 1042 "source", a_cksum); 1043 return (B_FALSE); 1044 } 1045 1046 /* generate checksum of file to install */ 1047 1048 cksumerr = 0; 1049 srcksum = compute_checksum(&cksumerr, a_src); 1050 if (cksumerr != 0) { 1051 progerr(ERR_CANNOT_CKSUM_FILE, a_src, strerror(errno)); 1052 return (B_FALSE); 1053 } 1054 1055 /* return false if source to install does not match recorded checksum */ 1056 1057 if (srcksum != dstcksum) { 1058 echoDebug(DBG_PKGOPS_CKSUM_MISMATCH, a_src, srcksum, dstpath, 1059 dstcksum); 1060 return (B_FALSE); 1061 } 1062 1063 /* src/dest identical - return true */ 1064 1065 echoDebug(DBG_PKGOPS_IS_INHERITED, dstpath, ""); 1066 1067 return (B_TRUE); 1068 } 1069 1070 /* 1071 * return string representing path to "global zone only file" 1072 */ 1073 1074 char * 1075 pkgGetGzOnlyPath(void) 1076 { 1077 return (GLOBALZONE_ONLY_PACKAGE_FILE_PATH); 1078 } 1079 1080 /* 1081 * Name: pkgAddThisZonePackage 1082 * Description: Add specified package to internal list of "this zone only" pkgs 1083 * Arguments: a_pkgInst - name of package to add to list 1084 * Returns: void 1085 */ 1086 1087 void 1088 pkgAddThisZonePackage(char *a_pkgInst) 1089 { 1090 /* entry assertions */ 1091 1092 assert(a_pkgInst != (char *)NULL); 1093 assert(*a_pkgInst != '\0'); 1094 1095 /* do not duplicate entries */ 1096 1097 if (pkgPackageIsThisZone(a_pkgInst) == B_TRUE) { 1098 return; 1099 } 1100 1101 /* add package name to internal list */ 1102 1103 if (thisZonePackages == (char **)NULL) { 1104 thisZonePackages = 1105 (char **)calloc(2, sizeof (char **)); 1106 } else { 1107 thisZonePackages = 1108 (char **)realloc(thisZonePackages, 1109 sizeof (char **)*(numThisZonePackages+2)); 1110 } 1111 1112 /* handle out of memory error */ 1113 1114 if (thisZonePackages == (char **)NULL) { 1115 progerr(ERR_MEMORY, errno); 1116 quit(99); 1117 } 1118 1119 /* add this entry to the end of the list */ 1120 1121 thisZonePackages[numThisZonePackages] = strdup(a_pkgInst); 1122 if (thisZonePackages[numThisZonePackages] == (char *)NULL) { 1123 progerr(ERR_MEMORY, errno); 1124 quit(99); 1125 } 1126 1127 numThisZonePackages++; 1128 1129 /* make sure end of the list is properly terminated */ 1130 1131 thisZonePackages[numThisZonePackages] = (char *)NULL; 1132 1133 /* exit debugging info */ 1134 1135 echoDebug(DBG_PKGOPS_ADD_TZP, numThisZonePackages, 1136 thisZonePackages[numThisZonePackages-1]); 1137 } 1138 1139 /* 1140 * Name: pkgPackageIsThisZone 1141 * Description: Determine if the specified package is marked to be installed 1142 * in this zone only 1143 * Arguments: a_pkgInst - pointer to string representing package name to check 1144 * Returns: boolean_t 1145 * B_TRUE - the package IS "this zone only" 1146 * B_FALSE - the paackage is NOT "this zone only" 1147 */ 1148 1149 boolean_t 1150 pkgPackageIsThisZone(char *a_pkgInst) 1151 { 1152 int n; 1153 1154 /* entry assertions */ 1155 1156 assert(a_pkgInst != (char *)NULL); 1157 assert(*a_pkgInst != '\0'); 1158 1159 /* if no inherited file systems, there can be no match */ 1160 1161 if (numThisZonePackages == 0) { 1162 echoDebug(DBG_PKGOPS_NOT_THISZONE, a_pkgInst); 1163 return (B_FALSE); 1164 } 1165 1166 /* 1167 * see if this package is in the "this zone only" list 1168 */ 1169 1170 for (n = 0; n < numThisZonePackages; n++) { 1171 if (strcmp(a_pkgInst, thisZonePackages[n]) == 0) { 1172 echoDebug(DBG_PKGOPS_IS_THISZONE, a_pkgInst); 1173 return (B_TRUE); 1174 } 1175 } 1176 1177 /* path is not in "this zone only" list */ 1178 1179 echoDebug(DBG_PKGOPS_IS_NOT_THISZONE, a_pkgInst); 1180 1181 return (B_FALSE); 1182 } 1183 1184 /* 1185 * Name: pkgLocateHighestInst 1186 * Description: Locate the highest installed instance of a package 1187 * Arguments: r_path - [RO, *RW] - (char *) 1188 * Pointer to buffer where the full path to the top level 1189 * directory containing the latest instance of the 1190 * specified package is located is placed. 1191 * r_pathLen - [RO, *RO] - (int) 1192 * Integer representing the size of r_path in bytes. 1193 * r_pkgInst - [RO, *RW] - (char *) 1194 * Pointer to buffer where the package instance name of the 1195 * latest instance of the specified package is placed. 1196 * r_pkgInstLen - [RO, *RO] - (int) 1197 * Integer representing the size of r_pkgInst in bytes. 1198 * a_rootPath - [RO, *RO] - (char *) 1199 * Pointer to string representing the root path to look 1200 * for the latest instance of the specified package. 1201 * a_pkgInst - [RO, *RO] - (char *) 1202 * Pointer to string representing the name of the package 1203 * to locate the latest installed instance of. 1204 */ 1205 1206 void 1207 pkgLocateHighestInst(char *r_path, int r_pathLen, char *r_pkgInst, 1208 int r_pkgInstLen, char *a_rootPath, char *a_pkgInst) 1209 { 1210 char pkgInstPath[PATH_MAX] = {'\0'}; 1211 char pkgWild[PKGSIZ+1] = {'\0'}; 1212 char pkgName[PKGSIZ+1] = {'\0'}; 1213 int npkgs; 1214 struct pkginfo *pinf = (struct pkginfo *)NULL; 1215 1216 /* entry assertions */ 1217 1218 assert(r_path != (char *)NULL); 1219 assert(r_pathLen > 0); 1220 assert(r_pkgInst != (char *)NULL); 1221 assert(r_pkgInstLen > 0); 1222 assert(a_pkgInst != (char *)NULL); 1223 assert(*a_pkgInst != '\0'); 1224 1225 /* normalize root path */ 1226 1227 if ((a_rootPath == (char *)NULL) || (strcmp(a_rootPath, "/") == 0)) { 1228 a_rootPath = ""; 1229 } 1230 1231 /* construct path to package repository directory (eg. /var/sadm/pkg) */ 1232 1233 (void) snprintf(pkgInstPath, sizeof (pkgInstPath), "%s%s", a_rootPath, 1234 PKGLOC); 1235 1236 /* entry debugging info */ 1237 1238 echoDebug(DBG_PKGOPS_LOCHIGH_ENTRY); 1239 echoDebug(DBG_PKGOPS_LOCHIGH_ARGS, pkgInstPath, a_pkgInst); 1240 1241 /* reset returned path/package instance so both ares empty */ 1242 1243 *r_path = '\0'; 1244 *r_pkgInst = '\0'; 1245 1246 /* remove any architecture extension */ 1247 1248 pkgstrGetToken_r((char *)NULL, a_pkgInst, 0, ".", 1249 pkgName, sizeof (pkgName)); 1250 1251 /* make sure that the package name is valid and can be wild carded */ 1252 1253 if (pkgnmchk(pkgName, NULL, 0) || strchr(pkgName, '.')) { 1254 progerr(ERR_PKGOPS_LOCHIGH_BAD_PKGNAME, pkgName); 1255 quit(99); 1256 } 1257 1258 /* create wild card specification for this package instance */ 1259 1260 (void) snprintf(pkgWild, sizeof (pkgWild), "%s.*", pkgName); 1261 1262 echoDebug(DBG_PKGOPS_LOCHIGH_WILDCARD, pkgName, pkgWild); 1263 1264 /* 1265 * inspect the system to determine if any instances of the 1266 * package being installed already exist on the system 1267 */ 1268 1269 for (npkgs = 0; ; npkgs++) { 1270 char *savePkgdir; 1271 int r; 1272 1273 /* allocate new pinfo structure for use in the pkginfo call */ 1274 1275 pinf = _pkginfoFactory(); 1276 1277 /* 1278 * lookup the specified package; the first call will cause the 1279 * pkgdir directory to be opened - it will be closed when the 1280 * end of directory is read and pkginfo() returns != 0. You must 1281 * cycle through all instances until pkginfo() returns != 0. 1282 * NOTE: pkginfo() requires the global variable 'pkgdir' be set 1283 * to the package installed directory (<root>/var/sadm/pkg). 1284 */ 1285 1286 savePkgdir = pkgdir; 1287 pkgdir = pkgInstPath; 1288 1289 r = pkginfo(pinf, pkgWild, NULL, NULL); 1290 1291 pkgdir = savePkgdir; 1292 1293 echoDebug(DBG_PKGOPS_PKGINFO_RETURNED, pkgName, r); 1294 1295 /* break out of loop of no package found */ 1296 1297 if (r != 0) { 1298 pkginfoFree(&pinf); 1299 break; 1300 } 1301 1302 echoDebug(DBG_PKGOPS_LOCHIGH_INSTANCE, npkgs, 1303 pinf->pkginst ? pinf->pkginst : "", 1304 pinf->name ? pinf->name : "", 1305 pinf->arch ? pinf->arch : "", 1306 pinf->version ? pinf->version : "", 1307 pinf->vendor ? pinf->vendor : "", 1308 pinf->basedir ? pinf->basedir : "", 1309 pinf->catg ? pinf->catg : "", 1310 pinf->status); 1311 1312 /* save path/instance name for this instance found */ 1313 1314 (void) strlcpy(r_pkgInst, pinf->pkginst, r_pkgInstLen); 1315 pkgstrPrintf_r(r_path, r_pathLen, "%s%s/%s", a_rootPath, 1316 PKGLOC, pinf->pkginst); 1317 1318 pkginfoFree(&pinf); 1319 } 1320 1321 echoDebug(DBG_PKGOPS_LOCHIGH_RETURN, npkgs, r_pkgInst, r_path); 1322 } 1323 1324 /* 1325 * Name: pkgTestInstalled 1326 * Description: determine if package is installed at specified root path 1327 * Arguments: a_packageName - name of package to test 1328 * a_rootPath - root path of alternative root to test 1329 * Returns: B_TRUE - package is installed 1330 * B_FALSE - package is not installed 1331 */ 1332 1333 boolean_t 1334 pkgTestInstalled(char *a_packageName, char *a_rootPath) 1335 { 1336 char cmd[MAXPATHLEN+1]; 1337 int rc; 1338 1339 /* entry assertions */ 1340 1341 assert(a_packageName != (char *)NULL); 1342 assert(*a_packageName != '\0'); 1343 assert(a_rootPath != (char *)NULL); 1344 assert(a_rootPath != '\0'); 1345 1346 /* entry debugging info */ 1347 1348 echoDebug(DBG_PKG_TEST_EXISTENCE, a_packageName, a_rootPath); 1349 1350 /* 1351 * create pkginfo command to execute: 1352 * /usr/bin/pkginfo -q <packageName> 1353 */ 1354 (void) snprintf(cmd, sizeof (cmd), 1355 "%s -q %s", PKGINFO_CMD, a_packageName); 1356 1357 /* execute command */ 1358 1359 rc = system(cmd); 1360 1361 /* return success if pkginfo returns "0" */ 1362 1363 if (rc == 0) { 1364 echoDebug(DBG_PKG_INSTALLED, a_packageName, a_rootPath); 1365 return (B_TRUE); 1366 } 1367 1368 /* package not installed */ 1369 1370 echoDebug(DBG_PKG_NOT_INSTALLED, a_packageName, a_rootPath); 1371 1372 return (B_FALSE); 1373 } 1374 1375 /* 1376 * ***************************************************************************** 1377 * static internal (private) functions 1378 * ***************************************************************************** 1379 */ 1380 1381 static void 1382 _pkginfoInit(struct pkginfo *a_info) 1383 { 1384 /* entry assertions */ 1385 1386 assert(a_info != (struct pkginfo *)NULL); 1387 1388 /* free previously allocated space */ 1389 1390 if (a_info->pkginst) { 1391 free(a_info->pkginst); 1392 if (a_info->arch) 1393 free(a_info->arch); 1394 if (a_info->version) 1395 free(a_info->version); 1396 if (a_info->basedir) 1397 free(a_info->basedir); 1398 if (a_info->name) 1399 free(a_info->name); 1400 if (a_info->vendor) 1401 free(a_info->vendor); 1402 if (a_info->catg) 1403 free(a_info->catg); 1404 } 1405 1406 a_info->pkginst = NULL; 1407 a_info->arch = a_info->version = NULL; 1408 a_info->basedir = a_info->name = NULL; 1409 a_info->vendor = a_info->catg = NULL; 1410 a_info->status = PI_UNKNOWN; 1411 } 1412 1413 static struct pkginfo * 1414 _pkginfoFactory(void) 1415 { 1416 struct pkginfo *pinf; 1417 1418 pinf = (struct pkginfo *)calloc(1, sizeof (struct pkginfo)); 1419 if (pinf == (struct pkginfo *)NULL) { 1420 progerr(ERR_MEM); 1421 exit(1); 1422 } 1423 1424 _pkginfoInit(pinf); 1425 return (pinf); 1426 } 1427