196670552SDag-Erling Smørgrav /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni *
4*e738085bSDag-Erling Smørgrav * Copyright (c) 2007-2009 Dag-Erling Smørgrav
596670552SDag-Erling Smørgrav * All rights reserved.
696670552SDag-Erling Smørgrav *
796670552SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without
896670552SDag-Erling Smørgrav * modification, are permitted provided that the following conditions
996670552SDag-Erling Smørgrav * are met:
1096670552SDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright
1196670552SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer
1296670552SDag-Erling Smørgrav * in this position and unchanged.
1396670552SDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright
1496670552SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the
1596670552SDag-Erling Smørgrav * documentation and/or other materials provided with the distribution.
1696670552SDag-Erling Smørgrav *
1796670552SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1896670552SDag-Erling Smørgrav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1996670552SDag-Erling Smørgrav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2096670552SDag-Erling Smørgrav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2196670552SDag-Erling Smørgrav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2296670552SDag-Erling Smørgrav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2396670552SDag-Erling Smørgrav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2496670552SDag-Erling Smørgrav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2596670552SDag-Erling Smørgrav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2696670552SDag-Erling Smørgrav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2796670552SDag-Erling Smørgrav * SUCH DAMAGE.
2896670552SDag-Erling Smørgrav */
2996670552SDag-Erling Smørgrav
3096670552SDag-Erling Smørgrav #include <sys/cdefs.h>
315649afd0SDag-Erling Smørgrav #include <sys/file.h>
3296670552SDag-Erling Smørgrav #include <sys/stat.h>
3396670552SDag-Erling Smørgrav
3496670552SDag-Erling Smørgrav #include <errno.h>
3596670552SDag-Erling Smørgrav #include <stdarg.h>
368f908538SDag-Erling Smørgrav #include <unistd.h>
378f908538SDag-Erling Smørgrav
388f908538SDag-Erling Smørgrav #include <libutil.h>
3996670552SDag-Erling Smørgrav
404e282554SDag-Erling Smørgrav /*
414e282554SDag-Erling Smørgrav * Reliably open and lock a file.
424e282554SDag-Erling Smørgrav *
4333d19692SConrad Meyer * Please do not modify this code without first reading the revision history
4433d19692SConrad Meyer * and discussing your changes with <des@freebsd.org>. Don't be fooled by the
4533d19692SConrad Meyer * code's apparent simplicity; there would be no need for this function if it
4633d19692SConrad Meyer * was easy to get right.
474e282554SDag-Erling Smørgrav */
4873979478SMariusz Zaborski static int
vflopenat(int dirfd,const char * path,int flags,va_list ap)4973979478SMariusz Zaborski vflopenat(int dirfd, const char *path, int flags, va_list ap)
5096670552SDag-Erling Smørgrav {
514b5b992bSDag-Erling Smørgrav int fd, operation, serrno, trunc;
5296670552SDag-Erling Smørgrav struct stat sb, fsb;
5396670552SDag-Erling Smørgrav mode_t mode;
5496670552SDag-Erling Smørgrav
5596670552SDag-Erling Smørgrav #ifdef O_EXLOCK
5696670552SDag-Erling Smørgrav flags &= ~O_EXLOCK;
5796670552SDag-Erling Smørgrav #endif
5896670552SDag-Erling Smørgrav
593dea5934SDag-Erling Smørgrav mode = 0;
6096670552SDag-Erling Smørgrav if (flags & O_CREAT) {
610e25c55aSDag-Erling Smørgrav mode = (mode_t)va_arg(ap, int); /* mode_t promoted to int */
6296670552SDag-Erling Smørgrav }
6396670552SDag-Erling Smørgrav
645649afd0SDag-Erling Smørgrav operation = LOCK_EX;
655649afd0SDag-Erling Smørgrav if (flags & O_NONBLOCK)
665649afd0SDag-Erling Smørgrav operation |= LOCK_NB;
673dea5934SDag-Erling Smørgrav
684b5b992bSDag-Erling Smørgrav trunc = (flags & O_TRUNC);
69400f7729SDag-Erling Smørgrav flags &= ~O_TRUNC;
70d75d5606SDag-Erling Smørgrav
7196670552SDag-Erling Smørgrav for (;;) {
7273979478SMariusz Zaborski if ((fd = openat(dirfd, path, flags, mode)) == -1)
7396670552SDag-Erling Smørgrav /* non-existent or no access */
7496670552SDag-Erling Smørgrav return (-1);
755649afd0SDag-Erling Smørgrav if (flock(fd, operation) == -1) {
7696670552SDag-Erling Smørgrav /* unsupported or interrupted */
7796670552SDag-Erling Smørgrav serrno = errno;
780e25c55aSDag-Erling Smørgrav (void)close(fd);
7996670552SDag-Erling Smørgrav errno = serrno;
8096670552SDag-Erling Smørgrav return (-1);
8196670552SDag-Erling Smørgrav }
8273979478SMariusz Zaborski if (fstatat(dirfd, path, &sb, 0) == -1) {
8396670552SDag-Erling Smørgrav /* disappeared from under our feet */
840e25c55aSDag-Erling Smørgrav (void)close(fd);
8596670552SDag-Erling Smørgrav continue;
8696670552SDag-Erling Smørgrav }
8796670552SDag-Erling Smørgrav if (fstat(fd, &fsb) == -1) {
8896670552SDag-Erling Smørgrav /* can't happen [tm] */
8996670552SDag-Erling Smørgrav serrno = errno;
900e25c55aSDag-Erling Smørgrav (void)close(fd);
9196670552SDag-Erling Smørgrav errno = serrno;
9296670552SDag-Erling Smørgrav return (-1);
9396670552SDag-Erling Smørgrav }
9496670552SDag-Erling Smørgrav if (sb.st_dev != fsb.st_dev ||
9596670552SDag-Erling Smørgrav sb.st_ino != fsb.st_ino) {
9696670552SDag-Erling Smørgrav /* changed under our feet */
970e25c55aSDag-Erling Smørgrav (void)close(fd);
9896670552SDag-Erling Smørgrav continue;
9996670552SDag-Erling Smørgrav }
1004b5b992bSDag-Erling Smørgrav if (trunc && ftruncate(fd, 0) != 0) {
101d75d5606SDag-Erling Smørgrav /* can't happen [tm] */
102d75d5606SDag-Erling Smørgrav serrno = errno;
1030e25c55aSDag-Erling Smørgrav (void)close(fd);
104d75d5606SDag-Erling Smørgrav errno = serrno;
105d75d5606SDag-Erling Smørgrav return (-1);
106d75d5606SDag-Erling Smørgrav }
10733d19692SConrad Meyer /*
10833d19692SConrad Meyer * The following change is provided as a specific example to
10933d19692SConrad Meyer * avoid.
11033d19692SConrad Meyer */
11133d19692SConrad Meyer #if 0
1124e282554SDag-Erling Smørgrav if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
1134e282554SDag-Erling Smørgrav serrno = errno;
1144e282554SDag-Erling Smørgrav (void)close(fd);
1154e282554SDag-Erling Smørgrav errno = serrno;
1164e282554SDag-Erling Smørgrav return (-1);
1174e282554SDag-Erling Smørgrav }
1184e282554SDag-Erling Smørgrav #endif
11996670552SDag-Erling Smørgrav return (fd);
12096670552SDag-Erling Smørgrav }
12196670552SDag-Erling Smørgrav }
12273979478SMariusz Zaborski
12373979478SMariusz Zaborski int
flopen(const char * path,int flags,...)12473979478SMariusz Zaborski flopen(const char *path, int flags, ...)
12573979478SMariusz Zaborski {
12673979478SMariusz Zaborski va_list ap;
12773979478SMariusz Zaborski int ret;
12873979478SMariusz Zaborski
12973979478SMariusz Zaborski va_start(ap, flags);
13073979478SMariusz Zaborski ret = vflopenat(AT_FDCWD, path, flags, ap);
13173979478SMariusz Zaborski va_end(ap);
13273979478SMariusz Zaborski return (ret);
13373979478SMariusz Zaborski }
13473979478SMariusz Zaborski
13573979478SMariusz Zaborski int
flopenat(int dirfd,const char * path,int flags,...)13673979478SMariusz Zaborski flopenat(int dirfd, const char *path, int flags, ...)
13773979478SMariusz Zaborski {
13873979478SMariusz Zaborski va_list ap;
13973979478SMariusz Zaborski int ret;
14073979478SMariusz Zaborski
14173979478SMariusz Zaborski va_start(ap, flags);
14273979478SMariusz Zaborski ret = vflopenat(dirfd, path, flags, ap);
14373979478SMariusz Zaborski va_end(ap);
14473979478SMariusz Zaborski return (ret);
14573979478SMariusz Zaborski }
146