varnish-cache/lib/libvarnish/vfl.c
1
/*-
2
 * Copyright (c) 2007-2009 Dag-Erling Coïdan Smørgrav
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer
10
 *    in this position and unchanged.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 *
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
 * SUCH DAMAGE.
26
 * Derived from:
27
 * $FreeBSD: head/lib/libutil/flopen.c 309344 2016-12-01 02:21:36Z cem $
28
 */
29
30
#include "config.h"
31
32
#include <sys/file.h>
33
#include <sys/stat.h>
34
35
#include <errno.h>
36
#include <fcntl.h>
37
#include <stdarg.h>
38
#include <string.h>
39
#include <unistd.h>
40
41
#include "vfl.h"
42
43
/*
44
 * Reliably open and lock a file.
45
 *
46
 * Please do not modify this code without first reading the revision history
47
 * and discussing your changes with <des@freebsd.org>.  Don't be fooled by the
48
 * code's apparent simplicity; there would be no need for this function if it
49
 * was easy to get right.
50
 */
51
int
52 2512
VFL_Open(const char *path, int flags, ...)
53
{
54
        int fd, operation, serrno, trunc;
55
        struct stat sb, fsb;
56
        mode_t mode;
57
58
#ifdef O_EXLOCK
59 2512
        flags &= ~O_EXLOCK;
60
#endif
61
62 2512
        mode = 0;
63 2512
        if (flags & O_CREAT) {
64
                va_list ap;
65
66 2512
                va_start(ap, flags);
67 2512
                mode = (mode_t)va_arg(ap, int); /* mode_t promoted to int */
68 2512
                va_end(ap);
69
        }
70
71 2512
        operation = LOCK_EX;
72 2512
        if (flags & O_NONBLOCK)
73 2512
                operation |= LOCK_NB;
74
75 2512
        trunc = (flags & O_TRUNC);
76 2512
        flags &= ~O_TRUNC;
77
78
        for (;;) {
79 2512
                if ((fd = open(path, flags, mode)) == -1)
80
                        /* non-existent or no access */
81 2
                        return (-1);
82 2510
                if (flock(fd, operation) == -1) {
83
                        /* unsupported or interrupted */
84 4
                        serrno = errno;
85 4
                        (void)close(fd);
86 4
                        errno = serrno;
87 4
                        return (-1);
88
                }
89 2506
                if (stat(path, &sb) == -1) {
90
                        /* disappeared from under our feet */
91 0
                        (void)close(fd);
92 0
                        continue;
93
                }
94 2506
                if (fstat(fd, &fsb) == -1) {
95
                        /* can't happen [tm] */
96 0
                        serrno = errno;
97 0
                        (void)close(fd);
98 0
                        errno = serrno;
99 0
                        return (-1);
100
                }
101 5012
                if (sb.st_dev != fsb.st_dev ||
102 2506
                    sb.st_ino != fsb.st_ino) {
103
                        /* changed under our feet */
104 0
                        (void)close(fd);
105 0
                        continue;
106
                }
107 2506
                if (trunc && ftruncate(fd, 0) != 0) {
108
                        /* can't happen [tm] */
109 0
                        serrno = errno;
110 0
                        (void)close(fd);
111 0
                        errno = serrno;
112 0
                        return (-1);
113
                }
114
                /*
115
                 * The following change is provided as a specific example to
116
                 * avoid.
117
                 */
118
#if 0
119
                if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
120
                        serrno = errno;
121
                        (void)close(fd);
122
                        errno = serrno;
123
                        return (-1);
124
                }
125
#endif
126 2506
                return (fd);
127 0
        }
128
}
129
130
/* Tests if the given fd is locked through flopen
131
 * If pid is non-NULL, stores the pid of the process holding the lock there
132
 * Returns 1 if the file is locked
133
 * Returns 0 if the file is unlocked
134
 * Returns -1 on error (and errno)
135
 */
136
int
137 0
VFL_Test(int fd, pid_t *pid)
138
{
139
        struct flock lock;
140
141 0
        memset(&lock, 0, sizeof lock);
142 0
        lock.l_type = F_WRLCK;
143 0
        lock.l_whence = SEEK_SET;
144
145 0
        if (fcntl(fd, F_GETLK, &lock) == -1)
146 0
                return (-1);
147 0
        if (lock.l_type == F_UNLCK)
148 0
                return (0);
149 0
        if (pid != NULL)
150 0
                *pid = lock.l_pid;
151 0
        return (1);
152
}