libsystem: add 64 bit signed/unsigned read-write api
[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 <fcntl.h>
30 #include <mntent.h>
31 #include <stdint.h>
32 #include <inttypes.h>
33
34 #include "libsystem.h"
35
36 static int _errno_old;
37
38 #define STORE_RESET_ERRNO       do {    \
39         _errno_old = errno;             \
40         errno = 0;                      \
41 } while (0)
42
43 #define RESTORE_ERRNO           do {    \
44         errno = _errno_old;             \
45         _errno_old = 0;                 \
46 } while (0)
47
48 bool streq_ptr(const char *a, const char *b) {
49
50         /* Like streq(), but tries to make sense of NULL pointers */
51
52         if (a && b)
53                 return streq(a, b);
54
55         if (!a && !b)
56                 return true;
57
58         return false;
59 }
60
61 char *truncate_nl(char *s) {
62         assert(s);
63
64         s[strcspn(s, NEWLINE)] = 0;
65
66         return s;
67 }
68
69 char *strnappend(const char *s, const char *suffix, size_t b) {
70         size_t a;
71         char *r;
72
73         if (!s && !suffix)
74                 return strdup("");
75
76         if (!s)
77                 return strndup(suffix, b);
78
79         if (!suffix)
80                 return strdup(s);
81
82         assert(s);
83         assert(suffix);
84
85         a = strlen(s);
86         if (b > ((size_t) -1) - a)
87                 return NULL;
88
89         r = new(char, a+b+1);
90         if (!r)
91                 return NULL;
92
93         memcpy(r, s, a);
94         memcpy(r+a, suffix, b);
95         r[a+b] = 0;
96
97         return r;
98 }
99
100 char *strappend(const char *s, const char *suffix) {
101         return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
102 }
103
104 char *strstrip(char *s) {
105         char *e;
106
107         /* Drops trailing whitespace. Modifies the string in
108          * place. Returns pointer to first non-space character */
109
110         s += strspn(s, WHITESPACE);
111
112         for (e = strchr(s, 0); e > s; e --)
113                 if (!strchr(WHITESPACE, e[-1]))
114                         break;
115
116         *e = 0;
117
118         return s;
119 }
120
121 int strdup_strip(const char *str, char **ret) {
122         char *r = NULL;
123         size_t s, l;
124
125         assert(str);
126         assert(ret);
127
128         s = strspn(str, WHITESPACE);
129
130         for (l = strlen(str + s); l > 0; l--)
131                 if (!strchr(WHITESPACE, str[s + l - 1]))
132                         break;
133
134         r = strndup(str + s, l);
135         if (!r)
136                 return -ENOMEM;
137
138         *ret = r;
139
140         return 0;
141 }
142
143 int strndup_strip(const char *str, size_t len, char **ret) {
144         char *r = NULL;
145         size_t s, l;
146
147         assert(str);
148         assert(ret);
149
150         s = strspn(str, WHITESPACE);
151
152         l = strlen(str + s);
153         if (len > s)
154                 l = l < len - s ? l : len - s;
155         else
156                 return -EFAULT;
157
158         for (; l > 0; l--)
159                 if (!strchr(WHITESPACE, str[s + l - 1]))
160                         break;
161
162         r = strndup(str + s, l);
163         if (!r)
164                 return -ENOMEM;
165
166         *ret = r;
167
168         return 0;
169 }
170
171 bool nulstr_contains(const char*nulstr, const char *needle) {
172         const char *i;
173
174         if (!nulstr)
175                 return false;
176
177         NULSTR_FOREACH(i, nulstr)
178                 if (streq(i, needle))
179                         return true;
180
181         return false;
182 }
183
184 bool path_is_absolute(const char *p) {
185
186         assert(p);
187
188         return p[0] == '/';
189 }
190
191 char *path_kill_slashes(char *path) {
192         char *f, *t;
193         bool slash = false;
194
195         /* Removes redundant inner and trailing slashes. Modifies the
196          * passed string in-place.
197          *
198          * ///foo///bar/ becomes /foo/bar
199          */
200
201         for (f = path, t = path; *f; f++) {
202
203                 if (*f == '/') {
204                         slash = true;
205                         continue;
206                 }
207
208                 if (slash) {
209                         slash = false;
210                         *(t++) = '/';
211                 }
212
213                 *(t++) = *f;
214         }
215
216         /* Special rule, if we are talking of the root directory, a
217            trailing slash is good */
218
219         if (t == path && slash)
220                 *(t++) = '/';
221
222         *t = 0;
223         return path;
224 }
225
226 char* endswith(const char *s, const char *postfix) {
227         size_t sl, pl;
228
229         assert(s);
230         assert(postfix);
231
232         sl = strlen(s);
233         pl = strlen(postfix);
234
235         if (pl == 0)
236                 return (char*) s + sl;
237
238         if (sl < pl)
239                 return NULL;
240
241         if (memcmp(s + sl - pl, postfix, pl) != 0)
242                 return NULL;
243
244         return (char*) s + sl - pl;
245 }
246
247 int parse_boolean(const char *v) {
248         assert(v);
249
250         if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || strcaseeq(v, "on"))
251                 return 1;
252         else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || strcaseeq(v, "off"))
253                 return 0;
254
255         return -EINVAL;
256 }
257
258 int parse_bytes(const char *b, size_t *s) {
259         _cleanup_free_ char *num = NULL;
260         size_t len, num_l, unit_l;
261
262         assert(b);
263
264         len = strlen(b);
265
266         if (!len)
267                 return 0;
268
269         num_l = strspn(b, "0123456789");
270         if (num_l < len-1)
271                 return -EINVAL;
272
273         unit_l = strcspn(b, "BKMG");
274         if (num_l != unit_l)
275                 return -EINVAL;
276
277         num = strndup(b, num_l);
278         if (!num)
279                 return -ENOMEM;
280
281         switch (b[len - 1]) {
282         case 'G':
283                 *s = atoi(num) << 30;
284                 break;
285         case 'M':
286                 *s = atoi(num) << 20;
287                 break;
288         case 'K':
289                 *s = atoi(num) << 10;
290                 break;
291         case 'B':
292         default:
293                 *s = atoi(num);
294                 break;
295         }
296
297         return 0;
298 }
299
300 int parse_percent(const char *string, size_t *percent) {
301         _cleanup_free_ char *num = NULL;
302         size_t len, num_len, per;
303
304         assert(string);
305         assert(percent);
306
307         len = strlen(string);
308         if (!len)
309                 return 0;
310
311         if (string[len-1] != '%')
312                 return -EINVAL;
313
314         num_len = strspn(string, "0123456789");
315         if (num_len < len-1)
316                 return -EINVAL;
317
318         num = strndup(string, num_len);
319         if (!num)
320                 return -ENOMEM;
321
322         per = atoi(num);
323         if (per > 100)
324                 return -EINVAL;
325
326         *percent = per;
327
328         return 0;
329 }
330
331 static bool __quote_complete(char *str, size_t l, char q) {
332         char *s, *s2;
333
334         assert(str);
335
336         if (!l)
337                 return true;
338
339         s = strchr(str, q);
340         if (!s || (s - str) > l)
341                 return true;
342
343         s = strchr(s + 1, q);
344         if (!s || (s - str) > l)
345                 return false;
346
347         s2 = strchr(s + 1, q);
348         if (!s2 || (s2 - str) > l)
349                 return true;
350
351         return __quote_complete(s + 1, l - (s + 1 - str), q);
352 }
353
354 static bool quote_complete(char *str, size_t l) {
355         char quotes[] = QUOTES;
356         int i;
357
358         assert(str);
359
360         if (!l)
361                 return true;
362
363         for (i = 0; quotes[i]; i++) {
364                 if (!__quote_complete(str, l, quotes[i]))
365                         return false;
366         }
367
368         return true;
369 }
370
371 char *split(const char *c, size_t *l, const char *separator, char **state) {
372         bool separator_include_quotes;
373         char *current;
374         size_t s;
375
376         assert(c);
377         assert(l);
378         assert(separator);
379         assert(state);
380
381         current = *state ? *state : (char*) c;
382         if (!*current || *c == 0)
383                 return NULL;
384
385         *l = 0;
386         separator_include_quotes = !!strspn(separator, QUOTES);
387         current += strspn(current, separator);
388
389         while((s = strcspn(current + *l, separator))) {
390                 *l += s;
391                 if (separator_include_quotes ||
392                     quote_complete(current, *l))
393                         break;
394                 (*l)++;
395         }
396
397         *state = current + *l;
398
399         return (char *)current;
400 }
401
402 bool is_number(const char *s, int l) {
403         int i;
404
405         for (i = 0; i < l; i++)
406                 if (!isdigit(s[i]))
407                         return false;
408
409         return true;
410 }
411
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;
414         char buf[1024];
415         ssize_t red;
416         int r;
417
418         assert(src);
419         assert(dst);
420
421         if (!force) {
422                 r = access(dst, F_OK);
423                 if (r == 0)
424                         return -EALREADY;
425                 else if (errno != ENOENT)
426                         return -errno;
427         }
428
429         wfd = open(dst, O_CREAT | O_WRONLY | O_TRUNC, mode);
430         if (wfd < 0)
431                 return -errno;
432
433         rfd = open(src, O_RDONLY);
434         if (rfd < 0)
435                 return -errno;
436
437         while ((red = read(rfd, buf, 1024)) > 0)
438                 if (write(wfd, buf, red) != red)
439                         return -errno;
440
441         if (red < 0)
442                 return -errno;
443
444         return 0;
445 }
446
447 int do_copy_mode(const char *src, const char *dst, mode_t mode) {
448
449         assert(src);
450         assert(dst);
451
452         return do_copy_internal(src, dst, mode, false);
453 }
454
455 int do_copy_mode_force(const char *src, const char *dst, mode_t mode) {
456
457         assert(src);
458         assert(dst);
459
460         return do_copy_internal(src, dst, mode, true);
461 }
462
463 int do_copy(const char *src, const char *dst) {
464
465         assert(src);
466         assert(dst);
467
468         return do_copy_internal(src, dst, 0644, false);
469 }
470
471 int do_copy_force(const char *src, const char *dst) {
472
473         assert(src);
474         assert(dst);
475
476         return do_copy_internal(src, dst, 0644, true);
477 }
478
479 int do_mkdir(const char *path, mode_t mode) {
480         char d[PATH_MAX];
481         size_t s, l;
482         int r, p;
483
484         assert(path);
485
486         l = strlen(path);
487
488         for (p = 0, s = 0; p < l; p += s + 1) {
489                 s = strcspn(path + p, "/");
490                 if (!s)
491                         continue;
492
493                 assert(PATH_MAX > p + s + 1);
494
495                 r = snprintf(d, p + s + 1, "%s", path);
496                 if (r < 0)
497                         return r;
498
499                 r = mkdir(d, mode);
500                 if (r < 0 && errno != EEXIST)
501                         return -errno;
502         }
503
504         return 0;
505 }
506
507 int rmdir_recursive(const char *path) {
508         _cleanup_closedir_ DIR *d = NULL;
509         struct dirent *de;
510         int r;
511
512         assert(path);
513
514         d = opendir(path);
515         if (!d)
516                 return -errno;
517
518         FOREACH_DIRENT(de, d, return -errno) {
519                 _cleanup_free_ char *p = NULL;
520
521                 r = asprintf(&p, "%s/%s", path, de->d_name);
522                 if (r < 0)
523                         return -ENOMEM;
524
525                 if (de->d_type == DT_DIR) {
526                         r = rmdir_recursive(p);
527                         if (r < 0)
528                                 return r;
529                 } else {
530                         r = unlink(p);
531                         if (r < 0)
532                                 return r;
533                 }
534         }
535
536         return rmdir(path);
537 }
538
539 char *strdup_unquote(const char *str, const char *quotes) {
540         size_t l;
541
542         assert(str);
543
544         l = strlen(str);
545         if (l < 2)
546                 return strdup(str);
547
548         if (strchr(quotes, str[0]) &&
549             str[0] == str[l-1])
550                 return strndup(str+1, l-2);
551
552         return strdup(str);
553 }
554
555 int write_str_to_file(FILE *f, const char *str, enum file_write_flags flags) {
556         int r = 0;
557
558         assert(f);
559         assert(str);
560
561         STORE_RESET_ERRNO;
562
563         (void) fputs(str, f);
564         if ((flags & FILE_WRITE_NEWLINE_IF_NOT) &&
565             !endswith(str, "\n"))
566                 (void) fputc('\n', f);
567
568         if (flags & FILE_WRITE_WITH_FFLUSH)
569                 (void) fflush(f);
570
571         if (ferror(f))
572                 r = errno ? -errno : -EIO;
573
574         RESTORE_ERRNO;
575
576         return r;
577 }
578
579 int write_str_to_path(const char *path, const char *str, enum file_write_flags flags) {
580         _cleanup_fclose_ FILE *f = NULL;
581
582         assert(path);
583         assert(str);
584
585         if (flags & FILE_WRITE_APPEND)
586                 f = fopen(path, "ae");
587         else
588                 f = fopen(path, "we");
589         if (!f)
590                 return -errno;
591
592         return write_str_to_file(f, str, flags);
593 }
594
595 int write_int32_to_file(FILE *f, int32_t i, enum file_write_flags flags) {
596         int r = 0;
597
598         assert(f);
599
600         STORE_RESET_ERRNO;
601
602         (void) fprintf(f, "%d", i);
603         if (flags & FILE_WRITE_NEWLINE_IF_NOT)
604                 (void) fputc('\n', f);
605
606         if (flags & FILE_WRITE_WITH_FFLUSH)
607                 (void) fflush(f);
608
609         if (ferror(f))
610                 r = errno ? -errno : -EIO;
611
612         RESTORE_ERRNO;
613
614         return r;
615 }
616
617 int write_int32_to_path(const char *path, int32_t i, enum file_write_flags flags) {
618         _cleanup_fclose_ FILE *f = NULL;
619
620         assert(path);
621
622         if (flags & FILE_WRITE_APPEND)
623                 f = fopen(path, "ae");
624         else
625                 f = fopen(path, "we");
626         if (!f)
627                 return -errno;
628
629         return write_int32_to_file(f, i, flags);
630 }
631
632 int write_uint32_to_file(FILE *f, uint32_t u, enum file_write_flags flags) {
633         int r = 0;
634
635         assert(f);
636
637         STORE_RESET_ERRNO;
638
639         (void) fprintf(f, "%u", u);
640         if (flags & FILE_WRITE_NEWLINE_IF_NOT)
641                 (void) fputc('\n', f);
642
643         if (flags & FILE_WRITE_WITH_FFLUSH)
644                 (void) fflush(f);
645
646         if (ferror(f))
647                 r = errno ? -errno : -EIO;
648
649         RESTORE_ERRNO;
650
651         return r;
652 }
653
654 int write_uint32_to_path(const char *path, uint32_t u, enum file_write_flags flags) {
655         _cleanup_fclose_ FILE *f = NULL;
656
657         assert(path);
658
659         if (flags & FILE_WRITE_APPEND)
660                 f = fopen(path, "ae");
661         else
662                 f = fopen(path, "we");
663         if (!f)
664                 return -errno;
665
666         return write_uint32_to_file(f, u, flags);
667 }
668
669 int write_int64_to_file(FILE *f, int64_t i, enum file_write_flags flags) {
670         int r = 0;
671
672         assert(f);
673
674         STORE_RESET_ERRNO;
675
676         (void) fprintf(f, "%" PRId64, i);
677         if (flags & FILE_WRITE_NEWLINE_IF_NOT)
678                 (void) fputc('\n', f);
679
680         if (flags & FILE_WRITE_WITH_FFLUSH)
681                 (void) fflush(f);
682
683         if (ferror(f))
684                 r = errno ? -errno : -EIO;
685
686         RESTORE_ERRNO;
687
688         return r;
689 }
690
691 int write_int64_to_path(const char *path, int64_t i, enum file_write_flags flags) {
692         _cleanup_fclose_ FILE *f = NULL;
693
694         assert(path);
695
696         if (flags & FILE_WRITE_APPEND)
697                 f = fopen(path, "ae");
698         else
699                 f = fopen(path, "we");
700         if (!f)
701                 return -errno;
702
703         return write_int64_to_file(f, i, flags);
704 }
705
706 int write_uint64_to_file(FILE *f, uint64_t u, enum file_write_flags flags) {
707         int r = 0;
708
709         assert(f);
710
711         STORE_RESET_ERRNO;
712
713         (void) fprintf(f, "%" PRIu64, u);
714         if (flags & FILE_WRITE_NEWLINE_IF_NOT)
715                 (void) fputc('\n', f);
716
717         if (flags & FILE_WRITE_WITH_FFLUSH)
718                 (void) fflush(f);
719
720         if (ferror(f))
721                 r = errno ? -errno : -EIO;
722
723         RESTORE_ERRNO;
724
725         return r;
726 }
727
728 int write_uint64_to_path(const char *path, uint64_t u, enum file_write_flags flags) {
729         _cleanup_fclose_ FILE *f = NULL;
730
731         assert(path);
732
733         if (flags & FILE_WRITE_APPEND)
734                 f = fopen(path, "ae");
735         else
736                 f = fopen(path, "we");
737         if (!f)
738                 return -errno;
739
740         return write_uint64_to_file(f, u, flags);
741 }
742
743 int read_one_line_from_file(FILE *f, char **line) {
744         char t[LINE_MAX], *c;
745
746         assert(f);
747         assert(line);
748
749         STORE_RESET_ERRNO;
750
751         if (!fgets(t, sizeof(t), f)) {
752
753                 if (ferror(f)) {
754                         int r;
755
756                         r = errno ? -errno : -EIO;
757                         RESTORE_ERRNO;
758                         return r;
759                 }
760
761                 t[0] = 0;
762         }
763
764         RESTORE_ERRNO;
765
766         c = strdup(t);
767         if (!c)
768                 return -ENOMEM;
769
770         *line = truncate_nl(c);
771
772         return 0;
773 }
774
775 int read_one_line_from_path(const char *path, char **line) {
776         _cleanup_fclose_ FILE *f = NULL;
777
778         assert(path);
779         assert(line);
780
781         f = fopen(path, "re");
782         if (!f)
783                 return -errno;
784
785         return read_one_line_from_file(f, line);
786 }
787
788 int read_int32_from_file(FILE *f, int32_t *i) {
789         int r = 0;
790
791         assert(f);
792         assert(i);
793
794         STORE_RESET_ERRNO;
795
796         r = fscanf(f, "%d", i);
797         if (r == EOF && ferror(f))
798                 r = errno ? -errno : -EOF;
799
800         RESTORE_ERRNO;
801
802         return r;
803 }
804
805 int read_int32_from_path(const char *path, int32_t *i) {
806         _cleanup_fclose_ FILE *f = NULL;
807
808         assert(path);
809         assert(i);
810
811         f = fopen(path, "re");
812         if (!f)
813                 return -errno;
814
815         return read_int32_from_file(f, i);
816 }
817
818 int read_uint32_from_file(FILE *f, uint32_t *u) {
819         int r = 0;
820
821         assert(f);
822         assert(u);
823
824         STORE_RESET_ERRNO;
825
826         r = fscanf(f, "%u", u);
827         if (r == EOF && ferror(f))
828                 r = errno ? -errno : -EOF;
829
830         RESTORE_ERRNO;
831
832         return r;
833 }
834
835 int read_uint32_from_path(const char *path, uint32_t *u) {
836         _cleanup_fclose_ FILE *f = NULL;
837
838         assert(path);
839         assert(u);
840
841         f = fopen(path, "re");
842         if (!f)
843                 return -errno;
844
845         return read_uint32_from_file(f, u);
846 }
847
848 int read_int64_from_file(FILE *f, int64_t *i) {
849         int r = 0;
850
851         assert(f);
852         assert(i);
853
854         STORE_RESET_ERRNO;
855
856         r = fscanf(f, "%" SCNd64, i);
857         if (r == EOF && ferror(f))
858                 r = errno ? -errno : -EOF;
859
860         RESTORE_ERRNO;
861
862         return r;
863 }
864
865 int read_int64_from_path(const char *path, int64_t *i) {
866         _cleanup_fclose_ FILE *f = NULL;
867
868         assert(path);
869         assert(i);
870
871         f = fopen(path, "re");
872         if (!f)
873                 return -errno;
874
875         return read_int64_from_file(f, i);
876 }
877
878 int read_uint64_from_file(FILE *f, uint64_t *u) {
879         int r = 0;
880
881         assert(f);
882         assert(u);
883
884         STORE_RESET_ERRNO;
885
886         r = fscanf(f, "%" SCNu64, u);
887         if (r == EOF && ferror(f))
888                 r = errno ? -errno : -EOF;
889
890         RESTORE_ERRNO;
891
892         return r;
893 }
894
895 int read_uint64_from_path(const char *path, uint64_t *u) {
896         _cleanup_fclose_ FILE *f = NULL;
897
898         assert(path);
899         assert(u);
900
901         f = fopen(path, "re");
902         if (!f)
903                 return -errno;
904
905         return read_uint64_from_file(f, u);
906 }
907
908 int str_to_strv(const char *str, char ***strv, const char *separator) {
909         char *w, *state, *p;
910         char **v = NULL, **new = NULL;
911         size_t l;
912         size_t i = 0;
913
914         FOREACH_WORD_SEPARATOR(w, l, str, separator, state) {
915                 p = strndup(w, l);
916                 if (!p) {
917                         free(v);
918                         return -ENOMEM;
919                 }
920
921                 new = (char **)realloc(v, sizeof(char *) * (i + 2));
922                 if (!new) {
923                         free(p);
924                         free(v);
925                         p = NULL;
926                         return -ENOMEM;
927                 }
928
929                 v = new;
930
931                 v[i] = p;
932                 v[i+1] = NULL;
933                 i++;
934         }
935
936         *strv = v;
937
938         return 0;
939 }
940
941 size_t sizeof_strv(char **strv) {
942         size_t u = 0;
943
944         if (!strv)
945                 return 0;
946
947         while(strv[u++])
948                 ;
949
950         return u - 1;
951 }
952
953 int strv_attach(char **first, char **second, char ***strv, bool free_second) {
954         char **new = NULL;
955         size_t n1 = 0, n2 = 0;
956
957         assert(strv);
958
959         if (first)
960                 n1 = sizeof_strv(first);
961
962         if (second) {
963                 n2 = sizeof_strv(second);
964
965                 new = (char **)realloc(first, sizeof(char *) * (n1 + n2 + 1));
966                 if (!new)
967                         return -ENOMEM;
968
969                 first = new;
970
971                 memcpy(first + n1, second, sizeof(char *) * (n2 + 1));
972
973                 if (free_second)
974                         free(second);
975         }
976
977         *strv = first;
978
979         return 0;
980 }
981
982 void strv_free_full(char **strv) {
983         char **s;
984
985         if (!strv)
986                 return;
987
988         FOREACH_STRV(s, strv) {
989                 if (s && *s) {
990                         free(*s);
991                         *s = NULL;
992                 }
993         }
994
995         free(strv);
996         strv = NULL;
997 }
998
999 bool isdir(const char *path) {
1000         struct stat st;
1001
1002         assert(path);
1003
1004         if (lstat(path, &st) < 0)
1005                 return false;
1006
1007         return S_ISDIR(st.st_mode);
1008 }
1009
1010 int touch(const char *path) {
1011         _cleanup_fclose_ FILE *f = NULL;
1012
1013         assert(path);
1014
1015         f = fopen(path, "w");
1016         if (!f)
1017                 return -errno;
1018
1019         return 0;
1020 }
1021
1022 bool mnt_is_mounted(const char *fsname, const char *dir, const char *type, const char *opts) {
1023         struct mntent *ent;
1024         FILE *f = NULL;
1025         bool matched = false;
1026
1027         f = setmntent("/etc/mtab", "r");
1028         if (!f)
1029                 return false;
1030
1031         while ((ent = getmntent(f))) {
1032                 if (fsname) {
1033                         if (streq(fsname, ent->mnt_fsname))
1034                                 matched = true;
1035                         else
1036                                 goto no_match;
1037                 }
1038
1039                 if (dir) {
1040                         if (streq(dir, ent->mnt_dir))
1041                                 matched = true;
1042                         else
1043                                 goto no_match;
1044                 }
1045
1046                 if (type) {
1047                         if (streq(type, ent->mnt_type))
1048                                 matched = true;
1049                         else
1050                                 goto no_match;
1051                 }
1052
1053                 if (opts) {
1054                         if (streq(opts, ent->mnt_opts))
1055                                 matched = true;
1056                         else
1057                                 goto no_match;
1058                 }
1059
1060                 if (matched)
1061                         break;
1062
1063         no_match:
1064                 matched = false;
1065         }
1066
1067         endmntent(f);
1068
1069         return matched;
1070 }