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