blob: 750cfca554009aa5ed2303fc331bb656364179a1 [file] [log] [blame]
bigbiff7b4c7a62015-01-01 19:44:14 -05001
2#include "fdiskP.h"
3
4
5/**
6 * SECTION: label
7 * @title: Label
8 * @short_description: disk label (PT) specific data and functions
9 *
10 * The fdisk_new_context() initializes all label drivers, and allocate
11 * per-label specific data struct. This concept allows to store label specific
12 * settings to the label driver independently on the currently active label
13 * driver. Note that label struct cannot be deallocated, so there is no
14 * reference counting for fdisk_label objects. All is destroyed by
15 * fdisk_unref_context() only.
16 *
17 * Anyway, all label drives share in-memory first sector. The function
18 * fdisk_create_disklabel() overwrites the sector. But it's possible that
19 * label driver also uses another buffers, for example GPT uses more than only
20 * the first sector.
21 *
22 * All label operations are in-memory only, except fdisk_write_disklabel().
23 *
24 * All functions that use "struct fdisk_context" rather than "struct
25 * fdisk_label" use the currently active label driver.
26 */
27
28
29int fdisk_probe_labels(struct fdisk_context *cxt)
30{
31 size_t i;
32
33 cxt->label = NULL;
34
35 for (i = 0; i < cxt->nlabels; i++) {
36 struct fdisk_label *lb = cxt->labels[i];
37 struct fdisk_label *org = fdisk_get_label(cxt, NULL);
38 int rc;
39
40 if (!lb->op->probe)
41 continue;
42 if (lb->disabled) {
43 DBG(CXT, ul_debugobj(cxt, "%s: disabled -- ignore", lb->name));
44 continue;
45 }
46 DBG(CXT, ul_debugobj(cxt, "probing for %s", lb->name));
47
48 cxt->label = lb;
49 rc = lb->op->probe(cxt);
50 cxt->label = org;
51
52 if (rc != 1) {
53 if (lb->op->deinit)
54 lb->op->deinit(lb); /* for sure */
55 continue;
56 }
57
58 __fdisk_switch_label(cxt, lb);
59 return 0;
60 }
61
62 DBG(CXT, ul_debugobj(cxt, "no label found"));
63 return 1; /* not found */
64}
65
66/**
67 * fdisk_label_get_name:
68 * @lb: label
69 *
70 * Returns: label name
71 */
72const char *fdisk_label_get_name(const struct fdisk_label *lb)
73{
74 return lb ? lb->name : NULL;
75}
76
77/**
78 * fdisk_label_is_labeltype:
79 * @lb: label
80 *
81 * Returns: FDISK_DISKLABEL_*.
82 */
83int fdisk_label_get_type(const struct fdisk_label *lb)
84{
85 return lb->id;
86}
87
88/**
89 * fdisk_label_require_geometry:
90 * @lb: label
91 *
92 * Returns: 1 if label requires CHS geometry
93 */
94int fdisk_label_require_geometry(const struct fdisk_label *lb)
95{
96 assert(lb);
97
98 return lb->flags & FDISK_LABEL_FL_REQUIRE_GEOMETRY ? 1 : 0;
99}
100
101/**
102 * fdisk_label_get_fields_ids
103 * @lb: label (or NULL for the current label)
104 * @cxt: context
105 * @ids: returns allocated array with FDISK_FIELD_* IDs
106 * @nids: returns number of items in fields
107 *
108 * This function returns the default fields for the label.
109 *
110 * Note that the set of the default fields depends on fdisk_enable_details()
111 * function. If the details are enabled then this function usually returns more
112 * fields.
113 *
114 * Returns: 0 on success, otherwise, a corresponding error.
115 */
116int fdisk_label_get_fields_ids(
117 const struct fdisk_label *lb,
118 struct fdisk_context *cxt,
119 int **ids, size_t *nids)
120{
121 size_t i, n;
122 int *c;
123
124 assert(cxt);
125
126 if (!lb)
127 lb = cxt->label;
128 if (!lb)
129 return -EINVAL;
130 if (!lb->fields || !lb->nfields)
131 return -ENOSYS;
132 c = calloc(lb->nfields, sizeof(int));
133 if (!c)
134 return -ENOMEM;
135 for (n = 0, i = 0; i < lb->nfields; i++) {
136 int id = lb->fields[i].id;
137
138 if ((fdisk_is_details(cxt) &&
139 (lb->fields[i].flags & FDISK_FIELDFL_EYECANDY))
140 || (!fdisk_is_details(cxt) &&
141 (lb->fields[i].flags & FDISK_FIELDFL_DETAIL))
142 || (id == FDISK_FIELD_SECTORS &&
143 fdisk_use_cylinders(cxt))
144 || (id == FDISK_FIELD_CYLINDERS &&
145 !fdisk_use_cylinders(cxt)))
146 continue;
147
148 c[n++] = id;
149 }
150 if (ids)
151 *ids = c;
152 else
153 free(c);
154 if (nids)
155 *nids = n;
156 return 0;
157}
158
159/**
160 * fdisk_label_get_field:
161 * @lb: label
162 * @id: FDISK_FIELD_*
163 *
164 * The field struct describes data stored in struct fdisk_partition. The info
165 * about data is usable for example to generate human readable output (e.g.
166 * fdisk 'p'rint command). See fdisk_partition_to_stirng() and fdisk code.
167 *
168 * Returns: pointer to static instance of the field.
169 */
170const struct fdisk_field *fdisk_label_get_field(const struct fdisk_label *lb, int id)
171{
172 size_t i;
173
174 assert(lb);
175 assert(id > 0);
176
177 for (i = 0; i < lb->nfields; i++) {
178 if (lb->fields[i].id == id)
179 return &lb->fields[i];
180 }
181
182 return NULL;
183}
184
185/**
186 * fdisk_label_get_field_by_name
187 * @lb: label
188 * @name: field name
189 *
190 * Returns: pointer to static instance of the field.
191 */
192const struct fdisk_field *fdisk_label_get_field_by_name(
193 const struct fdisk_label *lb,
194 const char *name)
195{
196 size_t i;
197
198 assert(lb);
199 assert(name);
200
201 for (i = 0; i < lb->nfields; i++) {
202 if (lb->fields[i].name && strcasecmp(lb->fields[i].name, name) == 0)
203 return &lb->fields[i];
204 }
205
206 return NULL;
207}
208
209
210/**
211 * fdisk_field_get_id:
212 * @field: field instance
213 *
214 * Returns: field Id (FDISK_FIELD_*)
215 */
216int fdisk_field_get_id(const struct fdisk_field *field)
217{
218 return field ? field->id : -EINVAL;
219}
220
221/**
222 * fdisk_field_get_name:
223 * @field: field instance
224 *
225 * Returns: field name
226 */
227const char *fdisk_field_get_name(const struct fdisk_field *field)
228{
229 return field ? field->name : NULL;
230}
231
232/**
233 * fdisk_field_get_width:
234 * @field: field instance
235 *
236 * Returns: libsmartcols compatible width.
237 */
238double fdisk_field_get_width(const struct fdisk_field *field)
239{
240 return field ? field->width : -EINVAL;
241}
242
243/**
244 * fdisk_field_is_number:
245 * @field: field instance
246 *
247 * Returns: 1 if field represent number
248 */
249int fdisk_field_is_number(const struct fdisk_field *field)
250{
251 return field->flags ? field->flags & FDISK_FIELDFL_NUMBER : 0;
252}
253
254
255/**
256 * fdisk_write_disklabel:
257 * @cxt: fdisk context
258 *
259 * Write in-memory changes to disk. Be careful!
260 *
261 * Returns: 0 on success, otherwise, a corresponding error.
262 */
263int fdisk_write_disklabel(struct fdisk_context *cxt)
264{
265 if (!cxt || !cxt->label || cxt->readonly)
266 return -EINVAL;
267 if (!cxt->label->op->write)
268 return -ENOSYS;
269 return cxt->label->op->write(cxt);
270}
271
272/**
273 * fdisk_verify_disklabel:
274 * @cxt: fdisk context
275 *
276 * Verifies the partition table.
277 *
278 * Returns: 0 on success, otherwise, a corresponding error.
279 */
280int fdisk_verify_disklabel(struct fdisk_context *cxt)
281{
282 if (!cxt || !cxt->label)
283 return -EINVAL;
284 if (!cxt->label->op->verify)
285 return -ENOSYS;
286 if (fdisk_missing_geometry(cxt))
287 return -EINVAL;
288
289 return cxt->label->op->verify(cxt);
290}
291
292/**
293 * fdisk_list_disklabel:
294 * @cxt: fdisk context
295 *
296 * Lists details about disklabel, but no partitions.
297 *
298 * This function uses libfdisk ASK interface to print data. The details about
299 * partitions table are printed by FDISK_ASKTYPE_INFO.
300 *
301 * Returns: 0 on success, otherwise, a corresponding error.
302 */
303int fdisk_list_disklabel(struct fdisk_context *cxt)
304{
305 if (!cxt || !cxt->label)
306 return -EINVAL;
307 if (!cxt->label->op->list)
308 return -ENOSYS;
309
310 return cxt->label->op->list(cxt);
311}
312
313/**
314 * fdisk_create_disklabel:
315 * @cxt: fdisk context
316 * @name: label name
317 *
318 * Creates a new disk label of type @name. If @name is NULL, then it will
319 * create a default system label type, either SUN or DOS. The function
320 * automaticaly switches the current label driver to @name. The function
321 * fdisk_get_label() returns the current label driver.
322 *
323 * The function modifies in-memory data only.
324 *
325 * Returns: 0 on success, otherwise, a corresponding error.
326 */
327int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name)
328{
329 int haslabel = 0;
330 struct fdisk_label *lb;
331
332 if (!cxt)
333 return -EINVAL;
334
335 if (!name) { /* use default label creation */
336#ifdef __sparc__
337 name = "sun";
338#else
339 name = "dos";
340#endif
341 }
342
343 if (cxt->label) {
344 fdisk_deinit_label(cxt->label);
345 haslabel = 1;
346 }
347
348 lb = fdisk_get_label(cxt, name);
349 if (!lb || lb->disabled)
350 return -EINVAL;
351 if (!lb->op->create)
352 return -ENOSYS;
353
354 __fdisk_switch_label(cxt, lb);
355
356 if (haslabel && !cxt->parent)
357 fdisk_reset_device_properties(cxt);
358
359 DBG(CXT, ul_debugobj(cxt, "create a new %s label", lb->name));
360 return cxt->label->op->create(cxt);
361}
362
363/**
364 * fdisk_locate_disklabel:
365 * @cxt: context
366 * @n: N item
367 * @name: return item name
368 * @offset: return offset where is item
369 * @size: of the item
370 *
371 * Locate disklabel and returns info about @n item of the label. For example
372 * GPT is composed from two items, PMBR and GPT, n=0 return offset to PMBR and n=1
373 * return offset to GPT. For more details see 'D' expect fdisk command.
374 *
375 * Returns: 0 on succes, <0 on error, 1 no more items.
376 */
377int fdisk_locate_disklabel(struct fdisk_context *cxt, int n, const char **name,
378 off_t *offset, size_t *size)
379{
380 if (!cxt || !cxt->label)
381 return -EINVAL;
382 if (!cxt->label->op->locate)
383 return -ENOSYS;
384
385 DBG(CXT, ul_debugobj(cxt, "locating %d chunk of %s.", n, cxt->label->name));
386 return cxt->label->op->locate(cxt, n, name, offset, size);
387}
388
389
390/**
391 * fdisk_get_disklabel_id:
392 * @cxt: fdisk context
393 * @id: returns pointer to allocated string (MBR Id or GPT dirk UUID)
394 *
395 * Returns: 0 on success, otherwise, a corresponding error.
396 */
397int fdisk_get_disklabel_id(struct fdisk_context *cxt, char **id)
398{
399 if (!cxt || !cxt->label)
400 return -EINVAL;
401 if (!cxt->label->op->get_id)
402 return -ENOSYS;
403
404 DBG(CXT, ul_debugobj(cxt, "asking for disk %s ID", cxt->label->name));
405 return cxt->label->op->get_id(cxt, id);
406}
407
408/**
409 * fdisk_set_disklabel_id:
410 * @cxt: fdisk context
411 *
412 * Returns: 0 on success, otherwise, a corresponding error.
413 */
414int fdisk_set_disklabel_id(struct fdisk_context *cxt)
415{
416 if (!cxt || !cxt->label)
417 return -EINVAL;
418 if (!cxt->label->op->set_id)
419 return -ENOSYS;
420
421 DBG(CXT, ul_debugobj(cxt, "setting %s disk ID", cxt->label->name));
422 return cxt->label->op->set_id(cxt);
423}
424
425/**
426 * fdisk_set_partition_type:
427 * @cxt: fdisk context
428 * @partnum: partition number
429 * @t: new type
430 *
431 * Returns: 0 on success, < 0 on error.
432 */
433int fdisk_set_partition_type(struct fdisk_context *cxt,
434 size_t partnum,
435 struct fdisk_parttype *t)
436{
437 if (!cxt || !cxt->label || !t)
438 return -EINVAL;
439
440
441 if (cxt->label->op->set_part) {
442 struct fdisk_partition *pa = fdisk_new_partition();
443 int rc;
444
445 if (!pa)
446 return -ENOMEM;
447 fdisk_partition_set_type(pa, t);
448
449 DBG(CXT, ul_debugobj(cxt, "partition: %zd: set type", partnum));
450 rc = cxt->label->op->set_part(cxt, partnum, pa);
451 fdisk_unref_partition(pa);
452 return rc;
453 }
454
455 return -ENOSYS;
456}
457
458
459/**
460 * fdisk_toggle_partition_flag:
461 * @cxt: fdisk context
462 * @partnum: partition number
463 * @flag: flag ID
464 *
465 * Returns: 0 on success, otherwise, a corresponding error.
466 */
467int fdisk_toggle_partition_flag(struct fdisk_context *cxt,
468 size_t partnum,
469 unsigned long flag)
470{
471 int rc;
472
473 if (!cxt || !cxt->label)
474 return -EINVAL;
475 if (!cxt->label->op->part_toggle_flag)
476 return -ENOSYS;
477
478 rc = cxt->label->op->part_toggle_flag(cxt, partnum, flag);
479
480 DBG(CXT, ul_debugobj(cxt, "partition: %zd: toggle: 0x%04lx [rc=%d]", partnum, flag, rc));
481 return rc;
482}
483
484/**
485 * fdisk_reorder_partitions
486 * @cxt: fdisk context
487 *
488 * Sort partitions according to the partition start sector.
489 *
490 * Returns: 0 on success, otherwise, a corresponding error.
491 */
492int fdisk_reorder_partitions(struct fdisk_context *cxt)
493{
494 if (!cxt || !cxt->label)
495 return -EINVAL;
496 if (!cxt->label->op->reorder)
497 return -ENOSYS;
498
499 return cxt->label->op->reorder(cxt);
500}
501
502/*
503 * Resets the current used label driver to initial state
504 */
505void fdisk_deinit_label(struct fdisk_label *lb)
506{
507 assert(lb);
508
509 /* private label information */
510 if (lb->op->deinit)
511 lb->op->deinit(lb);
512}
513
514/**
515 * fdisk_label_set_changed:
516 * @lb: label
517 * @changed: 0/1
518 *
519 * Marks in-memory data as changed, to force fdisk_write_disklabel() to write
520 * to device. This should be unnecessar by default, the library keeps track
521 * about changes.
522 */
523void fdisk_label_set_changed(struct fdisk_label *lb, int changed)
524{
525 assert(lb);
526 lb->changed = changed ? 1 : 0;
527}
528
529/**
530 * fdisk_label_is_changed:
531 * @lb: label
532 *
533 * Returns: 1 if in-memory data has been changed.
534 */
535int fdisk_label_is_changed(const struct fdisk_label *lb)
536{
537 assert(lb);
538 return lb ? lb->changed : 0;
539}
540
541/**
542 * fdisk_label_set_disabled:
543 * @lb: label
544 * @disabled: 0 or 1
545 *
546 * Mark label as disabled, then libfdisk is going to ignore the label when
547 * probe device for labels.
548 */
549void fdisk_label_set_disabled(struct fdisk_label *lb, int disabled)
550{
551 assert(lb);
552
553 DBG(LABEL, ul_debug("%s label %s",
554 lb->name,
555 disabled ? "DISABLED" : "ENABLED"));
556 lb->disabled = disabled ? 1 : 0;
557}
558
559/**
560 * fdisk_label_is_disabled:
561 * @lb: label
562 *
563 * Returns: 1 if label driver disabled.
564 */
565int fdisk_label_is_disabled(const struct fdisk_label *lb)
566{
567 assert(lb);
568 return lb ? lb->disabled : 0;
569}