]>
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>
32 #include "pathnames.h"
35 #include "canonicalize.h"
37 char *mnt_getenv_safe(const char *arg
)
39 if ((getuid() != geteuid()) || (getgid() != getegid()))
42 if (prctl(PR_GET_DUMPABLE
, 0, 0, 0, 0) == 0)
45 #if (defined(linux) && defined(SYS_prctl))
46 if (syscall(SYS_prctl
, PR_GET_DUMPABLE
, 0, 0, 0, 0) == 0)
51 #ifdef HAVE___SECURE_GETENV
52 return __secure_getenv(arg
);
58 int endswith(const char *s
, const char *sx
)
72 return !strcmp(s
+ off
, sx
);
75 int startswith(const char *s
, const char *sx
)
86 return !strncmp(s
, sx
, off
);
93 * Encode @str to be compatible with fstab/mtab
95 * Returns: new allocated string or NULL in case of error.
97 char *mnt_mangle(const char *str
)
106 * Decode @str from fstab/mtab
108 * Returns: new allocated string or NULL in case of error.
110 char *mnt_unmangle(const char *str
)
112 return unmangle(str
);
116 * mnt_fstype_is_pseudofs:
117 * @type: filesystem name
119 * Returns: 1 for filesystems like proc, sysfs, ... or 0.
121 int mnt_fstype_is_pseudofs(const char *type
)
125 if (strcmp(type
, "none") == 0 ||
126 strcmp(type
, "proc") == 0 ||
127 strcmp(type
, "tmpfs") == 0 ||
128 strcmp(type
, "sysfs") == 0 ||
129 strcmp(type
, "devpts") == 0||
130 strcmp(type
, "cgroups") == 0 ||
131 strcmp(type
, "devfs") == 0 ||
132 strcmp(type
, "dlmfs") == 0 ||
133 strcmp(type
, "cpuset") == 0 ||
134 strcmp(type
, "spufs") == 0)
140 * mnt_fstype_is_netfs:
141 * @type: filesystem name
143 * Returns: 1 for filesystems like cifs, nfs, ... or 0.
145 int mnt_fstype_is_netfs(const char *type
)
149 if (strcmp(type
, "cifs") == 0 ||
150 strcmp(type
, "smbfs") == 0 ||
151 strncmp(type
, "nfs", 3) == 0 ||
152 strcmp(type
, "afs") == 0 ||
153 strcmp(type
, "ncpfs") == 0)
160 * @type: filesystem type
161 * @pattern: filesystem name or comma delimitted list of names
163 * The @pattern list of filesystem can be prefixed with a global
164 * "no" prefix to invert matching of the whole list. The "no" could
165 * also used for individual items in the @pattern list. So,
166 * "nofoo,bar" has the same meaning as "nofoo,nobar".
168 * "bar" : "nofoo,bar" -> False (global "no" prefix)
170 * "bar" : "foo,bar" -> True
172 * "bar" : "foo,nobar" -> False
174 * Returns: 1 if type is matching, else 0. This function also returns
175 * 0 if @pattern is NULL and @type is non-NULL.
177 int mnt_match_fstype(const char *type
, const char *pattern
)
179 int no
= 0; /* negated types list */
183 if (!pattern
&& !type
)
188 if (!strncmp(pattern
, "no", 2)) {
193 /* Does type occur in types, separated by commas? */
197 if (!strncmp(p
, "no", 2) && !strncmp(p
+2, type
, len
) &&
198 (p
[len
+2] == 0 || p
[len
+2] == ','))
200 if (strncmp(p
, type
, len
) == 0 && (p
[len
] == 0 || p
[len
] == ','))
211 /* Returns 1 if needle found or noneedle not found in haystack
212 * Otherwise returns 0
214 static int check_option(const char *haystack
, size_t len
,
215 const char *needle
, size_t needle_len
)
220 if (needle_len
>= 2 && !strncmp(needle
, "no", 2)) {
226 for (p
= haystack
; p
&& p
< haystack
+ len
; p
++) {
227 char *sep
= strchr(p
, ',');
228 size_t plen
= sep
? sep
- p
: len
- (p
- haystack
);
230 if (plen
== needle_len
) {
231 if (!strncmp(p
, needle
, plen
))
232 return !no
; /* foo or nofoo was found */
237 return no
; /* foo or nofoo was not found */
242 * @optstr: options string
243 * @pattern: comma delimitted list of options
245 * The "no" could used for individual items in the @options list. The "no"
246 * prefix does not have a global meanning.
248 * Unlike fs type matching, nonetdev,user and nonetdev,nouser have
249 * DIFFERENT meanings; each option is matched explicitly as specified.
251 * "xxx,yyy,zzz" : "nozzz" -> False
253 * "xxx,yyy,zzz" : "xxx,noeee" -> True
255 * Returns: 1 if pattern is matching, else 0. This function also returns 0
256 * if @pattern is NULL and @optstr is non-NULL.
258 int mnt_match_options(const char *optstr
, const char *pattern
)
261 size_t len
, optstr_len
= 0;
263 if (!pattern
&& !optstr
)
268 len
= strlen(pattern
);
270 optstr_len
= strlen(optstr
);
272 for (p
= pattern
; p
< pattern
+ len
; p
++) {
273 char *sep
= strchr(p
, ',');
274 size_t plen
= sep
? sep
- p
: len
- (p
- pattern
);
277 continue; /* if two ',' appear in a row */
279 if (!check_option(optstr
, optstr_len
, p
, plen
))
280 return 0; /* any match failure means failure */
285 /* no match failures in list means success */
290 * Returns allocated string with username or NULL.
292 char *mnt_get_username(const uid_t uid
)
296 size_t sz
= sysconf(_SC_GETPW_R_SIZE_MAX
);
297 char *buf
, *username
= NULL
;
300 sz
= 16384; /* Should be more than enough */
306 if (!getpwuid_r(uid
, &pwd
, buf
, sz
, &res
) && res
)
307 username
= strdup(pwd
.pw_name
);
314 * Returns 1 if /etc/mtab is a reqular file.
316 int mnt_has_regular_mtab(void)
320 if (lstat(_PATH_MOUNTED
, &st
) == 0 && S_ISREG(st
.st_mode
))
326 * mnt_get_writable_mtab_path:
328 * It's not error if this function return NULL and errno is not set. In case of
329 * error the errno is set by open(2).
331 * Returns: pointer to the static string with path to mtab or NULL.
333 const char *mnt_get_writable_mtab_path(void)
335 struct stat mst
, ist
;
338 mtab
= !lstat(_PATH_MOUNTED
, &mst
);
339 info
= !stat(MNT_PATH_RUNDIR
, &ist
);
343 /* A) mtab is symlink, /var/run/mount is available */
344 if (mtab
&& S_ISLNK(mst
.st_mode
) && info
) {
345 int fd
= open(MNT_PATH_MOUNTINFO
, O_RDWR
| O_CREAT
, 0644);
348 return MNT_PATH_MOUNTINFO
;
350 return NULL
; /* probably EACCES */
353 /* B) classis system with /etc/mtab */
354 if (mtab
&& S_ISREG(mst
.st_mode
)) {
355 int fd
= open(_PATH_MOUNTED
, O_RDWR
, 0644);
358 return _PATH_MOUNTED
;
360 return NULL
; /* probably EACCES */
367 /* returns basename and keeps dirname in the @path, if @path is "/" (root)
368 * then returns empty string */
369 static char *stripoff_last_component(char *path
)
371 char *p
= strrchr(path
, '/');
379 char *mnt_get_mountpoint(const char *path
)
381 char *mnt
= strdup(path
);
387 if (*mnt
== '/' && *(mnt
+ 1) == '\0')
395 char *p
= stripoff_last_component(mnt
);
399 if (stat(*mnt
? mnt
: "/", &st
))
407 } while (mnt
&& *(mnt
+ 1) != '\0');
411 DBG(DEBUG_UTILS
, fprintf(stderr
,
412 "libmount: utils: fs-root for %s is %s\n", path
, mnt
));
419 char *mnt_get_fs_root(const char *path
, const char *mnt
)
421 char *m
= (char *) mnt
;
426 m
= mnt_get_mountpoint(path
);
431 p
= sz
> 1 ? path
+ sz
: path
;
436 return *p
? strdup(p
) : strdup("/");
440 int test_match_fstype(struct mtest
*ts
, int argc
, char *argv
[])
442 char *type
= argv
[1];
443 char *pattern
= argv
[2];
445 printf("%s\n", mnt_match_fstype(type
, pattern
) ? "MATCH" : "NOT-MATCH");
449 int test_match_options(struct mtest
*ts
, int argc
, char *argv
[])
451 char *optstr
= argv
[1];
452 char *pattern
= argv
[2];
454 printf("%s\n", mnt_match_options(optstr
, pattern
) ? "MATCH" : "NOT-MATCH");
458 int test_startswith(struct mtest
*ts
, int argc
, char *argv
[])
460 char *optstr
= argv
[1];
461 char *pattern
= argv
[2];
463 printf("%s\n", startswith(optstr
, pattern
) ? "YES" : "NOT");
467 int test_endswith(struct mtest
*ts
, int argc
, char *argv
[])
469 char *optstr
= argv
[1];
470 char *pattern
= argv
[2];
472 printf("%s\n", endswith(optstr
, pattern
) ? "YES" : "NOT");
476 int test_mountpoint(struct mtest
*ts
, int argc
, char *argv
[])
478 char *path
= canonicalize_path(argv
[1]),
479 *mnt
= path
? mnt_get_mountpoint(path
) : NULL
;
481 printf("%s: %s\n", argv
[1], mnt
? : "unknown");
487 int test_fsroot(struct mtest
*ts
, int argc
, char *argv
[])
489 char *path
= canonicalize_path(argv
[1]),
490 *mnt
= path
? mnt_get_fs_root(path
) : NULL
;
492 printf("%s: %s\n", argv
[1], mnt
? : "unknown");
498 int main(int argc
, char *argv
[])
500 struct mtest tss
[] = {
501 { "--match-fstype", test_match_fstype
, "<type> <pattern> FS types matching" },
502 { "--match-options", test_match_options
, "<options> <pattern> options matching" },
503 { "--starts-with", test_startswith
, "<string> <prefix>" },
504 { "--ends-with", test_endswith
, "<string> <prefix>" },
505 { "--mountpoint", test_mountpoint
, "<path>" },
506 { "--fs-root", test_fsroot
, "<path>" },
510 return mnt_run_test(tss
, argc
, argv
);
513 #endif /* TEST_PROGRAM */