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