varnish-cache/lib/libvarnish/vpf.c
1
/*-
2
 * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
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
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
25
 * Derived from:
26
 * $FreeBSD: head/lib/libutil/pidfile.c 184091 2008-10-20 17:41:08Z des $
27
 */
28
29
#include "config.h"
30
31
#include <sys/param.h>
32
#include <sys/file.h>
33
#include <sys/stat.h>
34
35
#include <errno.h>
36
#include <fcntl.h>
37
#include <stdint.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <unistd.h>
42
43
#include "vdef.h"
44
45
#include "vas.h"        // XXX Flexelint "not used" - but req'ed for assert()
46
#include "vfl.h"
47
#include "vpf.h"
48
49
struct vpf_fh {
50
        int     pf_fd;
51
        char    pf_path[MAXPATHLEN + 1];
52
        dev_t   pf_dev;
53
        ino_t   pf_ino;
54
};
55
56
static int _VPF_Remove(struct vpf_fh *pfh, int freeit);
57
58
static int
59 4984
vpf_verify(const struct vpf_fh *pfh)
60
{
61
        struct stat sb;
62
63 4984
        if (pfh == NULL || pfh->pf_fd == -1)
64 0
                return (EINVAL);
65
        /*
66
         * Check remembered descriptor.
67
         */
68 4984
        if (fstat(pfh->pf_fd, &sb) == -1)
69 0
                return (errno);
70 4984
        if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino)
71 0
                return (EINVAL);
72 4984
        return (0);
73
}
74
75
static int
76 4
vpf_read(const char *path, pid_t *pidptr)
77
{
78
        char buf[16], *endptr;
79
        int error, fd, i;
80
81 4
        fd = open(path, O_RDONLY | O_CLOEXEC);
82 4
        if (fd == -1)
83 0
                return (errno);
84
85 4
        i = read(fd, buf, sizeof(buf) - 1);
86 4
        error = errno;  /* Remember errno in case close() wants to change it. */
87 4
        (void)close(fd);
88 4
        if (i == -1)
89 0
                return (error);
90 4
        else if (i == 0)
91 0
                return (EAGAIN);
92 4
        buf[i] = '\0';
93
94 4
        *pidptr = strtol(buf, &endptr, 10);
95 4
        if (endptr != &buf[i])
96 0
                return (EINVAL);
97
98 4
        return (0);
99
}
100
101
struct vpf_fh *
102 2512
VPF_Open(const char *path, mode_t mode, pid_t *pidptr)
103
{
104
        struct vpf_fh *pfh;
105
        struct stat sb;
106
        int error, fd, len;
107
108 2512
        pfh = malloc(sizeof(*pfh));
109 2512
        if (pfh == NULL)
110 0
                return (NULL);
111
112 2512
        assert(path != NULL);
113 2512
        len = snprintf(pfh->pf_path, sizeof(pfh->pf_path),
114
            "%s", path);
115
116 2512
        if (len >= (int)sizeof(pfh->pf_path)) {
117 0
                free(pfh);
118 0
                errno = ENAMETOOLONG;
119 0
                return (NULL);
120
        }
121
122
        /*
123
         * Open the PID file and obtain exclusive lock.
124
         * We truncate PID file here only to remove old PID immediately,
125
         * PID file will be truncated again in VPF_Write(), so
126
         * VPF_Write() can be called multiple times.
127
         */
128 2512
        fd = VFL_Open(pfh->pf_path,
129
            O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode);
130 2512
        if (fd == -1) {
131 6
                if (errno == EWOULDBLOCK && pidptr != NULL) {
132 4
                        errno = vpf_read(pfh->pf_path, pidptr);
133 4
                        if (errno == 0)
134 4
                                errno = EEXIST;
135
                }
136 6
                free(pfh);
137 6
                return (NULL);
138
        }
139
140
        /*
141
         * Remember file information, so in VPF_Write() we are sure we write
142
         * to the proper descriptor.
143
         */
144 2506
        if (fstat(fd, &sb) == -1) {
145 0
                error = errno;
146 0
                (void)unlink(pfh->pf_path);
147 0
                (void)close(fd);
148 0
                free(pfh);
149 0
                errno = error;
150 0
                return (NULL);
151
        }
152
153 2506
        pfh->pf_fd = fd;
154 2506
        pfh->pf_dev = sb.st_dev;
155 2506
        pfh->pf_ino = sb.st_ino;
156
157 2506
        return (pfh);
158
}
159
160
int
161 2494
VPF_Write(struct vpf_fh *pfh)
162
{
163
        char pidstr[16];
164
        int error, fd;
165
166
        /*
167
         * Check remembered descriptor, so we don't overwrite some other
168
         * file if pidfile was closed and descriptor reused.
169
         */
170 2494
        errno = vpf_verify(pfh);
171 2494
        if (errno != 0) {
172
                /*
173
                 * Don't close descriptor, because we are not sure if it's ours.
174
                 */
175 0
                return (-1);
176
        }
177 2494
        fd = pfh->pf_fd;
178
179
        /*
180
         * Truncate PID file, so multiple calls of VPF_Write() are allowed.
181
         */
182 2494
        if (ftruncate(fd, 0) == -1) {
183 0
                error = errno;
184 0
                (void)_VPF_Remove(pfh, 0);
185 0
                errno = error;
186 0
                return (-1);
187
        }
188
189 2494
        error = snprintf(pidstr, sizeof(pidstr), "%jd", (intmax_t)getpid());
190 2494
        assert(error < sizeof pidstr);
191 2494
        if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) {
192 0
                error = errno;
193 0
                (void)_VPF_Remove(pfh, 0);
194 0
                errno = error;
195 0
                return (-1);
196
        }
197
198 2494
        return (0);
199
}
200
201
int
202 0
VPF_Close(struct vpf_fh *pfh)
203
{
204
        int error;
205
206 0
        error = vpf_verify(pfh);
207 0
        if (error != 0) {
208 0
                errno = error;
209 0
                return (-1);
210
        }
211
212 0
        if (close(pfh->pf_fd) == -1)
213 0
                error = errno;
214 0
        free(pfh);
215 0
        if (error != 0) {
216 0
                errno = error;
217 0
                return (-1);
218
        }
219 0
        return (0);
220
}
221
222
static int
223 2490
_VPF_Remove(struct vpf_fh *pfh, int freeit)
224
{
225
        int error;
226
227 2490
        error = vpf_verify(pfh);
228 2490
        if (error != 0) {
229 0
                errno = error;
230 0
                return (-1);
231
        }
232
233 2490
        if (unlink(pfh->pf_path) == -1)
234 0
                error = errno;
235 2490
        if (close(pfh->pf_fd) == -1) {
236 0
                if (error == 0)
237 0
                        error = errno;
238
        }
239 2490
        if (freeit)
240 2490
                free(pfh);
241
        else
242 0
                pfh->pf_fd = -1;
243 2490
        if (error != 0) {
244 0
                errno = error;
245 0
                return (-1);
246
        }
247 2490
        return (0);
248
}
249
250
int
251 2490
VPF_Remove(struct vpf_fh *pfh)
252
{
253
254 2490
        return (_VPF_Remove(pfh, 1));
255
}