xref: /freebsd/lib/libutil/flopen.c (revision 3dea5934000e33ef21d9784a9575a89f9a7f557b)
196670552SDag-Erling Smørgrav /*-
296670552SDag-Erling Smørgrav  * Copyright (c) 2007 Dag-Erling Co�dan Sm�rgrav
396670552SDag-Erling Smørgrav  * All rights reserved.
496670552SDag-Erling Smørgrav  *
596670552SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
696670552SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
796670552SDag-Erling Smørgrav  * are met:
896670552SDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
996670552SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer
1096670552SDag-Erling Smørgrav  *    in this position and unchanged.
1196670552SDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
1296670552SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
1396670552SDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
1496670552SDag-Erling Smørgrav  *
1596670552SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1696670552SDag-Erling Smørgrav  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1796670552SDag-Erling Smørgrav  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1896670552SDag-Erling Smørgrav  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1996670552SDag-Erling Smørgrav  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2096670552SDag-Erling Smørgrav  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2196670552SDag-Erling Smørgrav  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2296670552SDag-Erling Smørgrav  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2396670552SDag-Erling Smørgrav  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2496670552SDag-Erling Smørgrav  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2596670552SDag-Erling Smørgrav  * SUCH DAMAGE.
2696670552SDag-Erling Smørgrav  *
2796670552SDag-Erling Smørgrav  * $Id$
2896670552SDag-Erling Smørgrav  */
2996670552SDag-Erling Smørgrav 
3096670552SDag-Erling Smørgrav #include <sys/cdefs.h>
3196670552SDag-Erling Smørgrav __FBSDID("$FreeBSD$");
3296670552SDag-Erling Smørgrav 
3396670552SDag-Erling Smørgrav #include <sys/stat.h>
3496670552SDag-Erling Smørgrav 
3596670552SDag-Erling Smørgrav #include <errno.h>
3696670552SDag-Erling Smørgrav #include <fcntl.h>
3796670552SDag-Erling Smørgrav #include <stdarg.h>
3896670552SDag-Erling Smørgrav 
3996670552SDag-Erling Smørgrav int
4096670552SDag-Erling Smørgrav flopen(const char *path, int flags, ...)
4196670552SDag-Erling Smørgrav {
423dea5934SDag-Erling Smørgrav 	int fd, operation, serrno;
4396670552SDag-Erling Smørgrav 	struct stat sb, fsb;
4496670552SDag-Erling Smørgrav 	mode_t mode;
4596670552SDag-Erling Smørgrav 
4696670552SDag-Erling Smørgrav #ifdef O_EXLOCK
4796670552SDag-Erling Smørgrav 	flags &= ~O_EXLOCK;
4896670552SDag-Erling Smørgrav #endif
4996670552SDag-Erling Smørgrav 
503dea5934SDag-Erling Smørgrav 	mode = 0;
5196670552SDag-Erling Smørgrav 	if (flags & O_CREAT) {
5296670552SDag-Erling Smørgrav 		va_list ap;
5396670552SDag-Erling Smørgrav 
5496670552SDag-Erling Smørgrav 		va_start(ap, flags);
5596670552SDag-Erling Smørgrav 		mode = va_arg(ap, int); /* mode_t promoted to int */
5696670552SDag-Erling Smørgrav 		va_end(ap);
5796670552SDag-Erling Smørgrav 	}
5896670552SDag-Erling Smørgrav 
593dea5934SDag-Erling Smørgrav 	operation = LOCK_EX;
603dea5934SDag-Erling Smørgrav 	if (flags & O_NONBLOCK)
613dea5934SDag-Erling Smørgrav 		operation |= LOCK_NB;
623dea5934SDag-Erling Smørgrav 
6396670552SDag-Erling Smørgrav 	for (;;) {
6496670552SDag-Erling Smørgrav 		if ((fd = open(path, flags, mode)) == -1)
6596670552SDag-Erling Smørgrav 			/* non-existent or no access */
6696670552SDag-Erling Smørgrav 			return (-1);
673dea5934SDag-Erling Smørgrav 		if (flock(fd, operation) == -1) {
6896670552SDag-Erling Smørgrav 			/* unsupported or interrupted */
6996670552SDag-Erling Smørgrav 			serrno = errno;
7096670552SDag-Erling Smørgrav 			close(fd);
7196670552SDag-Erling Smørgrav 			errno = serrno;
7296670552SDag-Erling Smørgrav 			return (-1);
7396670552SDag-Erling Smørgrav 		}
7496670552SDag-Erling Smørgrav 		if (stat(path, &sb) == -1) {
7596670552SDag-Erling Smørgrav 			/* disappeared from under our feet */
7696670552SDag-Erling Smørgrav 			close(fd);
7796670552SDag-Erling Smørgrav 			continue;
7896670552SDag-Erling Smørgrav 		}
7996670552SDag-Erling Smørgrav 		if (fstat(fd, &fsb) == -1) {
8096670552SDag-Erling Smørgrav 			/* can't happen [tm] */
8196670552SDag-Erling Smørgrav 			serrno = errno;
8296670552SDag-Erling Smørgrav 			close(fd);
8396670552SDag-Erling Smørgrav 			errno = serrno;
8496670552SDag-Erling Smørgrav 			return (-1);
8596670552SDag-Erling Smørgrav 		}
8696670552SDag-Erling Smørgrav 		if (sb.st_dev != fsb.st_dev ||
8796670552SDag-Erling Smørgrav 		    sb.st_ino != fsb.st_ino) {
8896670552SDag-Erling Smørgrav 			/* changed under our feet */
8996670552SDag-Erling Smørgrav 			close(fd);
9096670552SDag-Erling Smørgrav 			continue;
9196670552SDag-Erling Smørgrav 		}
9296670552SDag-Erling Smørgrav 		return (fd);
9396670552SDag-Erling Smørgrav 	}
9496670552SDag-Erling Smørgrav }
95