📄 dmsetup.c
字号:
static void _out_char(const unsigned c){ /* Only first UTF-8 char counts */ _cur_x += ((c & 0xc0) != 0x80); if (!_tree_switches[TR_TRUNCATE]) { putchar((int) c); return; } /* Truncation? */ if (_cur_x <= _termwidth) putchar((int) c); if (_cur_x == _termwidth + 1 && ((c & 0xc0) != 0x80)) { if (_last_char || (c & 0x80)) { putchar('.'); putchar('.'); putchar('.'); } else { _last_char = c; _cur_x--; } }}static void _out_string(const char *str){ while (*str) _out_char((unsigned char) *str++);}/* non-negative integers only */static unsigned _out_int(unsigned num){ unsigned digits = 0; unsigned divi; if (!num) { _out_char('0'); return 1; } /* non zero case */ for (divi = 1; num / divi; divi *= 10) digits++; for (divi /= 10; divi; divi /= 10) _out_char('0' + (num / divi) % 10); return digits;}static void _out_newline(void){ if (_last_char && _cur_x == _termwidth) putchar(_last_char); _last_char = 0; putchar('\n'); _cur_x = 1;}static void _out_prefix(unsigned depth){ unsigned x, d; for (d = 0; d < depth; d++) { for (x = _tree_width[d] + 1; x > 0; x--) _out_char(' '); _out_string(d == depth - 1 ? !_tree_more[depth] ? _tsym->last_2 : _tsym->branch_2 : _tree_more[d + 1] ? _tsym->vert_2 : _tsym->empty_2); }}/* * Display tree */static void _display_tree_attributes(struct dm_tree_node *node){ int attr = 0; const char *uuid; const struct dm_info *info; uuid = dm_tree_node_get_uuid(node); info = dm_tree_node_get_info(node); if (!info->exists) return; if (_tree_switches[TR_ACTIVE]) { _out_string(attr++ ? ", " : " ["); _out_string(info->suspended ? "SUSPENDED" : "ACTIVE"); } if (_tree_switches[TR_RW]) { _out_string(attr++ ? ", " : " ["); _out_string(info->read_only ? "RO" : "RW"); } if (_tree_switches[TR_OPENCOUNT]) { _out_string(attr++ ? ", " : " ["); (void) _out_int((unsigned) info->open_count); } if (_tree_switches[TR_UUID]) { _out_string(attr++ ? ", " : " ["); _out_string(uuid && *uuid ? uuid : ""); } if (attr) _out_char(']');}static void _display_tree_node(struct dm_tree_node *node, unsigned depth, unsigned first_child __attribute((unused)), unsigned last_child, unsigned has_children){ int offset; const char *name; const struct dm_info *info; int first_on_line = 0; /* Sub-tree for targets has 2 more depth */ if (depth + 2 > MAX_DEPTH) return; name = dm_tree_node_get_name(node); if ((!name || !*name) && !_tree_switches[TR_DEVICE]) return; /* Indicate whether there are more nodes at this depth */ _tree_more[depth] = !last_child; _tree_width[depth] = 0; if (_cur_x == 1) first_on_line = 1; if (!TR_PRINT_COMPACT || first_on_line) _out_prefix(depth); /* Remember the starting point for compact */ offset = _cur_x; if (TR_PRINT_COMPACT && !first_on_line) _out_string(_tree_more[depth] ? _tsym->first_3 : _tsym->single_3); /* display node */ if (name) _out_string(name); info = dm_tree_node_get_info(node); if (_tree_switches[TR_DEVICE]) { _out_string(name ? " (" : "("); (void) _out_int(info->major); _out_char(':'); (void) _out_int(info->minor); _out_char(')'); } /* display additional info */ if (TR_PRINT_ATTRIBUTE) _display_tree_attributes(node); if (TR_PRINT_COMPACT) _tree_width[depth] = _cur_x - offset; if (!TR_PRINT_COMPACT || !has_children) _out_newline(); if (TR_PRINT_TARGETS) { _tree_more[depth + 1] = has_children; // FIXME _display_tree_targets(name, depth + 2); }}/* * Walk the dependency tree */static void _display_tree_walk_children(struct dm_tree_node *node, unsigned depth){ struct dm_tree_node *child, *next_child; void *handle = NULL; uint32_t inverted = _tree_switches[TR_BOTTOMUP]; unsigned first_child = 1; unsigned has_children; next_child = dm_tree_next_child(&handle, node, inverted); while ((child = next_child)) { next_child = dm_tree_next_child(&handle, node, inverted); has_children = dm_tree_node_num_children(child, inverted) ? 1 : 0; _display_tree_node(child, depth, first_child, next_child ? 0U : 1U, has_children); if (has_children) _display_tree_walk_children(child, depth + 1); first_child = 0; }}static int _add_dep(int argc __attribute((unused)), char **argv __attribute((unused)), void *data){ struct dm_names *names = (struct dm_names *) data; if (!dm_tree_add_dev(_dtree, (unsigned) MAJOR(names->dev), (unsigned) MINOR(names->dev))) return 0; return 1;}/* * Create and walk dependency tree */static int _build_whole_deptree(void){ if (_dtree) return 1; if (!(_dtree = dm_tree_create())) return 0; if (!_process_all(0, NULL, 0, _add_dep)) return 0; return 1;}static int _display_tree(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused))){ if (!_build_whole_deptree()) return 0; _display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0); return 1;}/* * Report device information *//* dm specific display functions */static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), struct dm_report_field *field, const void *data, void *private __attribute((unused))){ const int32_t value = *(const int32_t *)data; return dm_report_field_int32(rh, field, &value);}static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), struct dm_report_field *field, const void *data, void *private __attribute((unused))){ const uint32_t value = *(const int32_t *)data; return dm_report_field_uint32(rh, field, &value);}static int _dm_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), struct dm_report_field *field, const void *data, void *private __attribute((unused))){ const char *name = dm_task_get_name((const struct dm_task *) data); return dm_report_field_string(rh, field, &name);}static int _dm_uuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), struct dm_report_field *field, const void *data, void *private __attribute((unused))){ const char *uuid = dm_task_get_uuid((const struct dm_task *) data); if (!uuid || !*uuid) uuid = ""; return dm_report_field_string(rh, field, &uuid);}static int _dm_info_status_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), struct dm_report_field *field, const void *data, void *private __attribute((unused))){ char buf[5]; const char *s = buf; const struct dm_info *info = data; buf[0] = info->live_table ? 'L' : '-'; buf[1] = info->inactive_table ? 'I' : '-'; buf[2] = info->suspended ? 's' : '-'; buf[3] = info->read_only ? 'r' : 'w'; buf[4] = '\0'; return dm_report_field_string(rh, field, &s);}static int _dm_info_devno_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private){ char buf[DM_MAX_TYPE_NAME], *repstr; struct dm_info *info = (struct dm_info *) data; if (!dm_pool_begin_object(mem, 8)) { log_error("dm_pool_begin_object failed"); return 0; } if (dm_snprintf(buf, sizeof(buf), "%d:%d", info->major, info->minor) < 0) { log_error("dm_pool_alloc failed"); goto out_abandon; } if (!dm_pool_grow_object(mem, buf, strlen(buf) + 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } repstr = dm_pool_end_object(mem); dm_report_field_set_value(field, repstr, repstr); return 1; out_abandon: dm_pool_abandon_object(mem); return 0;}static int _dm_tree_names(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private, unsigned inverted){ struct dm_tree_node *node = (struct dm_tree_node *) data, *parent; void *t = NULL; const char *name; int first_node = 1; char *repstr; if (!dm_pool_begin_object(mem, 16)) { log_error("dm_pool_begin_object failed"); return 0; } while ((parent = dm_tree_next_child(&t, node, inverted))) { name = dm_tree_node_get_name(parent); if (!name || !*name) continue; if (!first_node && !dm_pool_grow_object(mem, ",", 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } if (!dm_pool_grow_object(mem, name, strlen(name))) { log_error("dm_pool_grow_object failed"); goto out_abandon; } if (first_node) first_node = 0; } if (!dm_pool_grow_object(mem, "\0", 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } repstr = dm_pool_end_object(mem); dm_report_field_set_value(field, repstr, repstr); return 1; out_abandon: dm_pool_abandon_object(mem); return 0;}static int _dm_deps_names_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private){ return _dm_tree_names(rh, mem, field, data, private, 0);}static int _dm_tree_parents_names_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private){ return _dm_tree_names(rh, mem, field, data, private, 1);}static int _dm_tree_parents_devs_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private){ struct dm_tree_node *node = (struct dm_tree_node *) data, *parent; void *t = NULL; const struct dm_info *info; int first_node = 1; char buf[DM_MAX_TYPE_NAME], *repstr; if (!dm_pool_begin_object(mem, 16)) { log_error("dm_pool_begin_object failed"); return 0; } while ((parent = dm_tree_next_child(&t, node, 1))) { info = dm_tree_node_get_info(parent); if (!info->major && !info->minor) continue; if (!first_node && !dm_pool_grow_object(mem, ",", 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } if (dm_snprintf(buf, sizeof(buf), "%d:%d", info->major, info->minor) < 0) { log_error("dm_snprintf failed"); goto out_abandon; } if (!dm_pool_grow_object(mem, buf, strlen(buf))) { log_error("dm_pool_grow_object failed"); goto out_abandon; } if (first_node) first_node = 0; } if (!dm_pool_grow_object(mem, "\0", 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } repstr = dm_pool_end_object(mem); dm_report_field_set_value(field, repstr, repstr); return 1; out_abandon: dm_pool_abandon_object(mem); return 0;}static int _dm_tree_parents_count_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private){ struct dm_tree_node *node = (struct dm_tree_node *) data; int num_parent = dm_tree_node_num_children(node, 1); return dm_report_field_int(rh, field, &num_parent);}static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private){ struct dm_deps *deps = (struct dm_deps *) data; int i; char buf[DM_MAX_TYPE_NAME], *repstr; if (!dm_pool_begin_object(mem, 16)) { log_error("dm_pool_begin_object failed"); return 0; } for (i = 0; i < deps->count; i++) { if (dm_snprintf(buf, sizeof(buf), "%d:%d", (int) MAJOR(deps->device[i]), (int) MINOR(deps->device[i])) < 0) { log_error("dm_snprintf failed"); goto out_abandon; } if (!dm_pool_grow_object(mem, buf, strlen(buf))) { log_error("dm_pool_grow_object failed"); goto out_abandon; } if (i + 1 < deps->count && !dm_pool_grow_object(mem, ",", 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } } if (!dm_pool_grow_object(mem, "\0", 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } repstr = dm_pool_end_object(mem); dm_report_field_set_value(field, repstr, repstr); return 1; out_abandon: dm_pool_abandon_object(mem); return 0;}static void *_task_get_obj(void *obj){ return ((struct dmsetup_report_obj *)obj)->task;}static void *_info_get_obj(void *obj){ return ((struct dmsetup_report_obj *)obj)->info;}static void *_deps_get_obj(void *obj){ return dm_task_get_deps(((struct dmsetup_report_obj *)obj)->deps_task);}static void *_tree_get_obj(void *obj){ return ((struct dmsetup_report_obj *)obj)->tree_node;}static const struct dm_report_object_type _report_types[] = { { DR_TASK, "Mapped Device Name", "", _task_get_obj }, { DR_INFO, "Mapped Device Information", "", _info_get_obj }, { DR_DEPS, "Mapped Device Relationship Information", "", _deps_get_obj }, { DR_TREE, "Mapped Device Relationship Information", "", _tree_get_obj }, { 0, "", "", NULL },};/* Column definitions */#define OFFSET_OF(strct, field) ((unsigned int) &((struct strct *)NULL)->field)#define STR (DM_REPORT_FIELD_TYPE_STRING)#define NUM (DM_REPORT_FIELD_TYPE_NUMBER)#define FIELD_O(type, strct, sorttype, head, field, width, func, id, desc) {DR_ ## type, sorttype, OFFSET_OF(strct, field), width, id, head, &_ ## func ## _disp, desc},#define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, sorttype, 0, width, id, head, &_ ## func ## _disp, desc},static const struct dm_report_field_type _report_fields[] = {/* *INDENT-OFF* */FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.")FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.")FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.")FIELD_F(INFO, STR, "DevNo", 5, dm_info_devno, "devno", "Device major and minor numbers")FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Block device major number.")FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor", "Block device minor number.")FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open", "Number of references to open device, if requested.")FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number of segments in live table, if present.")FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.")FIELD_O(DEPS, dm_deps, NUM, "#Devs", count, 5, int32, "device_count", "Number of devices used by this one.")FIELD_F(TREE, STR, "DevNames", 8, dm_deps_names, "devs_used", "List of names of mapped devices used by this one.")FIELD_F(DEPS, STR, "DevNos", 6, dm_deps, "devnos_used", "List of device numbers of devices used by this one.")FIELD_F(TREE, NUM, "#Refs", 5, dm_tree_parents_count, "device_ref_count", "Number of mapped devices referencing this one.")FIELD_F(TREE, STR, "RefNames", 8, dm_tree_parents_names, "names_using_dev", "List of names of mapped devices using this one.")FIELD_F(TREE, STR, "RefDevNos", 9, dm_tree_parents_devs, "devnos_using_dev", "List of device numbers of mapped devices using this one."){0, 0, 0, 0, "", "", NULL, NULL},/* *INDENT-ON* */};#undef STR#undef NUM#undef FIELD_O#undef FIELD_Fstatic const char *default_report_options = "name,major,minor,attr,open,segments,events,uuid";static int _report_init(struct command *c){ char *options = (char *) default_report_options; const char *keys = ""; const char *separator = " "; int aligned = 1, headings = 1, buffered = 1; uint32_t flags = 0; size_t len = 0; int r = 0; /* emulate old dmsetup behaviour */ if (_switches[NOHEADINGS_ARG]) { separator = ":"; aligned = 0; headings = 0; } if (_switches[UNBUFFERED_ARG]) buffered = 0; if (_switches[OPTIONS_ARG] && _string_args[OPTIONS_ARG]) { if (*_string_args[OPTIONS_ARG] != '+') options = _string_args[OPTIONS_ARG]; else { len = strlen(default_report_options) + strlen(_string_args[OPTIONS_ARG]) + 1; if (!(options = dm_malloc(len))) { err("Failed to allocate option string."); return 0; } if (dm_snprintf(options, len, "%s,%s", default_report_options, &_string_args[OPTIONS_ARG][1]) < 0) { err("snprintf failed"); goto out; } } } if (_switches[SORT_ARG] && _string_args[SORT_ARG]) { keys = _string_args[SORT_ARG]; buffered = 1; if (c && (!strcmp(c->name, "status") || !strcmp(c->name, "table"))) { err("--sort is not yet supported with status and table"); goto out; } } if (_switches[SEPARATOR_ARG] && _string_args[SEPARATOR_ARG]) { separator = _string_args[SEPARATOR_ARG]; aligned = 0; } if (aligned) flags |= DM_REPORT_OUTPUT_ALIGNED; if (buffered) flags |= DM_REPORT_OUTPUT_BUFFERED; if (headings) flags |= DM_REPORT_OUTPUT_HEADINGS; if (!(_report = dm_report_init(&_report_type, _report_types, _report_fields, options, separator, flags, keys, NULL))) goto out; if ((_report_type & DR_TREE) && !_build_whole_deptree()) { err("Internal device dependency tree creation failed."); goto out; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -