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 <fcntl.h> 33 #include <sys/types.h> 34 #include <sys/param.h> 35 #include <sys/sysmacros.h> 36 #include <string.h> 37 #include <strings.h> 38 #include <sys/wait.h> 39 #include <sys/stat.h> 40 #include <sys/mman.h> 41 #include <sys/statvfs.h> 42 #include <signal.h> 43 #include <limits.h> 44 #include <errno.h> 45 #include <fcntl.h> 46 #include <stdlib.h> 47 #include <unistd.h> 48 #include <time.h> 49 #include <errno.h> 50 #include <pkglocs.h> 51 #include <locale.h> 52 #include <libintl.h> 53 #include <pkglib.h> 54 #include "libinst.h" 55 #include "libadm.h" 56 57 #define LOCKFILE ".pkg.lock.client" 58 #define LOCKFILESERV ".pkg.lock" 59 60 #define LOCKWAIT 10 /* seconds between retries */ 61 #define LOCKRETRY 20 /* number of retries for a DB lock */ 62 63 #define ERR_COMMIT "WARNING: unable to commit contents database update" 64 #define ERR_NOCLOSE "WARNING: unable to close <%s>" 65 #define ERR_NOUNLINK_LATENT "WARNING: unable to unlink latent <%s>" 66 #define ERR_LINK_FAIL "link(%s, %s) failed (errno %d)" 67 #define ERR_NORENAME_CONTENTS "unable to establish contents file <%s> "\ 68 "from <%s>" 69 #define ERR_RENAME_FAIL "rename(%s, %s) failed (errno %d)" 70 #define ERR_RESTORE_FAIL "attempt to restore <%s> failed" 71 #define ERR_NOUNLINK "WARNING: unable to unlink <%s>" 72 #define ERR_FCLOSE_FAIL "fclose failed (errno %d)" 73 #define ERR_ERRNO "(errno %d: %s)" 74 #define ERR_NOTMPOPEN "unable to open temporary contents file image" 75 #define ERR_CFBACK "Not enough space to backup <%s>" 76 #define ERR_CREAT_CONT "unable to create contents file <%s>: %s" 77 #define ERR_ACCESS_CONT "unable to access contents file <%s>: %s" 78 #define ERR_CFBACK1 "Need=%llu blocks, Available=%llu blocks " \ 79 "(block size=%d)" 80 #define ERR_NOCFILE "unable to locate contents file <%s>" 81 #define ERR_NOROPEN "unable to open <%s> for reading" 82 #define ERR_NOOPEN "unable to open <%s> for writing" 83 #define ERR_NOSTAT "unable to stat contents file <%s>" 84 #define ERR_NOSTATV "statvfs(%s) failed" 85 #define ERR_NOUPD "unable to update contents file" 86 #define ERR_DRCONTCP "unable to copy contents file to <%s>" 87 88 #define MSG_XWTING "NOTE: Waiting for exclusive access to the package " \ 89 "database." 90 #define MSG_NOLOCK "NOTE: Couldn't lock the package database." 91 92 #define ERR_NOLOCK "Database lock failed." 93 #define ERR_OPLOCK "unable to open lock file <%s>." 94 #define ERR_MKLOCK "unable to create lock file <%s>." 95 #define ERR_LCKREM "unable to lock package database - remote host " \ 96 "unavailable." 97 #define ERR_BADLCK "unable to lock package database - unknown error." 98 #define ERR_DEADLCK "unable to lock package database - deadlock condition." 99 #define ERR_TMOUT "unable to lock package database - too many retries." 100 #define ERR_CFDIR "unable to locate contents file directory" 101 102 static int active_lock; 103 static int lock_fd; /* fd of LOCKFILE. */ 104 static char *pkgadm_dir; 105 106 int pkgWlock(int verbose); 107 static int pkgWunlock(void); 108 109 /* forward declarations */ 110 111 int relslock(void); 112 113 /*ARGSUSED*/ 114 static void 115 do_alarm(int n) 116 { 117 (void) signal(SIGALRM, SIG_IGN); 118 (void) signal(SIGALRM, do_alarm); 119 (void) alarm(LOCKWAIT); 120 } 121 122 /* 123 * Point packaging to the appropriate contents file. This is primarily used 124 * to establish a dryrun contents file. If the malloc() doesn't work, this 125 * returns 99 (internal error), else 0. 126 */ 127 int 128 set_cfdir(char *cfdir) 129 { 130 char realcf[PATH_MAX]; 131 char tmpcf[PATH_MAX]; 132 int status; 133 134 if (cfdir == NULL) { 135 pkgadm_dir = get_PKGADM(); 136 return (0); 137 } 138 139 if ((pkgadm_dir = strdup(cfdir)) == NULL) { 140 return (99); 141 } 142 143 (void) snprintf(tmpcf, sizeof (tmpcf), "%s/contents", pkgadm_dir); 144 145 /* 146 * return if a temporary contents file already exists - 147 * assume it is from a prior package in this series. 148 */ 149 150 if (access(tmpcf, F_OK) == 0) { 151 return (0); 152 } 153 154 /* 155 * no temporary contents file exists - create one. 156 */ 157 158 (void) snprintf(realcf, sizeof (realcf), "%s/contents", get_PKGADM()); 159 160 /* 161 * If there's a contents file there already, copy it 162 * over, otherwise initialize one. Make sure that the 163 * server, if running, flushes the contents file. 164 */ 165 166 (void) pkgsync(NULL, get_PKGADM(), B_FALSE); 167 168 /* create new contents file if one does not already exist */ 169 170 if (access(realcf, F_OK) != 0) { 171 int n; 172 173 n = open(tmpcf, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644); 174 if (n < 0) { 175 progerr(gettext(ERR_CREAT_CONT), tmpcf, 176 strerror(errno)); 177 return (99); 178 } 179 (void) close(n); 180 } else { 181 182 /* contents file exists, save in pkgadm-dir */ 183 184 status = copyf(realcf, tmpcf, (time_t)0); 185 if (status != 0) { 186 progerr(gettext(ERR_DRCONTCP), tmpcf); 187 return (99); 188 } 189 } 190 191 return (0); 192 } 193 194 /* 195 * This function installs the database lock, opens the contents file for 196 * reading and creates and opens the temporary contents file for read/write. 197 * It returns 1 if successful, 0 otherwise. 198 */ 199 int 200 ocfile(PKGserver *server, VFP_T **r_tmpvfp, fsblkcnt_t map_blks) 201 { 202 struct stat64 statb; 203 struct statvfs64 svfsb; 204 fsblkcnt_t free_blocks; 205 fsblkcnt_t need_blocks; 206 VFP_T *tmpvfp = (VFP_T *)NULL; 207 char contents[PATH_MAX]; 208 int n; 209 off_t cdiff_alloc; 210 PKGserver newserver; 211 212 /* establish package administration contents directory location */ 213 214 if (pkgadm_dir == NULL) { 215 if (set_cfdir(NULL) != 0) { 216 progerr(gettext(ERR_CFDIR)); 217 return (0); 218 } 219 } 220 221 /* Lock the file for exclusive access */ 222 223 if (!pkgWlock(1)) { 224 progerr(gettext(ERR_NOLOCK)); 225 return (0); 226 } 227 228 if (*server != NULL) { 229 vfpTruncate(*r_tmpvfp); 230 (void) vfpClearModified(*r_tmpvfp); 231 232 return (1); 233 } 234 235 newserver = pkgopenserver(NULL, pkgadm_dir, B_FALSE); 236 237 /* The error has been reported. */ 238 if (newserver == NULL) 239 return (0); 240 241 /* reset return VFP/FILE pointers */ 242 243 (*r_tmpvfp) = (VFP_T *)NULL; 244 245 /* determine path to the primary contents file */ 246 (void) snprintf(contents, sizeof (contents), "%s/contents", pkgadm_dir); 247 248 /* 249 * Check and see if there is enough space for the packaging commands 250 * to back up the contents file, if there is not, then do not allow 251 * execution to continue by failing the ocfile() call. 252 */ 253 254 /* Get the contents file size */ 255 256 if (stat64(contents, &statb) == -1) { 257 int lerrno = errno; 258 259 progerr(gettext(ERR_NOCFILE), contents); 260 logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno)); 261 pkgcloseserver(newserver); 262 return (0); 263 } 264 265 /* Get the filesystem space */ 266 267 if (statvfs64(contents, &svfsb) == -1) { 268 int lerrno = errno; 269 270 progerr(gettext(ERR_NOSTATV), contents); 271 logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno)); 272 pkgcloseserver(newserver); 273 return (0); 274 } 275 276 free_blocks = (((fsblkcnt_t)svfsb.f_frsize > 0) ? 277 howmany(svfsb.f_frsize, DEV_BSIZE) : 278 howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bfree; 279 280 /* 281 * If we're removing a package, then the log might grow to the size 282 * of the full contents file. 283 */ 284 285 if (map_blks == 0LL) 286 map_blks = nblk(statb.st_size, svfsb.f_bsize, svfsb.f_frsize); 287 288 /* 289 * Calculate the number of blocks we need to be able to operate on 290 * the contents file. 291 */ 292 need_blocks = map_blks + 293 /* Max of the log file */ 294 nblk(MAXLOGFILESIZE, svfsb.f_bsize, svfsb.f_frsize) + 295 /* Current content file */ 296 nblk(statb.st_size, svfsb.f_bsize, svfsb.f_frsize); 297 298 if ((need_blocks + 10) > free_blocks) { 299 progerr(gettext(ERR_CFBACK), contents); 300 progerr(gettext(ERR_CFBACK1), need_blocks, free_blocks, 301 DEV_BSIZE); 302 pkgcloseserver(newserver); 303 return (0); 304 } 305 306 /* 307 * open the temporary contents file without a path name - this causes 308 * the "vfp" to be opened on in-memory storage only, the size of which 309 * is set following a successful return - this causes the temporary 310 * contents file to be maintained in memory only - if no changes are 311 * made as the primary contents file is processed, the in memory data 312 * is discarded and not written to the disk. 313 */ 314 315 if (vfpOpen(&tmpvfp, (char *)NULL, "w", VFP_NONE) != 0) { 316 int lerrno = errno; 317 318 progerr(gettext(ERR_NOTMPOPEN)); 319 logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno)); 320 pkgcloseserver(newserver); 321 return (0); 322 } 323 324 /* 325 * set size of allocation for temporary contents file - this sets the 326 * size of the in-memory buffer associated with the open vfp. 327 * We only store the new and changed entries. 328 * We allocate memory depending on the size of the pkgmap; it's not 329 * completely right but <some value + * 1.5 * map_blks * DEV_BSIZE> 330 * seems fine (an install adds the size if the name of the package.) 331 */ 332 333 cdiff_alloc = map_blks * DEV_BSIZE; 334 cdiff_alloc += cdiff_alloc/2; 335 if (cdiff_alloc < 1000000) 336 cdiff_alloc += 1000000; 337 338 if (vfpSetSize(tmpvfp, cdiff_alloc) != 0) { 339 int lerrno = errno; 340 341 progerr(gettext(ERR_NOTMPOPEN)); 342 logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno)); 343 (void) vfpClose(&tmpvfp); 344 pkgcloseserver(newserver); 345 return (0); 346 } 347 348 /* set return ->s to open server/vfps */ 349 350 (*r_tmpvfp) = tmpvfp; 351 *server = newserver; 352 353 return (1); /* All OK */ 354 } 355 356 /* 357 * This is a simple open and lock of the contents file. It doesn't create a 358 * temporary contents file and it doesn't need to do any space checking. 359 * Returns 1 for OK and 0 for "didn't do it". 360 */ 361 int 362 socfile(PKGserver *server, boolean_t quiet) 363 { 364 char contents[PATH_MAX]; 365 boolean_t readonly = B_FALSE; 366 PKGserver newserver; 367 368 if (pkgadm_dir == NULL) { 369 if (set_cfdir(NULL) != 0) { 370 progerr(gettext(ERR_CFDIR)); 371 return (0); 372 } 373 } 374 375 /* 376 * Lock the database for exclusive access, but don't make a fuss if 377 * it fails (user may not be root and the .pkg.lock file may not 378 * exist yet). 379 */ 380 381 if (!pkgWlock(0)) { 382 if (!quiet) 383 logerr(gettext(MSG_NOLOCK)); 384 readonly = B_TRUE; 385 } 386 387 newserver = pkgopenserver(NULL, pkgadm_dir, readonly); 388 if (newserver == NULL) 389 return (0); 390 391 *server = newserver; 392 return (1); 393 } 394 395 /* 396 * Name: swapcfile 397 * Description: This function closes both the current and temporary contents 398 * files specified, and conditionally replaces the old transitory 399 * contents file with the newly updated temporary contents file. 400 * The "ocfile()" or "socfile()" functions must be called to re- 401 * open the real contents file for processing. 402 * Arguments: PKGserver - handle to the package database 403 * a_cfTmpVfp - (VFP_T **) - [RW, *RW] 404 * This is the VFP associated which contains all the 405 * modifications to be written back to the database. 406 * file that is being written to. 407 * pkginst - (char) - [RO, *RO] 408 * This is the name of the package being operated on; 409 * this is used to write the "last modified by xxx" 410 * comment at the end of the contents file. 411 * dbchg - (int) - [RO] 412 * == 0 - the temporary contents file has NOT been changed 413 * with respect to the real contents file; do not 414 * update the real contents file with the contents 415 * of the temporary contents file. 416 * != 0 - the temporary contetns file HAS been changed with 417 * respect to the real contents file; DO update the 418 * real contents file with the contents of the 419 * temporary contents file. 420 * Returns: int == RESULT_OK - successful 421 * == RESULT_WRN - successful with warnings 422 * == RESULT_ERR - failed with fatal errors - deserves an 423 * alarming message and a quit() 424 * NOTES: If dbchg != 0, the contents file is always updated. If dbchg == 0, 425 * the contents file is updated IF the data is modified indication 426 * is set on the contents file associated with a_cfTmpVfp. 427 */ 428 429 int 430 swapcfile(PKGserver server, VFP_T **a_cfTmpVfp, char *pkginst, int dbchg) 431 { 432 char *pe; 433 char *pl; 434 char *ps; 435 char line[256]; 436 char timeb[BUFSIZ]; 437 int retval = RESULT_OK; 438 struct tm *timep; 439 time_t clock; 440 441 /* normalize pkginst so its never null */ 442 443 if (pkginst == (char *)NULL) { 444 dbchg = 0; 445 pkginst = "<unknown>"; 446 } 447 448 /* 449 * If no changes were made to the database, checkpoint the temporary 450 * contents file - if this fails, then just close the file which causes 451 * the contents file to be reopened and reread if it is needed again 452 */ 453 454 if ((dbchg == 0) && (vfpGetModified(*a_cfTmpVfp) == 0)) { 455 (void) pkgWunlock(); /* Free the database lock. */ 456 return (retval); 457 } 458 459 /* 460 * changes made to the current temporary contents file - 461 * remove any trailing comment lines in the temp contents file, then 462 * append updated modification info records to temp contents file 463 */ 464 465 pe = vfpGetCurrCharPtr(*a_cfTmpVfp); /* last char in contents file */ 466 ps = vfpGetFirstCharPtr(*a_cfTmpVfp); /* 1st char in contents file */ 467 pl = pe; /* last match is last char in contents file */ 468 469 /* skip past all trailing newlines and null bytes */ 470 471 while ((pe > ps) && ((*pe == '\n') || (*pe == '\0'))) { 472 pe--; 473 } 474 475 /* remove trailing comments as long as there are lines in the file */ 476 477 while (pe > ps) { 478 if (*pe != '\n') { 479 /* curr char is not newline: backup one byte */ 480 pl = pe--; 481 } else if (*pl != '#') { 482 /* curr char is newline next char not comment break */ 483 break; 484 } else { 485 /* curr char is newline next char is comment - remove */ 486 *pl = '\0'; 487 vfpSetLastCharPtr(*a_cfTmpVfp, pl); 488 pe--; 489 } 490 } 491 492 /* create two update comment lines */ 493 494 (void) time(&clock); 495 timep = localtime(&clock); 496 497 (void) strftime(timeb, sizeof (timeb), "%c\n", timep); 498 (void) snprintf(line, sizeof (line), 499 gettext("# Last modified by %s for %s package\n# %s"), 500 get_prog_name(), pkginst, timeb); 501 vfpPuts(*a_cfTmpVfp, line); 502 503 /* commit temporary contents file bytes to storage */ 504 505 if (pkgservercommitfile(*a_cfTmpVfp, server) != 0) { 506 int lerrno = errno; 507 508 logerr(gettext(ERR_COMMIT)); 509 vfpClose(a_cfTmpVfp); 510 pkgcloseserver(server); 511 (void) pkgWunlock(); /* Free the database lock. */ 512 return (RESULT_ERR); 513 } 514 515 return (relslock() == 0 ? RESULT_ERR : retval); 516 } 517 518 /* This function releases the lock on the package database. */ 519 int 520 relslock(void) 521 { 522 /* 523 * This closes the contents file and releases the lock. 524 */ 525 if (!pkgWunlock()) { 526 int lerrno = errno; 527 528 progerr(gettext(ERR_NOUPD)); 529 logerr(gettext(ERR_FCLOSE_FAIL), lerrno); 530 return (0); 531 } 532 return (1); 533 } 534 535 /* 536 * This function attempts to lock the package database. It returns 1 on 537 * success, 0 on failure. The positive logic verbose flag determines whether 538 * or not the function displays the error message upon failure. 539 */ 540 int 541 pkgWlock(int verbose) { 542 int retry_cnt, retval; 543 char lockpath[PATH_MAX]; 544 545 active_lock = 0; 546 547 (void) snprintf(lockpath, sizeof (lockpath), 548 "%s/%s", pkgadm_dir, LOCKFILE); 549 550 retry_cnt = LOCKRETRY; 551 552 /* 553 * If the lock file is not present, create it. The mode is set to 554 * allow any process to lock the database, that's because pkgchk may 555 * be run by a non-root user. 556 */ 557 if (access(lockpath, F_OK) == -1) { 558 lock_fd = open(lockpath, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644); 559 if (lock_fd < 0) { 560 if (verbose) 561 progerr(gettext(ERR_MKLOCK), lockpath); 562 return (0); 563 } else { 564 (void) fchmod(lock_fd, 0644); /* force perms. */ 565 } 566 } else { 567 if ((lock_fd = open(lockpath, O_RDWR)) == -1) { 568 if (verbose) 569 progerr(gettext(ERR_OPLOCK), lockpath); 570 return (0); 571 } 572 } 573 574 (void) signal(SIGALRM, do_alarm); 575 (void) alarm(LOCKWAIT); 576 577 do { 578 if (lockf(lock_fd, F_LOCK, 0)) { 579 if (errno == EAGAIN || errno == EINTR) 580 logerr(gettext(MSG_XWTING)); 581 else if (errno == ECOMM) { 582 logerr(gettext(ERR_LCKREM)); 583 retval = 0; 584 break; 585 } else if (errno == EBADF) { 586 logerr(gettext(ERR_BADLCK)); 587 retval = 0; 588 break; 589 } else if (errno == EDEADLK) { 590 logerr(gettext(ERR_DEADLCK)); 591 retval = 0; 592 break; 593 } 594 } else { 595 active_lock = 1; 596 retval = 1; 597 break; 598 } 599 } while (retry_cnt--); 600 601 (void) signal(SIGALRM, SIG_IGN); 602 603 if (retval == 0) 604 { 605 if (retry_cnt == -1) { 606 logerr(gettext(ERR_TMOUT)); 607 } 608 609 (void) pkgWunlock(); /* close the lockfile. */ 610 } 611 612 return (retval); 613 } 614 615 /* 616 * Release the lock on the package database. Returns 1 on success, 0 on 617 * failure. 618 */ 619 static int 620 pkgWunlock(void) { 621 if (active_lock) { 622 active_lock = 0; 623 if (close(lock_fd)) 624 return (0); 625 else 626 return (1); 627 } else 628 return (1); 629 } 630 631 /* 632 * This function verifies that the contents file is in place. 633 * returns 1 - if it exists 634 * returns 0 - if it does not exist 635 */ 636 int 637 iscfile(void) 638 { 639 char contents[PATH_MAX]; 640 641 (void) snprintf(contents, PATH_MAX, "%s/contents", get_PKGADM()); 642 643 return (access(contents, F_OK) == 0 ? 1 : 0); 644 } 645 646 /* 647 * This function verifies that the contents file is in place. If it is - no 648 * change. If it isn't - this creates it. 649 * Returns: == 0 : failure 650 * != 0 : success 651 */ 652 653 int 654 vcfile(void) 655 { 656 int lerrno; 657 int fd; 658 char contents[PATH_MAX]; 659 660 /* 661 * create full path to contents file 662 */ 663 664 (void) snprintf(contents, sizeof (contents), 665 "%s/contents", get_PKGADM()); 666 667 /* 668 * Attempt to create the file - will only be successful 669 * if the file does not currently exist. 670 */ 671 672 fd = open(contents, O_WRONLY | O_CREAT | O_EXCL, 0644); 673 if (fd >= 0) { 674 /* 675 * Contents file wasn't there, but is now. 676 */ 677 678 echo(gettext("## Software contents file initialized")); 679 (void) close(fd); 680 return (1); /* success */ 681 } 682 683 /* 684 * Could not create the file - it may exist or there may be 685 * permissions issues - find out and act accordingly. 686 */ 687 688 lerrno = errno; 689 690 /* success if error is 'file exists' */ 691 692 if (lerrno == EEXIST) { 693 return (1); /* success */ 694 } 695 696 /* success if error is 'permission denied' but file exists */ 697 698 if (lerrno == EACCES) { 699 /* 700 * Because O_CREAT and O_EXCL are specified in open(), 701 * if the contents file already exists, the open will 702 * fail with EACCES - determine if this is the case - 703 * if so return success. 704 */ 705 706 if (access(contents, F_OK) == 0) { 707 return (1); /* success */ 708 } 709 710 /* 711 * access() failed - if because of permissions failure this 712 * means the contents file exists but it cannot be accessed 713 * or the path to the contents file cannot be accessed - in 714 * either case the contents file cannot be accessed. 715 */ 716 717 if (errno == EACCES) { 718 progerr(gettext(ERR_ACCESS_CONT), contents, 719 strerror(lerrno)); 720 logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno)); 721 return (0); /* failure */ 722 } 723 } 724 725 /* 726 * the contents file does not exist and it cannot be created. 727 */ 728 729 progerr(gettext(ERR_CREAT_CONT), contents, strerror(lerrno)); 730 logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno)); 731 return (0); /* failure */ 732 } 733