]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/utils.c
2 * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com>
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
11 * @short_description: misc utils.
20 #include "pathnames.h"
23 #include "canonicalize.h"
26 #include "fileutils.h"
27 #include "statfs_magic.h"
29 int append_string(char **a
, const char *b
)
40 return !*a
? -ENOMEM
: 0;
46 tmp
= realloc(*a
, al
+ bl
+ 1);
50 memcpy((*a
) + al
, b
, bl
+ 1);
55 * Return 1 if the file is not accessible or empty
57 int is_file_empty(const char *name
)
62 return (stat(name
, &st
) != 0 || st
.st_size
== 0);
65 int mnt_valid_tagname(const char *tagname
)
67 if (tagname
&& *tagname
&& (
68 strcmp("UUID", tagname
) == 0 ||
69 strcmp("LABEL", tagname
) == 0 ||
70 strcmp("PARTUUID", tagname
) == 0 ||
71 strcmp("PARTLABEL", tagname
) == 0))
79 * @tag: NAME=value string
81 * Returns: 1 if the @tag is parsable and tag NAME= is supported by libmount, or 0.
83 int mnt_tag_is_valid(const char *tag
)
86 int rc
= tag
&& blkid_parse_tag_string(tag
, &t
, NULL
) == 0
87 && mnt_valid_tagname(t
);
93 int mnt_parse_offset(const char *str
, size_t len
, uintmax_t *res
)
101 p
= strndup(str
, len
);
105 if (strtosize(p
, res
))
111 /* used as a callback by bsearch in mnt_fstype_is_pseudofs() */
112 static int fstype_cmp(const void *v1
, const void *v2
)
114 const char *s1
= *(const char **)v1
;
115 const char *s2
= *(const char **)v2
;
117 return strcmp(s1
, s2
);
121 * Note that the @target has to be an absolute path (so at least "/"). The
122 * @filename returns an allocated buffer with the last path component, for example:
124 * mnt_chdir_to_parent("/mnt/test", &buf) ==> chdir("/mnt"), buf="test"
126 int mnt_chdir_to_parent(const char *target
, char **filename
)
128 char *buf
, *parent
, *last
= NULL
;
132 if (!target
|| *target
!= '/')
135 DBG(UTILS
, ul_debug("moving to %s parent", target
));
137 buf
= strdup(target
);
141 if (*(buf
+ 1) != '\0') {
142 last
= stripoff_last_component(buf
);
147 parent
= buf
&& *buf
? buf
: "/";
149 if (chdir(parent
) == -1) {
150 DBG(UTILS
, ul_debug("failed to chdir to %s: %m", parent
));
154 if (!getcwd(cwd
, sizeof(cwd
))) {
155 DBG(UTILS
, ul_debug("failed to obtain current directory: %m"));
159 if (strcmp(cwd
, parent
) != 0) {
161 "unexpected chdir (expected=%s, cwd=%s)", parent
, cwd
));
166 "current directory moved to %s [last_component='%s']",
173 memcpy(*filename
, ".", 2);
175 memmove(*filename
, last
, strlen(last
) + 1);
185 * Check if @path is on a read-only filesystem independently of file permissions.
187 int mnt_is_readonly(const char *path
)
189 if (access(path
, W_OK
) == 0)
196 #ifdef HAVE_UTIMENSAT
198 * access(2) returns EACCES on read-only FS:
200 * - for set-uid application if one component of the path is not
201 * accessible for the current rUID. (Note that euidaccess(2) does not
202 * check for EROFS at all).
204 * - for a read-write filesystem with a read-only VFS node (aka -o remount,ro,bind)
207 struct timespec times
[2];
209 times
[0].tv_nsec
= UTIME_NOW
; /* atime */
210 times
[1].tv_nsec
= UTIME_OMIT
; /* mtime */
212 if (utimensat(AT_FDCWD
, path
, times
, 0) == -1)
213 return errno
== EROFS
;
223 * Encode @str to be compatible with fstab/mtab
225 * Returns: newly allocated string or NULL in case of error.
227 char *mnt_mangle(const char *str
)
236 * Decode @str from fstab/mtab
238 * Returns: newly allocated string or NULL in case of error.
240 char *mnt_unmangle(const char *str
)
242 return unmangle(str
, NULL
);
246 * mnt_fstype_is_pseudofs:
247 * @type: filesystem name
249 * Returns: 1 for filesystems like proc, sysfs, ... or 0.
251 int mnt_fstype_is_pseudofs(const char *type
)
253 /* This array must remain sorted when adding new fstypes */
254 static const char *pseudofs
[] = {
269 "fuse.gvfs-fuse-daemon",
289 return !(bsearch(&type
, pseudofs
, ARRAY_SIZE(pseudofs
),
290 sizeof(char*), fstype_cmp
) == NULL
);
294 * mnt_fstype_is_netfs:
295 * @type: filesystem name
297 * Returns: 1 for filesystems like cifs, nfs, ... or 0.
299 int mnt_fstype_is_netfs(const char *type
)
303 if (strcmp(type
, "cifs") == 0 ||
304 strcmp(type
, "smbfs") == 0 ||
305 strncmp(type
,"nfs", 3) == 0 ||
306 strcmp(type
, "afs") == 0 ||
307 strcmp(type
, "ncpfs") == 0 ||
308 strncmp(type
,"9p", 2) == 0)
313 const char *mnt_statfs_get_fstype(struct statfs
*vfs
)
317 switch (vfs
->f_type
) {
318 case STATFS_ADFS_MAGIC
: return "adfs";
319 case STATFS_AFFS_MAGIC
: return "affs";
320 case STATFS_AFS_MAGIC
: return "afs";
321 case STATFS_AUTOFS_MAGIC
: return "autofs";
322 case STATFS_BDEVFS_MAGIC
: return "bdev";
323 case STATFS_BEFS_MAGIC
: return "befs";
324 case STATFS_BFS_MAGIC
: return "befs";
325 case STATFS_BINFMTFS_MAGIC
: return "binfmt_misc";
326 case STATFS_BTRFS_MAGIC
: return "btrfs";
327 case STATFS_CEPH_MAGIC
: return "ceph";
328 case STATFS_CGROUP_MAGIC
: return "cgroup";
329 case STATFS_CIFS_MAGIC
: return "cifs";
330 case STATFS_CODA_MAGIC
: return "coda";
331 case STATFS_CONFIGFS_MAGIC
: return "configfs";
332 case STATFS_CRAMFS_MAGIC
: return "cramfs";
333 case STATFS_DEBUGFS_MAGIC
: return "debugfs";
334 case STATFS_DEVPTS_MAGIC
: return "devpts";
335 case STATFS_ECRYPTFS_MAGIC
: return "ecryptfs";
336 case STATFS_EFIVARFS_MAGIC
: return "efivarfs";
337 case STATFS_EFS_MAGIC
: return "efs";
338 case STATFS_EXOFS_MAGIC
: return "exofs";
339 case STATFS_EXT4_MAGIC
: return "ext4"; /* all extN use the same magic */
340 case STATFS_F2FS_MAGIC
: return "f2fs";
341 case STATFS_FUSE_MAGIC
: return "fuse";
342 case STATFS_FUTEXFS_MAGIC
: return "futexfs";
343 case STATFS_GFS2_MAGIC
: return "gfs2";
344 case STATFS_HFSPLUS_MAGIC
: return "hfsplus";
345 case STATFS_HOSTFS_MAGIC
: return "hostfs";
346 case STATFS_HPFS_MAGIC
: return "hpfs";
347 case STATFS_HPPFS_MAGIC
: return "hppfs";
348 case STATFS_HUGETLBFS_MAGIC
: return "hugetlbfs";
349 case STATFS_ISOFS_MAGIC
: return "iso9660";
350 case STATFS_JFFS2_MAGIC
: return "jffs2";
351 case STATFS_JFS_MAGIC
: return "jfs";
352 case STATFS_LOGFS_MAGIC
: return "logfs";
353 case STATFS_MINIX2_MAGIC
:
354 case STATFS_MINIX2_MAGIC2
:
355 case STATFS_MINIX3_MAGIC
:
356 case STATFS_MINIX_MAGIC
:
357 case STATFS_MINIX_MAGIC2
: return "minix";
358 case STATFS_MQUEUE_MAGIC
: return "mqueue";
359 case STATFS_MSDOS_MAGIC
: return "vfat";
360 case STATFS_NCP_MAGIC
: return "ncp";
361 case STATFS_NFS_MAGIC
: return "nfs";
362 case STATFS_NILFS_MAGIC
: return "nilfs2";
363 case STATFS_NTFS_MAGIC
: return "ntfs";
364 case STATFS_OCFS2_MAGIC
: return "ocfs2";
365 case STATFS_OMFS_MAGIC
: return "omfs";
366 case STATFS_OPENPROMFS_MAGIC
: return "openpromfs";
367 case STATFS_PIPEFS_MAGIC
: return "pipefs";
368 case STATFS_PROC_MAGIC
: return "proc";
369 case STATFS_PSTOREFS_MAGIC
: return "pstore";
370 case STATFS_QNX4_MAGIC
: return "qnx4";
371 case STATFS_QNX6_MAGIC
: return "qnx6";
372 case STATFS_RAMFS_MAGIC
: return "ramfs";
373 case STATFS_REISERFS_MAGIC
: return "reiser4";
374 case STATFS_ROMFS_MAGIC
: return "romfs";
375 case STATFS_SECURITYFS_MAGIC
: return "securityfs";
376 case STATFS_SELINUXFS_MAGIC
: return "selinuxfs";
377 case STATFS_SMACKFS_MAGIC
: return "smackfs";
378 case STATFS_SMB_MAGIC
: return "smb";
379 case STATFS_SOCKFS_MAGIC
: return "sockfs";
380 case STATFS_SQUASHFS_MAGIC
: return "squashfs";
381 case STATFS_SYSFS_MAGIC
: return "sysfs";
382 case STATFS_TMPFS_MAGIC
: return "tmpfs";
383 case STATFS_UBIFS_MAGIC
: return "ubifs";
384 case STATFS_UDF_MAGIC
: return "udf";
385 case STATFS_UFS2_MAGIC
:
386 case STATFS_UFS_MAGIC
: return "ufs";
387 case STATFS_V9FS_MAGIC
: return "9p";
388 case STATFS_VXFS_MAGIC
: return "vxfs";
389 case STATFS_XENFS_MAGIC
: return "xenfs";
390 case STATFS_XFS_MAGIC
: return "xfs";
401 * @type: filesystem type
402 * @pattern: filesystem name or comma delimited list of names
404 * The @pattern list of filesystems can be prefixed with a global
405 * "no" prefix to invert matching of the whole list. The "no" could
406 * also be used for individual items in the @pattern list. So,
407 * "nofoo,bar" has the same meaning as "nofoo,nobar".
409 * "bar" : "nofoo,bar" -> False (global "no" prefix)
411 * "bar" : "foo,bar" -> True
413 * "bar" : "foo,nobar" -> False
415 * Returns: 1 if type is matching, else 0. This function also returns
416 * 0 if @pattern is NULL and @type is non-NULL.
418 int mnt_match_fstype(const char *type
, const char *pattern
)
420 return match_fstype(type
, pattern
);
424 /* Returns 1 if needle found or noneedle not found in haystack
425 * Otherwise returns 0
427 static int check_option(const char *haystack
, size_t len
,
428 const char *needle
, size_t needle_len
)
433 if (needle_len
>= 1 && *needle
== '+') {
436 } else if (needle_len
>= 2 && !strncmp(needle
, "no", 2)) {
442 for (p
= haystack
; p
&& p
< haystack
+ len
; p
++) {
443 char *sep
= strchr(p
, ',');
444 size_t plen
= sep
? (size_t) (sep
- p
) :
445 len
- (p
- haystack
);
447 if (plen
== needle_len
) {
448 if (!strncmp(p
, needle
, plen
))
449 return !no
; /* foo or nofoo was found */
454 return no
; /* foo or nofoo was not found */
459 * @optstr: options string
460 * @pattern: comma delimited list of options
462 * The "no" could be used for individual items in the @options list. The "no"
463 * prefix does not have a global meaning.
465 * Unlike fs type matching, nonetdev,user and nonetdev,nouser have
466 * DIFFERENT meanings; each option is matched explicitly as specified.
468 * The "no" prefix interpretation could be disabled by the "+" prefix, for example
469 * "+noauto" matches if @optstr literally contains the "noauto" string.
471 * "xxx,yyy,zzz" : "nozzz" -> False
473 * "xxx,yyy,zzz" : "xxx,noeee" -> True
475 * "bar,zzz" : "nofoo" -> True
477 * "nofoo,bar" : "+nofoo" -> True
479 * "bar,zzz" : "+nofoo" -> False
482 * Returns: 1 if pattern is matching, else 0. This function also returns 0
483 * if @pattern is NULL and @optstr is non-NULL.
485 int mnt_match_options(const char *optstr
, const char *pattern
)
488 size_t len
, optstr_len
= 0;
490 if (!pattern
&& !optstr
)
495 len
= strlen(pattern
);
497 optstr_len
= strlen(optstr
);
499 for (p
= pattern
; p
< pattern
+ len
; p
++) {
500 char *sep
= strchr(p
, ',');
501 size_t plen
= sep
? (size_t) (sep
- p
) :
505 continue; /* if two ',' appear in a row */
507 if (!check_option(optstr
, optstr_len
, p
, plen
))
508 return 0; /* any match failure means failure */
513 /* no match failures in list means success */
517 void mnt_free_filesystems(char **filesystems
)
523 for (p
= filesystems
; *p
; p
++)
528 static int add_filesystem(char ***filesystems
, char *name
)
537 for (n
= 0, p
= *filesystems
; *p
; p
++, n
++) {
538 if (strcmp(*p
, name
) == 0)
545 if (n
== 0 || !((n
+ 1) % MYCHUNK
)) {
546 size_t items
= ((n
+ 1 + MYCHUNK
) / MYCHUNK
) * MYCHUNK
;
547 char **x
= realloc(*filesystems
, items
* sizeof(char *));
556 (*filesystems
)[n
] = name
;
557 (*filesystems
)[n
+ 1] = NULL
;
560 mnt_free_filesystems(*filesystems
);
564 static int get_filesystems(const char *filename
, char ***filesystems
, const char *pattern
)
570 f
= fopen(filename
, "r" UL_CLOEXECSTR
);
574 DBG(UTILS
, ul_debug("reading filesystems list from: %s", filename
));
576 while (fgets(line
, sizeof(line
), f
)) {
577 char name
[sizeof(line
)];
579 if (*line
== '#' || strncmp(line
, "nodev", 5) == 0)
581 if (sscanf(line
, " %128[^\n ]\n", name
) != 1)
583 if (strcmp(name
, "*") == 0) {
585 break; /* end of the /etc/filesystems */
587 if (pattern
&& !mnt_match_fstype(name
, pattern
))
589 rc
= add_filesystem(filesystems
, name
);
599 * Always check the @filesystems pointer!
603 * ...mount will try to read the file /etc/filesystems, or, if that does not
604 * exist, /proc/filesystems. All of the filesystem types listed there will
605 * be tried, except for those that are labeled "nodev" (e.g., devpts,
606 * proc and nfs). If /etc/filesystems ends in a line with a single * only,
607 * mount will read /proc/filesystems afterwards.
609 int mnt_get_filesystems(char ***filesystems
, const char *pattern
)
618 rc
= get_filesystems(_PATH_FILESYSTEMS
, filesystems
, pattern
);
622 rc
= get_filesystems(_PATH_PROC_FILESYSTEMS
, filesystems
, pattern
);
623 if (rc
== 1 && *filesystems
)
624 rc
= 0; /* /proc/filesystems not found */
629 static size_t get_pw_record_size(void)
631 #ifdef _SC_GETPW_R_SIZE_MAX
632 long sz
= sysconf(_SC_GETPW_R_SIZE_MAX
);
640 * Returns an allocated string with username or NULL.
642 char *mnt_get_username(const uid_t uid
)
646 size_t sz
= get_pw_record_size();
647 char *buf
, *username
= NULL
;
653 if (!getpwuid_r(uid
, &pwd
, buf
, sz
, &res
) && res
)
654 username
= strdup(pwd
.pw_name
);
660 int mnt_get_uid(const char *username
, uid_t
*uid
)
665 size_t sz
= get_pw_record_size();
668 if (!username
|| !uid
)
675 if (!getpwnam_r(username
, &pwd
, buf
, sz
, &pw
) && pw
) {
680 "cannot convert '%s' username to UID", username
));
681 rc
= errno
? -errno
: -EINVAL
;
688 int mnt_get_gid(const char *groupname
, gid_t
*gid
)
693 size_t sz
= get_pw_record_size();
696 if (!groupname
|| !gid
)
703 if (!getgrnam_r(groupname
, &grp
, buf
, sz
, &gr
) && gr
) {
708 "cannot convert '%s' groupname to GID", groupname
));
709 rc
= errno
? -errno
: -EINVAL
;
716 int mnt_in_group(gid_t gid
)
724 n
= getgroups(0, NULL
);
728 grps
= malloc(n
* sizeof(*grps
));
732 if (getgroups(n
, grps
) == n
) {
733 for (i
= 0; i
< n
; i
++) {
734 if (grps
[i
] == gid
) {
745 static int try_write(const char *filename
)
752 fd
= open(filename
, O_RDWR
|O_CREAT
|O_CLOEXEC
,
753 S_IWUSR
|S_IRUSR
|S_IRGRP
|S_IROTH
);
762 * mnt_has_regular_mtab:
763 * @mtab: returns path to mtab
764 * @writable: returns 1 if the file is writable
766 * If the file does not exist and @writable argument is not NULL, then it will
767 * try to create the file.
769 * Returns: 1 if /etc/mtab is a regular file, and 0 in case of error (check
770 * errno for more details).
772 int mnt_has_regular_mtab(const char **mtab
, int *writable
)
776 const char *filename
= mtab
&& *mtab
? *mtab
: mnt_get_mtab_path();
783 DBG(UTILS
, ul_debug("mtab: %s", filename
));
785 rc
= lstat(filename
, &st
);
789 if (S_ISREG(st
.st_mode
)) {
791 *writable
= !try_write(filename
);
797 /* try to create the file */
799 *writable
= !try_write(filename
);
805 DBG(UTILS
, ul_debug("%s: irregular/non-writable", filename
));
810 * Don't export this to libmount API -- utab is private library stuff.
812 * If the file does not exist and @writable argument is not NULL, then it will
813 * try to create the directory (e.g. /run/mount) and the file.
815 * Returns: 1 if utab is a regular file, and 0 in case of
816 * error (check errno for more details).
818 int mnt_has_regular_utab(const char **utab
, int *writable
)
822 const char *filename
= utab
&& *utab
? *utab
: mnt_get_utab_path();
829 DBG(UTILS
, ul_debug("utab: %s", filename
));
831 rc
= lstat(filename
, &st
);
835 if (S_ISREG(st
.st_mode
)) {
837 *writable
= !try_write(filename
);
840 goto done
; /* it's not a regular file */
844 char *dirname
= strdup(filename
);
849 stripoff_last_component(dirname
); /* remove filename */
851 rc
= mkdir(dirname
, S_IWUSR
|
852 S_IRUSR
|S_IRGRP
|S_IROTH
|
853 S_IXUSR
|S_IXGRP
|S_IXOTH
);
855 if (rc
&& errno
!= EEXIST
)
856 goto done
; /* probably EACCES */
858 *writable
= !try_write(filename
);
863 DBG(UTILS
, ul_debug("%s: irregular/non-writable file", filename
));
868 * mnt_get_swaps_path:
870 * Returns: path to /proc/swaps or $LIBMOUNT_SWAPS.
872 const char *mnt_get_swaps_path(void)
874 const char *p
= safe_getenv("LIBMOUNT_SWAPS");
875 return p
? : _PATH_PROC_SWAPS
;
879 * mnt_get_fstab_path:
881 * Returns: path to /etc/fstab or $LIBMOUNT_FSTAB.
883 const char *mnt_get_fstab_path(void)
885 const char *p
= safe_getenv("LIBMOUNT_FSTAB");
886 return p
? : _PATH_MNTTAB
;
892 * This function returns the *default* location of the mtab file. The result does
893 * not have to be writable. See also mnt_has_regular_mtab().
895 * Returns: path to /etc/mtab or $LIBMOUNT_MTAB.
897 const char *mnt_get_mtab_path(void)
899 const char *p
= safe_getenv("LIBMOUNT_MTAB");
900 return p
? : _PATH_MOUNTED
;
904 * Don't export this to libmount API -- utab is private library stuff.
906 * Returns: path to /run/mount/utab (or /dev/.mount/utab) or $LIBMOUNT_UTAB.
908 const char *mnt_get_utab_path(void)
911 const char *p
= safe_getenv("LIBMOUNT_UTAB");
916 if (stat(MNT_RUNTIME_TOPDIR
, &st
) == 0)
917 return MNT_PATH_UTAB
;
919 return MNT_PATH_UTAB_OLD
;
923 /* returns file descriptor or -errno, @name returns a unique filename
925 int mnt_open_uniq_filename(const char *filename
, char **name
)
936 rc
= asprintf(&n
, "%s.XXXXXX", filename
);
940 /* This is for very old glibc and for compatibility with Posix, which says
941 * nothing about mkstemp() mode. All sane glibc use secure mode (0600).
943 oldmode
= umask(S_IRGRP
|S_IWGRP
|S_IXGRP
|
944 S_IROTH
|S_IWOTH
|S_IXOTH
);
945 fd
= mkostemp(n
, O_RDWR
|O_CREAT
|O_EXCL
|O_CLOEXEC
);
959 * mnt_get_mountpoint:
962 * This function finds the mountpoint that a given path resides in. @path
963 * should be canonicalized. The returned pointer should be freed by the caller.
965 * Returns: allocated string with the target of the mounted device or NULL on error
967 char *mnt_get_mountpoint(const char *path
)
978 if (*mnt
== '/' && *(mnt
+ 1) == '\0')
986 char *p
= stripoff_last_component(mnt
);
990 if (stat(*mnt
? mnt
: "/", &st
))
999 } while (mnt
&& *(mnt
+ 1) != '\0');
1001 memcpy(mnt
, "/", 2);
1003 DBG(UTILS
, ul_debug("%s mountpoint is %s", path
, mnt
));
1010 char *mnt_get_fs_root(const char *path
, const char *mnt
)
1012 char *m
= (char *) mnt
, *res
;
1017 m
= mnt_get_mountpoint(path
);
1022 p
= sz
> 1 ? path
+ sz
: path
;
1027 res
= *p
? strdup(p
) : strdup("/");
1028 DBG(UTILS
, ul_debug("%s fs-root is %s", path
, res
));
1033 * Search for @name kernel command parametr.
1035 * Returns newly allocated string with a parameter argument if the @name is
1036 * specified as "name=" or returns pointer to @name or returns NULL if not
1037 * found. If it is specified more than once, we grab the last copy.
1039 * For example cmdline: "aaa bbb=BBB ccc"
1041 * @name is "aaa" --returns--> "aaa" (pointer to @name)
1042 * @name is "bbb=" --returns--> "BBB" (allocated)
1043 * @name is "foo" --returns--> NULL
1045 * Note: It is not really feasible to parse the command line exactly the same
1046 * as the kernel does since we don't know which options are valid. We can use
1047 * the -- marker though and not walk past that.
1049 char *mnt_get_kernel_cmdline_option(const char *name
)
1054 char *p
, *res
= NULL
, *mem
= NULL
;
1055 char buf
[BUFSIZ
]; /* see kernel include/asm-generic/setup.h: COMMAND_LINE_SIZE */
1056 const char *path
= _PATH_PROC_CMDLINE
;
1058 if (!name
|| !name
[0])
1062 path
= getenv("LIBMOUNT_KERNEL_CMDLINE");
1064 path
= _PATH_PROC_CMDLINE
;
1066 f
= fopen(path
, "r" UL_CLOEXECSTR
);
1070 p
= fgets(buf
, sizeof(buf
), f
);
1073 if (!p
|| !*p
|| *p
== '\n')
1076 p
= strstr(p
, " -- ");
1078 /* no more kernel args after this */
1082 buf
[len
- 1] = '\0'; /* remove last '\n' */
1086 if (name
[len
- 1] == '=')
1089 for (p
= buf
; p
&& *p
; p
++) {
1090 if (!(p
= strstr(p
, name
)))
1091 break; /* not found the option */
1092 if (p
!= buf
&& !isblank(*(p
- 1)))
1093 continue; /* no space before the option */
1094 if (!val
&& *(p
+ len
) != '\0' && !isblank(*(p
+ len
)))
1095 continue; /* no space after the option */
1100 while (*p
&& !isblank(*p
)) /* jump to the end of the argument */
1105 res
= mem
= strdup(v
);
1109 res
= (char *) name
; /* option without '=' */
1110 /* don't break -- keep scanning for more options */
1117 int test_match_fstype(struct libmnt_test
*ts
, int argc
, char *argv
[])
1119 char *type
= argv
[1];
1120 char *pattern
= argv
[2];
1122 printf("%s\n", mnt_match_fstype(type
, pattern
) ? "MATCH" : "NOT-MATCH");
1126 int test_match_options(struct libmnt_test
*ts
, int argc
, char *argv
[])
1128 char *optstr
= argv
[1];
1129 char *pattern
= argv
[2];
1131 printf("%s\n", mnt_match_options(optstr
, pattern
) ? "MATCH" : "NOT-MATCH");
1135 int test_startswith(struct libmnt_test
*ts
, int argc
, char *argv
[])
1137 char *optstr
= argv
[1];
1138 char *pattern
= argv
[2];
1140 printf("%s\n", startswith(optstr
, pattern
) ? "YES" : "NOT");
1144 int test_endswith(struct libmnt_test
*ts
, int argc
, char *argv
[])
1146 char *optstr
= argv
[1];
1147 char *pattern
= argv
[2];
1149 printf("%s\n", endswith(optstr
, pattern
) ? "YES" : "NOT");
1153 int test_appendstr(struct libmnt_test
*ts
, int argc
, char *argv
[])
1155 char *str
= strdup(argv
[1]);
1156 const char *ap
= argv
[2];
1158 append_string(&str
, ap
);
1159 printf("new string: '%s'\n", str
);
1165 int test_mountpoint(struct libmnt_test
*ts
, int argc
, char *argv
[])
1167 char *path
= canonicalize_path(argv
[1]),
1168 *mnt
= path
? mnt_get_mountpoint(path
) : NULL
;
1170 printf("%s: %s\n", argv
[1], mnt
? : "unknown");
1176 int test_fsroot(struct libmnt_test
*ts
, int argc
, char *argv
[])
1178 char *path
= canonicalize_path(argv
[1]),
1179 *mnt
= path
? mnt_get_fs_root(path
, NULL
) : NULL
;
1181 printf("%s: %s\n", argv
[1], mnt
? : "unknown");
1187 int test_filesystems(struct libmnt_test
*ts
, int argc
, char *argv
[])
1189 char **filesystems
= NULL
;
1192 rc
= mnt_get_filesystems(&filesystems
, argc
? argv
[1] : NULL
);
1195 for (p
= filesystems
; *p
; p
++)
1197 mnt_free_filesystems(filesystems
);
1202 int test_chdir(struct libmnt_test
*ts
, int argc
, char *argv
[])
1205 char *path
= canonicalize_path(argv
[1]),
1211 rc
= mnt_chdir_to_parent(path
, &last
);
1213 printf("path='%s', abs='%s', last='%s'\n",
1214 argv
[1], path
, last
);
1221 int test_kernel_cmdline(struct libmnt_test
*ts
, int argc
, char *argv
[])
1223 char *name
= argv
[1];
1226 res
= mnt_get_kernel_cmdline_option(name
);
1228 printf("'%s' not found\n", name
);
1229 else if (res
== name
)
1230 printf("'%s' found\n", name
);
1232 printf("'%s' found, argument: '%s'\n", name
, res
);
1239 int test_mkdir(struct libmnt_test
*ts
, int argc
, char *argv
[])
1243 rc
= mkdir_p(argv
[1], S_IRWXU
|
1247 printf("mkdir %s failed\n", argv
[1]);
1251 int test_statfs_type(struct libmnt_test
*ts
, int argc
, char *argv
[])
1256 rc
= statfs(argv
[1], &vfs
);
1258 printf("%s: statfs failed: %m\n", argv
[1]);
1260 printf("%-30s: statfs type: %-12s [0x%lx]\n", argv
[1],
1261 mnt_statfs_get_fstype(&vfs
),
1267 int main(int argc
, char *argv
[])
1269 struct libmnt_test tss
[] = {
1270 { "--match-fstype", test_match_fstype
, "<type> <pattern> FS types matching" },
1271 { "--match-options", test_match_options
, "<options> <pattern> options matching" },
1272 { "--filesystems", test_filesystems
, "[<pattern>] list /{etc,proc}/filesystems" },
1273 { "--starts-with", test_startswith
, "<string> <prefix>" },
1274 { "--ends-with", test_endswith
, "<string> <prefix>" },
1275 { "--append-string", test_appendstr
, "<string> <appendix>" },
1276 { "--mountpoint", test_mountpoint
, "<path>" },
1277 { "--fs-root", test_fsroot
, "<path>" },
1278 { "--cd-parent", test_chdir
, "<path>" },
1279 { "--kernel-cmdline",test_kernel_cmdline
, "<option> | <option>=" },
1280 { "--mkdir", test_mkdir
, "<path>" },
1281 { "--statfs-type", test_statfs_type
, "<path>" },
1286 return mnt_run_test(tss
, argc
, argv
);
1289 #endif /* TEST_PROGRAM */