1163953Srrs/*-
2169382Srrs * Copyright (c) 2007 Dag-Erling Sm��rgrav
3163953Srrs * All rights reserved.
4163953Srrs *
5163953Srrs * Redistribution and use in source and binary forms, with or without
6163953Srrs * modification, are permitted provided that the following conditions
7163953Srrs * are met:
8163953Srrs * 1. Redistributions of source code must retain the above copyright
9163953Srrs *    notice, this list of conditions and the following disclaimer
10163953Srrs *    in this position and unchanged.
11163953Srrs * 2. Redistributions in binary form must reproduce the above copyright
12163953Srrs *    notice, this list of conditions and the following disclaimer in the
13163953Srrs *    documentation and/or other materials provided with the distribution.
14163953Srrs *
15163953Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16163953Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17163953Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18163953Srrs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19163953Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20163953Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21163953Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22163953Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23163953Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24163953Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25163953Srrs * SUCH DAMAGE.
26163953Srrs *
27163953Srrs * Derived from FreeBSD head/lib/libutil/flopen.c r193591
28163953Srrs */
29163953Srrs
30163953Srrs#include <sys/file.h>
31163953Srrs#include <sys/stat.h>
32163953Srrs
33163953Srrs#include <errno.h>
34163953Srrs#include <stdarg.h>
35163953Srrs#include <unistd.h>
36163953Srrs
37163953Srrsstatic int
38167598Srrsflopen(const char *path, int flags, ...)
39163953Srrs{
40163953Srrs	int fd, operation, serrno, trunc;
41163953Srrs	struct stat sb, fsb;
42163953Srrs	mode_t mode;
43163953Srrs
44163953Srrs#ifdef O_EXLOCK
45163953Srrs	flags &= ~O_EXLOCK;
46163953Srrs#endif
47170091Srrs
48163953Srrs	mode = 0;
49163953Srrs	if (flags & O_CREAT) {
50163953Srrs		va_list ap;
51163953Srrs
52163953Srrs		va_start(ap, flags);
53163953Srrs		mode = (mode_t)va_arg(ap, int); /* mode_t promoted to int */
54163953Srrs		va_end(ap);
55163953Srrs	}
56165220Srrs
57165220Srrs        operation = LOCK_EX;
58165220Srrs        if (flags & O_NONBLOCK)
59165220Srrs                operation |= LOCK_NB;
60165220Srrs
61163953Srrs	trunc = (flags & O_TRUNC);
62163953Srrs	flags &= ~O_TRUNC;
63165220Srrs
64163953Srrs	for (;;) {
65163953Srrs		if ((fd = open(path, flags, mode)) == -1)
66163953Srrs			/* non-existent or no access */
67165220Srrs			return (-1);
68165220Srrs		if (flock(fd, operation) == -1) {
69165220Srrs			/* unsupported or interrupted */
70165220Srrs			serrno = errno;
71165220Srrs			(void)close(fd);
72165220Srrs			errno = serrno;
73163953Srrs			return (-1);
74163953Srrs		}
75163953Srrs		if (stat(path, &sb) == -1) {
76163953Srrs			/* disappeared from under our feet */
77163953Srrs			(void)close(fd);
78163953Srrs			continue;
79163953Srrs		}
80163953Srrs		if (fstat(fd, &fsb) == -1) {
81169352Srrs			/* can't happen [tm] */
82169352Srrs			serrno = errno;
83163953Srrs			(void)close(fd);
84163953Srrs			errno = serrno;
85163953Srrs			return (-1);
86163953Srrs		}
87163953Srrs		if (sb.st_dev != fsb.st_dev ||
88169420Srrs		    sb.st_ino != fsb.st_ino) {
89169420Srrs			/* changed under our feet */
90163953Srrs			(void)close(fd);
91163953Srrs			continue;
92163953Srrs		}
93163953Srrs		if (trunc && ftruncate(fd, 0) != 0) {
94169420Srrs			/* can't happen [tm] */
95169420Srrs			serrno = errno;
96169420Srrs			(void)close(fd);
97163953Srrs			errno = serrno;
98163953Srrs			return (-1);
99163953Srrs		}
100163953Srrs		return (fd);
101169352Srrs	}
102169352Srrs}
103168299Srrs