Skip to content

Commit

Permalink
Implement partition mount verification
Browse files Browse the repository at this point in the history
Do not check a mounted partition and allow the user to allow checking a
read-write mounted partition as well.

Only check for mounting if we want to write, if we aren't fixing we will
not write and so no impact will be on any mounted filesystem to care.

Closes baruch#20
  • Loading branch information
baruch committed Nov 15, 2015
1 parent a271f5e commit 37e7547
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 3 deletions.
74 changes: 74 additions & 0 deletions arch/arch-linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <errno.h>
#include <net/if.h>
#include <netinet/in.h>
#include <mntent.h>

static void strtrim(char *s)
{
Expand Down Expand Up @@ -237,6 +238,79 @@ static int sg_ioctl(int fd, unsigned char *cdb, unsigned cdb_len,
return 0;
}

static disk_mount_e mount_point_check(struct mntent *mnt)
{
char *next = mnt->mnt_opts;
char *opt;

/* Device is mounted, check it */
while ((opt = strtok(next, ", \t\r\n")) != NULL) {
next = NULL; // continue scanning for this string
if (strcmp(opt, "rw") == 0)
return DISK_MOUNTED_RW;
}

return DISK_MOUNTED_RO;
}

disk_mount_e disk_dev_mount_state(const char *path)
{
struct stat dev_st_buf;
struct stat st_buf;
FILE *f = NULL;
struct mntent *mnt;
disk_mount_e state = DISK_MOUNTED_RW; // assume the worst

f = setmntent("/proc/mounts", "r");
if (f == NULL) {
ERROR("Failed to open /proc/mounts to know the state, errno=%d", errno);
goto Exit;
}

if (stat(path, &dev_st_buf) != 0) {
ERROR("Failed to stat the path %s, errno=%d", path, errno);
goto Exit;
}

if (!S_ISBLK(dev_st_buf.st_mode)) {
ERROR("Device %s is not a block device", path);
goto Exit; // We only want block devices
}

// From here we assume the disk is not mounted
state = DISK_NOT_MOUNTED;

while ((mnt = getmntent(f)) != NULL) {
disk_mount_e cur_state = DISK_NOT_MOUNTED;

/* Ignore non-full-path entries */
if (mnt->mnt_fsname[0] != '/')
continue;
/* Check for a name prefix match, we may check a full block device and a partition is mounted */
if (strncmp(path, mnt->mnt_fsname, strlen(path)) == 0) {
cur_state = mount_point_check(mnt);
if (cur_state > state)
state = cur_state;
continue;
}
/* Check for an underlying device match (name may have changed in between actions) */
if (stat(mnt->mnt_fsname, &st_buf) == 0) {
if (!S_ISBLK(st_buf.st_mode))
continue;
if (dev_st_buf.st_rdev == st_buf.st_rdev) {
cur_state = mount_point_check(mnt);
if (cur_state > state)
state = cur_state;
}
}
}

Exit:
if (f)
endmntent(f);
return state;
}

bool disk_dev_open(disk_dev_t *dev, const char *path)
{
dev->fd = open(path, O_RDWR|O_DIRECT);
Expand Down
11 changes: 10 additions & 1 deletion cli/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct options_t {
unsigned scan_size;
char *data_log_name;
char *data_log_raw_name;
disk_mount_e allowed_mount;
};

static void print_header(void)
Expand All @@ -67,6 +68,8 @@ static int usage(void) {
printf(" -e, --size <size> - Scan size (default to 64K, must be multiple of 512)\n");
printf(" -o, --output <file> - Output file (json)\n");
printf(" -r, --raw-log <file> - Raw log of all scan results (json)\n");
printf(" --force-mounted - Allow checking a read-only mounted disk\n");
printf(" --force-mounted-rw - Allow checking a read-write mounted disk\n");
printf("\n");
return 1;
}
Expand Down Expand Up @@ -203,6 +206,7 @@ static int parse_args(int argc, char **argv, options_t *opts)
{
int c;
int unknown = 0;
static int allowed_mount = DISK_NOT_MOUNTED;

opts->scan_size = 64*1024;

Expand All @@ -215,6 +219,8 @@ static int parse_args(int argc, char **argv, options_t *opts)
{"size", required_argument, 0, 'e'},
{"raw-log", required_argument, 0, 'r'},
{"output", required_argument, 0, 'o'},
{"force-mounted", no_argument, &allowed_mount, DISK_MOUNTED_RO},
{"force-mounted-rw", no_argument, &allowed_mount, DISK_MOUNTED_RW},
{0, 0, 0, 0}
};

Expand Down Expand Up @@ -276,6 +282,7 @@ static int parse_args(int argc, char **argv, options_t *opts)
}

opts->disk_path = argv[optind];
opts->allowed_mount = allowed_mount;
return 0;
}

Expand Down Expand Up @@ -306,8 +313,10 @@ int diskscan_cli(int argc, char **argv)
{
int ret;
options_t opts;

memset(&opts, 0, sizeof(opts));
opts.mode = SCAN_MODE_SEQ;
opts.allowed_mount = DISK_NOT_MOUNTED;

if (parse_args(argc, argv, &opts))
return 1;
Expand All @@ -317,7 +326,7 @@ int diskscan_cli(int argc, char **argv)

setup_signals();

if (disk_open(&disk, opts.disk_path, opts.fix, 70))
if (disk_open(&disk, opts.disk_path, opts.fix, 70, opts.allowed_mount))
return 1;

/*
Expand Down
8 changes: 8 additions & 0 deletions include/arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ typedef struct {
unsigned sense_len;
} io_result_t;

typedef enum {
DISK_NOT_MOUNTED = 0,
DISK_MOUNTED_RO = 1,
DISK_MOUNTED_RW = 2,
} disk_mount_e;

disk_mount_e disk_dev_mount_state(const char *path);

bool disk_dev_open(disk_dev_t *dev, const char *path);
void disk_dev_close(disk_dev_t *dev);
void disk_dev_cdb_out(disk_dev_t *dev, unsigned char *cdb, unsigned cdb_len, unsigned char *buf, unsigned buf_size, unsigned *buf_read,
Expand Down
2 changes: 1 addition & 1 deletion include/diskscan.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ typedef struct disk_t {
data_log_t data_log;
} disk_t;

int disk_open(disk_t *disk, const char *path, int fix, unsigned latency_graph_len);
int disk_open(disk_t *disk, const char *path, int fix, unsigned latency_graph_len, disk_mount_e allowed_mount);
int disk_scan(disk_t *disk, enum scan_mode mode, unsigned data_size);
int disk_close(disk_t *disk);
void disk_scan_stop(disk_t *disk);
Expand Down
33 changes: 32 additions & 1 deletion lib/diskscan.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,33 @@ static void disk_scsi_monitor_end(disk_t *disk)
(void)disk;
}

int disk_open(disk_t *disk, const char *path, int fix, unsigned latency_graph_len)
static const char *disk_mount_str(disk_mount_e mount)
{
switch (mount) {
case DISK_NOT_MOUNTED: return "not mounted";
case DISK_MOUNTED_RO: return "mounted read-only";
case DISK_MOUNTED_RW: return "mounted read-write";
default: return "unknown";
}
}

static int disk_mount_allowed(const char *path, disk_mount_e allowed_mount)
{
const disk_mount_e mount_state = disk_dev_mount_state(path);

if (mount_state > allowed_mount) {
ERROR("Disk is currently %s and we only allow %s, use --force-mounted or --force-mounted-rw if the risk of problems is acceptable", disk_mount_str(mount_state), disk_mount_str(allowed_mount));
return 0;
}

if (mount_state != DISK_NOT_MOUNTED) {
INFO("Disk is %s but this is allowed with a force option", disk_mount_str(mount_state));
}

return 1;
}

int disk_open(disk_t *disk, const char *path, int fix, unsigned latency_graph_len, disk_mount_e allowed_mount)
{
memset(disk, 0, sizeof(*disk));
disk->fix = fix;
Expand All @@ -286,6 +312,11 @@ int disk_open(disk_t *disk, const char *path, int fix, unsigned latency_graph_le
return 1;
}

if (fix && !disk_mount_allowed(path, allowed_mount)) {
ERROR("Better not fix with the disk mounted, mounted fs may get confused when data is possibly modified under its feet");
return 1;
}

if (!disk_dev_open(&disk->dev, path)) {
ERROR("Failed to open path %s, errno=%d: %s", path, errno, strerror(errno));
return 1;
Expand Down

0 comments on commit 37e7547

Please sign in to comment.