f87dfa0bccac8dbeede96b0101be08ec447d4feb
[platform/core/system/libsystem.git] / src / libsystem / libsystem.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /*
4  * libsystem
5  *
6  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
7  *
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
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  */
20
21 #include <stddef.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <limits.h>
26 #include <ctype.h>
27 #include <sys/wait.h>
28 #include <sys/stat.h>
29 #include <mntent.h>
30
31 #include "libsystem.h"
32
33 static int _errno_old;
34
35 #define STORE_RESET_ERRNO       do {    \
36         _errno_old = errno;             \
37         errno = 0;                      \
38 } while (0)
39
40 #define RESTORE_ERRNO           do {    \
41         errno = _errno_old;             \
42         _errno_old = 0;                 \
43 } while (0)
44
45 bool streq_ptr(const char *a, const char *b) {
46
47         /* Like streq(), but tries to make sense of NULL pointers */
48
49         if (a && b)
50                 return streq(a, b);
51
52         if (!a && !b)
53                 return true;
54
55         return false;
56 }
57
58 char *truncate_nl(char *s) {
59         assert(s);
60
61         s[strcspn(s, NEWLINE)] = 0;
62
63         return s;
64 }
65
66 char *strnappend(const char *s, const char *suffix, size_t b) {
67         size_t a;
68         char *r;
69
70         if (!s && !suffix)
71                 return strdup("");
72
73         if (!s)
74                 return strndup(suffix, b);
75
76         if (!suffix)
77                 return strdup(s);
78
79         assert(s);
80         assert(suffix);
81
82         a = strlen(s);
83         if (b > ((size_t) -1) - a)
84                 return NULL;
85
86         r = new(char, a+b+1);
87         if (!r)
88                 return NULL;
89
90         memcpy(r, s, a);
91         memcpy(r+a, suffix, b);
92         r[a+b] = 0;
93
94         return r;
95 }
96
97 char *strappend(const char *s, const char *suffix) {
98         return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
99 }
100
101 char *strstrip(char *s) {
102         char *e;
103
104         /* Drops trailing whitespace. Modifies the string in
105          * place. Returns pointer to first non-space character */
106
107         s += strspn(s, WHITESPACE);
108
109         for (e = strchr(s, 0); e > s; e --)
110                 if (!strchr(WHITESPACE, e[-1]))
111                         break;
112
113         *e = 0;
114
115         return s;
116 }
117
118 int strdup_strip(const char *str, char **ret) {
119         char *r = NULL;
120         size_t s, l;
121
122         assert(str);
123         assert(ret);
124
125         s = strspn(str, WHITESPACE);
126
127         for (l = strlen(str + s); l > 0; l--)
128                 if (!strchr(WHITESPACE, str[s + l - 1]))
129                         break;
130
131         r = strndup(str + s, l);
132         if (!r)
133                 return -ENOMEM;
134
135         *ret = r;
136
137         return 0;
138 }
139
140 int strndup_strip(const char *str, size_t len, char **ret) {
141         char *r = NULL;
142         size_t s, l;
143
144         assert(str);
145         assert(ret);
146
147         s = strspn(str, WHITESPACE);
148
149         l = strlen(str + s);
150         if (len > s)
151                 l = l < len - s ? l : len - s;
152         else
153                 return -EFAULT;
154
155         for (; l > 0; l--)
156                 if (!strchr(WHITESPACE, str[s + l - 1]))
157                         break;
158
159         r = strndup(str + s, l);
160         if (!r)
161                 return -ENOMEM;
162
163         *ret = r;
164
165         return 0;
166 }
167
168 bool nulstr_contains(const char*nulstr, const char *needle) {
169         const char *i;
170
171         if (!nulstr)
172                 return false;
173
174         NULSTR_FOREACH(i, nulstr)
175                 if (streq(i, needle))
176                         return true;
177
178         return false;
179 }
180
181 bool path_is_absolute(const char *p) {
182
183         assert(p);
184
185         return p[0] == '/';
186 }
187
188 char *path_kill_slashes(char *path) {
189         char *f, *t;
190         bool slash = false;
191
192         /* Removes redundant inner and trailing slashes. Modifies the
193          * passed string in-place.
194          *
195          * ///foo///bar/ becomes /foo/bar
196          */
197
198         for (f = path, t = path; *f; f++) {
199
200                 if (*f == '/') {
201                         slash = true;
202                         continue;
203                 }
204
205                 if (slash) {
206                         slash = false;
207                         *(t++) = '/';
208                 }
209
210                 *(t++) = *f;
211         }
212
213         /* Special rule, if we are talking of the root directory, a
214            trailing slash is good */
215
216         if (t == path && slash)
217                 *(t++) = '/';
218
219         *t = 0;
220         return path;
221 }
222
223 char* endswith(const char *s, const char *postfix) {
224         size_t sl, pl;
225
226         assert(s);
227         assert(postfix);
228
229         sl = strlen(s);
230         pl = strlen(postfix);
231
232         if (pl == 0)
233                 return (char*) s + sl;
234
235         if (sl < pl)
236                 return NULL;
237
238         if (memcmp(s + sl - pl, postfix, pl) != 0)
239                 return NULL;
240
241         return (char*) s + sl - pl;
242 }
243
244 int parse_boolean(const char *v) {
245         assert(v);
246
247         if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || strcaseeq(v, "on"))
248                 return 1;
249         else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || strcaseeq(v, "off"))
250                 return 0;
251
252         return -EINVAL;
253 }
254
255 int parse_bytes(const char *b, size_t *s) {
256         _cleanup_free_ char *num = NULL;
257         size_t len, num_l, unit_l;
258
259         assert(b);
260
261         len = strlen(b);
262
263         if (!len)
264                 return 0;
265
266         num_l = strspn(b, "0123456789");
267         if (num_l < len-1)
268                 return -EINVAL;
269
270         unit_l = strcspn(b, "BKMG");
271         if (num_l != unit_l)
272                 return -EINVAL;
273
274         num = strndup(b, num_l);
275         if (!num)
276                 return -ENOMEM;
277
278         switch (b[len - 1]) {
279         case 'G':
280                 *s = atoi(num) << 30;
281                 break;
282         case 'M':
283                 *s = atoi(num) << 20;
284                 break;
285         case 'K':
286                 *s = atoi(num) << 10;
287                 break;
288         case 'B':
289         default:
290                 *s = atoi(num);
291                 break;
292         }
293
294         return 0;
295 }
296
297 int parse_percent(const char *string, size_t *percent) {
298         _cleanup_free_ char *num = NULL;
299         size_t len, num_len, per;
300
301         assert(string);
302         assert(percent);
303
304         len = strlen(string);
305         if (!len)
306                 return 0;
307
308         if (string[len-1] != '%')
309                 return -EINVAL;
310
311         num_len = strspn(string, "0123456789");
312         if (num_len < len-1)
313                 return -EINVAL;
314
315         num = strndup(string, num_len);
316         if (!num)
317                 return -ENOMEM;
318
319         per = atoi(num);
320         if (per > 100)
321                 return -EINVAL;
322
323         *percent = per;
324
325         return 0;
326 }
327
328 static bool __quote_complete(char *str, size_t l, char q) {
329         char *s, *s2;
330
331         assert(str);
332
333         if (!l)
334                 return true;
335
336         s = strchr(str, q);
337         if (!s || (s - str) > l)
338                 return true;
339
340         s = strchr(s + 1, q);
341         if (!s || (s - str) > l)
342                 return false;
343
344         s2 = strchr(s + 1, q);
345         if (!s2 || (s2 - str) > l)
346                 return true;
347
348         return __quote_complete(s + 1, l - (s + 1 - str), q);
349 }
350
351 static bool quote_complete(char *str, size_t l) {
352         char quotes[] = QUOTES;
353         int i;
354
355         assert(str);
356
357         if (!l)
358                 return true;
359
360         for (i = 0; quotes[i]; i++) {
361                 if (!__quote_complete(str, l, quotes[i]))
362                         return false;
363         }
364
365         return true;
366 }
367
368 char *split(const char *c, size_t *l, const char *separator, char **state) {
369         bool separator_include_quotes;
370         char *current;
371         size_t s;
372
373         assert(c);
374         assert(l);
375         assert(separator);
376         assert(state);
377
378         current = *state ? *state : (char*) c;
379         if (!*current || *c == 0)
380                 return NULL;
381
382         *l = 0;
383         separator_include_quotes = !!strspn(separator, QUOTES);
384         current += strspn(current, separator);
385
386         while((s = strcspn(current + *l, separator))) {
387                 *l += s;
388                 if (separator_include_quotes ||
389                     quote_complete(current, *l))
390                         break;
391                 (*l)++;
392         }
393
394         *state = current + *l;
395
396         return (char *)current;
397 }
398
399 bool is_number(const char *s, int l) {
400         int i;
401
402         for (i = 0; i < l; i++)
403                 if (!isdigit(s[i]))
404                         return false;
405
406         return true;
407 }
408
409 int do_copy(const char *src, const char *dst, const char *option, int64_t timeout_msec) {
410         /* TODO
411          * change direct execution of cp to c api
412          */
413         char *argv[] = {"/bin/cp", NULL, NULL, NULL, NULL};
414
415         assert(src);
416         assert(dst);
417         assert(option);
418
419         argv[1] = (char *)src;
420         argv[2] = (char *)dst;
421         argv[3] = (char *)option;
422
423         return do_fork_exec(argv, NULL, timeout_msec);
424 }
425
426 int do_mkdir(const char *path, mode_t mode) {
427         char d[PATH_MAX];
428         size_t s, l;
429         int r, p;
430
431         assert(path);
432
433         l = strlen(path);
434
435         for (p = 0, s = 0; p < l; p += s + 1) {
436                 s = strcspn(path + p, "/");
437                 if (!s)
438                         continue;
439
440                 assert(PATH_MAX > p + s + 1);
441
442                 r = snprintf(d, p + s + 1, "%s", path);
443                 if (r < 0)
444                         return r;
445
446                 r = mkdir(d, mode);
447                 if (r < 0 && errno != EEXIST)
448                         return -errno;
449         }
450
451         return 0;
452 }
453
454 int rmdir_recursive(const char *path) {
455         _cleanup_closedir_ DIR *d = NULL;
456         struct dirent *de;
457         int r;
458
459         assert(path);
460
461         d = opendir(path);
462         if (!d)
463                 return -errno;
464
465         FOREACH_DIRENT(de, d, return -errno) {
466                 _cleanup_free_ char *p = NULL;
467
468                 r = asprintf(&p, "%s/%s", path, de->d_name);
469                 if (r < 0)
470                         return -ENOMEM;
471
472                 if (de->d_type == DT_DIR) {
473                         r = rmdir_recursive(p);
474                         if (r < 0)
475                                 return r;
476                 } else {
477                         r = unlink(p);
478                         if (r < 0)
479                                 return r;
480                 }
481         }
482
483         return rmdir(path);
484 }
485
486 char *strdup_unquote(const char *str, const char *quotes) {
487         size_t l;
488
489         assert(str);
490
491         l = strlen(str);
492         if (l < 2)
493                 return strdup(str);
494
495         if (strchr(quotes, str[0]) &&
496             str[0] == str[l-1])
497                 return strndup(str+1, l-2);
498
499         return strdup(str);
500 }
501
502 int write_str_to_file(FILE *f, const char *str, enum file_write_flags flags) {
503         int r = 0;
504
505         assert(f);
506         assert(str);
507
508         STORE_RESET_ERRNO;
509
510         (void) fputs(str, f);
511         if ((flags & FILE_WRITE_NEWLINE_IF_NOT) &&
512             !endswith(str, "\n"))
513                 (void) fputc('\n', f);
514
515         if (flags & FILE_WRITE_WITH_FFLUSH)
516                 (void) fflush(f);
517
518         if (ferror(f))
519                 r = errno ? -errno : -EIO;
520
521         RESTORE_ERRNO;
522
523         return r;
524 }
525
526 int write_str_to_path(const char *path, const char *str, enum file_write_flags flags) {
527         _cleanup_fclose_ FILE *f = NULL;
528
529         assert(path);
530         assert(str);
531
532         if (flags & FILE_WRITE_APPEND)
533                 f = fopen(path, "ae");
534         else
535                 f = fopen(path, "we");
536         if (!f)
537                 return -errno;
538
539         return write_str_to_file(f, str, flags);
540 }
541
542 int write_int32_to_file(FILE *f, int32_t i, enum file_write_flags flags) {
543         int r = 0;
544
545         assert(f);
546
547         STORE_RESET_ERRNO;
548
549         (void) fprintf(f, "%d", i);
550         if (flags & FILE_WRITE_NEWLINE_IF_NOT)
551                 (void) fputc('\n', f);
552
553         if (flags & FILE_WRITE_WITH_FFLUSH)
554                 (void) fflush(f);
555
556         if (ferror(f))
557                 r = errno ? -errno : -EIO;
558
559         RESTORE_ERRNO;
560
561         return r;
562 }
563
564 int write_int32_to_path(const char *path, int32_t i, enum file_write_flags flags) {
565         _cleanup_fclose_ FILE *f = NULL;
566
567         assert(path);
568
569         if (flags & FILE_WRITE_APPEND)
570                 f = fopen(path, "ae");
571         else
572                 f = fopen(path, "we");
573         if (!f)
574                 return -errno;
575
576         return write_int32_to_file(f, i, flags);
577 }
578
579 int write_uint32_to_file(FILE *f, uint32_t u, enum file_write_flags flags) {
580         int r = 0;
581
582         assert(f);
583
584         STORE_RESET_ERRNO;
585
586         (void) fprintf(f, "%u", u);
587         if (flags & FILE_WRITE_NEWLINE_IF_NOT)
588                 (void) fputc('\n', f);
589
590         if (flags & FILE_WRITE_WITH_FFLUSH)
591                 (void) fflush(f);
592
593         if (ferror(f))
594                 r = errno ? -errno : -EIO;
595
596         RESTORE_ERRNO;
597
598         return r;
599 }
600
601 int write_uint32_to_path(const char *path, uint32_t u, enum file_write_flags flags) {
602         _cleanup_fclose_ FILE *f = NULL;
603
604         assert(path);
605
606         if (flags & FILE_WRITE_APPEND)
607                 f = fopen(path, "ae");
608         else
609                 f = fopen(path, "we");
610         if (!f)
611                 return -errno;
612
613         return write_uint32_to_file(f, u, flags);
614 }
615
616 int read_one_line_from_file(FILE *f, char **line) {
617         char t[LINE_MAX], *c;
618
619         assert(f);
620         assert(line);
621
622         STORE_RESET_ERRNO;
623
624         if (!fgets(t, sizeof(t), f)) {
625
626                 if (ferror(f)) {
627                         int r;
628
629                         r = errno ? -errno : -EIO;
630                         RESTORE_ERRNO;
631                         return r;
632                 }
633
634                 t[0] = 0;
635         }
636
637         RESTORE_ERRNO;
638
639         c = strdup(t);
640         if (!c)
641                 return -ENOMEM;
642
643         *line = truncate_nl(c);
644
645         return 0;
646 }
647
648 int read_one_line_from_path(const char *path, char **line) {
649         _cleanup_fclose_ FILE *f = NULL;
650
651         assert(path);
652         assert(line);
653
654         f = fopen(path, "re");
655         if (!f)
656                 return -errno;
657
658         return read_one_line_from_file(f, line);
659 }
660
661 int read_int32_from_file(FILE *f, int32_t *i) {
662         int r = 0;
663
664         assert(f);
665         assert(i);
666
667         STORE_RESET_ERRNO;
668
669         r = fscanf(f, "%d", i);
670         if (r == EOF && ferror(f))
671                 r = errno ? -errno : -EOF;
672
673         RESTORE_ERRNO;
674
675         return r;
676 }
677
678 int read_int32_from_path(const char *path, int32_t *i) {
679         _cleanup_fclose_ FILE *f = NULL;
680
681         assert(path);
682         assert(i);
683
684         f = fopen(path, "re");
685         if (!f)
686                 return -errno;
687
688         return read_int32_from_file(f, i);
689 }
690
691 int read_uint32_from_file(FILE *f, uint32_t *u) {
692         int r = 0;
693
694         assert(f);
695         assert(u);
696
697         STORE_RESET_ERRNO;
698
699         r = fscanf(f, "%u", u);
700         if (r == EOF && ferror(f))
701                 r = errno ? -errno : -EOF;
702
703         RESTORE_ERRNO;
704
705         return r;
706 }
707
708 int read_uint32_from_path(const char *path, uint32_t *u) {
709         _cleanup_fclose_ FILE *f = NULL;
710
711         assert(path);
712         assert(u);
713
714         f = fopen(path, "re");
715         if (!f)
716                 return -errno;
717
718         return read_uint32_from_file(f, u);
719 }
720
721 int str_to_strv(const char *str, char ***strv, const char *separator) {
722         char *w, *state, *p;
723         char **v = NULL, **new = NULL;
724         size_t l;
725         size_t i = 0;
726
727         FOREACH_WORD_SEPARATOR(w, l, str, separator, state) {
728                 p = strndup(w, l);
729                 if (!p) {
730                         free(v);
731                         return -ENOMEM;
732                 }
733
734                 new = (char **)realloc(v, sizeof(char *) * (i + 2));
735                 if (!new) {
736                         free(p);
737                         free(v);
738                         p = NULL;
739                         return -ENOMEM;
740                 }
741
742                 v = new;
743
744                 v[i] = p;
745                 v[i+1] = NULL;
746                 i++;
747         }
748
749         *strv = v;
750
751         return 0;
752 }
753
754 size_t sizeof_strv(char **strv) {
755         size_t u = 0;
756
757         if (!strv)
758                 return 0;
759
760         while(strv[u++])
761                 ;
762
763         return u - 1;
764 }
765
766 int strv_attach(char **first, char **second, char ***strv, bool free_second) {
767         char **new = NULL;
768         size_t n1 = 0, n2 = 0;
769
770         assert(strv);
771
772         if (first)
773                 n1 = sizeof_strv(first);
774
775         if (second) {
776                 n2 = sizeof_strv(second);
777
778                 new = (char **)realloc(first, sizeof(char *) * (n1 + n2 + 1));
779                 if (!new)
780                         return -ENOMEM;
781
782                 first = new;
783
784                 memcpy(first + n1, second, sizeof(char *) * (n2 + 1));
785
786                 if (free_second)
787                         free(second);
788         }
789
790         *strv = first;
791
792         return 0;
793 }
794
795 void strv_free_full(char **strv) {
796         char **s;
797
798         if (!strv)
799                 return;
800
801         FOREACH_STRV(s, strv) {
802                 if (s && *s) {
803                         free(*s);
804                         *s = NULL;
805                 }
806         }
807
808         free(strv);
809         strv = NULL;
810 }
811
812 bool isdir(const char *path) {
813         struct stat st;
814
815         assert(path);
816
817         if (lstat(path, &st) < 0)
818                 return false;
819
820         return S_ISDIR(st.st_mode);
821 }
822
823 int touch(const char *path) {
824         _cleanup_fclose_ FILE *f = NULL;
825
826         assert(path);
827
828         f = fopen(path, "w");
829         if (!f)
830                 return -errno;
831
832         return 0;
833 }
834
835 bool mnt_is_mounted(const char *fsname, const char *dir, const char *type, const char *opts) {
836         struct mntent *ent;
837         FILE *f = NULL;
838         bool matched = false;
839
840         f = setmntent("/etc/mtab", "r");
841         if (!f)
842                 return false;
843
844         while ((ent = getmntent(f))) {
845                 if (fsname) {
846                         if (streq(fsname, ent->mnt_fsname))
847                                 matched = true;
848                         else
849                                 goto no_match;
850                 }
851
852                 if (dir) {
853                         if (streq(dir, ent->mnt_dir))
854                                 matched = true;
855                         else
856                                 goto no_match;
857                 }
858
859                 if (type) {
860                         if (streq(type, ent->mnt_type))
861                                 matched = true;
862                         else
863                                 goto no_match;
864                 }
865
866                 if (opts) {
867                         if (streq(opts, ent->mnt_opts))
868                                 matched = true;
869                         else
870                                 goto no_match;
871                 }
872
873                 if (matched)
874                         break;
875
876         no_match:
877                 matched = false;
878         }
879
880         endmntent(f);
881
882         return matched;
883 }