544 lines
13 KiB
C
544 lines
13 KiB
C
#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|O_NONBLOCK)) < 0)
|
|
return 0;
|
|
ret = blkdev_is_cdrom(fd);
|
|
|
|
close(fd);
|
|
return ret;
|
|
}
|
|
|
|
void list_disk_identifier(struct fdisk_context *cxt)
|
|
{
|
|
struct fdisk_label *lb = fdisk_get_label(cxt, NULL);
|
|
char *id = NULL;
|
|
|
|
if (fdisk_has_label(cxt))
|
|
fdisk_info(cxt, _("Disklabel type: %s"),
|
|
fdisk_label_get_name(lb));
|
|
|
|
if (!fdisk_is_details(cxt) && fdisk_get_disklabel_id(cxt, &id) == 0 && id) {
|
|
fdisk_info(cxt, _("Disk identifier: %s"), id);
|
|
free(id);
|
|
}
|
|
}
|
|
|
|
void list_disk_geometry(struct fdisk_context *cxt)
|
|
{
|
|
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_DECIMAL_2DIGITS
|
|
| 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 (fdisk_get_devmodel(cxt))
|
|
fdisk_info(cxt, _("Disk model: %s"), fdisk_get_devmodel(cxt));
|
|
|
|
if (lb && (fdisk_label_require_geometry(lb) || fdisk_use_cylinders(cxt)))
|
|
fdisk_info(cxt, _("Geometry: %d heads, %ju sectors/track, %ju cylinders"),
|
|
fdisk_get_geom_heads(cxt),
|
|
(uintmax_t) fdisk_get_geom_sectors(cxt),
|
|
(uintmax_t) 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));
|
|
|
|
list_disk_identifier(cxt);
|
|
}
|
|
|
|
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 column 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;
|
|
if (scols_line_refer_data(ln, i, data)) {
|
|
fdisk_warn(cxt, _("failed to add output data"));
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* print */
|
|
if (!scols_table_is_empty(out)) {
|
|
fdisk_info(cxt, "%s", ""); /* just line break */
|
|
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)
|
|
fdisk_info(cxt, "%s", ""); /* line break */
|
|
fdisk_warnx(cxt, _("Partition %zu does not start on physical sector boundary."),
|
|
fdisk_partition_get_partno(pa) + 1);
|
|
post++;
|
|
}
|
|
if (fdisk_partition_has_wipe(cxt, pa)) {
|
|
if (!post)
|
|
fdisk_info(cxt, "%s", ""); /* line break */
|
|
|
|
fdisk_info(cxt, _("Filesystem/RAID signature on partition %zu will be wiped."),
|
|
fdisk_partition_get_partno(pa) + 1);
|
|
post++;
|
|
}
|
|
}
|
|
|
|
if (fdisk_table_wrong_order(tb)) {
|
|
if (!post)
|
|
fdisk_info(cxt, "%s", ""); /* line break */
|
|
fdisk_info(cxt, _("Partition table entries are not in disk order."));
|
|
}
|
|
done:
|
|
scols_unref_table(out);
|
|
fdisk_unref_table(tb);
|
|
fdisk_free_iter(itr);
|
|
}
|
|
|
|
void list_freespace(struct fdisk_context *cxt)
|
|
{
|
|
struct fdisk_table *tb = NULL;
|
|
struct fdisk_partition *pa = NULL;
|
|
struct fdisk_iter *itr = NULL;
|
|
struct libscols_table *out = NULL;
|
|
const char *bold = NULL;
|
|
size_t i;
|
|
uintmax_t sumsize = 0, bytes = 0;
|
|
char *strsz;
|
|
|
|
static const char *colnames[] = { N_("Start"), N_("End"), N_("Sectors"), N_("Size") };
|
|
static const int colids[] = { FDISK_FIELD_START, FDISK_FIELD_END, FDISK_FIELD_SECTORS, FDISK_FIELD_SIZE };
|
|
|
|
if (fdisk_get_freespaces(cxt, &tb))
|
|
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);
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(colnames); i++) {
|
|
struct libscols_column *co = scols_table_new_column(out, _(colnames[i]), 5, SCOLS_FL_RIGHT);
|
|
|
|
if (!co)
|
|
goto done;
|
|
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);
|
|
char *data;
|
|
|
|
if (!ln) {
|
|
fdisk_warn(cxt, _("failed to allocate output line"));
|
|
goto done;
|
|
}
|
|
for (i = 0; i < ARRAY_SIZE(colids); i++) {
|
|
if (fdisk_partition_to_string(pa, cxt, colids[i], &data))
|
|
continue;
|
|
if (scols_line_refer_data(ln, i, data)) {
|
|
fdisk_warn(cxt, _("failed to add output data"));
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (fdisk_partition_has_size(pa))
|
|
sumsize += fdisk_partition_get_size(pa);
|
|
}
|
|
|
|
bytes = sumsize * fdisk_get_sector_size(cxt);
|
|
strsz = size_to_human_string(SIZE_DECIMAL_2DIGITS
|
|
| SIZE_SUFFIX_SPACE
|
|
| SIZE_SUFFIX_3LETTER, bytes);
|
|
|
|
color_scheme_enable("header", UL_COLOR_BOLD);
|
|
fdisk_info(cxt, _("Unpartitioned space %s: %s, %ju bytes, %ju sectors"),
|
|
fdisk_get_devname(cxt), strsz,
|
|
bytes, sumsize);
|
|
color_disable();
|
|
free(strsz);
|
|
|
|
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));
|
|
|
|
/* print */
|
|
if (!scols_table_is_empty(out)) {
|
|
fdisk_info(cxt, "%s", ""); /* line break */
|
|
scols_print_table(out);
|
|
}
|
|
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);
|
|
if (devno <= 0)
|
|
continue;
|
|
|
|
if (sysfs_devno_is_dm_private(devno, NULL) ||
|
|
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, int separator)
|
|
{
|
|
if (fdisk_assign_device(cxt, device, 1) != 0) { /* read-only */
|
|
if (warnme || errno == EACCES)
|
|
warn(_("cannot open %s"), device);
|
|
return -1;
|
|
}
|
|
|
|
if (separator)
|
|
fputs("\n\n", stdout);
|
|
|
|
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;
|
|
}
|
|
|
|
int print_device_freespace(struct fdisk_context *cxt, char *device, int warnme,
|
|
int separator)
|
|
{
|
|
if (fdisk_assign_device(cxt, device, 1) != 0) { /* read-only */
|
|
if (warnme || errno == EACCES)
|
|
warn(_("cannot open %s"), device);
|
|
return -1;
|
|
}
|
|
|
|
if (separator)
|
|
fputs("\n\n", stdout);
|
|
|
|
list_freespace(cxt);
|
|
fdisk_deassign_device(cxt, 1);
|
|
return 0;
|
|
}
|
|
|
|
void print_all_devices_pt(struct fdisk_context *cxt, int verify)
|
|
{
|
|
FILE *f = NULL;
|
|
int sep = 0;
|
|
char *dev;
|
|
|
|
while ((dev = next_proc_partition(&f))) {
|
|
print_device_pt(cxt, dev, 0, verify, sep);
|
|
free(dev);
|
|
sep = 1;
|
|
}
|
|
}
|
|
|
|
void print_all_devices_freespace(struct fdisk_context *cxt)
|
|
{
|
|
FILE *f = NULL;
|
|
int sep = 0;
|
|
char *dev;
|
|
|
|
while ((dev = next_proc_partition(&f))) {
|
|
print_device_freespace(cxt, dev, 0, sep);
|
|
free(dev);
|
|
sep = 1;
|
|
}
|
|
}
|
|
|
|
/* 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(80);
|
|
|
|
fprintf(out, USAGE_COLUMNS);
|
|
|
|
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(FDISK_NFIELDS * 2, sizeof(int));
|
|
|
|
/* 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,
|
|
&fields_nids, fieldname_to_id) < 0)
|
|
exit(EXIT_FAILURE);
|
|
done:
|
|
fields_label = NULL;
|
|
if (n)
|
|
*n = fields_nids;
|
|
return fields_ids;
|
|
}
|
|
|