| #include <libfdisk.h> |
| #include <libsmartcols.h> |
| #include <assert.h> |
| |
| #include "c.h" |
| #include "xalloc.h" |
| #include "nls.h" |
| #include "blkdev.h" |
| #include "mbsalign.h" |
| #include "pathnames.h" |
| #include "canonicalize.h" |
| #include "strutils.h" |
| #include "sysfs.h" |
| #include "colors.h" |
| #include "ttyutils.h" |
| |
| #include "fdisk-list.h" |
| |
| /* see init_fields() */ |
| static const char *fields_string; |
| static int *fields_ids; |
| static size_t fields_nids; |
| static const struct fdisk_label *fields_label; |
| |
| static int is_ide_cdrom_or_tape(char *device) |
| { |
| int fd, ret; |
| |
| if ((fd = open(device, O_RDONLY)) < 0) |
| return 0; |
| ret = blkdev_is_cdrom(fd); |
| |
| close(fd); |
| return ret; |
| } |
| |
| |
| void list_disk_geometry(struct fdisk_context *cxt) |
| { |
| char *id = NULL; |
| struct fdisk_label *lb = fdisk_get_label(cxt, NULL); |
| uint64_t bytes = fdisk_get_nsectors(cxt) * fdisk_get_sector_size(cxt); |
| char *strsz = size_to_human_string(SIZE_SUFFIX_SPACE |
| | SIZE_SUFFIX_3LETTER, bytes); |
| |
| color_scheme_enable("header", UL_COLOR_BOLD); |
| fdisk_info(cxt, _("Disk %s: %s, %ju bytes, %ju sectors"), |
| fdisk_get_devname(cxt), strsz, |
| bytes, (uintmax_t) fdisk_get_nsectors(cxt)); |
| color_disable(); |
| free(strsz); |
| |
| if (lb && (fdisk_label_require_geometry(lb) || fdisk_use_cylinders(cxt))) |
| fdisk_info(cxt, _("Geometry: %d heads, %llu sectors/track, %llu cylinders"), |
| fdisk_get_geom_heads(cxt), |
| fdisk_get_geom_sectors(cxt), |
| fdisk_get_geom_cylinders(cxt)); |
| |
| fdisk_info(cxt, _("Units: %s of %d * %ld = %ld bytes"), |
| fdisk_get_unit(cxt, FDISK_PLURAL), |
| fdisk_get_units_per_sector(cxt), |
| fdisk_get_sector_size(cxt), |
| fdisk_get_units_per_sector(cxt) * fdisk_get_sector_size(cxt)); |
| |
| fdisk_info(cxt, _("Sector size (logical/physical): %lu bytes / %lu bytes"), |
| fdisk_get_sector_size(cxt), |
| fdisk_get_physector_size(cxt)); |
| fdisk_info(cxt, _("I/O size (minimum/optimal): %lu bytes / %lu bytes"), |
| fdisk_get_minimal_iosize(cxt), |
| fdisk_get_optimal_iosize(cxt)); |
| if (fdisk_get_alignment_offset(cxt)) |
| fdisk_info(cxt, _("Alignment offset: %lu bytes"), |
| fdisk_get_alignment_offset(cxt)); |
| if (fdisk_has_label(cxt)) |
| fdisk_info(cxt, _("Disklabel type: %s"), |
| fdisk_label_get_name(lb)); |
| |
| if (fdisk_get_disklabel_id(cxt, &id) == 0 && id) |
| fdisk_info(cxt, _("Disk identifier: %s"), id); |
| } |
| |
| void list_disklabel(struct fdisk_context *cxt) |
| { |
| struct fdisk_table *tb = NULL; |
| struct fdisk_partition *pa = NULL; |
| struct fdisk_iter *itr = NULL; |
| struct fdisk_label *lb; |
| struct libscols_table *out = NULL; |
| const char *bold = NULL; |
| int *ids = NULL; /* IDs of fdisk_fields */ |
| size_t nids = 0, i; |
| int post = 0; |
| |
| /* print label specific stuff by libfdisk FDISK_ASK_INFO API */ |
| fdisk_list_disklabel(cxt); |
| |
| /* get partitions and generate output */ |
| if (fdisk_get_partitions(cxt, &tb) || fdisk_table_get_nents(tb) <= 0) |
| goto done; |
| |
| ids = init_fields(cxt, NULL, &nids); |
| if (!ids) |
| goto done; |
| |
| itr = fdisk_new_iter(FDISK_ITER_FORWARD); |
| if (!itr) { |
| fdisk_warn(cxt, _("failed to allocate iterator")); |
| goto done; |
| } |
| |
| out = scols_new_table(); |
| if (!out) { |
| fdisk_warn(cxt, _("failed to allocate output table")); |
| goto done; |
| } |
| |
| if (colors_wanted()) { |
| scols_table_enable_colors(out, 1); |
| bold = color_scheme_get_sequence("header", UL_COLOR_BOLD); |
| } |
| |
| lb = fdisk_get_label(cxt, NULL); |
| assert(lb); |
| |
| /* define output table columns */ |
| for (i = 0; i < nids; i++) { |
| int fl = 0; |
| struct libscols_column *co; |
| const struct fdisk_field *field = |
| fdisk_label_get_field(lb, ids[i]); |
| if (!field) |
| continue; |
| if (fdisk_field_is_number(field)) |
| fl |= SCOLS_FL_RIGHT; |
| if (fdisk_field_get_id(field) == FDISK_FIELD_TYPE) |
| fl |= SCOLS_FL_TRUNC; |
| |
| co = scols_table_new_column(out, |
| _(fdisk_field_get_name(field)), |
| fdisk_field_get_width(field), fl); |
| if (!co) |
| goto done; |
| |
| /* set colum header color */ |
| if (bold) |
| scols_cell_set_color(scols_column_get_header(co), bold); |
| } |
| |
| /* fill-in output table */ |
| while (fdisk_table_next_partition(tb, itr, &pa) == 0) { |
| struct libscols_line *ln = scols_table_new_line(out, NULL); |
| |
| if (!ln) { |
| fdisk_warn(cxt, _("failed to allocate output line")); |
| goto done; |
| } |
| |
| for (i = 0; i < nids; i++) { |
| char *data = NULL; |
| |
| if (fdisk_partition_to_string(pa, cxt, ids[i], &data)) |
| continue; |
| scols_line_refer_data(ln, i, data); |
| } |
| } |
| |
| /* print */ |
| if (!scols_table_is_empty(out)) { |
| fputc('\n', stdout); |
| scols_print_table(out); |
| } |
| |
| /* print warnings */ |
| fdisk_reset_iter(itr, FDISK_ITER_FORWARD); |
| while (itr && fdisk_table_next_partition(tb, itr, &pa) == 0) { |
| if (!fdisk_partition_has_start(pa)) |
| continue; |
| if (!fdisk_lba_is_phy_aligned(cxt, fdisk_partition_get_start(pa))) { |
| if (!post) |
| fputc('\n', stdout); |
| fdisk_warnx(cxt, _("Partition %zu does not start on physical sector boundary."), |
| fdisk_partition_get_partno(pa) + 1); |
| post++; |
| } |
| } |
| |
| if (fdisk_table_wrong_order(tb)) { |
| if (!post) |
| fputc('\n', stdout); |
| fdisk_info(cxt, _("Partition table entries are not in disk order.")); |
| } |
| done: |
| scols_unref_table(out); |
| fdisk_unref_table(tb); |
| fdisk_free_iter(itr); |
| } |
| |
| char *next_proc_partition(FILE **f) |
| { |
| char line[128 + 1]; |
| |
| if (!*f) { |
| *f = fopen(_PATH_PROC_PARTITIONS, "r"); |
| if (!*f) { |
| warn(_("cannot open %s"), _PATH_PROC_PARTITIONS); |
| return NULL; |
| } |
| } |
| |
| while (fgets(line, sizeof(line), *f)) { |
| char buf[PATH_MAX], *cn; |
| dev_t devno; |
| |
| if (sscanf(line, " %*d %*d %*d %128[^\n ]", buf) != 1) |
| continue; |
| |
| devno = sysfs_devname_to_devno(buf, NULL); |
| if (devno <= 0) |
| continue; |
| |
| if (sysfs_devno_is_lvm_private(devno) || |
| sysfs_devno_is_wholedisk(devno) <= 0) |
| continue; |
| |
| if (!sysfs_devno_to_devpath(devno, buf, sizeof(buf))) |
| continue; |
| |
| cn = canonicalize_path(buf); |
| if (!cn) |
| continue; |
| |
| if (!is_ide_cdrom_or_tape(cn)) |
| return cn; |
| } |
| fclose(*f); |
| *f = NULL; |
| |
| return NULL; |
| } |
| |
| int print_device_pt(struct fdisk_context *cxt, char *device, int warnme, int verify) |
| { |
| if (fdisk_assign_device(cxt, device, 1) != 0) { /* read-only */ |
| if (warnme || errno == EACCES) |
| warn(_("cannot open %s"), device); |
| return -1; |
| } |
| |
| list_disk_geometry(cxt); |
| |
| if (fdisk_has_label(cxt)) { |
| list_disklabel(cxt); |
| if (verify) |
| fdisk_verify_disklabel(cxt); |
| } |
| fdisk_deassign_device(cxt, 1); |
| return 0; |
| } |
| |
| void print_all_devices_pt(struct fdisk_context *cxt, int verify) |
| { |
| FILE *f = NULL; |
| int ct = 0; |
| char *dev; |
| |
| while ((dev = next_proc_partition(&f))) { |
| if (ct) |
| fputs("\n\n", stdout); |
| if (print_device_pt(cxt, dev, 0, verify) == 0) |
| ct++; |
| free(dev); |
| } |
| } |
| |
| /* usable for example in usage() */ |
| void list_available_columns(FILE *out) |
| { |
| size_t i; |
| int termwidth; |
| struct fdisk_label *lb = NULL; |
| struct fdisk_context *cxt = fdisk_new_context(); |
| |
| if (!cxt) |
| return; |
| |
| termwidth = get_terminal_width(); |
| if (termwidth <= 0) |
| termwidth = 80; |
| |
| fprintf(out, _("\nAvailable columns (for -o):\n")); |
| |
| while (fdisk_next_label(cxt, &lb) == 0) { |
| size_t width = 6; /* label name and separators */ |
| |
| fprintf(out, " %s:", fdisk_label_get_name(lb)); |
| for (i = 1; i < FDISK_NFIELDS; i++) { |
| const struct fdisk_field *fl = fdisk_label_get_field(lb, i); |
| const char *name = fl ? fdisk_field_get_name(fl) : NULL; |
| size_t len; |
| |
| if (!name) |
| continue; |
| len = strlen(name) + 1; |
| if (width + len > (size_t) termwidth) { |
| fputs("\n ", out); |
| width = 6; |
| } |
| fprintf(out, " %s", name); |
| width += len; |
| } |
| fputc('\n', out); |
| } |
| |
| fdisk_unref_context(cxt); |
| } |
| |
| static int fieldname_to_id(const char *name, size_t namesz) |
| { |
| const struct fdisk_field *fl; |
| char buf[namesz + 1]; |
| |
| assert(name); |
| assert(namesz); |
| assert(fields_label); |
| |
| memcpy(buf, name, namesz); |
| buf[namesz] = '\0'; |
| |
| fl = fdisk_label_get_field_by_name(fields_label, buf); |
| if (!fl) { |
| warnx(_("%s unknown column: %s"), |
| fdisk_label_get_name(fields_label), buf); |
| return -1; |
| } |
| return fdisk_field_get_id(fl); |
| } |
| |
| /* |
| * Initialize array with output columns (fields_ids[]) according to |
| * comma delimited list of columns (@str). If the list string is not |
| * defined then use library defaults. This function is "-o <list>" |
| * backend. |
| * |
| * If the columns are already initialized then returns already existing columns. |
| */ |
| int *init_fields(struct fdisk_context *cxt, const char *str, size_t *n) |
| { |
| int *dflt_ids = NULL; |
| struct fdisk_label *lb; |
| |
| if (!fields_string) |
| fields_string = str; |
| if (!cxt) |
| goto done; |
| |
| lb = fdisk_get_label(cxt, NULL); |
| |
| if (!lb || fields_label != lb) { /* label changed: reset */ |
| free(fields_ids); |
| fields_ids = NULL; |
| fields_label = lb; |
| fields_nids = 0; |
| } |
| |
| if (!fields_label) /* no label */ |
| goto done; |
| if (fields_nids) |
| goto done; /* already initialized */ |
| |
| /* library default */ |
| if (fdisk_label_get_fields_ids(NULL, cxt, &dflt_ids, &fields_nids)) |
| goto done; |
| |
| fields_ids = xcalloc(sizeof(int), FDISK_NFIELDS * 2); |
| |
| /* copy defaults to the list with wanted fields */ |
| memcpy(fields_ids, dflt_ids, fields_nids * sizeof(int)); |
| free(dflt_ids); |
| |
| /* extend or replace fields_nids[] according to fields_string */ |
| if (fields_string && |
| string_add_to_idarray(fields_string, fields_ids, FDISK_NFIELDS * 2, |
| (int *) &fields_nids, fieldname_to_id) < 0) |
| exit(EXIT_FAILURE); |
| done: |
| fields_label = NULL; |
| if (n) |
| *n = fields_nids; |
| return fields_ids; |
| } |
| |