From 51b24c8a3370e7190a60ea0ec519b22f64098b08 Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Tue, 4 Dec 2001 23:19:04 +0000 Subject: [PATCH] Added error handling and changed some parts to behave same as ioctl version. --- dmsetup/Makefile.in | 2 +- lib/fs/libdevmapper.c | 395 +++++++++++++++++++++++------------------- 2 files changed, 215 insertions(+), 182 deletions(-) diff --git a/dmsetup/Makefile.in b/dmsetup/Makefile.in index f7c7f49..4379424 100644 --- a/dmsetup/Makefile.in +++ b/dmsetup/Makefile.in @@ -13,6 +13,6 @@ TARGETS=dmsetup include ../make.tmpl -dmsetup: dmsetup.o $(interfacedir)/libdevmapper.so +dmsetup: $(OBJECTS) $(interfacedir)/libdevmapper.so $(CC) -o dmsetup dmsetup.o $(LD_FLAGS) -ldevmapper diff --git a/lib/fs/libdevmapper.c b/lib/fs/libdevmapper.c index f66a3b0..924461f 100644 --- a/lib/fs/libdevmapper.c +++ b/lib/fs/libdevmapper.c @@ -15,19 +15,22 @@ #include #include #include +#include #include +#include #define DEV_DIR "/dev/" -#define DM_DIR "device-mapper" -#define ALIGNMENT sizeof(int) -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif -#define MKDEV(x,y) ((x) << 8 | (y)) +/* FIXME Obtain from kernel header */ +#define DM_DIR "device-mapper" static char _dm_dir[PATH_MAX] = DEV_DIR DM_DIR; +typedef enum { + DIR_CREATE, + DIR_REMOVE +} do_newold_t; + /* * Library users can provide their own logging * function. @@ -69,42 +72,42 @@ struct dm_task { #define NR_ARGS 16 -static char *mkpath(int n, char *base, ...) +/* + * Join n path components together with /'s. + */ +static char *mkpath(int n, ...) { va_list va; - char *args[NR_ARGS]; - int len = strlen(base) + 1; - int i = 0; - char *str; + int len = 0, i; + char *str, *r; - if (n > NR_ARGS) - return NULL; + va_start(va, n); + for (i = 0; i < n; i++) + len += strlen(va_arg(va, char *)) + 1; - va_start(va, base); - for(i = 0; i < n; i++) { - args[i] = (char *)va_arg(va, char *); - len += strlen(args[i]); - len++; - } va_end(va); - str = malloc(len); - if (str) { - strcpy(str, base); - for(i = 0; i < n; i++) { - strcat(str, "/"); - strcat(str, args[i]); - } + if (!(r = str = malloc(len))) { + log("mkpath: malloc(%d) failed", len); + return NULL; } - return str; + + va_start(va, n); + for (i = 0; i < n; i++) + str += sprintf(str, "%s%s", i ? "/" : "", va_arg(va, char *)); + va_end(va); + + return r; } struct dm_task *dm_task_create(int type) { struct dm_task *dmt = malloc(sizeof(*dmt)); - if (!dmt) + if (!dmt) { + log("dm_task_create: malloc(%d) failed", sizeof(*dmt)); return NULL; + } memset(dmt, 0, sizeof(*dmt)); @@ -147,19 +150,24 @@ static struct target *_create_target(unsigned long long start, int size = strlen(params) + strlen(type); int ret; - size += 64; /* Guess at max size of start and len */ + size += 64; /* Guess at max size of start and len */ t = malloc(size + sizeof(struct target)); - if (!t) + if (!t) { + log("_create_target: malloc(%d) failed", + size + sizeof(struct target)); return NULL; + } + memset(t, 0, size + sizeof(struct target)); - t->str = (char *)(t + 1); + t->str = (char *) (t + 1); ret = sprintf(t->str, "%Lu %Lu %s %s\n", start, len, type, params); if (ret > size) { /* This should be impossible, but check anyway */ - log("Internal error - ran out of buffer space"); - exit(-1); + log("_create_target internal error: Ran out of buffer space"); + free(t); + return NULL; } return t; @@ -168,8 +176,7 @@ static struct target *_create_target(unsigned long long start, int dm_task_add_target(struct dm_task *dmt, unsigned long long start, unsigned long long size, - const char *ttype, - const char *params) + const char *ttype, const char *params) { struct target *t = _create_target(start, size, ttype, params); @@ -242,181 +249,206 @@ static int _rm_dev_node(const char *dev_name) static int do_suspend(char *mnt, char *name, int on) { - char *path = mkpath(2, mnt, name, "suspend"); - int ret = -1; - - if (path) { - FILE *fp = fopen(path, "rw"); - if (fp) { - if (fprintf(fp, "%d\n", on) > 0) - ret = 0; - fclose(fp); - } - free(path); - } + char *path; + FILE *fp; + int ret = 0; + + if (!(path = mkpath(3, mnt, name, "suspend"))) + return 0; + + if ((fp = fopen(path, "rw"))) { + if (fprintf(fp, "%d\n", on) > 0) + ret = 1; + else + log("%s: fprintf failed: %s", path, strerror(errno)); + fclose(fp); + } else + log("%s: fopen failed: %s", path, strerror(errno)); + + free(path); return ret; } -static int do_newold(char *mnt, char *name, int create) +static int do_newold(char *mnt, char *name, do_newold_t create) { - char *path = mkpath(1, mnt, name); - int ret = -1; + char *path = mkpath(2, mnt, name); + int ret; - if (path) { - if (create) - ret = mkdir(path, 0750); - else - ret = rmdir(path); - free(path); - } + if (!path) + return 0; - return ret; + if (create == DIR_CREATE) { + if ((ret = mkdir(path, 0750)) < 0) + log("%s: mkdir failed: %s", path, strerror(errno)); + } else if ((ret = rmdir(path)) < 0) + log("%s: rmdir failed: %s", path, strerror(errno)); + + free(path); + + return (ret < 0) ? 0 : 1; } static int do_device(char *mnt, char *name, struct dm_info *info) { - char *path = mkpath(2, mnt, name, "device"); - int ret = -1; - if (path) { - struct stat st; - if (stat(path, &st) == 0) { - info->major = st.st_rdev >> 8; - info->minor = st.st_rdev & 0xff; - } - free(path); - } - return ret; + char *path; + struct stat st; + + if (!(path = mkpath(3, mnt, name, "device"))) + return 0; + + if (!stat(path, &st)) { + info->major = MAJOR(st.st_rdev); + info->minor = MINOR(st.st_rdev); + info->exists = 1; + } else + info->exists = 0; + + free(path); + return 1; } static int do_suspend_state(char *mnt, char *name, struct dm_info *info) { - char *path = mkpath(2, mnt, name, "suspend"); - int ret = -1; - if (path) { - FILE *fp = fopen(path, "r"); - if (fp) { - int state; - if (fscanf(fp, "%d", &state) == 1) { - info->suspended = state; - ret = 0; - } - fclose(fp); - } - free(path); - } + char *path; + FILE *fp; + int ret = 0; + + if (!(path = mkpath(3, mnt, name, "suspend"))) + return 0; + + if ((fp = fopen(path, "r"))) { + if (fscanf(fp, "%d", &info->suspended) == 1) + ret = 1; + else + log("%s fscanf failed: %s", path, strerror(errno)); + fclose(fp); + } else + log("%s: fopen failed: %s", path, strerror(errno)); + + free(path); + return ret; } static int do_info(char *mnt, char *name, struct dm_info *info) { - int ret; - memset(info, 0, sizeof(struct dm_info)); - ret = do_device(mnt, name, info); - if (ret < 0) - goto out; - ret = do_suspend_state(mnt, name, info); - if (ret < 0) - goto out; - info->exists = 1; -out: - return ret; + if (!do_device(mnt, name, info)) + return 0; + + if (info->exists && !do_suspend_state(mnt, name, info)) + return 0; + + return 1; } -static int write_data(int fd, struct dm_task *dmt) +/* + * Writes a buffer out to a file, returns 0 on failure. + */ +static int write_buffer(int fd, const void *buf, size_t count) { - struct target *tmp = dmt->head; - int n = 0; - struct iovec *iov; - int ret = -1; - - while(tmp) { - n++; - tmp = tmp->next; - } + size_t n = 0; + int tot = 0; - iov = malloc(n * sizeof(struct iovec)); - if (iov) { - tmp = dmt->head; - n = 0; - while(tmp) { - iov[n].iov_base = tmp->str; - iov[n].iov_len = strlen(tmp->str); - n++; - tmp = tmp->next; - } + while (tot < count) { + do + n = write(fd, buf, count - tot); + while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN))); + + if (n <= 0) + return 0; - ret = writev(fd, iov, n); - free(iov); + tot += n; + buf += n; } - return ret; + return 1; +} + +static int write_data(int fd, struct dm_task *dmt) +{ + struct target *t; + + for (t = dmt->head; t; t = t->next) + if (!write_buffer(fd, t->str, strlen(t->str))) + return 0; + + return 1; } static int do_load(char *mnt, char *name, struct dm_task *dmt) { - char *path = mkpath(2, mnt, name, "table"); - int ret = -1; - if (path) { - int fd = open(path, O_RDWR); - if (fd >= 0) { - ret = write_data(fd, dmt); - close(fd); - } + char *path; + int fd, ret = 0; + + if (!(path = mkpath(3, mnt, name, "table"))) + return 0; + + if ((fd = open(path, O_RDWR)) != -1) { + if (!(ret = write_data(fd, dmt))) + log("%s: write failed: %s", path, strerror(errno)); + close(fd); } + + free(path); + return ret; } static void strip_nl(char *str) { - while(*str && *str != '\n' && *str != '\r') + while (*str && *str != '\n' && *str != '\r') str++; *str = 0; } static int do_error_check(char *mnt, char *name) { - char *path = mkpath(2, mnt, name, "error"); - int ret = -1; - if (path) { - FILE *fp = fopen(path, "r"); - if (fp) { - char buf[1024]; - ret = 0; - while(fgets(buf, 1023, fp)) { - buf[1023] = 0; - strip_nl(buf); - log(buf); - ret = -1; - } - fclose(fp); - } + char *path; + FILE *fp; + int ret = 1; + char buf[1024]; + + if (!(path = mkpath(3, mnt, name, "error"))) + return 0; + + if (!(fp = fopen(path, "r"))) { + log("%s: fopen failed: %s", path, strerror(errno)); free(path); + return 0; + } + + while (fgets(buf, sizeof(buf), fp)) { + strip_nl(buf); + log(buf); + ret = 0; } + + fclose(fp); + free(path); return ret; } static char *find_mount_point(void) { - FILE *fp = fopen("/proc/mounts", "r"); -static char mpoint[4096]; - if (fp) { - int fsdump, fspass; - char device[1024]; - char fstype[30]; - char fsoptions[4096]; - while(fscanf(fp, "%1024s %4096s %30s %4096s %d %d", device, mpoint, fstype, fsoptions, &fsdump, &fspass) == 6) { - if (strlen(fstype) != 4) - continue; - if (strcmp(fstype, "dmfs")) - continue; + FILE *fp; + static char mpoint[4096]; + char fstype[30]; + + if ((fp = fopen("/proc/mounts", "r")) < 0) { + log("/proc/mounts: fopen failed: %s", strerror(errno)); + return NULL; + } + + while (fscanf(fp, "%*s%4096s%30s%*s%*d%*d", mpoint, fstype) == 2) { + if (!strcmp(fstype, "dmfs")) { fclose(fp); return mpoint; } - fclose(fp); } + fclose(fp); return NULL; } @@ -425,59 +457,60 @@ int dm_task_run(struct dm_task *dmt) char *mnt = find_mount_point(); if (mnt == NULL) { + /* FIXME Mount it temporarily if not mounted */ log("Cannot find mount point for dmfs or dmfs not mounted"); - goto bad; + return 0; + } + + if (!dmt->dev_name || !*dmt->dev_name) { + log("dm_task_run: Device name not supplied"); + return 0; } switch (dmt->type) { case DM_DEVICE_CREATE: - do_newold(mnt, dmt->dev_name, 1); - do_info(mnt, dmt->dev_name, &dmt->info); + if (!do_newold(mnt, dmt->dev_name, DIR_CREATE) || + !do_load(mnt, dmt->dev_name, dmt) || + !do_error_check(mnt, dmt->dev_name) || + !do_info(mnt, dmt->dev_name, &dmt->info)) + return 0; + _add_dev_node(dmt->dev_name, + MKDEV(dmt->info.major, dmt->info.minor)); break; case DM_DEVICE_RELOAD: - do_load(mnt, dmt->dev_name, dmt); - do_error_check(mnt, dmt->dev_name); + if (!do_load(mnt, dmt->dev_name, dmt) || + !do_error_check(mnt, dmt->dev_name)) return 0; break; case DM_DEVICE_REMOVE: - do_newold(mnt, dmt->dev_name, 1); - dmt->info.exists = 0; + if (!do_newold(mnt, dmt->dev_name, DIR_REMOVE) || + !do_info(mnt, dmt->dev_name, &dmt->info)) + return 0; + _rm_dev_node(dmt->dev_name); break; case DM_DEVICE_SUSPEND: - do_suspend(mnt, dmt->dev_name, 1); + if (!do_suspend(mnt, dmt->dev_name, 1)) + return 0; break; case DM_DEVICE_RESUME: - do_suspend(mnt, dmt->dev_name, 0); + if (!do_suspend(mnt, dmt->dev_name, 0)) + return 0; break; case DM_DEVICE_INFO: - do_info(mnt, dmt->dev_name, &dmt->info); + if (!do_info(mnt, dmt->dev_name, &dmt->info)) + return 0; break; default: - log("Internal error: unknown device-mapper task %d", - dmt->type); - goto bad; - } - - switch (dmt->type) { - case DM_DEVICE_CREATE: - _add_dev_node(dmt->dev_name, - MKDEV(dmt->info.major, dmt->info.minor)); - break; - - case DM_DEVICE_REMOVE: - _rm_dev_node(dmt->dev_name); - break; + log("Internal error: unknown device-mapper task %d", dmt->type); + return 0; } return 1; - - bad: - return 0; } int dm_set_dev_dir(const char *dir) -- 2.43.5