]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - shlibs/mount/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.
17 #ifdef HAVE_SYS_PRCTL_H
18 #include <sys/prctl.h>
20 #define PR_GET_DUMPABLE 3
22 #if (!defined(HAVE_PRCTL) && defined(linux))
23 #include <sys/syscall.h>
27 #include <sys/types.h>
33 #include "pathnames.h"
36 #include "canonicalize.h"
38 char *mnt_getenv_safe(const char *arg
)
40 if ((getuid() != geteuid()) || (getgid() != getegid()))
43 if (prctl(PR_GET_DUMPABLE
, 0, 0, 0, 0) == 0)
46 #if (defined(linux) && defined(SYS_prctl))
47 if (syscall(SYS_prctl
, PR_GET_DUMPABLE
, 0, 0, 0, 0) == 0)
52 #ifdef HAVE___SECURE_GETENV
53 return __secure_getenv(arg
);
59 int endswith(const char *s
, const char *sx
)
73 return !strcmp(s
+ off
, sx
);
76 int startswith(const char *s
, const char *sx
)
87 return !strncmp(s
, sx
, off
);
94 * Encode @str to be compatible with fstab/mtab
96 * Returns: new allocated string or NULL in case of error.
98 char *mnt_mangle(const char *str
)
107 * Decode @str from fstab/mtab
109 * Returns: new allocated string or NULL in case of error.
111 char *mnt_unmangle(const char *str
)
113 return unmangle(str
);
117 * mnt_fstype_is_pseudofs:
118 * @type: filesystem name
120 * Returns: 1 for filesystems like proc, sysfs, ... or 0.
122 int mnt_fstype_is_pseudofs(const char *type
)
126 if (strcmp(type
, "none") == 0 ||
127 strcmp(type
, "proc") == 0 ||
128 strcmp(type
, "tmpfs") == 0 ||
129 strcmp(type
, "sysfs") == 0 ||
130 strcmp(type
, "devpts") == 0||
131 strcmp(type
, "cgroups") == 0 ||
132 strcmp(type
, "devfs") == 0 ||
133 strcmp(type
, "dlmfs") == 0 ||
134 strcmp(type
, "cpuset") == 0 ||
135 strcmp(type
, "securityfs") == 0 ||
136 strcmp(type
, "rpc_pipefs") == 0 ||
137 strcmp(type
, "fusectl") == 0 ||
138 strcmp(type
, "binfmt_misc") == 0 ||
139 strcmp(type
, "fuse.gvfs-fuse-daemon") == 0 ||
140 strcmp(type
, "debugfs") == 0 ||
141 strcmp(type
, "spufs") == 0)
147 * mnt_fstype_is_netfs:
148 * @type: filesystem name
150 * Returns: 1 for filesystems like cifs, nfs, ... or 0.
152 int mnt_fstype_is_netfs(const char *type
)
156 if (strcmp(type
, "cifs") == 0 ||
157 strcmp(type
, "smbfs") == 0 ||
158 strncmp(type
, "nfs", 3) == 0 ||
159 strcmp(type
, "afs") == 0 ||
160 strcmp(type
, "ncpfs") == 0)
167 * @type: filesystem type
168 * @pattern: filesystem name or comma delimitted list of names
170 * The @pattern list of filesystem can be prefixed with a global
171 * "no" prefix to invert matching of the whole list. The "no" could
172 * also used for individual items in the @pattern list. So,
173 * "nofoo,bar" has the same meaning as "nofoo,nobar".
175 * "bar" : "nofoo,bar" -> False (global "no" prefix)
177 * "bar" : "foo,bar" -> True
179 * "bar" : "foo,nobar" -> False
181 * Returns: 1 if type is matching, else 0. This function also returns
182 * 0 if @pattern is NULL and @type is non-NULL.
184 int mnt_match_fstype(const char *type
, const char *pattern
)
186 int no
= 0; /* negated types list */
190 if (!pattern
&& !type
)
195 if (!strncmp(pattern
, "no", 2)) {
200 /* Does type occur in types, separated by commas? */
204 if (!strncmp(p
, "no", 2) && !strncmp(p
+2, type
, len
) &&
205 (p
[len
+2] == 0 || p
[len
+2] == ','))
207 if (strncmp(p
, type
, len
) == 0 && (p
[len
] == 0 || p
[len
] == ','))
218 /* Returns 1 if needle found or noneedle not found in haystack
219 * Otherwise returns 0
221 static int check_option(const char *haystack
, size_t len
,
222 const char *needle
, size_t needle_len
)
227 if (needle_len
>= 2 && !strncmp(needle
, "no", 2)) {
233 for (p
= haystack
; p
&& p
< haystack
+ len
; p
++) {
234 char *sep
= strchr(p
, ',');
235 size_t plen
= sep
? sep
- p
: len
- (p
- haystack
);
237 if (plen
== needle_len
) {
238 if (!strncmp(p
, needle
, plen
))
239 return !no
; /* foo or nofoo was found */
244 return no
; /* foo or nofoo was not found */
249 * @optstr: options string
250 * @pattern: comma delimitted list of options
252 * The "no" could used for individual items in the @options list. The "no"
253 * prefix does not have a global meanning.
255 * Unlike fs type matching, nonetdev,user and nonetdev,nouser have
256 * DIFFERENT meanings; each option is matched explicitly as specified.
258 * "xxx,yyy,zzz" : "nozzz" -> False
260 * "xxx,yyy,zzz" : "xxx,noeee" -> True
262 * Returns: 1 if pattern is matching, else 0. This function also returns 0
263 * if @pattern is NULL and @optstr is non-NULL.
265 int mnt_match_options(const char *optstr
, const char *pattern
)
268 size_t len
, optstr_len
= 0;
270 if (!pattern
&& !optstr
)
275 len
= strlen(pattern
);
277 optstr_len
= strlen(optstr
);
279 for (p
= pattern
; p
< pattern
+ len
; p
++) {
280 char *sep
= strchr(p
, ',');
281 size_t plen
= sep
? sep
- p
: len
- (p
- pattern
);
284 continue; /* if two ',' appear in a row */
286 if (!check_option(optstr
, optstr_len
, p
, plen
))
287 return 0; /* any match failure means failure */
292 /* no match failures in list means success */
297 * Returns allocated string with username or NULL.
299 char *mnt_get_username(const uid_t uid
)
303 size_t sz
= sysconf(_SC_GETPW_R_SIZE_MAX
);
304 char *buf
, *username
= NULL
;
307 sz
= 16384; /* Should be more than enough */
313 if (!getpwuid_r(uid
, &pwd
, buf
, sz
, &res
) && res
)
314 username
= strdup(pwd
.pw_name
);
320 int mnt_get_uid(const char *username
, uid_t
*uid
)
324 size_t sz
= sysconf(_SC_GETPW_R_SIZE_MAX
);
328 sz
= 16384; /* Should be more than enough */
334 if (!getpwnam_r(username
, &pwd
, buf
, sz
, &pw
) && pw
)
341 int mnt_get_gid(const char *groupname
, gid_t
*gid
)
345 size_t sz
= sysconf(_SC_GETGR_R_SIZE_MAX
);
349 sz
= 16384; /* Should be more than enough */
355 if (!getgrnam_r(groupname
, &grp
, buf
, sz
, &gr
) && gr
)
363 * Returns 1 if /etc/mtab is a reqular file.
365 int mnt_has_regular_mtab(void)
369 if (lstat(_PATH_MOUNTED
, &st
) == 0 && S_ISREG(st
.st_mode
))
375 * mnt_get_writable_mtab_path:
377 * It's not error if this function return NULL and errno is not set. In case of
378 * error the errno is set by open(2).
380 * Returns: pointer to the static string with path to mtab or NULL.
382 const char *mnt_get_writable_mtab_path(void)
384 struct stat mst
, ist
;
387 mtab
= !lstat(_PATH_MOUNTED
, &mst
);
388 info
= !stat(MNT_PATH_RUNDIR
, &ist
);
392 /* A) mtab is symlink, /var/run/mount is available */
393 if (mtab
&& S_ISLNK(mst
.st_mode
) && info
) {
394 int fd
= open(MNT_PATH_MOUNTINFO
, O_RDWR
| O_CREAT
, 0644);
397 return MNT_PATH_MOUNTINFO
;
399 return NULL
; /* probably EACCES */
402 /* B) classis system with /etc/mtab */
403 if (mtab
&& S_ISREG(mst
.st_mode
)) {
404 int fd
= open(_PATH_MOUNTED
, O_RDWR
, 0644);
407 return _PATH_MOUNTED
;
409 return NULL
; /* probably EACCES */
416 /* returns basename and keeps dirname in the @path, if @path is "/" (root)
417 * then returns empty string */
418 static char *stripoff_last_component(char *path
)
420 char *p
= strrchr(path
, '/');
428 char *mnt_get_mountpoint(const char *path
)
430 char *mnt
= strdup(path
);
436 if (*mnt
== '/' && *(mnt
+ 1) == '\0')
444 char *p
= stripoff_last_component(mnt
);
448 if (stat(*mnt
? mnt
: "/", &st
))
456 } while (mnt
&& *(mnt
+ 1) != '\0');
460 DBG(UTILS
, mnt_debug("fs-root for %s is %s", path
, mnt
));
467 char *mnt_get_fs_root(const char *path
, const char *mnt
)
469 char *m
= (char *) mnt
;
474 m
= mnt_get_mountpoint(path
);
479 p
= sz
> 1 ? path
+ sz
: path
;
484 return *p
? strdup(p
) : strdup("/");
488 int test_match_fstype(struct mtest
*ts
, int argc
, char *argv
[])
490 char *type
= argv
[1];
491 char *pattern
= argv
[2];
493 printf("%s\n", mnt_match_fstype(type
, pattern
) ? "MATCH" : "NOT-MATCH");
497 int test_match_options(struct mtest
*ts
, int argc
, char *argv
[])
499 char *optstr
= argv
[1];
500 char *pattern
= argv
[2];
502 printf("%s\n", mnt_match_options(optstr
, pattern
) ? "MATCH" : "NOT-MATCH");
506 int test_startswith(struct mtest
*ts
, int argc
, char *argv
[])
508 char *optstr
= argv
[1];
509 char *pattern
= argv
[2];
511 printf("%s\n", startswith(optstr
, pattern
) ? "YES" : "NOT");
515 int test_endswith(struct mtest
*ts
, int argc
, char *argv
[])
517 char *optstr
= argv
[1];
518 char *pattern
= argv
[2];
520 printf("%s\n", endswith(optstr
, pattern
) ? "YES" : "NOT");
524 int test_mountpoint(struct mtest
*ts
, int argc
, char *argv
[])
526 char *path
= canonicalize_path(argv
[1]),
527 *mnt
= path
? mnt_get_mountpoint(path
) : NULL
;
529 printf("%s: %s\n", argv
[1], mnt
? : "unknown");
535 int test_fsroot(struct mtest
*ts
, int argc
, char *argv
[])
537 char *path
= canonicalize_path(argv
[1]),
538 *mnt
= path
? mnt_get_fs_root(path
, NULL
) : NULL
;
540 printf("%s: %s\n", argv
[1], mnt
? : "unknown");
546 int main(int argc
, char *argv
[])
548 struct mtest tss
[] = {
549 { "--match-fstype", test_match_fstype
, "<type> <pattern> FS types matching" },
550 { "--match-options", test_match_options
, "<options> <pattern> options matching" },
551 { "--starts-with", test_startswith
, "<string> <prefix>" },
552 { "--ends-with", test_endswith
, "<string> <prefix>" },
553 { "--mountpoint", test_mountpoint
, "<path>" },
554 { "--fs-root", test_fsroot
, "<path>" },
558 return mnt_run_test(tss
, argc
, argv
);
561 #endif /* TEST_PROGRAM */