]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/fdisk-list.c
wipefs: add --lock and LOCK_BLOCK_DEVICE
[thirdparty/util-linux.git] / disk-utils / fdisk-list.c
CommitLineData
152788aa
KZ
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"
fff8ad58 15#include "ttyutils.h"
152788aa
KZ
16
17#include "fdisk-list.h"
18
fff8ad58
KZ
19/* see init_fields() */
20static const char *fields_string;
21static int *fields_ids;
22static size_t fields_nids;
23static const struct fdisk_label *fields_label;
24
152788aa
KZ
25static int is_ide_cdrom_or_tape(char *device)
26{
27 int fd, ret;
28
29 if ((fd = open(device, O_RDONLY)) < 0)
30 return 0;
31 ret = blkdev_is_cdrom(fd);
32
33 close(fd);
34 return ret;
35}
36
35ca5118
KZ
37void 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}
152788aa
KZ
51
52void list_disk_geometry(struct fdisk_context *cxt)
53{
152788aa
KZ
54 struct fdisk_label *lb = fdisk_get_label(cxt, NULL);
55 uint64_t bytes = fdisk_get_nsectors(cxt) * fdisk_get_sector_size(cxt);
39f37044
KZ
56 char *strsz = size_to_human_string(SIZE_DECIMAL_2DIGITS
57 | SIZE_SUFFIX_SPACE
152788aa
KZ
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
6ec47609
KZ
67 if (fdisk_get_devmodel(cxt))
68 fdisk_info(cxt, _("Disk model: %s"), fdisk_get_devmodel(cxt));
69
152788aa
KZ
70 if (lb && (fdisk_label_require_geometry(lb) || fdisk_use_cylinders(cxt)))
71 fdisk_info(cxt, _("Geometry: %d heads, %llu sectors/track, %llu cylinders"),
72 fdisk_get_geom_heads(cxt),
73 fdisk_get_geom_sectors(cxt),
74 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));
152788aa 91
35ca5118 92 list_disk_identifier(cxt);
152788aa
KZ
93}
94
95void 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;
c7475647 105 int post = 0;
152788aa
KZ
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
fff8ad58
KZ
114 ids = init_fields(cxt, NULL, &nids);
115 if (!ids)
152788aa
KZ
116 goto done;
117
118 itr = fdisk_new_iter(FDISK_ITER_FORWARD);
119 if (!itr) {
54fefa07 120 fdisk_warn(cxt, _("failed to allocate iterator"));
152788aa
KZ
121 goto done;
122 }
123
124 out = scols_new_table();
125 if (!out) {
54fefa07 126 fdisk_warn(cxt, _("failed to allocate output table"));
152788aa
KZ
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)
6d812a48 145 continue;
152788aa
KZ
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,
9ac1fcf6 152 _(fdisk_field_get_name(field)),
152788aa
KZ
153 fdisk_field_get_width(field), fl);
154 if (!co)
155 goto done;
156
3fd1f771 157 /* set column header color */
152788aa
KZ
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) {
54fefa07 167 fdisk_warn(cxt, _("failed to allocate output line"));
152788aa
KZ
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;
780ce22c
KZ
176 if (scols_line_refer_data(ln, i, data)) {
177 fdisk_warn(cxt, _("failed to add output data"));
178 goto done;
179 }
152788aa
KZ
180 }
181 }
182
183 /* print */
184 if (!scols_table_is_empty(out)) {
901f85fe 185 fdisk_info(cxt, ""); /* just line break */
152788aa
KZ
186 scols_print_table(out);
187 }
188
189 /* print warnings */
c7475647 190 fdisk_reset_iter(itr, FDISK_ITER_FORWARD);
152788aa 191 while (itr && fdisk_table_next_partition(tb, itr, &pa) == 0) {
ecf40cda
KZ
192 if (!fdisk_partition_has_start(pa))
193 continue;
c7475647
KZ
194 if (!fdisk_lba_is_phy_aligned(cxt, fdisk_partition_get_start(pa))) {
195 if (!post)
901f85fe 196 fdisk_info(cxt, ""); /* line break */
152788aa
KZ
197 fdisk_warnx(cxt, _("Partition %zu does not start on physical sector boundary."),
198 fdisk_partition_get_partno(pa) + 1);
c7475647
KZ
199 post++;
200 }
ddead341
KZ
201 if (fdisk_partition_has_wipe(cxt, pa)) {
202 if (!post)
203 fdisk_info(cxt, ""); /* line break */
ad524980
RP
204
205 fdisk_info(cxt, _("Filesystem/RAID signature on partition %zu will be wiped."),
206 fdisk_partition_get_partno(pa) + 1);
207 post++;
ddead341 208 }
152788aa
KZ
209 }
210
c7475647
KZ
211 if (fdisk_table_wrong_order(tb)) {
212 if (!post)
901f85fe 213 fdisk_info(cxt, ""); /* line break */
152788aa 214 fdisk_info(cxt, _("Partition table entries are not in disk order."));
c7475647 215 }
152788aa 216done:
152788aa
KZ
217 scols_unref_table(out);
218 fdisk_unref_table(tb);
219 fdisk_free_iter(itr);
220}
221
0efd951c
KZ
222void 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;
780ce22c
KZ
277 if (scols_line_refer_data(ln, i, data)) {
278 fdisk_warn(cxt, _("failed to add output data"));
279 goto done;
280 }
0efd951c
KZ
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);
39f37044
KZ
288 strsz = size_to_human_string(SIZE_DECIMAL_2DIGITS
289 | SIZE_SUFFIX_SPACE
290 | SIZE_SUFFIX_3LETTER, bytes);
0efd951c
KZ
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)) {
901f85fe 311 fdisk_info(cxt, ""); /* line break */
0efd951c
KZ
312 scols_print_table(out);
313 }
314done:
315 scols_unref_table(out);
316 fdisk_unref_table(tb);
317 fdisk_free_iter(itr);
318}
319
d464e2f0 320char *next_proc_partition(FILE **f)
152788aa 321{
152788aa 322 char line[128 + 1];
152788aa 323
d464e2f0
KZ
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 }
152788aa
KZ
330 }
331
d464e2f0 332 while (fgets(line, sizeof(line), *f)) {
152788aa
KZ
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
efb17218 339 devno = sysfs_devname_to_devno(buf);
152788aa
KZ
340 if (devno <= 0)
341 continue;
342
80ec018c 343 if (sysfs_devno_is_dm_private(devno, NULL) ||
152788aa
KZ
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
d464e2f0
KZ
354 if (!is_ide_cdrom_or_tape(cn))
355 return cn;
356 }
357 fclose(*f);
358 *f = NULL;
359
360 return NULL;
361}
362
4a52959d
WS
363int print_device_pt(struct fdisk_context *cxt, char *device, int warnme,
364 int verify, int seperator)
d464e2f0
KZ
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
4a52959d
WS
372 if (seperator)
373 fputs("\n\n", stdout);
374
d464e2f0
KZ
375 list_disk_geometry(cxt);
376
d2c47697 377 if (fdisk_has_label(cxt)) {
d464e2f0 378 list_disklabel(cxt);
d2c47697
KZ
379 if (verify)
380 fdisk_verify_disklabel(cxt);
381 }
d464e2f0
KZ
382 fdisk_deassign_device(cxt, 1);
383 return 0;
384}
385
9bf75171
WS
386int print_device_freespace(struct fdisk_context *cxt, char *device, int warnme,
387 int seperator)
0efd951c
KZ
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
9bf75171
WS
395 if (seperator)
396 fputs("\n\n", stdout);
397
0efd951c
KZ
398 list_freespace(cxt);
399 fdisk_deassign_device(cxt, 1);
400 return 0;
401}
402
d2c47697 403void print_all_devices_pt(struct fdisk_context *cxt, int verify)
d464e2f0
KZ
404{
405 FILE *f = NULL;
4a52959d 406 int sep = 0;
d464e2f0
KZ
407 char *dev;
408
409 while ((dev = next_proc_partition(&f))) {
4a52959d 410 print_device_pt(cxt, dev, 0, verify, sep);
d464e2f0 411 free(dev);
4a52959d 412 sep = 1;
152788aa 413 }
152788aa
KZ
414}
415
0efd951c
KZ
416void print_all_devices_freespace(struct fdisk_context *cxt)
417{
418 FILE *f = NULL;
9bf75171 419 int sep = 0;
0efd951c
KZ
420 char *dev;
421
422 while ((dev = next_proc_partition(&f))) {
9bf75171 423 print_device_freespace(cxt, dev, 0, sep);
0efd951c 424 free(dev);
9bf75171 425 sep = 1;
0efd951c
KZ
426 }
427}
428
fff8ad58
KZ
429/* usable for example in usage() */
430void 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
43b4f7ea 440 termwidth = get_terminal_width(80);
fff8ad58 441
c3a4cfc5 442 fprintf(out, USAGE_COLUMNS);
fff8ad58
KZ
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
469static 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 */
498int *init_fields(struct fdisk_context *cxt, const char *str, size_t *n)
499{
500 int *dflt_ids = NULL;
6d812a48 501 struct fdisk_label *lb;
fff8ad58
KZ
502
503 if (!fields_string)
504 fields_string = str;
6d812a48
KZ
505 if (!cxt)
506 goto done;
fff8ad58 507
6d812a48
KZ
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 }
fff8ad58 516
6d812a48 517 if (!fields_label) /* no label */
fff8ad58 518 goto done;
6d812a48
KZ
519 if (fields_nids)
520 goto done; /* already initialized */
fff8ad58
KZ
521
522 /* library default */
523 if (fdisk_label_get_fields_ids(NULL, cxt, &dflt_ids, &fields_nids))
524 goto done;
525
622be278 526 fields_ids = xcalloc(FDISK_NFIELDS * 2, sizeof(int));
fff8ad58
KZ
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,
40b17508 535 &fields_nids, fieldname_to_id) < 0)
fff8ad58
KZ
536 exit(EXIT_FAILURE);
537done:
538 fields_label = NULL;
539 if (n)
540 *n = fields_nids;
541 return fields_ids;
542}
543