xref: /titanic_51/usr/src/cmd/svr4pkg/libinst/ocfile.c (revision 62224350e5355e6834f7deb9d8a7d062a50cb7c2)
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*62224350SCasper H.S. Dik  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
245c51f124SMoriah Waterland  * Use is subject to license terms.
255c51f124SMoriah Waterland  */
265c51f124SMoriah Waterland 
275c51f124SMoriah Waterland /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
285c51f124SMoriah Waterland /* All Rights Reserved */
295c51f124SMoriah Waterland 
305c51f124SMoriah Waterland 
315c51f124SMoriah Waterland #include <stdio.h>
325c51f124SMoriah Waterland #include <fcntl.h>
335c51f124SMoriah Waterland #include <sys/types.h>
345c51f124SMoriah Waterland #include <sys/param.h>
355c51f124SMoriah Waterland #include <sys/sysmacros.h>
365c51f124SMoriah Waterland #include <string.h>
375c51f124SMoriah Waterland #include <strings.h>
385c51f124SMoriah Waterland #include <sys/wait.h>
395c51f124SMoriah Waterland #include <sys/stat.h>
405c51f124SMoriah Waterland #include <sys/mman.h>
415c51f124SMoriah Waterland #include <sys/statvfs.h>
425c51f124SMoriah Waterland #include <signal.h>
435c51f124SMoriah Waterland #include <limits.h>
445c51f124SMoriah Waterland #include <errno.h>
455c51f124SMoriah Waterland #include <fcntl.h>
465c51f124SMoriah Waterland #include <stdlib.h>
475c51f124SMoriah Waterland #include <unistd.h>
485c51f124SMoriah Waterland #include <time.h>
495c51f124SMoriah Waterland #include <errno.h>
505c51f124SMoriah Waterland #include <pkglocs.h>
515c51f124SMoriah Waterland #include <locale.h>
525c51f124SMoriah Waterland #include <libintl.h>
535c51f124SMoriah Waterland #include <pkglib.h>
545c51f124SMoriah Waterland #include "libinst.h"
555c51f124SMoriah Waterland #include "libadm.h"
565c51f124SMoriah Waterland 
57*62224350SCasper H.S. Dik #define	LOCKFILE	".pkg.lock.client"
58*62224350SCasper H.S. Dik #define	LOCKFILESERV	".pkg.lock"
59*62224350SCasper H.S. Dik 
605c51f124SMoriah Waterland #define	LOCKWAIT	10	/* seconds between retries */
615c51f124SMoriah Waterland #define	LOCKRETRY	20	/* number of retries for a DB lock */
625c51f124SMoriah Waterland 
63*62224350SCasper H.S. Dik #define	ERR_COMMIT	"WARNING: unable to commit contents database update"
645c51f124SMoriah Waterland #define	ERR_NOCLOSE	"WARNING: unable to close <%s>"
655c51f124SMoriah Waterland #define	ERR_NOUNLINK_LATENT	"WARNING: unable to unlink latent <%s>"
665c51f124SMoriah Waterland #define	ERR_LINK_FAIL	"link(%s, %s) failed (errno %d)"
675c51f124SMoriah Waterland #define	ERR_NORENAME_CONTENTS	"unable to establish contents file <%s> "\
685c51f124SMoriah Waterland 			"from <%s>"
695c51f124SMoriah Waterland #define	ERR_RENAME_FAIL	"rename(%s, %s) failed (errno %d)"
705c51f124SMoriah Waterland #define	ERR_RESTORE_FAIL	"attempt to restore <%s> failed"
715c51f124SMoriah Waterland #define	ERR_NOUNLINK	"WARNING: unable to unlink <%s>"
725c51f124SMoriah Waterland #define	ERR_FCLOSE_FAIL	"fclose failed (errno %d)"
735c51f124SMoriah Waterland #define	ERR_ERRNO	"(errno %d: %s)"
745c51f124SMoriah Waterland #define	ERR_NOTMPOPEN	"unable to open temporary contents file image"
755c51f124SMoriah Waterland #define	ERR_CFBACK	"Not enough space to backup <%s>"
765c51f124SMoriah Waterland #define	ERR_CREAT_CONT	"unable to create contents file <%s>: %s"
775c51f124SMoriah Waterland #define	ERR_ACCESS_CONT	"unable to access contents file <%s>: %s"
785c51f124SMoriah Waterland #define	ERR_CFBACK1	"Need=%llu blocks, Available=%llu blocks " \
795c51f124SMoriah Waterland 			"(block size=%d)"
805c51f124SMoriah Waterland #define	ERR_NOCFILE	"unable to locate contents file <%s>"
815c51f124SMoriah Waterland #define	ERR_NOROPEN	"unable to open <%s> for reading"
825c51f124SMoriah Waterland #define	ERR_NOOPEN	"unable to open <%s> for writing"
835c51f124SMoriah Waterland #define	ERR_NOSTAT	"unable to stat contents file <%s>"
845c51f124SMoriah Waterland #define	ERR_NOSTATV	"statvfs(%s) failed"
855c51f124SMoriah Waterland #define	ERR_NOUPD	"unable to update contents file"
865c51f124SMoriah Waterland #define	ERR_DRCONTCP	"unable to copy contents file to <%s>"
875c51f124SMoriah Waterland 
885c51f124SMoriah Waterland #define	MSG_XWTING	"NOTE: Waiting for exclusive access to the package " \
895c51f124SMoriah Waterland 				"database."
905c51f124SMoriah Waterland #define	MSG_NOLOCK	"NOTE: Couldn't lock the package database."
915c51f124SMoriah Waterland 
925c51f124SMoriah Waterland #define	ERR_NOLOCK	"Database lock failed."
935c51f124SMoriah Waterland #define	ERR_OPLOCK	"unable to open lock file <%s>."
945c51f124SMoriah Waterland #define	ERR_MKLOCK	"unable to create lock file <%s>."
955c51f124SMoriah Waterland #define	ERR_LCKREM	"unable to lock package database - remote host " \
965c51f124SMoriah Waterland 				"unavailable."
975c51f124SMoriah Waterland #define	ERR_BADLCK	"unable to lock package database - unknown error."
985c51f124SMoriah Waterland #define	ERR_DEADLCK	"unable to lock package database - deadlock condition."
995c51f124SMoriah Waterland #define	ERR_TMOUT	"unable to lock package database - too many retries."
1005c51f124SMoriah Waterland #define	ERR_CFDIR	"unable to locate contents file directory"
1015c51f124SMoriah Waterland 
1025c51f124SMoriah Waterland static int	active_lock;
1035c51f124SMoriah Waterland static int	lock_fd;	/* fd of LOCKFILE. */
1045c51f124SMoriah Waterland static char	*pkgadm_dir;
1055c51f124SMoriah Waterland 
106*62224350SCasper H.S. Dik int		pkgWlock(int verbose);
1075c51f124SMoriah Waterland static int	pkgWunlock(void);
1085c51f124SMoriah Waterland 
1095c51f124SMoriah Waterland /* forward declarations */
1105c51f124SMoriah Waterland 
1115c51f124SMoriah Waterland int relslock(void);
1125c51f124SMoriah Waterland 
1135c51f124SMoriah Waterland /*ARGSUSED*/
1145c51f124SMoriah Waterland static void
1155c51f124SMoriah Waterland do_alarm(int n)
1165c51f124SMoriah Waterland {
1175c51f124SMoriah Waterland 	(void) signal(SIGALRM, SIG_IGN);
1185c51f124SMoriah Waterland 	(void) signal(SIGALRM, do_alarm);
1195c51f124SMoriah Waterland 	(void) alarm(LOCKWAIT);
1205c51f124SMoriah Waterland }
1215c51f124SMoriah Waterland 
1225c51f124SMoriah Waterland /*
1235c51f124SMoriah Waterland  * Point packaging to the appropriate contents file. This is primarily used
1245c51f124SMoriah Waterland  * to establish a dryrun contents file. If the malloc() doesn't work, this
1255c51f124SMoriah Waterland  * returns 99 (internal error), else 0.
1265c51f124SMoriah Waterland  */
1275c51f124SMoriah Waterland int
1285c51f124SMoriah Waterland set_cfdir(char *cfdir)
1295c51f124SMoriah Waterland {
1305c51f124SMoriah Waterland 	char	realcf[PATH_MAX];
1315c51f124SMoriah Waterland 	char	tmpcf[PATH_MAX];
1325c51f124SMoriah Waterland 	int	status;
1335c51f124SMoriah Waterland 
1345c51f124SMoriah Waterland 	if (cfdir == NULL) {
1355c51f124SMoriah Waterland 		pkgadm_dir = get_PKGADM();
1365c51f124SMoriah Waterland 		return (0);
1375c51f124SMoriah Waterland 	}
1385c51f124SMoriah Waterland 
1395c51f124SMoriah Waterland 	if ((pkgadm_dir = strdup(cfdir)) == NULL) {
1405c51f124SMoriah Waterland 		return (99);
1415c51f124SMoriah Waterland 	}
1425c51f124SMoriah Waterland 
1435c51f124SMoriah Waterland 	(void) snprintf(tmpcf, sizeof (tmpcf), "%s/contents", pkgadm_dir);
1445c51f124SMoriah Waterland 
1455c51f124SMoriah Waterland 	/*
1465c51f124SMoriah Waterland 	 * return if a temporary contents file already exists -
1475c51f124SMoriah Waterland 	 * assume it is from a prior package in this series.
1485c51f124SMoriah Waterland 	 */
1495c51f124SMoriah Waterland 
1505c51f124SMoriah Waterland 	if (access(tmpcf, F_OK) == 0) {
1515c51f124SMoriah Waterland 		return (0);
1525c51f124SMoriah Waterland 	}
1535c51f124SMoriah Waterland 
1545c51f124SMoriah Waterland 	/*
1555c51f124SMoriah Waterland 	 * no temporary contents file exists - create one.
1565c51f124SMoriah Waterland 	 */
1575c51f124SMoriah Waterland 
1585c51f124SMoriah Waterland 	(void) snprintf(realcf, sizeof (realcf), "%s/contents", get_PKGADM());
1595c51f124SMoriah Waterland 
1605c51f124SMoriah Waterland 	/*
1615c51f124SMoriah Waterland 	 * If there's a contents file there already, copy it
162*62224350SCasper H.S. Dik 	 * over, otherwise initialize one.  Make sure that the
163*62224350SCasper H.S. Dik 	 * server, if running, flushes the contents file.
1645c51f124SMoriah Waterland 	 */
1655c51f124SMoriah Waterland 
166*62224350SCasper H.S. Dik 	(void) pkgsync(NULL, get_PKGADM(), B_FALSE);
167*62224350SCasper H.S. Dik 
1685c51f124SMoriah Waterland 	/* create new contents file if one does not already exist */
1695c51f124SMoriah Waterland 
1705c51f124SMoriah Waterland 	if (access(realcf, F_OK) != 0) {
1715c51f124SMoriah Waterland 		int n;
1725c51f124SMoriah Waterland 
1735c51f124SMoriah Waterland 		n = open(tmpcf, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
1745c51f124SMoriah Waterland 		if (n < 0) {
1755c51f124SMoriah Waterland 			progerr(gettext(ERR_CREAT_CONT), tmpcf,
1765c51f124SMoriah Waterland 			    strerror(errno));
1775c51f124SMoriah Waterland 			return (99);
1785c51f124SMoriah Waterland 		}
1795c51f124SMoriah Waterland 		(void) close(n);
1805c51f124SMoriah Waterland 	} else {
1815c51f124SMoriah Waterland 
1825c51f124SMoriah Waterland 		/* contents file exists, save in pkgadm-dir */
1835c51f124SMoriah Waterland 
1845c51f124SMoriah Waterland 		status = copyf(realcf, tmpcf, (time_t)0);
1855c51f124SMoriah Waterland 		if (status != 0) {
1865c51f124SMoriah Waterland 			progerr(gettext(ERR_DRCONTCP), tmpcf);
1875c51f124SMoriah Waterland 			return (99);
1885c51f124SMoriah Waterland 		}
1895c51f124SMoriah Waterland 	}
1905c51f124SMoriah Waterland 
1915c51f124SMoriah Waterland 	return (0);
1925c51f124SMoriah Waterland }
1935c51f124SMoriah Waterland 
1945c51f124SMoriah Waterland /*
1955c51f124SMoriah Waterland  * This function installs the database lock, opens the contents file for
1965c51f124SMoriah Waterland  * reading and creates and opens the temporary contents file for read/write.
1975c51f124SMoriah Waterland  * It returns 1 if successful, 0 otherwise.
1985c51f124SMoriah Waterland  */
1995c51f124SMoriah Waterland int
200*62224350SCasper H.S. Dik ocfile(PKGserver *server, VFP_T **r_tmpvfp, fsblkcnt_t map_blks)
2015c51f124SMoriah Waterland {
2025c51f124SMoriah Waterland 	struct	stat64	statb;
2035c51f124SMoriah Waterland 	struct	statvfs64	svfsb;
2045c51f124SMoriah Waterland 	fsblkcnt_t free_blocks;
2055c51f124SMoriah Waterland 	fsblkcnt_t need_blocks;
2065c51f124SMoriah Waterland 	VFP_T		*tmpvfp = (VFP_T *)NULL;
2075c51f124SMoriah Waterland 	char		contents[PATH_MAX];
2085c51f124SMoriah Waterland 	int		n;
209*62224350SCasper H.S. Dik 	off_t		cdiff_alloc;
210*62224350SCasper H.S. Dik 	PKGserver	newserver;
2115c51f124SMoriah Waterland 
2125c51f124SMoriah Waterland 	/* establish package administration contents directory location */
2135c51f124SMoriah Waterland 
2145c51f124SMoriah Waterland 	if (pkgadm_dir == NULL) {
2155c51f124SMoriah Waterland 		if (set_cfdir(NULL) != 0) {
2165c51f124SMoriah Waterland 			progerr(gettext(ERR_CFDIR));
2175c51f124SMoriah Waterland 			return (0);
2185c51f124SMoriah Waterland 		}
2195c51f124SMoriah Waterland 	}
2205c51f124SMoriah Waterland 
2215c51f124SMoriah Waterland 	/* Lock the file for exclusive access */
2225c51f124SMoriah Waterland 
2235c51f124SMoriah Waterland 	if (!pkgWlock(1)) {
2245c51f124SMoriah Waterland 		progerr(gettext(ERR_NOLOCK));
2255c51f124SMoriah Waterland 		return (0);
2265c51f124SMoriah Waterland 	}
2275c51f124SMoriah Waterland 
228*62224350SCasper H.S. Dik 	if (*server != NULL) {
229*62224350SCasper H.S. Dik 		vfpTruncate(*r_tmpvfp);
230*62224350SCasper H.S. Dik 		(void) vfpClearModified(*r_tmpvfp);
2315c51f124SMoriah Waterland 
232*62224350SCasper H.S. Dik 		return (1);
2335c51f124SMoriah Waterland 	}
2345c51f124SMoriah Waterland 
235*62224350SCasper H.S. Dik 	newserver = pkgopenserver(NULL, pkgadm_dir, B_FALSE);
236*62224350SCasper H.S. Dik 
237*62224350SCasper H.S. Dik 	/* The error has been reported. */
238*62224350SCasper H.S. Dik 	if (newserver == NULL)
2395c51f124SMoriah Waterland 		return (0);
240*62224350SCasper H.S. Dik 
241*62224350SCasper H.S. Dik 	/* reset return VFP/FILE pointers */
242*62224350SCasper H.S. Dik 
243*62224350SCasper H.S. Dik 	(*r_tmpvfp) = (VFP_T *)NULL;
244*62224350SCasper H.S. Dik 
245*62224350SCasper H.S. Dik 	/* determine path to the primary contents file */
246*62224350SCasper H.S. Dik 	(void) snprintf(contents, sizeof (contents), "%s/contents", pkgadm_dir);
2475c51f124SMoriah Waterland 
2485c51f124SMoriah Waterland 	/*
2495c51f124SMoriah Waterland 	 * Check and see if there is enough space for the packaging commands
2505c51f124SMoriah Waterland 	 * to back up the contents file, if there is not, then do not allow
2515c51f124SMoriah Waterland 	 * execution to continue by failing the ocfile() call.
2525c51f124SMoriah Waterland 	 */
2535c51f124SMoriah Waterland 
2545c51f124SMoriah Waterland 	/* Get the contents file size */
2555c51f124SMoriah Waterland 
256*62224350SCasper H.S. Dik 	if (stat64(contents, &statb) == -1) {
2575c51f124SMoriah Waterland 		int	lerrno = errno;
2585c51f124SMoriah Waterland 
259*62224350SCasper H.S. Dik 		progerr(gettext(ERR_NOCFILE), contents);
2605c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
261*62224350SCasper H.S. Dik 		pkgcloseserver(newserver);
2625c51f124SMoriah Waterland 		return (0);
2635c51f124SMoriah Waterland 	}
2645c51f124SMoriah Waterland 
2655c51f124SMoriah Waterland 	/* Get the filesystem space */
2665c51f124SMoriah Waterland 
267*62224350SCasper H.S. Dik 	if (statvfs64(contents, &svfsb) == -1) {
2685c51f124SMoriah Waterland 		int	lerrno = errno;
2695c51f124SMoriah Waterland 
2705c51f124SMoriah Waterland 		progerr(gettext(ERR_NOSTATV), contents);
2715c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
272*62224350SCasper H.S. Dik 		pkgcloseserver(newserver);
2735c51f124SMoriah Waterland 		return (0);
2745c51f124SMoriah Waterland 	}
2755c51f124SMoriah Waterland 
2765c51f124SMoriah Waterland 	free_blocks = (((fsblkcnt_t)svfsb.f_frsize > 0) ?
2775c51f124SMoriah Waterland 			howmany(svfsb.f_frsize, DEV_BSIZE) :
2785c51f124SMoriah Waterland 			howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bfree;
2795c51f124SMoriah Waterland 
280*62224350SCasper H.S. Dik 	/*
281*62224350SCasper H.S. Dik 	 * If we're removing a package, then the log might grow to the size
282*62224350SCasper H.S. Dik 	 * of the full contents file.
283*62224350SCasper H.S. Dik 	 */
284*62224350SCasper H.S. Dik 
285*62224350SCasper H.S. Dik 	if (map_blks == 0LL)
286*62224350SCasper H.S. Dik 		map_blks = nblk(statb.st_size, svfsb.f_bsize, svfsb.f_frsize);
2875c51f124SMoriah Waterland 
2885c51f124SMoriah Waterland 	/*
2895c51f124SMoriah Waterland 	 * Calculate the number of blocks we need to be able to operate on
2905c51f124SMoriah Waterland 	 * the contents file.
2915c51f124SMoriah Waterland 	 */
2925c51f124SMoriah Waterland 	need_blocks = map_blks +
293*62224350SCasper H.S. Dik 		/* Max of the log file */
294*62224350SCasper H.S. Dik 		nblk(MAXLOGFILESIZE, svfsb.f_bsize, svfsb.f_frsize) +
295*62224350SCasper H.S. Dik 		/* Current content file */
2965c51f124SMoriah Waterland 		nblk(statb.st_size, svfsb.f_bsize, svfsb.f_frsize);
2975c51f124SMoriah Waterland 
2985c51f124SMoriah Waterland 	if ((need_blocks + 10) > free_blocks) {
2995c51f124SMoriah Waterland 		progerr(gettext(ERR_CFBACK), contents);
3005c51f124SMoriah Waterland 		progerr(gettext(ERR_CFBACK1), need_blocks, free_blocks,
3015c51f124SMoriah Waterland 			DEV_BSIZE);
302*62224350SCasper H.S. Dik 		pkgcloseserver(newserver);
3035c51f124SMoriah Waterland 		return (0);
3045c51f124SMoriah Waterland 	}
3055c51f124SMoriah Waterland 
3065c51f124SMoriah Waterland 	/*
3075c51f124SMoriah Waterland 	 * open the temporary contents file without a path name - this causes
3085c51f124SMoriah Waterland 	 * the "vfp" to be opened on in-memory storage only, the size of which
3095c51f124SMoriah Waterland 	 * is set following a successful return - this causes the temporary
3105c51f124SMoriah Waterland 	 * contents file to be maintained in memory only - if no changes are
3115c51f124SMoriah Waterland 	 * made as the primary contents file is processed, the in memory data
3125c51f124SMoriah Waterland 	 * is discarded and not written to the disk.
3135c51f124SMoriah Waterland 	 */
3145c51f124SMoriah Waterland 
3155c51f124SMoriah Waterland 	if (vfpOpen(&tmpvfp, (char *)NULL, "w", VFP_NONE) != 0) {
3165c51f124SMoriah Waterland 		int	lerrno = errno;
3175c51f124SMoriah Waterland 
3185c51f124SMoriah Waterland 		progerr(gettext(ERR_NOTMPOPEN));
3195c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
320*62224350SCasper H.S. Dik 		pkgcloseserver(newserver);
3215c51f124SMoriah Waterland 		return (0);
3225c51f124SMoriah Waterland 	}
3235c51f124SMoriah Waterland 
3245c51f124SMoriah Waterland 	/*
3255c51f124SMoriah Waterland 	 * set size of allocation for temporary contents file - this sets the
3265c51f124SMoriah Waterland 	 * size of the in-memory buffer associated with the open vfp.
327*62224350SCasper H.S. Dik 	 * We only store the new and changed entries.
328*62224350SCasper H.S. Dik 	 * We allocate memory depending on the size of the pkgmap; it's not
329*62224350SCasper H.S. Dik 	 * completely right but <some value + * 1.5 * map_blks * DEV_BSIZE>
330*62224350SCasper H.S. Dik 	 * seems fine (an install adds the size if the name of the package.)
3315c51f124SMoriah Waterland 	 */
3325c51f124SMoriah Waterland 
333*62224350SCasper H.S. Dik 	cdiff_alloc = map_blks * DEV_BSIZE;
334*62224350SCasper H.S. Dik 	cdiff_alloc += cdiff_alloc/2;
335*62224350SCasper H.S. Dik 	if (cdiff_alloc < 1000000)
336*62224350SCasper H.S. Dik 		cdiff_alloc += 1000000;
337*62224350SCasper H.S. Dik 
338*62224350SCasper H.S. Dik 	if (vfpSetSize(tmpvfp, cdiff_alloc) != 0) {
3395c51f124SMoriah Waterland 		int	lerrno = errno;
3405c51f124SMoriah Waterland 
3415c51f124SMoriah Waterland 		progerr(gettext(ERR_NOTMPOPEN));
3425c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
3435c51f124SMoriah Waterland 		(void) vfpClose(&tmpvfp);
344*62224350SCasper H.S. Dik 		pkgcloseserver(newserver);
3455c51f124SMoriah Waterland 		return (0);
3465c51f124SMoriah Waterland 	}
3475c51f124SMoriah Waterland 
348*62224350SCasper H.S. Dik 	/* set return ->s to open server/vfps */
3495c51f124SMoriah Waterland 
3505c51f124SMoriah Waterland 	(*r_tmpvfp) = tmpvfp;
351*62224350SCasper H.S. Dik 	*server = newserver;
3525c51f124SMoriah Waterland 
3535c51f124SMoriah Waterland 	return (1);	/* All OK */
3545c51f124SMoriah Waterland }
3555c51f124SMoriah Waterland 
3565c51f124SMoriah Waterland /*
3575c51f124SMoriah Waterland  * This is a simple open and lock of the contents file. It doesn't create a
3585c51f124SMoriah Waterland  * temporary contents file and it doesn't need to do any space checking.
3595c51f124SMoriah Waterland  * Returns 1 for OK and 0 for "didn't do it".
3605c51f124SMoriah Waterland  */
3615c51f124SMoriah Waterland int
362*62224350SCasper H.S. Dik socfile(PKGserver *server, boolean_t quiet)
3635c51f124SMoriah Waterland {
3645c51f124SMoriah Waterland 	char		contents[PATH_MAX];
365*62224350SCasper H.S. Dik 	boolean_t 	readonly = B_FALSE;
366*62224350SCasper H.S. Dik 	PKGserver	newserver;
3675c51f124SMoriah Waterland 
3685c51f124SMoriah Waterland 	if (pkgadm_dir == NULL) {
3695c51f124SMoriah Waterland 		if (set_cfdir(NULL) != 0) {
3705c51f124SMoriah Waterland 			progerr(gettext(ERR_CFDIR));
3715c51f124SMoriah Waterland 			return (0);
3725c51f124SMoriah Waterland 		}
3735c51f124SMoriah Waterland 	}
3745c51f124SMoriah Waterland 
3755c51f124SMoriah Waterland 	/*
3765c51f124SMoriah Waterland 	 * Lock the database for exclusive access, but don't make a fuss if
3775c51f124SMoriah Waterland 	 * it fails (user may not be root and the .pkg.lock file may not
3785c51f124SMoriah Waterland 	 * exist yet).
3795c51f124SMoriah Waterland 	 */
3805c51f124SMoriah Waterland 
3815c51f124SMoriah Waterland 	if (!pkgWlock(0)) {
382*62224350SCasper H.S. Dik 		if (!quiet)
3835c51f124SMoriah Waterland 			logerr(gettext(MSG_NOLOCK));
384*62224350SCasper H.S. Dik 		readonly = B_TRUE;
3855c51f124SMoriah Waterland 	}
3865c51f124SMoriah Waterland 
387*62224350SCasper H.S. Dik 	newserver = pkgopenserver(NULL, pkgadm_dir, readonly);
388*62224350SCasper H.S. Dik 	if (newserver == NULL)
3895c51f124SMoriah Waterland 		return (0);
3905c51f124SMoriah Waterland 
391*62224350SCasper H.S. Dik 	*server = newserver;
3925c51f124SMoriah Waterland 	return (1);
3935c51f124SMoriah Waterland }
3945c51f124SMoriah Waterland 
3955c51f124SMoriah Waterland /*
3965c51f124SMoriah Waterland  * Name:	swapcfile
3975c51f124SMoriah Waterland  * Description: This function closes both the current and temporary contents
3985c51f124SMoriah Waterland  *		files specified, and conditionally replaces the old transitory
3995c51f124SMoriah Waterland  *		contents file with the newly updated temporary contents file.
4005c51f124SMoriah Waterland  *		The "ocfile()" or "socfile()" functions must be called to re-
4015c51f124SMoriah Waterland  *		open the real contents file for processing.
402*62224350SCasper H.S. Dik  * Arguments:	PKGserver - handle to the package database
4035c51f124SMoriah Waterland  *		a_cfTmpVfp - (VFP_T **) - [RW, *RW]
404*62224350SCasper H.S. Dik  *			This is the VFP associated which contains all the
405*62224350SCasper H.S. Dik  *			modifications to be written back to the database.
4065c51f124SMoriah Waterland  *			file that is being written to.
4075c51f124SMoriah Waterland  *		pkginst - (char) - [RO, *RO]
4085c51f124SMoriah Waterland  *			This is the name of the package being operated on;
4095c51f124SMoriah Waterland  *			this is used to write the "last modified by xxx"
4105c51f124SMoriah Waterland  *			comment at the end of the contents file.
4115c51f124SMoriah Waterland  *		dbchg - (int) - [RO]
4125c51f124SMoriah Waterland  *			== 0 - the temporary contents file has NOT been changed
4135c51f124SMoriah Waterland  *				with respect to the real contents file; do not
4145c51f124SMoriah Waterland  *				update the real contents file with the contents
4155c51f124SMoriah Waterland  *				of the temporary contents file.
4165c51f124SMoriah Waterland  *			!= 0 - the temporary contetns file HAS been changed with
4175c51f124SMoriah Waterland  *				respect to the real contents file; DO update the
4185c51f124SMoriah Waterland  *				real contents file with the contents of the
4195c51f124SMoriah Waterland  *				temporary contents file.
4205c51f124SMoriah Waterland  * Returns:	int	== RESULT_OK - successful
4215c51f124SMoriah Waterland  *			== RESULT_WRN - successful with warnings
4225c51f124SMoriah Waterland  *			== RESULT_ERR - failed with fatal errors - deserves an
4235c51f124SMoriah Waterland  *				alarming message and a quit()
4245c51f124SMoriah Waterland  * NOTES: If dbchg != 0, the contents file is always updated. If dbchg == 0,
4255c51f124SMoriah Waterland  *		the contents file is updated IF the data is modified indication
4265c51f124SMoriah Waterland  *		is set on the contents file associated with a_cfTmpVfp.
4275c51f124SMoriah Waterland  */
4285c51f124SMoriah Waterland 
4295c51f124SMoriah Waterland int
430*62224350SCasper H.S. Dik swapcfile(PKGserver server, VFP_T **a_cfTmpVfp, char *pkginst, int dbchg)
4315c51f124SMoriah Waterland {
4325c51f124SMoriah Waterland 	char	*pe;
4335c51f124SMoriah Waterland 	char	*pl;
4345c51f124SMoriah Waterland 	char	*ps;
4355c51f124SMoriah Waterland 	char	line[256];
4365c51f124SMoriah Waterland 	char	timeb[BUFSIZ];
4375c51f124SMoriah Waterland 	int	retval = RESULT_OK;
4385c51f124SMoriah Waterland 	struct tm	*timep;
4395c51f124SMoriah Waterland 	time_t	clock;
4405c51f124SMoriah Waterland 
4415c51f124SMoriah Waterland 	/* normalize pkginst so its never null */
4425c51f124SMoriah Waterland 
4435c51f124SMoriah Waterland 	if (pkginst == (char *)NULL) {
4445c51f124SMoriah Waterland 		dbchg = 0;
4455c51f124SMoriah Waterland 		pkginst = "<unknown>";
4465c51f124SMoriah Waterland 	}
4475c51f124SMoriah Waterland 
4485c51f124SMoriah Waterland 	/*
4495c51f124SMoriah Waterland 	 * If no changes were made to the database, checkpoint the temporary
4505c51f124SMoriah Waterland 	 * contents file - if this fails, then just close the file which causes
4515c51f124SMoriah Waterland 	 * the contents file to be reopened and reread if it is needed again
4525c51f124SMoriah Waterland 	 */
4535c51f124SMoriah Waterland 
4545c51f124SMoriah Waterland 	if ((dbchg == 0) && (vfpGetModified(*a_cfTmpVfp) == 0)) {
4555c51f124SMoriah Waterland 		(void) pkgWunlock();	/* Free the database lock. */
4565c51f124SMoriah Waterland 		return (retval);
4575c51f124SMoriah Waterland 	}
4585c51f124SMoriah Waterland 
4595c51f124SMoriah Waterland 	/*
4605c51f124SMoriah Waterland 	 * changes made to the current temporary contents file -
4615c51f124SMoriah Waterland 	 * remove any trailing comment lines in the temp contents file, then
4625c51f124SMoriah Waterland 	 * append updated modification info records to temp contents file
4635c51f124SMoriah Waterland 	 */
4645c51f124SMoriah Waterland 
4655c51f124SMoriah Waterland 	pe = vfpGetCurrCharPtr(*a_cfTmpVfp);	/* last char in contents file */
4665c51f124SMoriah Waterland 	ps = vfpGetFirstCharPtr(*a_cfTmpVfp);	/* 1st char in contents file */
4675c51f124SMoriah Waterland 	pl = pe;	/* last match is last char in contents file */
4685c51f124SMoriah Waterland 
4695c51f124SMoriah Waterland 	/* skip past all trailing newlines and null bytes */
4705c51f124SMoriah Waterland 
4715c51f124SMoriah Waterland 	while ((pe > ps) && ((*pe == '\n') || (*pe == '\0'))) {
4725c51f124SMoriah Waterland 		pe--;
4735c51f124SMoriah Waterland 	}
4745c51f124SMoriah Waterland 
4755c51f124SMoriah Waterland 	/* remove trailing comments as long as there are lines in the file */
4765c51f124SMoriah Waterland 
4775c51f124SMoriah Waterland 	while (pe > ps) {
4785c51f124SMoriah Waterland 		if (*pe != '\n') {
4795c51f124SMoriah Waterland 			/* curr char is not newline: backup one byte */
4805c51f124SMoriah Waterland 			pl = pe--;
4815c51f124SMoriah Waterland 		} else if (*pl != '#') {
4825c51f124SMoriah Waterland 			/* curr char is newline next char not comment break */
4835c51f124SMoriah Waterland 			break;
4845c51f124SMoriah Waterland 		} else {
4855c51f124SMoriah Waterland 			/* curr char is newline next char is comment - remove */
4865c51f124SMoriah Waterland 			*pl = '\0';
4875c51f124SMoriah Waterland 			vfpSetLastCharPtr(*a_cfTmpVfp, pl);
4885c51f124SMoriah Waterland 			pe--;
4895c51f124SMoriah Waterland 		}
4905c51f124SMoriah Waterland 	}
4915c51f124SMoriah Waterland 
4925c51f124SMoriah Waterland 	/* create two update comment lines */
4935c51f124SMoriah Waterland 
4945c51f124SMoriah Waterland 	(void) time(&clock);
4955c51f124SMoriah Waterland 	timep = localtime(&clock);
4965c51f124SMoriah Waterland 
4975c51f124SMoriah Waterland 	(void) strftime(timeb, sizeof (timeb), "%c\n", timep);
4985c51f124SMoriah Waterland 	(void) snprintf(line, sizeof (line),
4995c51f124SMoriah Waterland 		gettext("# Last modified by %s for %s package\n# %s"),
5005c51f124SMoriah Waterland 		get_prog_name(), pkginst, timeb);
5015c51f124SMoriah Waterland 	vfpPuts(*a_cfTmpVfp, line);
5025c51f124SMoriah Waterland 
5035c51f124SMoriah Waterland 	/* commit temporary contents file bytes to storage */
5045c51f124SMoriah Waterland 
505*62224350SCasper H.S. Dik 	if (pkgservercommitfile(*a_cfTmpVfp, server) != 0) {
5065c51f124SMoriah Waterland 		int	lerrno = errno;
5075c51f124SMoriah Waterland 
508*62224350SCasper H.S. Dik 		logerr(gettext(ERR_COMMIT));
5095c51f124SMoriah Waterland 		vfpClose(a_cfTmpVfp);
510*62224350SCasper H.S. Dik 		pkgcloseserver(server);
5115c51f124SMoriah Waterland 		(void) pkgWunlock();	/* Free the database lock. */
5125c51f124SMoriah Waterland 		return (RESULT_ERR);
5135c51f124SMoriah Waterland 	}
5145c51f124SMoriah Waterland 
5155c51f124SMoriah Waterland 	return (relslock() == 0 ? RESULT_ERR : retval);
5165c51f124SMoriah Waterland }
5175c51f124SMoriah Waterland 
5185c51f124SMoriah Waterland /* This function releases the lock on the package database. */
5195c51f124SMoriah Waterland int
5205c51f124SMoriah Waterland relslock(void)
5215c51f124SMoriah Waterland {
5225c51f124SMoriah Waterland 	/*
5235c51f124SMoriah Waterland 	 * This closes the contents file and releases the lock.
5245c51f124SMoriah Waterland 	 */
5255c51f124SMoriah Waterland 	if (!pkgWunlock()) {
5265c51f124SMoriah Waterland 		int	lerrno = errno;
5275c51f124SMoriah Waterland 
5285c51f124SMoriah Waterland 		progerr(gettext(ERR_NOUPD));
5295c51f124SMoriah Waterland 		logerr(gettext(ERR_FCLOSE_FAIL), lerrno);
5305c51f124SMoriah Waterland 		return (0);
5315c51f124SMoriah Waterland 	}
5325c51f124SMoriah Waterland 	return (1);
5335c51f124SMoriah Waterland }
5345c51f124SMoriah Waterland 
5355c51f124SMoriah Waterland /*
5365c51f124SMoriah Waterland  * This function attempts to lock the package database. It returns 1 on
5375c51f124SMoriah Waterland  * success, 0 on failure. The positive logic verbose flag determines whether
5385c51f124SMoriah Waterland  * or not the function displays the error message upon failure.
5395c51f124SMoriah Waterland  */
540*62224350SCasper H.S. Dik int
5415c51f124SMoriah Waterland pkgWlock(int verbose) {
5425c51f124SMoriah Waterland 	int retry_cnt, retval;
5435c51f124SMoriah Waterland 	char lockpath[PATH_MAX];
5445c51f124SMoriah Waterland 
5455c51f124SMoriah Waterland 	active_lock = 0;
5465c51f124SMoriah Waterland 
5475c51f124SMoriah Waterland 	(void) snprintf(lockpath, sizeof (lockpath),
5485c51f124SMoriah Waterland 			"%s/%s", pkgadm_dir, LOCKFILE);
5495c51f124SMoriah Waterland 
5505c51f124SMoriah Waterland 	retry_cnt = LOCKRETRY;
5515c51f124SMoriah Waterland 
5525c51f124SMoriah Waterland 	/*
5535c51f124SMoriah Waterland 	 * If the lock file is not present, create it. The mode is set to
5545c51f124SMoriah Waterland 	 * allow any process to lock the database, that's because pkgchk may
5555c51f124SMoriah Waterland 	 * be run by a non-root user.
5565c51f124SMoriah Waterland 	 */
5575c51f124SMoriah Waterland 	if (access(lockpath, F_OK) == -1) {
5585c51f124SMoriah Waterland 		lock_fd = open(lockpath, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644);
5595c51f124SMoriah Waterland 		if (lock_fd < 0) {
5605c51f124SMoriah Waterland 			if (verbose)
5615c51f124SMoriah Waterland 				progerr(gettext(ERR_MKLOCK), lockpath);
5625c51f124SMoriah Waterland 			return (0);
5635c51f124SMoriah Waterland 		} else {
5645c51f124SMoriah Waterland 			(void) fchmod(lock_fd, 0644);	/* force perms. */
5655c51f124SMoriah Waterland 		}
5665c51f124SMoriah Waterland 	} else {
5675c51f124SMoriah Waterland 		if ((lock_fd = open(lockpath, O_RDWR)) == -1) {
5685c51f124SMoriah Waterland 			if (verbose)
5695c51f124SMoriah Waterland 				progerr(gettext(ERR_OPLOCK), lockpath);
5705c51f124SMoriah Waterland 			return (0);
5715c51f124SMoriah Waterland 		}
5725c51f124SMoriah Waterland 	}
5735c51f124SMoriah Waterland 
5745c51f124SMoriah Waterland 	(void) signal(SIGALRM, do_alarm);
5755c51f124SMoriah Waterland 	(void) alarm(LOCKWAIT);
5765c51f124SMoriah Waterland 
5775c51f124SMoriah Waterland 	do {
5785c51f124SMoriah Waterland 		if (lockf(lock_fd, F_LOCK, 0)) {
5795c51f124SMoriah Waterland 			if (errno == EAGAIN || errno == EINTR)
5805c51f124SMoriah Waterland 				logerr(gettext(MSG_XWTING));
5815c51f124SMoriah Waterland 			else if (errno == ECOMM) {
5825c51f124SMoriah Waterland 				logerr(gettext(ERR_LCKREM));
5835c51f124SMoriah Waterland 				retval = 0;
5845c51f124SMoriah Waterland 				break;
5855c51f124SMoriah Waterland 			} else if (errno == EBADF) {
5865c51f124SMoriah Waterland 				logerr(gettext(ERR_BADLCK));
5875c51f124SMoriah Waterland 				retval = 0;
5885c51f124SMoriah Waterland 				break;
5895c51f124SMoriah Waterland 			} else if (errno == EDEADLK) {
5905c51f124SMoriah Waterland 				logerr(gettext(ERR_DEADLCK));
5915c51f124SMoriah Waterland 				retval = 0;
5925c51f124SMoriah Waterland 				break;
5935c51f124SMoriah Waterland 			}
5945c51f124SMoriah Waterland 		} else {
5955c51f124SMoriah Waterland 			active_lock = 1;
5965c51f124SMoriah Waterland 			retval = 1;
5975c51f124SMoriah Waterland 			break;
5985c51f124SMoriah Waterland 		}
5995c51f124SMoriah Waterland 	} while (retry_cnt--);
6005c51f124SMoriah Waterland 
6015c51f124SMoriah Waterland 	(void) signal(SIGALRM, SIG_IGN);
6025c51f124SMoriah Waterland 
6035c51f124SMoriah Waterland 	if (retval == 0)
6045c51f124SMoriah Waterland 	{
6055c51f124SMoriah Waterland 		if (retry_cnt == -1) {
6065c51f124SMoriah Waterland 			logerr(gettext(ERR_TMOUT));
6075c51f124SMoriah Waterland 		}
6085c51f124SMoriah Waterland 
6095c51f124SMoriah Waterland 		(void) pkgWunlock();	/* close the lockfile. */
6105c51f124SMoriah Waterland 	}
6115c51f124SMoriah Waterland 
6125c51f124SMoriah Waterland 	return (retval);
6135c51f124SMoriah Waterland }
6145c51f124SMoriah Waterland 
6155c51f124SMoriah Waterland /*
6165c51f124SMoriah Waterland  * Release the lock on the package database. Returns 1 on success, 0 on
6175c51f124SMoriah Waterland  * failure.
6185c51f124SMoriah Waterland  */
6195c51f124SMoriah Waterland static int
6205c51f124SMoriah Waterland pkgWunlock(void) {
6215c51f124SMoriah Waterland 	if (active_lock) {
6225c51f124SMoriah Waterland 		active_lock = 0;
6235c51f124SMoriah Waterland 		if (close(lock_fd))
6245c51f124SMoriah Waterland 			return (0);
6255c51f124SMoriah Waterland 		else
6265c51f124SMoriah Waterland 			return (1);
6275c51f124SMoriah Waterland 	} else
6285c51f124SMoriah Waterland 		return (1);
6295c51f124SMoriah Waterland }
6305c51f124SMoriah Waterland 
6315c51f124SMoriah Waterland /*
6325c51f124SMoriah Waterland  * This function verifies that the contents file is in place.
6335c51f124SMoriah Waterland  * returns 1 - if it exists
6345c51f124SMoriah Waterland  * returns 0 - if it does not exist
6355c51f124SMoriah Waterland  */
6365c51f124SMoriah Waterland int
6375c51f124SMoriah Waterland iscfile(void)
6385c51f124SMoriah Waterland {
6395c51f124SMoriah Waterland 	char	contents[PATH_MAX];
6405c51f124SMoriah Waterland 
6415c51f124SMoriah Waterland 	(void) snprintf(contents, PATH_MAX, "%s/contents", get_PKGADM());
6425c51f124SMoriah Waterland 
6435c51f124SMoriah Waterland 	return (access(contents, F_OK) == 0 ? 1 : 0);
6445c51f124SMoriah Waterland }
6455c51f124SMoriah Waterland 
6465c51f124SMoriah Waterland /*
6475c51f124SMoriah Waterland  * This function verifies that the contents file is in place. If it is - no
6485c51f124SMoriah Waterland  * change. If it isn't - this creates it.
6495c51f124SMoriah Waterland  * Returns:	== 0 : failure
6505c51f124SMoriah Waterland  *		!= 0 : success
6515c51f124SMoriah Waterland  */
6525c51f124SMoriah Waterland 
6535c51f124SMoriah Waterland int
6545c51f124SMoriah Waterland vcfile(void)
6555c51f124SMoriah Waterland {
6565c51f124SMoriah Waterland 	int	lerrno;
6575c51f124SMoriah Waterland 	int	fd;
6585c51f124SMoriah Waterland 	char	contents[PATH_MAX];
6595c51f124SMoriah Waterland 
6605c51f124SMoriah Waterland 	/*
6615c51f124SMoriah Waterland 	 * create full path to contents file
6625c51f124SMoriah Waterland 	 */
6635c51f124SMoriah Waterland 
6645c51f124SMoriah Waterland 	(void) snprintf(contents, sizeof (contents),
6655c51f124SMoriah Waterland 			"%s/contents", get_PKGADM());
6665c51f124SMoriah Waterland 
6675c51f124SMoriah Waterland 	/*
6685c51f124SMoriah Waterland 	 * Attempt to create the file - will only be successful
6695c51f124SMoriah Waterland 	 * if the file does not currently exist.
6705c51f124SMoriah Waterland 	 */
6715c51f124SMoriah Waterland 
6725c51f124SMoriah Waterland 	fd = open(contents, O_WRONLY | O_CREAT | O_EXCL, 0644);
6735c51f124SMoriah Waterland 	if (fd >= 0) {
6745c51f124SMoriah Waterland 		/*
6755c51f124SMoriah Waterland 		 * Contents file wasn't there, but is now.
6765c51f124SMoriah Waterland 		 */
6775c51f124SMoriah Waterland 
6785c51f124SMoriah Waterland 		echo(gettext("## Software contents file initialized"));
6795c51f124SMoriah Waterland 		(void) close(fd);
6805c51f124SMoriah Waterland 		return (1);	/* success */
6815c51f124SMoriah Waterland 	}
6825c51f124SMoriah Waterland 
6835c51f124SMoriah Waterland 	/*
6845c51f124SMoriah Waterland 	 * Could not create the file - it may exist or there may be
6855c51f124SMoriah Waterland 	 * permissions issues - find out and act accordingly.
6865c51f124SMoriah Waterland 	 */
6875c51f124SMoriah Waterland 
6885c51f124SMoriah Waterland 	lerrno = errno;
6895c51f124SMoriah Waterland 
6905c51f124SMoriah Waterland 	/* success if error is 'file exists' */
6915c51f124SMoriah Waterland 
6925c51f124SMoriah Waterland 	if (lerrno == EEXIST) {
6935c51f124SMoriah Waterland 		return (1);	/* success */
6945c51f124SMoriah Waterland 	}
6955c51f124SMoriah Waterland 
6965c51f124SMoriah Waterland 	/* success if error is 'permission denied' but file exists */
6975c51f124SMoriah Waterland 
6985c51f124SMoriah Waterland 	if (lerrno == EACCES) {
6995c51f124SMoriah Waterland 		/*
7005c51f124SMoriah Waterland 		 * Because O_CREAT and O_EXCL are specified in open(),
7015c51f124SMoriah Waterland 		 * if the contents file already exists, the open will
7025c51f124SMoriah Waterland 		 * fail with EACCES - determine if this is the case -
7035c51f124SMoriah Waterland 		 * if so return success.
7045c51f124SMoriah Waterland 		 */
7055c51f124SMoriah Waterland 
7065c51f124SMoriah Waterland 		if (access(contents, F_OK) == 0) {
7075c51f124SMoriah Waterland 			return (1);	/* success */
7085c51f124SMoriah Waterland 		}
7095c51f124SMoriah Waterland 
7105c51f124SMoriah Waterland 		/*
7115c51f124SMoriah Waterland 		 * access() failed - if because of permissions failure this
7125c51f124SMoriah Waterland 		 * means the contents file exists but it cannot be accessed
7135c51f124SMoriah Waterland 		 * or the path to the contents file cannot be accessed - in
7145c51f124SMoriah Waterland 		 * either case the contents file cannot be accessed.
7155c51f124SMoriah Waterland 		 */
7165c51f124SMoriah Waterland 
7175c51f124SMoriah Waterland 		if (errno == EACCES) {
7185c51f124SMoriah Waterland 			progerr(gettext(ERR_ACCESS_CONT), contents,
7195c51f124SMoriah Waterland 					strerror(lerrno));
7205c51f124SMoriah Waterland 			logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
7215c51f124SMoriah Waterland 			return (0);	/* failure */
7225c51f124SMoriah Waterland 		}
7235c51f124SMoriah Waterland 	}
7245c51f124SMoriah Waterland 
7255c51f124SMoriah Waterland 	/*
7265c51f124SMoriah Waterland 	 * the contents file does not exist and it cannot be created.
7275c51f124SMoriah Waterland 	 */
7285c51f124SMoriah Waterland 
7295c51f124SMoriah Waterland 	progerr(gettext(ERR_CREAT_CONT), contents, strerror(lerrno));
7305c51f124SMoriah Waterland 	logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
7315c51f124SMoriah Waterland 	return (0);	/* failure */
7325c51f124SMoriah Waterland }
733