From f0d104cdadfb250f980431178648e081a6b23e28 Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Wed, 15 Aug 2012 11:18:34 +0200 Subject: [PATCH] dmsetup tests --- tools/dmsetup.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 223 insertions(+), 3 deletions(-) diff --git a/tools/dmsetup.c b/tools/dmsetup.c index 6934de8..99331b0 100644 --- a/tools/dmsetup.c +++ b/tools/dmsetup.c @@ -112,6 +112,9 @@ extern char *optarg; #define err(msg, x...) fprintf(stderr, msg "\n", ##x) +#define MAX_FDS 32 +#define FD_PREFIX "fd:" + /* * We have only very simple switches ATM. */ @@ -149,6 +152,7 @@ enum { SORT_ARG, TABLE_ARG, TARGET_ARG, + TRANSLATE_TABLE_ARG, TREE_ARG, UID_ARG, UNBUFFERED_ARG, @@ -191,6 +195,9 @@ static struct dm_report *_report; static report_type_t _report_type; static dev_name_t _dev_name_type; +static int _file_descriptors[MAX_FDS]; +static int _fds_count = 0; + /* * Commands */ @@ -208,10 +215,205 @@ struct command { command_fn fn; }; +static int _open_fd(const char *dev_path) +{ + int fd; + if (_fds_count >= MAX_FDS) { + // error + return -2; + } + + fd = open(dev_path, O_RDONLY); + if (fd >= 0) + _file_descriptors[_fds_count++] = fd; + + return fd; +} + +static void _close_fds(void) +{ + while (_fds_count > 0) + close(_file_descriptors[--_fds_count]); +} + +static void _close_last_fd(void) +{ + if (_fds_count) + close(_file_descriptors[--_fds_count]); +} + +#ifdef UDEV_SYNC_SUPPORT +static char *_get_devpath_from_udev(dev_t dev_id) +{ + char *ret = NULL; + + struct udev *udev; + struct udev_device *udev_dev; + + udev = udev_new(); + if (!udev) + return NULL; + + udev_dev = udev_device_new_from_devnum(udev, 'b', dev_id); + if (!udev_dev) + goto bad; + + ret = strdup(udev_device_get_devnode(udev_dev)); + + udev_device_unref(udev_dev); +bad: + udev_unref(udev); + + return ret; +} +#endif + +static char *_get_devpath_by_devid(dev_t dev_id) +{ + char *ret; + +#ifdef UDEV_SYNC_SUPPORT + ret = _get_devpath_from_udev(dev_id); +#else + /* TODO: How to get devnode path w/o udev */ + ret = NULL; +#endif + + return ret; +} + +static char *_lookup_dev_path(const char *dev_ptr, size_t str_len) { + dev_t dev_id; + char dummy; + char *ret = NULL, *dev_cpy; + + int maj, min; + + /* + * this is safe, there's at least one '\0' char + * after dev_ptr + str_len + */ + dev_cpy = strndup(dev_ptr, str_len); + if (!dev_cpy) + return dev_cpy; + + if (sscanf(dev_cpy, "%d:%d%c", &maj, &min, &dummy) == 2) { + if (maj < 0 || min < 0) + goto out; + + dev_id = makedev(maj, min); + if (major(dev_id) != maj || minor(dev_id) != min) + goto out; + + ret = _get_devpath_by_devid(dev_id); + goto out; + } + else + ret = dev_cpy; + + return ret; +out: + free(dev_cpy); + return ret; +} + +static int _translate_string(char **dest, const char *dev_ptr, size_t dev_str_len, size_t *remaining_size) +{ + int r; + int written; + + char *dev_str; + + dev_str = _lookup_dev_path(dev_ptr, dev_str_len); + if (!dev_str) + return 1; + + /* "fd:" + at least one char for number after colon */ + if (*remaining_size < (strlen(FD_PREFIX) + 1)) + return -ENOMEM; + + r = _open_fd(dev_str); + if (r < 0) + return r; + + written = snprintf(*dest, *remaining_size, "%s%u", FD_PREFIX, r); + if (written >= *remaining_size) { + free(dev_str); + _close_last_fd(); + return -ENOMEM; + } + + *remaining_size -= written; + *dest += written; + + free(dev_str); + + return 0; +} + +/* @orig points to trimed string */ +static int _translate_table_line(char *orig, char **new) +{ + char *begin = NULL, *buffer, *copy_from, *copy_to; + int r; + size_t b_current = 2 * strlen(orig); + + buffer = (char *) malloc((b_current * 2 + 1) * sizeof(char)); + if (!buffer) + return -ENOMEM; + + begin = copy_from = orig; + copy_to = buffer; + + while (*orig++) { + // first non-white char is begin of substr + if (isspace(*orig) || !*orig) { + if (begin) { + + if (b_current < (begin - copy_from)) { + r = -ENOMEM; + goto bad; + } + + if (begin - copy_from) + memcpy(copy_to, copy_from, begin - copy_from); + b_current -= begin - copy_from; + copy_to += begin - copy_from; + + r = _translate_string(©_to, begin, orig - begin, &b_current); + + if (r) { + if (r == -ENOMEM) + goto bad; + + copy_from = begin; + } else + copy_from = orig; + + + begin = NULL; + } + } + else + begin = begin ?: orig; + } + + if (copy_from != (orig - 1)) + memcpy(copy_to, copy_from, (orig - 1) - copy_from); + + *new = buffer; + + return 0; + +bad: + free(buffer); + return r; +} + static int _parse_line(struct dm_task *dmt, char *buffer, const char *file, int line) { - char ttype[LINE_SIZE], *ptr, *comment; + char ttype[LINE_SIZE], *ptr, *comment, *translated_line; unsigned long long start, size; int n; @@ -239,9 +441,20 @@ static int _parse_line(struct dm_task *dmt, char *buffer, const char *file, if ((comment = strchr(ptr, (int) '#'))) *comment = '\0'; + if (_switches[TRANSLATE_TABLE_ARG]) { + log_debug("table translation enabled!\n"); + if (!_translate_table_line(ptr, &translated_line)) { + log_debug("this is translated line: %s\n", translated_line); + ptr = translated_line; + } + } + if (!dm_task_add_target(dmt, start, size, ttype, ptr)) return 0; + if (_switches[TRANSLATE_TABLE_ARG] && ptr == translated_line) + free(translated_line); + return 1; } @@ -2985,7 +3198,7 @@ static struct command _commands[] = { {"create", " [-j|--major -m|--minor ]\n" "\t [-U|--uid ] [-G|--gid ] [-M|--mode ]\n" "\t [-u|uuid ] [{--addnodeonresume|--addnodeoncreate}]\n" - "\t [--notable | --table | ]", + "\t [--notable | --table
| ] [-T|--translate-table]", 1, 2,0, _create}, {"remove", "[-f|--force] ", 0, -1, 1, _remove}, {"remove_all", "[-f|--force]", 0, 0, 0, _remove_all}, @@ -3476,6 +3689,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) {"yes", 0, &ind, YES_ARG}, {"addnodeonresume", 0, &ind, ADD_NODE_ON_RESUME_ARG}, {"addnodeoncreate", 0, &ind, ADD_NODE_ON_CREATE_ARG}, + {"translatetable", 0, &ind, TRANSLATE_TABLE_ARG}, {0, 0, 0, 0} }; #else @@ -3534,7 +3748,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) optarg = 0; optind = OPTIND_INIT; - while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfG:hj:m:M:no:O:ru:U:vy", + while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfG:hj:m:M:no:O:ru:TU:vy", long_options, NULL)) != -1) { if (c == ':' || c == '?') return 0; @@ -3574,6 +3788,8 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) _switches[UUID_ARG]++; _uuid = optarg; } + if (c == 'T' || ind == TRANSLATE_TABLE_ARG) + _switches[TRANSLATE_TABLE_ARG]++; if (c == 'y' || ind == YES_ARG) _switches[YES_ARG]++; if (ind == ADD_NODE_ON_RESUME_ARG) @@ -3792,9 +4008,13 @@ int main(int argc, char **argv) } } while (cmd->repeatable_cmd && argc > 1); + _close_fds(); + r = 0; out: + _close_fds(); + if (_report) { dm_report_output(_report); dm_report_free(_report); -- 1.8.0