Coverage Report

Created: 2026-02-14 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/casync/src/util.c
Line
Count
Source
1
/* SPDX-License-Identifier: LGPL-2.1+ */
2
3
#include <ctype.h>
4
#include <fcntl.h>
5
#include <libgen.h>
6
#include <poll.h>
7
#include <stdarg.h>
8
#include <sys/stat.h>
9
#include <sys/wait.h>
10
#include <time.h>
11
#include <linux/fs.h>
12
#include <linux/falloc.h>
13
#include <linux/msdos_fs.h>
14
15
#if USE_SYS_RANDOM_H
16
#  include <sys/random.h>
17
#endif
18
19
#include "def.h"
20
#include "time-util.h"
21
#include "util.h"
22
23
0
#define HOLE_MIN 4096
24
25
0
int loop_write(int fd, const void *p, size_t l) {
26
27
0
        if (fd < 0)
28
0
                return -EBADF;
29
0
        if (!p && l > 0)
30
0
                return -EINVAL;
31
32
0
        while (l > 0) {
33
0
                ssize_t w;
34
35
0
                w = write(fd, p, l);
36
0
                if (w < 0)
37
0
                        return -errno;
38
39
0
                assert((size_t) w <= l);
40
41
0
                p = (const uint8_t*) p + w;
42
0
                l -= w;
43
0
        }
44
45
0
        return 0;
46
0
}
47
48
0
int loop_write_block(int fd, const void *p, size_t l) {
49
0
        if (fd < 0)
50
0
                return -EBADF;
51
0
        if (!p && l > 0)
52
0
                return -EINVAL;
53
54
0
        while (l > 0) {
55
0
                ssize_t w;
56
57
0
                w = write(fd, p, l);
58
0
                if (w < 0) {
59
0
                        if (errno == EAGAIN) {
60
61
0
                                struct pollfd pollfd = {
62
0
                                        .fd = fd,
63
0
                                        .events = POLLOUT,
64
0
                                };
65
66
0
                                if (poll(&pollfd, 1, -1) < 0)
67
0
                                        return -errno;
68
69
0
                                continue;
70
0
                        }
71
72
0
                        return -errno;
73
0
                }
74
75
0
                assert((size_t) w <= l);
76
77
0
                p = (const uint8_t*) p + w;
78
0
                l -= w;
79
0
        }
80
81
0
        return 0;
82
0
}
83
84
0
int write_zeroes(int fd, size_t l) {
85
0
        const char *zeroes;
86
0
        off_t p, end;
87
0
        size_t bs;
88
89
        /* Writes the specified number of zero bytes to the current file position. If possible this is done via "hole
90
         * punching", i.e. by creating sparse files. Unfortunately there's no syscall currently available that
91
         * implements this efficiently, hence we have to fake it via the existing FALLOC_FL_PUNCH_HOLE operation, which
92
         * requires us to extend the file size manually if necessary. This means we need 6 syscalls in the worst case,
93
         * instead of one. Bummer... But this is Linux, so what did you expect? */
94
95
0
        if (fd < 0)
96
0
                return -EBADF;
97
0
        if (l == 0)
98
0
                return 0;
99
100
0
        p = lseek(fd, 0, SEEK_CUR); /* Determine where we are */
101
0
        if (p == (off_t) -1)
102
0
                goto fallback;
103
104
0
        if (p + (off_t) l < p)
105
0
                return -EOVERFLOW;
106
107
0
        end = lseek(fd, 0, SEEK_END); /* Determine file size (this also puts the file offset at the end, but we don't care) */
108
0
        if (end == (off_t) -1)
109
0
                return -errno;
110
111
0
        if (end > p) {
112
0
                if (fallocate(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, p, l) < 0) {
113
114
0
                        if (lseek(fd, p, SEEK_SET) == (off_t) -1) /* Revert to the original position, before we fallback to write() */
115
0
                                return -errno;
116
117
0
                        goto fallback;
118
0
                }
119
0
        }
120
121
0
        if (p + (off_t) l > end) {
122
0
                if (ftruncate(fd, p + l) < 0)
123
0
                        return -errno;
124
0
        }
125
126
0
        if (lseek(fd, p + l, SEEK_SET) == (off_t) -1) /* Make sure we position the offset now after the hole we just added */
127
0
                return -errno;
128
129
0
        return 1; /* Return > 0 when we managed to punch holes */
130
131
0
fallback:
132
0
        bs = MIN(4096U, l);
133
0
        zeroes = alloca0(bs);
134
135
0
        while (l > 0) {
136
0
                ssize_t w;
137
138
0
                w = write(fd, zeroes, MIN(l, bs));
139
0
                if (w < 0)
140
0
                        return -errno;
141
142
0
                assert((size_t) w <= l);
143
0
                l -= w;
144
0
        }
145
146
0
        return 0; /* Return == 0 if we could only write out zeroes */
147
0
}
148
149
0
static bool memeqzero(const void *data, size_t length) {
150
        /* Does the buffer consist entirely of NULs?
151
         * Copied from https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92,
152
         * which is licensed CC-0.
153
         */
154
155
0
        const uint8_t *p = data;
156
0
        size_t i;
157
158
        /* Check first 16 bytes manually */
159
0
        for (i = 0; i < 16; i++, length--) {
160
0
                if (length == 0)
161
0
                        return true;
162
0
                if (p[i])
163
0
                        return false;
164
0
        }
165
166
        /* Now we know first 16 bytes are NUL, memcmp with self.  */
167
0
        return memcmp(data, p + i, length) == 0;
168
0
}
169
170
0
int loop_write_with_holes(int fd, const void *p, size_t l, uint64_t *ret_punched) {
171
0
        const uint8_t *q, *start = p, *zero_start = NULL;
172
0
        uint64_t n_punched = 0;
173
0
        int r;
174
175
        /* Write out the specified data much like loop_write(), but try to punch holes for any longer series of zero
176
         * bytes, thus creating sparse files if possible. */
177
178
0
        for (q = p; q < (const uint8_t*) p + l; ) {
179
0
                size_t left = MIN(HOLE_MIN, (const uint8_t*) p + l - q);
180
181
0
                if (memeqzero(q, left)) {
182
0
                        if (!zero_start)
183
0
                                zero_start = q;
184
185
0
                } else if (zero_start) {
186
0
                        if (q - zero_start >= HOLE_MIN) {
187
0
                                r = loop_write(fd, start, zero_start - start);
188
0
                                if (r < 0)
189
0
                                        return r;
190
191
0
                                r = write_zeroes(fd, q - zero_start);
192
0
                                if (r < 0)
193
0
                                        return r;
194
195
                                /* Couldn't punch hole? then don't bother again */
196
0
                                if (r == 0) {
197
0
                                        r = loop_write(fd, q, (const uint8_t*) p + l - q);
198
0
                                        if (r < 0)
199
0
                                                return r;
200
201
0
                                        goto success;
202
0
                                }
203
204
0
                                n_punched += q - zero_start;
205
0
                                start = q;
206
0
                        }
207
208
0
                        zero_start = NULL;
209
0
                }
210
211
0
                q += left;
212
0
        }
213
214
0
        if (zero_start)
215
0
                if (q - zero_start >= HOLE_MIN) {
216
0
                        r = loop_write(fd, start, zero_start - start);
217
0
                        if (r < 0)
218
0
                                return r;
219
220
0
                        r = write_zeroes(fd, q - zero_start);
221
0
                        if (r < 0)
222
0
                                return r;
223
0
                        if (r > 0)
224
0
                                n_punched += q - zero_start;
225
226
0
                        goto success;
227
0
                }
228
229
0
        r = loop_write(fd, start, q - start);
230
0
        if (r < 0)
231
0
                return r;
232
233
0
 success:
234
0
        if (ret_punched)
235
0
                *ret_punched = n_punched;
236
237
0
        return 0;
238
0
}
239
240
0
ssize_t loop_read(int fd, void *p, size_t l) {
241
0
        ssize_t sum = 0;
242
243
0
        if (fd < 0)
244
0
                return -EBADF;
245
0
        if (!p)
246
0
                return -EINVAL;
247
0
        if (l == 0)
248
0
                return -EINVAL;
249
250
0
        while (l > 0) {
251
0
                ssize_t r;
252
253
0
                r = read(fd, p, l);
254
0
                if (r < 0)
255
0
                        return -errno;
256
0
                if (r == 0)
257
0
                        break;
258
259
0
                p = (uint8_t*) p + r;
260
0
                l -= r;
261
0
                sum += r;
262
0
        }
263
264
0
        return sum;
265
0
}
266
267
0
int skip_bytes(int fd, uint64_t bytes) {
268
0
        size_t buffer_size;
269
0
        void *m;
270
0
        off_t p;
271
272
0
        if (bytes == 0)
273
0
                return 0;
274
275
0
        p = lseek(fd, (off_t) bytes, SEEK_CUR);
276
0
        if (p != (off_t) -1)
277
0
                return 0;
278
279
0
        buffer_size = MIN(bytes, BUFFER_SIZE);
280
0
        m = alloca(buffer_size);
281
282
0
        do {
283
0
                ssize_t l;
284
285
0
                l = read(fd, m, MIN(bytes, buffer_size));
286
0
                if (l < 0)
287
0
                        return -errno;
288
0
                if (l == 0)
289
0
                        return -EPIPE;
290
291
0
                assert((uint64_t) l <= bytes);
292
0
                bytes -= l;
293
294
0
        } while (bytes > 0);
295
296
0
        return 0;
297
0
}
298
299
0
char *endswith(const char *p, const char *suffix) {
300
0
        size_t a, b;
301
0
        const char *e;
302
303
0
        a = strlen(p);
304
0
        b = strlen(suffix);
305
306
0
        if (b > a)
307
0
                return NULL;
308
309
0
        e = p + a - b;
310
311
0
        return strcmp(e, suffix) == 0 ? (char*) e : NULL;
312
0
}
313
314
#if !HAVE_GETRANDOM
315
#  ifndef __NR_getrandom
316
#    if defined __x86_64__
317
#      define __NR_getrandom 318
318
#    elif defined(__i386__)
319
#      define __NR_getrandom 355
320
#    elif defined(__arm__)
321
#      define __NR_getrandom 384
322
#   elif defined(__aarch64__)
323
#      define __NR_getrandom 278
324
#    elif defined(__ia64__)
325
#      define __NR_getrandom 1339
326
#    elif defined(__m68k__)
327
#      define __NR_getrandom 352
328
#    elif defined(__s390x__)
329
#      define __NR_getrandom 349
330
#    elif defined(__powerpc__)
331
#      define __NR_getrandom 359
332
#    elif defined _MIPS_SIM
333
#      if _MIPS_SIM == _MIPS_SIM_ABI32
334
#        define __NR_getrandom 4353
335
#      endif
336
#      if _MIPS_SIM == _MIPS_SIM_NABI32
337
#        define __NR_getrandom 6317
338
#      endif
339
#      if _MIPS_SIM == _MIPS_SIM_ABI64
340
#        define __NR_getrandom 5313
341
#      endif
342
#    else
343
#      warning "__NR_getrandom unknown for your architecture"
344
#    endif
345
#  endif
346
347
static inline int getrandom(void *buffer, size_t count, unsigned flags) {
348
#  ifdef __NR_getrandom
349
        return syscall(__NR_getrandom, buffer, count, flags);
350
#  else
351
        errno = ENOSYS;
352
        return -1;
353
#  endif
354
}
355
#endif
356
357
#ifndef GRND_NONBLOCK
358
#define GRND_NONBLOCK 0x0001
359
#endif
360
361
#ifndef GRND_RANDOM
362
#define GRND_RANDOM 0x0002
363
#endif
364
365
0
int dev_urandom(void *p, size_t n) {
366
0
        static int have_syscall = -1;
367
0
        int fd, r;
368
0
        ssize_t l;
369
370
0
        if (have_syscall != 0 || (size_t) (int) n != n) {
371
0
                r = getrandom(p, n, GRND_NONBLOCK);
372
0
                if (r == (int) n) {
373
0
                        have_syscall = true;
374
0
                        return 0;
375
0
                }
376
377
0
                if (r < 0) {
378
0
                        if (errno == ENOSYS)
379
0
                                have_syscall = false;
380
0
                        else if (errno == EAGAIN)
381
0
                                have_syscall = true;
382
0
                        else
383
0
                                return -errno;
384
0
                } else
385
0
                        return -ENODATA;
386
0
        }
387
388
0
        fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
389
0
        if (fd < 0)
390
0
                return errno == ENOENT ? -ENOSYS : -errno;
391
392
0
        l = loop_read(fd, p, n);
393
0
        (void) close(fd);
394
395
0
        if (l < 0)
396
0
                return (int) l;
397
0
        if ((size_t) l != n)
398
0
                return -EIO;
399
400
0
        return 0;
401
0
}
402
403
0
char octchar(int x) {
404
0
        return '0' + (x & 7);
405
0
}
406
407
0
char hexchar(int x) {
408
0
        static const char table[16] = "0123456789abcdef";
409
410
0
        return table[x & 15];
411
0
}
412
413
0
int unhexchar(char c) {
414
415
0
        if (c >= '0' && c <= '9')
416
0
                return c - '0';
417
418
0
        if (c >= 'a' && c <= 'f')
419
0
                return c - 'a' + 10;
420
421
0
        if (c >= 'A' && c <= 'F')
422
0
                return c - 'A' + 10;
423
424
0
        return -EINVAL;
425
0
}
426
427
0
char *hexmem(const void *p, size_t l) {
428
0
        const uint8_t *x;
429
0
        char *r, *z;
430
431
0
        z = r = new(char, l * 2 + 1);
432
0
        if (!r)
433
0
                return NULL;
434
435
0
        for (x = p; x < (const uint8_t*) p + l; x++) {
436
0
                *(z++) = hexchar(*x >> 4);
437
0
                *(z++) = hexchar(*x & 15);
438
0
        }
439
440
0
        *z = 0;
441
0
        return r;
442
0
}
443
444
0
bool filename_is_valid(const char *p) {
445
0
        const char *e;
446
447
0
        if (isempty(p))
448
0
                return false;
449
450
0
        if (dot_or_dot_dot(p))
451
0
                return false;
452
453
0
        e = strchrnul(p, '/');
454
0
        if (*e != 0)
455
0
                return false;
456
457
0
        if (e - p > FILENAME_MAX)
458
0
                return false;
459
460
0
        return true;
461
0
}
462
463
0
int tempfn_random(const char *p, char **ret) {
464
0
        const char *fn;
465
0
        char *t, *x;
466
0
        uint64_t u;
467
0
        unsigned i;
468
469
0
        assert(p);
470
0
        assert(ret);
471
472
        /*
473
         * Turns this:
474
         *         /foo/bar/waldo
475
         *
476
         * Into this:
477
         *         /foo/bar/.#waldobaa2a261115984a9
478
         */
479
480
0
        fn = strrchr(p, '/');
481
0
        fn = fn ? fn + 1 : p;
482
0
        if (!filename_is_valid(fn))
483
0
                return -EINVAL;
484
485
0
        t = new(char, strlen(p) + 2 + 16 + 1);
486
0
        if (!t)
487
0
                return -ENOMEM;
488
489
0
        x = stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn);
490
491
0
        u = random_u64();
492
0
        for (i = 0; i < 16; i++) {
493
0
                *(x++) = hexchar(u & 0xF);
494
0
                u >>= 4;
495
0
        }
496
497
0
        *x = 0;
498
499
0
        *ret = t;
500
0
        return 0;
501
0
}
502
503
0
void hexdump(FILE *f, const void *p, size_t s) {
504
0
        const uint8_t *b = p;
505
0
        unsigned n = 0;
506
507
0
        assert(s == 0 || b);
508
509
0
        if (!f)
510
0
                f = stdout;
511
512
0
        while (s > 0) {
513
0
                size_t i;
514
515
0
                fprintf(f, "%04x  ", n);
516
517
0
                for (i = 0; i < 16; i++) {
518
519
0
                        if (i >= s)
520
0
                                fputs("   ", f);
521
0
                        else
522
0
                                fprintf(f, "%02x ", b[i]);
523
524
0
                        if (i == 7)
525
0
                                fputc(' ', f);
526
0
                }
527
528
0
                fputc(' ', f);
529
530
0
                for (i = 0; i < 16; i++) {
531
532
0
                        if (i >= s)
533
0
                                fputc(' ', f);
534
0
                        else
535
0
                                fputc(isprint(b[i]) ? (char) b[i] : '.', f);
536
0
                }
537
538
0
                fputc('\n', f);
539
540
0
                if (s < 16)
541
0
                        break;
542
543
0
                n += 16;
544
0
                b += 16;
545
0
                s -= 16;
546
0
        }
547
0
}
548
549
0
char* dirname_malloc(const char *path) {
550
0
        char *d, *dir, *dir2;
551
552
0
        assert(path);
553
554
0
        d = strdup(path);
555
0
        if (!d)
556
0
                return NULL;
557
558
0
        dir = dirname(d);
559
0
        assert(dir);
560
561
0
        if (dir == d)
562
0
                return d;
563
564
0
        dir2 = strdup(dir);
565
0
        free(d);
566
567
0
        return dir2;
568
0
}
569
570
0
char *strjoin_real(const char *x, ...) {
571
0
        va_list ap;
572
0
        size_t l;
573
0
        char *r, *p;
574
575
0
        va_start(ap, x);
576
577
0
        if (x) {
578
0
                l = strlen(x);
579
580
0
                for (;;) {
581
0
                        const char *t;
582
0
                        size_t n;
583
584
0
                        t = va_arg(ap, const char *);
585
0
                        if (!t)
586
0
                                break;
587
588
0
                        n = strlen(t);
589
0
                        if (n > ((size_t) -1) - l) {
590
0
                                va_end(ap);
591
0
                                return NULL;
592
0
                        }
593
594
0
                        l += n;
595
0
                }
596
0
        } else
597
0
                l = 0;
598
599
0
        va_end(ap);
600
601
0
        r = new(char, l+1);
602
0
        if (!r)
603
0
                return NULL;
604
605
0
        if (x) {
606
0
                p = stpcpy(r, x);
607
608
0
                va_start(ap, x);
609
610
0
                for (;;) {
611
0
                        const char *t;
612
613
0
                        t = va_arg(ap, const char *);
614
0
                        if (!t)
615
0
                                break;
616
617
0
                        p = stpcpy(p, t);
618
0
                }
619
620
0
                va_end(ap);
621
0
        } else
622
0
                r[0] = 0;
623
624
0
        return r;
625
0
}
626
627
0
char* ls_format_mode(mode_t m, char ret[LS_FORMAT_MODE_MAX]) {
628
629
0
        if (m == (mode_t) -1)
630
0
                return NULL;
631
632
0
        switch (m & S_IFMT) {
633
634
0
        case S_IFSOCK:
635
0
                ret[0] = 's';
636
0
                break;
637
638
0
        case S_IFDIR:
639
0
                ret[0] = 'd';
640
0
                break;
641
642
0
        case S_IFREG:
643
0
                ret[0] = '-';
644
0
                break;
645
646
0
        case S_IFBLK:
647
0
                ret[0] = 'b';
648
0
                break;
649
650
0
        case S_IFCHR:
651
0
                ret[0] = 'c';
652
0
                break;
653
654
0
        case S_IFLNK:
655
0
                ret[0] = 'l';
656
0
                break;
657
658
0
        case S_IFIFO:
659
0
                ret[0] = 'p';
660
0
                break;
661
662
0
        default:
663
0
                return NULL;
664
0
        }
665
666
0
        ret[1] = m & 0400 ? 'r' : '-';
667
0
        ret[2] = m & 0200 ? 'w' : '-';
668
0
        ret[3] = (m & S_ISUID) ? (m & 0100 ? 's' : 'S') : (m & 0100 ? 'x' : '-');
669
670
0
        ret[4] = m & 0040 ? 'r' : '-';
671
0
        ret[5] = m & 0020 ? 'w' : '-';
672
0
        ret[6] = (m & S_ISGID) ? (m & 0010 ? 's' : 'S') : (m & 0010 ? 'x' : '-');
673
674
0
        ret[7] = m & 0004 ? 'r' : '-';
675
0
        ret[8] = m & 0002 ? 'w' : '-';
676
0
        ret[9] = (S_ISDIR(m) && (m & S_ISVTX)) ? (m & 0001 ? 't' : 'T') : (m & 0001 ? 'x' : '-');
677
678
0
        ret[10] = 0;
679
680
0
        return ret;
681
0
}
682
683
0
char *ls_format_chattr(unsigned flags, char ret[LS_FORMAT_CHATTR_MAX]) {
684
685
0
        static const struct {
686
0
                unsigned flag;
687
0
                char code;
688
0
        } table[] = {
689
0
                { FS_SYNC_FL,        'S' },
690
0
                { FS_DIRSYNC_FL,     'D' },
691
0
                { FS_IMMUTABLE_FL,   'i' },
692
0
                { FS_APPEND_FL,      'a' },
693
0
                { FS_NODUMP_FL,      'd' },
694
0
                { FS_NOATIME_FL,     'A' },
695
0
                { FS_COMPR_FL,       'c' },
696
0
                { FS_NOCOMP_FL,      'N' }, /* Not an official one, but one we made up, since lsattr(1) doesn't know it. Subject to change, as soon as it starts supporting that. */
697
0
                { FS_NOCOW_FL,       'C' },
698
0
                { FS_PROJINHERIT_FL, 'P' },
699
0
        };
700
701
0
        size_t i;
702
703
0
        if (flags == (unsigned) -1)
704
0
                return NULL;
705
706
0
        assert(ELEMENTSOF(table) == LS_FORMAT_CHATTR_MAX-1);
707
708
0
        for (i = 0; i < ELEMENTSOF(table); i++)
709
0
                ret[i] = flags & table[i].flag ? table[i].code : '-';
710
711
0
        ret[i] = 0;
712
713
0
        return ret;
714
0
}
715
716
0
char *ls_format_fat_attrs(uint32_t flags, char ret[LS_FORMAT_FAT_ATTRS_MAX]) {
717
718
0
        static const struct {
719
0
                uint32_t flag;
720
0
                char code;
721
0
        } table[] = {
722
0
                { ATTR_HIDDEN, 'h' },
723
0
                { ATTR_SYS,    's' },
724
0
                { ATTR_ARCH,   'a' },
725
0
        };
726
727
0
        size_t i;
728
729
0
        if (flags == (uint32_t) -1)
730
0
                return NULL;
731
732
0
        assert(ELEMENTSOF(table) == LS_FORMAT_FAT_ATTRS_MAX-1);
733
734
0
        for (i = 0; i < ELEMENTSOF(table); i++)
735
0
                ret[i] = flags & table[i].flag ? table[i].code : '-';
736
737
0
        ret[i] = 0;
738
739
0
        return ret;
740
0
}
741
742
0
int safe_atoi(const char *s, int *ret_i) {
743
0
        char *x = NULL;
744
0
        long l;
745
746
0
        assert(s);
747
0
        assert(ret_i);
748
749
0
        errno = 0;
750
0
        l = strtol(s, &x, 0);
751
0
        if (errno > 0)
752
0
                return -errno;
753
0
        if (!x || x == s || *x)
754
0
                return -EINVAL;
755
0
        if ((long) (int) l != l)
756
0
                return -ERANGE;
757
758
0
        *ret_i = (int) l;
759
0
        return 0;
760
0
}
761
762
0
int safe_atou(const char *s, unsigned *ret_u) {
763
0
        char *x = NULL;
764
0
        unsigned long l;
765
766
0
        assert(s);
767
768
        /* strtoul() is happy to parse negative values, and silently
769
         * converts them to unsigned values without generating an
770
         * error. We want a clean error, hence let's look for the "-"
771
         * prefix on our own, and generate an error. But let's do so
772
         * only after strtoul() validated that the string is clean
773
         * otherwise, so that we return EINVAL preferably over
774
         * ERANGE. */
775
776
0
        s += strspn(s, WHITESPACE);
777
778
0
        errno = 0;
779
0
        l = strtoul(s, &x, 0);
780
0
        if (errno > 0)
781
0
                return -errno;
782
0
        if (!x || x == s || *x)
783
0
                return -EINVAL;
784
0
        if (*s == '-')
785
0
                return -ERANGE;
786
0
        if ((unsigned long) (unsigned) l != l)
787
0
                return -ERANGE;
788
789
0
        if (ret_u)
790
0
                *ret_u = (unsigned) l;
791
792
0
        return 0;
793
0
}
794
795
0
int safe_atollu(const char *s, long long unsigned *ret_llu) {
796
0
        char *x = NULL;
797
0
        unsigned long long l;
798
799
0
        assert(s);
800
801
0
        s += strspn(s, WHITESPACE);
802
803
0
        errno = 0;
804
0
        l = strtoull(s, &x, 0);
805
0
        if (errno > 0)
806
0
                return -errno;
807
0
        if (!x || x == s || *x != 0)
808
0
                return -EINVAL;
809
0
        if (*s == '-')
810
0
                return -ERANGE;
811
812
0
        if (ret_llu)
813
0
                *ret_llu = l;
814
815
0
        return 0;
816
0
}
817
818
0
int safe_atollx(const char *s, long long unsigned *ret_llu) {
819
0
        char *x = NULL;
820
0
        unsigned long long l;
821
822
0
        assert(s);
823
824
0
        s += strspn(s, WHITESPACE);
825
826
0
        errno = 0;
827
0
        l = strtoull(s, &x, 16);
828
0
        if (errno > 0)
829
0
                return -errno;
830
0
        if (!x || x == s || *x != 0)
831
0
                return -EINVAL;
832
0
        if (*s == '-')
833
0
                return -ERANGE;
834
835
0
        if (ret_llu)
836
0
                *ret_llu = l;
837
838
0
        return 0;
839
0
}
840
841
0
int readlinkat_malloc(int fd, const char *p, char **ret) {
842
0
        size_t l = 256;
843
0
        int r;
844
845
0
        assert(p);
846
0
        assert(ret);
847
848
0
        for (;;) {
849
0
                char *c;
850
0
                ssize_t n;
851
852
0
                c = new(char, l);
853
0
                if (!c)
854
0
                        return -ENOMEM;
855
856
0
                n = readlinkat(fd, p, c, l-1);
857
0
                if (n < 0) {
858
0
                        r = -errno;
859
0
                        free(c);
860
0
                        return r;
861
0
                }
862
863
0
                if ((size_t) n < l-1) {
864
0
                        c[n] = 0;
865
0
                        *ret = c;
866
0
                        return 0;
867
0
                }
868
869
0
                free(c);
870
0
                l *= 2;
871
0
        }
872
0
}
873
874
0
int readlink_malloc(const char *p, char **ret) {
875
0
        return readlinkat_malloc(AT_FDCWD, p, ret);
876
0
}
877
878
0
char **strv_free(char **l) {
879
0
        char **k;
880
881
0
        if (!l)
882
0
                return NULL;
883
884
0
        for (k = l; *k; k++)
885
0
                free(*k);
886
887
0
        return mfree(l);
888
0
}
889
890
0
size_t strv_length(char **l) {
891
0
        size_t n = 0;
892
893
0
        if (!l)
894
0
                return 0;
895
896
0
        for (; *l; l++)
897
0
                n++;
898
899
0
        return n;
900
0
}
901
902
0
int strv_push(char ***l, char *value) {
903
0
        char **c;
904
0
        unsigned n, m;
905
906
0
        assert(l);
907
908
0
        if (!value)
909
0
                return 0;
910
911
0
        n = strv_length(*l);
912
913
        /* Increase and check for overflow */
914
0
        m = n + 2;
915
0
        if (m < n)
916
0
                return -ENOMEM;
917
918
0
        c = realloc_multiply(*l, sizeof(char*), m);
919
0
        if (!c)
920
0
                return -ENOMEM;
921
922
0
        c[n] = value;
923
0
        c[n+1] = NULL;
924
925
0
        *l = c;
926
0
        return 0;
927
0
}
928
929
0
int strv_consume(char ***l, char *value) {
930
0
        int r;
931
932
0
        assert(l);
933
934
0
        r = strv_push(l, value);
935
0
        if (r < 0)
936
0
                free(value);
937
938
0
        return r;
939
0
}
940
941
0
int strv_extend(char ***l, const char *value) {
942
0
        char *v;
943
944
0
        assert(l);
945
946
0
        if (!value)
947
0
                return 0;
948
949
0
        v = strdup(value);
950
0
        if (!v)
951
0
                return -ENOMEM;
952
953
0
        return strv_consume(l, v);
954
0
}
955
956
0
int xopendirat(int fd, const char *name, int flags, DIR **ret) {
957
0
        int nfd;
958
0
        DIR *d;
959
960
0
        nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
961
0
        if (nfd < 0)
962
0
                return -errno;
963
964
0
        d = fdopendir(nfd);
965
0
        if (!d) {
966
0
                safe_close(nfd);
967
0
                return -errno;
968
0
        }
969
970
0
        *ret = d;
971
0
        return 0;
972
0
}
973
974
0
void progress(void) {
975
0
        static const char slashes[] = {
976
0
                '-',
977
0
                '\\',
978
0
                '|',
979
0
                '/',
980
0
        };
981
0
        static unsigned i = 0;
982
0
        static uint64_t last_nsec = 0;
983
984
0
        struct timespec now;
985
0
        static uint64_t now_nsec;
986
987
0
        assert(clock_gettime(CLOCK_MONOTONIC, &now) >= 0);
988
0
        now_nsec = timespec_to_nsec(now);
989
990
0
        if (last_nsec + 250000000 > now_nsec)
991
0
                return;
992
993
0
        last_nsec = now_nsec;
994
995
0
        fputc(slashes[i % ELEMENTSOF(slashes)], stderr);
996
0
        fputc('\b', stderr);
997
0
        fflush(stderr);
998
999
0
        i++;
1000
0
}
1001
1002
0
char *strextend(char **x, ...) {
1003
0
        va_list ap;
1004
0
        size_t f, l;
1005
0
        char *r, *p;
1006
1007
0
        assert(x);
1008
1009
0
        l = f = *x ? strlen(*x) : 0;
1010
1011
0
        va_start(ap, x);
1012
0
        for (;;) {
1013
0
                const char *t;
1014
0
                size_t n;
1015
1016
0
                t = va_arg(ap, const char *);
1017
0
                if (!t)
1018
0
                        break;
1019
1020
0
                n = strlen(t);
1021
0
                if (n > ((size_t) -1) - l) {
1022
0
                        va_end(ap);
1023
0
                        return NULL;
1024
0
                }
1025
1026
0
                l += n;
1027
0
        }
1028
0
        va_end(ap);
1029
1030
0
        r = realloc(*x, l+1);
1031
0
        if (!r)
1032
0
                return NULL;
1033
1034
0
        p = r + f;
1035
1036
0
        va_start(ap, x);
1037
0
        for (;;) {
1038
0
                const char *t;
1039
1040
0
                t = va_arg(ap, const char *);
1041
0
                if (!t)
1042
0
                        break;
1043
1044
0
                p = stpcpy(p, t);
1045
0
        }
1046
0
        va_end(ap);
1047
1048
0
        *p = 0;
1049
0
        *x = r;
1050
1051
0
        return r + l;
1052
0
}
1053
1054
0
bool uid_is_valid(uid_t uid) {
1055
1056
        /* Some libc APIs use UID_INVALID as special placeholder */
1057
0
        if (uid == (uid_t) UINT32_C(0xFFFFFFFF))
1058
0
                return false;
1059
1060
        /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
1061
0
        if (uid == (uid_t) UINT32_C(0xFFFF))
1062
0
                return false;
1063
1064
0
        return true;
1065
0
}
1066
1067
0
int parse_uid(const char *s, uid_t *ret) {
1068
0
        uint32_t uid = 0;
1069
0
        int r;
1070
1071
0
        assert(s);
1072
1073
0
        assert(sizeof(uid_t) == sizeof(uint32_t));
1074
0
        r = safe_atou32(s, &uid);
1075
0
        if (r < 0)
1076
0
                return r;
1077
1078
0
        if (!uid_is_valid(uid))
1079
0
                return -ENXIO; /* we return ENXIO instead of EINVAL
1080
                                * here, to make it easy to distinguish
1081
                                * invalid numeric uids from invalid
1082
                                * strings. */
1083
1084
0
        if (ret)
1085
0
                *ret = uid;
1086
1087
0
        return 0;
1088
0
}
1089
1090
0
int wait_for_terminate(pid_t pid, siginfo_t *status) {
1091
0
        siginfo_t dummy;
1092
1093
0
        assert(pid >= 1);
1094
1095
0
        if (!status)
1096
0
                status = &dummy;
1097
1098
0
        for (;;) {
1099
0
                memset(status, 0, sizeof(siginfo_t));
1100
1101
0
                if (waitid(P_PID, pid, status, WEXITED) < 0) {
1102
1103
0
                        if (errno == EINTR)
1104
0
                                continue;
1105
1106
0
                        return -errno;
1107
0
                }
1108
1109
0
                return 0;
1110
0
        }
1111
0
}
1112
1113
0
char *strv_find(char **l, const char *name) {
1114
0
        char **i;
1115
1116
0
        assert(name);
1117
1118
0
        STRV_FOREACH(i, l)
1119
0
                if (streq(*i, name))
1120
0
                        return *i;
1121
1122
0
        return NULL;
1123
0
}
1124
1125
0
size_t page_size(void) {
1126
0
        static size_t pgsz = 0;
1127
0
        long v;
1128
1129
0
        if (_likely_(pgsz > 0))
1130
0
                return pgsz;
1131
1132
0
        v = sysconf(_SC_PAGESIZE);
1133
0
        assert(v > 0);
1134
1135
0
        pgsz = (size_t) v;
1136
0
        return pgsz;
1137
0
}
1138
1139
0
int parse_boolean(const char *v) {
1140
0
        if (!v)
1141
0
                return -EINVAL;
1142
1143
0
        if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
1144
0
                return 1;
1145
0
        if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
1146
0
                return 0;
1147
1148
0
        return -EINVAL;
1149
0
}
1150
1151
0
int getenv_bool(const char *p) {
1152
0
        const char *e;
1153
1154
0
        e = getenv(p);
1155
0
        if (!e)
1156
0
                return -ENXIO;
1157
1158
0
        return parse_boolean(e);
1159
0
}
1160
1161
0
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
1162
0
        size_t a, newalloc;
1163
0
        void *q;
1164
1165
0
        assert(p);
1166
0
        assert(allocated);
1167
1168
0
        if (*allocated >= need)
1169
0
                return *p;
1170
1171
0
        newalloc = MAX(need * 2, 64u / size);
1172
0
        a = newalloc * size;
1173
1174
        /* check for overflows */
1175
0
        if (a < size * need)
1176
0
                return NULL;
1177
1178
0
        q = realloc(*p, a);
1179
0
        if (!q)
1180
0
                return NULL;
1181
1182
0
        *p = q;
1183
0
        *allocated = newalloc;
1184
0
        return q;
1185
0
}
1186
1187
0
void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
1188
0
        size_t prev;
1189
0
        uint8_t *q;
1190
1191
0
        assert(p);
1192
0
        assert(allocated);
1193
1194
0
        prev = *allocated;
1195
1196
0
        q = greedy_realloc(p, allocated, need, size);
1197
0
        if (!q)
1198
0
                return NULL;
1199
1200
0
        if (*allocated > prev)
1201
0
                memzero(q + prev * size, (*allocated - prev) * size);
1202
1203
0
        return q;
1204
0
}
1205
1206
0
int skip_bytes_fd(int fd, uint64_t n_bytes) {
1207
0
        void *p;
1208
0
        size_t m;
1209
1210
0
        if (fd < 0)
1211
0
                return -EBADF;
1212
0
        if (n_bytes == 0)
1213
0
                return 0;
1214
1215
0
        if (lseek(fd, n_bytes, SEEK_CUR) == (off_t) -1) {
1216
0
                if (errno != -ESPIPE)
1217
0
                        return -errno;
1218
0
        } else
1219
0
                return 0;
1220
1221
0
        m = (size_t) MIN(n_bytes, (uint64_t) PIPE_BUF);
1222
0
        p = alloca(m);
1223
1224
0
        for (;;) {
1225
0
                ssize_t k;
1226
1227
0
                k = read(fd, p, m);
1228
0
                if (k < 0)
1229
0
                        return -errno;
1230
0
                if (k == 0)
1231
0
                        return -ENXIO;
1232
1233
0
                n_bytes -= k;
1234
1235
0
                if (n_bytes == 0)
1236
0
                        return 0;
1237
1238
0
                m = (size_t) MIN(n_bytes, (uint64_t) PIPE_BUF);
1239
0
        }
1240
0
}
1241
1242
0
char *truncate_nl(char *p) {
1243
1244
0
        char *e;
1245
1246
0
        for (e = strchr(p, 0); e > p; e --)
1247
0
                if (!strchr(NEWLINE, e[-1]))
1248
0
                        break;
1249
1250
0
        *e = 0;
1251
1252
0
        return p;
1253
0
}
1254
1255
0
int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
1256
0
        int r;
1257
1258
0
        if (renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE) >= 0)
1259
0
                return 0;
1260
1261
        /* renameat2() exists since Linux 3.15, btrfs added support for it later.  If it is not implemented, fallback
1262
         * to another method. */
1263
0
        if (!ERRNO_IS_UNSUPPORTED(errno))
1264
0
                return -errno;
1265
1266
        /* Let's try linkat(). This will of course failure for non-files, but that's fine. */
1267
0
        if (linkat(olddirfd, oldpath, newdirfd, newpath, 0) >= 0) {
1268
0
                if (unlinkat(olddirfd, oldpath, 0) >= 0)
1269
0
                        return 0;
1270
1271
0
                r = -errno;
1272
0
                (void) unlinkat(newdirfd, newpath, 0);
1273
0
                return r;
1274
0
        } else if (!ERRNO_IS_UNSUPPORTED(errno))
1275
0
                return -errno;
1276
1277
        /* if renameat2 and linkat aren't supported, fallback to faccessat+renameat,
1278
         * it isn't atomic but that's the best we can do */
1279
0
        if (faccessat(newdirfd, newpath, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
1280
0
                return -EEXIST;
1281
1282
0
        if (errno != ENOENT)
1283
0
                return -errno;
1284
1285
0
        if (renameat(olddirfd, oldpath, newdirfd, newpath) < 0)
1286
0
                return -errno;
1287
1288
0
        return 0;
1289
0
}
1290
1291
0
char* path_startswith(const char *path, const char *prefix) {
1292
0
        assert(path);
1293
0
        assert(prefix);
1294
1295
        /* Returns a pointer to the start of the first component after the parts matched by
1296
         * the prefix, iff
1297
         * - both paths are absolute or both paths are relative,
1298
         * and
1299
         * - each component in prefix in turn matches a component in path at the same position.
1300
         * An empty string will be returned when the prefix and path are equivalent.
1301
         *
1302
         * Returns NULL otherwise.
1303
         */
1304
1305
0
        if ((path[0] == '/') != (prefix[0] == '/'))
1306
0
                return NULL;
1307
1308
0
        for (;;) {
1309
0
                size_t a, b;
1310
1311
0
                path += strspn(path, "/");
1312
0
                prefix += strspn(prefix, "/");
1313
1314
0
                if (*prefix == 0)
1315
0
                        return (char*) path;
1316
1317
0
                if (*path == 0)
1318
0
                        return NULL;
1319
1320
0
                a = strcspn(path, "/");
1321
0
                b = strcspn(prefix, "/");
1322
1323
0
                if (a != b)
1324
0
                        return NULL;
1325
1326
0
                if (memcmp(path, prefix, a) != 0)
1327
0
                        return NULL;
1328
1329
0
                path += a;
1330
0
                prefix += b;
1331
0
        }
1332
0
}
1333
1334
0
static int getenv_tmp_dir(const char **ret_path) {
1335
0
        const char *n;
1336
0
        int r, ret = 0;
1337
1338
0
        assert(ret_path);
1339
1340
        /* We use the same order of environment variables python uses in tempfile.gettempdir():
1341
         * https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir */
1342
0
        FOREACH_STRING(n, "TMPDIR", "TEMP", "TMP") {
1343
0
                const char *e;
1344
1345
0
                e = secure_getenv(n);
1346
0
                if (!e)
1347
0
                        continue;
1348
0
                if (!path_is_absolute(e)) {
1349
0
                        r = -ENOTDIR;
1350
0
                        goto next;
1351
0
                }
1352
0
                if (!path_is_safe(e)) {
1353
0
                        r = -EPERM;
1354
0
                        goto next;
1355
0
                }
1356
1357
0
                r = is_dir(e, true);
1358
0
                if (r < 0)
1359
0
                        goto next;
1360
0
                if (r == 0) {
1361
0
                        r = -ENOTDIR;
1362
0
                        goto next;
1363
0
                }
1364
1365
0
                *ret_path = e;
1366
0
                return 1;
1367
1368
0
        next:
1369
                /* Remember first error, to make this more debuggable */
1370
0
                if (ret >= 0)
1371
0
                        ret = r;
1372
0
        }
1373
1374
0
        if (ret < 0)
1375
0
                return ret;
1376
1377
0
        *ret_path = NULL;
1378
0
        return ret;
1379
0
}
1380
1381
0
static int tmp_dir_internal(const char *def, const char **ret) {
1382
0
        const char *e;
1383
0
        int r, k;
1384
1385
0
        assert(def);
1386
0
        assert(ret);
1387
1388
0
        r = getenv_tmp_dir(&e);
1389
0
        if (r > 0) {
1390
0
                *ret = e;
1391
0
                return 0;
1392
0
        }
1393
1394
0
        k = is_dir(def, true);
1395
0
        if (k == 0)
1396
0
                k = -ENOTDIR;
1397
0
        if (k < 0)
1398
0
                return r < 0 ? r : k;
1399
1400
0
        *ret = def;
1401
0
        return 0;
1402
0
}
1403
1404
0
int var_tmp_dir(const char **ret) {
1405
1406
        /* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
1407
         * even might survive a boot: /var/tmp. If $TMPDIR (or related environment variables) are set, its value is
1408
         * returned preferably however. Note that both this function and tmp_dir() below are affected by $TMPDIR,
1409
         * making it a variable that overrides all temporary file storage locations. */
1410
1411
0
        return tmp_dir_internal("/var/tmp", ret);
1412
0
}
1413
1414
0
int tmp_dir(const char **ret) {
1415
1416
        /* Similar to var_tmp_dir() above, but returns the location for "smaller" temporary files, which is usually
1417
         * backed by an in-memory file system: /tmp. */
1418
1419
0
        return tmp_dir_internal("/tmp", ret);
1420
0
}
1421
1422
0
bool path_is_safe(const char *p) {
1423
1424
0
        if (isempty(p))
1425
0
                return false;
1426
1427
0
        if (dot_or_dot_dot(p))
1428
0
                return false;
1429
1430
0
        if (startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
1431
0
                return false;
1432
1433
0
        if (strlen(p)+1 > PATH_MAX)
1434
0
                return false;
1435
1436
0
        return true;
1437
0
}
1438
1439
0
int is_dir(const char* path, bool follow) {
1440
0
        struct stat st;
1441
0
        int r;
1442
1443
0
        assert(path);
1444
1445
0
        if (follow)
1446
0
                r = stat(path, &st);
1447
0
        else
1448
0
                r = lstat(path, &st);
1449
0
        if (r < 0)
1450
0
                return -errno;
1451
1452
0
        return !!S_ISDIR(st.st_mode);
1453
0
}
1454
1455
0
int free_and_strdup(char **p, const char *s) {
1456
0
        char *t;
1457
1458
0
        assert(p);
1459
1460
        /* Replaces a string pointer with an strdup()ed new string, possibly freeing the old one. */
1461
1462
0
        if (streq_ptr(*p, s))
1463
0
                return 0;
1464
1465
0
        if (s) {
1466
0
                t = strdup(s);
1467
0
                if (!t)
1468
0
                        return -ENOMEM;
1469
0
        } else
1470
0
                t = NULL;
1471
1472
0
        free(*p);
1473
0
        *p = t;
1474
1475
0
        return 1;
1476
0
}
1477
1478
DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
1479
1480
0
int read_line(FILE *f, size_t limit, char **ret) {
1481
0
        _cleanup_free_ char *buffer = NULL;
1482
0
        size_t n = 0, allocated = 0, count = 0;
1483
1484
0
        assert(f);
1485
1486
        /* Something like a bounded version of getline().
1487
         *
1488
         * Considers EOF, \n and \0 end of line delimiters, and does not include these delimiters in the string
1489
         * returned.
1490
         *
1491
         * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
1492
         * the number of characters in the returned string). When EOF is hit, 0 is returned.
1493
         *
1494
         * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
1495
         * delimiters. If the limit is hit we fail and return -ENOBUFS.
1496
         *
1497
         * If a line shall be skipped ret may be initialized as NULL. */
1498
1499
0
        if (ret) {
1500
0
                if (!GREEDY_REALLOC(buffer, allocated, 1))
1501
0
                        return -ENOMEM;
1502
0
        }
1503
1504
0
        {
1505
0
                _unused_ _cleanup_(funlockfilep) FILE *flocked = f;
1506
0
                flockfile(f);
1507
1508
0
                for (;;) {
1509
0
                        int c;
1510
1511
0
                        if (n >= limit)
1512
0
                                return -ENOBUFS;
1513
1514
0
                        errno = 0;
1515
0
                        c = fgetc_unlocked(f);
1516
0
                        if (c == EOF) {
1517
                                /* if we read an error, and have no data to return, then propagate the error */
1518
0
                                if (ferror_unlocked(f) && n == 0)
1519
0
                                        return errno > 0 ? -errno : -EIO;
1520
1521
0
                                break;
1522
0
                        }
1523
1524
0
                        count++;
1525
1526
0
                        if (IN_SET(c, '\n', 0)) /* Reached a delimiter */
1527
0
                                break;
1528
1529
0
                        if (ret) {
1530
0
                                if (!GREEDY_REALLOC(buffer, allocated, n + 2))
1531
0
                                        return -ENOMEM;
1532
1533
0
                                buffer[n] = (char) c;
1534
0
                        }
1535
1536
0
                        n++;
1537
0
                }
1538
0
        }
1539
1540
0
        if (ret) {
1541
0
                buffer[n] = 0;
1542
1543
0
                *ret = buffer;
1544
0
                buffer = NULL;
1545
0
        }
1546
1547
0
        return (int) count;
1548
0
}
1549
1550
0
char *delete_trailing_chars(char *s, const char *bad) {
1551
0
        char *p, *c = s;
1552
1553
        /* Drops all specified bad characters, at the end of the string */
1554
1555
0
        if (!s)
1556
0
                return NULL;
1557
1558
0
        if (!bad)
1559
0
                bad = WHITESPACE;
1560
1561
0
        for (p = s; *p; p++)
1562
0
                if (!strchr(bad, *p))
1563
0
                        c = p + 1;
1564
1565
0
        *c = 0;
1566
1567
0
        return s;
1568
0
}
1569
1570
0
char *strstrip(char *s) {
1571
0
        if (!s)
1572
0
                return NULL;
1573
1574
0
        delete_trailing_chars(s, WHITESPACE);
1575
0
        return s + strspn(s, WHITESPACE);
1576
0
}