1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
8 * Licensed under the Apache License, Version 2.0 (the License);
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
31 #include "libsystem.h"
33 static int _errno_old;
35 #define STORE_RESET_ERRNO do { \
40 #define RESTORE_ERRNO do { \
45 bool streq_ptr(const char *a, const char *b) {
47 /* Like streq(), but tries to make sense of NULL pointers */
58 char *truncate_nl(char *s) {
61 s[strcspn(s, NEWLINE)] = 0;
66 char *strnappend(const char *s, const char *suffix, size_t b) {
74 return strndup(suffix, b);
83 if (b > ((size_t) -1) - a)
91 memcpy(r+a, suffix, b);
97 char *strappend(const char *s, const char *suffix) {
98 return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
101 char *strstrip(char *s) {
104 /* Drops trailing whitespace. Modifies the string in
105 * place. Returns pointer to first non-space character */
107 s += strspn(s, WHITESPACE);
109 for (e = strchr(s, 0); e > s; e --)
110 if (!strchr(WHITESPACE, e[-1]))
118 int strdup_strip(const char *str, char **ret) {
125 s = strspn(str, WHITESPACE);
127 for (l = strlen(str + s); l > 0; l--)
128 if (!strchr(WHITESPACE, str[s + l - 1]))
131 r = strndup(str + s, l);
140 int strndup_strip(const char *str, size_t len, char **ret) {
147 s = strspn(str, WHITESPACE);
151 l = l < len - s ? l : len - s;
156 if (!strchr(WHITESPACE, str[s + l - 1]))
159 r = strndup(str + s, l);
168 bool nulstr_contains(const char*nulstr, const char *needle) {
174 NULSTR_FOREACH(i, nulstr)
175 if (streq(i, needle))
181 bool path_is_absolute(const char *p) {
188 char *path_kill_slashes(char *path) {
192 /* Removes redundant inner and trailing slashes. Modifies the
193 * passed string in-place.
195 * ///foo///bar/ becomes /foo/bar
198 for (f = path, t = path; *f; f++) {
213 /* Special rule, if we are talking of the root directory, a
214 trailing slash is good */
216 if (t == path && slash)
223 char* endswith(const char *s, const char *postfix) {
230 pl = strlen(postfix);
233 return (char*) s + sl;
238 if (memcmp(s + sl - pl, postfix, pl) != 0)
241 return (char*) s + sl - pl;
244 int parse_boolean(const char *v) {
247 if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || strcaseeq(v, "on"))
249 else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || strcaseeq(v, "off"))
255 int parse_bytes(const char *b, size_t *s) {
256 _cleanup_free_ char *num = NULL;
257 size_t len, num_l, unit_l;
266 num_l = strspn(b, "0123456789");
270 unit_l = strcspn(b, "BKMG");
274 num = strndup(b, num_l);
278 switch (b[len - 1]) {
280 *s = atoi(num) << 30;
283 *s = atoi(num) << 20;
286 *s = atoi(num) << 10;
297 int parse_percent(const char *string, size_t *percent) {
298 _cleanup_free_ char *num = NULL;
299 size_t len, num_len, per;
304 len = strlen(string);
308 if (string[len-1] != '%')
311 num_len = strspn(string, "0123456789");
315 num = strndup(string, num_len);
328 static bool __quote_complete(char *str, size_t l, char q) {
337 if (!s || (s - str) > l)
340 s = strchr(s + 1, q);
341 if (!s || (s - str) > l)
344 s2 = strchr(s + 1, q);
345 if (!s2 || (s2 - str) > l)
348 return __quote_complete(s + 1, l - (s + 1 - str), q);
351 static bool quote_complete(char *str, size_t l) {
352 char quotes[] = QUOTES;
360 for (i = 0; quotes[i]; i++) {
361 if (!__quote_complete(str, l, quotes[i]))
368 char *split(const char *c, size_t *l, const char *separator, char **state) {
369 bool separator_include_quotes;
378 current = *state ? *state : (char*) c;
379 if (!*current || *c == 0)
383 separator_include_quotes = !!strspn(separator, QUOTES);
384 current += strspn(current, separator);
386 while((s = strcspn(current + *l, separator))) {
388 if (separator_include_quotes ||
389 quote_complete(current, *l))
394 *state = current + *l;
396 return (char *)current;
399 bool is_number(const char *s, int l) {
402 for (i = 0; i < l; i++)
409 int do_copy(const char *src, const char *dst, const char *option, int64_t timeout_msec) {
411 * change direct execution of cp to c api
413 char *argv[] = {"/bin/cp", NULL, NULL, NULL, NULL};
419 argv[1] = (char *)src;
420 argv[2] = (char *)dst;
421 argv[3] = (char *)option;
423 return do_fork_exec(argv, NULL, timeout_msec);
426 int do_mkdir(const char *path, mode_t mode) {
435 for (p = 0, s = 0; p < l; p += s + 1) {
436 s = strcspn(path + p, "/");
440 assert(PATH_MAX > p + s + 1);
442 r = snprintf(d, p + s + 1, "%s", path);
447 if (r < 0 && errno != EEXIST)
454 int rmdir_recursive(const char *path) {
455 _cleanup_closedir_ DIR *d = NULL;
465 FOREACH_DIRENT(de, d, return -errno) {
466 _cleanup_free_ char *p = NULL;
468 r = asprintf(&p, "%s/%s", path, de->d_name);
472 if (de->d_type == DT_DIR) {
473 r = rmdir_recursive(p);
486 char *strdup_unquote(const char *str, const char *quotes) {
495 if (strchr(quotes, str[0]) &&
497 return strndup(str+1, l-2);
502 int write_str_to_file(FILE *f, const char *str, enum file_write_flags flags) {
510 (void) fputs(str, f);
511 if ((flags & FILE_WRITE_NEWLINE_IF_NOT) &&
512 !endswith(str, "\n"))
513 (void) fputc('\n', f);
515 if (flags & FILE_WRITE_WITH_FFLUSH)
519 r = errno ? -errno : -EIO;
526 int write_str_to_path(const char *path, const char *str, enum file_write_flags flags) {
527 _cleanup_fclose_ FILE *f = NULL;
532 if (flags & FILE_WRITE_APPEND)
533 f = fopen(path, "ae");
535 f = fopen(path, "we");
539 return write_str_to_file(f, str, flags);
542 int write_int32_to_file(FILE *f, int32_t i, enum file_write_flags flags) {
549 (void) fprintf(f, "%d", i);
550 if (flags & FILE_WRITE_NEWLINE_IF_NOT)
551 (void) fputc('\n', f);
553 if (flags & FILE_WRITE_WITH_FFLUSH)
557 r = errno ? -errno : -EIO;
564 int write_int32_to_path(const char *path, int32_t i, enum file_write_flags flags) {
565 _cleanup_fclose_ FILE *f = NULL;
569 if (flags & FILE_WRITE_APPEND)
570 f = fopen(path, "ae");
572 f = fopen(path, "we");
576 return write_int32_to_file(f, i, flags);
579 int write_uint32_to_file(FILE *f, uint32_t u, enum file_write_flags flags) {
586 (void) fprintf(f, "%u", u);
587 if (flags & FILE_WRITE_NEWLINE_IF_NOT)
588 (void) fputc('\n', f);
590 if (flags & FILE_WRITE_WITH_FFLUSH)
594 r = errno ? -errno : -EIO;
601 int write_uint32_to_path(const char *path, uint32_t u, enum file_write_flags flags) {
602 _cleanup_fclose_ FILE *f = NULL;
606 if (flags & FILE_WRITE_APPEND)
607 f = fopen(path, "ae");
609 f = fopen(path, "we");
613 return write_uint32_to_file(f, u, flags);
616 int read_one_line_from_file(FILE *f, char **line) {
617 char t[LINE_MAX], *c;
624 if (!fgets(t, sizeof(t), f)) {
629 r = errno ? -errno : -EIO;
643 *line = truncate_nl(c);
648 int read_one_line_from_path(const char *path, char **line) {
649 _cleanup_fclose_ FILE *f = NULL;
654 f = fopen(path, "re");
658 return read_one_line_from_file(f, line);
661 int read_int32_from_file(FILE *f, int32_t *i) {
669 r = fscanf(f, "%d", i);
670 if (r == EOF && ferror(f))
671 r = errno ? -errno : -EOF;
678 int read_int32_from_path(const char *path, int32_t *i) {
679 _cleanup_fclose_ FILE *f = NULL;
684 f = fopen(path, "re");
688 return read_int32_from_file(f, i);
691 int read_uint32_from_file(FILE *f, uint32_t *u) {
699 r = fscanf(f, "%u", u);
700 if (r == EOF && ferror(f))
701 r = errno ? -errno : -EOF;
708 int read_uint32_from_path(const char *path, uint32_t *u) {
709 _cleanup_fclose_ FILE *f = NULL;
714 f = fopen(path, "re");
718 return read_uint32_from_file(f, u);
721 int str_to_strv(const char *str, char ***strv, const char *separator) {
723 char **v = NULL, **new = NULL;
727 FOREACH_WORD_SEPARATOR(w, l, str, separator, state) {
734 new = (char **)realloc(v, sizeof(char *) * (i + 2));
754 size_t sizeof_strv(char **strv) {
766 int strv_attach(char **first, char **second, char ***strv, bool free_second) {
768 size_t n1 = 0, n2 = 0;
773 n1 = sizeof_strv(first);
776 n2 = sizeof_strv(second);
778 new = (char **)realloc(first, sizeof(char *) * (n1 + n2 + 1));
784 memcpy(first + n1, second, sizeof(char *) * (n2 + 1));
795 void strv_free_full(char **strv) {
801 FOREACH_STRV(s, strv) {
812 bool isdir(const char *path) {
817 if (lstat(path, &st) < 0)
820 return S_ISDIR(st.st_mode);
823 int touch(const char *path) {
824 _cleanup_fclose_ FILE *f = NULL;
828 f = fopen(path, "w");
835 bool mnt_is_mounted(const char *fsname, const char *dir, const char *type, const char *opts) {
838 bool matched = false;
840 f = setmntent("/etc/mtab", "r");
844 while ((ent = getmntent(f))) {
846 if (streq(fsname, ent->mnt_fsname))
853 if (streq(dir, ent->mnt_dir))
860 if (streq(type, ent->mnt_type))
867 if (streq(opts, ent->mnt_opts))