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