xref: /illumos-gate/usr/src/cmd/svr4pkg/libinst/ocfile.c (revision 94360ae1f2b5d61a6b7fd32a528b0d0860f1f1d7)
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 2009 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.client"
58 #define	LOCKFILESERV	".pkg.lock"
59 
60 #define	LOCKWAIT	10	/* seconds between retries */
61 #define	LOCKRETRY	20	/* number of retries for a DB lock */
62 
63 #define	ERR_COMMIT	"WARNING: unable to commit contents database update"
64 #define	ERR_NOCLOSE	"WARNING: unable to close <%s>"
65 #define	ERR_NOUNLINK_LATENT	"WARNING: unable to unlink latent <%s>"
66 #define	ERR_LINK_FAIL	"link(%s, %s) failed (errno %d)"
67 #define	ERR_NORENAME_CONTENTS	"unable to establish contents file <%s> "\
68 			"from <%s>"
69 #define	ERR_RENAME_FAIL	"rename(%s, %s) failed (errno %d)"
70 #define	ERR_RESTORE_FAIL	"attempt to restore <%s> failed"
71 #define	ERR_NOUNLINK	"WARNING: unable to unlink <%s>"
72 #define	ERR_FCLOSE_FAIL	"fclose failed (errno %d)"
73 #define	ERR_ERRNO	"(errno %d: %s)"
74 #define	ERR_NOTMPOPEN	"unable to open temporary contents file image"
75 #define	ERR_CFBACK	"Not enough space to backup <%s>"
76 #define	ERR_CREAT_CONT	"unable to create contents file <%s>: %s"
77 #define	ERR_ACCESS_CONT	"unable to access contents file <%s>: %s"
78 #define	ERR_CFBACK1	"Need=%llu blocks, Available=%llu blocks " \
79 			"(block size=%d)"
80 #define	ERR_NOCFILE	"unable to locate contents file <%s>"
81 #define	ERR_NOROPEN	"unable to open <%s> for reading"
82 #define	ERR_NOOPEN	"unable to open <%s> for writing"
83 #define	ERR_NOSTAT	"unable to stat contents file <%s>"
84 #define	ERR_NOSTATV	"statvfs(%s) failed"
85 #define	ERR_NOUPD	"unable to update contents file"
86 #define	ERR_DRCONTCP	"unable to copy contents file to <%s>"
87 
88 #define	MSG_XWTING	"NOTE: Waiting for exclusive access to the package " \
89 				"database."
90 #define	MSG_NOLOCK	"NOTE: Couldn't lock the package database."
91 
92 #define	ERR_NOLOCK	"Database lock failed."
93 #define	ERR_OPLOCK	"unable to open lock file <%s>."
94 #define	ERR_MKLOCK	"unable to create lock file <%s>."
95 #define	ERR_LCKREM	"unable to lock package database - remote host " \
96 				"unavailable."
97 #define	ERR_BADLCK	"unable to lock package database - unknown error."
98 #define	ERR_DEADLCK	"unable to lock package database - deadlock condition."
99 #define	ERR_TMOUT	"unable to lock package database - too many retries."
100 #define	ERR_CFDIR	"unable to locate contents file directory"
101 
102 static int	active_lock;
103 static int	lock_fd;	/* fd of LOCKFILE. */
104 static char	*pkgadm_dir;
105 
106 int		pkgWlock(int verbose);
107 static int	pkgWunlock(void);
108 
109 /* forward declarations */
110 
111 int relslock(void);
112 
113 /*ARGSUSED*/
114 static void
115 do_alarm(int n)
116 {
117 	(void) signal(SIGALRM, SIG_IGN);
118 	(void) signal(SIGALRM, do_alarm);
119 	(void) alarm(LOCKWAIT);
120 }
121 
122 /*
123  * Point packaging to the appropriate contents file. This is primarily used
124  * to establish a dryrun contents file. If the malloc() doesn't work, this
125  * returns 99 (internal error), else 0.
126  */
127 int
128 set_cfdir(char *cfdir)
129 {
130 	char	realcf[PATH_MAX];
131 	char	tmpcf[PATH_MAX];
132 	int	status;
133 
134 	if (cfdir == NULL) {
135 		pkgadm_dir = get_PKGADM();
136 		return (0);
137 	}
138 
139 	if ((pkgadm_dir = strdup(cfdir)) == NULL) {
140 		return (99);
141 	}
142 
143 	(void) snprintf(tmpcf, sizeof (tmpcf), "%s/contents", pkgadm_dir);
144 
145 	/*
146 	 * return if a temporary contents file already exists -
147 	 * assume it is from a prior package in this series.
148 	 */
149 
150 	if (access(tmpcf, F_OK) == 0) {
151 		return (0);
152 	}
153 
154 	/*
155 	 * no temporary contents file exists - create one.
156 	 */
157 
158 	(void) snprintf(realcf, sizeof (realcf), "%s/contents", get_PKGADM());
159 
160 	/*
161 	 * If there's a contents file there already, copy it
162 	 * over, otherwise initialize one.  Make sure that the
163 	 * server, if running, flushes the contents file.
164 	 */
165 
166 	(void) pkgsync(NULL, get_PKGADM(), B_FALSE);
167 
168 	/* create new contents file if one does not already exist */
169 
170 	if (access(realcf, F_OK) != 0) {
171 		int n;
172 
173 		n = open(tmpcf, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
174 		if (n < 0) {
175 			progerr(gettext(ERR_CREAT_CONT), tmpcf,
176 			    strerror(errno));
177 			return (99);
178 		}
179 		(void) close(n);
180 	} else {
181 
182 		/* contents file exists, save in pkgadm-dir */
183 
184 		status = copyf(realcf, tmpcf, (time_t)0);
185 		if (status != 0) {
186 			progerr(gettext(ERR_DRCONTCP), tmpcf);
187 			return (99);
188 		}
189 	}
190 
191 	return (0);
192 }
193 
194 /*
195  * This function installs the database lock, opens the contents file for
196  * reading and creates and opens the temporary contents file for read/write.
197  * It returns 1 if successful, 0 otherwise.
198  */
199 int
200 ocfile(PKGserver *server, VFP_T **r_tmpvfp, fsblkcnt_t map_blks)
201 {
202 	struct	stat64	statb;
203 	struct	statvfs64	svfsb;
204 	fsblkcnt_t free_blocks;
205 	fsblkcnt_t need_blocks;
206 	VFP_T		*tmpvfp = (VFP_T *)NULL;
207 	char		contents[PATH_MAX];
208 	int		n;
209 	off_t		cdiff_alloc;
210 	PKGserver	newserver;
211 
212 	/* establish package administration contents directory location */
213 
214 	if (pkgadm_dir == NULL) {
215 		if (set_cfdir(NULL) != 0) {
216 			progerr(gettext(ERR_CFDIR));
217 			return (0);
218 		}
219 	}
220 
221 	/* Lock the file for exclusive access */
222 
223 	if (!pkgWlock(1)) {
224 		progerr(gettext(ERR_NOLOCK));
225 		return (0);
226 	}
227 
228 	if (*server != NULL) {
229 		vfpTruncate(*r_tmpvfp);
230 		(void) vfpClearModified(*r_tmpvfp);
231 
232 		return (1);
233 	}
234 
235 	newserver = pkgopenserver(NULL, pkgadm_dir, B_FALSE);
236 
237 	/* The error has been reported. */
238 	if (newserver == NULL)
239 		return (0);
240 
241 	/* reset return VFP/FILE pointers */
242 
243 	(*r_tmpvfp) = (VFP_T *)NULL;
244 
245 	/* determine path to the primary contents file */
246 	(void) snprintf(contents, sizeof (contents), "%s/contents", pkgadm_dir);
247 
248 	/*
249 	 * Check and see if there is enough space for the packaging commands
250 	 * to back up the contents file, if there is not, then do not allow
251 	 * execution to continue by failing the ocfile() call.
252 	 */
253 
254 	/* Get the contents file size */
255 
256 	if (stat64(contents, &statb) == -1) {
257 		int	lerrno = errno;
258 
259 		progerr(gettext(ERR_NOCFILE), contents);
260 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
261 		pkgcloseserver(newserver);
262 		return (0);
263 	}
264 
265 	/* Get the filesystem space */
266 
267 	if (statvfs64(contents, &svfsb) == -1) {
268 		int	lerrno = errno;
269 
270 		progerr(gettext(ERR_NOSTATV), contents);
271 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
272 		pkgcloseserver(newserver);
273 		return (0);
274 	}
275 
276 	free_blocks = (((fsblkcnt_t)svfsb.f_frsize > 0) ?
277 			howmany(svfsb.f_frsize, DEV_BSIZE) :
278 			howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bfree;
279 
280 	/*
281 	 * If we're removing a package, then the log might grow to the size
282 	 * of the full contents file.
283 	 */
284 
285 	if (map_blks == 0LL)
286 		map_blks = nblk(statb.st_size, svfsb.f_bsize, svfsb.f_frsize);
287 
288 	/*
289 	 * Calculate the number of blocks we need to be able to operate on
290 	 * the contents file.
291 	 */
292 	need_blocks = map_blks +
293 		/* Max of the log file */
294 		nblk(MAXLOGFILESIZE, svfsb.f_bsize, svfsb.f_frsize) +
295 		/* Current content file */
296 		nblk(statb.st_size, svfsb.f_bsize, svfsb.f_frsize);
297 
298 	if ((need_blocks + 10) > free_blocks) {
299 		progerr(gettext(ERR_CFBACK), contents);
300 		progerr(gettext(ERR_CFBACK1), need_blocks, free_blocks,
301 			DEV_BSIZE);
302 		pkgcloseserver(newserver);
303 		return (0);
304 	}
305 
306 	/*
307 	 * open the temporary contents file without a path name - this causes
308 	 * the "vfp" to be opened on in-memory storage only, the size of which
309 	 * is set following a successful return - this causes the temporary
310 	 * contents file to be maintained in memory only - if no changes are
311 	 * made as the primary contents file is processed, the in memory data
312 	 * is discarded and not written to the disk.
313 	 */
314 
315 	if (vfpOpen(&tmpvfp, (char *)NULL, "w", VFP_NONE) != 0) {
316 		int	lerrno = errno;
317 
318 		progerr(gettext(ERR_NOTMPOPEN));
319 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
320 		pkgcloseserver(newserver);
321 		return (0);
322 	}
323 
324 	/*
325 	 * set size of allocation for temporary contents file - this sets the
326 	 * size of the in-memory buffer associated with the open vfp.
327 	 * We only store the new and changed entries.
328 	 * We allocate memory depending on the size of the pkgmap; it's not
329 	 * completely right but <some value + * 1.5 * map_blks * DEV_BSIZE>
330 	 * seems fine (an install adds the size if the name of the package.)
331 	 */
332 
333 	cdiff_alloc = map_blks * DEV_BSIZE;
334 	cdiff_alloc += cdiff_alloc/2;
335 	if (cdiff_alloc < 1000000)
336 		cdiff_alloc += 1000000;
337 
338 	if (vfpSetSize(tmpvfp, cdiff_alloc) != 0) {
339 		int	lerrno = errno;
340 
341 		progerr(gettext(ERR_NOTMPOPEN));
342 		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
343 		(void) vfpClose(&tmpvfp);
344 		pkgcloseserver(newserver);
345 		return (0);
346 	}
347 
348 	/* set return ->s to open server/vfps */
349 
350 	(*r_tmpvfp) = tmpvfp;
351 	*server = newserver;
352 
353 	return (1);	/* All OK */
354 }
355 
356 /*
357  * This is a simple open and lock of the contents file. It doesn't create a
358  * temporary contents file and it doesn't need to do any space checking.
359  * Returns 1 for OK and 0 for "didn't do it".
360  */
361 int
362 socfile(PKGserver *server, boolean_t quiet)
363 {
364 	char		contents[PATH_MAX];
365 	boolean_t 	readonly = B_FALSE;
366 	PKGserver	newserver;
367 
368 	if (pkgadm_dir == NULL) {
369 		if (set_cfdir(NULL) != 0) {
370 			progerr(gettext(ERR_CFDIR));
371 			return (0);
372 		}
373 	}
374 
375 	/*
376 	 * Lock the database for exclusive access, but don't make a fuss if
377 	 * it fails (user may not be root and the .pkg.lock file may not
378 	 * exist yet).
379 	 */
380 
381 	if (!pkgWlock(0)) {
382 		if (!quiet)
383 			logerr(gettext(MSG_NOLOCK));
384 		readonly = B_TRUE;
385 	}
386 
387 	newserver = pkgopenserver(NULL, pkgadm_dir, readonly);
388 	if (newserver == NULL)
389 		return (0);
390 
391 	*server = newserver;
392 	return (1);
393 }
394 
395 /*
396  * Name:	swapcfile
397  * Description: This function closes both the current and temporary contents
398  *		files specified, and conditionally replaces the old transitory
399  *		contents file with the newly updated temporary contents file.
400  *		The "ocfile()" or "socfile()" functions must be called to re-
401  *		open the real contents file for processing.
402  * Arguments:	PKGserver - handle to the package database
403  *		a_cfTmpVfp - (VFP_T **) - [RW, *RW]
404  *			This is the VFP associated which contains all the
405  *			modifications to be written back to the database.
406  *			file that is being written to.
407  *		pkginst - (char) - [RO, *RO]
408  *			This is the name of the package being operated on;
409  *			this is used to write the "last modified by xxx"
410  *			comment at the end of the contents file.
411  *		dbchg - (int) - [RO]
412  *			== 0 - the temporary contents file has NOT been changed
413  *				with respect to the real contents file; do not
414  *				update the real contents file with the contents
415  *				of the temporary contents file.
416  *			!= 0 - the temporary contetns file HAS been changed with
417  *				respect to the real contents file; DO update the
418  *				real contents file with the contents of the
419  *				temporary contents file.
420  * Returns:	int	== RESULT_OK - successful
421  *			== RESULT_WRN - successful with warnings
422  *			== RESULT_ERR - failed with fatal errors - deserves an
423  *				alarming message and a quit()
424  * NOTES: If dbchg != 0, the contents file is always updated. If dbchg == 0,
425  *		the contents file is updated IF the data is modified indication
426  *		is set on the contents file associated with a_cfTmpVfp.
427  */
428 
429 int
430 swapcfile(PKGserver server, VFP_T **a_cfTmpVfp, char *pkginst, int dbchg)
431 {
432 	char	*pe;
433 	char	*pl;
434 	char	*ps;
435 	char	line[256];
436 	char	timeb[BUFSIZ];
437 	int	retval = RESULT_OK;
438 	struct tm	*timep;
439 	time_t	clock;
440 
441 	/* normalize pkginst so its never null */
442 
443 	if (pkginst == (char *)NULL) {
444 		dbchg = 0;
445 		pkginst = "<unknown>";
446 	}
447 
448 	/*
449 	 * If no changes were made to the database, checkpoint the temporary
450 	 * contents file - if this fails, then just close the file which causes
451 	 * the contents file to be reopened and reread if it is needed again
452 	 */
453 
454 	if ((dbchg == 0) && (vfpGetModified(*a_cfTmpVfp) == 0)) {
455 		(void) pkgWunlock();	/* Free the database lock. */
456 		return (retval);
457 	}
458 
459 	/*
460 	 * changes made to the current temporary contents file -
461 	 * remove any trailing comment lines in the temp contents file, then
462 	 * append updated modification info records to temp contents file
463 	 */
464 
465 	pe = vfpGetCurrCharPtr(*a_cfTmpVfp);	/* last char in contents file */
466 	ps = vfpGetFirstCharPtr(*a_cfTmpVfp);	/* 1st char in contents file */
467 	pl = pe;	/* last match is last char in contents file */
468 
469 	/* skip past all trailing newlines and null bytes */
470 
471 	while ((pe > ps) && ((*pe == '\n') || (*pe == '\0'))) {
472 		pe--;
473 	}
474 
475 	/* remove trailing comments as long as there are lines in the file */
476 
477 	while (pe > ps) {
478 		if (*pe != '\n') {
479 			/* curr char is not newline: backup one byte */
480 			pl = pe--;
481 		} else if (*pl != '#') {
482 			/* curr char is newline next char not comment break */
483 			break;
484 		} else {
485 			/* curr char is newline next char is comment - remove */
486 			*pl = '\0';
487 			vfpSetLastCharPtr(*a_cfTmpVfp, pl);
488 			pe--;
489 		}
490 	}
491 
492 	/* create two update comment lines */
493 
494 	(void) time(&clock);
495 	timep = localtime(&clock);
496 
497 	(void) strftime(timeb, sizeof (timeb), "%c\n", timep);
498 	(void) snprintf(line, sizeof (line),
499 		gettext("# Last modified by %s for %s package\n# %s"),
500 		get_prog_name(), pkginst, timeb);
501 	vfpPuts(*a_cfTmpVfp, line);
502 
503 	/* commit temporary contents file bytes to storage */
504 
505 	if (pkgservercommitfile(*a_cfTmpVfp, server) != 0) {
506 		int	lerrno = errno;
507 
508 		logerr(gettext(ERR_COMMIT));
509 		vfpClose(a_cfTmpVfp);
510 		pkgcloseserver(server);
511 		(void) pkgWunlock();	/* Free the database lock. */
512 		return (RESULT_ERR);
513 	}
514 
515 	return (relslock() == 0 ? RESULT_ERR : retval);
516 }
517 
518 /* This function releases the lock on the package database. */
519 int
520 relslock(void)
521 {
522 	/*
523 	 * This closes the contents file and releases the lock.
524 	 */
525 	if (!pkgWunlock()) {
526 		int	lerrno = errno;
527 
528 		progerr(gettext(ERR_NOUPD));
529 		logerr(gettext(ERR_FCLOSE_FAIL), lerrno);
530 		return (0);
531 	}
532 	return (1);
533 }
534 
535 /*
536  * This function attempts to lock the package database. It returns 1 on
537  * success, 0 on failure. The positive logic verbose flag determines whether
538  * or not the function displays the error message upon failure.
539  */
540 int
541 pkgWlock(int verbose) {
542 	int retry_cnt, retval;
543 	char lockpath[PATH_MAX];
544 
545 	active_lock = 0;
546 
547 	(void) snprintf(lockpath, sizeof (lockpath),
548 			"%s/%s", pkgadm_dir, LOCKFILE);
549 
550 	retry_cnt = LOCKRETRY;
551 
552 	/*
553 	 * If the lock file is not present, create it. The mode is set to
554 	 * allow any process to lock the database, that's because pkgchk may
555 	 * be run by a non-root user.
556 	 */
557 	if (access(lockpath, F_OK) == -1) {
558 		lock_fd = open(lockpath, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644);
559 		if (lock_fd < 0) {
560 			if (verbose)
561 				progerr(gettext(ERR_MKLOCK), lockpath);
562 			return (0);
563 		} else {
564 			(void) fchmod(lock_fd, 0644);	/* force perms. */
565 		}
566 	} else {
567 		if ((lock_fd = open(lockpath, O_RDWR)) == -1) {
568 			if (verbose)
569 				progerr(gettext(ERR_OPLOCK), lockpath);
570 			return (0);
571 		}
572 	}
573 
574 	(void) signal(SIGALRM, do_alarm);
575 	(void) alarm(LOCKWAIT);
576 
577 	do {
578 		if (lockf(lock_fd, F_LOCK, 0)) {
579 			if (errno == EAGAIN || errno == EINTR)
580 				logerr(gettext(MSG_XWTING));
581 			else if (errno == ECOMM) {
582 				logerr(gettext(ERR_LCKREM));
583 				retval = 0;
584 				break;
585 			} else if (errno == EBADF) {
586 				logerr(gettext(ERR_BADLCK));
587 				retval = 0;
588 				break;
589 			} else if (errno == EDEADLK) {
590 				logerr(gettext(ERR_DEADLCK));
591 				retval = 0;
592 				break;
593 			}
594 		} else {
595 			active_lock = 1;
596 			retval = 1;
597 			break;
598 		}
599 	} while (retry_cnt--);
600 
601 	(void) signal(SIGALRM, SIG_IGN);
602 
603 	if (retval == 0)
604 	{
605 		if (retry_cnt == -1) {
606 			logerr(gettext(ERR_TMOUT));
607 		}
608 
609 		(void) pkgWunlock();	/* close the lockfile. */
610 	}
611 
612 	return (retval);
613 }
614 
615 /*
616  * Release the lock on the package database. Returns 1 on success, 0 on
617  * failure.
618  */
619 static int
620 pkgWunlock(void) {
621 	if (active_lock) {
622 		active_lock = 0;
623 		if (close(lock_fd))
624 			return (0);
625 		else
626 			return (1);
627 	} else
628 		return (1);
629 }
630 
631 /*
632  * This function verifies that the contents file is in place.
633  * returns 1 - if it exists
634  * returns 0 - if it does not exist
635  */
636 int
637 iscfile(void)
638 {
639 	char	contents[PATH_MAX];
640 
641 	(void) snprintf(contents, PATH_MAX, "%s/contents", get_PKGADM());
642 
643 	return (access(contents, F_OK) == 0 ? 1 : 0);
644 }
645 
646 /*
647  * This function verifies that the contents file is in place. If it is - no
648  * change. If it isn't - this creates it.
649  * Returns:	== 0 : failure
650  *		!= 0 : success
651  */
652 
653 int
654 vcfile(void)
655 {
656 	int	lerrno;
657 	int	fd;
658 	char	contents[PATH_MAX];
659 
660 	/*
661 	 * create full path to contents file
662 	 */
663 
664 	(void) snprintf(contents, sizeof (contents),
665 			"%s/contents", get_PKGADM());
666 
667 	/*
668 	 * Attempt to create the file - will only be successful
669 	 * if the file does not currently exist.
670 	 */
671 
672 	fd = open(contents, O_WRONLY | O_CREAT | O_EXCL, 0644);
673 	if (fd >= 0) {
674 		/*
675 		 * Contents file wasn't there, but is now.
676 		 */
677 
678 		echo(gettext("## Software contents file initialized"));
679 		(void) close(fd);
680 		return (1);	/* success */
681 	}
682 
683 	/*
684 	 * Could not create the file - it may exist or there may be
685 	 * permissions issues - find out and act accordingly.
686 	 */
687 
688 	lerrno = errno;
689 
690 	/* success if error is 'file exists' */
691 
692 	if (lerrno == EEXIST) {
693 		return (1);	/* success */
694 	}
695 
696 	/* success if error is 'permission denied' but file exists */
697 
698 	if (lerrno == EACCES) {
699 		/*
700 		 * Because O_CREAT and O_EXCL are specified in open(),
701 		 * if the contents file already exists, the open will
702 		 * fail with EACCES - determine if this is the case -
703 		 * if so return success.
704 		 */
705 
706 		if (access(contents, F_OK) == 0) {
707 			return (1);	/* success */
708 		}
709 
710 		/*
711 		 * access() failed - if because of permissions failure this
712 		 * means the contents file exists but it cannot be accessed
713 		 * or the path to the contents file cannot be accessed - in
714 		 * either case the contents file cannot be accessed.
715 		 */
716 
717 		if (errno == EACCES) {
718 			progerr(gettext(ERR_ACCESS_CONT), contents,
719 					strerror(lerrno));
720 			logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
721 			return (0);	/* failure */
722 		}
723 	}
724 
725 	/*
726 	 * the contents file does not exist and it cannot be created.
727 	 */
728 
729 	progerr(gettext(ERR_CREAT_CONT), contents, strerror(lerrno));
730 	logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
731 	return (0);	/* failure */
732 }
733