15c51f124SMoriah Waterland /* 25c51f124SMoriah Waterland * CDDL HEADER START 35c51f124SMoriah Waterland * 45c51f124SMoriah Waterland * The contents of this file are subject to the terms of the 55c51f124SMoriah Waterland * Common Development and Distribution License (the "License"). 65c51f124SMoriah Waterland * You may not use this file except in compliance with the License. 75c51f124SMoriah Waterland * 85c51f124SMoriah Waterland * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95c51f124SMoriah Waterland * or http://www.opensolaris.org/os/licensing. 105c51f124SMoriah Waterland * See the License for the specific language governing permissions 115c51f124SMoriah Waterland * and limitations under the License. 125c51f124SMoriah Waterland * 135c51f124SMoriah Waterland * When distributing Covered Code, include this CDDL HEADER in each 145c51f124SMoriah Waterland * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155c51f124SMoriah Waterland * If applicable, add the following below this CDDL HEADER, with the 165c51f124SMoriah Waterland * fields enclosed by brackets "[]" replaced with your own identifying 175c51f124SMoriah Waterland * information: Portions Copyright [yyyy] [name of copyright owner] 185c51f124SMoriah Waterland * 195c51f124SMoriah Waterland * CDDL HEADER END 205c51f124SMoriah Waterland */ 215c51f124SMoriah Waterland 225c51f124SMoriah Waterland /* 23*214c2196SCasper H.S. Dik * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 245c51f124SMoriah Waterland */ 255c51f124SMoriah Waterland 265c51f124SMoriah Waterland /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 275c51f124SMoriah Waterland /* All Rights Reserved */ 285c51f124SMoriah Waterland 295c51f124SMoriah Waterland 305c51f124SMoriah Waterland #include <stdio.h> 315c51f124SMoriah Waterland #include <fcntl.h> 325c51f124SMoriah Waterland #include <sys/types.h> 335c51f124SMoriah Waterland #include <sys/param.h> 345c51f124SMoriah Waterland #include <sys/sysmacros.h> 355c51f124SMoriah Waterland #include <string.h> 365c51f124SMoriah Waterland #include <strings.h> 375c51f124SMoriah Waterland #include <sys/wait.h> 385c51f124SMoriah Waterland #include <sys/stat.h> 395c51f124SMoriah Waterland #include <sys/mman.h> 405c51f124SMoriah Waterland #include <sys/statvfs.h> 415c51f124SMoriah Waterland #include <signal.h> 425c51f124SMoriah Waterland #include <limits.h> 435c51f124SMoriah Waterland #include <errno.h> 445c51f124SMoriah Waterland #include <fcntl.h> 455c51f124SMoriah Waterland #include <stdlib.h> 465c51f124SMoriah Waterland #include <unistd.h> 475c51f124SMoriah Waterland #include <time.h> 485c51f124SMoriah Waterland #include <errno.h> 495c51f124SMoriah Waterland #include <pkglocs.h> 505c51f124SMoriah Waterland #include <locale.h> 515c51f124SMoriah Waterland #include <libintl.h> 525c51f124SMoriah Waterland #include <pkglib.h> 535c51f124SMoriah Waterland #include "libinst.h" 545c51f124SMoriah Waterland #include "libadm.h" 555c51f124SMoriah Waterland 5662224350SCasper H.S. Dik #define LOCKFILE ".pkg.lock.client" 5762224350SCasper H.S. Dik #define LOCKFILESERV ".pkg.lock" 5862224350SCasper H.S. Dik 595c51f124SMoriah Waterland #define LOCKWAIT 10 /* seconds between retries */ 605c51f124SMoriah Waterland #define LOCKRETRY 20 /* number of retries for a DB lock */ 615c51f124SMoriah Waterland 6262224350SCasper H.S. Dik #define ERR_COMMIT "WARNING: unable to commit contents database update" 635c51f124SMoriah Waterland #define ERR_NOCLOSE "WARNING: unable to close <%s>" 645c51f124SMoriah Waterland #define ERR_NOUNLINK_LATENT "WARNING: unable to unlink latent <%s>" 655c51f124SMoriah Waterland #define ERR_LINK_FAIL "link(%s, %s) failed (errno %d)" 665c51f124SMoriah Waterland #define ERR_NORENAME_CONTENTS "unable to establish contents file <%s> "\ 675c51f124SMoriah Waterland "from <%s>" 685c51f124SMoriah Waterland #define ERR_RENAME_FAIL "rename(%s, %s) failed (errno %d)" 695c51f124SMoriah Waterland #define ERR_RESTORE_FAIL "attempt to restore <%s> failed" 705c51f124SMoriah Waterland #define ERR_NOUNLINK "WARNING: unable to unlink <%s>" 715c51f124SMoriah Waterland #define ERR_FCLOSE_FAIL "fclose failed (errno %d)" 725c51f124SMoriah Waterland #define ERR_ERRNO "(errno %d: %s)" 735c51f124SMoriah Waterland #define ERR_NOTMPOPEN "unable to open temporary contents file image" 745c51f124SMoriah Waterland #define ERR_CFBACK "Not enough space to backup <%s>" 755c51f124SMoriah Waterland #define ERR_CREAT_CONT "unable to create contents file <%s>: %s" 765c51f124SMoriah Waterland #define ERR_ACCESS_CONT "unable to access contents file <%s>: %s" 775c51f124SMoriah Waterland #define ERR_CFBACK1 "Need=%llu blocks, Available=%llu blocks " \ 785c51f124SMoriah Waterland "(block size=%d)" 795c51f124SMoriah Waterland #define ERR_NOCFILE "unable to locate contents file <%s>" 805c51f124SMoriah Waterland #define ERR_NOROPEN "unable to open <%s> for reading" 815c51f124SMoriah Waterland #define ERR_NOOPEN "unable to open <%s> for writing" 825c51f124SMoriah Waterland #define ERR_NOSTAT "unable to stat contents file <%s>" 835c51f124SMoriah Waterland #define ERR_NOSTATV "statvfs(%s) failed" 845c51f124SMoriah Waterland #define ERR_NOUPD "unable to update contents file" 855c51f124SMoriah Waterland #define ERR_DRCONTCP "unable to copy contents file to <%s>" 865c51f124SMoriah Waterland 875c51f124SMoriah Waterland #define MSG_XWTING "NOTE: Waiting for exclusive access to the package " \ 885c51f124SMoriah Waterland "database." 895c51f124SMoriah Waterland #define MSG_NOLOCK "NOTE: Couldn't lock the package database." 905c51f124SMoriah Waterland 915c51f124SMoriah Waterland #define ERR_NOLOCK "Database lock failed." 925c51f124SMoriah Waterland #define ERR_OPLOCK "unable to open lock file <%s>." 935c51f124SMoriah Waterland #define ERR_MKLOCK "unable to create lock file <%s>." 945c51f124SMoriah Waterland #define ERR_LCKREM "unable to lock package database - remote host " \ 955c51f124SMoriah Waterland "unavailable." 965c51f124SMoriah Waterland #define ERR_BADLCK "unable to lock package database - unknown error." 975c51f124SMoriah Waterland #define ERR_DEADLCK "unable to lock package database - deadlock condition." 985c51f124SMoriah Waterland #define ERR_TMOUT "unable to lock package database - too many retries." 995c51f124SMoriah Waterland #define ERR_CFDIR "unable to locate contents file directory" 1005c51f124SMoriah Waterland 1015c51f124SMoriah Waterland static int active_lock; 1025c51f124SMoriah Waterland static int lock_fd; /* fd of LOCKFILE. */ 1035c51f124SMoriah Waterland static char *pkgadm_dir; 1045c51f124SMoriah Waterland 10562224350SCasper H.S. Dik int pkgWlock(int verbose); 1065c51f124SMoriah Waterland static int pkgWunlock(void); 1075c51f124SMoriah Waterland 1085c51f124SMoriah Waterland /* forward declarations */ 1095c51f124SMoriah Waterland 1105c51f124SMoriah Waterland int relslock(void); 1115c51f124SMoriah Waterland 1125c51f124SMoriah Waterland /*ARGSUSED*/ 1135c51f124SMoriah Waterland static void 1145c51f124SMoriah Waterland do_alarm(int n) 1155c51f124SMoriah Waterland { 1165c51f124SMoriah Waterland (void) signal(SIGALRM, SIG_IGN); 1175c51f124SMoriah Waterland (void) signal(SIGALRM, do_alarm); 1185c51f124SMoriah Waterland (void) alarm(LOCKWAIT); 1195c51f124SMoriah Waterland } 1205c51f124SMoriah Waterland 1215c51f124SMoriah Waterland /* 1225c51f124SMoriah Waterland * Point packaging to the appropriate contents file. This is primarily used 1235c51f124SMoriah Waterland * to establish a dryrun contents file. If the malloc() doesn't work, this 1245c51f124SMoriah Waterland * returns 99 (internal error), else 0. 1255c51f124SMoriah Waterland */ 1265c51f124SMoriah Waterland int 1275c51f124SMoriah Waterland set_cfdir(char *cfdir) 1285c51f124SMoriah Waterland { 1295c51f124SMoriah Waterland char realcf[PATH_MAX]; 1305c51f124SMoriah Waterland char tmpcf[PATH_MAX]; 1315c51f124SMoriah Waterland int status; 1325c51f124SMoriah Waterland 1335c51f124SMoriah Waterland if (cfdir == NULL) { 1345c51f124SMoriah Waterland pkgadm_dir = get_PKGADM(); 1355c51f124SMoriah Waterland return (0); 1365c51f124SMoriah Waterland } 1375c51f124SMoriah Waterland 1385c51f124SMoriah Waterland if ((pkgadm_dir = strdup(cfdir)) == NULL) { 1395c51f124SMoriah Waterland return (99); 1405c51f124SMoriah Waterland } 1415c51f124SMoriah Waterland 1425c51f124SMoriah Waterland (void) snprintf(tmpcf, sizeof (tmpcf), "%s/contents", pkgadm_dir); 1435c51f124SMoriah Waterland 1445c51f124SMoriah Waterland /* 1455c51f124SMoriah Waterland * return if a temporary contents file already exists - 1465c51f124SMoriah Waterland * assume it is from a prior package in this series. 1475c51f124SMoriah Waterland */ 1485c51f124SMoriah Waterland 1495c51f124SMoriah Waterland if (access(tmpcf, F_OK) == 0) { 1505c51f124SMoriah Waterland return (0); 1515c51f124SMoriah Waterland } 1525c51f124SMoriah Waterland 1535c51f124SMoriah Waterland /* 1545c51f124SMoriah Waterland * no temporary contents file exists - create one. 1555c51f124SMoriah Waterland */ 1565c51f124SMoriah Waterland 1575c51f124SMoriah Waterland (void) snprintf(realcf, sizeof (realcf), "%s/contents", get_PKGADM()); 1585c51f124SMoriah Waterland 1595c51f124SMoriah Waterland /* 1605c51f124SMoriah Waterland * If there's a contents file there already, copy it 16162224350SCasper H.S. Dik * over, otherwise initialize one. Make sure that the 16262224350SCasper H.S. Dik * server, if running, flushes the contents file. 1635c51f124SMoriah Waterland */ 1645c51f124SMoriah Waterland 16562224350SCasper H.S. Dik (void) pkgsync(NULL, get_PKGADM(), B_FALSE); 16662224350SCasper H.S. Dik 1675c51f124SMoriah Waterland /* create new contents file if one does not already exist */ 1685c51f124SMoriah Waterland 1695c51f124SMoriah Waterland if (access(realcf, F_OK) != 0) { 1705c51f124SMoriah Waterland int n; 1715c51f124SMoriah Waterland 1725c51f124SMoriah Waterland n = open(tmpcf, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644); 1735c51f124SMoriah Waterland if (n < 0) { 1745c51f124SMoriah Waterland progerr(gettext(ERR_CREAT_CONT), tmpcf, 1755c51f124SMoriah Waterland strerror(errno)); 1765c51f124SMoriah Waterland return (99); 1775c51f124SMoriah Waterland } 1785c51f124SMoriah Waterland (void) close(n); 1795c51f124SMoriah Waterland } else { 1805c51f124SMoriah Waterland 1815c51f124SMoriah Waterland /* contents file exists, save in pkgadm-dir */ 1825c51f124SMoriah Waterland 1835c51f124SMoriah Waterland status = copyf(realcf, tmpcf, (time_t)0); 1845c51f124SMoriah Waterland if (status != 0) { 1855c51f124SMoriah Waterland progerr(gettext(ERR_DRCONTCP), tmpcf); 1865c51f124SMoriah Waterland return (99); 1875c51f124SMoriah Waterland } 1885c51f124SMoriah Waterland } 1895c51f124SMoriah Waterland 1905c51f124SMoriah Waterland return (0); 1915c51f124SMoriah Waterland } 1925c51f124SMoriah Waterland 1935c51f124SMoriah Waterland /* 1945c51f124SMoriah Waterland * This function installs the database lock, opens the contents file for 1955c51f124SMoriah Waterland * reading and creates and opens the temporary contents file for read/write. 1965c51f124SMoriah Waterland * It returns 1 if successful, 0 otherwise. 1975c51f124SMoriah Waterland */ 1985c51f124SMoriah Waterland int 19962224350SCasper H.S. Dik ocfile(PKGserver *server, VFP_T **r_tmpvfp, fsblkcnt_t map_blks) 2005c51f124SMoriah Waterland { 201*214c2196SCasper H.S. Dik struct stat64 statb, statl; 2025c51f124SMoriah Waterland struct statvfs64 svfsb; 2035c51f124SMoriah Waterland fsblkcnt_t free_blocks; 2045c51f124SMoriah Waterland fsblkcnt_t need_blocks; 205*214c2196SCasper H.S. Dik fsblkcnt_t log_blocks; 2065c51f124SMoriah Waterland VFP_T *tmpvfp = (VFP_T *)NULL; 2075c51f124SMoriah Waterland char contents[PATH_MAX]; 208*214c2196SCasper H.S. Dik char logfile[PATH_MAX]; 2095c51f124SMoriah Waterland int n; 21062224350SCasper H.S. Dik off_t cdiff_alloc; 21162224350SCasper H.S. Dik PKGserver newserver; 2125c51f124SMoriah Waterland 2135c51f124SMoriah Waterland /* establish package administration contents directory location */ 2145c51f124SMoriah Waterland 2155c51f124SMoriah Waterland if (pkgadm_dir == NULL) { 2165c51f124SMoriah Waterland if (set_cfdir(NULL) != 0) { 2175c51f124SMoriah Waterland progerr(gettext(ERR_CFDIR)); 2185c51f124SMoriah Waterland return (0); 2195c51f124SMoriah Waterland } 2205c51f124SMoriah Waterland } 2215c51f124SMoriah Waterland 2225c51f124SMoriah Waterland /* Lock the file for exclusive access */ 2235c51f124SMoriah Waterland 2245c51f124SMoriah Waterland if (!pkgWlock(1)) { 2255c51f124SMoriah Waterland progerr(gettext(ERR_NOLOCK)); 2265c51f124SMoriah Waterland return (0); 2275c51f124SMoriah Waterland } 2285c51f124SMoriah Waterland 22962224350SCasper H.S. Dik if (*server != NULL) { 23062224350SCasper H.S. Dik vfpTruncate(*r_tmpvfp); 23162224350SCasper H.S. Dik (void) vfpClearModified(*r_tmpvfp); 2325c51f124SMoriah Waterland 23362224350SCasper H.S. Dik return (1); 2345c51f124SMoriah Waterland } 2355c51f124SMoriah Waterland 23662224350SCasper H.S. Dik newserver = pkgopenserver(NULL, pkgadm_dir, B_FALSE); 23762224350SCasper H.S. Dik 23862224350SCasper H.S. Dik /* The error has been reported. */ 23962224350SCasper H.S. Dik if (newserver == NULL) 2405c51f124SMoriah Waterland return (0); 24162224350SCasper H.S. Dik 24262224350SCasper H.S. Dik /* reset return VFP/FILE pointers */ 24362224350SCasper H.S. Dik 24462224350SCasper H.S. Dik (*r_tmpvfp) = (VFP_T *)NULL; 24562224350SCasper H.S. Dik 24662224350SCasper H.S. Dik /* determine path to the primary contents file */ 24762224350SCasper H.S. Dik (void) snprintf(contents, sizeof (contents), "%s/contents", pkgadm_dir); 2485c51f124SMoriah Waterland 2495c51f124SMoriah Waterland /* 2505c51f124SMoriah Waterland * Check and see if there is enough space for the packaging commands 2515c51f124SMoriah Waterland * to back up the contents file, if there is not, then do not allow 2525c51f124SMoriah Waterland * execution to continue by failing the ocfile() call. 2535c51f124SMoriah Waterland */ 2545c51f124SMoriah Waterland 2555c51f124SMoriah Waterland /* Get the contents file size */ 2565c51f124SMoriah Waterland 25762224350SCasper H.S. Dik if (stat64(contents, &statb) == -1) { 2585c51f124SMoriah Waterland int lerrno = errno; 2595c51f124SMoriah Waterland 26062224350SCasper H.S. Dik progerr(gettext(ERR_NOCFILE), contents); 2615c51f124SMoriah Waterland logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno)); 26262224350SCasper H.S. Dik pkgcloseserver(newserver); 2635c51f124SMoriah Waterland return (0); 2645c51f124SMoriah Waterland } 2655c51f124SMoriah Waterland 2665c51f124SMoriah Waterland /* Get the filesystem space */ 2675c51f124SMoriah Waterland 26862224350SCasper H.S. Dik if (statvfs64(contents, &svfsb) == -1) { 2695c51f124SMoriah Waterland int lerrno = errno; 2705c51f124SMoriah Waterland 2715c51f124SMoriah Waterland progerr(gettext(ERR_NOSTATV), contents); 2725c51f124SMoriah Waterland logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno)); 27362224350SCasper H.S. Dik pkgcloseserver(newserver); 2745c51f124SMoriah Waterland return (0); 2755c51f124SMoriah Waterland } 2765c51f124SMoriah Waterland 2775c51f124SMoriah Waterland free_blocks = (((fsblkcnt_t)svfsb.f_frsize > 0) ? 2785c51f124SMoriah Waterland howmany(svfsb.f_frsize, DEV_BSIZE) : 2795c51f124SMoriah Waterland howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bfree; 2805c51f124SMoriah Waterland 281*214c2196SCasper H.S. Dik /* determine blocks used by the logfile */ 282*214c2196SCasper H.S. Dik (void) snprintf(logfile, sizeof (logfile), "%s/" PKGLOG, pkgadm_dir); 28362224350SCasper H.S. Dik 284*214c2196SCasper H.S. Dik if (stat64(logfile, &statl) == -1) 285*214c2196SCasper H.S. Dik log_blocks = 0; 286*214c2196SCasper H.S. Dik else 287*214c2196SCasper H.S. Dik log_blocks = nblk(statl.st_size, svfsb.f_bsize, svfsb.f_frsize); 2885c51f124SMoriah Waterland 2895c51f124SMoriah Waterland /* 2905c51f124SMoriah Waterland * Calculate the number of blocks we need to be able to operate on 291*214c2196SCasper H.S. Dik * the contents file and the log file. 292*214c2196SCasper H.S. Dik * When adding a package (map_blks > 0), we add the size of the 293*214c2196SCasper H.S. Dik * pkgmap file times 1.5 as the pkgmap is a bit smaller then the 294*214c2196SCasper H.S. Dik * lines added to the contents file. That data is written both to 295*214c2196SCasper H.S. Dik * the new contents file and the log file (2 * 1.5 * map_blks). 296*214c2196SCasper H.S. Dik * The new contents file is limited by the size of the current 297*214c2196SCasper H.S. Dik * contents file and the increased log file. 298*214c2196SCasper H.S. Dik * If we're removing a package, then the log might grow to the size 299*214c2196SCasper H.S. Dik * of the full contents file but then the new contents file would 300*214c2196SCasper H.S. Dik * be zero and so we only need to add the size of the contents file. 3015c51f124SMoriah Waterland */ 302*214c2196SCasper H.S. Dik need_blocks = map_blks * 3 + 303*214c2196SCasper H.S. Dik /* Current log file */ 304*214c2196SCasper H.S. Dik log_blocks + 305*214c2196SCasper H.S. Dik /* Current contents file */ 3065c51f124SMoriah Waterland nblk(statb.st_size, svfsb.f_bsize, svfsb.f_frsize); 3075c51f124SMoriah Waterland 3085c51f124SMoriah Waterland if ((need_blocks + 10) > free_blocks) { 3095c51f124SMoriah Waterland progerr(gettext(ERR_CFBACK), contents); 3105c51f124SMoriah Waterland progerr(gettext(ERR_CFBACK1), need_blocks, free_blocks, 3115c51f124SMoriah Waterland DEV_BSIZE); 31262224350SCasper H.S. Dik pkgcloseserver(newserver); 3135c51f124SMoriah Waterland return (0); 3145c51f124SMoriah Waterland } 3155c51f124SMoriah Waterland 3165c51f124SMoriah Waterland /* 3175c51f124SMoriah Waterland * open the temporary contents file without a path name - this causes 3185c51f124SMoriah Waterland * the "vfp" to be opened on in-memory storage only, the size of which 3195c51f124SMoriah Waterland * is set following a successful return - this causes the temporary 3205c51f124SMoriah Waterland * contents file to be maintained in memory only - if no changes are 3215c51f124SMoriah Waterland * made as the primary contents file is processed, the in memory data 3225c51f124SMoriah Waterland * is discarded and not written to the disk. 3235c51f124SMoriah Waterland */ 3245c51f124SMoriah Waterland 3255c51f124SMoriah Waterland if (vfpOpen(&tmpvfp, (char *)NULL, "w", VFP_NONE) != 0) { 3265c51f124SMoriah Waterland int lerrno = errno; 3275c51f124SMoriah Waterland 3285c51f124SMoriah Waterland progerr(gettext(ERR_NOTMPOPEN)); 3295c51f124SMoriah Waterland logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno)); 33062224350SCasper H.S. Dik pkgcloseserver(newserver); 3315c51f124SMoriah Waterland return (0); 3325c51f124SMoriah Waterland } 3335c51f124SMoriah Waterland 3345c51f124SMoriah Waterland /* 3355c51f124SMoriah Waterland * set size of allocation for temporary contents file - this sets the 3365c51f124SMoriah Waterland * size of the in-memory buffer associated with the open vfp. 33762224350SCasper H.S. Dik * We only store the new and changed entries. 33862224350SCasper H.S. Dik * We allocate memory depending on the size of the pkgmap; it's not 33962224350SCasper H.S. Dik * completely right but <some value + * 1.5 * map_blks * DEV_BSIZE> 34062224350SCasper H.S. Dik * seems fine (an install adds the size if the name of the package.) 3415c51f124SMoriah Waterland */ 3425c51f124SMoriah Waterland 34362224350SCasper H.S. Dik cdiff_alloc = map_blks * DEV_BSIZE; 34462224350SCasper H.S. Dik cdiff_alloc += cdiff_alloc/2; 34562224350SCasper H.S. Dik if (cdiff_alloc < 1000000) 34662224350SCasper H.S. Dik cdiff_alloc += 1000000; 34762224350SCasper H.S. Dik 34862224350SCasper H.S. Dik if (vfpSetSize(tmpvfp, cdiff_alloc) != 0) { 3495c51f124SMoriah Waterland int lerrno = errno; 3505c51f124SMoriah Waterland 3515c51f124SMoriah Waterland progerr(gettext(ERR_NOTMPOPEN)); 3525c51f124SMoriah Waterland logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno)); 3535c51f124SMoriah Waterland (void) vfpClose(&tmpvfp); 35462224350SCasper H.S. Dik pkgcloseserver(newserver); 3555c51f124SMoriah Waterland return (0); 3565c51f124SMoriah Waterland } 3575c51f124SMoriah Waterland 35862224350SCasper H.S. Dik /* set return ->s to open server/vfps */ 3595c51f124SMoriah Waterland 3605c51f124SMoriah Waterland (*r_tmpvfp) = tmpvfp; 36162224350SCasper H.S. Dik *server = newserver; 3625c51f124SMoriah Waterland 3635c51f124SMoriah Waterland return (1); /* All OK */ 3645c51f124SMoriah Waterland } 3655c51f124SMoriah Waterland 3665c51f124SMoriah Waterland /* 3675c51f124SMoriah Waterland * This is a simple open and lock of the contents file. It doesn't create a 3685c51f124SMoriah Waterland * temporary contents file and it doesn't need to do any space checking. 3695c51f124SMoriah Waterland * Returns 1 for OK and 0 for "didn't do it". 3705c51f124SMoriah Waterland */ 3715c51f124SMoriah Waterland int 37262224350SCasper H.S. Dik socfile(PKGserver *server, boolean_t quiet) 3735c51f124SMoriah Waterland { 3745c51f124SMoriah Waterland char contents[PATH_MAX]; 37562224350SCasper H.S. Dik boolean_t readonly = B_FALSE; 37662224350SCasper H.S. Dik PKGserver newserver; 3775c51f124SMoriah Waterland 3785c51f124SMoriah Waterland if (pkgadm_dir == NULL) { 3795c51f124SMoriah Waterland if (set_cfdir(NULL) != 0) { 3805c51f124SMoriah Waterland progerr(gettext(ERR_CFDIR)); 3815c51f124SMoriah Waterland return (0); 3825c51f124SMoriah Waterland } 3835c51f124SMoriah Waterland } 3845c51f124SMoriah Waterland 3855c51f124SMoriah Waterland /* 3865c51f124SMoriah Waterland * Lock the database for exclusive access, but don't make a fuss if 3875c51f124SMoriah Waterland * it fails (user may not be root and the .pkg.lock file may not 3885c51f124SMoriah Waterland * exist yet). 3895c51f124SMoriah Waterland */ 3905c51f124SMoriah Waterland 3915c51f124SMoriah Waterland if (!pkgWlock(0)) { 39262224350SCasper H.S. Dik if (!quiet) 3935c51f124SMoriah Waterland logerr(gettext(MSG_NOLOCK)); 39462224350SCasper H.S. Dik readonly = B_TRUE; 3955c51f124SMoriah Waterland } 3965c51f124SMoriah Waterland 39762224350SCasper H.S. Dik newserver = pkgopenserver(NULL, pkgadm_dir, readonly); 39862224350SCasper H.S. Dik if (newserver == NULL) 3995c51f124SMoriah Waterland return (0); 4005c51f124SMoriah Waterland 40162224350SCasper H.S. Dik *server = newserver; 4025c51f124SMoriah Waterland return (1); 4035c51f124SMoriah Waterland } 4045c51f124SMoriah Waterland 4055c51f124SMoriah Waterland /* 4065c51f124SMoriah Waterland * Name: swapcfile 4075c51f124SMoriah Waterland * Description: This function closes both the current and temporary contents 4085c51f124SMoriah Waterland * files specified, and conditionally replaces the old transitory 4095c51f124SMoriah Waterland * contents file with the newly updated temporary contents file. 4105c51f124SMoriah Waterland * The "ocfile()" or "socfile()" functions must be called to re- 4115c51f124SMoriah Waterland * open the real contents file for processing. 41262224350SCasper H.S. Dik * Arguments: PKGserver - handle to the package database 4135c51f124SMoriah Waterland * a_cfTmpVfp - (VFP_T **) - [RW, *RW] 41462224350SCasper H.S. Dik * This is the VFP associated which contains all the 41562224350SCasper H.S. Dik * modifications to be written back to the database. 4165c51f124SMoriah Waterland * file that is being written to. 4175c51f124SMoriah Waterland * pkginst - (char) - [RO, *RO] 4185c51f124SMoriah Waterland * This is the name of the package being operated on; 4195c51f124SMoriah Waterland * this is used to write the "last modified by xxx" 4205c51f124SMoriah Waterland * comment at the end of the contents file. 4215c51f124SMoriah Waterland * dbchg - (int) - [RO] 4225c51f124SMoriah Waterland * == 0 - the temporary contents file has NOT been changed 4235c51f124SMoriah Waterland * with respect to the real contents file; do not 4245c51f124SMoriah Waterland * update the real contents file with the contents 4255c51f124SMoriah Waterland * of the temporary contents file. 4265c51f124SMoriah Waterland * != 0 - the temporary contetns file HAS been changed with 4275c51f124SMoriah Waterland * respect to the real contents file; DO update the 4285c51f124SMoriah Waterland * real contents file with the contents of the 4295c51f124SMoriah Waterland * temporary contents file. 4305c51f124SMoriah Waterland * Returns: int == RESULT_OK - successful 4315c51f124SMoriah Waterland * == RESULT_WRN - successful with warnings 4325c51f124SMoriah Waterland * == RESULT_ERR - failed with fatal errors - deserves an 4335c51f124SMoriah Waterland * alarming message and a quit() 4345c51f124SMoriah Waterland * NOTES: If dbchg != 0, the contents file is always updated. If dbchg == 0, 4355c51f124SMoriah Waterland * the contents file is updated IF the data is modified indication 4365c51f124SMoriah Waterland * is set on the contents file associated with a_cfTmpVfp. 4375c51f124SMoriah Waterland */ 4385c51f124SMoriah Waterland 4395c51f124SMoriah Waterland int 44062224350SCasper H.S. Dik swapcfile(PKGserver server, VFP_T **a_cfTmpVfp, char *pkginst, int dbchg) 4415c51f124SMoriah Waterland { 4425c51f124SMoriah Waterland char *pe; 4435c51f124SMoriah Waterland char *pl; 4445c51f124SMoriah Waterland char *ps; 4455c51f124SMoriah Waterland char line[256]; 4465c51f124SMoriah Waterland char timeb[BUFSIZ]; 4475c51f124SMoriah Waterland int retval = RESULT_OK; 4485c51f124SMoriah Waterland struct tm *timep; 4495c51f124SMoriah Waterland time_t clock; 4505c51f124SMoriah Waterland 4515c51f124SMoriah Waterland /* normalize pkginst so its never null */ 4525c51f124SMoriah Waterland 4535c51f124SMoriah Waterland if (pkginst == (char *)NULL) { 4545c51f124SMoriah Waterland dbchg = 0; 4555c51f124SMoriah Waterland pkginst = "<unknown>"; 4565c51f124SMoriah Waterland } 4575c51f124SMoriah Waterland 4585c51f124SMoriah Waterland /* 4595c51f124SMoriah Waterland * If no changes were made to the database, checkpoint the temporary 4605c51f124SMoriah Waterland * contents file - if this fails, then just close the file which causes 4615c51f124SMoriah Waterland * the contents file to be reopened and reread if it is needed again 4625c51f124SMoriah Waterland */ 4635c51f124SMoriah Waterland 4645c51f124SMoriah Waterland if ((dbchg == 0) && (vfpGetModified(*a_cfTmpVfp) == 0)) { 4655c51f124SMoriah Waterland (void) pkgWunlock(); /* Free the database lock. */ 4665c51f124SMoriah Waterland return (retval); 4675c51f124SMoriah Waterland } 4685c51f124SMoriah Waterland 4695c51f124SMoriah Waterland /* 4705c51f124SMoriah Waterland * changes made to the current temporary contents file - 4715c51f124SMoriah Waterland * remove any trailing comment lines in the temp contents file, then 4725c51f124SMoriah Waterland * append updated modification info records to temp contents file 4735c51f124SMoriah Waterland */ 4745c51f124SMoriah Waterland 4755c51f124SMoriah Waterland pe = vfpGetCurrCharPtr(*a_cfTmpVfp); /* last char in contents file */ 4765c51f124SMoriah Waterland ps = vfpGetFirstCharPtr(*a_cfTmpVfp); /* 1st char in contents file */ 4775c51f124SMoriah Waterland pl = pe; /* last match is last char in contents file */ 4785c51f124SMoriah Waterland 4795c51f124SMoriah Waterland /* skip past all trailing newlines and null bytes */ 4805c51f124SMoriah Waterland 4815c51f124SMoriah Waterland while ((pe > ps) && ((*pe == '\n') || (*pe == '\0'))) { 4825c51f124SMoriah Waterland pe--; 4835c51f124SMoriah Waterland } 4845c51f124SMoriah Waterland 4855c51f124SMoriah Waterland /* remove trailing comments as long as there are lines in the file */ 4865c51f124SMoriah Waterland 4875c51f124SMoriah Waterland while (pe > ps) { 4885c51f124SMoriah Waterland if (*pe != '\n') { 4895c51f124SMoriah Waterland /* curr char is not newline: backup one byte */ 4905c51f124SMoriah Waterland pl = pe--; 4915c51f124SMoriah Waterland } else if (*pl != '#') { 4925c51f124SMoriah Waterland /* curr char is newline next char not comment break */ 4935c51f124SMoriah Waterland break; 4945c51f124SMoriah Waterland } else { 4955c51f124SMoriah Waterland /* curr char is newline next char is comment - remove */ 4965c51f124SMoriah Waterland *pl = '\0'; 4975c51f124SMoriah Waterland vfpSetLastCharPtr(*a_cfTmpVfp, pl); 4985c51f124SMoriah Waterland pe--; 4995c51f124SMoriah Waterland } 5005c51f124SMoriah Waterland } 5015c51f124SMoriah Waterland 5025c51f124SMoriah Waterland /* create two update comment lines */ 5035c51f124SMoriah Waterland 5045c51f124SMoriah Waterland (void) time(&clock); 5055c51f124SMoriah Waterland timep = localtime(&clock); 5065c51f124SMoriah Waterland 5075c51f124SMoriah Waterland (void) strftime(timeb, sizeof (timeb), "%c\n", timep); 5085c51f124SMoriah Waterland (void) snprintf(line, sizeof (line), 5095c51f124SMoriah Waterland gettext("# Last modified by %s for %s package\n# %s"), 5105c51f124SMoriah Waterland get_prog_name(), pkginst, timeb); 5115c51f124SMoriah Waterland vfpPuts(*a_cfTmpVfp, line); 5125c51f124SMoriah Waterland 5135c51f124SMoriah Waterland /* commit temporary contents file bytes to storage */ 5145c51f124SMoriah Waterland 51562224350SCasper H.S. Dik if (pkgservercommitfile(*a_cfTmpVfp, server) != 0) { 5165c51f124SMoriah Waterland int lerrno = errno; 5175c51f124SMoriah Waterland 51862224350SCasper H.S. Dik logerr(gettext(ERR_COMMIT)); 5195c51f124SMoriah Waterland vfpClose(a_cfTmpVfp); 52062224350SCasper H.S. Dik pkgcloseserver(server); 5215c51f124SMoriah Waterland (void) pkgWunlock(); /* Free the database lock. */ 5225c51f124SMoriah Waterland return (RESULT_ERR); 5235c51f124SMoriah Waterland } 5245c51f124SMoriah Waterland 5255c51f124SMoriah Waterland return (relslock() == 0 ? RESULT_ERR : retval); 5265c51f124SMoriah Waterland } 5275c51f124SMoriah Waterland 5285c51f124SMoriah Waterland /* This function releases the lock on the package database. */ 5295c51f124SMoriah Waterland int 5305c51f124SMoriah Waterland relslock(void) 5315c51f124SMoriah Waterland { 5325c51f124SMoriah Waterland /* 5335c51f124SMoriah Waterland * This closes the contents file and releases the lock. 5345c51f124SMoriah Waterland */ 5355c51f124SMoriah Waterland if (!pkgWunlock()) { 5365c51f124SMoriah Waterland int lerrno = errno; 5375c51f124SMoriah Waterland 5385c51f124SMoriah Waterland progerr(gettext(ERR_NOUPD)); 5395c51f124SMoriah Waterland logerr(gettext(ERR_FCLOSE_FAIL), lerrno); 5405c51f124SMoriah Waterland return (0); 5415c51f124SMoriah Waterland } 5425c51f124SMoriah Waterland return (1); 5435c51f124SMoriah Waterland } 5445c51f124SMoriah Waterland 5455c51f124SMoriah Waterland /* 5465c51f124SMoriah Waterland * This function attempts to lock the package database. It returns 1 on 5475c51f124SMoriah Waterland * success, 0 on failure. The positive logic verbose flag determines whether 5485c51f124SMoriah Waterland * or not the function displays the error message upon failure. 5495c51f124SMoriah Waterland */ 55062224350SCasper H.S. Dik int 5515c51f124SMoriah Waterland pkgWlock(int verbose) { 5525c51f124SMoriah Waterland int retry_cnt, retval; 5535c51f124SMoriah Waterland char lockpath[PATH_MAX]; 5545c51f124SMoriah Waterland 5555c51f124SMoriah Waterland active_lock = 0; 5565c51f124SMoriah Waterland 5575c51f124SMoriah Waterland (void) snprintf(lockpath, sizeof (lockpath), 5585c51f124SMoriah Waterland "%s/%s", pkgadm_dir, LOCKFILE); 5595c51f124SMoriah Waterland 5605c51f124SMoriah Waterland retry_cnt = LOCKRETRY; 5615c51f124SMoriah Waterland 5625c51f124SMoriah Waterland /* 5635c51f124SMoriah Waterland * If the lock file is not present, create it. The mode is set to 5645c51f124SMoriah Waterland * allow any process to lock the database, that's because pkgchk may 5655c51f124SMoriah Waterland * be run by a non-root user. 5665c51f124SMoriah Waterland */ 5675c51f124SMoriah Waterland if (access(lockpath, F_OK) == -1) { 5685c51f124SMoriah Waterland lock_fd = open(lockpath, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644); 5695c51f124SMoriah Waterland if (lock_fd < 0) { 5705c51f124SMoriah Waterland if (verbose) 5715c51f124SMoriah Waterland progerr(gettext(ERR_MKLOCK), lockpath); 5725c51f124SMoriah Waterland return (0); 5735c51f124SMoriah Waterland } else { 5745c51f124SMoriah Waterland (void) fchmod(lock_fd, 0644); /* force perms. */ 5755c51f124SMoriah Waterland } 5765c51f124SMoriah Waterland } else { 5775c51f124SMoriah Waterland if ((lock_fd = open(lockpath, O_RDWR)) == -1) { 5785c51f124SMoriah Waterland if (verbose) 5795c51f124SMoriah Waterland progerr(gettext(ERR_OPLOCK), lockpath); 5805c51f124SMoriah Waterland return (0); 5815c51f124SMoriah Waterland } 5825c51f124SMoriah Waterland } 5835c51f124SMoriah Waterland 5845c51f124SMoriah Waterland (void) signal(SIGALRM, do_alarm); 5855c51f124SMoriah Waterland (void) alarm(LOCKWAIT); 5865c51f124SMoriah Waterland 5875c51f124SMoriah Waterland do { 5885c51f124SMoriah Waterland if (lockf(lock_fd, F_LOCK, 0)) { 5895c51f124SMoriah Waterland if (errno == EAGAIN || errno == EINTR) 5905c51f124SMoriah Waterland logerr(gettext(MSG_XWTING)); 5915c51f124SMoriah Waterland else if (errno == ECOMM) { 5925c51f124SMoriah Waterland logerr(gettext(ERR_LCKREM)); 5935c51f124SMoriah Waterland retval = 0; 5945c51f124SMoriah Waterland break; 5955c51f124SMoriah Waterland } else if (errno == EBADF) { 5965c51f124SMoriah Waterland logerr(gettext(ERR_BADLCK)); 5975c51f124SMoriah Waterland retval = 0; 5985c51f124SMoriah Waterland break; 5995c51f124SMoriah Waterland } else if (errno == EDEADLK) { 6005c51f124SMoriah Waterland logerr(gettext(ERR_DEADLCK)); 6015c51f124SMoriah Waterland retval = 0; 6025c51f124SMoriah Waterland break; 6035c51f124SMoriah Waterland } 6045c51f124SMoriah Waterland } else { 6055c51f124SMoriah Waterland active_lock = 1; 6065c51f124SMoriah Waterland retval = 1; 6075c51f124SMoriah Waterland break; 6085c51f124SMoriah Waterland } 6095c51f124SMoriah Waterland } while (retry_cnt--); 6105c51f124SMoriah Waterland 6115c51f124SMoriah Waterland (void) signal(SIGALRM, SIG_IGN); 6125c51f124SMoriah Waterland 6135c51f124SMoriah Waterland if (retval == 0) 6145c51f124SMoriah Waterland { 6155c51f124SMoriah Waterland if (retry_cnt == -1) { 6165c51f124SMoriah Waterland logerr(gettext(ERR_TMOUT)); 6175c51f124SMoriah Waterland } 6185c51f124SMoriah Waterland 6195c51f124SMoriah Waterland (void) pkgWunlock(); /* close the lockfile. */ 6205c51f124SMoriah Waterland } 6215c51f124SMoriah Waterland 6225c51f124SMoriah Waterland return (retval); 6235c51f124SMoriah Waterland } 6245c51f124SMoriah Waterland 6255c51f124SMoriah Waterland /* 6265c51f124SMoriah Waterland * Release the lock on the package database. Returns 1 on success, 0 on 6275c51f124SMoriah Waterland * failure. 6285c51f124SMoriah Waterland */ 6295c51f124SMoriah Waterland static int 6305c51f124SMoriah Waterland pkgWunlock(void) { 6315c51f124SMoriah Waterland if (active_lock) { 6325c51f124SMoriah Waterland active_lock = 0; 6335c51f124SMoriah Waterland if (close(lock_fd)) 6345c51f124SMoriah Waterland return (0); 6355c51f124SMoriah Waterland else 6365c51f124SMoriah Waterland return (1); 6375c51f124SMoriah Waterland } else 6385c51f124SMoriah Waterland return (1); 6395c51f124SMoriah Waterland } 6405c51f124SMoriah Waterland 6415c51f124SMoriah Waterland /* 6425c51f124SMoriah Waterland * This function verifies that the contents file is in place. 6435c51f124SMoriah Waterland * returns 1 - if it exists 6445c51f124SMoriah Waterland * returns 0 - if it does not exist 6455c51f124SMoriah Waterland */ 6465c51f124SMoriah Waterland int 6475c51f124SMoriah Waterland iscfile(void) 6485c51f124SMoriah Waterland { 6495c51f124SMoriah Waterland char contents[PATH_MAX]; 6505c51f124SMoriah Waterland 6515c51f124SMoriah Waterland (void) snprintf(contents, PATH_MAX, "%s/contents", get_PKGADM()); 6525c51f124SMoriah Waterland 6535c51f124SMoriah Waterland return (access(contents, F_OK) == 0 ? 1 : 0); 6545c51f124SMoriah Waterland } 6555c51f124SMoriah Waterland 6565c51f124SMoriah Waterland /* 6575c51f124SMoriah Waterland * This function verifies that the contents file is in place. If it is - no 6585c51f124SMoriah Waterland * change. If it isn't - this creates it. 6595c51f124SMoriah Waterland * Returns: == 0 : failure 6605c51f124SMoriah Waterland * != 0 : success 6615c51f124SMoriah Waterland */ 6625c51f124SMoriah Waterland 6635c51f124SMoriah Waterland int 6645c51f124SMoriah Waterland vcfile(void) 6655c51f124SMoriah Waterland { 6665c51f124SMoriah Waterland int lerrno; 6675c51f124SMoriah Waterland int fd; 6685c51f124SMoriah Waterland char contents[PATH_MAX]; 6695c51f124SMoriah Waterland 6705c51f124SMoriah Waterland /* 6715c51f124SMoriah Waterland * create full path to contents file 6725c51f124SMoriah Waterland */ 6735c51f124SMoriah Waterland 6745c51f124SMoriah Waterland (void) snprintf(contents, sizeof (contents), 6755c51f124SMoriah Waterland "%s/contents", get_PKGADM()); 6765c51f124SMoriah Waterland 6775c51f124SMoriah Waterland /* 6785c51f124SMoriah Waterland * Attempt to create the file - will only be successful 6795c51f124SMoriah Waterland * if the file does not currently exist. 6805c51f124SMoriah Waterland */ 6815c51f124SMoriah Waterland 6825c51f124SMoriah Waterland fd = open(contents, O_WRONLY | O_CREAT | O_EXCL, 0644); 6835c51f124SMoriah Waterland if (fd >= 0) { 6845c51f124SMoriah Waterland /* 6855c51f124SMoriah Waterland * Contents file wasn't there, but is now. 6865c51f124SMoriah Waterland */ 6875c51f124SMoriah Waterland 6885c51f124SMoriah Waterland echo(gettext("## Software contents file initialized")); 6895c51f124SMoriah Waterland (void) close(fd); 6905c51f124SMoriah Waterland return (1); /* success */ 6915c51f124SMoriah Waterland } 6925c51f124SMoriah Waterland 6935c51f124SMoriah Waterland /* 6945c51f124SMoriah Waterland * Could not create the file - it may exist or there may be 6955c51f124SMoriah Waterland * permissions issues - find out and act accordingly. 6965c51f124SMoriah Waterland */ 6975c51f124SMoriah Waterland 6985c51f124SMoriah Waterland lerrno = errno; 6995c51f124SMoriah Waterland 7005c51f124SMoriah Waterland /* success if error is 'file exists' */ 7015c51f124SMoriah Waterland 7025c51f124SMoriah Waterland if (lerrno == EEXIST) { 7035c51f124SMoriah Waterland return (1); /* success */ 7045c51f124SMoriah Waterland } 7055c51f124SMoriah Waterland 7065c51f124SMoriah Waterland /* success if error is 'permission denied' but file exists */ 7075c51f124SMoriah Waterland 7085c51f124SMoriah Waterland if (lerrno == EACCES) { 7095c51f124SMoriah Waterland /* 7105c51f124SMoriah Waterland * Because O_CREAT and O_EXCL are specified in open(), 7115c51f124SMoriah Waterland * if the contents file already exists, the open will 7125c51f124SMoriah Waterland * fail with EACCES - determine if this is the case - 7135c51f124SMoriah Waterland * if so return success. 7145c51f124SMoriah Waterland */ 7155c51f124SMoriah Waterland 7165c51f124SMoriah Waterland if (access(contents, F_OK) == 0) { 7175c51f124SMoriah Waterland return (1); /* success */ 7185c51f124SMoriah Waterland } 7195c51f124SMoriah Waterland 7205c51f124SMoriah Waterland /* 7215c51f124SMoriah Waterland * access() failed - if because of permissions failure this 7225c51f124SMoriah Waterland * means the contents file exists but it cannot be accessed 7235c51f124SMoriah Waterland * or the path to the contents file cannot be accessed - in 7245c51f124SMoriah Waterland * either case the contents file cannot be accessed. 7255c51f124SMoriah Waterland */ 7265c51f124SMoriah Waterland 7275c51f124SMoriah Waterland if (errno == EACCES) { 7285c51f124SMoriah Waterland progerr(gettext(ERR_ACCESS_CONT), contents, 7295c51f124SMoriah Waterland strerror(lerrno)); 7305c51f124SMoriah Waterland logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno)); 7315c51f124SMoriah Waterland return (0); /* failure */ 7325c51f124SMoriah Waterland } 7335c51f124SMoriah Waterland } 7345c51f124SMoriah Waterland 7355c51f124SMoriah Waterland /* 7365c51f124SMoriah Waterland * the contents file does not exist and it cannot be created. 7375c51f124SMoriah Waterland */ 7385c51f124SMoriah Waterland 7395c51f124SMoriah Waterland progerr(gettext(ERR_CREAT_CONT), contents, strerror(lerrno)); 7405c51f124SMoriah Waterland logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno)); 7415c51f124SMoriah Waterland return (0); /* failure */ 7425c51f124SMoriah Waterland } 743