(root)/
util-linux-2.39/
disk-utils/
fdisk-list.c
       1  #include <libfdisk.h>
       2  #include <libsmartcols.h>
       3  #include <assert.h>
       4  
       5  #include "c.h"
       6  #include "xalloc.h"
       7  #include "nls.h"
       8  #include "blkdev.h"
       9  #include "mbsalign.h"
      10  #include "pathnames.h"
      11  #include "canonicalize.h"
      12  #include "strutils.h"
      13  #include "sysfs.h"
      14  #include "colors.h"
      15  #include "ttyutils.h"
      16  
      17  #include "fdisk-list.h"
      18  
      19  /* see init_fields() */
      20  static const char *fields_string;
      21  static int *fields_ids;
      22  static size_t fields_nids;
      23  static const struct fdisk_label *fields_label;
      24  
      25  static int is_ide_cdrom_or_tape(char *device)
      26  {
      27  	int fd, ret;
      28  
      29  	if ((fd = open(device, O_RDONLY|O_NONBLOCK)) < 0)
      30  		return 0;
      31  	ret = blkdev_is_cdrom(fd);
      32  
      33  	close(fd);
      34  	return ret;
      35  }
      36  
      37  void list_disk_identifier(struct fdisk_context *cxt)
      38  {
      39  	struct fdisk_label *lb = fdisk_get_label(cxt, NULL);
      40  	char *id = NULL;
      41  
      42  	if (fdisk_has_label(cxt))
      43  		fdisk_info(cxt, _("Disklabel type: %s"),
      44  				fdisk_label_get_name(lb));
      45  
      46  	if (!fdisk_is_details(cxt) && fdisk_get_disklabel_id(cxt, &id) == 0 && id) {
      47  		fdisk_info(cxt, _("Disk identifier: %s"), id);
      48  		free(id);
      49  	}
      50  }
      51  
      52  void list_disk_geometry(struct fdisk_context *cxt)
      53  {
      54  	struct fdisk_label *lb = fdisk_get_label(cxt, NULL);
      55  	uint64_t bytes = fdisk_get_nsectors(cxt) * fdisk_get_sector_size(cxt);
      56  	char *strsz = size_to_human_string(SIZE_DECIMAL_2DIGITS
      57  					   | SIZE_SUFFIX_SPACE
      58  					   | SIZE_SUFFIX_3LETTER, bytes);
      59  
      60  	color_scheme_enable("header", UL_COLOR_BOLD);
      61  	fdisk_info(cxt,	_("Disk %s: %s, %ju bytes, %ju sectors"),
      62  			fdisk_get_devname(cxt), strsz,
      63  			bytes, (uintmax_t) fdisk_get_nsectors(cxt));
      64  	color_disable();
      65  	free(strsz);
      66  
      67  	if (fdisk_get_devmodel(cxt))
      68  		fdisk_info(cxt, _("Disk model: %s"), fdisk_get_devmodel(cxt));
      69  
      70  	if (lb && (fdisk_label_require_geometry(lb) || fdisk_use_cylinders(cxt)))
      71  		fdisk_info(cxt, _("Geometry: %d heads, %ju sectors/track, %ju cylinders"),
      72  			       fdisk_get_geom_heads(cxt),
      73  			       (uintmax_t) fdisk_get_geom_sectors(cxt),
      74  			       (uintmax_t) fdisk_get_geom_cylinders(cxt));
      75  
      76  	fdisk_info(cxt, _("Units: %s of %d * %ld = %ld bytes"),
      77  	       fdisk_get_unit(cxt, FDISK_PLURAL),
      78  	       fdisk_get_units_per_sector(cxt),
      79  	       fdisk_get_sector_size(cxt),
      80  	       fdisk_get_units_per_sector(cxt) * fdisk_get_sector_size(cxt));
      81  
      82  	fdisk_info(cxt, _("Sector size (logical/physical): %lu bytes / %lu bytes"),
      83  				fdisk_get_sector_size(cxt),
      84  				fdisk_get_physector_size(cxt));
      85  	fdisk_info(cxt, _("I/O size (minimum/optimal): %lu bytes / %lu bytes"),
      86  				fdisk_get_minimal_iosize(cxt),
      87  				fdisk_get_optimal_iosize(cxt));
      88  	if (fdisk_get_alignment_offset(cxt))
      89  		fdisk_info(cxt, _("Alignment offset: %lu bytes"),
      90  				fdisk_get_alignment_offset(cxt));
      91  
      92  	list_disk_identifier(cxt);
      93  }
      94  
      95  void list_disklabel(struct fdisk_context *cxt)
      96  {
      97  	struct fdisk_table *tb = NULL;
      98  	struct fdisk_partition *pa = NULL;
      99  	struct fdisk_iter *itr = NULL;
     100  	struct fdisk_label *lb;
     101  	struct libscols_table *out = NULL;
     102  	const char *bold = NULL;
     103  	int *ids = NULL;		/* IDs of fdisk_fields */
     104  	size_t	nids = 0, i;
     105  	int post = 0;
     106  
     107  	/* print label specific stuff by libfdisk FDISK_ASK_INFO API */
     108  	fdisk_list_disklabel(cxt);
     109  
     110  	/* get partitions and generate output */
     111  	if (fdisk_get_partitions(cxt, &tb) || fdisk_table_get_nents(tb) <= 0)
     112  		goto done;
     113  
     114  	ids = init_fields(cxt, NULL, &nids);
     115  	if (!ids)
     116  		goto done;
     117  
     118  	itr = fdisk_new_iter(FDISK_ITER_FORWARD);
     119  	if (!itr) {
     120  		fdisk_warn(cxt, _("failed to allocate iterator"));
     121  		goto done;
     122  	}
     123  
     124  	out = scols_new_table();
     125  	if (!out) {
     126  		fdisk_warn(cxt, _("failed to allocate output table"));
     127  		goto done;
     128  	}
     129  
     130  	if (colors_wanted()) {
     131  		scols_table_enable_colors(out, 1);
     132  		bold = color_scheme_get_sequence("header", UL_COLOR_BOLD);
     133  	}
     134  
     135  	lb = fdisk_get_label(cxt, NULL);
     136  	assert(lb);
     137  
     138  	/* define output table columns */
     139  	for (i = 0; i < nids; i++) {
     140  		int fl = 0;
     141  		struct libscols_column *co;
     142  		const struct fdisk_field *field =
     143  				fdisk_label_get_field(lb, ids[i]);
     144  		if (!field)
     145  			continue;
     146  		if (fdisk_field_is_number(field))
     147  			fl |= SCOLS_FL_RIGHT;
     148  		if (fdisk_field_get_id(field) == FDISK_FIELD_TYPE)
     149  			fl |= SCOLS_FL_TRUNC;
     150  
     151  		co = scols_table_new_column(out,
     152  				_(fdisk_field_get_name(field)),
     153  				fdisk_field_get_width(field), fl);
     154  		if (!co)
     155  			goto done;
     156  
     157  		/* set column header color */
     158  		if (bold)
     159  			scols_cell_set_color(scols_column_get_header(co), bold);
     160  	}
     161  
     162  	/* fill-in output table */
     163  	while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
     164  		struct libscols_line *ln = scols_table_new_line(out, NULL);
     165  
     166  		if (!ln) {
     167  			fdisk_warn(cxt, _("failed to allocate output line"));
     168  			goto done;
     169  		}
     170  
     171  		for (i = 0; i < nids; i++) {
     172  			char *data = NULL;
     173  
     174  			if (fdisk_partition_to_string(pa, cxt, ids[i], &data))
     175  				continue;
     176  			if (scols_line_refer_data(ln, i, data)) {
     177  				fdisk_warn(cxt, _("failed to add output data"));
     178  				goto done;
     179  			}
     180  		}
     181  	}
     182  
     183  	/* print */
     184  	if (!scols_table_is_empty(out)) {
     185  		fdisk_info(cxt, "%s", "");	/* just line break */
     186  		scols_print_table(out);
     187  	}
     188  
     189  	/* print warnings */
     190  	fdisk_reset_iter(itr, FDISK_ITER_FORWARD);
     191  	while (itr && fdisk_table_next_partition(tb, itr, &pa) == 0) {
     192  		if (!fdisk_partition_has_start(pa))
     193  			continue;
     194  		if (!fdisk_lba_is_phy_aligned(cxt, fdisk_partition_get_start(pa))) {
     195  			if (!post)
     196  				fdisk_info(cxt, "%s", ""); /* line break */
     197  			fdisk_warnx(cxt, _("Partition %zu does not start on physical sector boundary."),
     198  					  fdisk_partition_get_partno(pa) + 1);
     199  			post++;
     200  		}
     201  		if (fdisk_partition_has_wipe(cxt, pa)) {
     202  			if (!post)
     203  				fdisk_info(cxt, "%s", ""); /* line break */
     204  
     205  			fdisk_info(cxt, _("Filesystem/RAID signature on partition %zu will be wiped."),
     206  					fdisk_partition_get_partno(pa) + 1);
     207  			post++;
     208  		}
     209  	}
     210  
     211  	if (fdisk_table_wrong_order(tb)) {
     212  		if (!post)
     213  			fdisk_info(cxt, "%s", ""); /* line break */
     214  		fdisk_info(cxt, _("Partition table entries are not in disk order."));
     215  	}
     216  done:
     217  	scols_unref_table(out);
     218  	fdisk_unref_table(tb);
     219  	fdisk_free_iter(itr);
     220  }
     221  
     222  void list_freespace(struct fdisk_context *cxt)
     223  {
     224  	struct fdisk_table *tb = NULL;
     225  	struct fdisk_partition *pa = NULL;
     226  	struct fdisk_iter *itr = NULL;
     227  	struct libscols_table *out = NULL;
     228  	const char *bold = NULL;
     229  	size_t i;
     230  	uintmax_t sumsize = 0, bytes = 0;
     231  	char *strsz;
     232  
     233  	static const char *colnames[] = { N_("Start"), N_("End"), N_("Sectors"), N_("Size") };
     234  	static const int colids[] = { FDISK_FIELD_START, FDISK_FIELD_END, FDISK_FIELD_SECTORS, FDISK_FIELD_SIZE };
     235  
     236  	if (fdisk_get_freespaces(cxt, &tb))
     237  		goto done;
     238  
     239  	itr = fdisk_new_iter(FDISK_ITER_FORWARD);
     240  	if (!itr) {
     241  		fdisk_warn(cxt, _("failed to allocate iterator"));
     242  		goto done;
     243  	}
     244  
     245  	out = scols_new_table();
     246  	if (!out) {
     247  		fdisk_warn(cxt, _("failed to allocate output table"));
     248  		goto done;
     249  	}
     250  
     251  	if (colors_wanted()) {
     252  		scols_table_enable_colors(out, 1);
     253  		bold = color_scheme_get_sequence("header", UL_COLOR_BOLD);
     254  	}
     255  
     256  	for (i = 0; i < ARRAY_SIZE(colnames); i++) {
     257  		struct libscols_column *co = scols_table_new_column(out, _(colnames[i]), 5, SCOLS_FL_RIGHT);
     258  
     259  		if (!co)
     260  			goto done;
     261  		if (bold)
     262  			scols_cell_set_color(scols_column_get_header(co), bold);
     263  	}
     264  
     265  	/* fill-in output table */
     266  	while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
     267  		struct libscols_line *ln = scols_table_new_line(out, NULL);
     268  		char *data;
     269  
     270  		if (!ln) {
     271  			fdisk_warn(cxt, _("failed to allocate output line"));
     272  			goto done;
     273  		}
     274  		for (i = 0; i < ARRAY_SIZE(colids); i++) {
     275  			if (fdisk_partition_to_string(pa, cxt, colids[i], &data))
     276  				continue;
     277  			if (scols_line_refer_data(ln, i, data)) {
     278  				fdisk_warn(cxt, _("failed to add output data"));
     279  				goto done;
     280  			}
     281  		}
     282  
     283  		if (fdisk_partition_has_size(pa))
     284  			sumsize += fdisk_partition_get_size(pa);
     285  	}
     286  
     287  	bytes = sumsize * fdisk_get_sector_size(cxt);
     288  	strsz = size_to_human_string(SIZE_DECIMAL_2DIGITS
     289  				     | SIZE_SUFFIX_SPACE
     290  				     | SIZE_SUFFIX_3LETTER, bytes);
     291  
     292  	color_scheme_enable("header", UL_COLOR_BOLD);
     293  	fdisk_info(cxt,	_("Unpartitioned space %s: %s, %ju bytes, %ju sectors"),
     294  			fdisk_get_devname(cxt), strsz,
     295  			bytes, sumsize);
     296  	color_disable();
     297  	free(strsz);
     298  
     299  	fdisk_info(cxt, _("Units: %s of %d * %ld = %ld bytes"),
     300  	       fdisk_get_unit(cxt, FDISK_PLURAL),
     301  	       fdisk_get_units_per_sector(cxt),
     302  	       fdisk_get_sector_size(cxt),
     303  	       fdisk_get_units_per_sector(cxt) * fdisk_get_sector_size(cxt));
     304  
     305  	fdisk_info(cxt, _("Sector size (logical/physical): %lu bytes / %lu bytes"),
     306  				fdisk_get_sector_size(cxt),
     307  				fdisk_get_physector_size(cxt));
     308  
     309  	/* print */
     310  	if (!scols_table_is_empty(out)) {
     311  		fdisk_info(cxt, "%s", "");	/* line break */
     312  		scols_print_table(out);
     313  	}
     314  done:
     315  	scols_unref_table(out);
     316  	fdisk_unref_table(tb);
     317  	fdisk_free_iter(itr);
     318  }
     319  
     320  char *next_proc_partition(FILE **f)
     321  {
     322  	char line[128 + 1];
     323  
     324  	if (!*f) {
     325  		*f = fopen(_PATH_PROC_PARTITIONS, "r");
     326  		if (!*f) {
     327  			warn(_("cannot open %s"), _PATH_PROC_PARTITIONS);
     328  			return NULL;
     329  		}
     330  	}
     331  
     332  	while (fgets(line, sizeof(line), *f)) {
     333  		char buf[PATH_MAX], *cn;
     334  		dev_t devno;
     335  
     336  		if (sscanf(line, " %*d %*d %*d %128[^\n ]", buf) != 1)
     337  			continue;
     338  
     339  		devno = sysfs_devname_to_devno(buf);
     340  		if (devno <= 0)
     341  			continue;
     342  
     343  		if (sysfs_devno_is_dm_private(devno, NULL) ||
     344  		    sysfs_devno_is_wholedisk(devno) <= 0)
     345  			continue;
     346  
     347  		if (!sysfs_devno_to_devpath(devno, buf, sizeof(buf)))
     348  			continue;
     349  
     350  		cn = canonicalize_path(buf);
     351  		if (!cn)
     352  			continue;
     353  
     354  		if (!is_ide_cdrom_or_tape(cn))
     355  			return cn;
     356  	}
     357  	fclose(*f);
     358  	*f = NULL;
     359  
     360  	return NULL;
     361  }
     362  
     363  int print_device_pt(struct fdisk_context *cxt, char *device, int warnme,
     364  		    int verify, int separator)
     365  {
     366  	if (fdisk_assign_device(cxt, device, 1) != 0) {	/* read-only */
     367  		if (warnme || errno == EACCES)
     368  			warn(_("cannot open %s"), device);
     369  		return -1;
     370  	}
     371  
     372  	if (separator)
     373  		fputs("\n\n", stdout);
     374  
     375  	list_disk_geometry(cxt);
     376  
     377  	if (fdisk_has_label(cxt)) {
     378  		list_disklabel(cxt);
     379  		if (verify)
     380  			fdisk_verify_disklabel(cxt);
     381  	}
     382  	fdisk_deassign_device(cxt, 1);
     383  	return 0;
     384  }
     385  
     386  int print_device_freespace(struct fdisk_context *cxt, char *device, int warnme,
     387  			   int separator)
     388  {
     389  	if (fdisk_assign_device(cxt, device, 1) != 0) {	/* read-only */
     390  		if (warnme || errno == EACCES)
     391  			warn(_("cannot open %s"), device);
     392  		return -1;
     393  	}
     394  
     395  	if (separator)
     396  		fputs("\n\n", stdout);
     397  
     398  	list_freespace(cxt);
     399  	fdisk_deassign_device(cxt, 1);
     400  	return 0;
     401  }
     402  
     403  void print_all_devices_pt(struct fdisk_context *cxt, int verify)
     404  {
     405  	FILE *f = NULL;
     406  	int sep = 0;
     407  	char *dev;
     408  
     409  	while ((dev = next_proc_partition(&f))) {
     410  		print_device_pt(cxt, dev, 0, verify, sep);
     411  		free(dev);
     412  		sep = 1;
     413  	}
     414  }
     415  
     416  void print_all_devices_freespace(struct fdisk_context *cxt)
     417  {
     418  	FILE *f = NULL;
     419  	int sep = 0;
     420  	char *dev;
     421  
     422  	while ((dev = next_proc_partition(&f))) {
     423  		print_device_freespace(cxt, dev, 0, sep);
     424  		free(dev);
     425  		sep = 1;
     426  	}
     427  }
     428  
     429  /* usable for example in usage() */
     430  void list_available_columns(FILE *out)
     431  {
     432  	size_t i;
     433  	int termwidth;
     434  	struct fdisk_label *lb = NULL;
     435  	struct fdisk_context *cxt = fdisk_new_context();
     436  
     437  	if (!cxt)
     438  		return;
     439  
     440  	termwidth = get_terminal_width(80);
     441  
     442  	fprintf(out, USAGE_COLUMNS);
     443  
     444  	while (fdisk_next_label(cxt, &lb) == 0) {
     445  		size_t width = 6;	/* label name and separators */
     446  
     447  		fprintf(out, " %s:", fdisk_label_get_name(lb));
     448  		for (i = 1; i < FDISK_NFIELDS; i++) {
     449  			const struct fdisk_field *fl = fdisk_label_get_field(lb, i);
     450  			const char *name = fl ? fdisk_field_get_name(fl) : NULL;
     451  			size_t len;
     452  
     453  			if (!name)
     454  				continue;
     455  			len = strlen(name) + 1;
     456  			if (width + len > (size_t) termwidth) {
     457  				fputs("\n     ", out);
     458  				width = 6;
     459  			}
     460  			fprintf(out, " %s", name);
     461  			width += len;
     462  		}
     463  		fputc('\n', out);
     464  	}
     465  
     466  	fdisk_unref_context(cxt);
     467  }
     468  
     469  static int fieldname_to_id(const char *name, size_t namesz)
     470  {
     471  	const struct fdisk_field *fl;
     472  	char buf[namesz + 1];
     473  
     474  	assert(name);
     475  	assert(namesz);
     476  	assert(fields_label);
     477  
     478  	memcpy(buf, name, namesz);
     479  	buf[namesz] = '\0';
     480  
     481  	fl = fdisk_label_get_field_by_name(fields_label, buf);
     482  	if (!fl) {
     483  		warnx(_("%s unknown column: %s"),
     484  				fdisk_label_get_name(fields_label), buf);
     485  		return -1;
     486  	}
     487  	return fdisk_field_get_id(fl);
     488  }
     489  
     490  /*
     491   * Initialize array with output columns (fields_ids[]) according to
     492   * comma delimited list of columns (@str). If the list string is not
     493   * defined then use library defaults. This function is "-o <list>"
     494   * backend.
     495   *
     496   * If the columns are already initialized then returns already existing columns.
     497   */
     498  int *init_fields(struct fdisk_context *cxt, const char *str, size_t *n)
     499  {
     500  	int *dflt_ids = NULL;
     501  	struct fdisk_label *lb;
     502  
     503  	if (!fields_string)
     504  		fields_string = str;
     505  	if (!cxt)
     506  	       goto done;
     507  
     508  	lb = fdisk_get_label(cxt, NULL);
     509  
     510  	if (!lb || fields_label != lb) {	/* label changed: reset */
     511  		free(fields_ids);
     512  		fields_ids = NULL;
     513  		fields_label = lb;
     514  		fields_nids = 0;
     515  	}
     516  
     517  	if (!fields_label)	/*  no label */
     518  		goto done;
     519  	if (fields_nids)
     520  		goto done;	/* already initialized */
     521  
     522  	/* library default */
     523  	if (fdisk_label_get_fields_ids(NULL, cxt, &dflt_ids, &fields_nids))
     524  		goto done;
     525  
     526  	fields_ids = xcalloc(FDISK_NFIELDS * 2, sizeof(int));
     527  
     528  	/* copy defaults to the list with wanted fields */
     529  	memcpy(fields_ids, dflt_ids, fields_nids * sizeof(int));
     530  	free(dflt_ids);
     531  
     532  	/* extend or replace fields_nids[] according to fields_string */
     533  	if (fields_string &&
     534  	    string_add_to_idarray(fields_string, fields_ids, FDISK_NFIELDS * 2,
     535  			          &fields_nids, fieldname_to_id) < 0)
     536  		exit(EXIT_FAILURE);
     537  done:
     538  	fields_label = NULL;
     539  	if (n)
     540  		*n = fields_nids;
     541  	return fields_ids;
     542  }
     543