chiark / gitweb /
when resetting signal handlers, set them to SA_RESTART
[elogind.git] / util.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 #include <assert.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <stdlib.h>
8 #include <signal.h>
9 #include <stdio.h>
10
11 #include "macro.h"
12 #include "util.h"
13
14 usec_t now(clockid_t clock) {
15         struct timespec ts;
16
17         assert_se(clock_gettime(clock, &ts) == 0);
18
19         return timespec_load(&ts);
20 }
21
22 usec_t timespec_load(const struct timespec *ts) {
23         assert(ts);
24
25         return
26                 (usec_t) ts->tv_sec * USEC_PER_SEC +
27                 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
28 }
29
30 struct timespec *timespec_store(struct timespec *ts, usec_t u)  {
31         assert(ts);
32
33         ts->tv_sec = (time_t) (u / USEC_PER_SEC);
34         ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
35
36         return ts;
37 }
38
39 usec_t timeval_load(const struct timeval *tv) {
40         assert(tv);
41
42         return
43                 (usec_t) tv->tv_sec * USEC_PER_SEC +
44                 (usec_t) tv->tv_usec;
45 }
46
47 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
48         assert(tv);
49
50         tv->tv_sec = (time_t) (u / USEC_PER_SEC);
51         tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
52
53         return tv;
54 }
55
56 bool endswith(const char *s, const char *postfix) {
57         size_t sl, pl;
58
59         assert(s);
60         assert(postfix);
61
62         sl = strlen(s);
63         pl = strlen(postfix);
64
65         if (sl < pl)
66                 return false;
67
68         return memcmp(s + sl - pl, postfix, pl) == 0;
69 }
70
71 bool startswith(const char *s, const char *prefix) {
72         size_t sl, pl;
73
74         assert(s);
75         assert(prefix);
76
77         sl = strlen(s);
78         pl = strlen(prefix);
79
80         if (sl < pl)
81                 return false;
82
83         return memcmp(s, prefix, pl) == 0;
84 }
85
86 int close_nointr(int fd) {
87         assert(fd >= 0);
88
89         for (;;) {
90                 int r;
91
92                 if ((r = close(fd)) >= 0)
93                         return r;
94
95                 if (errno != EINTR)
96                         return r;
97         }
98 }
99
100 void close_nointr_nofail(int fd) {
101
102         /* like close_nointr() but cannot fail, and guarantees errno
103          * is unchanged */
104
105         assert_se(close_nointr(fd) == 0);
106 }
107
108 int parse_boolean(const char *v) {
109         assert(v);
110
111         if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
112                 return 1;
113         else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
114                 return 0;
115
116         return -EINVAL;
117 }
118
119 int safe_atou(const char *s, unsigned *ret_u) {
120         char *x = NULL;
121         unsigned long l;
122
123         assert(s);
124         assert(ret_u);
125
126         errno = 0;
127         l = strtoul(s, &x, 0);
128
129         if (!x || *x || errno)
130                 return errno ? -errno : -EINVAL;
131
132         if ((unsigned long) (unsigned) l != l)
133                 return -ERANGE;
134
135         *ret_u = (unsigned) l;
136         return 0;
137 }
138
139 int safe_atoi(const char *s, int *ret_i) {
140         char *x = NULL;
141         long l;
142
143         assert(s);
144         assert(ret_i);
145
146         errno = 0;
147         l = strtol(s, &x, 0);
148
149         if (!x || *x || errno)
150                 return errno ? -errno : -EINVAL;
151
152         if ((long) (int) l != l)
153                 return -ERANGE;
154
155         *ret_i = (int) l;
156         return 0;
157 }
158
159 int safe_atolu(const char *s, long unsigned *ret_lu) {
160         char *x = NULL;
161         unsigned long l;
162
163         assert(s);
164         assert(ret_lu);
165
166         errno = 0;
167         l = strtoul(s, &x, 0);
168
169         if (!x || *x || errno)
170                 return errno ? -errno : -EINVAL;
171
172         *ret_lu = l;
173         return 0;
174 }
175
176 int safe_atoli(const char *s, long int *ret_li) {
177         char *x = NULL;
178         long l;
179
180         assert(s);
181         assert(ret_li);
182
183         errno = 0;
184         l = strtol(s, &x, 0);
185
186         if (!x || *x || errno)
187                 return errno ? -errno : -EINVAL;
188
189         *ret_li = l;
190         return 0;
191 }
192
193 int safe_atollu(const char *s, long long unsigned *ret_llu) {
194         char *x = NULL;
195         unsigned long long l;
196
197         assert(s);
198         assert(ret_llu);
199
200         errno = 0;
201         l = strtoull(s, &x, 0);
202
203         if (!x || *x || errno)
204                 return errno ? -errno : -EINVAL;
205
206         *ret_llu = l;
207         return 0;
208 }
209
210 int safe_atolli(const char *s, long long int *ret_lli) {
211         char *x = NULL;
212         long long l;
213
214         assert(s);
215         assert(ret_lli);
216
217         errno = 0;
218         l = strtoll(s, &x, 0);
219
220         if (!x || *x || errno)
221                 return errno ? -errno : -EINVAL;
222
223         *ret_lli = l;
224         return 0;
225 }
226
227 /* Split a string into words. */
228 char *split_spaces(const char *c, size_t *l, char **state) {
229         char *current;
230
231         current = *state ? *state : (char*) c;
232
233         if (!*current || *c == 0)
234                 return NULL;
235
236         current += strspn(current, WHITESPACE);
237         *l = strcspn(current, WHITESPACE);
238         *state = current+*l;
239
240         return (char*) current;
241 }
242
243 /* Split a string into words, but consider strings enclosed in '' and
244  * "" as words even if they include spaces. */
245 char *split_quoted(const char *c, size_t *l, char **state) {
246         char *current;
247
248         current = *state ? *state : (char*) c;
249
250         if (!*current || *c == 0)
251                 return NULL;
252
253         current += strspn(current, WHITESPACE);
254
255         if (*current == '\'') {
256                 current ++;
257                 *l = strcspn(current, "'");
258                 *state = current+*l;
259
260                 if (**state == '\'')
261                         (*state)++;
262         } else if (*current == '\"') {
263                 current ++;
264                 *l = strcspn(current, "\"");
265                 *state = current+*l;
266
267                 if (**state == '\"')
268                         (*state)++;
269         } else {
270                 *l = strcspn(current, WHITESPACE);
271                 *state = current+*l;
272         }
273
274         /* FIXME: Cannot deal with strings that have spaces AND ticks
275          * in them */
276
277         return (char*) current;
278 }
279
280 const char *sigchld_code(int code) {
281
282         if (code == CLD_EXITED)
283                 return "exited";
284         else if (code == CLD_KILLED)
285                 return "killed";
286         else if (code == CLD_DUMPED)
287                 return "dumped";
288         else if (code == CLD_TRAPPED)
289                 return "trapped";
290         else if (code == CLD_STOPPED)
291                 return "stopped";
292         else if (code == CLD_CONTINUED)
293                 return "continued";
294
295         return "unknown";
296 }
297
298 int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
299         int r;
300         FILE *f;
301         char fn[132], line[256], *p;
302         long long unsigned ppid;
303
304         assert(pid >= 0);
305         assert(_ppid);
306
307         assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%llu/stat", (unsigned long long) pid) < (int) (sizeof(fn)-1));
308         fn[sizeof(fn)-1] = 0;
309
310         if (!(f = fopen(fn, "r")))
311                 return -errno;
312
313         if (!(fgets(line, sizeof(line), f))) {
314                 r = -errno;
315                 fclose(f);
316                 return r;
317         }
318
319         fclose(f);
320
321         /* Let's skip the pid and comm fields. The latter is enclosed
322          * in () but does not escape any () in its value, so let's
323          * skip over it manually */
324
325         if (!(p = strrchr(line, ')')))
326                 return -EIO;
327
328         p++;
329
330         if (sscanf(p, " "
331                    "%*c "  /* state */
332                    "%llu ", /* ppid */
333                    &ppid) != 1)
334                 return -EIO;
335
336         if ((long long unsigned) (pid_t) ppid != ppid)
337                 return -ERANGE;
338
339         *_ppid = (pid_t) ppid;
340
341         return 0;
342 }
343
344 int write_one_line_file(const char *fn, const char *line) {
345         FILE *f;
346         int r;
347
348         assert(fn);
349         assert(line);
350
351         if (!(f = fopen(fn, "we")))
352                 return -errno;
353
354         if (fputs(line, f) < 0) {
355                 r = -errno;
356                 goto finish;
357         }
358
359         r = 0;
360 finish:
361         fclose(f);
362         return r;
363 }
364
365 int read_one_line_file(const char *fn, char **line) {
366         FILE *f;
367         int r;
368         char t[64], *c;
369
370         assert(fn);
371         assert(line);
372
373         if (!(f = fopen(fn, "re")))
374                 return -errno;
375
376         if (!(fgets(t, sizeof(t), f))) {
377                 r = -errno;
378                 goto finish;
379         }
380
381         if (!(c = strdup(t))) {
382                 r = -ENOMEM;
383                 goto finish;
384         }
385
386         *line = c;
387         r = 0;
388
389 finish:
390         fclose(f);
391         return r;
392 }
393
394 char *strappend(const char *s, const char *suffix) {
395         size_t a, b;
396         char *r;
397
398         assert(s);
399         assert(suffix);
400
401         a = strlen(s);
402         b = strlen(suffix);
403
404         if (!(r = new(char, a+b+1)))
405                 return NULL;
406
407         memcpy(r, s, a);
408         memcpy(r+a, suffix, b);
409         r[a+b] = 0;
410
411         return r;
412 }
413
414 int readlink_malloc(const char *p, char **r) {
415         size_t l = 100;
416
417         assert(p);
418         assert(r);
419
420         for (;;) {
421                 char *c;
422                 ssize_t n;
423
424                 if (!(c = new(char, l)))
425                         return -ENOMEM;
426
427                 if ((n = readlink(p, c, l-1)) < 0) {
428                         int ret = -errno;
429                         free(c);
430                         return ret;
431                 }
432
433                 if ((size_t) n < l-1) {
434                         c[n] = 0;
435                         *r = c;
436                         return 0;
437                 }
438
439                 free(c);
440                 l *= 2;
441         }
442 }
443
444 char *file_name_from_path(const char *p) {
445         char *r;
446
447         assert(p);
448
449         if ((r = strrchr(p, '/')))
450                 return r + 1;
451
452         return (char*) p;
453 }
454
455 bool path_is_absolute(const char *p) {
456         assert(p);
457
458         return p[0] == '/';
459 }
460
461 bool is_path(const char *p) {
462
463         return !!strchr(p, '/');
464 }
465
466 char *path_make_absolute(const char *p, const char *prefix) {
467         char *r;
468
469         assert(p);
470
471         if (path_is_absolute(p) || !prefix)
472                 return strdup(p);
473
474         if (asprintf(&r, "%s/%s", prefix, p) < 0)
475                 return NULL;
476
477         return r;
478 }
479
480 int reset_all_signal_handlers(void) {
481         int sig;
482
483         for (sig = 1; sig < _NSIG; sig++) {
484                 struct sigaction sa;
485
486                 if (sig == SIGKILL || sig == SIGSTOP)
487                         continue;
488
489                 zero(sa);
490                 sa.sa_handler = SIG_DFL;
491                 sa.sa_flags = SA_RESTART;
492
493                 /* On Linux the first two RT signals are reserved by
494                  * glibc, and sigaction() will return EINVAL for them. */
495                 if ((sigaction(sig, &sa, NULL) < 0))
496                         if (errno != EINVAL)
497                                 return -errno;
498         }
499
500     return 0;
501 }
502
503 char *strstrip(char *s) {
504         char *e, *l = NULL;
505
506         /* Drops trailing whitespace. Modifies the string in
507          * place. Returns pointer to first non-space character */
508
509         s += strspn(s, WHITESPACE);
510
511         for (e = s; *e; e++)
512                 if (!strchr(WHITESPACE, *e))
513                         l = e;
514
515         if (l)
516                 *(l+1) = 0;
517         else
518                 *s = 0;
519
520         return s;
521
522 }
523
524 char *file_in_same_dir(const char *path, const char *filename) {
525         char *e, *r;
526         size_t k;
527
528         assert(path);
529         assert(filename);
530
531         /* This removes the last component of path and appends
532          * filename, unless the latter is absolute anyway or the
533          * former isn't */
534
535         if (path_is_absolute(filename))
536                 return strdup(filename);
537
538         if (!(e = strrchr(path, '/')))
539                 return strdup(filename);
540
541         k = strlen(filename);
542         if (!(r = new(char, e-path+1+k+1)))
543                 return NULL;
544
545         memcpy(r, path, e-path+1);
546         memcpy(r+(e-path)+1, filename, k+1);
547
548         return r;
549 }