]> git.ipfire.org Git - thirdparty/dracut.git/blame - install/util.c
Merge branch 'master' of github.com:haraldh/dracut
[thirdparty/dracut.git] / install / util.c
CommitLineData
026b81e9
HH
1/***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <string.h>
21#include <unistd.h>
22#include <errno.h>
23#include <fcntl.h>
24#include <sys/types.h>
25#include <sys/syscall.h>
26
27#include "util.h"
28
29static inline pid_t gettid(void) {
30 return (pid_t) syscall(SYS_gettid);
31}
32
33size_t page_size(void) {
34 static __thread size_t pgsz = 0;
35 long r;
36
37 if (_likely_(pgsz > 0))
38 return pgsz;
39
40 assert_se((r = sysconf(_SC_PAGESIZE)) > 0);
41
42 pgsz = (size_t) r;
43
44 return pgsz;
45}
46
47bool endswith(const char *s, const char *postfix) {
48 size_t sl, pl;
49
50 assert(s);
51 assert(postfix);
52
53 sl = strlen(s);
54 pl = strlen(postfix);
55
56 if (pl == 0)
57 return true;
58
59 if (sl < pl)
60 return false;
61
62 return memcmp(s + sl - pl, postfix, pl) == 0;
63}
64int close_nointr(int fd) {
65 assert(fd >= 0);
66
67 for (;;) {
68 int r;
69
70 r = close(fd);
71 if (r >= 0)
72 return r;
73
74 if (errno != EINTR)
75 return -errno;
76 }
77}
78
79void close_nointr_nofail(int fd) {
80 int saved_errno = errno;
81
82 /* like close_nointr() but cannot fail, and guarantees errno
83 * is unchanged */
84
85 assert_se(close_nointr(fd) == 0);
86
87 errno = saved_errno;
88}
89
90int open_terminal(const char *name, int mode) {
91 int fd, r;
92 unsigned c = 0;
93
94 /*
95 * If a TTY is in the process of being closed opening it might
96 * cause EIO. This is horribly awful, but unlikely to be
97 * changed in the kernel. Hence we work around this problem by
98 * retrying a couple of times.
99 *
100 * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
101 */
102
103 for (;;) {
104 if ((fd = open(name, mode)) >= 0)
105 break;
106
107 if (errno != EIO)
108 return -errno;
109
110 if (c >= 20)
111 return -errno;
112
113 usleep(50 * USEC_PER_MSEC);
114 c++;
115 }
116
117 if (fd < 0)
118 return -errno;
119
120 if ((r = isatty(fd)) < 0) {
121 close_nointr_nofail(fd);
122 return -errno;
123 }
124
125 if (!r) {
126 close_nointr_nofail(fd);
127 return -ENOTTY;
128 }
129
130 return fd;
131}
132
133bool streq_ptr(const char *a, const char *b) {
134
135 /* Like streq(), but tries to make sense of NULL pointers */
136
137 if (a && b)
138 return streq(a, b);
139
140 if (!a && !b)
141 return true;
142
143 return false;
144}
145bool is_main_thread(void) {
146 static __thread int cached = 0;
147
148 if (_unlikely_(cached == 0))
149 cached = getpid() == gettid() ? 1 : -1;
150
151 return cached > 0;
152}
153
154int safe_atou(const char *s, unsigned *ret_u) {
155 char *x = NULL;
156 unsigned long l;
157
158 assert(s);
159 assert(ret_u);
160
161 errno = 0;
162 l = strtoul(s, &x, 0);
163
164 if (!x || *x || errno)
165 return errno ? -errno : -EINVAL;
166
167 if ((unsigned long) (unsigned) l != l)
168 return -ERANGE;
169
170 *ret_u = (unsigned) l;
171 return 0;
172}
173
174static const char *const log_level_table[] = {
175 [LOG_EMERG] = "emerg",
176 [LOG_ALERT] = "alert",
177 [LOG_CRIT] = "crit",
178 [LOG_ERR] = "err",
179 [LOG_WARNING] = "warning",
180 [LOG_NOTICE] = "notice",
181 [LOG_INFO] = "info",
182 [LOG_DEBUG] = "debug"
183};
184
185DEFINE_STRING_TABLE_LOOKUP(log_level, int);
791532b0
HH
186
187char *strnappend(const char *s, const char *suffix, size_t b) {
188 size_t a;
189 char *r;
190
191 if (!s && !suffix)
192 return strdup("");
193
194 if (!s)
195 return strndup(suffix, b);
196
197 if (!suffix)
198 return strdup(s);
199
200 assert(s);
201 assert(suffix);
202
203 a = strlen(s);
204 if (b > ((size_t) -1) - a)
205 return NULL;
206
207 r = new(char, a+b+1);
208 if (!r)
209 return NULL;
210
211 memcpy(r, s, a);
212 memcpy(r+a, suffix, b);
213 r[a+b] = 0;
214
215 return r;
216}
217
218char *strappend(const char *s, const char *suffix) {
219 return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
220}
221
222char *strjoin(const char *x, ...) {
223 va_list ap;
224 size_t l;
e7ba1392 225 char *r;
791532b0
HH
226
227 va_start(ap, x);
228
229 if (x) {
230 l = strlen(x);
231
232 for (;;) {
233 const char *t;
234 size_t n;
235
236 t = va_arg(ap, const char *);
237 if (!t)
238 break;
239
240 n = strlen(t);
241 if (n > ((size_t) -1) - l) {
242 va_end(ap);
243 return NULL;
244 }
245
246 l += n;
247 }
248 } else
249 l = 0;
250
251 va_end(ap);
252
253 r = new(char, l+1);
254 if (!r)
255 return NULL;
256
257 if (x) {
e7ba1392
HH
258 char *p;
259
791532b0
HH
260 p = stpcpy(r, x);
261
262 va_start(ap, x);
263
264 for (;;) {
265 const char *t;
266
267 t = va_arg(ap, const char *);
268 if (!t)
269 break;
270
271 p = stpcpy(p, t);
272 }
273
274 va_end(ap);
275 } else
276 r[0] = 0;
277
278 return r;
279}
2f461da2
HH
280
281char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix) {
282 char *r, *t;
283 const char *f;
284 size_t pl;
285
286 assert(s);
287
288 /* Undoes C style string escaping, and optionally prefixes it. */
289
290 pl = prefix ? strlen(prefix) : 0;
291
292 r = new(char, pl+length+1);
293 if (!r)
294 return r;
295
296 if (prefix)
297 memcpy(r, prefix, pl);
298
299 for (f = s, t = r + pl; f < s + length; f++) {
300
301 if (*f != '\\') {
302 *(t++) = *f;
303 continue;
304 }
305
306 f++;
307
308 switch (*f) {
309
310 case 'a':
311 *(t++) = '\a';
312 break;
313 case 'b':
314 *(t++) = '\b';
315 break;
316 case 'f':
317 *(t++) = '\f';
318 break;
319 case 'n':
320 *(t++) = '\n';
321 break;
322 case 'r':
323 *(t++) = '\r';
324 break;
325 case 't':
326 *(t++) = '\t';
327 break;
328 case 'v':
329 *(t++) = '\v';
330 break;
331 case '\\':
332 *(t++) = '\\';
333 break;
334 case '"':
335 *(t++) = '"';
336 break;
337 case '\'':
338 *(t++) = '\'';
339 break;
340
341 case 's':
342 /* This is an extension of the XDG syntax files */
343 *(t++) = ' ';
344 break;
345
346 case 'x': {
347 /* hexadecimal encoding */
348 int a, b;
349
350 a = unhexchar(f[1]);
351 b = unhexchar(f[2]);
352
353 if (a < 0 || b < 0) {
354 /* Invalid escape code, let's take it literal then */
355 *(t++) = '\\';
356 *(t++) = 'x';
357 } else {
358 *(t++) = (char) ((a << 4) | b);
359 f += 2;
360 }
361
362 break;
363 }
364
365 case '0':
366 case '1':
367 case '2':
368 case '3':
369 case '4':
370 case '5':
371 case '6':
372 case '7': {
373 /* octal encoding */
374 int a, b, c;
375
376 a = unoctchar(f[0]);
377 b = unoctchar(f[1]);
378 c = unoctchar(f[2]);
379
380 if (a < 0 || b < 0 || c < 0) {
381 /* Invalid escape code, let's take it literal then */
382 *(t++) = '\\';
383 *(t++) = f[0];
384 } else {
385 *(t++) = (char) ((a << 6) | (b << 3) | c);
386 f += 2;
387 }
388
389 break;
390 }
391
392 case 0:
393 /* premature end of string.*/
394 *(t++) = '\\';
395 goto finish;
396
397 default:
398 /* Invalid escape code, let's take it literal then */
399 *(t++) = '\\';
400 *(t++) = *f;
401 break;
402 }
403 }
404
405finish:
406 *t = 0;
407 return r;
408}
409
410char *cunescape_length(const char *s, size_t length) {
411 return cunescape_length_with_prefix(s, length, NULL);
412}
413
414
415/* Split a string into words, but consider strings enclosed in '' and
416 * "" as words even if they include spaces. */
417char *split_quoted(const char *c, size_t *l, char **state) {
418 const char *current, *e;
419 bool escaped = false;
420
421 assert(c);
422 assert(l);
423 assert(state);
424
425 current = *state ? *state : c;
426
427 current += strspn(current, WHITESPACE);
428
429 if (*current == 0)
430 return NULL;
431
432 else if (*current == '\'') {
433 current ++;
434
435 for (e = current; *e; e++) {
436 if (escaped)
437 escaped = false;
438 else if (*e == '\\')
439 escaped = true;
440 else if (*e == '\'')
441 break;
442 }
443
444 *l = e-current;
445 *state = (char*) (*e == 0 ? e : e+1);
446
447 } else if (*current == '\"') {
448 current ++;
449
450 for (e = current; *e; e++) {
451 if (escaped)
452 escaped = false;
453 else if (*e == '\\')
454 escaped = true;
455 else if (*e == '\"')
456 break;
457 }
458
459 *l = e-current;
460 *state = (char*) (*e == 0 ? e : e+1);
461
462 } else {
463 for (e = current; *e; e++) {
464 if (escaped)
465 escaped = false;
466 else if (*e == '\\')
467 escaped = true;
468 else if (strchr(WHITESPACE, *e))
469 break;
470 }
471 *l = e-current;
472 *state = (char*) e;
473 }
474
475 return (char*) current;
476}
477
478/* Split a string into words. */
479char *split(const char *c, size_t *l, const char *separator, char **state) {
480 char *current;
481
482 current = *state ? *state : (char*) c;
483
484 if (!*current || *c == 0)
485 return NULL;
486
487 current += strspn(current, separator);
488 *l = strcspn(current, separator);
489 *state = current+*l;
490
491 return (char*) current;
492}
493
494int unhexchar(char c) {
495
496 if (c >= '0' && c <= '9')
497 return c - '0';
498
499 if (c >= 'a' && c <= 'f')
500 return c - 'a' + 10;
501
502 if (c >= 'A' && c <= 'F')
503 return c - 'A' + 10;
504
505 return -1;
506}
507
508int unoctchar(char c) {
509
510 if (c >= '0' && c <= '7')
511 return c - '0';
512
513 return -1;
514}