Commit 98a2479f0ba02a0c54ff360aa5745ff5a6939b2e

Guillem Jover 2010-01-09T23:49:32

Add flopen function Taken from FreeBSD.

diff --git a/Makefile b/Makefile
index 2d51ba1..be8314b 100644
--- a/Makefile
+++ b/Makefile
@@ -25,6 +25,7 @@ LIB_SRCS := \
 	bsd_getopt.c \
 	err.c \
 	fgetln.c \
+	flopen.c \
 	heapsort.c \
 	humanize_number.c \
 	dehumanize_number.c \
@@ -76,6 +77,7 @@ LIB_MANS := \
 	strlcpy.3 \
 	strlcat.3 \
 	fgetln.3 \
+	flopen.3 \
 	readpassphrase.3 \
 	humanize_number.3 \
 	fmtcheck.3 \
diff --git a/Versions b/Versions
index 24548ca..7b092da 100644
--- a/Versions
+++ b/Versions
@@ -51,5 +51,7 @@ LIBBSD_0.2 {
     dehumanize_number;
 
     readpassphrase;
+
+    flopen;
 } LIBBSD_0.1;
 
diff --git a/include/libutil.h b/include/libutil.h
index 5f72f8c..298bbc3 100644
--- a/include/libutil.h
+++ b/include/libutil.h
@@ -46,6 +46,8 @@
 __BEGIN_DECLS
 int humanize_number(char *buf, size_t len, int64_t bytes,
     const char *suffix, int scale, int flags);
+
+int flopen(const char *_path, int _flags, ...);
 __END_DECLS
 
 /* humanize_number(3) */
diff --git a/src/flopen.3 b/src/flopen.3
new file mode 100644
index 0000000..4c53d46
--- /dev/null
+++ b/src/flopen.3
@@ -0,0 +1,102 @@
+.\"-
+.\" Copyright (c) 2007 Dag-Erling Coïdan Smørgrav
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 6, 2009
+.Dt FLOPEN 3
+.Os
+.Sh NAME
+.Nm flopen
+.Nd "Reliably open and lock a file"
+.Sh LIBRARY
+.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
+.Lb libbsd
+.Sh SYNOPSIS
+.In sys/fcntl.h
+.In libutil.h
+.Ft int
+.Fn flopen "const char *path" "int flags"
+.Ft int
+.Fn flopen "const char *path" "int flags" "mode_t mode"
+.Sh DESCRIPTION
+The
+.Fn flopen
+function opens or creates a file and acquires an exclusive lock on it.
+It is essentially equivalent with calling
+.Fn open
+with the same parameters followed by
+.Fn flock
+with an
+.Va operation
+argument of
+.Dv LOCK_EX ,
+except that
+.Fn flopen
+will attempt to detect and handle races that may occur between opening
+/ creating the file and locking it.
+Thus, it is well suited for opening lock files, PID files, spool
+files, mailboxes and other kinds of files which are used for
+synchronization between processes.
+.Pp
+If
+.Va flags
+includes
+.Dv O_NONBLOCK
+and the file is already locked,
+.Fn flopen
+will fail and set
+.Va errno
+to
+.Dv EWOULDBLOCK .
+.Pp
+As with
+.Fn open ,
+the additional
+.Va mode
+argument is required if
+.Va flags
+includes
+.Dv O_CREAT .
+.Sh RETURN VALUES
+If successful,
+.Fn flopen
+returns a valid file descriptor.
+Otherwise, it returns -1, and sets
+.Va errno
+as described in
+.Xr flock 2
+and
+.Xr open 2 .
+.Sh SEE ALSO
+.Xr errno 2 ,
+.Xr flock 2 ,
+.Xr open 2
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+function and this manual page were written by
+.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org .
diff --git a/src/flopen.c b/src/flopen.c
new file mode 100644
index 0000000..754c9c0
--- /dev/null
+++ b/src/flopen.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 2007 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+int
+flopen(const char *path, int flags, ...)
+{
+	int fd, operation, serrno, trunc;
+	struct stat sb, fsb;
+	mode_t mode;
+
+#ifdef O_EXLOCK
+	flags &= ~O_EXLOCK;
+#endif
+
+	mode = 0;
+	if (flags & O_CREAT) {
+		va_list ap;
+
+		va_start(ap, flags);
+		mode = (mode_t)va_arg(ap, int); /* mode_t promoted to int */
+		va_end(ap);
+	}
+
+        operation = LOCK_EX;
+        if (flags & O_NONBLOCK)
+                operation |= LOCK_NB;
+
+	trunc = (flags & O_TRUNC);
+	flags &= ~O_TRUNC;
+
+	for (;;) {
+		if ((fd = open(path, flags, mode)) == -1)
+			/* non-existent or no access */
+			return (-1);
+		if (flock(fd, operation) == -1) {
+			/* unsupported or interrupted */
+			serrno = errno;
+			(void)close(fd);
+			errno = serrno;
+			return (-1);
+		}
+		if (stat(path, &sb) == -1) {
+			/* disappeared from under our feet */
+			(void)close(fd);
+			continue;
+		}
+		if (fstat(fd, &fsb) == -1) {
+			/* can't happen [tm] */
+			serrno = errno;
+			(void)close(fd);
+			errno = serrno;
+			return (-1);
+		}
+		if (sb.st_dev != fsb.st_dev ||
+		    sb.st_ino != fsb.st_ino) {
+			/* changed under our feet */
+			(void)close(fd);
+			continue;
+		}
+		if (trunc && ftruncate(fd, 0) != 0) {
+			/* can't happen [tm] */
+			serrno = errno;
+			(void)close(fd);
+			errno = serrno;
+			return (-1);
+		}
+		return (fd);
+	}
+}