forked from Mirrors/btrfs-progs
multidevice support for check_mounted
Check_mount() should also work with multi device filesystems. This patch adds checks that allow to detect if a file is a device file used by a mounted single or multi device btrfs or if it is a regular file used by a loopback device that is part of a mounted single or multi device btrfs. The single device checks also work for non-btrfs filesystems. This might be helpful to prevent users from running btrfs programs (e.g. mkfs.btrfs) accidentally on a filesystem used somewhere else. Signed-off-by: Andi Drebes <lists-receive@programmierforen.de>master
parent
075587c96c
commit
09559bfe7b
|
@ -42,7 +42,11 @@
|
|||
#define GFP_NOFS 0
|
||||
#define __read_mostly
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#ifndef ULONG_MAX
|
||||
#define ULONG_MAX (~0UL)
|
||||
#endif
|
||||
|
||||
#define BUG() abort()
|
||||
#ifdef __CHECKER__
|
||||
#define __force __attribute__((force))
|
||||
|
|
239
utils.c
239
utils.c
|
@ -31,6 +31,10 @@
|
|||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <mntent.h>
|
||||
#include <linux/loop.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <limits.h>
|
||||
#include "kerncompat.h"
|
||||
#include "radix-tree.h"
|
||||
#include "ctree.h"
|
||||
|
@ -586,55 +590,224 @@ error:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* checks if a device is a loop device */
|
||||
int is_loop_device (const char* device) {
|
||||
struct stat statbuf;
|
||||
|
||||
if(stat(device, &statbuf) < 0)
|
||||
return -errno;
|
||||
|
||||
return (S_ISBLK(statbuf.st_mode) &&
|
||||
MAJOR(statbuf.st_rdev) == LOOP_MAJOR);
|
||||
}
|
||||
|
||||
|
||||
/* Takes a loop device path (e.g. /dev/loop0) and returns
|
||||
* the associated file (e.g. /images/my_btrfs.img) */
|
||||
int resolve_loop_device(const char* loop_dev, char* loop_file, int max_len)
|
||||
{
|
||||
int loop_fd;
|
||||
int ret_ioctl;
|
||||
struct loop_info loopinfo;
|
||||
|
||||
if ((loop_fd = open(loop_dev, O_RDONLY)) < 0)
|
||||
return -errno;
|
||||
|
||||
ret_ioctl = ioctl(loop_fd, LOOP_GET_STATUS, &loopinfo);
|
||||
close(loop_fd);
|
||||
|
||||
if (ret_ioctl == 0)
|
||||
strncpy(loop_file, loopinfo.lo_name, max_len);
|
||||
else
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Checks whether a and b are identical or device
|
||||
* files associated with the same block device
|
||||
*/
|
||||
int is_same_blk_file(const char* a, const char* b)
|
||||
{
|
||||
struct stat st_buf_a, st_buf_b;
|
||||
char real_a[PATH_MAX];
|
||||
char real_b[PATH_MAX];
|
||||
|
||||
if(!realpath(a, real_a) ||
|
||||
!realpath(b, real_b))
|
||||
{
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Identical path? */
|
||||
if(strcmp(real_a, real_b) == 0)
|
||||
return 1;
|
||||
|
||||
if(stat(a, &st_buf_a) < 0 ||
|
||||
stat(b, &st_buf_b) < 0)
|
||||
{
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Same blockdevice? */
|
||||
if(S_ISBLK(st_buf_a.st_mode) &&
|
||||
S_ISBLK(st_buf_b.st_mode) &&
|
||||
st_buf_a.st_rdev == st_buf_b.st_rdev)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Hardlink? */
|
||||
if (st_buf_a.st_dev == st_buf_b.st_dev &&
|
||||
st_buf_a.st_ino == st_buf_b.st_ino)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* checks if a and b are identical or device
|
||||
* files associated with the same block device or
|
||||
* if one file is a loop device that uses the other
|
||||
* file.
|
||||
*/
|
||||
int is_same_loop_file(const char* a, const char* b)
|
||||
{
|
||||
char res_a[PATH_MAX];
|
||||
char res_b[PATH_MAX];
|
||||
const char* final_a;
|
||||
const char* final_b;
|
||||
int ret;
|
||||
|
||||
/* Resolve a if it is a loop device */
|
||||
if((ret = is_loop_device(a)) < 0) {
|
||||
return ret;
|
||||
} else if(ret) {
|
||||
if((ret = resolve_loop_device(a, res_a, sizeof(res_a))) < 0)
|
||||
return ret;
|
||||
|
||||
final_a = res_a;
|
||||
} else {
|
||||
final_a = a;
|
||||
}
|
||||
|
||||
/* Resolve b if it is a loop device */
|
||||
if((ret = is_loop_device(b)) < 0) {
|
||||
return ret;
|
||||
} else if(ret) {
|
||||
if((ret = resolve_loop_device(b, res_b, sizeof(res_b))) < 0)
|
||||
return ret;
|
||||
|
||||
final_b = res_b;
|
||||
} else {
|
||||
final_b = b;
|
||||
}
|
||||
|
||||
return is_same_blk_file(final_a, final_b);
|
||||
}
|
||||
|
||||
/* Checks if a file exists and is a block or regular file*/
|
||||
int is_existing_blk_or_reg_file(const char* filename)
|
||||
{
|
||||
struct stat st_buf;
|
||||
|
||||
if(stat(filename, &st_buf) < 0) {
|
||||
if(errno == ENOENT)
|
||||
return 0;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return (S_ISBLK(st_buf.st_mode) || S_ISREG(st_buf.st_mode));
|
||||
}
|
||||
|
||||
/* Checks if a file is used (directly or indirectly via a loop device)
|
||||
* by a device in fs_devices
|
||||
*/
|
||||
int blk_file_in_dev_list(struct btrfs_fs_devices* fs_devices, const char* file)
|
||||
{
|
||||
int ret;
|
||||
struct list_head *head;
|
||||
struct list_head *cur;
|
||||
struct btrfs_device *device;
|
||||
|
||||
head = &fs_devices->devices;
|
||||
list_for_each(cur, head) {
|
||||
device = list_entry(cur, struct btrfs_device, dev_list);
|
||||
|
||||
if((ret = is_same_loop_file(device->name, file)))
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns 1 if the device was mounted, < 0 on error or 0 if everything
|
||||
* is safe to continue. TODO, this should also scan multi-device filesystems
|
||||
* is safe to continue.
|
||||
*/
|
||||
int check_mounted(char *file)
|
||||
int check_mounted(const char* file)
|
||||
{
|
||||
struct mntent *mnt;
|
||||
struct stat st_buf;
|
||||
dev_t file_dev = 0;
|
||||
dev_t file_rdev = 0;
|
||||
ino_t file_ino = 0;
|
||||
int ret;
|
||||
int fd;
|
||||
u64 total_devs = 1;
|
||||
int is_btrfs;
|
||||
struct btrfs_fs_devices* fs_devices_mnt = NULL;
|
||||
FILE *f;
|
||||
int ret = 0;
|
||||
struct mntent *mnt;
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf (stderr, "check_mounted(): Could not open %s\n", file);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* scan the initial device */
|
||||
ret = btrfs_scan_one_device(fd, file, &fs_devices_mnt,
|
||||
&total_devs, BTRFS_SUPER_INFO_OFFSET);
|
||||
is_btrfs = (ret >= 0);
|
||||
close(fd);
|
||||
|
||||
/* scan other devices */
|
||||
if (is_btrfs && total_devs > 1) {
|
||||
if((ret = btrfs_scan_for_fsid(fs_devices_mnt, total_devs, 1)))
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* iterate over the list of currently mountes filesystems */
|
||||
if ((f = setmntent ("/proc/mounts", "r")) == NULL)
|
||||
return -errno;
|
||||
|
||||
if (stat(file, &st_buf) < 0) {
|
||||
return -errno;
|
||||
} else {
|
||||
if (S_ISBLK(st_buf.st_mode)) {
|
||||
file_rdev = st_buf.st_rdev;
|
||||
} else {
|
||||
file_dev = st_buf.st_dev;
|
||||
file_ino = st_buf.st_ino;
|
||||
}
|
||||
}
|
||||
|
||||
while ((mnt = getmntent (f)) != NULL) {
|
||||
if (strcmp(file, mnt->mnt_fsname) == 0)
|
||||
break;
|
||||
if(is_btrfs) {
|
||||
if(strcmp(mnt->mnt_type, "btrfs") != 0)
|
||||
continue;
|
||||
|
||||
if (stat(mnt->mnt_fsname, &st_buf) == 0) {
|
||||
if (S_ISBLK(st_buf.st_mode)) {
|
||||
if (file_rdev && (file_rdev == st_buf.st_rdev))
|
||||
break;
|
||||
} else if (file_dev && ((file_dev == st_buf.st_dev) &&
|
||||
(file_ino == st_buf.st_ino))) {
|
||||
break;
|
||||
}
|
||||
ret = blk_file_in_dev_list(fs_devices_mnt, mnt->mnt_fsname);
|
||||
} else {
|
||||
/* ignore entries in the mount table that are not
|
||||
associated with a file*/
|
||||
if((ret = is_existing_blk_or_reg_file(mnt->mnt_fsname)) < 0)
|
||||
goto out_mntloop_err;
|
||||
else if(!ret)
|
||||
continue;
|
||||
|
||||
ret = is_same_loop_file(file, mnt->mnt_fsname);
|
||||
}
|
||||
|
||||
if(ret < 0)
|
||||
goto out_mntloop_err;
|
||||
else if(ret)
|
||||
break;
|
||||
}
|
||||
|
||||
if (mnt) {
|
||||
/* found an entry in mnt table */
|
||||
ret = 1;
|
||||
}
|
||||
/* Did we find an entry in mnt table? */
|
||||
ret = (mnt != NULL);
|
||||
|
||||
out_mntloop_err:
|
||||
endmntent (f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
2
utils.h
2
utils.h
|
@ -36,7 +36,7 @@ int btrfs_scan_for_fsid(struct btrfs_fs_devices *fs_devices, u64 total_devs,
|
|||
int run_ioctls);
|
||||
void btrfs_register_one_device(char *fname);
|
||||
int btrfs_scan_one_dir(char *dirname, int run_ioctl);
|
||||
int check_mounted(char *devicename);
|
||||
int check_mounted(const char *devicename);
|
||||
int btrfs_device_already_in_root(struct btrfs_root *root, int fd,
|
||||
int super_offset);
|
||||
char *pretty_sizes(u64 size);
|
||||
|
|
Loading…
Reference in New Issue