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