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