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 | } |