]> git.ipfire.org Git - thirdparty/util-linux.git/blob - disk-utils/fdisk-list.c
libblkid: make example more robust
[thirdparty/util-linux.git] / 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)) < 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, %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));
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, ""); /* 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, ""); /* 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, ""); /* line break */
204 fdisk_info(cxt, _("Filesystem/RAID signature on partition %zu will be wiped."),
205 fdisk_partition_get_partno(pa) + 1);
206 post++;
207 }
208 }
209
210 if (fdisk_table_wrong_order(tb)) {
211 if (!post)
212 fdisk_info(cxt, ""); /* line break */
213 fdisk_info(cxt, _("Partition table entries are not in disk order."));
214 }
215 done:
216 scols_unref_table(out);
217 fdisk_unref_table(tb);
218 fdisk_free_iter(itr);
219 }
220
221 void list_freespace(struct fdisk_context *cxt)
222 {
223 struct fdisk_table *tb = NULL;
224 struct fdisk_partition *pa = NULL;
225 struct fdisk_iter *itr = NULL;
226 struct libscols_table *out = NULL;
227 const char *bold = NULL;
228 size_t i;
229 uintmax_t sumsize = 0, bytes = 0;
230 char *strsz;
231
232 static const char *colnames[] = { N_("Start"), N_("End"), N_("Sectors"), N_("Size") };
233 static const int colids[] = { FDISK_FIELD_START, FDISK_FIELD_END, FDISK_FIELD_SECTORS, FDISK_FIELD_SIZE };
234
235 if (fdisk_get_freespaces(cxt, &tb))
236 goto done;
237
238 itr = fdisk_new_iter(FDISK_ITER_FORWARD);
239 if (!itr) {
240 fdisk_warn(cxt, _("failed to allocate iterator"));
241 goto done;
242 }
243
244 out = scols_new_table();
245 if (!out) {
246 fdisk_warn(cxt, _("failed to allocate output table"));
247 goto done;
248 }
249
250 if (colors_wanted()) {
251 scols_table_enable_colors(out, 1);
252 bold = color_scheme_get_sequence("header", UL_COLOR_BOLD);
253 }
254
255 for (i = 0; i < ARRAY_SIZE(colnames); i++) {
256 struct libscols_column *co = scols_table_new_column(out, _(colnames[i]), 5, SCOLS_FL_RIGHT);
257
258 if (!co)
259 goto done;
260 if (bold)
261 scols_cell_set_color(scols_column_get_header(co), bold);
262 }
263
264 /* fill-in output table */
265 while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
266 struct libscols_line *ln = scols_table_new_line(out, NULL);
267 char *data;
268
269 if (!ln) {
270 fdisk_warn(cxt, _("failed to allocate output line"));
271 goto done;
272 }
273 for (i = 0; i < ARRAY_SIZE(colids); i++) {
274 if (fdisk_partition_to_string(pa, cxt, colids[i], &data))
275 continue;
276 if (scols_line_refer_data(ln, i, data)) {
277 fdisk_warn(cxt, _("failed to add output data"));
278 goto done;
279 }
280 }
281
282 if (fdisk_partition_has_size(pa))
283 sumsize += fdisk_partition_get_size(pa);
284 }
285
286 bytes = sumsize * fdisk_get_sector_size(cxt);
287 strsz = size_to_human_string(SIZE_DECIMAL_2DIGITS
288 | SIZE_SUFFIX_SPACE
289 | SIZE_SUFFIX_3LETTER, bytes);
290
291 color_scheme_enable("header", UL_COLOR_BOLD);
292 fdisk_info(cxt, _("Unpartitioned space %s: %s, %ju bytes, %ju sectors"),
293 fdisk_get_devname(cxt), strsz,
294 bytes, sumsize);
295 color_disable();
296 free(strsz);
297
298 fdisk_info(cxt, _("Units: %s of %d * %ld = %ld bytes"),
299 fdisk_get_unit(cxt, FDISK_PLURAL),
300 fdisk_get_units_per_sector(cxt),
301 fdisk_get_sector_size(cxt),
302 fdisk_get_units_per_sector(cxt) * fdisk_get_sector_size(cxt));
303
304 fdisk_info(cxt, _("Sector size (logical/physical): %lu bytes / %lu bytes"),
305 fdisk_get_sector_size(cxt),
306 fdisk_get_physector_size(cxt));
307
308 /* print */
309 if (!scols_table_is_empty(out)) {
310 fdisk_info(cxt, ""); /* line break */
311 scols_print_table(out);
312 }
313 done:
314 scols_unref_table(out);
315 fdisk_unref_table(tb);
316 fdisk_free_iter(itr);
317 }
318
319 char *next_proc_partition(FILE **f)
320 {
321 char line[128 + 1];
322
323 if (!*f) {
324 *f = fopen(_PATH_PROC_PARTITIONS, "r");
325 if (!*f) {
326 warn(_("cannot open %s"), _PATH_PROC_PARTITIONS);
327 return NULL;
328 }
329 }
330
331 while (fgets(line, sizeof(line), *f)) {
332 char buf[PATH_MAX], *cn;
333 dev_t devno;
334
335 if (sscanf(line, " %*d %*d %*d %128[^\n ]", buf) != 1)
336 continue;
337
338 devno = sysfs_devname_to_devno(buf);
339 if (devno <= 0)
340 continue;
341
342 if (sysfs_devno_is_dm_private(devno, NULL) ||
343 sysfs_devno_is_wholedisk(devno) <= 0)
344 continue;
345
346 if (!sysfs_devno_to_devpath(devno, buf, sizeof(buf)))
347 continue;
348
349 cn = canonicalize_path(buf);
350 if (!cn)
351 continue;
352
353 if (!is_ide_cdrom_or_tape(cn))
354 return cn;
355 }
356 fclose(*f);
357 *f = NULL;
358
359 return NULL;
360 }
361
362 int print_device_pt(struct fdisk_context *cxt, char *device, int warnme, int verify)
363 {
364 if (fdisk_assign_device(cxt, device, 1) != 0) { /* read-only */
365 if (warnme || errno == EACCES)
366 warn(_("cannot open %s"), device);
367 return -1;
368 }
369
370 list_disk_geometry(cxt);
371
372 if (fdisk_has_label(cxt)) {
373 list_disklabel(cxt);
374 if (verify)
375 fdisk_verify_disklabel(cxt);
376 }
377 fdisk_deassign_device(cxt, 1);
378 return 0;
379 }
380
381 int print_device_freespace(struct fdisk_context *cxt, char *device, int warnme)
382 {
383 if (fdisk_assign_device(cxt, device, 1) != 0) { /* read-only */
384 if (warnme || errno == EACCES)
385 warn(_("cannot open %s"), device);
386 return -1;
387 }
388
389 list_freespace(cxt);
390 fdisk_deassign_device(cxt, 1);
391 return 0;
392 }
393
394 void print_all_devices_pt(struct fdisk_context *cxt, int verify)
395 {
396 FILE *f = NULL;
397 int ct = 0;
398 char *dev;
399
400 while ((dev = next_proc_partition(&f))) {
401 if (ct)
402 fputs("\n\n", stdout);
403 if (print_device_pt(cxt, dev, 0, verify) == 0)
404 ct++;
405 free(dev);
406 }
407 }
408
409 void print_all_devices_freespace(struct fdisk_context *cxt)
410 {
411 FILE *f = NULL;
412 int ct = 0;
413 char *dev;
414
415 while ((dev = next_proc_partition(&f))) {
416 if (ct)
417 fputs("\n\n", stdout);
418 if (print_device_freespace(cxt, dev, 0) == 0)
419 ct++;
420 free(dev);
421 }
422 }
423
424 /* usable for example in usage() */
425 void list_available_columns(FILE *out)
426 {
427 size_t i;
428 int termwidth;
429 struct fdisk_label *lb = NULL;
430 struct fdisk_context *cxt = fdisk_new_context();
431
432 if (!cxt)
433 return;
434
435 termwidth = get_terminal_width(80);
436
437 fprintf(out, USAGE_COLUMNS);
438
439 while (fdisk_next_label(cxt, &lb) == 0) {
440 size_t width = 6; /* label name and separators */
441
442 fprintf(out, " %s:", fdisk_label_get_name(lb));
443 for (i = 1; i < FDISK_NFIELDS; i++) {
444 const struct fdisk_field *fl = fdisk_label_get_field(lb, i);
445 const char *name = fl ? fdisk_field_get_name(fl) : NULL;
446 size_t len;
447
448 if (!name)
449 continue;
450 len = strlen(name) + 1;
451 if (width + len > (size_t) termwidth) {
452 fputs("\n ", out);
453 width = 6;
454 }
455 fprintf(out, " %s", name);
456 width += len;
457 }
458 fputc('\n', out);
459 }
460
461 fdisk_unref_context(cxt);
462 }
463
464 static int fieldname_to_id(const char *name, size_t namesz)
465 {
466 const struct fdisk_field *fl;
467 char buf[namesz + 1];
468
469 assert(name);
470 assert(namesz);
471 assert(fields_label);
472
473 memcpy(buf, name, namesz);
474 buf[namesz] = '\0';
475
476 fl = fdisk_label_get_field_by_name(fields_label, buf);
477 if (!fl) {
478 warnx(_("%s unknown column: %s"),
479 fdisk_label_get_name(fields_label), buf);
480 return -1;
481 }
482 return fdisk_field_get_id(fl);
483 }
484
485 /*
486 * Initialize array with output columns (fields_ids[]) according to
487 * comma delimited list of columns (@str). If the list string is not
488 * defined then use library defaults. This function is "-o <list>"
489 * backend.
490 *
491 * If the columns are already initialized then returns already existing columns.
492 */
493 int *init_fields(struct fdisk_context *cxt, const char *str, size_t *n)
494 {
495 int *dflt_ids = NULL;
496 struct fdisk_label *lb;
497
498 if (!fields_string)
499 fields_string = str;
500 if (!cxt)
501 goto done;
502
503 lb = fdisk_get_label(cxt, NULL);
504
505 if (!lb || fields_label != lb) { /* label changed: reset */
506 free(fields_ids);
507 fields_ids = NULL;
508 fields_label = lb;
509 fields_nids = 0;
510 }
511
512 if (!fields_label) /* no label */
513 goto done;
514 if (fields_nids)
515 goto done; /* already initialized */
516
517 /* library default */
518 if (fdisk_label_get_fields_ids(NULL, cxt, &dflt_ids, &fields_nids))
519 goto done;
520
521 fields_ids = xcalloc(FDISK_NFIELDS * 2, sizeof(int));
522
523 /* copy defaults to the list with wanted fields */
524 memcpy(fields_ids, dflt_ids, fields_nids * sizeof(int));
525 free(dflt_ids);
526
527 /* extend or replace fields_nids[] according to fields_string */
528 if (fields_string &&
529 string_add_to_idarray(fields_string, fields_ids, FDISK_NFIELDS * 2,
530 &fields_nids, fieldname_to_id) < 0)
531 exit(EXIT_FAILURE);
532 done:
533 fields_label = NULL;
534 if (n)
535 *n = fields_nids;
536 return fields_ids;
537 }
538