]> git.ipfire.org Git - thirdparty/util-linux.git/blame - shlibs/mount/src/fs.c
libmount: add support for userdata and work with VFS tree
[thirdparty/util-linux.git] / shlibs / mount / src / fs.c
CommitLineData
d115ee9b
KZ
1/*
2 * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com>
3 *
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
6 *
7 * The mnt_fs is representation of one line in a fstab / mtab / mountinfo.
8 */
9
10#include <stdio.h>
11#include <string.h>
12#include <stdlib.h>
13#include <ctype.h>
3fca8422 14#include <errno.h>
d115ee9b
KZ
15#include <blkid/blkid.h>
16
17#include "nls.h"
18#include "mountP.h"
19
20/**
21 * mnt_new_fs:
22 *
23 * Returns newly allocated mnt_file fs.
24 */
25mnt_fs *mnt_new_fs(void)
26{
27 mnt_fs *fs = calloc(1, sizeof(struct _mnt_fs));
28 if (!fs)
29 return NULL;
30
31 INIT_LIST_HEAD(&fs->ents);
32 return fs;
33}
34
35/**
36 * mnt_free_fs:
37 * @fs: fs pointer
38 *
39 * Deallocates the fs.
40 */
41void mnt_free_fs(mnt_fs *fs)
42{
43 if (!fs)
44 return;
45 list_del(&fs->ents);
46
47 free(fs->source);
48 free(fs->tagname);
49 free(fs->tagval);
50 free(fs->mntroot);
51 free(fs->target);
52 free(fs->fstype);
53 free(fs->optstr);
54 free(fs->vfs_optstr);
55 free(fs->fs_optstr);
56
57 free(fs);
58}
59
26b4f9e4
KZ
60/**
61 * mnt_fs_get_userdata:
62 * @fs: mnt_file instance
63 *
64 * Returns private data set by mnt_fs_set_userdata() or NULL.
65 */
66void *mnt_fs_get_userdata(mnt_fs *fs)
67{
68 return fs ? fs->userdata : NULL;
69}
70
71/**
72 * mnt_fs_set_userdata:
73 * @fs: mnt_file instance
74 *
75 * The "userdata" are library independent data.
76 *
77 * Returns 0 or -1 in case of error (if @fs is NULL).
78 */
79int mnt_fs_set_userdata(mnt_fs *fs, void *data)
80{
81 if (!fs)
82 return -1;
83 fs->userdata = data;
84 return 0;
85}
86
d115ee9b
KZ
87/**
88 * mnt_fs_get_srcpath:
89 * @fs: mnt_file (fstab/mtab/mountinfo) fs
90 *
91 * The mount "source path" is:
92 * - a directory for 'bind' mounts (in fstab or mtab only)
93 * - a device name for standard mounts
94 * - NULL when path is not set (for example when TAG
95 * (LABEL/UUID) is defined)
96 *
97 * See also mnt_fs_get_tag() and mnt_fs_get_source().
98 *
99 * Returns mount "source" path or NULL in case of error or when the path
100 * is not defined.
101 *
102 */
103const char *mnt_fs_get_srcpath(mnt_fs *fs)
104{
105 assert(fs);
106 if (!fs)
107 return NULL;
108
109 /* fstab-like fs */
110 if (fs->tagname)
111 return NULL; /* the source contains a "NAME=value" */
112 return fs->source;
113}
114
115/**
116 * @fs: mnt_file (fstab/mtab/mountinfo) fs
117 *
118 * Returns mount "source". Note that the source could be unparsed TAG
119 * (LABEL/UUID). See also mnt_fs_get_srcpath() and mnt_fs_get_tag().
120 */
121const char *mnt_fs_get_source(mnt_fs *fs)
122{
123 return fs ? fs->source : NULL;
124}
125
126/* Used by parser mnt_file ONLY (@source has to be allocated) */
127int __mnt_fs_set_source(mnt_fs *fs, char *source)
128{
129 assert(fs);
130
131 if (!source)
132 return -1;
133
134 if (strchr(source, '=')) {
135 char *name, *val;
136
137 if (blkid_parse_tag_string(source, &name, &val) != 0)
138 return -1;
139
140 fs->tagval = val;
141 fs->tagname = name;
142 }
143
144 fs->source = source;
145 return 0;
146}
147
148/**
149 * mnt_fs_set_source:
150 * @fs: fstab/mtab/mountinfo entry
151 * @source: new source
152 *
153 * Returns 0 on success or -1 in case of error.
154 */
155int mnt_fs_set_source(mnt_fs *fs, const char *source)
156{
157 char *p;
158
159 if (!fs && !source)
160 return -1;
161
162 p = strdup(source);
163 if (!p)
164 return -1;
165
166 free(fs->tagval);
167 free(fs->tagname);
168 free(fs->source);
169 fs->tagval = fs->tagname = fs->source = NULL;
170
171 return __mnt_fs_set_source(fs, p);
172}
173
174/**
175 * mnt_fs_get_tag:
176 * @fs: fs
177 * @name: returns pointer to NAME string
178 * @value: returns pointer to VALUE string
179 *
180 * "TAG" is NAME=VALUE (e.g. LABEL=foo)
181 *
182 * The TAG is the first column in the fstab file. The TAG
183 * or "srcpath" has to be always set for all entries.
184 *
185 * See also mnt_fs_get_source().
186 *
187 * Example:
188 * char *src;
189 * mnt_fs *fs = mnt_file_find_target(mf, "/home");
190 *
191 * if (!fs)
192 * goto err;
193 *
194 * src = mnt_fs_get_srcpath(fs);
195 * if (!src) {
196 * char *tag, *val;
197 * if (mnt_fs_get_tag(fs, &tag, &val) == 0)
198 * printf("%s: %s\n", tag, val); // LABEL or UUID
199 * } else
200 * printf("device: %s\n", src); // device or bind path
201 *
202 * Returns 0 on success or -1 in case that a TAG is not defined.
203 */
204int mnt_fs_get_tag(mnt_fs *fs, const char **name, const char **value)
205{
206 if (fs == NULL || !fs->tagname)
207 return -1;
208 if (name)
209 *name = fs->tagname;
210 if (value)
211 *value = fs->tagval;
212 return 0;
213}
214
215/**
216 * mnt_fs_get_target:
217 * @fs: fstab/mtab/mountinfo entry pointer
218 *
219 * Returns pointer to mountpoint path or NULL
220 */
221const char *mnt_fs_get_target(mnt_fs *fs)
222{
223 assert(fs);
224 return fs ? fs->target : NULL;
225}
226
227/**
228 * mnt_fs_set_target:
229 * @fs: fstab/mtab/mountinfo entry
230 * @target: mountpoint
231 *
232 * Returns 0 on success or -1 in case of error.
233 */
234int mnt_fs_set_target(mnt_fs *fs, const char *target)
235{
236 char *p;
237
238 assert(fs);
239
240 if (!fs || !target)
241 return -1;
242
243 p = strdup(target);
244 if (!p)
245 return -1;
246 free(fs->target);
247 fs->target = p;
248
249 return 0;
250}
251
252/**
253 * mnt_fs_get_fstype:
254 * @fs: fstab/mtab/mountinfo entry pointer
255 *
256 * Returns pointer to filesystem type.
257 */
258const char *mnt_fs_get_fstype(mnt_fs *fs)
259{
260 assert(fs);
261 return fs ? fs->fstype : NULL;
262}
263
264/* Used by mnt_file parser only */
265int __mnt_fs_set_fstype(mnt_fs *fs, char *fstype)
266{
267 assert(fs);
268
269 if (!fstype)
270 return -1;
271
272 fs->fstype = fstype;
273 fs->flags &= ~MNT_FS_PSEUDO;
274 fs->flags &= ~MNT_FS_NET;
275
276 /* save info about pseudo filesystems */
277 if (mnt_fstype_is_pseudofs(fs->fstype))
278 fs->flags |= MNT_FS_PSEUDO;
279 else if (mnt_fstype_is_netfs(fs->fstype))
280 fs->flags |= MNT_FS_NET;
281
282 return 0;
283}
284
285/**
286 * mnt_fs_set_fstype:
287 * @fs: fstab/mtab/mountinfo entry
288 * @fstype: filesystem type
289 *
290 * Returns 0 on success or -1 in case of error.
291 */
292int mnt_fs_set_fstype(mnt_fs *fs, const char *fstype)
293{
294 char *p;
295
296 if (!fs || !fstype)
297 return -1;
298
299 p = strdup(fstype);
300 if (!p)
301 return -1;
302 free(fs->fstype);
303
304 return __mnt_fs_set_fstype(fs, p);
305}
306
307/**
308 * mnt_fs_get_optstr:
309 * @fs: fstab/mtab/mountinfo entry pointer
310 *
311 * Returns pointer to mount option string with all options (FS and VFS)
312 */
313const char *mnt_fs_get_optstr(mnt_fs *fs)
314{
315 assert(fs);
316 return fs ? fs->optstr : NULL;
317}
318
319/**
320 * mnt_fs_set_optstr:
321 * @fs: fstab/mtab/mountinfo entry
322 * @optstr: options string
323 *
324 * Returns 0 on success or -1 in case of error.
325 */
326int mnt_fs_set_optstr(mnt_fs *fs, const char *optstr)
327{
328 assert(fs);
329
330 if (!fs || !optstr)
331 return -1;
332 free(fs->optstr);
333 free(fs->fs_optstr);
334 free(fs->vfs_optstr);
335 fs->fs_optstr = fs->vfs_optstr = NULL;
336
337 fs->optstr = strdup(optstr);
338
339 return fs->optstr ? 0 : -1;
340}
341
342/**
343 * mnt_fs_get_fs_optstr:
344 * @fs: fstab/mtab/mountinfo entry pointer
345 *
346 * This function works for "mountinfo" files only.
347 *
348 * Returns pointer to superblock (fs-depend) mount option string or NULL.
349 */
350const char *mnt_fs_get_fs_optstr(mnt_fs *fs)
351{
352 assert(fs);
353 return fs ? fs->fs_optstr : NULL;
354}
355
356/**
357 * mnt_fs_get_vfs_optstr:
efe73c3e 358 * @fs: fstab/mtab entry pointer
d115ee9b
KZ
359 *
360 * This function works for "mountinfo" files only.
361 *
362 * Returns pointer to fs-independent (VFS) mount option string or NULL.
363 */
364const char *mnt_fs_get_vfs_optstr(mnt_fs *fs)
365{
366 assert(fs);
367 return fs ? fs->vfs_optstr : NULL;
368}
369
370
371/**
372 * mnt_fs_get_freq:
373 * @fs: fstab/mtab/mountinfo entry pointer
374 *
375 * Returns "dump frequency in days".
376 */
377int mnt_fs_get_freq(mnt_fs *fs)
378{
379 assert(fs);
380 return fs ? fs->freq : 0;
381}
382
383/**
384 * mnt_fs_set_freq:
efe73c3e 385 * @fs: fstab/mtab entry pointer
d115ee9b
KZ
386 * @freq: dump frequency in days
387 *
388 * Returns 0 on success or -1 in case of error.
389 */
390int mnt_fs_set_freq(mnt_fs *fs, int freq)
391{
392 assert(fs);
d115ee9b
KZ
393 if (!fs)
394 return -1;
395 fs->freq = freq;
396 return 0;
397}
398
399/**
400 * mnt_fs_get_passno:
efe73c3e 401 * @fs: fstab/mtab entry pointer
d115ee9b
KZ
402 *
403 * Returns "pass number on parallel fsck".
404 */
405int mnt_fs_get_passno(mnt_fs *fs)
406{
407 assert(fs);
408 return fs ? fs->passno: 0;
409}
410
411/**
412 * mnt_fs_set_passno:
efe73c3e 413 * @fs: fstab/mtab entry pointer
d115ee9b
KZ
414 * @passno: pass number
415 *
416 * Returns 0 on success or -1 in case of error.
417 */
418int mnt_fs_set_passno(mnt_fs *fs, int passno)
419{
420 assert(fs);
d115ee9b
KZ
421 if (!fs)
422 return -1;
423 fs->passno = passno;
424 return 0;
425}
426
efe73c3e
KZ
427/**
428 * mnt_fs_get_id:
429 * @fs: /proc/self/mountinfo entry
430 *
431 * Returns: mount ID (unique identifier of the mount) or -1 if ID undefined
432 * (for example if @fs is not mountinfo entry).
433 */
434int mnt_fs_get_id(mnt_fs *fs)
435{
436 assert(fs);
437 return fs ? fs->id : -1;
438}
439
440/**
441 * mnt_fs_get_parent_id:
442 * @fs: /proc/self/mountinfo entry
443 *
444 * Returns: parent mount ID or -1 if ID undefined (for example if @fs is not
445 * mountinfo entry).
446 */
447int mnt_fs_get_parent_id(mnt_fs *fs)
448{
449 assert(fs);
450 return fs ? fs->parent : -1;
451}
452
453/**
454 * mnt_fs_get_devno:
455 * @fs: /proc/self/mountinfo
456 *
457 * Returns: value of st_dev for files on filesystem or 0 in case of error.
458 */
459dev_t mnt_fs_get_devno(mnt_fs *fs)
460{
461 assert(fs);
462 return fs ? fs->devno : 0;
463}
464
d115ee9b
KZ
465/**
466 * mnt_fs_get_option:
467 * @fs: fstab/mtab/mountinfo entry pointer
468 * @name: option name
469 * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL
470 * @valsz: returns size of options value or 0
471 *
472 * Returns 0 on success, 1 when not found the @name or -1 in case of error.
473 */
474int mnt_fs_get_option(mnt_fs *fs, const char *name,
475 char **value, size_t *valsz)
476{
477 char *optstr = (char *) mnt_fs_get_optstr(fs);
478 return optstr ? mnt_optstr_get_option(optstr, name, value, valsz) : 1;
479}
480
3fca8422
KZ
481/**
482 * mnt_fs_match_target:
483 * @fs: filesystem
484 * @target: mountpoint path
485 * @cache: tags/paths cache or NULL
486 *
487 * Possible are three attempts:
488 * 1) compare @target with @fs->target
489 * 2) realpath(@target) with @fs->target
490 * 3) realpath(@target) with realpath(@fs->target).
491 *
492 * The 2nd and 3rd attempts are not performed when @cache is NULL.
493 *
494 * Returns 1 if @fs target is equal to @target else 0.
495 */
496int mnt_fs_match_target(mnt_fs *fs, const char *target, mnt_cache *cache)
497{
498 int rc = 0;
499
500 if (!fs || !target || !fs->target)
501 return 0;
502
503 /* 1) native paths */
504 rc = !strcmp(target, fs->target);
505
506 if (!rc && cache) {
507 /* 2) - canonicalized and non-canonicalized */
508 char *cn = mnt_resolve_path(target, cache);
509 rc = (cn && strcmp(cn, fs->target) == 0);
510
511 /* 3) - canonicalized and canonicalized */
512 if (!rc && cn) {
513 char *tcn = mnt_resolve_path(fs->target, cache);
514 rc = (tcn && strcmp(cn, tcn) == 0);
515 }
516 }
517
518 return rc;
519}
520
521/**
522 * mnt_fs_match_source:
523 * @fs: filesystem
524 * @source: tag or path (device or so)
525 * @cache: tags/paths cache or NULL
526 *
527 * Possible are four attempts:
528 * 1) compare @source with @fs->source
529 * 2) compare realpath(@source) with @fs->source
530 * 3) compare realpath(@source) with realpath(@fs->source)
531 * 4) compare realpath(@source) with evaluated tag from @fs->source
532 *
533 * The 2nd, 3rd and 4th attempts are not performed when @cache is NULL. The
534 * 2nd and 3rd attempts are not performed if @fs->source is tag.
535 *
536 * Returns 1 if @fs source is equal to @source else 0.
537 */
538int mnt_fs_match_source(mnt_fs *fs, const char *source, mnt_cache *cache)
539{
540 int rc = 0;
541 char *cn;
542 const char *src, *t, *v;
543
544 if (!fs || !source || !fs->source)
545 return 0;
546
547 /* 1) native paths/tags */
548 rc = !strcmp(source, fs->source);
549 if (rc || !cache)
550 return rc;
551
552 if (fs->flags & (MNT_FS_NET | MNT_FS_PSEUDO))
553 return 0;
554
555 cn = mnt_resolve_spec(source, cache);
556 if (!cn)
557 return 0;
558
559 /* 2) canonicalized and native */
560 src = mnt_fs_get_srcpath(fs);
561 if (src)
562 rc = !strcmp(cn, src);
563
564 /* 3) canonicalized and canonicalized */
565 if (src && !rc) {
566 src = mnt_resolve_path(src, cache);
567 rc = !strcmp(cn, src);
568 }
569 if (src && !rc)
570 /* fs->source is path and does not match with @source */
571 return 0;
572
573 if (mnt_fs_get_tag(fs, &t, &v))
574 return 0;
575
576 /* read @source's tags to the cache */
577 if (mnt_cache_read_tags(cache, cn) < 1) {
578 if (errno == EACCES) {
579 /* we don't have permissions to read TAGs from
580 * @source, but can translate @fs tag to devname.
581 *
582 * (because libblkid uses udev symlinks and this is
583 * accessible for non-root uses)
584 */
585 char *x = mnt_resolve_tag(t, v, cache);
586 if (x && !strcmp(x, cn))
587 return 1;
588 }
589 return 0;
590 }
591
592 /* 4) has the @source a tag that matches with tag from @fs ? */
593 if (!mnt_cache_device_has_tag(cache, cn, t, v))
594 return 0;
595
596 return 1;
597}
598
599/**
600 * mnt_fs_match_fstype:
601 * @fs: filesystem
602 * @types: filesystem name or comma delimited list of filesystems
603 *
604 * For more details see mnt_match_fstype().
605 *
606 * Returns 1 if @fs type is matching to @types else 0. The function returns
607 * 0 when types is NULL.
608 */
609int mnt_fs_match_fstype(mnt_fs *fs, const char *types)
610{
611 return mnt_match_fstype(fs->fstype, types);
612}
613
614/**
615 * mnt_fs_match_options:
616 * @fs: filesystem
617 * @options: comma delimited list of options (and nooptions)
618 *
619 * For more details see mnt_match_options().
620 *
621 * Returns 1 if @fs type is matching to @options else 0. The function returns
622 * 0 when types is NULL.
623 */
624int mnt_fs_match_options(mnt_fs *fs, const char *options)
625{
626 return mnt_match_options(fs->optstr, options);
627}
628
d115ee9b
KZ
629/* Unfortunately the classical Unix /etc/mtab and /etc/fstab
630 do not handle directory names containing spaces.
631 Here we mangle them, replacing a space by \040.
632 What do other Unices do? */
633
634static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' };
635
636static char *mangle(const char *s)
637{
638 char *ss, *sp;
639 int n;
640
641 n = strlen(s);
642 ss = sp = malloc(4*n+1);
643 if (!sp)
644 return NULL;
645 while(1) {
646 for (n = 0; n < sizeof(need_escaping); n++) {
647 if (*s == need_escaping[n]) {
648 *sp++ = '\\';
649 *sp++ = '0' + ((*s & 0300) >> 6);
650 *sp++ = '0' + ((*s & 070) >> 3);
651 *sp++ = '0' + (*s & 07);
652 goto next;
653 }
654 }
655 *sp++ = *s;
656 if (*s == 0)
657 break;
658 next:
659 s++;
660 }
661 return ss;
662}
663
664/**
665 * mnt_fprintf_line:
666 * @f: FILE
667 * @fmt: printf-like format string (see MNT_MFILE_PRINTFMT)
668 * @source: (spec) device name or tag=value
669 * @target: mountpoint
670 * @fstype: filesystem type
671 * @options: mount options
672 * @freq: dump frequency in days
673 * @passno: pass number on parallel fsck
674 *
675 * Returns return value from fprintf().
676 */
677int mnt_fprintf_line( FILE *f,
678 const char *fmt,
679 const char *source,
680 const char *target,
681 const char *fstype,
682 const char *options,
683 int freq,
684 int passno)
685{
686 char *m1 = NULL, *m2 = NULL, *m3 = NULL, *m4 = NULL;
687 int rc = -1;
688
689 if (!f || !fmt || !source || !target || !fstype || !options)
690 return -1;
691
692 m1 = mangle(source);
693 m2 = mangle(target);
694 m3 = mangle(fstype);
695 m4 = mangle(options);
696
697 if (!m1 || !m2 || !m3 || !m4)
698 goto done;
699
700 rc = fprintf(f, fmt, m1, m2, m3, m4, freq, passno);
701done:
702 free(m1);
703 free(m2);
704 free(m3);
705 free(m4);
706
707 return rc;
708}
709
710/**
711 * mnt_fs_fprintf:
712 * @fs: fstab/mtab/mountinfo entry
713 * @f: FILE
714 * @fmt: printf-like format string (see MNT_MFILE_PRINTFMT)
715 *
716 * Returns return value from fprintf().
717 */
718int mnt_fs_fprintf(mnt_fs *fs, FILE *f, const char *fmt)
719{
720 assert(fs);
721 assert(f);
722 assert(fmt);
723
724 if (!fs || !f)
725 return -1;
726
727 return mnt_fprintf_line(f, fmt,
728 mnt_fs_get_source(fs),
729 mnt_fs_get_target(fs),
730 mnt_fs_get_fstype(fs),
731 mnt_fs_get_optstr(fs),
732 mnt_fs_get_freq(fs),
733 mnt_fs_get_passno(fs));
734}
735
736/**
737 * mnt_fs_print_debug
738 * @fs: fstab/mtab/mountinfo entry
739 * @file: output
740 *
741 * Returns 0 on success or -1 in case of error.
742 */
743int mnt_fs_print_debug(mnt_fs *fs, FILE *file)
744{
745 if (!fs)
746 return -1;
747 fprintf(file, "------ fs: %p\n", fs);
748 fprintf(file, "source: %s\n", mnt_fs_get_source(fs));
749 fprintf(file, "target: %s\n", mnt_fs_get_target(fs));
750 fprintf(file, "fstype: %s\n", mnt_fs_get_fstype(fs));
751 fprintf(file, "optstr: %s\n", mnt_fs_get_optstr(fs));
752 fprintf(file, "freq: %d\n", mnt_fs_get_freq(fs));
753 fprintf(file, "pass: %d\n", mnt_fs_get_passno(fs));
efe73c3e
KZ
754 fprintf(file, "id: %d\n", mnt_fs_get_id(fs));
755 fprintf(file, "parent: %d\n", mnt_fs_get_parent_id(fs));
756 fprintf(file, "devno: %d:%d\n", major(mnt_fs_get_devno(fs)),
757 minor(mnt_fs_get_devno(fs)));
758
d115ee9b
KZ
759
760 return 0;
761}