xref: /titanic_44/usr/src/cmd/svr4pkg/libinst/ocfile.c (revision 5c51f1241dbbdf2656d0e10011981411ed0c9673)
1*5c51f124SMoriah Waterland /*
2*5c51f124SMoriah Waterland  * CDDL HEADER START
3*5c51f124SMoriah Waterland  *
4*5c51f124SMoriah Waterland  * The contents of this file are subject to the terms of the
5*5c51f124SMoriah Waterland  * Common Development and Distribution License (the "License").
6*5c51f124SMoriah Waterland  * You may not use this file except in compliance with the License.
7*5c51f124SMoriah Waterland  *
8*5c51f124SMoriah Waterland  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5c51f124SMoriah Waterland  * or http://www.opensolaris.org/os/licensing.
10*5c51f124SMoriah Waterland  * See the License for the specific language governing permissions
11*5c51f124SMoriah Waterland  * and limitations under the License.
12*5c51f124SMoriah Waterland  *
13*5c51f124SMoriah Waterland  * When distributing Covered Code, include this CDDL HEADER in each
14*5c51f124SMoriah Waterland  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5c51f124SMoriah Waterland  * If applicable, add the following below this CDDL HEADER, with the
16*5c51f124SMoriah Waterland  * fields enclosed by brackets "[]" replaced with your own identifying
17*5c51f124SMoriah Waterland  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5c51f124SMoriah Waterland  *
19*5c51f124SMoriah Waterland  * CDDL HEADER END
20*5c51f124SMoriah Waterland  */
21*5c51f124SMoriah Waterland 
22*5c51f124SMoriah Waterland /*
23*5c51f124SMoriah Waterland  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*5c51f124SMoriah Waterland  * Use is subject to license terms.
25*5c51f124SMoriah Waterland  */
26*5c51f124SMoriah Waterland 
27*5c51f124SMoriah Waterland /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28*5c51f124SMoriah Waterland /* All Rights Reserved */
29*5c51f124SMoriah Waterland 
30*5c51f124SMoriah Waterland 
31*5c51f124SMoriah Waterland #include <stdio.h>
32*5c51f124SMoriah Waterland #include <fcntl.h>
33*5c51f124SMoriah Waterland #include <sys/types.h>
34*5c51f124SMoriah Waterland #include <sys/param.h>
35*5c51f124SMoriah Waterland #include <sys/sysmacros.h>
36*5c51f124SMoriah Waterland #include <string.h>
37*5c51f124SMoriah Waterland #include <strings.h>
38*5c51f124SMoriah Waterland #include <sys/wait.h>
39*5c51f124SMoriah Waterland #include <sys/stat.h>
40*5c51f124SMoriah Waterland #include <sys/mman.h>
41*5c51f124SMoriah Waterland #include <sys/statvfs.h>
42*5c51f124SMoriah Waterland #include <signal.h>
43*5c51f124SMoriah Waterland #include <limits.h>
44*5c51f124SMoriah Waterland #include <errno.h>
45*5c51f124SMoriah Waterland #include <fcntl.h>
46*5c51f124SMoriah Waterland #include <stdlib.h>
47*5c51f124SMoriah Waterland #include <unistd.h>
48*5c51f124SMoriah Waterland #include <time.h>
49*5c51f124SMoriah Waterland #include <errno.h>
50*5c51f124SMoriah Waterland #include <pkglocs.h>
51*5c51f124SMoriah Waterland #include <locale.h>
52*5c51f124SMoriah Waterland #include <libintl.h>
53*5c51f124SMoriah Waterland #include <pkglib.h>
54*5c51f124SMoriah Waterland #include "libinst.h"
55*5c51f124SMoriah Waterland #include "libadm.h"
56*5c51f124SMoriah Waterland 
57*5c51f124SMoriah Waterland #define	LOCKFILE	".pkg.lock"
58*5c51f124SMoriah Waterland #define	LOCKWAIT	10	/* seconds between retries */
59*5c51f124SMoriah Waterland #define	LOCKRETRY	20	/* number of retries for a DB lock */
60*5c51f124SMoriah Waterland 
61*5c51f124SMoriah Waterland #define	ERR_TC_WRITE	"WARNING: unable to write temp contents file <%s>"
62*5c51f124SMoriah Waterland #define	ERR_NOCLOSE	"WARNING: unable to close <%s>"
63*5c51f124SMoriah Waterland #define	ERR_NOUNLINK_LATENT	"WARNING: unable to unlink latent <%s>"
64*5c51f124SMoriah Waterland #define	ERR_LINK_FAIL	"link(%s, %s) failed (errno %d)"
65*5c51f124SMoriah Waterland #define	ERR_NORENAME_CONTENTS	"unable to establish contents file <%s> "\
66*5c51f124SMoriah Waterland 			"from <%s>"
67*5c51f124SMoriah Waterland #define	ERR_RENAME_FAIL	"rename(%s, %s) failed (errno %d)"
68*5c51f124SMoriah Waterland #define	ERR_RESTORE_FAIL	"attempt to restore <%s> failed"
69*5c51f124SMoriah Waterland #define	ERR_NOUNLINK	"WARNING: unable to unlink <%s>"
70*5c51f124SMoriah Waterland #define	ERR_FCLOSE_FAIL	"fclose failed (errno %d)"
71*5c51f124SMoriah Waterland #define	ERR_ERRNO	"(errno %d: %s)"
72*5c51f124SMoriah Waterland #define	ERR_NOTMPOPEN	"unable to open temporary contents file image"
73*5c51f124SMoriah Waterland #define	ERR_CFBACK	"Not enough space to backup <%s>"
74*5c51f124SMoriah Waterland #define	ERR_CREAT_CONT	"unable to create contents file <%s>: %s"
75*5c51f124SMoriah Waterland #define	ERR_ACCESS_CONT	"unable to access contents file <%s>: %s"
76*5c51f124SMoriah Waterland #define	ERR_CFBACK1	"Need=%llu blocks, Available=%llu blocks " \
77*5c51f124SMoriah Waterland 			"(block size=%d)"
78*5c51f124SMoriah Waterland #define	ERR_NOCFILE	"unable to locate contents file <%s>"
79*5c51f124SMoriah Waterland #define	ERR_NOROPEN	"unable to open <%s> for reading"
80*5c51f124SMoriah Waterland #define	ERR_NOOPEN	"unable to open <%s> for writing"
81*5c51f124SMoriah Waterland #define	ERR_NOSTAT	"unable to stat contents file <%s>"
82*5c51f124SMoriah Waterland #define	ERR_NOSTATV	"statvfs(%s) failed"
83*5c51f124SMoriah Waterland #define	ERR_NOUPD	"unable to update contents file"
84*5c51f124SMoriah Waterland #define	ERR_DRCONTCP	"unable to copy contents file to <%s>"
85*5c51f124SMoriah Waterland 
86*5c51f124SMoriah Waterland #define	MSG_XWTING	"NOTE: Waiting for exclusive access to the package " \
87*5c51f124SMoriah Waterland 				"database."
88*5c51f124SMoriah Waterland #define	MSG_NOLOCK	"NOTE: Couldn't lock the package database."
89*5c51f124SMoriah Waterland 
90*5c51f124SMoriah Waterland #define	ERR_NOLOCK	"Database lock failed."
91*5c51f124SMoriah Waterland #define	ERR_OPLOCK	"unable to open lock file <%s>."
92*5c51f124SMoriah Waterland #define	ERR_MKLOCK	"unable to create lock file <%s>."
93*5c51f124SMoriah Waterland #define	ERR_LCKREM	"unable to lock package database - remote host " \
94*5c51f124SMoriah Waterland 				"unavailable."
95*5c51f124SMoriah Waterland #define	ERR_BADLCK	"unable to lock package database - unknown error."
96*5c51f124SMoriah Waterland #define	ERR_DEADLCK	"unable to lock package database - deadlock condition."
97*5c51f124SMoriah Waterland #define	ERR_TMOUT	"unable to lock package database - too many retries."
98*5c51f124SMoriah Waterland #define	ERR_CFDIR	"unable to locate contents file directory"
99*5c51f124SMoriah Waterland 
100*5c51f124SMoriah Waterland static int	active_lock;
101*5c51f124SMoriah Waterland static int	lock_fd;	/* fd of LOCKFILE. */
102*5c51f124SMoriah Waterland static char	*pkgadm_dir;
103*5c51f124SMoriah Waterland 
104*5c51f124SMoriah Waterland static int	pkgWlock(int verbose);
105*5c51f124SMoriah Waterland static int	pkgWunlock(void);
106*5c51f124SMoriah Waterland 
107*5c51f124SMoriah Waterland /*
108*5c51f124SMoriah Waterland  * This VFP is used to cache the last copy of the contents file that was
109*5c51f124SMoriah Waterland  * written out - upon subsequent open if the contents file has not changed
110*5c51f124SMoriah Waterland  * since it was last written out, use the last cached copy that is still
111*5c51f124SMoriah Waterland  * in memory to avoid re-reading the contents file again. If the contents
112*5c51f124SMoriah Waterland  * file has changed since the cached copy was written out, the previous
113*5c51f124SMoriah Waterland  * copy is discarded and the new contents file contents are read in.
114*5c51f124SMoriah Waterland  */
115*5c51f124SMoriah Waterland 
116*5c51f124SMoriah Waterland static VFP_T	*contentsVfp = {(VFP_T *)NULL};
117*5c51f124SMoriah Waterland 
118*5c51f124SMoriah Waterland /*
119*5c51f124SMoriah Waterland  * This defines the maximum number of bytes that can be added to the contents
120*5c51f124SMoriah Waterland  * file for a single package - this must be higher than the largest expected
121*5c51f124SMoriah Waterland  * pkgmap file will ever be. This controls the amount of memory allocated for
122*5c51f124SMoriah Waterland  * the contents file additions. A pkgmap file with an average line length of
123*5c51f124SMoriah Waterland  * 128/256/512 bytes could add 62500/31250/15625 entries with this size. This
124*5c51f124SMoriah Waterland  * allows the contents file to have a fixed allocation without having to check
125*5c51f124SMoriah Waterland  * size and realloc as necessary with the attendant cost of the realloc. The
126*5c51f124SMoriah Waterland  * real memory used will only be those pages that are actually touched when
127*5c51f124SMoriah Waterland  * the contents file is written.
128*5c51f124SMoriah Waterland  */
129*5c51f124SMoriah Waterland 
130*5c51f124SMoriah Waterland #define	CONTENTS_DELTA	(32*1024*1024)	/* 32mb */
131*5c51f124SMoriah Waterland 
132*5c51f124SMoriah Waterland /* forward declarations */
133*5c51f124SMoriah Waterland 
134*5c51f124SMoriah Waterland int relslock(void);
135*5c51f124SMoriah Waterland 
136*5c51f124SMoriah Waterland /*ARGSUSED*/
137*5c51f124SMoriah Waterland static void
138*5c51f124SMoriah Waterland do_alarm(int n)
139*5c51f124SMoriah Waterland {
140*5c51f124SMoriah Waterland 	(void) signal(SIGALRM, SIG_IGN);
141*5c51f124SMoriah Waterland 	(void) signal(SIGALRM, do_alarm);
142*5c51f124SMoriah Waterland 	(void) alarm(LOCKWAIT);
143*5c51f124SMoriah Waterland }
144*5c51f124SMoriah Waterland 
145*5c51f124SMoriah Waterland /*
146*5c51f124SMoriah Waterland  * Point packaging to the appropriate contents file. This is primarily used
147*5c51f124SMoriah Waterland  * to establish a dryrun contents file. If the malloc() doesn't work, this
148*5c51f124SMoriah Waterland  * returns 99 (internal error), else 0.
149*5c51f124SMoriah Waterland  */
150*5c51f124SMoriah Waterland int
151*5c51f124SMoriah Waterland set_cfdir(char *cfdir)
152*5c51f124SMoriah Waterland {
153*5c51f124SMoriah Waterland 	char	realcf[PATH_MAX];
154*5c51f124SMoriah Waterland 	char	tmpcf[PATH_MAX];
155*5c51f124SMoriah Waterland 	int	status;
156*5c51f124SMoriah Waterland 
157*5c51f124SMoriah Waterland 	if (cfdir == NULL) {
158*5c51f124SMoriah Waterland 		pkgadm_dir = get_PKGADM();
159*5c51f124SMoriah Waterland 		return (0);
160*5c51f124SMoriah Waterland 	}
161*5c51f124SMoriah Waterland 
162*5c51f124SMoriah Waterland 	if ((pkgadm_dir = strdup(cfdir)) == NULL) {
163*5c51f124SMoriah Waterland 		return (99);
164*5c51f124SMoriah Waterland 	}
165*5c51f124SMoriah Waterland 
166*5c51f124SMoriah Waterland 	(void) snprintf(tmpcf, sizeof (tmpcf), "%s/contents", pkgadm_dir);
167*5c51f124SMoriah Waterland 
168*5c51f124SMoriah Waterland 	/*
169*5c51f124SMoriah Waterland 	 * return if a temporary contents file already exists -
170*5c51f124SMoriah Waterland 	 * assume it is from a prior package in this series.
171*5c51f124SMoriah Waterland 	 */
172*5c51f124SMoriah Waterland 
173*5c51f124SMoriah Waterland 	if (access(tmpcf, F_OK) == 0) {
174*5c51f124SMoriah Waterland 		return (0);
175*5c51f124SMoriah Waterland 	}
176*5c51f124SMoriah Waterland 
177*5c51f124SMoriah Waterland 	/*
178*5c51f124SMoriah Waterland 	 * no temporary contents file exists - create one.
179*5c51f124SMoriah Waterland 	 */
180*5c51f124SMoriah Waterland 
181*5c51f124SMoriah Waterland 	(void) snprintf(realcf, sizeof (realcf), "%s/contents", get_PKGADM());
182*5c51f124SMoriah Waterland 
183*5c51f124SMoriah Waterland 	/*
184*5c51f124SMoriah Waterland 	 * If there's a contents file there already, copy it
185*5c51f124SMoriah Waterland 	 * over, otherwise initialize one.
186*5c51f124SMoriah Waterland 	 */
187*5c51f124SMoriah Waterland 
188*5c51f124SMoriah Waterland 	/* create new contents file if one does not already exist */
189*5c51f124SMoriah Waterland 
190*5c51f124SMoriah Waterland 	if (access(realcf, F_OK) != 0) {
191*5c51f124SMoriah Waterland 		int n;
192*5c51f124SMoriah Waterland 
193*5c51f124SMoriah Waterland 		n = open(tmpcf, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
194*5c51f124SMoriah Waterland 		if (n < 0) {
195*5c51f124SMoriah Waterland 			progerr(gettext(ERR_CREAT_CONT), tmpcf,
196*5c51f124SMoriah Waterland 						strerror(errno));
197*5c51f124SMoriah Waterland 			return (99);
198*5c51f124SMoriah Waterland 		}
199*5c51f124SMoriah Waterland 		(void) close(n);
200*5c51f124SMoriah Waterland 	} else {
201*5c51f124SMoriah Waterland 
202*5c51f124SMoriah Waterland 		/* contents file exists, save in pkgadm-dir */
203*5c51f124SMoriah Waterland 
204*5c51f124SMoriah Waterland 		status = copyf(realcf, tmpcf, (time_t)0);
205*5c51f124SMoriah Waterland 		if (status != 0) {
206*5c51f124SMoriah Waterland 			progerr(gettext(ERR_DRCONTCP), tmpcf);
207*5c51f124SMoriah Waterland 			return (99);
208*5c51f124SMoriah Waterland 		}
209*5c51f124SMoriah Waterland 	}
210*5c51f124SMoriah Waterland 
211*5c51f124SMoriah Waterland 	return (0);
212*5c51f124SMoriah Waterland }
213*5c51f124SMoriah Waterland 
214*5c51f124SMoriah Waterland /*
215*5c51f124SMoriah Waterland  * This function installs the database lock, opens the contents file for
216*5c51f124SMoriah Waterland  * reading and creates and opens the temporary contents file for read/write.
217*5c51f124SMoriah Waterland  * It returns 1 if successful, 0 otherwise.
218*5c51f124SMoriah Waterland  */
219*5c51f124SMoriah Waterland int
220*5c51f124SMoriah Waterland ocfile(VFP_T **r_mapvfp, VFP_T **r_tmpvfp, fsblkcnt_t map_blks)
221*5c51f124SMoriah Waterland {
222*5c51f124SMoriah Waterland 	struct	stat64	statb;
223*5c51f124SMoriah Waterland 	struct	statvfs64	svfsb;
224*5c51f124SMoriah Waterland 	fsblkcnt_t free_blocks;
225*5c51f124SMoriah Waterland 	fsblkcnt_t need_blocks;
226*5c51f124SMoriah Waterland 	VFP_T		*mapvfp = (VFP_T *)NULL;
227*5c51f124SMoriah Waterland 	VFP_T		*tmpvfp = (VFP_T *)NULL;
228*5c51f124SMoriah Waterland 	char		contents[PATH_MAX];
229*5c51f124SMoriah Waterland 	int		n;
230*5c51f124SMoriah Waterland 
231*5c51f124SMoriah Waterland 	/* reset return VFP/FILE pointers */
232*5c51f124SMoriah Waterland 
233*5c51f124SMoriah Waterland 	(*r_mapvfp) = (VFP_T *)NULL;
234*5c51f124SMoriah Waterland 	(*r_tmpvfp) = (VFP_T *)NULL;
235*5c51f124SMoriah Waterland 
236*5c51f124SMoriah Waterland 	/* establish package administration contents directory location */
237*5c51f124SMoriah Waterland 
238*5c51f124SMoriah Waterland 	if (pkgadm_dir == NULL) {
239*5c51f124SMoriah Waterland 		if (set_cfdir(NULL) != 0) {
240*5c51f124SMoriah Waterland 			progerr(gettext(ERR_CFDIR));
241*5c51f124SMoriah Waterland 			return (0);
242*5c51f124SMoriah Waterland 		}
243*5c51f124SMoriah Waterland 	}
244*5c51f124SMoriah Waterland 
245*5c51f124SMoriah Waterland 	/* Lock the file for exclusive access */
246*5c51f124SMoriah Waterland 
247*5c51f124SMoriah Waterland 	if (!pkgWlock(1)) {
248*5c51f124SMoriah Waterland 		progerr(gettext(ERR_NOLOCK));
249*5c51f124SMoriah Waterland 		return (0);
250*5c51f124SMoriah Waterland 	}
251*5c51f124SMoriah Waterland 
252*5c51f124SMoriah Waterland 	/* determine path to the primary contents file */
253*5c51f124SMoriah Waterland 
254*5c51f124SMoriah Waterland 	(void) snprintf(contents, sizeof (contents), "%s/contents", pkgadm_dir);
255*5c51f124SMoriah Waterland 
256*5c51f124SMoriah Waterland 	/*
257*5c51f124SMoriah Waterland 	 * open the contents file to read only - if a previous contents file has
258*5c51f124SMoriah Waterland 	 * been cached attempt to use that cached copy for the open, otherwise
259*5c51f124SMoriah Waterland 	 * just open the contents file directly
260*5c51f124SMoriah Waterland 	 */
261*5c51f124SMoriah Waterland 
262*5c51f124SMoriah Waterland 	n = vfpCheckpointOpen(&contentsVfp, &mapvfp, contents, "r", VFP_NONE);
263*5c51f124SMoriah Waterland 
264*5c51f124SMoriah Waterland 	/* return error if contents file cannot be accessed */
265*5c51f124SMoriah Waterland 
266*5c51f124SMoriah Waterland 	if (n != 0) {
267*5c51f124SMoriah Waterland 		int	lerrno = errno;
268*5c51f124SMoriah Waterland 
269*5c51f124SMoriah Waterland 		if (errno == ENOENT) {
270*5c51f124SMoriah Waterland 			progerr(gettext(ERR_NOCFILE), contents);
271*5c51f124SMoriah Waterland 		} else {
272*5c51f124SMoriah Waterland 			progerr(gettext(ERR_NOROPEN), contents);
273*5c51f124SMoriah Waterland 		}
274*5c51f124SMoriah Waterland 
275*5c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
276*5c51f124SMoriah Waterland 		return (0);
277*5c51f124SMoriah Waterland 	}
278*5c51f124SMoriah Waterland 
279*5c51f124SMoriah Waterland 	/*
280*5c51f124SMoriah Waterland 	 * Check and see if there is enough space for the packaging commands
281*5c51f124SMoriah Waterland 	 * to back up the contents file, if there is not, then do not allow
282*5c51f124SMoriah Waterland 	 * execution to continue by failing the ocfile() call.
283*5c51f124SMoriah Waterland 	 */
284*5c51f124SMoriah Waterland 
285*5c51f124SMoriah Waterland 	/* Get the contents file size */
286*5c51f124SMoriah Waterland 
287*5c51f124SMoriah Waterland 	if (fstat64(fileno(mapvfp->_vfpFile), &statb) == -1) {
288*5c51f124SMoriah Waterland 		int	lerrno = errno;
289*5c51f124SMoriah Waterland 
290*5c51f124SMoriah Waterland 		progerr(gettext(ERR_NOSTAT), contents);
291*5c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
292*5c51f124SMoriah Waterland 		(void) vfpClose(&mapvfp);
293*5c51f124SMoriah Waterland 		return (0);
294*5c51f124SMoriah Waterland 	}
295*5c51f124SMoriah Waterland 
296*5c51f124SMoriah Waterland 	/* Get the filesystem space */
297*5c51f124SMoriah Waterland 
298*5c51f124SMoriah Waterland 	if (fstatvfs64(fileno(mapvfp->_vfpFile), &svfsb) == -1) {
299*5c51f124SMoriah Waterland 		int	lerrno = errno;
300*5c51f124SMoriah Waterland 
301*5c51f124SMoriah Waterland 		progerr(gettext(ERR_NOSTATV), contents);
302*5c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
303*5c51f124SMoriah Waterland 		(void) vfpClose(&mapvfp);
304*5c51f124SMoriah Waterland 		return (0);
305*5c51f124SMoriah Waterland 	}
306*5c51f124SMoriah Waterland 
307*5c51f124SMoriah Waterland 	free_blocks = (((fsblkcnt_t)svfsb.f_frsize > 0) ?
308*5c51f124SMoriah Waterland 			howmany(svfsb.f_frsize, DEV_BSIZE) :
309*5c51f124SMoriah Waterland 			howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bfree;
310*5c51f124SMoriah Waterland 
311*5c51f124SMoriah Waterland 	if (map_blks == 0LL) {
312*5c51f124SMoriah Waterland 		map_blks = 10LL;
313*5c51f124SMoriah Waterland 	}
314*5c51f124SMoriah Waterland 
315*5c51f124SMoriah Waterland 	/*
316*5c51f124SMoriah Waterland 	 * Calculate the number of blocks we need to be able to operate on
317*5c51f124SMoriah Waterland 	 * the contents file.
318*5c51f124SMoriah Waterland 	 */
319*5c51f124SMoriah Waterland 	need_blocks = map_blks +
320*5c51f124SMoriah Waterland 		nblk(statb.st_size, svfsb.f_bsize, svfsb.f_frsize);
321*5c51f124SMoriah Waterland 
322*5c51f124SMoriah Waterland 	if ((need_blocks + 10) > free_blocks) {
323*5c51f124SMoriah Waterland 		progerr(gettext(ERR_CFBACK), contents);
324*5c51f124SMoriah Waterland 		progerr(gettext(ERR_CFBACK1), need_blocks, free_blocks,
325*5c51f124SMoriah Waterland 			DEV_BSIZE);
326*5c51f124SMoriah Waterland 		(void) vfpClose(&mapvfp);
327*5c51f124SMoriah Waterland 		return (0);
328*5c51f124SMoriah Waterland 	}
329*5c51f124SMoriah Waterland 
330*5c51f124SMoriah Waterland 	/*
331*5c51f124SMoriah Waterland 	 * open the temporary contents file without a path name - this causes
332*5c51f124SMoriah Waterland 	 * the "vfp" to be opened on in-memory storage only, the size of which
333*5c51f124SMoriah Waterland 	 * is set following a successful return - this causes the temporary
334*5c51f124SMoriah Waterland 	 * contents file to be maintained in memory only - if no changes are
335*5c51f124SMoriah Waterland 	 * made as the primary contents file is processed, the in memory data
336*5c51f124SMoriah Waterland 	 * is discarded and not written to the disk.
337*5c51f124SMoriah Waterland 	 */
338*5c51f124SMoriah Waterland 
339*5c51f124SMoriah Waterland 	if (vfpOpen(&tmpvfp, (char *)NULL, "w", VFP_NONE) != 0) {
340*5c51f124SMoriah Waterland 		int	lerrno = errno;
341*5c51f124SMoriah Waterland 
342*5c51f124SMoriah Waterland 		progerr(gettext(ERR_NOTMPOPEN));
343*5c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
344*5c51f124SMoriah Waterland 		(void) vfpClose(&mapvfp);
345*5c51f124SMoriah Waterland 		return (0);
346*5c51f124SMoriah Waterland 	}
347*5c51f124SMoriah Waterland 
348*5c51f124SMoriah Waterland 	/*
349*5c51f124SMoriah Waterland 	 * set size of allocation for temporary contents file - this sets the
350*5c51f124SMoriah Waterland 	 * size of the in-memory buffer associated with the open vfp.
351*5c51f124SMoriah Waterland 	 */
352*5c51f124SMoriah Waterland 
353*5c51f124SMoriah Waterland 	if (vfpSetSize(tmpvfp, statb.st_size + CONTENTS_DELTA) != 0) {
354*5c51f124SMoriah Waterland 		int	lerrno = errno;
355*5c51f124SMoriah Waterland 
356*5c51f124SMoriah Waterland 		progerr(gettext(ERR_NOTMPOPEN));
357*5c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
358*5c51f124SMoriah Waterland 		(void) vfpClose(&tmpvfp);
359*5c51f124SMoriah Waterland 		(void) vfpClose(&mapvfp);
360*5c51f124SMoriah Waterland 		return (0);
361*5c51f124SMoriah Waterland 	}
362*5c51f124SMoriah Waterland 
363*5c51f124SMoriah Waterland 	/*
364*5c51f124SMoriah Waterland 	 * now that the temporary file is opened, advise the vm system to start
365*5c51f124SMoriah Waterland 	 * mapping the real contents file into memory if possible
366*5c51f124SMoriah Waterland 	 */
367*5c51f124SMoriah Waterland 
368*5c51f124SMoriah Waterland 	(void) vfpSetFlags(mapvfp, VFP_NEEDNOW);
369*5c51f124SMoriah Waterland 
370*5c51f124SMoriah Waterland 	/* set return ->s to open vfps */
371*5c51f124SMoriah Waterland 
372*5c51f124SMoriah Waterland 	(*r_mapvfp) = mapvfp;
373*5c51f124SMoriah Waterland 	(*r_tmpvfp) = tmpvfp;
374*5c51f124SMoriah Waterland 
375*5c51f124SMoriah Waterland 	return (1);	/* All OK */
376*5c51f124SMoriah Waterland }
377*5c51f124SMoriah Waterland 
378*5c51f124SMoriah Waterland /*
379*5c51f124SMoriah Waterland  * This is a simple open and lock of the contents file. It doesn't create a
380*5c51f124SMoriah Waterland  * temporary contents file and it doesn't need to do any space checking.
381*5c51f124SMoriah Waterland  * Returns 1 for OK and 0 for "didn't do it".
382*5c51f124SMoriah Waterland  */
383*5c51f124SMoriah Waterland int
384*5c51f124SMoriah Waterland socfile(VFP_T **r_mapvfp)
385*5c51f124SMoriah Waterland {
386*5c51f124SMoriah Waterland 	VFP_T	*mapvfp = (VFP_T *)NULL;
387*5c51f124SMoriah Waterland 	char	contents[PATH_MAX];
388*5c51f124SMoriah Waterland 	int	n;
389*5c51f124SMoriah Waterland 
390*5c51f124SMoriah Waterland 	/* reset return VFP/FILE pointer */
391*5c51f124SMoriah Waterland 
392*5c51f124SMoriah Waterland 	(*r_mapvfp) = (VFP_T *)NULL;
393*5c51f124SMoriah Waterland 
394*5c51f124SMoriah Waterland 	if (pkgadm_dir == NULL) {
395*5c51f124SMoriah Waterland 		if (set_cfdir(NULL) != 0) {
396*5c51f124SMoriah Waterland 			progerr(gettext(ERR_CFDIR));
397*5c51f124SMoriah Waterland 			return (0);
398*5c51f124SMoriah Waterland 		}
399*5c51f124SMoriah Waterland 	}
400*5c51f124SMoriah Waterland 
401*5c51f124SMoriah Waterland 	/*
402*5c51f124SMoriah Waterland 	 * Lock the database for exclusive access, but don't make a fuss if
403*5c51f124SMoriah Waterland 	 * it fails (user may not be root and the .pkg.lock file may not
404*5c51f124SMoriah Waterland 	 * exist yet).
405*5c51f124SMoriah Waterland 	 */
406*5c51f124SMoriah Waterland 
407*5c51f124SMoriah Waterland 	if (!pkgWlock(0)) {
408*5c51f124SMoriah Waterland 		logerr(gettext(MSG_NOLOCK));
409*5c51f124SMoriah Waterland 	}
410*5c51f124SMoriah Waterland 
411*5c51f124SMoriah Waterland 	/* open the contents file to read only */
412*5c51f124SMoriah Waterland 
413*5c51f124SMoriah Waterland 	(void) snprintf(contents, sizeof (contents), "%s/contents", pkgadm_dir);
414*5c51f124SMoriah Waterland 
415*5c51f124SMoriah Waterland 	n = vfpCheckpointOpen(&contentsVfp, &mapvfp, contents,
416*5c51f124SMoriah Waterland 							"r", VFP_NEEDNOW);
417*5c51f124SMoriah Waterland 	if (n != 0) {
418*5c51f124SMoriah Waterland 		int lerrno = errno;
419*5c51f124SMoriah Waterland 
420*5c51f124SMoriah Waterland 		if (errno == ENOENT) {
421*5c51f124SMoriah Waterland 			progerr(gettext(ERR_NOCFILE), contents);
422*5c51f124SMoriah Waterland 		} else {
423*5c51f124SMoriah Waterland 			progerr(gettext(ERR_NOROPEN), contents);
424*5c51f124SMoriah Waterland 		}
425*5c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
426*5c51f124SMoriah Waterland 		return (0);
427*5c51f124SMoriah Waterland 	}
428*5c51f124SMoriah Waterland 
429*5c51f124SMoriah Waterland 	*r_mapvfp = mapvfp;
430*5c51f124SMoriah Waterland 
431*5c51f124SMoriah Waterland 	return (1);
432*5c51f124SMoriah Waterland }
433*5c51f124SMoriah Waterland 
434*5c51f124SMoriah Waterland /*
435*5c51f124SMoriah Waterland  * Name:	swapcfile
436*5c51f124SMoriah Waterland  * Description: This function closes both the current and temporary contents
437*5c51f124SMoriah Waterland  *		files specified, and conditionally replaces the old transitory
438*5c51f124SMoriah Waterland  *		contents file with the newly updated temporary contents file.
439*5c51f124SMoriah Waterland  *		The "ocfile()" or "socfile()" functions must be called to re-
440*5c51f124SMoriah Waterland  *		open the real contents file for processing.
441*5c51f124SMoriah Waterland  * Arguments:	a_cfVfp - (VFP_T **) - [RW, *RW]
442*5c51f124SMoriah Waterland  *			This is the VFP associated with the real contents file
443*5c51f124SMoriah Waterland  *			that is being read from and data processed.
444*5c51f124SMoriah Waterland  *		a_cfTmpVfp - (VFP_T **) - [RW, *RW]
445*5c51f124SMoriah Waterland  *			This is the VFP associated with the temporary contents
446*5c51f124SMoriah Waterland  *			file that is being written to.
447*5c51f124SMoriah Waterland  *		pkginst - (char) - [RO, *RO]
448*5c51f124SMoriah Waterland  *			This is the name of the package being operated on;
449*5c51f124SMoriah Waterland  *			this is used to write the "last modified by xxx"
450*5c51f124SMoriah Waterland  *			comment at the end of the contents file.
451*5c51f124SMoriah Waterland  *		dbchg - (int) - [RO]
452*5c51f124SMoriah Waterland  *			== 0 - the temporary contents file has NOT been changed
453*5c51f124SMoriah Waterland  *				with respect to the real contents file; do not
454*5c51f124SMoriah Waterland  *				update the real contents file with the contents
455*5c51f124SMoriah Waterland  *				of the temporary contents file.
456*5c51f124SMoriah Waterland  *			!= 0 - the temporary contetns file HAS been changed with
457*5c51f124SMoriah Waterland  *				respect to the real contents file; DO update the
458*5c51f124SMoriah Waterland  *				real contents file with the contents of the
459*5c51f124SMoriah Waterland  *				temporary contents file.
460*5c51f124SMoriah Waterland  * Returns:	int	== RESULT_OK - successful
461*5c51f124SMoriah Waterland  *			== RESULT_WRN - successful with warnings
462*5c51f124SMoriah Waterland  *			== RESULT_ERR - failed with fatal errors - deserves an
463*5c51f124SMoriah Waterland  *				alarming message and a quit()
464*5c51f124SMoriah Waterland  * NOTES: If dbchg != 0, the contents file is always updated. If dbchg == 0,
465*5c51f124SMoriah Waterland  *		the contents file is updated IF the data is modified indication
466*5c51f124SMoriah Waterland  *		is set on the contents file associated with a_cfTmpVfp.
467*5c51f124SMoriah Waterland  */
468*5c51f124SMoriah Waterland 
469*5c51f124SMoriah Waterland int
470*5c51f124SMoriah Waterland swapcfile(VFP_T **a_cfVfp, VFP_T **a_cfTmpVfp, char *pkginst, int dbchg)
471*5c51f124SMoriah Waterland {
472*5c51f124SMoriah Waterland 	char	*pe;
473*5c51f124SMoriah Waterland 	char	*pl;
474*5c51f124SMoriah Waterland 	char	*ps;
475*5c51f124SMoriah Waterland 	char	contentsPath[PATH_MAX] = {'\0'};
476*5c51f124SMoriah Waterland 	char	line[256];
477*5c51f124SMoriah Waterland 	char	sContentsPath[PATH_MAX] = {'\0'};
478*5c51f124SMoriah Waterland 	char	tContentsPath[PATH_MAX] = {'\0'};
479*5c51f124SMoriah Waterland 	char	timeb[BUFSIZ];
480*5c51f124SMoriah Waterland 	int	retval = RESULT_OK;
481*5c51f124SMoriah Waterland 	struct tm	*timep;
482*5c51f124SMoriah Waterland 	time_t	clock;
483*5c51f124SMoriah Waterland 
484*5c51f124SMoriah Waterland 	/* normalize pkginst so its never null */
485*5c51f124SMoriah Waterland 
486*5c51f124SMoriah Waterland 	if (pkginst == (char *)NULL) {
487*5c51f124SMoriah Waterland 		dbchg = 0;
488*5c51f124SMoriah Waterland 		pkginst = "<unknown>";
489*5c51f124SMoriah Waterland 	}
490*5c51f124SMoriah Waterland 
491*5c51f124SMoriah Waterland 	/* cache all paths for the associated open files */
492*5c51f124SMoriah Waterland 
493*5c51f124SMoriah Waterland 	(void) strlcpy(contentsPath, vfpGetPath(*a_cfVfp),
494*5c51f124SMoriah Waterland 			sizeof (contentsPath));
495*5c51f124SMoriah Waterland 
496*5c51f124SMoriah Waterland 	(void) snprintf(tContentsPath, sizeof (tContentsPath),
497*5c51f124SMoriah Waterland 			"%s/t.contents", pkgadm_dir);
498*5c51f124SMoriah Waterland 
499*5c51f124SMoriah Waterland 	(void) snprintf(sContentsPath, sizeof (sContentsPath),
500*5c51f124SMoriah Waterland 			"%s/s.contents", pkgadm_dir);
501*5c51f124SMoriah Waterland 
502*5c51f124SMoriah Waterland 	/* original contents file no longer needed - close */
503*5c51f124SMoriah Waterland 
504*5c51f124SMoriah Waterland 	if (vfpClose(a_cfVfp) != 0) {
505*5c51f124SMoriah Waterland 		int	lerrno = errno;
506*5c51f124SMoriah Waterland 
507*5c51f124SMoriah Waterland 		logerr(gettext(ERR_NOCLOSE), contentsPath);
508*5c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
509*5c51f124SMoriah Waterland 		retval = RESULT_WRN;
510*5c51f124SMoriah Waterland 	}
511*5c51f124SMoriah Waterland 
512*5c51f124SMoriah Waterland 	/*
513*5c51f124SMoriah Waterland 	 * If no changes were made to the database, checkpoint the temporary
514*5c51f124SMoriah Waterland 	 * contents file - if this fails, then just close the file which causes
515*5c51f124SMoriah Waterland 	 * the contents file to be reopened and reread if it is needed again
516*5c51f124SMoriah Waterland 	 */
517*5c51f124SMoriah Waterland 
518*5c51f124SMoriah Waterland 	if ((dbchg == 0) && (vfpGetModified(*a_cfTmpVfp) == 0)) {
519*5c51f124SMoriah Waterland 		if (vfpCheckpointFile(&contentsVfp, a_cfTmpVfp,
520*5c51f124SMoriah Waterland 							contentsPath) != 0) {
521*5c51f124SMoriah Waterland 			vfpClose(a_cfTmpVfp);
522*5c51f124SMoriah Waterland 		}
523*5c51f124SMoriah Waterland 		(void) pkgWunlock();	/* Free the database lock. */
524*5c51f124SMoriah Waterland 		return (retval);
525*5c51f124SMoriah Waterland 	}
526*5c51f124SMoriah Waterland 
527*5c51f124SMoriah Waterland 	/*
528*5c51f124SMoriah Waterland 	 * changes made to the current temporary contents file -
529*5c51f124SMoriah Waterland 	 * remove any trailing comment lines in the temp contents file, then
530*5c51f124SMoriah Waterland 	 * append updated modification info records to temp contents file
531*5c51f124SMoriah Waterland 	 */
532*5c51f124SMoriah Waterland 
533*5c51f124SMoriah Waterland 	pe = vfpGetCurrCharPtr(*a_cfTmpVfp);	/* last char in contents file */
534*5c51f124SMoriah Waterland 	ps = vfpGetFirstCharPtr(*a_cfTmpVfp);	/* 1st char in contents file */
535*5c51f124SMoriah Waterland 	pl = pe;	/* last match is last char in contents file */
536*5c51f124SMoriah Waterland 
537*5c51f124SMoriah Waterland 	/* skip past all trailing newlines and null bytes */
538*5c51f124SMoriah Waterland 
539*5c51f124SMoriah Waterland 	while ((pe > ps) && ((*pe == '\n') || (*pe == '\0'))) {
540*5c51f124SMoriah Waterland 		pe--;
541*5c51f124SMoriah Waterland 	}
542*5c51f124SMoriah Waterland 
543*5c51f124SMoriah Waterland 	/* remove trailing comments as long as there are lines in the file */
544*5c51f124SMoriah Waterland 
545*5c51f124SMoriah Waterland 	while (pe > ps) {
546*5c51f124SMoriah Waterland 		if (*pe != '\n') {
547*5c51f124SMoriah Waterland 			/* curr char is not newline: backup one byte */
548*5c51f124SMoriah Waterland 			pl = pe--;
549*5c51f124SMoriah Waterland 		} else if (*pl != '#') {
550*5c51f124SMoriah Waterland 			/* curr char is newline next char not comment break */
551*5c51f124SMoriah Waterland 			break;
552*5c51f124SMoriah Waterland 		} else {
553*5c51f124SMoriah Waterland 			/* curr char is newline next char is comment - remove */
554*5c51f124SMoriah Waterland 			*pl = '\0';
555*5c51f124SMoriah Waterland 			vfpSetLastCharPtr(*a_cfTmpVfp, pl);
556*5c51f124SMoriah Waterland 			pe--;
557*5c51f124SMoriah Waterland 		}
558*5c51f124SMoriah Waterland 	}
559*5c51f124SMoriah Waterland 
560*5c51f124SMoriah Waterland 	/* create two update comment lines */
561*5c51f124SMoriah Waterland 
562*5c51f124SMoriah Waterland 	(void) time(&clock);
563*5c51f124SMoriah Waterland 	timep = localtime(&clock);
564*5c51f124SMoriah Waterland 
565*5c51f124SMoriah Waterland 	(void) strftime(timeb, sizeof (timeb), "%c\n", timep);
566*5c51f124SMoriah Waterland 	(void) snprintf(line, sizeof (line),
567*5c51f124SMoriah Waterland 		gettext("# Last modified by %s for %s package\n# %s"),
568*5c51f124SMoriah Waterland 		get_prog_name(), pkginst, timeb);
569*5c51f124SMoriah Waterland 	vfpPuts(*a_cfTmpVfp, line);
570*5c51f124SMoriah Waterland 
571*5c51f124SMoriah Waterland 	/* commit temporary contents file bytes to storage */
572*5c51f124SMoriah Waterland 
573*5c51f124SMoriah Waterland 	if (vfpWriteToFile(*a_cfTmpVfp, tContentsPath) != 0) {
574*5c51f124SMoriah Waterland 		int	lerrno = errno;
575*5c51f124SMoriah Waterland 
576*5c51f124SMoriah Waterland 		logerr(gettext(ERR_TC_WRITE), tContentsPath);
577*5c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
578*5c51f124SMoriah Waterland 		vfpClose(a_cfTmpVfp);
579*5c51f124SMoriah Waterland 		(void) remove(tContentsPath);
580*5c51f124SMoriah Waterland 		(void) pkgWunlock();	/* Free the database lock. */
581*5c51f124SMoriah Waterland 		return (RESULT_ERR);
582*5c51f124SMoriah Waterland 	}
583*5c51f124SMoriah Waterland 
584*5c51f124SMoriah Waterland 	/*
585*5c51f124SMoriah Waterland 	 * Now we want to make a copy of the old contents file as a
586*5c51f124SMoriah Waterland 	 * fail-safe. In support of that, we create a hard link to
587*5c51f124SMoriah Waterland 	 * s.contents.
588*5c51f124SMoriah Waterland 	 */
589*5c51f124SMoriah Waterland 
590*5c51f124SMoriah Waterland 	if ((access(sContentsPath, F_OK) == 0) && remove(sContentsPath)) {
591*5c51f124SMoriah Waterland 		int	lerrno = errno;
592*5c51f124SMoriah Waterland 
593*5c51f124SMoriah Waterland 		logerr(gettext(ERR_NOUNLINK_LATENT), sContentsPath);
594*5c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
595*5c51f124SMoriah Waterland 		(void) remove(tContentsPath);
596*5c51f124SMoriah Waterland 		(void) pkgWunlock();	/* Free the database lock. */
597*5c51f124SMoriah Waterland 		vfpClose(a_cfTmpVfp);
598*5c51f124SMoriah Waterland 		return (RESULT_ERR);
599*5c51f124SMoriah Waterland 	}
600*5c51f124SMoriah Waterland 
601*5c51f124SMoriah Waterland 	if (link(contentsPath, sContentsPath) != 0) {
602*5c51f124SMoriah Waterland 		int	lerrno = errno;
603*5c51f124SMoriah Waterland 
604*5c51f124SMoriah Waterland 		progerr(gettext(ERR_NOUPD));
605*5c51f124SMoriah Waterland 		logerr(gettext(ERR_LINK_FAIL), contentsPath, sContentsPath,
606*5c51f124SMoriah Waterland 			lerrno);
607*5c51f124SMoriah Waterland 		(void) remove(tContentsPath);
608*5c51f124SMoriah Waterland 		(void) pkgWunlock();	/* Free the database lock. */
609*5c51f124SMoriah Waterland 		vfpClose(a_cfTmpVfp);
610*5c51f124SMoriah Waterland 		return (RESULT_ERR);
611*5c51f124SMoriah Waterland 	}
612*5c51f124SMoriah Waterland 
613*5c51f124SMoriah Waterland 	if (rename(tContentsPath, contentsPath) != 0) {
614*5c51f124SMoriah Waterland 		int	lerrno = errno;
615*5c51f124SMoriah Waterland 
616*5c51f124SMoriah Waterland 		progerr(gettext(ERR_NORENAME_CONTENTS), contentsPath,
617*5c51f124SMoriah Waterland 			tContentsPath);
618*5c51f124SMoriah Waterland 		logerr(gettext(ERR_RENAME_FAIL), tContentsPath,
619*5c51f124SMoriah Waterland 			contentsPath, lerrno);
620*5c51f124SMoriah Waterland 		if (rename(sContentsPath, contentsPath)) {
621*5c51f124SMoriah Waterland 			lerrno = errno;
622*5c51f124SMoriah Waterland 			progerr(gettext(ERR_RESTORE_FAIL), contentsPath);
623*5c51f124SMoriah Waterland 			logerr(gettext(ERR_RENAME_FAIL), sContentsPath,
624*5c51f124SMoriah Waterland 				contentsPath, lerrno);
625*5c51f124SMoriah Waterland 		}
626*5c51f124SMoriah Waterland 		(void) remove(tContentsPath);
627*5c51f124SMoriah Waterland 	}
628*5c51f124SMoriah Waterland 
629*5c51f124SMoriah Waterland 	if (remove(sContentsPath) != 0) {
630*5c51f124SMoriah Waterland 		int	lerrno = errno;
631*5c51f124SMoriah Waterland 
632*5c51f124SMoriah Waterland 		logerr(gettext(ERR_NOUNLINK), sContentsPath);
633*5c51f124SMoriah Waterland 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
634*5c51f124SMoriah Waterland 		retval = RESULT_WRN;
635*5c51f124SMoriah Waterland 	}
636*5c51f124SMoriah Waterland 
637*5c51f124SMoriah Waterland 	/*
638*5c51f124SMoriah Waterland 	 * checkpoint the temporary contents file - if this fails, then
639*5c51f124SMoriah Waterland 	 * just close the file which causes the contents file to be reopened
640*5c51f124SMoriah Waterland 	 * and reread if it is needed again
641*5c51f124SMoriah Waterland 	 */
642*5c51f124SMoriah Waterland 
643*5c51f124SMoriah Waterland 	if (vfpCheckpointFile(&contentsVfp, a_cfTmpVfp, contentsPath) != 0) {
644*5c51f124SMoriah Waterland 		vfpClose(a_cfTmpVfp);
645*5c51f124SMoriah Waterland 	}
646*5c51f124SMoriah Waterland 
647*5c51f124SMoriah Waterland 	return (relslock() == 0 ? RESULT_ERR : retval);
648*5c51f124SMoriah Waterland }
649*5c51f124SMoriah Waterland 
650*5c51f124SMoriah Waterland /* This function releases the lock on the package database. */
651*5c51f124SMoriah Waterland int
652*5c51f124SMoriah Waterland relslock(void)
653*5c51f124SMoriah Waterland {
654*5c51f124SMoriah Waterland 	/*
655*5c51f124SMoriah Waterland 	 * This closes the contents file and releases the lock.
656*5c51f124SMoriah Waterland 	 */
657*5c51f124SMoriah Waterland 	if (!pkgWunlock()) {
658*5c51f124SMoriah Waterland 		int	lerrno = errno;
659*5c51f124SMoriah Waterland 
660*5c51f124SMoriah Waterland 		progerr(gettext(ERR_NOUPD));
661*5c51f124SMoriah Waterland 		logerr(gettext(ERR_FCLOSE_FAIL), lerrno);
662*5c51f124SMoriah Waterland 		return (0);
663*5c51f124SMoriah Waterland 	}
664*5c51f124SMoriah Waterland 	return (1);
665*5c51f124SMoriah Waterland }
666*5c51f124SMoriah Waterland 
667*5c51f124SMoriah Waterland /*
668*5c51f124SMoriah Waterland  * This function attempts to lock the package database. It returns 1 on
669*5c51f124SMoriah Waterland  * success, 0 on failure. The positive logic verbose flag determines whether
670*5c51f124SMoriah Waterland  * or not the function displays the error message upon failure.
671*5c51f124SMoriah Waterland  */
672*5c51f124SMoriah Waterland static int
673*5c51f124SMoriah Waterland pkgWlock(int verbose) {
674*5c51f124SMoriah Waterland 	int retry_cnt, retval;
675*5c51f124SMoriah Waterland 	char lockpath[PATH_MAX];
676*5c51f124SMoriah Waterland 
677*5c51f124SMoriah Waterland 	active_lock = 0;
678*5c51f124SMoriah Waterland 
679*5c51f124SMoriah Waterland 	(void) snprintf(lockpath, sizeof (lockpath),
680*5c51f124SMoriah Waterland 			"%s/%s", pkgadm_dir, LOCKFILE);
681*5c51f124SMoriah Waterland 
682*5c51f124SMoriah Waterland 	retry_cnt = LOCKRETRY;
683*5c51f124SMoriah Waterland 
684*5c51f124SMoriah Waterland 	/*
685*5c51f124SMoriah Waterland 	 * If the lock file is not present, create it. The mode is set to
686*5c51f124SMoriah Waterland 	 * allow any process to lock the database, that's because pkgchk may
687*5c51f124SMoriah Waterland 	 * be run by a non-root user.
688*5c51f124SMoriah Waterland 	 */
689*5c51f124SMoriah Waterland 	if (access(lockpath, F_OK) == -1) {
690*5c51f124SMoriah Waterland 		lock_fd = open(lockpath, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644);
691*5c51f124SMoriah Waterland 		if (lock_fd < 0) {
692*5c51f124SMoriah Waterland 			if (verbose)
693*5c51f124SMoriah Waterland 				progerr(gettext(ERR_MKLOCK), lockpath);
694*5c51f124SMoriah Waterland 			return (0);
695*5c51f124SMoriah Waterland 		} else {
696*5c51f124SMoriah Waterland 			(void) fchmod(lock_fd, 0644);	/* force perms. */
697*5c51f124SMoriah Waterland 		}
698*5c51f124SMoriah Waterland 	} else {
699*5c51f124SMoriah Waterland 		if ((lock_fd = open(lockpath, O_RDWR)) == -1) {
700*5c51f124SMoriah Waterland 			if (verbose)
701*5c51f124SMoriah Waterland 				progerr(gettext(ERR_OPLOCK), lockpath);
702*5c51f124SMoriah Waterland 			return (0);
703*5c51f124SMoriah Waterland 		}
704*5c51f124SMoriah Waterland 	}
705*5c51f124SMoriah Waterland 
706*5c51f124SMoriah Waterland 	(void) signal(SIGALRM, do_alarm);
707*5c51f124SMoriah Waterland 	(void) alarm(LOCKWAIT);
708*5c51f124SMoriah Waterland 
709*5c51f124SMoriah Waterland 	do {
710*5c51f124SMoriah Waterland 		if (lockf(lock_fd, F_LOCK, 0)) {
711*5c51f124SMoriah Waterland 			if (errno == EAGAIN || errno == EINTR)
712*5c51f124SMoriah Waterland 				logerr(gettext(MSG_XWTING));
713*5c51f124SMoriah Waterland 			else if (errno == ECOMM) {
714*5c51f124SMoriah Waterland 				logerr(gettext(ERR_LCKREM));
715*5c51f124SMoriah Waterland 				retval = 0;
716*5c51f124SMoriah Waterland 				break;
717*5c51f124SMoriah Waterland 			} else if (errno == EBADF) {
718*5c51f124SMoriah Waterland 				logerr(gettext(ERR_BADLCK));
719*5c51f124SMoriah Waterland 				retval = 0;
720*5c51f124SMoriah Waterland 				break;
721*5c51f124SMoriah Waterland 			} else if (errno == EDEADLK) {
722*5c51f124SMoriah Waterland 				logerr(gettext(ERR_DEADLCK));
723*5c51f124SMoriah Waterland 				retval = 0;
724*5c51f124SMoriah Waterland 				break;
725*5c51f124SMoriah Waterland 			}
726*5c51f124SMoriah Waterland 		} else {
727*5c51f124SMoriah Waterland 			active_lock = 1;
728*5c51f124SMoriah Waterland 			retval = 1;
729*5c51f124SMoriah Waterland 			break;
730*5c51f124SMoriah Waterland 		}
731*5c51f124SMoriah Waterland 	} while (retry_cnt--);
732*5c51f124SMoriah Waterland 
733*5c51f124SMoriah Waterland 	(void) signal(SIGALRM, SIG_IGN);
734*5c51f124SMoriah Waterland 
735*5c51f124SMoriah Waterland 	if (retval == 0)
736*5c51f124SMoriah Waterland 	{
737*5c51f124SMoriah Waterland 		if (retry_cnt == -1) {
738*5c51f124SMoriah Waterland 			logerr(gettext(ERR_TMOUT));
739*5c51f124SMoriah Waterland 		}
740*5c51f124SMoriah Waterland 
741*5c51f124SMoriah Waterland 		(void) pkgWunlock();	/* close the lockfile. */
742*5c51f124SMoriah Waterland 	}
743*5c51f124SMoriah Waterland 
744*5c51f124SMoriah Waterland 	return (retval);
745*5c51f124SMoriah Waterland }
746*5c51f124SMoriah Waterland 
747*5c51f124SMoriah Waterland /*
748*5c51f124SMoriah Waterland  * Release the lock on the package database. Returns 1 on success, 0 on
749*5c51f124SMoriah Waterland  * failure.
750*5c51f124SMoriah Waterland  */
751*5c51f124SMoriah Waterland static int
752*5c51f124SMoriah Waterland pkgWunlock(void) {
753*5c51f124SMoriah Waterland 	if (active_lock) {
754*5c51f124SMoriah Waterland 		active_lock = 0;
755*5c51f124SMoriah Waterland 		if (close(lock_fd))
756*5c51f124SMoriah Waterland 			return (0);
757*5c51f124SMoriah Waterland 		else
758*5c51f124SMoriah Waterland 			return (1);
759*5c51f124SMoriah Waterland 	} else
760*5c51f124SMoriah Waterland 		return (1);
761*5c51f124SMoriah Waterland }
762*5c51f124SMoriah Waterland 
763*5c51f124SMoriah Waterland /*
764*5c51f124SMoriah Waterland  * This function verifies that the contents file is in place.
765*5c51f124SMoriah Waterland  * returns 1 - if it exists
766*5c51f124SMoriah Waterland  * returns 0 - if it does not exist
767*5c51f124SMoriah Waterland  */
768*5c51f124SMoriah Waterland int
769*5c51f124SMoriah Waterland iscfile(void)
770*5c51f124SMoriah Waterland {
771*5c51f124SMoriah Waterland 	char	contents[PATH_MAX];
772*5c51f124SMoriah Waterland 
773*5c51f124SMoriah Waterland 	(void) snprintf(contents, PATH_MAX, "%s/contents", get_PKGADM());
774*5c51f124SMoriah Waterland 
775*5c51f124SMoriah Waterland 	return (access(contents, F_OK) == 0 ? 1 : 0);
776*5c51f124SMoriah Waterland }
777*5c51f124SMoriah Waterland 
778*5c51f124SMoriah Waterland /*
779*5c51f124SMoriah Waterland  * This function verifies that the contents file is in place. If it is - no
780*5c51f124SMoriah Waterland  * change. If it isn't - this creates it.
781*5c51f124SMoriah Waterland  * Returns:	== 0 : failure
782*5c51f124SMoriah Waterland  *		!= 0 : success
783*5c51f124SMoriah Waterland  */
784*5c51f124SMoriah Waterland 
785*5c51f124SMoriah Waterland int
786*5c51f124SMoriah Waterland vcfile(void)
787*5c51f124SMoriah Waterland {
788*5c51f124SMoriah Waterland 	int	lerrno;
789*5c51f124SMoriah Waterland 	int	fd;
790*5c51f124SMoriah Waterland 	char	contents[PATH_MAX];
791*5c51f124SMoriah Waterland 
792*5c51f124SMoriah Waterland 	/*
793*5c51f124SMoriah Waterland 	 * create full path to contents file
794*5c51f124SMoriah Waterland 	 */
795*5c51f124SMoriah Waterland 
796*5c51f124SMoriah Waterland 	(void) snprintf(contents, sizeof (contents),
797*5c51f124SMoriah Waterland 			"%s/contents", get_PKGADM());
798*5c51f124SMoriah Waterland 
799*5c51f124SMoriah Waterland 	/*
800*5c51f124SMoriah Waterland 	 * Attempt to create the file - will only be successful
801*5c51f124SMoriah Waterland 	 * if the file does not currently exist.
802*5c51f124SMoriah Waterland 	 */
803*5c51f124SMoriah Waterland 
804*5c51f124SMoriah Waterland 	fd = open(contents, O_WRONLY | O_CREAT | O_EXCL, 0644);
805*5c51f124SMoriah Waterland 	if (fd >= 0) {
806*5c51f124SMoriah Waterland 		/*
807*5c51f124SMoriah Waterland 		 * Contents file wasn't there, but is now.
808*5c51f124SMoriah Waterland 		 */
809*5c51f124SMoriah Waterland 
810*5c51f124SMoriah Waterland 		echo(gettext("## Software contents file initialized"));
811*5c51f124SMoriah Waterland 		(void) close(fd);
812*5c51f124SMoriah Waterland 		return (1);	/* success */
813*5c51f124SMoriah Waterland 	}
814*5c51f124SMoriah Waterland 
815*5c51f124SMoriah Waterland 	/*
816*5c51f124SMoriah Waterland 	 * Could not create the file - it may exist or there may be
817*5c51f124SMoriah Waterland 	 * permissions issues - find out and act accordingly.
818*5c51f124SMoriah Waterland 	 */
819*5c51f124SMoriah Waterland 
820*5c51f124SMoriah Waterland 	lerrno = errno;
821*5c51f124SMoriah Waterland 
822*5c51f124SMoriah Waterland 	/* success if error is 'file exists' */
823*5c51f124SMoriah Waterland 
824*5c51f124SMoriah Waterland 	if (lerrno == EEXIST) {
825*5c51f124SMoriah Waterland 		return (1);	/* success */
826*5c51f124SMoriah Waterland 	}
827*5c51f124SMoriah Waterland 
828*5c51f124SMoriah Waterland 	/* success if error is 'permission denied' but file exists */
829*5c51f124SMoriah Waterland 
830*5c51f124SMoriah Waterland 	if (lerrno == EACCES) {
831*5c51f124SMoriah Waterland 		/*
832*5c51f124SMoriah Waterland 		 * Because O_CREAT and O_EXCL are specified in open(),
833*5c51f124SMoriah Waterland 		 * if the contents file already exists, the open will
834*5c51f124SMoriah Waterland 		 * fail with EACCES - determine if this is the case -
835*5c51f124SMoriah Waterland 		 * if so return success.
836*5c51f124SMoriah Waterland 		 */
837*5c51f124SMoriah Waterland 
838*5c51f124SMoriah Waterland 		if (access(contents, F_OK) == 0) {
839*5c51f124SMoriah Waterland 			return (1);	/* success */
840*5c51f124SMoriah Waterland 		}
841*5c51f124SMoriah Waterland 
842*5c51f124SMoriah Waterland 		/*
843*5c51f124SMoriah Waterland 		 * access() failed - if because of permissions failure this
844*5c51f124SMoriah Waterland 		 * means the contents file exists but it cannot be accessed
845*5c51f124SMoriah Waterland 		 * or the path to the contents file cannot be accessed - in
846*5c51f124SMoriah Waterland 		 * either case the contents file cannot be accessed.
847*5c51f124SMoriah Waterland 		 */
848*5c51f124SMoriah Waterland 
849*5c51f124SMoriah Waterland 		if (errno == EACCES) {
850*5c51f124SMoriah Waterland 			progerr(gettext(ERR_ACCESS_CONT), contents,
851*5c51f124SMoriah Waterland 					strerror(lerrno));
852*5c51f124SMoriah Waterland 			logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
853*5c51f124SMoriah Waterland 			return (0);	/* failure */
854*5c51f124SMoriah Waterland 		}
855*5c51f124SMoriah Waterland 	}
856*5c51f124SMoriah Waterland 
857*5c51f124SMoriah Waterland 	/*
858*5c51f124SMoriah Waterland 	 * the contents file does not exist and it cannot be created.
859*5c51f124SMoriah Waterland 	 */
860*5c51f124SMoriah Waterland 
861*5c51f124SMoriah Waterland 	progerr(gettext(ERR_CREAT_CONT), contents, strerror(lerrno));
862*5c51f124SMoriah Waterland 	logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
863*5c51f124SMoriah Waterland 	return (0);	/* failure */
864*5c51f124SMoriah Waterland }
865