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