]>
Commit | Line | Data |
---|---|---|
60918275 LP |
1 | /*-*- Mode: C; c-basic-offset: 8 -*-*/ |
2 | ||
3 | #include <assert.h> | |
4 | #include <string.h> | |
5 | #include <unistd.h> | |
6 | #include <errno.h> | |
85261803 | 7 | #include <stdlib.h> |
034c6ed7 LP |
8 | #include <signal.h> |
9 | #include <stdio.h> | |
1dccbe19 LP |
10 | #include <syslog.h> |
11 | #include <sched.h> | |
12 | #include <sys/resource.h> | |
60918275 LP |
13 | |
14 | #include "macro.h" | |
15 | #include "util.h" | |
1dccbe19 LP |
16 | #include "ioprio.h" |
17 | #include "missing.h" | |
60918275 LP |
18 | |
19 | usec_t now(clockid_t clock) { | |
20 | struct timespec ts; | |
21 | ||
22 | assert_se(clock_gettime(clock, &ts) == 0); | |
23 | ||
24 | return timespec_load(&ts); | |
25 | } | |
26 | ||
27 | usec_t timespec_load(const struct timespec *ts) { | |
28 | assert(ts); | |
29 | ||
30 | return | |
31 | (usec_t) ts->tv_sec * USEC_PER_SEC + | |
32 | (usec_t) ts->tv_nsec / NSEC_PER_USEC; | |
33 | } | |
34 | ||
35 | struct timespec *timespec_store(struct timespec *ts, usec_t u) { | |
36 | assert(ts); | |
37 | ||
38 | ts->tv_sec = (time_t) (u / USEC_PER_SEC); | |
39 | ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC); | |
40 | ||
41 | return ts; | |
42 | } | |
43 | ||
44 | usec_t timeval_load(const struct timeval *tv) { | |
45 | assert(tv); | |
46 | ||
47 | return | |
48 | (usec_t) tv->tv_sec * USEC_PER_SEC + | |
49 | (usec_t) tv->tv_usec; | |
50 | } | |
51 | ||
52 | struct timeval *timeval_store(struct timeval *tv, usec_t u) { | |
53 | assert(tv); | |
54 | ||
55 | tv->tv_sec = (time_t) (u / USEC_PER_SEC); | |
56 | tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC); | |
57 | ||
58 | return tv; | |
59 | } | |
60 | ||
61 | bool endswith(const char *s, const char *postfix) { | |
62 | size_t sl, pl; | |
63 | ||
64 | assert(s); | |
65 | assert(postfix); | |
66 | ||
67 | sl = strlen(s); | |
68 | pl = strlen(postfix); | |
69 | ||
70 | if (sl < pl) | |
71 | return false; | |
72 | ||
73 | return memcmp(s + sl - pl, postfix, pl) == 0; | |
74 | } | |
75 | ||
76 | bool startswith(const char *s, const char *prefix) { | |
77 | size_t sl, pl; | |
78 | ||
79 | assert(s); | |
80 | assert(prefix); | |
81 | ||
82 | sl = strlen(s); | |
83 | pl = strlen(prefix); | |
84 | ||
85 | if (sl < pl) | |
86 | return false; | |
87 | ||
88 | return memcmp(s, prefix, pl) == 0; | |
89 | } | |
90 | ||
79d6d816 LP |
91 | bool first_word(const char *s, const char *word) { |
92 | size_t sl, wl; | |
93 | ||
94 | assert(s); | |
95 | assert(word); | |
96 | ||
97 | sl = strlen(s); | |
98 | wl = strlen(word); | |
99 | ||
100 | if (sl < wl) | |
101 | return false; | |
102 | ||
103 | if (memcmp(s, word, wl) != 0) | |
104 | return false; | |
105 | ||
106 | return (s[wl] == 0 || | |
107 | strchr(WHITESPACE, s[wl])); | |
108 | } | |
109 | ||
42f4e3c4 | 110 | int close_nointr(int fd) { |
60918275 LP |
111 | assert(fd >= 0); |
112 | ||
113 | for (;;) { | |
114 | int r; | |
115 | ||
116 | if ((r = close(fd)) >= 0) | |
117 | return r; | |
118 | ||
119 | if (errno != EINTR) | |
120 | return r; | |
121 | } | |
122 | } | |
85261803 | 123 | |
85f136b5 LP |
124 | void close_nointr_nofail(int fd) { |
125 | ||
126 | /* like close_nointr() but cannot fail, and guarantees errno | |
127 | * is unchanged */ | |
128 | ||
129 | assert_se(close_nointr(fd) == 0); | |
130 | } | |
131 | ||
85261803 LP |
132 | int parse_boolean(const char *v) { |
133 | assert(v); | |
134 | ||
44d8db9e | 135 | if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) |
85261803 | 136 | return 1; |
44d8db9e | 137 | else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) |
85261803 LP |
138 | return 0; |
139 | ||
140 | return -EINVAL; | |
141 | } | |
142 | ||
143 | int safe_atou(const char *s, unsigned *ret_u) { | |
144 | char *x = NULL; | |
034c6ed7 | 145 | unsigned long l; |
85261803 LP |
146 | |
147 | assert(s); | |
148 | assert(ret_u); | |
149 | ||
150 | errno = 0; | |
151 | l = strtoul(s, &x, 0); | |
152 | ||
153 | if (!x || *x || errno) | |
154 | return errno ? -errno : -EINVAL; | |
155 | ||
034c6ed7 | 156 | if ((unsigned long) (unsigned) l != l) |
85261803 LP |
157 | return -ERANGE; |
158 | ||
159 | *ret_u = (unsigned) l; | |
160 | return 0; | |
161 | } | |
162 | ||
163 | int safe_atoi(const char *s, int *ret_i) { | |
164 | char *x = NULL; | |
034c6ed7 | 165 | long l; |
85261803 LP |
166 | |
167 | assert(s); | |
168 | assert(ret_i); | |
169 | ||
170 | errno = 0; | |
171 | l = strtol(s, &x, 0); | |
172 | ||
173 | if (!x || *x || errno) | |
174 | return errno ? -errno : -EINVAL; | |
175 | ||
034c6ed7 | 176 | if ((long) (int) l != l) |
85261803 LP |
177 | return -ERANGE; |
178 | ||
034c6ed7 LP |
179 | *ret_i = (int) l; |
180 | return 0; | |
181 | } | |
182 | ||
183 | int safe_atolu(const char *s, long unsigned *ret_lu) { | |
184 | char *x = NULL; | |
185 | unsigned long l; | |
186 | ||
187 | assert(s); | |
188 | assert(ret_lu); | |
189 | ||
190 | errno = 0; | |
191 | l = strtoul(s, &x, 0); | |
192 | ||
193 | if (!x || *x || errno) | |
194 | return errno ? -errno : -EINVAL; | |
195 | ||
196 | *ret_lu = l; | |
197 | return 0; | |
198 | } | |
199 | ||
200 | int safe_atoli(const char *s, long int *ret_li) { | |
201 | char *x = NULL; | |
202 | long l; | |
203 | ||
204 | assert(s); | |
205 | assert(ret_li); | |
206 | ||
207 | errno = 0; | |
208 | l = strtol(s, &x, 0); | |
209 | ||
210 | if (!x || *x || errno) | |
211 | return errno ? -errno : -EINVAL; | |
212 | ||
213 | *ret_li = l; | |
214 | return 0; | |
215 | } | |
216 | ||
217 | int safe_atollu(const char *s, long long unsigned *ret_llu) { | |
218 | char *x = NULL; | |
219 | unsigned long long l; | |
220 | ||
221 | assert(s); | |
222 | assert(ret_llu); | |
223 | ||
224 | errno = 0; | |
225 | l = strtoull(s, &x, 0); | |
226 | ||
227 | if (!x || *x || errno) | |
228 | return errno ? -errno : -EINVAL; | |
229 | ||
230 | *ret_llu = l; | |
231 | return 0; | |
232 | } | |
233 | ||
234 | int safe_atolli(const char *s, long long int *ret_lli) { | |
235 | char *x = NULL; | |
236 | long long l; | |
237 | ||
238 | assert(s); | |
239 | assert(ret_lli); | |
240 | ||
241 | errno = 0; | |
242 | l = strtoll(s, &x, 0); | |
243 | ||
244 | if (!x || *x || errno) | |
245 | return errno ? -errno : -EINVAL; | |
246 | ||
247 | *ret_lli = l; | |
85261803 LP |
248 | return 0; |
249 | } | |
a41e8209 | 250 | |
a41e8209 LP |
251 | /* Split a string into words. */ |
252 | char *split_spaces(const char *c, size_t *l, char **state) { | |
253 | char *current; | |
254 | ||
255 | current = *state ? *state : (char*) c; | |
256 | ||
257 | if (!*current || *c == 0) | |
258 | return NULL; | |
259 | ||
260 | current += strspn(current, WHITESPACE); | |
261 | *l = strcspn(current, WHITESPACE); | |
262 | *state = current+*l; | |
263 | ||
264 | return (char*) current; | |
265 | } | |
034c6ed7 LP |
266 | |
267 | /* Split a string into words, but consider strings enclosed in '' and | |
268 | * "" as words even if they include spaces. */ | |
269 | char *split_quoted(const char *c, size_t *l, char **state) { | |
270 | char *current; | |
271 | ||
272 | current = *state ? *state : (char*) c; | |
273 | ||
274 | if (!*current || *c == 0) | |
275 | return NULL; | |
276 | ||
277 | current += strspn(current, WHITESPACE); | |
278 | ||
279 | if (*current == '\'') { | |
280 | current ++; | |
281 | *l = strcspn(current, "'"); | |
282 | *state = current+*l; | |
283 | ||
284 | if (**state == '\'') | |
285 | (*state)++; | |
286 | } else if (*current == '\"') { | |
287 | current ++; | |
b858b600 | 288 | *l = strcspn(current, "\""); |
034c6ed7 LP |
289 | *state = current+*l; |
290 | ||
291 | if (**state == '\"') | |
292 | (*state)++; | |
293 | } else { | |
294 | *l = strcspn(current, WHITESPACE); | |
295 | *state = current+*l; | |
296 | } | |
297 | ||
44d8db9e LP |
298 | /* FIXME: Cannot deal with strings that have spaces AND ticks |
299 | * in them */ | |
300 | ||
034c6ed7 LP |
301 | return (char*) current; |
302 | } | |
303 | ||
034c6ed7 LP |
304 | int get_parent_of_pid(pid_t pid, pid_t *_ppid) { |
305 | int r; | |
306 | FILE *f; | |
307 | char fn[132], line[256], *p; | |
308 | long long unsigned ppid; | |
309 | ||
310 | assert(pid >= 0); | |
311 | assert(_ppid); | |
312 | ||
313 | assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%llu/stat", (unsigned long long) pid) < (int) (sizeof(fn)-1)); | |
314 | fn[sizeof(fn)-1] = 0; | |
315 | ||
316 | if (!(f = fopen(fn, "r"))) | |
317 | return -errno; | |
318 | ||
319 | if (!(fgets(line, sizeof(line), f))) { | |
320 | r = -errno; | |
321 | fclose(f); | |
322 | return r; | |
323 | } | |
324 | ||
325 | fclose(f); | |
326 | ||
327 | /* Let's skip the pid and comm fields. The latter is enclosed | |
328 | * in () but does not escape any () in its value, so let's | |
329 | * skip over it manually */ | |
330 | ||
331 | if (!(p = strrchr(line, ')'))) | |
332 | return -EIO; | |
333 | ||
334 | p++; | |
335 | ||
336 | if (sscanf(p, " " | |
337 | "%*c " /* state */ | |
338 | "%llu ", /* ppid */ | |
339 | &ppid) != 1) | |
340 | return -EIO; | |
341 | ||
342 | if ((long long unsigned) (pid_t) ppid != ppid) | |
343 | return -ERANGE; | |
344 | ||
345 | *_ppid = (pid_t) ppid; | |
346 | ||
347 | return 0; | |
348 | } | |
349 | ||
350 | int write_one_line_file(const char *fn, const char *line) { | |
351 | FILE *f; | |
352 | int r; | |
353 | ||
354 | assert(fn); | |
355 | assert(line); | |
356 | ||
357 | if (!(f = fopen(fn, "we"))) | |
358 | return -errno; | |
359 | ||
360 | if (fputs(line, f) < 0) { | |
361 | r = -errno; | |
362 | goto finish; | |
363 | } | |
364 | ||
365 | r = 0; | |
366 | finish: | |
367 | fclose(f); | |
368 | return r; | |
369 | } | |
370 | ||
371 | int read_one_line_file(const char *fn, char **line) { | |
372 | FILE *f; | |
373 | int r; | |
374 | char t[64], *c; | |
375 | ||
376 | assert(fn); | |
377 | assert(line); | |
378 | ||
379 | if (!(f = fopen(fn, "re"))) | |
380 | return -errno; | |
381 | ||
382 | if (!(fgets(t, sizeof(t), f))) { | |
383 | r = -errno; | |
384 | goto finish; | |
385 | } | |
386 | ||
387 | if (!(c = strdup(t))) { | |
388 | r = -ENOMEM; | |
389 | goto finish; | |
390 | } | |
391 | ||
392 | *line = c; | |
393 | r = 0; | |
394 | ||
395 | finish: | |
396 | fclose(f); | |
397 | return r; | |
398 | } | |
44d8db9e LP |
399 | |
400 | char *strappend(const char *s, const char *suffix) { | |
401 | size_t a, b; | |
402 | char *r; | |
403 | ||
404 | assert(s); | |
405 | assert(suffix); | |
406 | ||
407 | a = strlen(s); | |
408 | b = strlen(suffix); | |
409 | ||
410 | if (!(r = new(char, a+b+1))) | |
411 | return NULL; | |
412 | ||
413 | memcpy(r, s, a); | |
414 | memcpy(r+a, suffix, b); | |
415 | r[a+b] = 0; | |
416 | ||
417 | return r; | |
418 | } | |
87f0e418 LP |
419 | |
420 | int readlink_malloc(const char *p, char **r) { | |
421 | size_t l = 100; | |
422 | ||
423 | assert(p); | |
424 | assert(r); | |
425 | ||
426 | for (;;) { | |
427 | char *c; | |
428 | ssize_t n; | |
429 | ||
430 | if (!(c = new(char, l))) | |
431 | return -ENOMEM; | |
432 | ||
433 | if ((n = readlink(p, c, l-1)) < 0) { | |
434 | int ret = -errno; | |
435 | free(c); | |
436 | return ret; | |
437 | } | |
438 | ||
439 | if ((size_t) n < l-1) { | |
440 | c[n] = 0; | |
441 | *r = c; | |
442 | return 0; | |
443 | } | |
444 | ||
445 | free(c); | |
446 | l *= 2; | |
447 | } | |
448 | } | |
449 | ||
450 | char *file_name_from_path(const char *p) { | |
451 | char *r; | |
452 | ||
453 | assert(p); | |
454 | ||
455 | if ((r = strrchr(p, '/'))) | |
456 | return r + 1; | |
457 | ||
458 | return (char*) p; | |
459 | } | |
0301abf4 LP |
460 | |
461 | bool path_is_absolute(const char *p) { | |
462 | assert(p); | |
463 | ||
464 | return p[0] == '/'; | |
465 | } | |
466 | ||
467 | bool is_path(const char *p) { | |
468 | ||
469 | return !!strchr(p, '/'); | |
470 | } | |
471 | ||
472 | char *path_make_absolute(const char *p, const char *prefix) { | |
473 | char *r; | |
474 | ||
475 | assert(p); | |
476 | ||
477 | if (path_is_absolute(p) || !prefix) | |
478 | return strdup(p); | |
479 | ||
480 | if (asprintf(&r, "%s/%s", prefix, p) < 0) | |
481 | return NULL; | |
482 | ||
483 | return r; | |
484 | } | |
2a987ee8 LP |
485 | |
486 | int reset_all_signal_handlers(void) { | |
487 | int sig; | |
488 | ||
489 | for (sig = 1; sig < _NSIG; sig++) { | |
490 | struct sigaction sa; | |
491 | ||
492 | if (sig == SIGKILL || sig == SIGSTOP) | |
493 | continue; | |
494 | ||
495 | zero(sa); | |
496 | sa.sa_handler = SIG_DFL; | |
431c32bf | 497 | sa.sa_flags = SA_RESTART; |
2a987ee8 LP |
498 | |
499 | /* On Linux the first two RT signals are reserved by | |
500 | * glibc, and sigaction() will return EINVAL for them. */ | |
501 | if ((sigaction(sig, &sa, NULL) < 0)) | |
502 | if (errno != EINVAL) | |
503 | return -errno; | |
504 | } | |
505 | ||
506 | return 0; | |
507 | } | |
4a72ff34 LP |
508 | |
509 | char *strstrip(char *s) { | |
510 | char *e, *l = NULL; | |
511 | ||
512 | /* Drops trailing whitespace. Modifies the string in | |
513 | * place. Returns pointer to first non-space character */ | |
514 | ||
515 | s += strspn(s, WHITESPACE); | |
516 | ||
517 | for (e = s; *e; e++) | |
518 | if (!strchr(WHITESPACE, *e)) | |
519 | l = e; | |
520 | ||
521 | if (l) | |
522 | *(l+1) = 0; | |
523 | else | |
524 | *s = 0; | |
525 | ||
526 | return s; | |
527 | ||
528 | } | |
529 | ||
530 | char *file_in_same_dir(const char *path, const char *filename) { | |
531 | char *e, *r; | |
532 | size_t k; | |
533 | ||
534 | assert(path); | |
535 | assert(filename); | |
536 | ||
537 | /* This removes the last component of path and appends | |
538 | * filename, unless the latter is absolute anyway or the | |
539 | * former isn't */ | |
540 | ||
541 | if (path_is_absolute(filename)) | |
542 | return strdup(filename); | |
543 | ||
544 | if (!(e = strrchr(path, '/'))) | |
545 | return strdup(filename); | |
546 | ||
547 | k = strlen(filename); | |
548 | if (!(r = new(char, e-path+1+k+1))) | |
549 | return NULL; | |
550 | ||
551 | memcpy(r, path, e-path+1); | |
552 | memcpy(r+(e-path)+1, filename, k+1); | |
553 | ||
554 | return r; | |
555 | } | |
fb624d04 LP |
556 | |
557 | char hexchar(int x) { | |
558 | static const char table[16] = "0123456789abcdef"; | |
559 | ||
560 | return table[x & 15]; | |
561 | } | |
4fe88d28 LP |
562 | |
563 | int unhexchar(char c) { | |
564 | ||
565 | if (c >= '0' && c <= '9') | |
566 | return c - '0'; | |
567 | ||
568 | if (c >= 'a' && c <= 'f') | |
569 | return c - 'a'; | |
570 | ||
571 | if (c >= 'A' && c <= 'F') | |
572 | return c - 'A'; | |
573 | ||
574 | return -1; | |
575 | } | |
576 | ||
577 | char octchar(int x) { | |
578 | return '0' + (x & 7); | |
579 | } | |
580 | ||
581 | int unoctchar(char c) { | |
582 | ||
583 | if (c >= '0' && c <= '7') | |
584 | return c - '0'; | |
585 | ||
586 | return -1; | |
587 | } | |
588 | ||
589 | char *cescape(const char *s) { | |
590 | char *r, *t; | |
591 | const char *f; | |
592 | ||
593 | assert(s); | |
594 | ||
595 | /* Does C style string escaping. */ | |
596 | ||
597 | if (!(r = new(char, strlen(s)*4 + 1))) | |
598 | return NULL; | |
599 | ||
600 | for (f = s, t = r; *f; f++) | |
601 | ||
602 | switch (*f) { | |
603 | ||
604 | case '\a': | |
605 | *(t++) = '\\'; | |
606 | *(t++) = 'a'; | |
607 | break; | |
608 | case '\b': | |
609 | *(t++) = '\\'; | |
610 | *(t++) = 'b'; | |
611 | break; | |
612 | case '\f': | |
613 | *(t++) = '\\'; | |
614 | *(t++) = 'f'; | |
615 | break; | |
616 | case '\n': | |
617 | *(t++) = '\\'; | |
618 | *(t++) = 'n'; | |
619 | break; | |
620 | case '\r': | |
621 | *(t++) = '\\'; | |
622 | *(t++) = 'r'; | |
623 | break; | |
624 | case '\t': | |
625 | *(t++) = '\\'; | |
626 | *(t++) = 't'; | |
627 | break; | |
628 | case '\v': | |
629 | *(t++) = '\\'; | |
630 | *(t++) = 'v'; | |
631 | break; | |
632 | case '\\': | |
633 | *(t++) = '\\'; | |
634 | *(t++) = '\\'; | |
635 | break; | |
636 | case '"': | |
637 | *(t++) = '\\'; | |
638 | *(t++) = '"'; | |
639 | break; | |
640 | case '\'': | |
641 | *(t++) = '\\'; | |
642 | *(t++) = '\''; | |
643 | break; | |
644 | ||
645 | default: | |
646 | /* For special chars we prefer octal over | |
647 | * hexadecimal encoding, simply because glib's | |
648 | * g_strescape() does the same */ | |
649 | if ((*f < ' ') || (*f >= 127)) { | |
650 | *(t++) = '\\'; | |
651 | *(t++) = octchar((unsigned char) *f >> 6); | |
652 | *(t++) = octchar((unsigned char) *f >> 3); | |
653 | *(t++) = octchar((unsigned char) *f); | |
654 | } else | |
655 | *(t++) = *f; | |
656 | break; | |
657 | } | |
658 | ||
659 | *t = 0; | |
660 | ||
661 | return r; | |
662 | } | |
663 | ||
664 | char *cunescape(const char *s) { | |
665 | char *r, *t; | |
666 | const char *f; | |
667 | ||
668 | assert(s); | |
669 | ||
670 | /* Undoes C style string escaping */ | |
671 | ||
672 | if (!(r = new(char, strlen(s)+1))) | |
673 | return r; | |
674 | ||
675 | for (f = s, t = r; *f; f++) { | |
676 | ||
677 | if (*f != '\\') { | |
678 | *(t++) = *f; | |
679 | continue; | |
680 | } | |
681 | ||
682 | f++; | |
683 | ||
684 | switch (*f) { | |
685 | ||
686 | case 'a': | |
687 | *(t++) = '\a'; | |
688 | break; | |
689 | case 'b': | |
690 | *(t++) = '\b'; | |
691 | break; | |
692 | case 'f': | |
693 | *(t++) = '\f'; | |
694 | break; | |
695 | case 'n': | |
696 | *(t++) = '\n'; | |
697 | break; | |
698 | case 'r': | |
699 | *(t++) = '\r'; | |
700 | break; | |
701 | case 't': | |
702 | *(t++) = '\t'; | |
703 | break; | |
704 | case 'v': | |
705 | *(t++) = '\v'; | |
706 | break; | |
707 | case '\\': | |
708 | *(t++) = '\\'; | |
709 | break; | |
710 | case '"': | |
711 | *(t++) = '"'; | |
712 | break; | |
713 | case '\'': | |
714 | *(t++) = '\''; | |
715 | break; | |
716 | ||
717 | case 'x': { | |
718 | /* hexadecimal encoding */ | |
719 | int a, b; | |
720 | ||
721 | if ((a = unhexchar(f[1])) < 0 || | |
722 | (b = unhexchar(f[2])) < 0) { | |
723 | /* Invalid escape code, let's take it literal then */ | |
724 | *(t++) = '\\'; | |
725 | *(t++) = 'x'; | |
726 | } else { | |
727 | *(t++) = (char) ((a << 4) | b); | |
728 | f += 2; | |
729 | } | |
730 | ||
731 | break; | |
732 | } | |
733 | ||
734 | case '0': | |
735 | case '1': | |
736 | case '2': | |
737 | case '3': | |
738 | case '4': | |
739 | case '5': | |
740 | case '6': | |
741 | case '7': { | |
742 | /* octal encoding */ | |
743 | int a, b, c; | |
744 | ||
745 | if ((a = unoctchar(f[0])) < 0 || | |
746 | (b = unoctchar(f[1])) < 0 || | |
747 | (c = unoctchar(f[2])) < 0) { | |
748 | /* Invalid escape code, let's take it literal then */ | |
749 | *(t++) = '\\'; | |
750 | *(t++) = f[0]; | |
751 | } else { | |
752 | *(t++) = (char) ((a << 6) | (b << 3) | c); | |
753 | f += 2; | |
754 | } | |
755 | ||
756 | break; | |
757 | } | |
758 | ||
759 | case 0: | |
760 | /* premature end of string.*/ | |
761 | *(t++) = '\\'; | |
762 | goto finish; | |
763 | ||
764 | default: | |
765 | /* Invalid escape code, let's take it literal then */ | |
766 | *(t++) = '\\'; | |
767 | *(t++) = 'f'; | |
768 | break; | |
769 | } | |
770 | } | |
771 | ||
772 | finish: | |
773 | *t = 0; | |
774 | return r; | |
775 | } | |
776 | ||
777 | ||
778 | char *xescape(const char *s, const char *bad) { | |
779 | char *r, *t; | |
780 | const char *f; | |
781 | ||
782 | /* Escapes all chars in bad, in addition to \ and all special | |
783 | * chars, in \xFF style escaping. May be reversed with | |
784 | * cunescape. */ | |
785 | ||
786 | if (!(r = new(char, strlen(s)*4+1))) | |
787 | return NULL; | |
788 | ||
789 | for (f = s, t = r; *f; f++) { | |
790 | ||
791 | if (*f < ' ' || *f >= 127 || | |
792 | *f == '\\' || strchr(bad, *f)) { | |
793 | *(t++) = '\\'; | |
794 | *(t++) = 'x'; | |
795 | *(t++) = hexchar(*f >> 4); | |
796 | *(t++) = hexchar(*f); | |
797 | } else | |
798 | *(t++) = *f; | |
799 | } | |
800 | ||
801 | *t = 0; | |
802 | ||
803 | return r; | |
804 | } | |
805 | ||
806 | char *path_kill_slashes(char *path) { | |
807 | char *f, *t; | |
808 | bool slash = false; | |
809 | ||
810 | /* Removes redundant inner and trailing slashes. Modifies the | |
811 | * passed string in-place. | |
812 | * | |
813 | * ///foo///bar/ becomes /foo/bar | |
814 | */ | |
815 | ||
816 | for (f = path, t = path; *f; f++) { | |
817 | ||
818 | if (*f == '/') { | |
819 | slash = true; | |
820 | continue; | |
821 | } | |
822 | ||
823 | if (slash) { | |
824 | slash = false; | |
825 | *(t++) = '/'; | |
826 | } | |
827 | ||
828 | *(t++) = *f; | |
829 | } | |
830 | ||
831 | /* Special rule, if we are talking of the root directory, a | |
832 | trailing slash is good */ | |
833 | ||
834 | if (t == path && slash) | |
835 | *(t++) = '/'; | |
836 | ||
837 | *t = 0; | |
838 | return path; | |
839 | } | |
840 | ||
841 | bool path_startswith(const char *path, const char *prefix) { | |
842 | assert(path); | |
843 | assert(prefix); | |
844 | ||
845 | if ((path[0] == '/') != (prefix[0] == '/')) | |
846 | return false; | |
847 | ||
848 | for (;;) { | |
849 | size_t a, b; | |
850 | ||
851 | path += strspn(path, "/"); | |
852 | prefix += strspn(prefix, "/"); | |
853 | ||
854 | if (*prefix == 0) | |
855 | return true; | |
856 | ||
857 | if (*path == 0) | |
858 | return false; | |
859 | ||
860 | a = strcspn(path, "/"); | |
861 | b = strcspn(prefix, "/"); | |
862 | ||
863 | if (a != b) | |
864 | return false; | |
865 | ||
866 | if (memcmp(path, prefix, a) != 0) | |
867 | return false; | |
868 | ||
869 | path += a; | |
870 | prefix += b; | |
871 | } | |
872 | } | |
873 | ||
874 | char *ascii_strlower(char *path) { | |
875 | char *p; | |
876 | ||
877 | assert(path); | |
878 | ||
879 | for (p = path; *p; p++) | |
880 | if (*p >= 'A' && *p <= 'Z') | |
881 | *p = *p - 'A' + 'a'; | |
882 | ||
883 | return p; | |
884 | } | |
1dccbe19 LP |
885 | |
886 | static const char *const ioprio_class_table[] = { | |
887 | [IOPRIO_CLASS_NONE] = "none", | |
888 | [IOPRIO_CLASS_RT] = "realtime", | |
889 | [IOPRIO_CLASS_BE] = "best-effort", | |
890 | [IOPRIO_CLASS_IDLE] = "idle" | |
891 | }; | |
892 | ||
893 | DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int); | |
894 | ||
895 | static const char *const sigchld_code_table[] = { | |
896 | [CLD_EXITED] = "exited", | |
897 | [CLD_KILLED] = "killed", | |
898 | [CLD_DUMPED] = "dumped", | |
899 | [CLD_TRAPPED] = "trapped", | |
900 | [CLD_STOPPED] = "stopped", | |
901 | [CLD_CONTINUED] = "continued", | |
902 | }; | |
903 | ||
904 | DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int); | |
905 | ||
906 | static const char *const log_facility_table[LOG_NFACILITIES] = { | |
907 | [LOG_FAC(LOG_KERN)] = "kern", | |
908 | [LOG_FAC(LOG_USER)] = "user", | |
909 | [LOG_FAC(LOG_MAIL)] = "mail", | |
910 | [LOG_FAC(LOG_DAEMON)] = "daemon", | |
911 | [LOG_FAC(LOG_AUTH)] = "auth", | |
912 | [LOG_FAC(LOG_SYSLOG)] = "syslog", | |
913 | [LOG_FAC(LOG_LPR)] = "lpr", | |
914 | [LOG_FAC(LOG_NEWS)] = "news", | |
915 | [LOG_FAC(LOG_UUCP)] = "uucp", | |
916 | [LOG_FAC(LOG_CRON)] = "cron", | |
917 | [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", | |
918 | [LOG_FAC(LOG_FTP)] = "ftp", | |
919 | [LOG_FAC(LOG_LOCAL0)] = "local0", | |
920 | [LOG_FAC(LOG_LOCAL1)] = "local1", | |
921 | [LOG_FAC(LOG_LOCAL2)] = "local2", | |
922 | [LOG_FAC(LOG_LOCAL3)] = "local3", | |
923 | [LOG_FAC(LOG_LOCAL4)] = "local4", | |
924 | [LOG_FAC(LOG_LOCAL5)] = "local5", | |
925 | [LOG_FAC(LOG_LOCAL6)] = "local6", | |
926 | [LOG_FAC(LOG_LOCAL7)] = "local7" | |
927 | }; | |
928 | ||
929 | DEFINE_STRING_TABLE_LOOKUP(log_facility, int); | |
930 | ||
931 | static const char *const log_level_table[] = { | |
932 | [LOG_EMERG] = "emerg", | |
933 | [LOG_ALERT] = "alert", | |
934 | [LOG_CRIT] = "crit", | |
935 | [LOG_ERR] = "err", | |
936 | [LOG_WARNING] = "warning", | |
937 | [LOG_NOTICE] = "notice", | |
938 | [LOG_INFO] = "info", | |
939 | [LOG_DEBUG] = "debug" | |
940 | }; | |
941 | ||
942 | DEFINE_STRING_TABLE_LOOKUP(log_level, int); | |
943 | ||
944 | static const char* const sched_policy_table[] = { | |
945 | [SCHED_OTHER] = "other", | |
946 | [SCHED_BATCH] = "batch", | |
947 | [SCHED_IDLE] = "idle", | |
948 | [SCHED_FIFO] = "fifo", | |
949 | [SCHED_RR] = "rr" | |
950 | }; | |
951 | ||
952 | DEFINE_STRING_TABLE_LOOKUP(sched_policy, int); | |
953 | ||
954 | static const char* const rlimit_table[] = { | |
955 | [RLIMIT_CPU] = "LimitCPU", | |
956 | [RLIMIT_FSIZE] = "LimitFSIZE", | |
957 | [RLIMIT_DATA] = "LimitDATA", | |
958 | [RLIMIT_STACK] = "LimitSTACK", | |
959 | [RLIMIT_CORE] = "LimitCORE", | |
960 | [RLIMIT_RSS] = "LimitRSS", | |
961 | [RLIMIT_NOFILE] = "LimitNOFILE", | |
962 | [RLIMIT_AS] = "LimitAS", | |
963 | [RLIMIT_NPROC] = "LimitNPROC", | |
964 | [RLIMIT_MEMLOCK] = "LimitMEMLOCK", | |
965 | [RLIMIT_LOCKS] = "LimitLOCKS", | |
966 | [RLIMIT_SIGPENDING] = "LimitSIGPENDING", | |
967 | [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE", | |
968 | [RLIMIT_NICE] = "LimitNICE", | |
969 | [RLIMIT_RTPRIO] = "LimitRTPRIO", | |
970 | [RLIMIT_RTTIME] = "LimitRTTIME" | |
971 | }; | |
972 | ||
973 | DEFINE_STRING_TABLE_LOOKUP(rlimit, int); |