varnish-cache/lib/libvarnish/vfil.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2011 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Dag-Erling Smørgrav <des@des.no>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 */
30
31
#include "config.h"
32
33
#include <time.h>
34
#include <sys/types.h>
35
#include <sys/stat.h>
36
#include <fcntl.h>
37
#include <limits.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <unistd.h>
41
#include <stdint.h>
42
#include <string.h>
43
#ifdef HAVE_SYS_MOUNT_H
44
#  include <sys/param.h>
45
#  include <sys/mount.h>
46
#endif
47
#ifdef HAVE_SYS_STATVFS_H
48
#  include <sys/statvfs.h>
49
#endif
50
#ifdef HAVE_SYS_VFS_H
51
#  include <sys/vfs.h>
52
#endif
53
#ifdef HAVE_FALLOCATE
54
#  include <linux/magic.h>
55
#endif
56
57
#include "vdef.h"
58
59
#include "miniobj.h"
60
#include "vas.h"
61
#include "vsb.h"
62
#include "vfil.h"
63
#include "vqueue.h"
64
65
void
66 390707
VFIL_null_fd(int target)
67
{
68
        int fd;
69
70 390707
        assert(target >= 0);
71 390707
        fd = open("/dev/null", O_RDWR);
72 390707
        assert(fd >= 0);
73 390707
        assert(dup2(fd, target) == target);
74 390707
        closefd(&fd);
75 390707
}
76
77
static char *
78 85708
vfil_readfd(int fd, ssize_t *sz)
79
{
80
        struct stat st;
81
        char *f;
82
        int i;
83
84 85708
        AZ(fstat(fd, &st));
85 85708
        if (!S_ISREG(st.st_mode))
86 0
                return (NULL);
87 85708
        f = malloc(st.st_size + 1);
88 85708
        assert(f != NULL);
89 85708
        i = read(fd, f, st.st_size + 1);
90 85708
        if (i != st.st_size) {
91 0
                free(f);
92 0
                return (NULL);
93
        }
94 85708
        f[i] = '\0';
95 85708
        if (sz != NULL)
96 308
                *sz = st.st_size;
97 85708
        return (f);
98 85708
}
99
100
static int
101 336
vfil_writefd(int fd, const char *buf, size_t sz)
102
{
103
        ssize_t len;
104
105 672
        while (sz > 0) {
106 336
                len = write(fd, buf, sz);
107 336
                if (len < 0)
108 0
                        return (len);
109 336
                if (len == 0)
110 0
                        break;
111 336
                buf += len;
112 336
                sz -= len;
113
        }
114
115 336
        return (sz == 0 ? 0 : -1);
116 336
}
117
118
static int
119 86268
vfil_openfile(const char *pfx, const char *fn, int flags, int mode)
120
{
121
        char fnb[PATH_MAX + 1];
122
123 86268
        if (fn[0] != '/' && pfx != NULL) {
124
                /* XXX: graceful length check */
125 0
                bprintf(fnb, "/%s/%s", pfx, fn);
126 0
                fn = fnb;
127 0
        }
128
129 86268
        if (flags & O_CREAT)
130 336
                return (open(fn, flags, mode));
131
        else
132 85932
                return (open(fn, flags));
133 86268
}
134
135
char *
136 85932
VFIL_readfile(const char *pfx, const char *fn, ssize_t *sz)
137
{
138
        int fd, err;
139
        char *r;
140
141 85932
        fd = vfil_openfile(pfx, fn, O_RDONLY, 0);
142 85932
        if (fd < 0)
143 224
                return (NULL);
144 85708
        r = vfil_readfd(fd, sz);
145 85708
        err = errno;
146 85708
        closefd(&fd);
147 85708
        errno = err;
148 85708
        return (r);
149 85932
}
150
151
int
152 336
VFIL_writefile(const char *pfx, const char *fn, const char *buf, size_t sz)
153
{
154
        int fd, err;
155
        int r;
156
157 336
        fd = vfil_openfile(pfx, fn, O_WRONLY|O_CREAT|O_TRUNC, 0660);
158 336
        if (fd < 0)
159 0
                return (fd);
160 336
        r = vfil_writefd(fd, buf, sz);
161 336
        err = errno;
162 336
        closefd(&fd);
163 336
        errno = err;
164 336
        return (r);
165 336
}
166
167
int
168 0
VFIL_nonblocking(int fd)
169
{
170
        int i;
171
172 0
        i = fcntl(fd, F_GETFL);
173 0
        assert(i != -1);
174 0
        i |= O_NONBLOCK;
175 0
        i = fcntl(fd, F_SETFL, i);
176 0
        assert(i != -1);
177 0
        return (i);
178
}
179
180
/*
181
 * Get file system information from an fd
182
 * Returns block size, total size and space available in the passed pointers
183
 * Returns 0 on success, or -1 on failure with errno set
184
 */
185
int
186 1057449
VFIL_fsinfo(int fd, unsigned *pbs, uintmax_t *psize, uintmax_t *pspace)
187
{
188
        unsigned bs;
189
        uintmax_t size, space;
190
#if defined(HAVE_SYS_STATVFS_H)
191
        struct statvfs fsst;
192
193 1057449
        if (fstatvfs(fd, &fsst))
194 0
                return (-1);
195 1057449
        bs = fsst.f_frsize;
196 1057449
        size = fsst.f_blocks * fsst.f_frsize;
197 1057449
        space = fsst.f_bavail * fsst.f_frsize;
198
#elif defined(HAVE_SYS_MOUNT_H) || defined(HAVE_SYS_VFS_H)
199
        struct statfs fsst;
200
201
        if (fstatfs(fd, &fsst))
202
                return (-1);
203
        bs = fsst.f_bsize;
204
        size = fsst.f_blocks * fsst.f_bsize;
205
        space = fsst.f_bavail * fsst.f_bsize;
206
#else
207
#error no struct statfs / struct statvfs
208
#endif
209
210 1057449
        if (pbs)
211 1148
                *pbs = bs;
212 1057449
        if (psize)
213 1148
                *psize = size;
214 1057449
        if (pspace)
215 1056301
                *pspace = space;
216 1057449
        return (0);
217 1057449
}
218
219
/*
220
 * Make sure that the file system can accommodate the file of the given
221
 * size. Will use fallocate if available. If fallocate is not available
222
 * and insist is true, it will write size zero bytes.
223
 *
224
 * Returns 0 on success, -1 on failure with errno set.
225
 */
226
227
int
228 1056301
VFIL_allocate(int fd, uintmax_t size, int insist)
229
{
230
        struct stat st;
231
        uintmax_t fsspace;
232
        size_t l;
233
        ssize_t l2, l3;
234
        char *buf;
235
        ssize_t bufsiz;
236 1056301
        int retval = 0;
237
238 1056301
        if (ftruncate(fd, size))
239 0
                return (-1);
240 1056301
        if (fstat(fd, &st))
241 0
                return (-1);
242 1056301
        if (VFIL_fsinfo(fd, NULL, NULL, &fsspace))
243 0
                return (-1);
244 1056301
        if ((st.st_blocks * 512) + fsspace < size) {
245
                /* Sum of currently allocated blocks and available space
246
                   is less than requested size */
247 0
                errno = ENOSPC;
248 0
                return (-1);
249
        }
250
#if defined(__linux__) && defined(HAVE_FALLOCATE)
251
        {
252
                /* fallocate will for some filesystems (e.g. xfs) not take
253
                   the already allocated blocks of the file into
254
                   account. This will cause fallocate to report ENOSPC
255
                   when called on an existing fully allocated file unless
256
                   the filesystem has enough free space to accommodate the
257
                   complete new file size. Because of this we enable
258
                   fallocate only on filesystems that are known to work as
259
                   we expect. */
260
                struct statfs stfs;
261
                if (!fstatfs(fd, &stfs) && stfs.f_type == EXT4_SUPER_MAGIC) {
262
                        if (!fallocate(fd, 0, 0, size))
263
                                return (0);
264
                        if (errno == ENOSPC)
265
                                return (-1);
266
                }
267
        }
268
#endif
269 1056301
        if (!insist)
270 84
                return (0);
271
272
        /* Write size zero bytes to make sure the entire file is allocated
273
           in the file system */
274 1056217
        if (size > 65536)
275 23769
                bufsiz = 64 * 1024;
276
        else
277 1032448
                bufsiz = size;
278 1056217
        buf = calloc(1, bufsiz);
279 1056217
        AN(buf);
280 1056217
        assert(lseek(fd, 0, SEEK_SET) == 0);
281 2849273
        for (l = 0; l < size; l += l2) {
282 1793056
                l2 = bufsiz;
283 1793056
                if (l + l2 > size)
284 0
                        l2 = size - l;
285 1793056
                l3 = write(fd, buf, l2);
286 1793056
                if (l3 != l2) {
287 0
                        retval = -1;
288 0
                        break;
289
                }
290 1793056
        }
291 1056217
        assert(lseek(fd, 0, SEEK_SET) == 0);
292 1056217
        free(buf);
293 1056217
        return (retval);
294 1056301
}
295
296
struct vfil_dir {
297
        unsigned                magic;
298
#define VFIL_DIR_MAGIC          0x3e214967
299
        char                    *dir;
300
        VTAILQ_ENTRY(vfil_dir)  list;
301
};
302
303
struct vfil_path {
304
        unsigned                magic;
305
#define VFIL_PATH_MAGIC         0x92dbcc31
306
        char                    *str;
307
        VTAILQ_HEAD(,vfil_dir)  paths;
308
};
309
310
/*
311
 * Path searching functions
312
 */
313
314
void
315 78428
VFIL_setpath(struct vfil_path **pp, const char *path)
316
{
317
        struct vfil_path *vp;
318
        struct vfil_dir *vd;
319
        char *p, *q;
320
321 78428
        AN(pp);
322 78428
        AN(path);
323
324 78428
        vp = *pp;
325 78428
        if (vp == NULL) {
326 78316
                ALLOC_OBJ(vp, VFIL_PATH_MAGIC);
327 78316
                AN(vp);
328 78316
                VTAILQ_INIT(&vp->paths);
329 78316
                *pp = vp;
330 78316
        }
331 78428
        REPLACE(vp->str, path);
332 78652
        while (!VTAILQ_EMPTY(&vp->paths)) {
333 224
                vd = VTAILQ_FIRST(&vp->paths);
334 224
                CHECK_OBJ_NOTNULL(vd, VFIL_DIR_MAGIC);
335 224
                VTAILQ_REMOVE(&vp->paths, vd, list);
336 224
                FREE_OBJ(vd);
337
        }
338 195804
        for (p = vp->str; p != NULL; p = q) {
339 117376
                q = strchr(p, ':');
340 117376
                if (q != NULL)
341 38948
                        *q++ = '\0';
342 117376
                ALLOC_OBJ(vd, VFIL_DIR_MAGIC);
343 117376
                AN(vd);
344 117376
                vd->dir = p;
345 117376
                VTAILQ_INSERT_TAIL(&vp->paths, vd, list);
346 117376
        }
347 78428
}
348
349
static int
350 1736
vfil_path_openfile(void *priv, const char *fn)
351
{
352
        char *p, **pp;
353
354 1736
        AN(priv);
355 1736
        AN(fn);
356 1736
        p = VFIL_readfile(NULL, fn, NULL);
357 1736
        if (p == NULL)
358 56
                return (1);
359
360 1680
        pp = priv;
361 1680
        *pp = p;
362 1680
        return (0);
363 1736
}
364
365
int
366 16772
VFIL_searchpath(const struct vfil_path *vp, vfil_path_func_f *func, void *priv,
367
    const char *fni, char **fno)
368
{
369
        struct vsb *vsb;
370
        struct vfil_dir *vd;
371
        int i, e;
372
373 16772
        CHECK_OBJ_NOTNULL(vp, VFIL_PATH_MAGIC);
374 16772
        AN(fno);
375 16772
        *fno = NULL;
376
377 16772
        if (func == NULL) {
378 1792
                func = vfil_path_openfile;
379 1792
                AN(priv);
380 1792
        }
381
382 16772
        if (*fni == '/') {
383 1428
                i = func(priv, fni);
384 1428
                if (i <= 0)
385 1372
                        REPLACE(*fno, fni);
386 1428
                return (i);
387
        }
388 15344
        vsb = VSB_new_auto();
389 15344
        AN(vsb);
390 15512
        VTAILQ_FOREACH(vd, &vp->paths, list) {
391 15428
                VSB_clear(vsb);
392 15428
                VSB_printf(vsb, "%s/%s", vd->dir, fni);
393 15428
                AZ(VSB_finish(vsb));
394 15428
                if (access(VSB_data(vsb), F_OK))
395 168
                        continue;
396 15260
                i = func(priv, VSB_data(vsb));
397 15260
                if (i <= 0) {
398 15260
                        e = errno;
399 15260
                        *fno = strdup(VSB_data(vsb));
400 15260
                        AN(*fno);
401 15260
                        VSB_destroy(&vsb);
402 15260
                        errno = e;
403 15260
                        return (i);
404
                }
405 0
        }
406 84
        VSB_destroy(&vsb);
407 84
        return (-1);
408 16772
}