xref: /onnv-gate/usr/src/cmd/svr4pkg/libinst/ocfile.c (revision 12497:63460d0ec640)
19781SMoriah.Waterland@Sun.COM /*
29781SMoriah.Waterland@Sun.COM  * CDDL HEADER START
39781SMoriah.Waterland@Sun.COM  *
49781SMoriah.Waterland@Sun.COM  * The contents of this file are subject to the terms of the
59781SMoriah.Waterland@Sun.COM  * Common Development and Distribution License (the "License").
69781SMoriah.Waterland@Sun.COM  * You may not use this file except in compliance with the License.
79781SMoriah.Waterland@Sun.COM  *
89781SMoriah.Waterland@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99781SMoriah.Waterland@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109781SMoriah.Waterland@Sun.COM  * See the License for the specific language governing permissions
119781SMoriah.Waterland@Sun.COM  * and limitations under the License.
129781SMoriah.Waterland@Sun.COM  *
139781SMoriah.Waterland@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149781SMoriah.Waterland@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159781SMoriah.Waterland@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169781SMoriah.Waterland@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179781SMoriah.Waterland@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189781SMoriah.Waterland@Sun.COM  *
199781SMoriah.Waterland@Sun.COM  * CDDL HEADER END
209781SMoriah.Waterland@Sun.COM  */
219781SMoriah.Waterland@Sun.COM 
229781SMoriah.Waterland@Sun.COM /*
23*12497SCasper.Dik@Sun.COM  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
249781SMoriah.Waterland@Sun.COM  */
259781SMoriah.Waterland@Sun.COM 
269781SMoriah.Waterland@Sun.COM /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
279781SMoriah.Waterland@Sun.COM /* All Rights Reserved */
289781SMoriah.Waterland@Sun.COM 
299781SMoriah.Waterland@Sun.COM 
309781SMoriah.Waterland@Sun.COM #include <stdio.h>
319781SMoriah.Waterland@Sun.COM #include <fcntl.h>
329781SMoriah.Waterland@Sun.COM #include <sys/types.h>
339781SMoriah.Waterland@Sun.COM #include <sys/param.h>
349781SMoriah.Waterland@Sun.COM #include <sys/sysmacros.h>
359781SMoriah.Waterland@Sun.COM #include <string.h>
369781SMoriah.Waterland@Sun.COM #include <strings.h>
379781SMoriah.Waterland@Sun.COM #include <sys/wait.h>
389781SMoriah.Waterland@Sun.COM #include <sys/stat.h>
399781SMoriah.Waterland@Sun.COM #include <sys/mman.h>
409781SMoriah.Waterland@Sun.COM #include <sys/statvfs.h>
419781SMoriah.Waterland@Sun.COM #include <signal.h>
429781SMoriah.Waterland@Sun.COM #include <limits.h>
439781SMoriah.Waterland@Sun.COM #include <errno.h>
449781SMoriah.Waterland@Sun.COM #include <fcntl.h>
459781SMoriah.Waterland@Sun.COM #include <stdlib.h>
469781SMoriah.Waterland@Sun.COM #include <unistd.h>
479781SMoriah.Waterland@Sun.COM #include <time.h>
489781SMoriah.Waterland@Sun.COM #include <errno.h>
499781SMoriah.Waterland@Sun.COM #include <pkglocs.h>
509781SMoriah.Waterland@Sun.COM #include <locale.h>
519781SMoriah.Waterland@Sun.COM #include <libintl.h>
529781SMoriah.Waterland@Sun.COM #include <pkglib.h>
539781SMoriah.Waterland@Sun.COM #include "libinst.h"
549781SMoriah.Waterland@Sun.COM #include "libadm.h"
559781SMoriah.Waterland@Sun.COM 
569869SCasper.Dik@Sun.COM #define	LOCKFILE	".pkg.lock.client"
579869SCasper.Dik@Sun.COM #define	LOCKFILESERV	".pkg.lock"
589869SCasper.Dik@Sun.COM 
599781SMoriah.Waterland@Sun.COM #define	LOCKWAIT	10	/* seconds between retries */
609781SMoriah.Waterland@Sun.COM #define	LOCKRETRY	20	/* number of retries for a DB lock */
619781SMoriah.Waterland@Sun.COM 
629869SCasper.Dik@Sun.COM #define	ERR_COMMIT	"WARNING: unable to commit contents database update"
639781SMoriah.Waterland@Sun.COM #define	ERR_NOCLOSE	"WARNING: unable to close <%s>"
649781SMoriah.Waterland@Sun.COM #define	ERR_NOUNLINK_LATENT	"WARNING: unable to unlink latent <%s>"
659781SMoriah.Waterland@Sun.COM #define	ERR_LINK_FAIL	"link(%s, %s) failed (errno %d)"
669781SMoriah.Waterland@Sun.COM #define	ERR_NORENAME_CONTENTS	"unable to establish contents file <%s> "\
679781SMoriah.Waterland@Sun.COM 			"from <%s>"
689781SMoriah.Waterland@Sun.COM #define	ERR_RENAME_FAIL	"rename(%s, %s) failed (errno %d)"
699781SMoriah.Waterland@Sun.COM #define	ERR_RESTORE_FAIL	"attempt to restore <%s> failed"
709781SMoriah.Waterland@Sun.COM #define	ERR_NOUNLINK	"WARNING: unable to unlink <%s>"
719781SMoriah.Waterland@Sun.COM #define	ERR_FCLOSE_FAIL	"fclose failed (errno %d)"
729781SMoriah.Waterland@Sun.COM #define	ERR_ERRNO	"(errno %d: %s)"
739781SMoriah.Waterland@Sun.COM #define	ERR_NOTMPOPEN	"unable to open temporary contents file image"
749781SMoriah.Waterland@Sun.COM #define	ERR_CFBACK	"Not enough space to backup <%s>"
759781SMoriah.Waterland@Sun.COM #define	ERR_CREAT_CONT	"unable to create contents file <%s>: %s"
769781SMoriah.Waterland@Sun.COM #define	ERR_ACCESS_CONT	"unable to access contents file <%s>: %s"
779781SMoriah.Waterland@Sun.COM #define	ERR_CFBACK1	"Need=%llu blocks, Available=%llu blocks " \
789781SMoriah.Waterland@Sun.COM 			"(block size=%d)"
799781SMoriah.Waterland@Sun.COM #define	ERR_NOCFILE	"unable to locate contents file <%s>"
809781SMoriah.Waterland@Sun.COM #define	ERR_NOROPEN	"unable to open <%s> for reading"
819781SMoriah.Waterland@Sun.COM #define	ERR_NOOPEN	"unable to open <%s> for writing"
829781SMoriah.Waterland@Sun.COM #define	ERR_NOSTAT	"unable to stat contents file <%s>"
839781SMoriah.Waterland@Sun.COM #define	ERR_NOSTATV	"statvfs(%s) failed"
849781SMoriah.Waterland@Sun.COM #define	ERR_NOUPD	"unable to update contents file"
859781SMoriah.Waterland@Sun.COM #define	ERR_DRCONTCP	"unable to copy contents file to <%s>"
869781SMoriah.Waterland@Sun.COM 
879781SMoriah.Waterland@Sun.COM #define	MSG_XWTING	"NOTE: Waiting for exclusive access to the package " \
889781SMoriah.Waterland@Sun.COM 				"database."
899781SMoriah.Waterland@Sun.COM #define	MSG_NOLOCK	"NOTE: Couldn't lock the package database."
909781SMoriah.Waterland@Sun.COM 
919781SMoriah.Waterland@Sun.COM #define	ERR_NOLOCK	"Database lock failed."
929781SMoriah.Waterland@Sun.COM #define	ERR_OPLOCK	"unable to open lock file <%s>."
939781SMoriah.Waterland@Sun.COM #define	ERR_MKLOCK	"unable to create lock file <%s>."
949781SMoriah.Waterland@Sun.COM #define	ERR_LCKREM	"unable to lock package database - remote host " \
959781SMoriah.Waterland@Sun.COM 				"unavailable."
969781SMoriah.Waterland@Sun.COM #define	ERR_BADLCK	"unable to lock package database - unknown error."
979781SMoriah.Waterland@Sun.COM #define	ERR_DEADLCK	"unable to lock package database - deadlock condition."
989781SMoriah.Waterland@Sun.COM #define	ERR_TMOUT	"unable to lock package database - too many retries."
999781SMoriah.Waterland@Sun.COM #define	ERR_CFDIR	"unable to locate contents file directory"
1009781SMoriah.Waterland@Sun.COM 
1019781SMoriah.Waterland@Sun.COM static int	active_lock;
1029781SMoriah.Waterland@Sun.COM static int	lock_fd;	/* fd of LOCKFILE. */
1039781SMoriah.Waterland@Sun.COM static char	*pkgadm_dir;
1049781SMoriah.Waterland@Sun.COM 
1059869SCasper.Dik@Sun.COM int		pkgWlock(int verbose);
1069781SMoriah.Waterland@Sun.COM static int	pkgWunlock(void);
1079781SMoriah.Waterland@Sun.COM 
1089781SMoriah.Waterland@Sun.COM /* forward declarations */
1099781SMoriah.Waterland@Sun.COM 
1109781SMoriah.Waterland@Sun.COM int relslock(void);
1119781SMoriah.Waterland@Sun.COM 
1129781SMoriah.Waterland@Sun.COM /*ARGSUSED*/
1139781SMoriah.Waterland@Sun.COM static void
do_alarm(int n)1149781SMoriah.Waterland@Sun.COM do_alarm(int n)
1159781SMoriah.Waterland@Sun.COM {
1169781SMoriah.Waterland@Sun.COM 	(void) signal(SIGALRM, SIG_IGN);
1179781SMoriah.Waterland@Sun.COM 	(void) signal(SIGALRM, do_alarm);
1189781SMoriah.Waterland@Sun.COM 	(void) alarm(LOCKWAIT);
1199781SMoriah.Waterland@Sun.COM }
1209781SMoriah.Waterland@Sun.COM 
1219781SMoriah.Waterland@Sun.COM /*
1229781SMoriah.Waterland@Sun.COM  * Point packaging to the appropriate contents file. This is primarily used
1239781SMoriah.Waterland@Sun.COM  * to establish a dryrun contents file. If the malloc() doesn't work, this
1249781SMoriah.Waterland@Sun.COM  * returns 99 (internal error), else 0.
1259781SMoriah.Waterland@Sun.COM  */
1269781SMoriah.Waterland@Sun.COM int
set_cfdir(char * cfdir)1279781SMoriah.Waterland@Sun.COM set_cfdir(char *cfdir)
1289781SMoriah.Waterland@Sun.COM {
1299781SMoriah.Waterland@Sun.COM 	char	realcf[PATH_MAX];
1309781SMoriah.Waterland@Sun.COM 	char	tmpcf[PATH_MAX];
1319781SMoriah.Waterland@Sun.COM 	int	status;
1329781SMoriah.Waterland@Sun.COM 
1339781SMoriah.Waterland@Sun.COM 	if (cfdir == NULL) {
1349781SMoriah.Waterland@Sun.COM 		pkgadm_dir = get_PKGADM();
1359781SMoriah.Waterland@Sun.COM 		return (0);
1369781SMoriah.Waterland@Sun.COM 	}
1379781SMoriah.Waterland@Sun.COM 
1389781SMoriah.Waterland@Sun.COM 	if ((pkgadm_dir = strdup(cfdir)) == NULL) {
1399781SMoriah.Waterland@Sun.COM 		return (99);
1409781SMoriah.Waterland@Sun.COM 	}
1419781SMoriah.Waterland@Sun.COM 
1429781SMoriah.Waterland@Sun.COM 	(void) snprintf(tmpcf, sizeof (tmpcf), "%s/contents", pkgadm_dir);
1439781SMoriah.Waterland@Sun.COM 
1449781SMoriah.Waterland@Sun.COM 	/*
1459781SMoriah.Waterland@Sun.COM 	 * return if a temporary contents file already exists -
1469781SMoriah.Waterland@Sun.COM 	 * assume it is from a prior package in this series.
1479781SMoriah.Waterland@Sun.COM 	 */
1489781SMoriah.Waterland@Sun.COM 
1499781SMoriah.Waterland@Sun.COM 	if (access(tmpcf, F_OK) == 0) {
1509781SMoriah.Waterland@Sun.COM 		return (0);
1519781SMoriah.Waterland@Sun.COM 	}
1529781SMoriah.Waterland@Sun.COM 
1539781SMoriah.Waterland@Sun.COM 	/*
1549781SMoriah.Waterland@Sun.COM 	 * no temporary contents file exists - create one.
1559781SMoriah.Waterland@Sun.COM 	 */
1569781SMoriah.Waterland@Sun.COM 
1579781SMoriah.Waterland@Sun.COM 	(void) snprintf(realcf, sizeof (realcf), "%s/contents", get_PKGADM());
1589781SMoriah.Waterland@Sun.COM 
1599781SMoriah.Waterland@Sun.COM 	/*
1609781SMoriah.Waterland@Sun.COM 	 * If there's a contents file there already, copy it
1619869SCasper.Dik@Sun.COM 	 * over, otherwise initialize one.  Make sure that the
1629869SCasper.Dik@Sun.COM 	 * server, if running, flushes the contents file.
1639781SMoriah.Waterland@Sun.COM 	 */
1649781SMoriah.Waterland@Sun.COM 
1659869SCasper.Dik@Sun.COM 	(void) pkgsync(NULL, get_PKGADM(), B_FALSE);
1669869SCasper.Dik@Sun.COM 
1679781SMoriah.Waterland@Sun.COM 	/* create new contents file if one does not already exist */
1689781SMoriah.Waterland@Sun.COM 
1699781SMoriah.Waterland@Sun.COM 	if (access(realcf, F_OK) != 0) {
1709781SMoriah.Waterland@Sun.COM 		int n;
1719781SMoriah.Waterland@Sun.COM 
1729781SMoriah.Waterland@Sun.COM 		n = open(tmpcf, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
1739781SMoriah.Waterland@Sun.COM 		if (n < 0) {
1749781SMoriah.Waterland@Sun.COM 			progerr(gettext(ERR_CREAT_CONT), tmpcf,
1759869SCasper.Dik@Sun.COM 			    strerror(errno));
1769781SMoriah.Waterland@Sun.COM 			return (99);
1779781SMoriah.Waterland@Sun.COM 		}
1789781SMoriah.Waterland@Sun.COM 		(void) close(n);
1799781SMoriah.Waterland@Sun.COM 	} else {
1809781SMoriah.Waterland@Sun.COM 
1819781SMoriah.Waterland@Sun.COM 		/* contents file exists, save in pkgadm-dir */
1829781SMoriah.Waterland@Sun.COM 
1839781SMoriah.Waterland@Sun.COM 		status = copyf(realcf, tmpcf, (time_t)0);
1849781SMoriah.Waterland@Sun.COM 		if (status != 0) {
1859781SMoriah.Waterland@Sun.COM 			progerr(gettext(ERR_DRCONTCP), tmpcf);
1869781SMoriah.Waterland@Sun.COM 			return (99);
1879781SMoriah.Waterland@Sun.COM 		}
1889781SMoriah.Waterland@Sun.COM 	}
1899781SMoriah.Waterland@Sun.COM 
1909781SMoriah.Waterland@Sun.COM 	return (0);
1919781SMoriah.Waterland@Sun.COM }
1929781SMoriah.Waterland@Sun.COM 
1939781SMoriah.Waterland@Sun.COM /*
1949781SMoriah.Waterland@Sun.COM  * This function installs the database lock, opens the contents file for
1959781SMoriah.Waterland@Sun.COM  * reading and creates and opens the temporary contents file for read/write.
1969781SMoriah.Waterland@Sun.COM  * It returns 1 if successful, 0 otherwise.
1979781SMoriah.Waterland@Sun.COM  */
1989781SMoriah.Waterland@Sun.COM int
ocfile(PKGserver * server,VFP_T ** r_tmpvfp,fsblkcnt_t map_blks)1999869SCasper.Dik@Sun.COM ocfile(PKGserver *server, VFP_T **r_tmpvfp, fsblkcnt_t map_blks)
2009781SMoriah.Waterland@Sun.COM {
201*12497SCasper.Dik@Sun.COM 	struct	stat64	statb, statl;
2029781SMoriah.Waterland@Sun.COM 	struct	statvfs64	svfsb;
2039781SMoriah.Waterland@Sun.COM 	fsblkcnt_t free_blocks;
2049781SMoriah.Waterland@Sun.COM 	fsblkcnt_t need_blocks;
205*12497SCasper.Dik@Sun.COM 	fsblkcnt_t log_blocks;
2069781SMoriah.Waterland@Sun.COM 	VFP_T		*tmpvfp = (VFP_T *)NULL;
2079781SMoriah.Waterland@Sun.COM 	char		contents[PATH_MAX];
208*12497SCasper.Dik@Sun.COM 	char		logfile[PATH_MAX];
2099781SMoriah.Waterland@Sun.COM 	int		n;
2109869SCasper.Dik@Sun.COM 	off_t		cdiff_alloc;
2119869SCasper.Dik@Sun.COM 	PKGserver	newserver;
2129781SMoriah.Waterland@Sun.COM 
2139781SMoriah.Waterland@Sun.COM 	/* establish package administration contents directory location */
2149781SMoriah.Waterland@Sun.COM 
2159781SMoriah.Waterland@Sun.COM 	if (pkgadm_dir == NULL) {
2169781SMoriah.Waterland@Sun.COM 		if (set_cfdir(NULL) != 0) {
2179781SMoriah.Waterland@Sun.COM 			progerr(gettext(ERR_CFDIR));
2189781SMoriah.Waterland@Sun.COM 			return (0);
2199781SMoriah.Waterland@Sun.COM 		}
2209781SMoriah.Waterland@Sun.COM 	}
2219781SMoriah.Waterland@Sun.COM 
2229781SMoriah.Waterland@Sun.COM 	/* Lock the file for exclusive access */
2239781SMoriah.Waterland@Sun.COM 
2249781SMoriah.Waterland@Sun.COM 	if (!pkgWlock(1)) {
2259781SMoriah.Waterland@Sun.COM 		progerr(gettext(ERR_NOLOCK));
2269781SMoriah.Waterland@Sun.COM 		return (0);
2279781SMoriah.Waterland@Sun.COM 	}
2289781SMoriah.Waterland@Sun.COM 
2299869SCasper.Dik@Sun.COM 	if (*server != NULL) {
2309869SCasper.Dik@Sun.COM 		vfpTruncate(*r_tmpvfp);
2319869SCasper.Dik@Sun.COM 		(void) vfpClearModified(*r_tmpvfp);
2329781SMoriah.Waterland@Sun.COM 
2339869SCasper.Dik@Sun.COM 		return (1);
2349869SCasper.Dik@Sun.COM 	}
2359781SMoriah.Waterland@Sun.COM 
2369869SCasper.Dik@Sun.COM 	newserver = pkgopenserver(NULL, pkgadm_dir, B_FALSE);
2379781SMoriah.Waterland@Sun.COM 
2389869SCasper.Dik@Sun.COM 	/* The error has been reported. */
2399869SCasper.Dik@Sun.COM 	if (newserver == NULL)
2409869SCasper.Dik@Sun.COM 		return (0);
2419781SMoriah.Waterland@Sun.COM 
2429869SCasper.Dik@Sun.COM 	/* reset return VFP/FILE pointers */
2439781SMoriah.Waterland@Sun.COM 
2449869SCasper.Dik@Sun.COM 	(*r_tmpvfp) = (VFP_T *)NULL;
2459869SCasper.Dik@Sun.COM 
2469869SCasper.Dik@Sun.COM 	/* determine path to the primary contents file */
2479869SCasper.Dik@Sun.COM 	(void) snprintf(contents, sizeof (contents), "%s/contents", pkgadm_dir);
2489781SMoriah.Waterland@Sun.COM 
2499781SMoriah.Waterland@Sun.COM 	/*
2509781SMoriah.Waterland@Sun.COM 	 * Check and see if there is enough space for the packaging commands
2519781SMoriah.Waterland@Sun.COM 	 * to back up the contents file, if there is not, then do not allow
2529781SMoriah.Waterland@Sun.COM 	 * execution to continue by failing the ocfile() call.
2539781SMoriah.Waterland@Sun.COM 	 */
2549781SMoriah.Waterland@Sun.COM 
2559781SMoriah.Waterland@Sun.COM 	/* Get the contents file size */
2569781SMoriah.Waterland@Sun.COM 
2579869SCasper.Dik@Sun.COM 	if (stat64(contents, &statb) == -1) {
2589781SMoriah.Waterland@Sun.COM 		int	lerrno = errno;
2599781SMoriah.Waterland@Sun.COM 
2609869SCasper.Dik@Sun.COM 		progerr(gettext(ERR_NOCFILE), contents);
2619781SMoriah.Waterland@Sun.COM 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
2629869SCasper.Dik@Sun.COM 		pkgcloseserver(newserver);
2639781SMoriah.Waterland@Sun.COM 		return (0);
2649781SMoriah.Waterland@Sun.COM 	}
2659781SMoriah.Waterland@Sun.COM 
2669781SMoriah.Waterland@Sun.COM 	/* Get the filesystem space */
2679781SMoriah.Waterland@Sun.COM 
2689869SCasper.Dik@Sun.COM 	if (statvfs64(contents, &svfsb) == -1) {
2699781SMoriah.Waterland@Sun.COM 		int	lerrno = errno;
2709781SMoriah.Waterland@Sun.COM 
2719781SMoriah.Waterland@Sun.COM 		progerr(gettext(ERR_NOSTATV), contents);
2729781SMoriah.Waterland@Sun.COM 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
2739869SCasper.Dik@Sun.COM 		pkgcloseserver(newserver);
2749781SMoriah.Waterland@Sun.COM 		return (0);
2759781SMoriah.Waterland@Sun.COM 	}
2769781SMoriah.Waterland@Sun.COM 
2779781SMoriah.Waterland@Sun.COM 	free_blocks = (((fsblkcnt_t)svfsb.f_frsize > 0) ?
278*12497SCasper.Dik@Sun.COM 	    howmany(svfsb.f_frsize, DEV_BSIZE) :
279*12497SCasper.Dik@Sun.COM 	    howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bfree;
2809781SMoriah.Waterland@Sun.COM 
281*12497SCasper.Dik@Sun.COM 	/* determine blocks used by the logfile */
282*12497SCasper.Dik@Sun.COM 	(void) snprintf(logfile, sizeof (logfile), "%s/" PKGLOG, pkgadm_dir);
2839869SCasper.Dik@Sun.COM 
284*12497SCasper.Dik@Sun.COM 	if (stat64(logfile, &statl) == -1)
285*12497SCasper.Dik@Sun.COM 		log_blocks = 0;
286*12497SCasper.Dik@Sun.COM 	else
287*12497SCasper.Dik@Sun.COM 		log_blocks = nblk(statl.st_size, svfsb.f_bsize, svfsb.f_frsize);
2889781SMoriah.Waterland@Sun.COM 
2899781SMoriah.Waterland@Sun.COM 	/*
2909781SMoriah.Waterland@Sun.COM 	 * Calculate the number of blocks we need to be able to operate on
291*12497SCasper.Dik@Sun.COM 	 * the contents file and the log file.
292*12497SCasper.Dik@Sun.COM 	 * When adding a package (map_blks > 0), we add the size of the
293*12497SCasper.Dik@Sun.COM 	 * pkgmap file times 1.5 as the pkgmap is a bit smaller then the
294*12497SCasper.Dik@Sun.COM 	 * lines added to the contents file.  That data is written both to
295*12497SCasper.Dik@Sun.COM 	 * the new contents file and the log file (2 * 1.5 * map_blks).
296*12497SCasper.Dik@Sun.COM 	 * The new contents file is limited by the size of the current
297*12497SCasper.Dik@Sun.COM 	 * contents file and the increased log file.
298*12497SCasper.Dik@Sun.COM 	 * If we're removing a package, then the log might grow to the size
299*12497SCasper.Dik@Sun.COM 	 * of the full contents file but then the new contents file would
300*12497SCasper.Dik@Sun.COM 	 * be zero and so we only need to add the size of the contents file.
3019781SMoriah.Waterland@Sun.COM 	 */
302*12497SCasper.Dik@Sun.COM 	need_blocks = map_blks * 3 +
303*12497SCasper.Dik@Sun.COM 	    /* Current log file */
304*12497SCasper.Dik@Sun.COM 	    log_blocks +
305*12497SCasper.Dik@Sun.COM 	    /* Current contents file */
306*12497SCasper.Dik@Sun.COM 	    nblk(statb.st_size, svfsb.f_bsize, svfsb.f_frsize);
3079781SMoriah.Waterland@Sun.COM 
3089781SMoriah.Waterland@Sun.COM 	if ((need_blocks + 10) > free_blocks) {
3099781SMoriah.Waterland@Sun.COM 		progerr(gettext(ERR_CFBACK), contents);
3109781SMoriah.Waterland@Sun.COM 		progerr(gettext(ERR_CFBACK1), need_blocks, free_blocks,
311*12497SCasper.Dik@Sun.COM 		    DEV_BSIZE);
3129869SCasper.Dik@Sun.COM 		pkgcloseserver(newserver);
3139781SMoriah.Waterland@Sun.COM 		return (0);
3149781SMoriah.Waterland@Sun.COM 	}
3159781SMoriah.Waterland@Sun.COM 
3169781SMoriah.Waterland@Sun.COM 	/*
3179781SMoriah.Waterland@Sun.COM 	 * open the temporary contents file without a path name - this causes
3189781SMoriah.Waterland@Sun.COM 	 * the "vfp" to be opened on in-memory storage only, the size of which
3199781SMoriah.Waterland@Sun.COM 	 * is set following a successful return - this causes the temporary
3209781SMoriah.Waterland@Sun.COM 	 * contents file to be maintained in memory only - if no changes are
3219781SMoriah.Waterland@Sun.COM 	 * made as the primary contents file is processed, the in memory data
3229781SMoriah.Waterland@Sun.COM 	 * is discarded and not written to the disk.
3239781SMoriah.Waterland@Sun.COM 	 */
3249781SMoriah.Waterland@Sun.COM 
3259781SMoriah.Waterland@Sun.COM 	if (vfpOpen(&tmpvfp, (char *)NULL, "w", VFP_NONE) != 0) {
3269781SMoriah.Waterland@Sun.COM 		int	lerrno = errno;
3279781SMoriah.Waterland@Sun.COM 
3289781SMoriah.Waterland@Sun.COM 		progerr(gettext(ERR_NOTMPOPEN));
3299781SMoriah.Waterland@Sun.COM 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
3309869SCasper.Dik@Sun.COM 		pkgcloseserver(newserver);
3319781SMoriah.Waterland@Sun.COM 		return (0);
3329781SMoriah.Waterland@Sun.COM 	}
3339781SMoriah.Waterland@Sun.COM 
3349781SMoriah.Waterland@Sun.COM 	/*
3359781SMoriah.Waterland@Sun.COM 	 * set size of allocation for temporary contents file - this sets the
3369781SMoriah.Waterland@Sun.COM 	 * size of the in-memory buffer associated with the open vfp.
3379869SCasper.Dik@Sun.COM 	 * We only store the new and changed entries.
3389869SCasper.Dik@Sun.COM 	 * We allocate memory depending on the size of the pkgmap; it's not
3399869SCasper.Dik@Sun.COM 	 * completely right but <some value + * 1.5 * map_blks * DEV_BSIZE>
3409869SCasper.Dik@Sun.COM 	 * seems fine (an install adds the size if the name of the package.)
3419781SMoriah.Waterland@Sun.COM 	 */
3429781SMoriah.Waterland@Sun.COM 
3439869SCasper.Dik@Sun.COM 	cdiff_alloc = map_blks * DEV_BSIZE;
3449869SCasper.Dik@Sun.COM 	cdiff_alloc += cdiff_alloc/2;
3459869SCasper.Dik@Sun.COM 	if (cdiff_alloc < 1000000)
3469869SCasper.Dik@Sun.COM 		cdiff_alloc += 1000000;
3479869SCasper.Dik@Sun.COM 
3489869SCasper.Dik@Sun.COM 	if (vfpSetSize(tmpvfp, cdiff_alloc) != 0) {
3499781SMoriah.Waterland@Sun.COM 		int	lerrno = errno;
3509781SMoriah.Waterland@Sun.COM 
3519781SMoriah.Waterland@Sun.COM 		progerr(gettext(ERR_NOTMPOPEN));
3529781SMoriah.Waterland@Sun.COM 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
3539781SMoriah.Waterland@Sun.COM 		(void) vfpClose(&tmpvfp);
3549869SCasper.Dik@Sun.COM 		pkgcloseserver(newserver);
3559781SMoriah.Waterland@Sun.COM 		return (0);
3569781SMoriah.Waterland@Sun.COM 	}
3579781SMoriah.Waterland@Sun.COM 
3589869SCasper.Dik@Sun.COM 	/* set return ->s to open server/vfps */
3599781SMoriah.Waterland@Sun.COM 
3609781SMoriah.Waterland@Sun.COM 	(*r_tmpvfp) = tmpvfp;
3619869SCasper.Dik@Sun.COM 	*server = newserver;
3629781SMoriah.Waterland@Sun.COM 
3639781SMoriah.Waterland@Sun.COM 	return (1);	/* All OK */
3649781SMoriah.Waterland@Sun.COM }
3659781SMoriah.Waterland@Sun.COM 
3669781SMoriah.Waterland@Sun.COM /*
3679781SMoriah.Waterland@Sun.COM  * This is a simple open and lock of the contents file. It doesn't create a
3689781SMoriah.Waterland@Sun.COM  * temporary contents file and it doesn't need to do any space checking.
3699781SMoriah.Waterland@Sun.COM  * Returns 1 for OK and 0 for "didn't do it".
3709781SMoriah.Waterland@Sun.COM  */
3719781SMoriah.Waterland@Sun.COM int
socfile(PKGserver * server,boolean_t quiet)3729869SCasper.Dik@Sun.COM socfile(PKGserver *server, boolean_t quiet)
3739781SMoriah.Waterland@Sun.COM {
3749869SCasper.Dik@Sun.COM 	char		contents[PATH_MAX];
3759869SCasper.Dik@Sun.COM 	boolean_t 	readonly = B_FALSE;
3769869SCasper.Dik@Sun.COM 	PKGserver	newserver;
3779781SMoriah.Waterland@Sun.COM 
3789781SMoriah.Waterland@Sun.COM 	if (pkgadm_dir == NULL) {
3799781SMoriah.Waterland@Sun.COM 		if (set_cfdir(NULL) != 0) {
3809781SMoriah.Waterland@Sun.COM 			progerr(gettext(ERR_CFDIR));
3819781SMoriah.Waterland@Sun.COM 			return (0);
3829781SMoriah.Waterland@Sun.COM 		}
3839781SMoriah.Waterland@Sun.COM 	}
3849781SMoriah.Waterland@Sun.COM 
3859781SMoriah.Waterland@Sun.COM 	/*
3869781SMoriah.Waterland@Sun.COM 	 * Lock the database for exclusive access, but don't make a fuss if
3879781SMoriah.Waterland@Sun.COM 	 * it fails (user may not be root and the .pkg.lock file may not
3889781SMoriah.Waterland@Sun.COM 	 * exist yet).
3899781SMoriah.Waterland@Sun.COM 	 */
3909781SMoriah.Waterland@Sun.COM 
3919781SMoriah.Waterland@Sun.COM 	if (!pkgWlock(0)) {
3929869SCasper.Dik@Sun.COM 		if (!quiet)
3939869SCasper.Dik@Sun.COM 			logerr(gettext(MSG_NOLOCK));
3949869SCasper.Dik@Sun.COM 		readonly = B_TRUE;
3959781SMoriah.Waterland@Sun.COM 	}
3969781SMoriah.Waterland@Sun.COM 
3979869SCasper.Dik@Sun.COM 	newserver = pkgopenserver(NULL, pkgadm_dir, readonly);
3989869SCasper.Dik@Sun.COM 	if (newserver == NULL)
3999869SCasper.Dik@Sun.COM 		return (0);
4009781SMoriah.Waterland@Sun.COM 
4019869SCasper.Dik@Sun.COM 	*server = newserver;
4029781SMoriah.Waterland@Sun.COM 	return (1);
4039781SMoriah.Waterland@Sun.COM }
4049781SMoriah.Waterland@Sun.COM 
4059781SMoriah.Waterland@Sun.COM /*
4069781SMoriah.Waterland@Sun.COM  * Name:	swapcfile
4079781SMoriah.Waterland@Sun.COM  * Description: This function closes both the current and temporary contents
4089781SMoriah.Waterland@Sun.COM  *		files specified, and conditionally replaces the old transitory
4099781SMoriah.Waterland@Sun.COM  *		contents file with the newly updated temporary contents file.
4109781SMoriah.Waterland@Sun.COM  *		The "ocfile()" or "socfile()" functions must be called to re-
4119781SMoriah.Waterland@Sun.COM  *		open the real contents file for processing.
4129869SCasper.Dik@Sun.COM  * Arguments:	PKGserver - handle to the package database
4139781SMoriah.Waterland@Sun.COM  *		a_cfTmpVfp - (VFP_T **) - [RW, *RW]
4149869SCasper.Dik@Sun.COM  *			This is the VFP associated which contains all the
4159869SCasper.Dik@Sun.COM  *			modifications to be written back to the database.
4169781SMoriah.Waterland@Sun.COM  *			file that is being written to.
4179781SMoriah.Waterland@Sun.COM  *		pkginst - (char) - [RO, *RO]
4189781SMoriah.Waterland@Sun.COM  *			This is the name of the package being operated on;
4199781SMoriah.Waterland@Sun.COM  *			this is used to write the "last modified by xxx"
4209781SMoriah.Waterland@Sun.COM  *			comment at the end of the contents file.
4219781SMoriah.Waterland@Sun.COM  *		dbchg - (int) - [RO]
4229781SMoriah.Waterland@Sun.COM  *			== 0 - the temporary contents file has NOT been changed
4239781SMoriah.Waterland@Sun.COM  *				with respect to the real contents file; do not
4249781SMoriah.Waterland@Sun.COM  *				update the real contents file with the contents
4259781SMoriah.Waterland@Sun.COM  *				of the temporary contents file.
4269781SMoriah.Waterland@Sun.COM  *			!= 0 - the temporary contetns file HAS been changed with
4279781SMoriah.Waterland@Sun.COM  *				respect to the real contents file; DO update the
4289781SMoriah.Waterland@Sun.COM  *				real contents file with the contents of the
4299781SMoriah.Waterland@Sun.COM  *				temporary contents file.
4309781SMoriah.Waterland@Sun.COM  * Returns:	int	== RESULT_OK - successful
4319781SMoriah.Waterland@Sun.COM  *			== RESULT_WRN - successful with warnings
4329781SMoriah.Waterland@Sun.COM  *			== RESULT_ERR - failed with fatal errors - deserves an
4339781SMoriah.Waterland@Sun.COM  *				alarming message and a quit()
4349781SMoriah.Waterland@Sun.COM  * NOTES: If dbchg != 0, the contents file is always updated. If dbchg == 0,
4359781SMoriah.Waterland@Sun.COM  *		the contents file is updated IF the data is modified indication
4369781SMoriah.Waterland@Sun.COM  *		is set on the contents file associated with a_cfTmpVfp.
4379781SMoriah.Waterland@Sun.COM  */
4389781SMoriah.Waterland@Sun.COM 
4399781SMoriah.Waterland@Sun.COM int
swapcfile(PKGserver server,VFP_T ** a_cfTmpVfp,char * pkginst,int dbchg)4409869SCasper.Dik@Sun.COM swapcfile(PKGserver server, VFP_T **a_cfTmpVfp, char *pkginst, int dbchg)
4419781SMoriah.Waterland@Sun.COM {
4429781SMoriah.Waterland@Sun.COM 	char	*pe;
4439781SMoriah.Waterland@Sun.COM 	char	*pl;
4449781SMoriah.Waterland@Sun.COM 	char	*ps;
4459781SMoriah.Waterland@Sun.COM 	char	line[256];
4469781SMoriah.Waterland@Sun.COM 	char	timeb[BUFSIZ];
4479781SMoriah.Waterland@Sun.COM 	int	retval = RESULT_OK;
4489781SMoriah.Waterland@Sun.COM 	struct tm	*timep;
4499781SMoriah.Waterland@Sun.COM 	time_t	clock;
4509781SMoriah.Waterland@Sun.COM 
4519781SMoriah.Waterland@Sun.COM 	/* normalize pkginst so its never null */
4529781SMoriah.Waterland@Sun.COM 
4539781SMoriah.Waterland@Sun.COM 	if (pkginst == (char *)NULL) {
4549781SMoriah.Waterland@Sun.COM 		dbchg = 0;
4559781SMoriah.Waterland@Sun.COM 		pkginst = "<unknown>";
4569781SMoriah.Waterland@Sun.COM 	}
4579781SMoriah.Waterland@Sun.COM 
4589781SMoriah.Waterland@Sun.COM 	/*
4599781SMoriah.Waterland@Sun.COM 	 * If no changes were made to the database, checkpoint the temporary
4609781SMoriah.Waterland@Sun.COM 	 * contents file - if this fails, then just close the file which causes
4619781SMoriah.Waterland@Sun.COM 	 * the contents file to be reopened and reread if it is needed again
4629781SMoriah.Waterland@Sun.COM 	 */
4639781SMoriah.Waterland@Sun.COM 
4649781SMoriah.Waterland@Sun.COM 	if ((dbchg == 0) && (vfpGetModified(*a_cfTmpVfp) == 0)) {
4659781SMoriah.Waterland@Sun.COM 		(void) pkgWunlock();	/* Free the database lock. */
4669781SMoriah.Waterland@Sun.COM 		return (retval);
4679781SMoriah.Waterland@Sun.COM 	}
4689781SMoriah.Waterland@Sun.COM 
4699781SMoriah.Waterland@Sun.COM 	/*
4709781SMoriah.Waterland@Sun.COM 	 * changes made to the current temporary contents file -
4719781SMoriah.Waterland@Sun.COM 	 * remove any trailing comment lines in the temp contents file, then
4729781SMoriah.Waterland@Sun.COM 	 * append updated modification info records to temp contents file
4739781SMoriah.Waterland@Sun.COM 	 */
4749781SMoriah.Waterland@Sun.COM 
4759781SMoriah.Waterland@Sun.COM 	pe = vfpGetCurrCharPtr(*a_cfTmpVfp);	/* last char in contents file */
4769781SMoriah.Waterland@Sun.COM 	ps = vfpGetFirstCharPtr(*a_cfTmpVfp);	/* 1st char in contents file */
4779781SMoriah.Waterland@Sun.COM 	pl = pe;	/* last match is last char in contents file */
4789781SMoriah.Waterland@Sun.COM 
4799781SMoriah.Waterland@Sun.COM 	/* skip past all trailing newlines and null bytes */
4809781SMoriah.Waterland@Sun.COM 
4819781SMoriah.Waterland@Sun.COM 	while ((pe > ps) && ((*pe == '\n') || (*pe == '\0'))) {
4829781SMoriah.Waterland@Sun.COM 		pe--;
4839781SMoriah.Waterland@Sun.COM 	}
4849781SMoriah.Waterland@Sun.COM 
4859781SMoriah.Waterland@Sun.COM 	/* remove trailing comments as long as there are lines in the file */
4869781SMoriah.Waterland@Sun.COM 
4879781SMoriah.Waterland@Sun.COM 	while (pe > ps) {
4889781SMoriah.Waterland@Sun.COM 		if (*pe != '\n') {
4899781SMoriah.Waterland@Sun.COM 			/* curr char is not newline: backup one byte */
4909781SMoriah.Waterland@Sun.COM 			pl = pe--;
4919781SMoriah.Waterland@Sun.COM 		} else if (*pl != '#') {
4929781SMoriah.Waterland@Sun.COM 			/* curr char is newline next char not comment break */
4939781SMoriah.Waterland@Sun.COM 			break;
4949781SMoriah.Waterland@Sun.COM 		} else {
4959781SMoriah.Waterland@Sun.COM 			/* curr char is newline next char is comment - remove */
4969781SMoriah.Waterland@Sun.COM 			*pl = '\0';
4979781SMoriah.Waterland@Sun.COM 			vfpSetLastCharPtr(*a_cfTmpVfp, pl);
4989781SMoriah.Waterland@Sun.COM 			pe--;
4999781SMoriah.Waterland@Sun.COM 		}
5009781SMoriah.Waterland@Sun.COM 	}
5019781SMoriah.Waterland@Sun.COM 
5029781SMoriah.Waterland@Sun.COM 	/* create two update comment lines */
5039781SMoriah.Waterland@Sun.COM 
5049781SMoriah.Waterland@Sun.COM 	(void) time(&clock);
5059781SMoriah.Waterland@Sun.COM 	timep = localtime(&clock);
5069781SMoriah.Waterland@Sun.COM 
5079781SMoriah.Waterland@Sun.COM 	(void) strftime(timeb, sizeof (timeb), "%c\n", timep);
5089781SMoriah.Waterland@Sun.COM 	(void) snprintf(line, sizeof (line),
509*12497SCasper.Dik@Sun.COM 	    gettext("# Last modified by %s for %s package\n# %s"),
510*12497SCasper.Dik@Sun.COM 	    get_prog_name(), pkginst, timeb);
5119781SMoriah.Waterland@Sun.COM 	vfpPuts(*a_cfTmpVfp, line);
5129781SMoriah.Waterland@Sun.COM 
5139781SMoriah.Waterland@Sun.COM 	/* commit temporary contents file bytes to storage */
5149781SMoriah.Waterland@Sun.COM 
5159869SCasper.Dik@Sun.COM 	if (pkgservercommitfile(*a_cfTmpVfp, server) != 0) {
5169781SMoriah.Waterland@Sun.COM 		int	lerrno = errno;
5179781SMoriah.Waterland@Sun.COM 
5189869SCasper.Dik@Sun.COM 		logerr(gettext(ERR_COMMIT));
5199869SCasper.Dik@Sun.COM 		vfpClose(a_cfTmpVfp);
5209869SCasper.Dik@Sun.COM 		pkgcloseserver(server);
5219781SMoriah.Waterland@Sun.COM 		(void) pkgWunlock();	/* Free the database lock. */
5229781SMoriah.Waterland@Sun.COM 		return (RESULT_ERR);
5239781SMoriah.Waterland@Sun.COM 	}
5249781SMoriah.Waterland@Sun.COM 
5259781SMoriah.Waterland@Sun.COM 	return (relslock() == 0 ? RESULT_ERR : retval);
5269781SMoriah.Waterland@Sun.COM }
5279781SMoriah.Waterland@Sun.COM 
5289781SMoriah.Waterland@Sun.COM /* This function releases the lock on the package database. */
5299781SMoriah.Waterland@Sun.COM int
relslock(void)5309781SMoriah.Waterland@Sun.COM relslock(void)
5319781SMoriah.Waterland@Sun.COM {
5329781SMoriah.Waterland@Sun.COM 	/*
5339781SMoriah.Waterland@Sun.COM 	 * This closes the contents file and releases the lock.
5349781SMoriah.Waterland@Sun.COM 	 */
5359781SMoriah.Waterland@Sun.COM 	if (!pkgWunlock()) {
5369781SMoriah.Waterland@Sun.COM 		int	lerrno = errno;
5379781SMoriah.Waterland@Sun.COM 
5389781SMoriah.Waterland@Sun.COM 		progerr(gettext(ERR_NOUPD));
5399781SMoriah.Waterland@Sun.COM 		logerr(gettext(ERR_FCLOSE_FAIL), lerrno);
5409781SMoriah.Waterland@Sun.COM 		return (0);
5419781SMoriah.Waterland@Sun.COM 	}
5429781SMoriah.Waterland@Sun.COM 	return (1);
5439781SMoriah.Waterland@Sun.COM }
5449781SMoriah.Waterland@Sun.COM 
5459781SMoriah.Waterland@Sun.COM /*
5469781SMoriah.Waterland@Sun.COM  * This function attempts to lock the package database. It returns 1 on
5479781SMoriah.Waterland@Sun.COM  * success, 0 on failure. The positive logic verbose flag determines whether
5489781SMoriah.Waterland@Sun.COM  * or not the function displays the error message upon failure.
5499781SMoriah.Waterland@Sun.COM  */
5509869SCasper.Dik@Sun.COM int
pkgWlock(int verbose)5519781SMoriah.Waterland@Sun.COM pkgWlock(int verbose) {
5529781SMoriah.Waterland@Sun.COM 	int retry_cnt, retval;
5539781SMoriah.Waterland@Sun.COM 	char lockpath[PATH_MAX];
5549781SMoriah.Waterland@Sun.COM 
5559781SMoriah.Waterland@Sun.COM 	active_lock = 0;
5569781SMoriah.Waterland@Sun.COM 
5579781SMoriah.Waterland@Sun.COM 	(void) snprintf(lockpath, sizeof (lockpath),
5589781SMoriah.Waterland@Sun.COM 			"%s/%s", pkgadm_dir, LOCKFILE);
5599781SMoriah.Waterland@Sun.COM 
5609781SMoriah.Waterland@Sun.COM 	retry_cnt = LOCKRETRY;
5619781SMoriah.Waterland@Sun.COM 
5629781SMoriah.Waterland@Sun.COM 	/*
5639781SMoriah.Waterland@Sun.COM 	 * If the lock file is not present, create it. The mode is set to
5649781SMoriah.Waterland@Sun.COM 	 * allow any process to lock the database, that's because pkgchk may
5659781SMoriah.Waterland@Sun.COM 	 * be run by a non-root user.
5669781SMoriah.Waterland@Sun.COM 	 */
5679781SMoriah.Waterland@Sun.COM 	if (access(lockpath, F_OK) == -1) {
5689781SMoriah.Waterland@Sun.COM 		lock_fd = open(lockpath, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644);
5699781SMoriah.Waterland@Sun.COM 		if (lock_fd < 0) {
5709781SMoriah.Waterland@Sun.COM 			if (verbose)
5719781SMoriah.Waterland@Sun.COM 				progerr(gettext(ERR_MKLOCK), lockpath);
5729781SMoriah.Waterland@Sun.COM 			return (0);
5739781SMoriah.Waterland@Sun.COM 		} else {
5749781SMoriah.Waterland@Sun.COM 			(void) fchmod(lock_fd, 0644);	/* force perms. */
5759781SMoriah.Waterland@Sun.COM 		}
5769781SMoriah.Waterland@Sun.COM 	} else {
5779781SMoriah.Waterland@Sun.COM 		if ((lock_fd = open(lockpath, O_RDWR)) == -1) {
5789781SMoriah.Waterland@Sun.COM 			if (verbose)
5799781SMoriah.Waterland@Sun.COM 				progerr(gettext(ERR_OPLOCK), lockpath);
5809781SMoriah.Waterland@Sun.COM 			return (0);
5819781SMoriah.Waterland@Sun.COM 		}
5829781SMoriah.Waterland@Sun.COM 	}
5839781SMoriah.Waterland@Sun.COM 
5849781SMoriah.Waterland@Sun.COM 	(void) signal(SIGALRM, do_alarm);
5859781SMoriah.Waterland@Sun.COM 	(void) alarm(LOCKWAIT);
5869781SMoriah.Waterland@Sun.COM 
5879781SMoriah.Waterland@Sun.COM 	do {
5889781SMoriah.Waterland@Sun.COM 		if (lockf(lock_fd, F_LOCK, 0)) {
5899781SMoriah.Waterland@Sun.COM 			if (errno == EAGAIN || errno == EINTR)
5909781SMoriah.Waterland@Sun.COM 				logerr(gettext(MSG_XWTING));
5919781SMoriah.Waterland@Sun.COM 			else if (errno == ECOMM) {
5929781SMoriah.Waterland@Sun.COM 				logerr(gettext(ERR_LCKREM));
5939781SMoriah.Waterland@Sun.COM 				retval = 0;
5949781SMoriah.Waterland@Sun.COM 				break;
5959781SMoriah.Waterland@Sun.COM 			} else if (errno == EBADF) {
5969781SMoriah.Waterland@Sun.COM 				logerr(gettext(ERR_BADLCK));
5979781SMoriah.Waterland@Sun.COM 				retval = 0;
5989781SMoriah.Waterland@Sun.COM 				break;
5999781SMoriah.Waterland@Sun.COM 			} else if (errno == EDEADLK) {
6009781SMoriah.Waterland@Sun.COM 				logerr(gettext(ERR_DEADLCK));
6019781SMoriah.Waterland@Sun.COM 				retval = 0;
6029781SMoriah.Waterland@Sun.COM 				break;
6039781SMoriah.Waterland@Sun.COM 			}
6049781SMoriah.Waterland@Sun.COM 		} else {
6059781SMoriah.Waterland@Sun.COM 			active_lock = 1;
6069781SMoriah.Waterland@Sun.COM 			retval = 1;
6079781SMoriah.Waterland@Sun.COM 			break;
6089781SMoriah.Waterland@Sun.COM 		}
6099781SMoriah.Waterland@Sun.COM 	} while (retry_cnt--);
6109781SMoriah.Waterland@Sun.COM 
6119781SMoriah.Waterland@Sun.COM 	(void) signal(SIGALRM, SIG_IGN);
6129781SMoriah.Waterland@Sun.COM 
6139781SMoriah.Waterland@Sun.COM 	if (retval == 0)
6149781SMoriah.Waterland@Sun.COM 	{
6159781SMoriah.Waterland@Sun.COM 		if (retry_cnt == -1) {
6169781SMoriah.Waterland@Sun.COM 			logerr(gettext(ERR_TMOUT));
6179781SMoriah.Waterland@Sun.COM 		}
6189781SMoriah.Waterland@Sun.COM 
6199781SMoriah.Waterland@Sun.COM 		(void) pkgWunlock();	/* close the lockfile. */
6209781SMoriah.Waterland@Sun.COM 	}
6219781SMoriah.Waterland@Sun.COM 
6229781SMoriah.Waterland@Sun.COM 	return (retval);
6239781SMoriah.Waterland@Sun.COM }
6249781SMoriah.Waterland@Sun.COM 
6259781SMoriah.Waterland@Sun.COM /*
6269781SMoriah.Waterland@Sun.COM  * Release the lock on the package database. Returns 1 on success, 0 on
6279781SMoriah.Waterland@Sun.COM  * failure.
6289781SMoriah.Waterland@Sun.COM  */
6299781SMoriah.Waterland@Sun.COM static int
pkgWunlock(void)6309781SMoriah.Waterland@Sun.COM pkgWunlock(void) {
6319781SMoriah.Waterland@Sun.COM 	if (active_lock) {
6329781SMoriah.Waterland@Sun.COM 		active_lock = 0;
6339781SMoriah.Waterland@Sun.COM 		if (close(lock_fd))
6349781SMoriah.Waterland@Sun.COM 			return (0);
6359781SMoriah.Waterland@Sun.COM 		else
6369781SMoriah.Waterland@Sun.COM 			return (1);
6379781SMoriah.Waterland@Sun.COM 	} else
6389781SMoriah.Waterland@Sun.COM 		return (1);
6399781SMoriah.Waterland@Sun.COM }
6409781SMoriah.Waterland@Sun.COM 
6419781SMoriah.Waterland@Sun.COM /*
6429781SMoriah.Waterland@Sun.COM  * This function verifies that the contents file is in place.
6439781SMoriah.Waterland@Sun.COM  * returns 1 - if it exists
6449781SMoriah.Waterland@Sun.COM  * returns 0 - if it does not exist
6459781SMoriah.Waterland@Sun.COM  */
6469781SMoriah.Waterland@Sun.COM int
iscfile(void)6479781SMoriah.Waterland@Sun.COM iscfile(void)
6489781SMoriah.Waterland@Sun.COM {
6499781SMoriah.Waterland@Sun.COM 	char	contents[PATH_MAX];
6509781SMoriah.Waterland@Sun.COM 
6519781SMoriah.Waterland@Sun.COM 	(void) snprintf(contents, PATH_MAX, "%s/contents", get_PKGADM());
6529781SMoriah.Waterland@Sun.COM 
6539781SMoriah.Waterland@Sun.COM 	return (access(contents, F_OK) == 0 ? 1 : 0);
6549781SMoriah.Waterland@Sun.COM }
6559781SMoriah.Waterland@Sun.COM 
6569781SMoriah.Waterland@Sun.COM /*
6579781SMoriah.Waterland@Sun.COM  * This function verifies that the contents file is in place. If it is - no
6589781SMoriah.Waterland@Sun.COM  * change. If it isn't - this creates it.
6599781SMoriah.Waterland@Sun.COM  * Returns:	== 0 : failure
6609781SMoriah.Waterland@Sun.COM  *		!= 0 : success
6619781SMoriah.Waterland@Sun.COM  */
6629781SMoriah.Waterland@Sun.COM 
6639781SMoriah.Waterland@Sun.COM int
vcfile(void)6649781SMoriah.Waterland@Sun.COM vcfile(void)
6659781SMoriah.Waterland@Sun.COM {
6669781SMoriah.Waterland@Sun.COM 	int	lerrno;
6679781SMoriah.Waterland@Sun.COM 	int	fd;
6689781SMoriah.Waterland@Sun.COM 	char	contents[PATH_MAX];
6699781SMoriah.Waterland@Sun.COM 
6709781SMoriah.Waterland@Sun.COM 	/*
6719781SMoriah.Waterland@Sun.COM 	 * create full path to contents file
6729781SMoriah.Waterland@Sun.COM 	 */
6739781SMoriah.Waterland@Sun.COM 
6749781SMoriah.Waterland@Sun.COM 	(void) snprintf(contents, sizeof (contents),
675*12497SCasper.Dik@Sun.COM 	    "%s/contents", get_PKGADM());
6769781SMoriah.Waterland@Sun.COM 
6779781SMoriah.Waterland@Sun.COM 	/*
6789781SMoriah.Waterland@Sun.COM 	 * Attempt to create the file - will only be successful
6799781SMoriah.Waterland@Sun.COM 	 * if the file does not currently exist.
6809781SMoriah.Waterland@Sun.COM 	 */
6819781SMoriah.Waterland@Sun.COM 
6829781SMoriah.Waterland@Sun.COM 	fd = open(contents, O_WRONLY | O_CREAT | O_EXCL, 0644);
6839781SMoriah.Waterland@Sun.COM 	if (fd >= 0) {
6849781SMoriah.Waterland@Sun.COM 		/*
6859781SMoriah.Waterland@Sun.COM 		 * Contents file wasn't there, but is now.
6869781SMoriah.Waterland@Sun.COM 		 */
6879781SMoriah.Waterland@Sun.COM 
6889781SMoriah.Waterland@Sun.COM 		echo(gettext("## Software contents file initialized"));
6899781SMoriah.Waterland@Sun.COM 		(void) close(fd);
6909781SMoriah.Waterland@Sun.COM 		return (1);	/* success */
6919781SMoriah.Waterland@Sun.COM 	}
6929781SMoriah.Waterland@Sun.COM 
6939781SMoriah.Waterland@Sun.COM 	/*
6949781SMoriah.Waterland@Sun.COM 	 * Could not create the file - it may exist or there may be
6959781SMoriah.Waterland@Sun.COM 	 * permissions issues - find out and act accordingly.
6969781SMoriah.Waterland@Sun.COM 	 */
6979781SMoriah.Waterland@Sun.COM 
6989781SMoriah.Waterland@Sun.COM 	lerrno = errno;
6999781SMoriah.Waterland@Sun.COM 
7009781SMoriah.Waterland@Sun.COM 	/* success if error is 'file exists' */
7019781SMoriah.Waterland@Sun.COM 
7029781SMoriah.Waterland@Sun.COM 	if (lerrno == EEXIST) {
7039781SMoriah.Waterland@Sun.COM 		return (1);	/* success */
7049781SMoriah.Waterland@Sun.COM 	}
7059781SMoriah.Waterland@Sun.COM 
7069781SMoriah.Waterland@Sun.COM 	/* success if error is 'permission denied' but file exists */
7079781SMoriah.Waterland@Sun.COM 
7089781SMoriah.Waterland@Sun.COM 	if (lerrno == EACCES) {
7099781SMoriah.Waterland@Sun.COM 		/*
7109781SMoriah.Waterland@Sun.COM 		 * Because O_CREAT and O_EXCL are specified in open(),
7119781SMoriah.Waterland@Sun.COM 		 * if the contents file already exists, the open will
7129781SMoriah.Waterland@Sun.COM 		 * fail with EACCES - determine if this is the case -
7139781SMoriah.Waterland@Sun.COM 		 * if so return success.
7149781SMoriah.Waterland@Sun.COM 		 */
7159781SMoriah.Waterland@Sun.COM 
7169781SMoriah.Waterland@Sun.COM 		if (access(contents, F_OK) == 0) {
7179781SMoriah.Waterland@Sun.COM 			return (1);	/* success */
7189781SMoriah.Waterland@Sun.COM 		}
7199781SMoriah.Waterland@Sun.COM 
7209781SMoriah.Waterland@Sun.COM 		/*
7219781SMoriah.Waterland@Sun.COM 		 * access() failed - if because of permissions failure this
7229781SMoriah.Waterland@Sun.COM 		 * means the contents file exists but it cannot be accessed
7239781SMoriah.Waterland@Sun.COM 		 * or the path to the contents file cannot be accessed - in
7249781SMoriah.Waterland@Sun.COM 		 * either case the contents file cannot be accessed.
7259781SMoriah.Waterland@Sun.COM 		 */
7269781SMoriah.Waterland@Sun.COM 
7279781SMoriah.Waterland@Sun.COM 		if (errno == EACCES) {
7289781SMoriah.Waterland@Sun.COM 			progerr(gettext(ERR_ACCESS_CONT), contents,
729*12497SCasper.Dik@Sun.COM 			    strerror(lerrno));
7309781SMoriah.Waterland@Sun.COM 			logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
7319781SMoriah.Waterland@Sun.COM 			return (0);	/* failure */
7329781SMoriah.Waterland@Sun.COM 		}
7339781SMoriah.Waterland@Sun.COM 	}
7349781SMoriah.Waterland@Sun.COM 
7359781SMoriah.Waterland@Sun.COM 	/*
7369781SMoriah.Waterland@Sun.COM 	 * the contents file does not exist and it cannot be created.
7379781SMoriah.Waterland@Sun.COM 	 */
7389781SMoriah.Waterland@Sun.COM 
7399781SMoriah.Waterland@Sun.COM 	progerr(gettext(ERR_CREAT_CONT), contents, strerror(lerrno));
7409781SMoriah.Waterland@Sun.COM 	logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
7419781SMoriah.Waterland@Sun.COM 	return (0);	/* failure */
7429781SMoriah.Waterland@Sun.COM }
743