chiark / gitweb /
implement drop-in directories
[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 int parse_boolean(const char *v) {
101         assert(v);
102
103         if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
104                 return 1;
105         else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
106                 return 0;
107
108         return -EINVAL;
109 }
110
111 int safe_atou(const char *s, unsigned *ret_u) {
112         char *x = NULL;
113         unsigned long l;
114
115         assert(s);
116         assert(ret_u);
117
118         errno = 0;
119         l = strtoul(s, &x, 0);
120
121         if (!x || *x || errno)
122                 return errno ? -errno : -EINVAL;
123
124         if ((unsigned long) (unsigned) l != l)
125                 return -ERANGE;
126
127         *ret_u = (unsigned) l;
128         return 0;
129 }
130
131 int safe_atoi(const char *s, int *ret_i) {
132         char *x = NULL;
133         long l;
134
135         assert(s);
136         assert(ret_i);
137
138         errno = 0;
139         l = strtol(s, &x, 0);
140
141         if (!x || *x || errno)
142                 return errno ? -errno : -EINVAL;
143
144         if ((long) (int) l != l)
145                 return -ERANGE;
146
147         *ret_i = (int) l;
148         return 0;
149 }
150
151 int safe_atolu(const char *s, long unsigned *ret_lu) {
152         char *x = NULL;
153         unsigned long l;
154
155         assert(s);
156         assert(ret_lu);
157
158         errno = 0;
159         l = strtoul(s, &x, 0);
160
161         if (!x || *x || errno)
162                 return errno ? -errno : -EINVAL;
163
164         *ret_lu = l;
165         return 0;
166 }
167
168 int safe_atoli(const char *s, long int *ret_li) {
169         char *x = NULL;
170         long l;
171
172         assert(s);
173         assert(ret_li);
174
175         errno = 0;
176         l = strtol(s, &x, 0);
177
178         if (!x || *x || errno)
179                 return errno ? -errno : -EINVAL;
180
181         *ret_li = l;
182         return 0;
183 }
184
185 int safe_atollu(const char *s, long long unsigned *ret_llu) {
186         char *x = NULL;
187         unsigned long long l;
188
189         assert(s);
190         assert(ret_llu);
191
192         errno = 0;
193         l = strtoull(s, &x, 0);
194
195         if (!x || *x || errno)
196                 return errno ? -errno : -EINVAL;
197
198         *ret_llu = l;
199         return 0;
200 }
201
202 int safe_atolli(const char *s, long long int *ret_lli) {
203         char *x = NULL;
204         long long l;
205
206         assert(s);
207         assert(ret_lli);
208
209         errno = 0;
210         l = strtoll(s, &x, 0);
211
212         if (!x || *x || errno)
213                 return errno ? -errno : -EINVAL;
214
215         *ret_lli = l;
216         return 0;
217 }
218
219 /* Split a string into words. */
220 char *split_spaces(const char *c, size_t *l, char **state) {
221         char *current;
222
223         current = *state ? *state : (char*) c;
224
225         if (!*current || *c == 0)
226                 return NULL;
227
228         current += strspn(current, WHITESPACE);
229         *l = strcspn(current, WHITESPACE);
230         *state = current+*l;
231
232         return (char*) current;
233 }
234
235 /* Split a string into words, but consider strings enclosed in '' and
236  * "" as words even if they include spaces. */
237 char *split_quoted(const char *c, size_t *l, char **state) {
238         char *current;
239
240         current = *state ? *state : (char*) c;
241
242         if (!*current || *c == 0)
243                 return NULL;
244
245         current += strspn(current, WHITESPACE);
246
247         if (*current == '\'') {
248                 current ++;
249                 *l = strcspn(current, "'");
250                 *state = current+*l;
251
252                 if (**state == '\'')
253                         (*state)++;
254         } else if (*current == '\"') {
255                 current ++;
256                 *l = strcspn(current+1, "\"");
257                 *state = current+*l;
258
259                 if (**state == '\"')
260                         (*state)++;
261         } else {
262                 *l = strcspn(current, WHITESPACE);
263                 *state = current+*l;
264         }
265
266         /* FIXME: Cannot deal with strings that have spaces AND ticks
267          * in them */
268
269         return (char*) current;
270 }
271
272 const char *sigchld_code(int code) {
273
274         if (code == CLD_EXITED)
275                 return "exited";
276         else if (code == CLD_KILLED)
277                 return "killed";
278         else if (code == CLD_DUMPED)
279                 return "dumped";
280         else if (code == CLD_TRAPPED)
281                 return "trapped";
282         else if (code == CLD_STOPPED)
283                 return "stopped";
284         else if (code == CLD_CONTINUED)
285                 return "continued";
286
287         return "unknown";
288 }
289
290 int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
291         int r;
292         FILE *f;
293         char fn[132], line[256], *p;
294         long long unsigned ppid;
295
296         assert(pid >= 0);
297         assert(_ppid);
298
299         assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%llu/stat", (unsigned long long) pid) < (int) (sizeof(fn)-1));
300         fn[sizeof(fn)-1] = 0;
301
302         if (!(f = fopen(fn, "r")))
303                 return -errno;
304
305         if (!(fgets(line, sizeof(line), f))) {
306                 r = -errno;
307                 fclose(f);
308                 return r;
309         }
310
311         fclose(f);
312
313         /* Let's skip the pid and comm fields. The latter is enclosed
314          * in () but does not escape any () in its value, so let's
315          * skip over it manually */
316
317         if (!(p = strrchr(line, ')')))
318                 return -EIO;
319
320         p++;
321
322         if (sscanf(p, " "
323                    "%*c "  /* state */
324                    "%llu ", /* ppid */
325                    &ppid) != 1)
326                 return -EIO;
327
328         if ((long long unsigned) (pid_t) ppid != ppid)
329                 return -ERANGE;
330
331         *_ppid = (pid_t) ppid;
332
333         return 0;
334 }
335
336 int write_one_line_file(const char *fn, const char *line) {
337         FILE *f;
338         int r;
339
340         assert(fn);
341         assert(line);
342
343         if (!(f = fopen(fn, "we")))
344                 return -errno;
345
346         if (fputs(line, f) < 0) {
347                 r = -errno;
348                 goto finish;
349         }
350
351         r = 0;
352 finish:
353         fclose(f);
354         return r;
355 }
356
357 int read_one_line_file(const char *fn, char **line) {
358         FILE *f;
359         int r;
360         char t[64], *c;
361
362         assert(fn);
363         assert(line);
364
365         if (!(f = fopen(fn, "re")))
366                 return -errno;
367
368         if (!(fgets(t, sizeof(t), f))) {
369                 r = -errno;
370                 goto finish;
371         }
372
373         if (!(c = strdup(t))) {
374                 r = -ENOMEM;
375                 goto finish;
376         }
377
378         *line = c;
379         r = 0;
380
381 finish:
382         fclose(f);
383         return r;
384 }
385
386 char *strappend(const char *s, const char *suffix) {
387         size_t a, b;
388         char *r;
389
390         assert(s);
391         assert(suffix);
392
393         a = strlen(s);
394         b = strlen(suffix);
395
396         if (!(r = new(char, a+b+1)))
397                 return NULL;
398
399         memcpy(r, s, a);
400         memcpy(r+a, suffix, b);
401         r[a+b] = 0;
402
403         return r;
404 }
405
406 int readlink_malloc(const char *p, char **r) {
407         size_t l = 100;
408
409         assert(p);
410         assert(r);
411
412         for (;;) {
413                 char *c;
414                 ssize_t n;
415
416                 if (!(c = new(char, l)))
417                         return -ENOMEM;
418
419                 if ((n = readlink(p, c, l-1)) < 0) {
420                         int ret = -errno;
421                         free(c);
422                         return ret;
423                 }
424
425                 if ((size_t) n < l-1) {
426                         c[n] = 0;
427                         *r = c;
428                         return 0;
429                 }
430
431                 free(c);
432                 l *= 2;
433         }
434 }
435
436 char *file_name_from_path(const char *p) {
437         char *r;
438
439         assert(p);
440
441         if ((r = strrchr(p, '/')))
442                 return r + 1;
443
444         return (char*) p;
445 }
446
447 bool path_is_absolute(const char *p) {
448         assert(p);
449
450         return p[0] == '/';
451 }
452
453 bool is_path(const char *p) {
454
455         return !!strchr(p, '/');
456 }
457
458 char *path_make_absolute(const char *p, const char *prefix) {
459         char *r;
460
461         assert(p);
462
463         if (path_is_absolute(p) || !prefix)
464                 return strdup(p);
465
466         if (asprintf(&r, "%s/%s", prefix, p) < 0)
467                 return NULL;
468
469         return r;
470 }