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.
34 #include "libsystem.h"
36 static int _errno_old;
38 #define STORE_RESET_ERRNO do { \
43 #define RESTORE_ERRNO do { \
48 bool streq_ptr(const char *a, const char *b) {
50 /* Like streq(), but tries to make sense of NULL pointers */
61 char *truncate_nl(char *s) {
64 s[strcspn(s, NEWLINE)] = 0;
69 char *strnappend(const char *s, const char *suffix, size_t b) {
77 return strndup(suffix, b);
86 if (b > ((size_t) -1) - a)
94 memcpy(r+a, suffix, b);
100 char *strappend(const char *s, const char *suffix) {
101 return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
104 char *strstrip(char *s) {
107 /* Drops trailing whitespace. Modifies the string in
108 * place. Returns pointer to first non-space character */
110 s += strspn(s, WHITESPACE);
112 for (e = strchr(s, 0); e > s; e --)
113 if (!strchr(WHITESPACE, e[-1]))
121 int strdup_strip(const char *str, char **ret) {
128 s = strspn(str, WHITESPACE);
130 for (l = strlen(str + s); l > 0; l--)
131 if (!strchr(WHITESPACE, str[s + l - 1]))
134 r = strndup(str + s, l);
143 int strndup_strip(const char *str, size_t len, char **ret) {
150 s = strspn(str, WHITESPACE);
154 l = l < len - s ? l : len - s;
159 if (!strchr(WHITESPACE, str[s + l - 1]))
162 r = strndup(str + s, l);
171 bool nulstr_contains(const char*nulstr, const char *needle) {
177 NULSTR_FOREACH(i, nulstr)
178 if (streq(i, needle))
184 bool path_is_absolute(const char *p) {
191 char *path_kill_slashes(char *path) {
195 /* Removes redundant inner and trailing slashes. Modifies the
196 * passed string in-place.
198 * ///foo///bar/ becomes /foo/bar
201 for (f = path, t = path; *f; f++) {
216 /* Special rule, if we are talking of the root directory, a
217 trailing slash is good */
219 if (t == path && slash)
226 char* endswith(const char *s, const char *postfix) {
233 pl = strlen(postfix);
236 return (char*) s + sl;
241 if (memcmp(s + sl - pl, postfix, pl) != 0)
244 return (char*) s + sl - pl;
247 int parse_boolean(const char *v) {
250 if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || strcaseeq(v, "on"))
252 else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || strcaseeq(v, "off"))
258 int parse_bytes(const char *b, size_t *s) {
259 _cleanup_free_ char *num = NULL;
260 size_t len, num_l, unit_l;
269 num_l = strspn(b, "0123456789");
273 unit_l = strcspn(b, "BKMG");
277 num = strndup(b, num_l);
281 switch (b[len - 1]) {
283 *s = atoi(num) << 30;
286 *s = atoi(num) << 20;
289 *s = atoi(num) << 10;
300 int parse_percent(const char *string, size_t *percent) {
301 _cleanup_free_ char *num = NULL;
302 size_t len, num_len, per;
307 len = strlen(string);
311 if (string[len-1] != '%')
314 num_len = strspn(string, "0123456789");
318 num = strndup(string, num_len);
331 static bool __quote_complete(char *str, size_t l, char q) {
340 if (!s || (s - str) > l)
343 s = strchr(s + 1, q);
344 if (!s || (s - str) > l)
347 s2 = strchr(s + 1, q);
348 if (!s2 || (s2 - str) > l)
351 return __quote_complete(s + 1, l - (s + 1 - str), q);
354 static bool quote_complete(char *str, size_t l) {
355 char quotes[] = QUOTES;
363 for (i = 0; quotes[i]; i++) {
364 if (!__quote_complete(str, l, quotes[i]))
371 char *split(const char *c, size_t *l, const char *separator, char **state) {
372 bool separator_include_quotes;
381 current = *state ? *state : (char*) c;
382 if (!*current || *c == 0)
386 separator_include_quotes = !!strspn(separator, QUOTES);
387 current += strspn(current, separator);
389 while((s = strcspn(current + *l, separator))) {
391 if (separator_include_quotes ||
392 quote_complete(current, *l))
397 *state = current + *l;
399 return (char *)current;
402 bool is_number(const char *s, int l) {
405 for (i = 0; i < l; i++)
412 static int do_copy_internal(const char *src, const char *dst, mode_t mode, bool force) {
413 _cleanup_close_ int rfd = -1, wfd = -1;
422 r = access(dst, F_OK);
425 else if (errno != ENOENT)
429 wfd = open(dst, O_CREAT | O_WRONLY | O_TRUNC, mode);
433 rfd = open(src, O_RDONLY);
437 while ((red = read(rfd, buf, 1024)) > 0)
438 if (write(wfd, buf, red) != red)
447 int do_copy_mode(const char *src, const char *dst, mode_t mode) {
452 return do_copy_internal(src, dst, mode, false);
455 int do_copy_mode_force(const char *src, const char *dst, mode_t mode) {
460 return do_copy_internal(src, dst, mode, true);
463 int do_copy(const char *src, const char *dst) {
468 return do_copy_internal(src, dst, 0644, false);
471 int do_copy_force(const char *src, const char *dst) {
476 return do_copy_internal(src, dst, 0644, true);
479 int do_mkdir(const char *path, mode_t mode) {
488 for (p = 0, s = 0; p < l; p += s + 1) {
489 s = strcspn(path + p, "/");
493 assert(PATH_MAX > p + s + 1);
495 r = snprintf(d, p + s + 1, "%s", path);
500 if (r < 0 && errno != EEXIST)
507 int rmdir_recursive(const char *path) {
508 _cleanup_closedir_ DIR *d = NULL;
518 FOREACH_DIRENT(de, d, return -errno) {
519 _cleanup_free_ char *p = NULL;
521 r = asprintf(&p, "%s/%s", path, de->d_name);
525 if (de->d_type == DT_DIR) {
526 r = rmdir_recursive(p);
539 char *strdup_unquote(const char *str, const char *quotes) {
548 if (strchr(quotes, str[0]) &&
550 return strndup(str+1, l-2);
555 int write_str_to_file(FILE *f, const char *str, enum file_write_flags flags) {
563 (void) fputs(str, f);
564 if ((flags & FILE_WRITE_NEWLINE_IF_NOT) &&
565 !endswith(str, "\n"))
566 (void) fputc('\n', f);
568 if (flags & FILE_WRITE_WITH_FFLUSH)
572 r = errno ? -errno : -EIO;
579 int write_str_to_path(const char *path, const char *str, enum file_write_flags flags) {
580 _cleanup_fclose_ FILE *f = NULL;
585 if (flags & FILE_WRITE_APPEND)
586 f = fopen(path, "ae");
588 f = fopen(path, "we");
592 return write_str_to_file(f, str, flags);
595 int write_int32_to_file(FILE *f, int32_t i, enum file_write_flags flags) {
602 (void) fprintf(f, "%d", i);
603 if (flags & FILE_WRITE_NEWLINE_IF_NOT)
604 (void) fputc('\n', f);
606 if (flags & FILE_WRITE_WITH_FFLUSH)
610 r = errno ? -errno : -EIO;
617 int write_int32_to_path(const char *path, int32_t i, enum file_write_flags flags) {
618 _cleanup_fclose_ FILE *f = NULL;
622 if (flags & FILE_WRITE_APPEND)
623 f = fopen(path, "ae");
625 f = fopen(path, "we");
629 return write_int32_to_file(f, i, flags);
632 int write_uint32_to_file(FILE *f, uint32_t u, enum file_write_flags flags) {
639 (void) fprintf(f, "%u", u);
640 if (flags & FILE_WRITE_NEWLINE_IF_NOT)
641 (void) fputc('\n', f);
643 if (flags & FILE_WRITE_WITH_FFLUSH)
647 r = errno ? -errno : -EIO;
654 int write_uint32_to_path(const char *path, uint32_t u, enum file_write_flags flags) {
655 _cleanup_fclose_ FILE *f = NULL;
659 if (flags & FILE_WRITE_APPEND)
660 f = fopen(path, "ae");
662 f = fopen(path, "we");
666 return write_uint32_to_file(f, u, flags);
669 int write_int64_to_file(FILE *f, int64_t i, enum file_write_flags flags) {
676 (void) fprintf(f, "%" PRId64, i);
677 if (flags & FILE_WRITE_NEWLINE_IF_NOT)
678 (void) fputc('\n', f);
680 if (flags & FILE_WRITE_WITH_FFLUSH)
684 r = errno ? -errno : -EIO;
691 int write_int64_to_path(const char *path, int64_t i, enum file_write_flags flags) {
692 _cleanup_fclose_ FILE *f = NULL;
696 if (flags & FILE_WRITE_APPEND)
697 f = fopen(path, "ae");
699 f = fopen(path, "we");
703 return write_int64_to_file(f, i, flags);
706 int write_uint64_to_file(FILE *f, uint64_t u, enum file_write_flags flags) {
713 (void) fprintf(f, "%" PRIu64, u);
714 if (flags & FILE_WRITE_NEWLINE_IF_NOT)
715 (void) fputc('\n', f);
717 if (flags & FILE_WRITE_WITH_FFLUSH)
721 r = errno ? -errno : -EIO;
728 int write_uint64_to_path(const char *path, uint64_t u, enum file_write_flags flags) {
729 _cleanup_fclose_ FILE *f = NULL;
733 if (flags & FILE_WRITE_APPEND)
734 f = fopen(path, "ae");
736 f = fopen(path, "we");
740 return write_uint64_to_file(f, u, flags);
743 int read_one_line_from_file(FILE *f, char **line) {
744 char t[LINE_MAX], *c;
751 if (!fgets(t, sizeof(t), f)) {
756 r = errno ? -errno : -EIO;
770 *line = truncate_nl(c);
775 int read_one_line_from_path(const char *path, char **line) {
776 _cleanup_fclose_ FILE *f = NULL;
781 f = fopen(path, "re");
785 return read_one_line_from_file(f, line);
788 int read_int32_from_file(FILE *f, int32_t *i) {
796 r = fscanf(f, "%d", i);
797 if (r == EOF && ferror(f))
798 r = errno ? -errno : -EOF;
805 int read_int32_from_path(const char *path, int32_t *i) {
806 _cleanup_fclose_ FILE *f = NULL;
811 f = fopen(path, "re");
815 return read_int32_from_file(f, i);
818 int read_uint32_from_file(FILE *f, uint32_t *u) {
826 r = fscanf(f, "%u", u);
827 if (r == EOF && ferror(f))
828 r = errno ? -errno : -EOF;
835 int read_uint32_from_path(const char *path, uint32_t *u) {
836 _cleanup_fclose_ FILE *f = NULL;
841 f = fopen(path, "re");
845 return read_uint32_from_file(f, u);
848 int read_int64_from_file(FILE *f, int64_t *i) {
856 r = fscanf(f, "%" SCNd64, i);
857 if (r == EOF && ferror(f))
858 r = errno ? -errno : -EOF;
865 int read_int64_from_path(const char *path, int64_t *i) {
866 _cleanup_fclose_ FILE *f = NULL;
871 f = fopen(path, "re");
875 return read_int64_from_file(f, i);
878 int read_uint64_from_file(FILE *f, uint64_t *u) {
886 r = fscanf(f, "%" SCNu64, u);
887 if (r == EOF && ferror(f))
888 r = errno ? -errno : -EOF;
895 int read_uint64_from_path(const char *path, uint64_t *u) {
896 _cleanup_fclose_ FILE *f = NULL;
901 f = fopen(path, "re");
905 return read_uint64_from_file(f, u);
908 int str_to_strv(const char *str, char ***strv, const char *separator) {
910 char **v = NULL, **new = NULL;
914 FOREACH_WORD_SEPARATOR(w, l, str, separator, state) {
921 new = (char **)realloc(v, sizeof(char *) * (i + 2));
941 size_t sizeof_strv(char **strv) {
953 int strv_attach(char **first, char **second, char ***strv, bool free_second) {
955 size_t n1 = 0, n2 = 0;
960 n1 = sizeof_strv(first);
963 n2 = sizeof_strv(second);
965 new = (char **)realloc(first, sizeof(char *) * (n1 + n2 + 1));
971 memcpy(first + n1, second, sizeof(char *) * (n2 + 1));
982 void strv_free_full(char **strv) {
988 FOREACH_STRV(s, strv) {
999 bool isdir(const char *path) {
1004 if (lstat(path, &st) < 0)
1007 return S_ISDIR(st.st_mode);
1010 int touch(const char *path) {
1011 _cleanup_fclose_ FILE *f = NULL;
1015 f = fopen(path, "w");
1022 bool mnt_is_mounted(const char *fsname, const char *dir, const char *type, const char *opts) {
1025 bool matched = false;
1027 f = setmntent("/etc/mtab", "r");
1031 while ((ent = getmntent(f))) {
1033 if (streq(fsname, ent->mnt_fsname))
1040 if (streq(dir, ent->mnt_dir))
1047 if (streq(type, ent->mnt_type))
1054 if (streq(opts, ent->mnt_opts))