if (mnt_context_is_nocanonicalize(cxt))
mnt_context_set_tabfilter(cxt, mountinfo_filter, (void *) tgt);
- else if (mnt_stat_mountpoint(tgt, &st) == 0 && S_ISDIR(st.st_mode)) {
+ else if (mnt_safe_stat(tgt, &st) == 0 && S_ISDIR(st.st_mode)) {
cache = mnt_context_get_cache(cxt);
cn_tgt = mnt_resolve_path(tgt, cache);
if (cn_tgt)
if (!ns_old)
return -MNT_ERR_NAMESPACE;
- /* Ignore errors when search in $PATH and do not modify
- * @rc due to stat() etc.
+ /* Ignore errors when search in $PATH and do not modify @rc
*/
path = strtok_r(search_path, ":", &p);
while (path) {
char helper[PATH_MAX];
- struct stat st;
- int xrc;
+ int len, found = 0;
- xrc = snprintf(helper, sizeof(helper), "%s/%s.%s",
+ len = snprintf(helper, sizeof(helper), "%s/%s.%s",
path, name, type);
path = strtok_r(NULL, ":", &p);
- if (xrc < 0 || (size_t) xrc >= sizeof(helper))
+ if (len < 0 || (size_t) len >= sizeof(helper))
continue;
- xrc = stat(helper, &st);
- if (xrc == -1 && errno == ENOENT && strchr(type, '.')) {
+ found = mnt_is_path(helper);
+ if (!found && strchr(type, '.')) {
/* If type ends with ".subtype" try without it */
char *hs = strrchr(helper, '.');
if (hs)
*hs = '\0';
- xrc = stat(helper, &st);
+ found = mnt_is_path(helper);
}
DBG(CXT, ul_debugobj(cxt, "%-25s ... %s", helper,
- xrc ? "not found" : "found"));
- if (xrc)
+ found ? "found" : "not found"));
+ if (!found)
continue;
/* success */
if (!buf)
break;
if (geteuid() == 0) {
- if (mnt_stat_mountpoint(tgt, &st) || !S_ISDIR(st.st_mode))
+ if (mnt_safe_stat(tgt, &st) || !S_ISDIR(st.st_mode))
snprintf(buf, bufsz, _("mount point is not a directory"));
else
snprintf(buf, bufsz, _("permission denied"));
snprintf(buf, bufsz, _("%s already mounted or mount point busy"), src);
break;
case ENOENT:
- if (tgt && mnt_lstat_mountpoint(tgt, &st)) {
+ if (tgt && mnt_safe_lstat(tgt, &st)) {
if (buf)
snprintf(buf, bufsz, _("mount point does not exist"));
- } else if (tgt && mnt_stat_mountpoint(tgt, &st)) {
+ } else if (tgt && mnt_safe_stat(tgt, &st)) {
if (buf)
snprintf(buf, bufsz, _("mount point is a symbolic link to nowhere"));
- } else if (src && stat(src, &st)) {
+ } else if (src && !mnt_is_path(src)) {
if (uflags & MNT_MS_NOFAIL)
return MNT_EX_SUCCESS;
if (buf)
break;
case ENOTDIR:
- if (mnt_stat_mountpoint(tgt, &st) || ! S_ISDIR(st.st_mode)) {
+ if (mnt_safe_stat(tgt, &st) || ! S_ISDIR(st.st_mode)) {
if (buf)
snprintf(buf, bufsz, _("mount point is not a directory"));
- } else if (src && stat(src, &st) && errno == ENOTDIR) {
+ } else if (src && !mnt_is_path(src)) {
if (uflags & MNT_MS_NOFAIL)
return MNT_EX_SUCCESS;
if (buf)
return MNT_EX_SUCCESS;
if (!buf)
break;
- if (src && stat(src, &st))
+ if (src && mnt_safe_stat(src, &st))
snprintf(buf, bufsz, _("%s is not a block device, and stat(2) fails?"), src);
else if (src && S_ISBLK(st.st_mode))
snprintf(buf, bufsz,
case EBADMSG:
/* Bad CRC for classic filesystems (e.g. extN or XFS) */
- if (buf && src && stat(src, &st) == 0
+ if (buf && src && mnt_safe_stat(src, &st) == 0
&& (S_ISBLK(st.st_mode) || S_ISREG(st.st_mode))) {
snprintf(buf, bufsz, _("cannot mount; probably corrupted filesystem on %s"), src);
break;
*/
struct stat st;
- if (mnt_stat_mountpoint(tgt, &st) == 0 && S_ISREG(st.st_mode)) {
+ if (mnt_safe_stat(tgt, &st) == 0 && S_ISREG(st.st_mode)) {
int count;
struct libmnt_cache *cache = mnt_context_get_cache(cxt);
const char *bf = cache ? mnt_resolve_path(tgt, cache) : tgt;
|| mnt_context_is_lazy(cxt)
|| mnt_context_is_nocanonicalize(cxt)
|| mnt_context_is_loopdel(cxt)
- || mnt_stat_mountpoint(tgt, &st) != 0 || !S_ISDIR(st.st_mode)
+ || mnt_safe_stat(tgt, &st) != 0 || !S_ISDIR(st.st_mode)
|| has_utab_entry(cxt, tgt))
return 1; /* not found */
extern char *mnt_get_kernel_cmdline_option(const char *name);
-extern int mnt_stat_mountpoint(const char *target, struct stat *st);
-extern int mnt_lstat_mountpoint(const char *target, struct stat *st);
+extern int mnt_safe_stat(const char *target, struct stat *st);
+extern int mnt_safe_lstat(const char *target, struct stat *st);
extern int mnt_is_path(const char *target);
extern int mnt_tmptgt_unshare(int *old_ns_fd);
struct stat st;
devno = mnt_fs_get_devno(fstab_fs);
- if (!devno && stat(src, &st) == 0 && S_ISBLK(st.st_mode))
+ if (!devno && mnt_safe_stat(src, &st) == 0 && S_ISBLK(st.st_mode))
devno = st.st_rdev;
}
struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt, int empty_for_enoent)
{
struct libmnt_table *tb;
- struct stat st;
if (!filename)
return NULL;
- if (stat(filename, &st))
+ if (!mnt_is_path(filename))
return empty_for_enoent ? mnt_new_table() : NULL;
tb = mnt_new_table();
filename = mnt_get_fstab_path();
if (!filename)
return -EINVAL;
- if (stat(filename, &st) != 0)
+ if (mnt_safe_stat(filename, &st) != 0)
return -errno;
tb->fmt = MNT_FMT_FSTAB;
return strcmp(s1, s2);
}
+/* This very simplified stat() alternative uses cached VFS data and does not
+ * directly ask the filesystem for details. It requires a kernel that supports
+ * statx(). It's usable only for file type, rdev and ino!
+ */
static int safe_stat(const char *target, struct stat *st, int nofollow)
{
assert(target);
if (rc == 0) {
st->st_ino = stx.stx_ino;
st->st_dev = makedev(stx.stx_dev_major, stx.stx_dev_minor);
+ st->st_rdev = makedev(stx.stx_rdev_major, stx.stx_rdev_minor);
st->st_mode = stx.stx_mode;
}
- return rc;
+
+ if (rc == 0 || errno != EOPNOTSUPP)
+ return rc;
}
-#else
-# ifdef AT_NO_AUTOMOUNT
+#endif
+
+#ifdef AT_NO_AUTOMOUNT
return fstatat(AT_FDCWD, target, st,
AT_NO_AUTOMOUNT | (nofollow ? AT_SYMLINK_NOFOLLOW : 0));
-# else
- return nofollow ? lstat(target, st) : stat(target, st);
-# endif
#endif
+ return nofollow ? lstat(target, st) : stat(target, st);
}
-int mnt_stat_mountpoint(const char *target, struct stat *st)
+int mnt_safe_stat(const char *target, struct stat *st)
{
return safe_stat(target, st, 0);
}
-int mnt_lstat_mountpoint(const char *target, struct stat *st)
+int mnt_safe_lstat(const char *target, struct stat *st)
{
return safe_stat(target, st, 1);
}
if (*mnt == '/' && *(mnt + 1) == '\0')
goto done;
- if (mnt_stat_mountpoint(mnt, &st))
+ if (mnt_safe_stat(mnt, &st))
goto err;
base = st.st_dev;
if (!p)
break;
- if (mnt_stat_mountpoint(*mnt ? mnt : "/", &st))
+ if (mnt_safe_stat(*mnt ? mnt : "/", &st))
goto err;
dir = st.st_dev;
if (dir != base) {
int rc;
if (strcmp(argv[0], "--lstat") == 0)
- rc = mnt_lstat_mountpoint(path, &st);
+ rc = mnt_safe_lstat(path, &st);
else
- rc = mnt_stat_mountpoint(path, &st);
+ rc = mnt_safe_stat(path, &st);
if (rc)
printf("%s: failed: rc=%d: %m\n", path, rc);
else {