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
do_alarm(int n)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
set_cfdir(char * cfdir)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
ocfile(PKGserver * server,VFP_T ** r_tmpvfp,fsblkcnt_t map_blks)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
socfile(PKGserver * server,boolean_t quiet)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
swapcfile(PKGserver server,VFP_T ** a_cfTmpVfp,char * pkginst,int dbchg)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
relslock(void)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
pkgWlock(int verbose)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
pkgWunlock(void)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
iscfile(void)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
vcfile(void)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