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
#include <sys/statvfs.h>
44
#if defined(__linux__) && defined(HAVE_FALLOCATE)
45
#  include <linux/magic.h>
46
#  include <sys/vfs.h>
47
#endif
48
49
#include "vdef.h"
50
51
#include "miniobj.h"
52
#include "vas.h"
53
#include "vsb.h"
54
#include "vfil.h"
55
#include "vqueue.h"
56
57
void
58 565841
VFIL_null_fd(int target)
59
{
60
        int fd;
61
62 565841
        assert(target >= 0);
63 565841
        fd = open("/dev/null", O_RDWR);
64 565841
        assert(fd >= 0);
65 565841
        assert(dup2(fd, target) == target);
66 565841
        closefd(&fd);
67 565841
}
68
69
static char *
70 232760
vfil_readfd(int fd, ssize_t *sz)
71
{
72
        struct stat st;
73
        char *f;
74
        int i;
75
76 232760
        AZ(fstat(fd, &st));
77 232760
        if (!S_ISREG(st.st_mode))
78 0
                return (NULL);
79 232760
        f = malloc(st.st_size + 1);
80 232760
        assert(f != NULL);
81 232760
        i = read(fd, f, st.st_size + 1);
82 232760
        if (i != st.st_size) {
83 0
                free(f);
84 0
                return (NULL);
85
        }
86 232760
        f[i] = '\0';
87 232760
        if (sz != NULL)
88 440
                *sz = st.st_size;
89 232760
        return (f);
90 232760
}
91
92
static int
93 560
vfil_writefd(int fd, const char *buf, size_t sz)
94
{
95
        ssize_t len;
96
97 1120
        while (sz > 0) {
98 560
                len = write(fd, buf, sz);
99 560
                if (len < 0)
100 0
                        return (len);
101 560
                if (len == 0)
102 0
                        break;
103 560
                buf += len;
104 560
                sz -= len;
105
        }
106
107 560
        return (sz == 0 ? 0 : -1);
108 560
}
109
110
static int
111 233640
vfil_openfile(const char *pfx, const char *fn, int flags, int mode)
112
{
113
        char fnb[PATH_MAX + 1];
114
115 233640
        if (fn[0] != '/' && pfx != NULL) {
116
                /* XXX: graceful length check */
117 0
                bprintf(fnb, "/%s/%s", pfx, fn);
118 0
                fn = fnb;
119 0
        }
120
121 233640
        if (flags & O_CREAT)
122 560
                return (open(fn, flags, mode));
123
        else
124 233080
                return (open(fn, flags));
125 233640
}
126
127
char *
128 233080
VFIL_readfile(const char *pfx, const char *fn, ssize_t *sz)
129
{
130
        int fd, err;
131
        char *r;
132
133 233080
        fd = vfil_openfile(pfx, fn, O_RDONLY, 0);
134 233080
        if (fd < 0)
135 320
                return (NULL);
136 232760
        r = vfil_readfd(fd, sz);
137 232760
        err = errno;
138 232760
        closefd(&fd);
139 232760
        errno = err;
140 232760
        return (r);
141 233080
}
142
143
int
144 560
VFIL_writefile(const char *pfx, const char *fn, const char *buf, size_t sz)
145
{
146
        int fd, err;
147
        int r;
148
149 560
        fd = vfil_openfile(pfx, fn, O_WRONLY|O_CREAT|O_TRUNC, 0660);
150 560
        if (fd < 0)
151 0
                return (fd);
152 560
        r = vfil_writefd(fd, buf, sz);
153 560
        err = errno;
154 560
        closefd(&fd);
155 560
        errno = err;
156 560
        return (r);
157 560
}
158
159
int
160 37600
VFIL_nonblocking(int fd)
161
{
162
        int i;
163
164 37600
        i = fcntl(fd, F_GETFL);
165 37600
        assert(i != -1);
166 37600
        i |= O_NONBLOCK;
167 37600
        i = fcntl(fd, F_SETFL, i);
168 37600
        assert(i != -1);
169 37600
        return (i);
170
}
171
172
/*
173
 * Get file system information from an fd
174
 * Returns block size, total size and space available in the passed pointers
175
 * Returns 0 on success, or -1 on failure with errno set
176
 */
177
int
178 1739628
VFIL_fsinfo(int fd, unsigned *pbs, uintmax_t *psize, uintmax_t *pspace)
179
{
180
        unsigned bs;
181
        uintmax_t size, space;
182
        struct statvfs fsst;
183
184 1739628
        if (fstatvfs(fd, &fsst))
185 0
                return (-1);
186 1739628
        bs = fsst.f_frsize;
187 1739628
        size = fsst.f_blocks * fsst.f_frsize;
188 1739628
        space = fsst.f_bavail * fsst.f_frsize;
189
190 1739628
        if (pbs)
191 1760
                *pbs = bs;
192 1739628
        if (psize)
193 1760
                *psize = size;
194 1739628
        if (pspace)
195 1737868
                *pspace = space;
196 1739628
        return (0);
197 1739628
}
198
199
/*
200
 * Make sure that the file system can accommodate the file of the given
201
 * size. Will use fallocate if available. If fallocate is not available
202
 * and insist is true, it will write size zero bytes.
203
 *
204
 * Returns 0 on success, -1 on failure with errno set.
205
 */
206
207
int
208 1737868
VFIL_allocate(int fd, uintmax_t size, int insist)
209
{
210
        struct stat st;
211
        uintmax_t fsspace;
212
        size_t l;
213
        ssize_t l2, l3;
214
        char *buf;
215
        ssize_t bufsiz;
216 1737868
        int retval = 0;
217
218 1737868
        if (ftruncate(fd, size))
219 0
                return (-1);
220 1737868
        if (fstat(fd, &st))
221 0
                return (-1);
222 1737868
        if (VFIL_fsinfo(fd, NULL, NULL, &fsspace))
223 0
                return (-1);
224 1737868
        if ((st.st_blocks * 512) + fsspace < size) {
225
                /* Sum of currently allocated blocks and available space
226
                   is less than requested size */
227 0
                errno = ENOSPC;
228 0
                return (-1);
229
        }
230
#if defined(__linux__) && defined(HAVE_FALLOCATE)
231
        {
232
                /* fallocate will for some filesystems (e.g. xfs) not take
233
                   the already allocated blocks of the file into
234
                   account. This will cause fallocate to report ENOSPC
235
                   when called on an existing fully allocated file unless
236
                   the filesystem has enough free space to accommodate the
237
                   complete new file size. Because of this we enable
238
                   fallocate only on filesystems that are known to work as
239
                   we expect. */
240
                struct statfs stfs;
241
                if (!fstatfs(fd, &stfs) && stfs.f_type == EXT4_SUPER_MAGIC) {
242
                        if (!fallocate(fd, 0, 0, size))
243
                                return (0);
244
                        if (errno == ENOSPC)
245
                                return (-1);
246
                }
247
        }
248
#endif
249 1737868
        if (!insist)
250 200
                return (0);
251
252
        /* Write size zero bytes to make sure the entire file is allocated
253
           in the file system */
254 1737668
        if (size > 65536)
255 36676
                bufsiz = 64 * 1024;
256
        else
257 1700992
                bufsiz = size;
258 1737668
        buf = calloc(1, bufsiz);
259 1737668
        AN(buf);
260 1737668
        assert(lseek(fd, 0, SEEK_SET) == 0);
261 4710884
        for (l = 0; l < size; l += l2) {
262 2973216
                l2 = bufsiz;
263 2973216
                if (l + l2 > size)
264 0
                        l2 = size - l;
265 2973216
                l3 = write(fd, buf, l2);
266 2973216
                if (l3 != l2) {
267 0
                        retval = -1;
268 0
                        break;
269
                }
270 2973216
        }
271 1737668
        assert(lseek(fd, 0, SEEK_SET) == 0);
272 1737668
        free(buf);
273 1737668
        return (retval);
274 1737868
}
275
276
struct vfil_dir {
277
        unsigned                magic;
278
#define VFIL_DIR_MAGIC          0x3e214967
279
        char                    *dir;
280
        VTAILQ_ENTRY(vfil_dir)  list;
281
};
282
283
struct vfil_path {
284
        unsigned                magic;
285
#define VFIL_PATH_MAGIC         0x92dbcc31
286
        char                    *str;
287
        VTAILQ_HEAD(,vfil_dir)  paths;
288
};
289
290
/*
291
 * Path searching functions
292
 */
293
294
void
295 120360
VFIL_setpath(struct vfil_path **pp, const char *path)
296
{
297
        struct vfil_path *vp;
298
        struct vfil_dir *vd;
299
        char *p, *q;
300
301 120360
        AN(pp);
302 120360
        AN(path);
303
304 120360
        vp = *pp;
305 120360
        if (vp == NULL) {
306 120200
                ALLOC_OBJ(vp, VFIL_PATH_MAGIC);
307 120200
                AN(vp);
308 120200
                VTAILQ_INIT(&vp->paths);
309 120200
                *pp = vp;
310 120200
        }
311 120360
        REPLACE(vp->str, path);
312 120680
        while (!VTAILQ_EMPTY(&vp->paths)) {
313 320
                vd = VTAILQ_FIRST(&vp->paths);
314 320
                CHECK_OBJ_NOTNULL(vd, VFIL_DIR_MAGIC);
315 320
                VTAILQ_REMOVE(&vp->paths, vd, list);
316 320
                FREE_OBJ(vd);
317
        }
318 300520
        for (p = vp->str; p != NULL; p = q) {
319 180160
                q = strchr(p, ':');
320 180160
                if (q != NULL)
321 59800
                        *q++ = '\0';
322 180160
                ALLOC_OBJ(vd, VFIL_DIR_MAGIC);
323 180160
                AN(vd);
324 180160
                vd->dir = p;
325 180160
                VTAILQ_INSERT_TAIL(&vp->paths, vd, list);
326 180160
        }
327 120360
}
328
329
static int
330 2480
vfil_path_openfile(void *priv, const char *fn)
331
{
332
        char *p, **pp;
333
334 2480
        AN(priv);
335 2480
        AN(fn);
336 2480
        p = VFIL_readfile(NULL, fn, NULL);
337 2480
        if (p == NULL)
338 80
                return (1);
339
340 2400
        pp = priv;
341 2400
        *pp = p;
342 2400
        return (0);
343 2480
}
344
345
int
346 26000
VFIL_searchpath(const struct vfil_path *vp, vfil_path_func_f *func, void *priv,
347
    const char *fni, char **fno)
348
{
349
        struct vsb *vsb;
350
        struct vfil_dir *vd;
351
        int i, e;
352
353 26000
        CHECK_OBJ_NOTNULL(vp, VFIL_PATH_MAGIC);
354 26000
        AN(fno);
355 26000
        *fno = NULL;
356
357 26000
        if (func == NULL) {
358 2560
                func = vfil_path_openfile;
359 2560
                AN(priv);
360 2560
        }
361
362 26000
        if (*fni == '/') {
363 2040
                i = func(priv, fni);
364 2040
                if (i <= 0)
365 1960
                        REPLACE(*fno, fni);
366 2040
                return (i);
367
        }
368 23960
        vsb = VSB_new_auto();
369 23960
        AN(vsb);
370 24200
        VTAILQ_FOREACH(vd, &vp->paths, list) {
371 24080
                VSB_clear(vsb);
372 24080
                VSB_printf(vsb, "%s/%s", vd->dir, fni);
373 24080
                AZ(VSB_finish(vsb));
374 24080
                if (access(VSB_data(vsb), F_OK))
375 240
                        continue;
376 23840
                i = func(priv, VSB_data(vsb));
377 23840
                if (i <= 0) {
378 23840
                        e = errno;
379 23840
                        *fno = strdup(VSB_data(vsb));
380 23840
                        AN(*fno);
381 23840
                        VSB_destroy(&vsb);
382 23840
                        errno = e;
383 23840
                        return (i);
384
                }
385 0
        }
386 120
        VSB_destroy(&vsb);
387 120
        return (-1);
388 26000
}