2 * Copyright (C) 2012-2020 all contributors <cmogstored-public@yhbt.net>
3 * License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
5 #include "cmogstored.h"
8 * statvfs() on GNU/Linux may call stat() internally, and stat() is bad
9 * for network mounts which may be stalled/slow, so favor the non-portable
10 * statfs() on GNU/Linux
14 #define MY_STATFS statfs
15 #else /* statvfs() is POSIX */
16 #define MY_STATFS statvfs
19 static bool resolve_symlink(char **orig
)
21 char *p
= canonicalize_filename_mode(*orig
, CAN_EXISTING
);
31 static bool stat_harder(struct mount_entry
*me
)
35 /* the device number may not have been populated, do it */
36 if (me
->me_dev
== (dev_t
)-1) {
37 if (stat(me
->me_mountdir
, &sb
) != 0)
39 me
->me_dev
= sb
.st_dev
;
43 * resolve symlinks for things that look like paths
44 * and skip dead symlinks
46 if (me
->me_devname
[0] == '/') {
47 if (lstat(me
->me_devname
, &sb
) == 0
48 && S_ISLNK(sb
.st_mode
)
49 && ! resolve_symlink(&me
->me_devname
))
56 * prevents us from using filesystems of unknown size, since those could
57 * be stalled/dead network mounts
59 bool mog_mnt_usable(struct mount_entry
*me
)
62 const char *path
= me
->me_mountdir
;
69 if (MY_STATFS(path
, &buf
) == 0)
70 return (buf
.f_blocks
> 0) ? stat_harder(me
) : false;
73 assert(errno
!= EFAULT
&& "BUG: EFAULT from statfs/statvfs");
75 case EINTR
: goto retry
;
76 case EIO
: /* this is important enough to log: */
77 case EOVERFLOW
: /* this is important enough to log: */
78 syslog(LOG_ERR
, MOG_STR(MY_STATFS
) "(%s) failed: %m", path
);
79 case ENOTDIR
: /* race between read_file_system_list and statvfs */
80 case ELOOP
: /* race between read_file_system_list and statvfs? */
81 case ENOSYS
: /* if statvfs() doesn't work, fstatvfs() won't, either */
82 case EACCES
: /* this is common */
86 * assume other errors are recoverable (or fail elsewhere)
87 * ENAMETOOLONG - would fail anyways if we need to stat(2)
88 * ENOMEM - maybe the kernel will get more memory back, soon