]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libfdisk/src/context.c
libfdisk: (docs) add reference to v2.33
[thirdparty/util-linux.git] / libfdisk / src / context.c
CommitLineData
6e876a98
KZ
1#ifdef HAVE_LIBBLKID
2# include <blkid.h>
3#endif
823f0fd1 4
b9da1532 5#include "blkdev.h"
5ecd6185
KZ
6#ifdef __linux__
7# include "partx.h"
8#endif
b9da1532 9#include "loopdev.h"
f4be9e2b 10#include "fdiskP.h"
f7b1f75e 11
5175ae87
KZ
12
13/**
14 * SECTION: context
705854f3
KZ
15 * @title: Context
16 * @short_description: stores info about device, labels etc.
5175ae87 17 *
7190b9b2 18 * The library distinguish between three types of partitioning objects.
5175ae87
KZ
19 *
20 * on-disk data
7190b9b2
KZ
21 * - disk label specific
22 * - probed and read by disklabel drivers when assign device to the context
23 * or when switch to another disk label type
24 * - only fdisk_write_disklabel() modify on-disk data
5175ae87
KZ
25 *
26 * in-memory data
7190b9b2
KZ
27 * - generic data and disklabel specific data stored in struct fdisk_label
28 * - all partitioning operations are based on in-memory data only
5175ae87
KZ
29 *
30 * struct fdisk_partition
7190b9b2
KZ
31 * - provides abstraction to present partitions to users
32 * - fdisk_partition is possible to gather to fdisk_table container
33 * - used as unified template for new partitions
34 * - the struct fdisk_partition is always completely independent object and
35 * any change to the object has no effect to in-memory (or on-disk) label data
5175ae87
KZ
36 */
37
6a632136
KZ
38/**
39 * fdisk_new_context:
40 *
41 * Returns: newly allocated libfdisk handler
42 */
4e0e8253 43struct fdisk_context *fdisk_new_context(void)
0c5d095e
KZ
44{
45 struct fdisk_context *cxt;
0c5d095e
KZ
46
47 cxt = calloc(1, sizeof(*cxt));
48 if (!cxt)
49 return NULL;
50
d71bd2f0 51 DBG(CXT, ul_debugobj(cxt, "alloc"));
4e0e8253 52 cxt->dev_fd = -1;
c7119037 53 cxt->refcount = 1;
4e0e8253 54
131e38a2
KZ
55 INIT_LIST_HEAD(&cxt->wipes);
56
0c5d095e
KZ
57 /*
58 * Allocate label specific structs.
59 *
60 * This is necessary (for example) to store label specific
61 * context setting.
62 */
63 cxt->labels[ cxt->nlabels++ ] = fdisk_new_gpt_label(cxt);
64 cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt);
b4fb2a61 65 cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt);
0c5d095e
KZ
66 cxt->labels[ cxt->nlabels++ ] = fdisk_new_sgi_label(cxt);
67 cxt->labels[ cxt->nlabels++ ] = fdisk_new_sun_label(cxt);
68
7095232d
KZ
69 bindtextdomain(LIBFDISK_TEXTDOMAIN, LOCALEDIR);
70
0c5d095e
KZ
71 return cxt;
72}
73
13633a81 74static int init_nested_from_parent(struct fdisk_context *cxt, int isnew)
11eee4c4
KZ
75{
76 struct fdisk_context *parent;
77
78 assert(cxt);
79 assert(cxt->parent);
80
81 parent = cxt->parent;
82
11eee4c4
KZ
83 cxt->alignment_offset = parent->alignment_offset;
84 cxt->ask_cb = parent->ask_cb;
85 cxt->ask_data = parent->ask_data;
86 cxt->dev_fd = parent->dev_fd;
87 cxt->first_lba = parent->first_lba;
88 cxt->firstsector_bufsz = parent->firstsector_bufsz;
89 cxt->firstsector = parent->firstsector;
90 cxt->geom = parent->geom;
91 cxt->grain = parent->grain;
92 cxt->io_size = parent->io_size;
93 cxt->last_lba = parent->last_lba;
94 cxt->min_io_size = parent->min_io_size;
95 cxt->optimal_io_size = parent->optimal_io_size;
96 cxt->phy_sector_size = parent->phy_sector_size;
97 cxt->readonly = parent->readonly;
98 cxt->script = parent->script;
99 fdisk_ref_script(cxt->script);
100 cxt->sector_size = parent->sector_size;
101 cxt->total_sectors = parent->total_sectors;
102 cxt->user_geom = parent->user_geom;
103 cxt->user_log_sector = parent->user_log_sector;
104 cxt->user_pyh_sector = parent->user_pyh_sector;
105
3457d90e 106 /* parent <--> nested independent setting, initialize for new nested
11eee4c4
KZ
107 * contexts only */
108 if (isnew) {
109 cxt->listonly = parent->listonly;
110 cxt->display_details = parent->display_details;
111 cxt->display_in_cyl_units = parent->display_in_cyl_units;
3457d90e 112 cxt->protect_bootbits = parent->protect_bootbits;
11eee4c4
KZ
113 }
114
745801e4
KZ
115 free(cxt->dev_model);
116 cxt->dev_model = NULL;
117 cxt->dev_model_probed = 0;
118
13633a81
KZ
119 free(cxt->dev_path);
120 cxt->dev_path = NULL;
121
122 if (parent->dev_path) {
123 cxt->dev_path = strdup(parent->dev_path);
124 if (!cxt->dev_path)
125 return -ENOMEM;
126 }
127
131e38a2
KZ
128 INIT_LIST_HEAD(&cxt->wipes);
129
13633a81 130 return 0;
11eee4c4
KZ
131}
132
6a632136
KZ
133/**
134 * fdisk_new_nested_context:
135 * @parent: parental context
136 * @name: optional label name (e.g. "bsd")
137 *
11eee4c4
KZ
138 * Create a new nested fdisk context for nested disk labels (e.g. BSD or PMBR).
139 * The function also probes for the nested label on the device if device is
140 * already assigned to parent.
141 *
142 * The new context is initialized according to @parent and both context shares
143 * some settings and file descriptor to the device. The child propagate some
144 * changes (like fdisk_assign_device()) to parent, but it does not work
145 * vice-versa. The behavior is undefined if you assign another device to
146 * parent.
6a632136 147 *
11eee4c4 148 * Returns: new context for nested partition table.
6a632136 149 */
01b20713
KZ
150struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent,
151 const char *name)
152{
153 struct fdisk_context *cxt;
8a9256f9 154 struct fdisk_label *lb = NULL;
01b20713
KZ
155
156 assert(parent);
01b20713
KZ
157
158 cxt = calloc(1, sizeof(*cxt));
159 if (!cxt)
160 return NULL;
161
4a79a8f1 162 DBG(CXT, ul_debugobj(parent, "alloc nested [%p] [name=%s]", cxt, name));
c7119037 163 cxt->refcount = 1;
01b20713 164
11eee4c4
KZ
165 fdisk_ref_context(parent);
166 cxt->parent = parent;
b720e0d7 167
9c321dfb
KZ
168 if (init_nested_from_parent(cxt, 1) != 0) {
169 cxt->parent = NULL;
170 fdisk_unref_context(cxt);
13633a81 171 return NULL;
9c321dfb 172 }
01b20713 173
d17c584a 174 if (name) {
4a79a8f1 175 if (strcasecmp(name, "bsd") == 0)
d17c584a 176 lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt);
4a79a8f1 177 else if (strcasecmp(name, "dos") == 0 || strcasecmp(name, "mbr") == 0)
d17c584a
KZ
178 lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt);
179 }
8a9256f9 180
11eee4c4 181 if (lb && parent->dev_fd >= 0) {
d71bd2f0 182 DBG(CXT, ul_debugobj(cxt, "probing for nested %s", lb->name));
8a9256f9
KZ
183
184 cxt->label = lb;
185
186 if (lb->op->probe(cxt) == 1)
6a632136 187 __fdisk_switch_label(cxt, lb);
8a9256f9 188 else {
d71bd2f0 189 DBG(CXT, ul_debugobj(cxt, "not found %s label", lb->name));
8a9256f9
KZ
190 if (lb->op->deinit)
191 lb->op->deinit(lb);
192 cxt->label = NULL;
193 }
194 }
01b20713
KZ
195
196 return cxt;
197}
198
199
62a9ef3e
KZ
200/**
201 * fdisk_ref_context:
202 * @cxt: context pointer
203 *
7190b9b2 204 * Increments reference counter.
62a9ef3e
KZ
205 */
206void fdisk_ref_context(struct fdisk_context *cxt)
207{
208 if (cxt)
209 cxt->refcount++;
210}
211
6a632136
KZ
212/**
213 * fdisk_get_label:
214 * @cxt: context instance
215 * @name: label name (e.g. "gpt")
216 *
217 * If no @name specified then returns the current context label.
218 *
3c5ee57c 219 * The label is allocated and maintained within the context #cxt. There is
9e930041 220 * nothing like reference counting for labels, you cannot deallocate the
3c5ee57c
KZ
221 * label.
222 *
6a632136 223 * Returns: label struct or NULL in case of error.
852ce62b 224 */
6a632136 225struct fdisk_label *fdisk_get_label(struct fdisk_context *cxt, const char *name)
0c5d095e
KZ
226{
227 size_t i;
228
229 assert(cxt);
230
852ce62b
KZ
231 if (!name)
232 return cxt->label;
4a79a8f1
KZ
233 else if (strcasecmp(name, "mbr") == 0)
234 name = "dos";
852ce62b 235
0c5d095e 236 for (i = 0; i < cxt->nlabels; i++)
7ab242ec 237 if (cxt->labels[i]
4a79a8f1 238 && strcasecmp(cxt->labels[i]->name, name) == 0)
0c5d095e
KZ
239 return cxt->labels[i];
240
d71bd2f0 241 DBG(CXT, ul_debugobj(cxt, "failed to found %s label driver", name));
0c5d095e
KZ
242 return NULL;
243}
244
6a632136
KZ
245/**
246 * fdisk_next_label:
247 * @cxt: context instance
248 * @lb: returns pointer to the next label
249 *
250 * <informalexample>
251 * <programlisting>
252 * // print all supported labels
253 * struct fdisk_context *cxt = fdisk_new_context();
254 * struct fdisk_label *lb = NULL;
255 *
256 * while (fdisk_next_label(cxt, &lb) == 0)
257 * print("label name: %s\n", fdisk_label_get_name(lb));
c7119037 258 * fdisk_unref_context(cxt);
6a632136
KZ
259 * </programlisting>
260 * </informalexample>
261 *
262 * Returns: <0 in case of error, 0 on success, 1 at the end.
263 */
264int fdisk_next_label(struct fdisk_context *cxt, struct fdisk_label **lb)
7a188aed
KZ
265{
266 size_t i;
267 struct fdisk_label *res = NULL;
268
269 if (!lb || !cxt)
270 return -EINVAL;
271
272 if (!*lb)
273 res = cxt->labels[0];
274 else {
275 for (i = 1; i < cxt->nlabels; i++) {
276 if (*lb == cxt->labels[i - 1]) {
277 res = cxt->labels[i];
278 break;
279 }
280 }
281 }
282
283 *lb = res;
284 return res ? 0 : 1;
285}
286
6a632136
KZ
287/**
288 * fdisk_get_nlabels:
289 * @cxt: context
290 *
291 * Returns: number of supported label types
292 */
293size_t fdisk_get_nlabels(struct fdisk_context *cxt)
7aa0d529
KZ
294{
295 return cxt ? cxt->nlabels : 0;
296}
297
6a632136 298int __fdisk_switch_label(struct fdisk_context *cxt, struct fdisk_label *lb)
53b422ab 299{
7a188aed
KZ
300 if (!lb || !cxt)
301 return -EINVAL;
302 if (lb->disabled) {
d71bd2f0 303 DBG(CXT, ul_debugobj(cxt, "*** attempt to switch to disabled label %s -- ignore!", lb->name));
53b422ab 304 return -EINVAL;
7a188aed 305 }
53b422ab 306 cxt->label = lb;
d71bd2f0 307 DBG(CXT, ul_debugobj(cxt, "--> switching context to %s!", lb->name));
9c76f85f
KZ
308
309 fdisk_apply_label_device_properties(cxt);
53b422ab
KZ
310 return 0;
311}
312
aa36c2cf
KZ
313/**
314 * fdisk_has_label:
315 * @cxt: fdisk context
316 *
317 * Returns: return 1 if there is label on the device.
318 */
319int fdisk_has_label(struct fdisk_context *cxt)
320{
321 return cxt && cxt->label;
322}
323
3457d90e
KZ
324/**
325 * fdisk_has_protected_bootbits:
326 * @cxt: fdisk context
327 *
328 * Returns: return 1 if boot bits protection enabled.
329 */
330int fdisk_has_protected_bootbits(struct fdisk_context *cxt)
331{
332 return cxt && cxt->protect_bootbits;
333}
334
335/**
336 * fdisk_enable_bootbits_protection:
337 * @cxt: fdisk context
338 * @enable: 1 or 0
339 *
340 * The library zeroizes all the first sector when create a new disk label by
341 * default. This function allows to control this behavior. For now it's
342 * supported for MBR and GPT.
343 *
344 * Returns: 0 on success, < 0 on error.
345 */
346int fdisk_enable_bootbits_protection(struct fdisk_context *cxt, int enable)
347{
348 if (!cxt)
349 return -EINVAL;
350 cxt->protect_bootbits = enable ? 1 : 0;
351 return 0;
352}
992f7cba
KZ
353/**
354 * fdisk_disable_dialogs
355 * @cxt: fdisk context
9070c2e2 356 * @disable: 1 or 0
992f7cba
KZ
357 *
358 * The library uses dialog driven partitioning by default.
359 *
360 * Returns: 0 on success, < 0 on error.
361 *
362 * Since: 2.31
363 */
364int fdisk_disable_dialogs(struct fdisk_context *cxt, int disable)
365{
366 if (!cxt)
367 return -EINVAL;
368
369 cxt->no_disalogs = disable;
370 return 0;
371}
372
373/**
374 * fdisk_has_dialogs
375 * @cxt: fdisk context
376 *
377 * See fdisk_disable_dialogs()
378 *
379 * Returns: 1 if dialog driven partitioning enabled (default), or 0.
380 *
381 * Since: 2.31
382 */
383int fdisk_has_dialogs(struct fdisk_context *cxt)
384{
385 return cxt->no_disalogs == 0;
386}
3457d90e 387
6cbb7371
KZ
388/**
389 * fdisk_enable_wipe
390 * @cxt: fdisk context
391 * @enable: 1 or 0
392 *
bd3457b8
KZ
393 * The library removes all PT/filesystem/RAID signatures before it writes
394 * partition table. The probing area where it looks for signatures is from
131e38a2
KZ
395 * the begin of the disk. The device is wiped by libblkid.
396 *
397 * See also fdisk_wipe_partition().
398 *
6cbb7371
KZ
399 * Returns: 0 on success, < 0 on error.
400 */
401int fdisk_enable_wipe(struct fdisk_context *cxt, int enable)
402{
403 if (!cxt)
404 return -EINVAL;
131e38a2 405
bd3457b8 406 fdisk_set_wipe_area(cxt, 0, cxt->total_sectors, enable);
6cbb7371
KZ
407 return 0;
408}
409
410/**
411 * fdisk_has_wipe
412 * @cxt: fdisk context
413 *
414 * Returns the current wipe setting. See fdisk_enable_wipe().
415 *
416 * Returns: 0 on success, < 0 on error.
417 */
418int fdisk_has_wipe(struct fdisk_context *cxt)
419{
131e38a2
KZ
420 if (!cxt)
421 return 0;
422
bd3457b8 423 return fdisk_has_wipe_area(cxt, 0, cxt->total_sectors);
6cbb7371
KZ
424}
425
426
427/**
428 * fdisk_get_collision
429 * @cxt: fdisk context
430 *
431 * Returns: name of the filesystem or RAID detected on the device or NULL.
432 */
433const char *fdisk_get_collision(struct fdisk_context *cxt)
434{
435 return cxt->collision;
436}
437
0cec78a3
KZ
438/**
439 * fdisk_is_ptcollision:
440 * @cxt: fdisk context
441 *
fcf841f8 442 * The collision detected by libblkid (usually another partition table). Note
8d3e3e6b
KZ
443 * that libfdisk does not support all partitions tables, so fdisk_has_label()
444 * may return false, but fdisk_is_ptcollision() may return true.
445 *
446 * Since: 2.30
0cec78a3
KZ
447 *
448 * Returns: 0 or 1
449 */
450int fdisk_is_ptcollision(struct fdisk_context *cxt)
451{
452 return cxt->pt_collision;
453}
454
59c8e95b
KZ
455/**
456 * fdisk_get_npartitions:
457 * @cxt: context
458 *
7190b9b2
KZ
459 * The maximal number of the partitions depends on disklabel and does not
460 * have to describe the real limit of PT.
461 *
462 * For example the limit for MBR without extend partition is 4, with extended
463 * partition it's unlimited (so the function returns the current number of all
464 * partitions in this case).
465 *
466 * And for example for GPT it depends on space allocated on disk for array of
467 * entry records (usually 128).
468 *
469 * It's fine to use fdisk_get_npartitions() in loops, but don't forget that
470 * partition may be unused (see fdisk_is_partition_used()).
471 *
472 * <informalexample>
473 * <programlisting>
474 * struct fdisk_partition *pa = NULL;
475 * size_t i, nmax = fdisk_get_npartitions(cxt);
476 *
477 * for (i = 0; i < nmax; i++) {
478 * if (!fdisk_is_partition_used(cxt, i))
479 * continue;
480 * ... do something ...
481 * }
482 * </programlisting>
483 * </informalexample>
484 *
485 * Note that the recommended way to list partitions is to use
486 * fdisk_get_partitions() and struct fdisk_table than ask disk driver for each
487 * individual partitions.
488 *
59c8e95b
KZ
489 * Returns: maximal number of partitions for the current label.
490 */
491size_t fdisk_get_npartitions(struct fdisk_context *cxt)
492{
493 return cxt && cxt->label ? cxt->label->nparts_max : 0;
494}
495
aa36c2cf
KZ
496/**
497 * fdisk_is_labeltype:
498 * @cxt: fdisk context
1753a234 499 * @id: FDISK_DISKLABEL_*
aa36c2cf 500 *
5175ae87 501 * See also fdisk_is_label() macro in libfdisk.h.
4af064f3 502 *
705854f3 503 * Returns: return 1 if the current label is @id
aa36c2cf 504 */
1753a234 505int fdisk_is_labeltype(struct fdisk_context *cxt, enum fdisk_labeltype id)
aa36c2cf 506{
1753a234 507 assert(cxt);
1753a234 508
b9710f1f 509 return cxt->label && (unsigned)fdisk_label_get_type(cxt->label) == id;
1753a234
KZ
510}
511
512/**
513 * fdisk_get_parent:
514 * @cxt: nested fdisk context
515 *
516 * Returns: pointer to parental context, or NULL
517 */
518struct fdisk_context *fdisk_get_parent(struct fdisk_context *cxt)
519{
520 assert(cxt);
521 return cxt->parent;
aa36c2cf 522}
53b422ab 523
4e0e8253
KZ
524static void reset_context(struct fdisk_context *cxt)
525{
7845ca8d 526 size_t i;
4e0e8253 527
d71bd2f0 528 DBG(CXT, ul_debugobj(cxt, "*** resetting context"));
0559e742
KZ
529
530 /* reset drives' private data */
531 for (i = 0; i < cxt->nlabels; i++)
532 fdisk_deinit_label(cxt->labels[i]);
4e0e8253 533
11eee4c4
KZ
534 if (cxt->parent) {
535 /* the first sector may be independent on parent */
536 if (cxt->parent->firstsector != cxt->firstsector)
537 free(cxt->firstsector);
538 } else {
539 /* we close device only in primary context */
540 if (cxt->dev_fd > -1)
541 close(cxt->dev_fd);
d17c584a 542 free(cxt->firstsector);
11eee4c4 543 }
4e0e8253 544
13633a81 545 free(cxt->dev_path);
7845ca8d 546 cxt->dev_path = NULL;
13633a81 547
745801e4
KZ
548 free(cxt->dev_model);
549 cxt->dev_model = NULL;
550 cxt->dev_model_probed = 0;
551
6cbb7371
KZ
552 free(cxt->collision);
553 cxt->collision = NULL;
554
7526c305
KZ
555 memset(&cxt->dev_st, 0, sizeof(cxt->dev_st));
556
13633a81 557 cxt->dev_fd = -1;
7845ca8d 558 cxt->firstsector = NULL;
7c2cfb18 559 cxt->firstsector_bufsz = 0;
7845ca8d 560
1653f0b0 561 fdisk_zeroize_device_properties(cxt);
11eee4c4 562
9138d6f9 563 fdisk_unref_script(cxt->script);
11eee4c4 564 cxt->script = NULL;
7845ca8d
KZ
565
566 cxt->label = NULL;
131e38a2
KZ
567
568 fdisk_free_wipe_areas(cxt);
4e0e8253
KZ
569}
570
823f0fd1 571/**
6a632136 572 * fdisk_assign_device:
11eee4c4 573 * @cxt: context
537187be 574 * @fname: path to the device to be handled
25b529fe
DB
575 * @readonly: how to open the device
576 *
11eee4c4
KZ
577 * Open the device, discovery topology, geometry, detect disklabel and switch
578 * the current label driver to reflect the probing result.
6a632136 579 *
11eee4c4
KZ
580 * Note that this function resets all generic setting in context. If the @cxt
581 * is nested context then the device is assigned to the parental context and
582 * necessary properties are copied to the @cxt. The change is propagated in
583 * child->parent direction only. It's impossible to use a different device for
584 * primary and nested contexts.
347a7f77 585 *
58c41e15 586 * Returns: 0 on success, < 0 on error.
823f0fd1 587 */
6a632136
KZ
588int fdisk_assign_device(struct fdisk_context *cxt,
589 const char *fname, int readonly)
823f0fd1 590{
2e2cfdae 591 int fd;
823f0fd1 592
d71bd2f0 593 DBG(CXT, ul_debugobj(cxt, "assigning device %s", fname));
4e0e8253
KZ
594 assert(cxt);
595
11eee4c4
KZ
596 /* redirect request to parent */
597 if (cxt->parent) {
598 int rc, org = fdisk_is_listonly(cxt->parent);
599
600 /* assign_device() is sensitive to "listonly" mode, so let's
7526c305 601 * follow the current context setting for the parent to avoid
11eee4c4
KZ
602 * unwanted extra warnings. */
603 fdisk_enable_listonly(cxt->parent, fdisk_is_listonly(cxt));
604
605 rc = fdisk_assign_device(cxt->parent, fname, readonly);
606 fdisk_enable_listonly(cxt->parent, org);
607
13633a81
KZ
608 if (!rc)
609 rc = init_nested_from_parent(cxt, 0);
11eee4c4
KZ
610 if (!rc)
611 fdisk_probe_labels(cxt);
612 return rc;
613 }
614
4e0e8253 615 reset_context(cxt);
95f9f309 616
e146ae4e
KZ
617 fd = open(fname, (readonly ? O_RDONLY : O_RDWR ) | O_CLOEXEC);
618 if (fd < 0)
0a48e237 619 goto fail;
823f0fd1 620
0a48e237
KZ
621 if (fstat(fd, &cxt->dev_st) != 0)
622 goto fail;
7526c305 623
e146ae4e 624 cxt->readonly = readonly;
823f0fd1
DB
625 cxt->dev_fd = fd;
626 cxt->dev_path = strdup(fname);
627 if (!cxt->dev_path)
628 goto fail;
618882d6 629
aa42788d
KZ
630 fdisk_discover_topology(cxt);
631 fdisk_discover_geometry(cxt);
823f0fd1 632
502dd53c
KZ
633 fdisk_apply_user_device_properties(cxt);
634
3eb78aa7
KZ
635 if (fdisk_read_firstsector(cxt) < 0)
636 goto fail;
637
7ce10975 638 fdisk_probe_labels(cxt);
1653f0b0 639
b2140d2f
KZ
640 fdisk_apply_label_device_properties(cxt);
641
6e876a98
KZ
642 /* warn about obsolete stuff on the device if we aren't in
643 * list-only mode and there is not PT yet */
37204dc6
KZ
644 if (!fdisk_is_listonly(cxt) && !fdisk_has_label(cxt)
645 && fdisk_check_collisions(cxt) < 0)
6cbb7371 646 goto fail;
6e876a98 647
d71bd2f0
KZ
648 DBG(CXT, ul_debugobj(cxt, "initialized for %s [%s]",
649 fname, readonly ? "READ-ONLY" : "READ-WRITE"));
4e0e8253 650 return 0;
823f0fd1 651fail:
2e2cfdae
SK
652 {
653 int rc = -errno;
654 if (fd >= 0)
655 close(fd);
656 DBG(CXT, ul_debugobj(cxt, "failed to assign device [rc=%d]", rc));
657 return rc;
658 }
823f0fd1
DB
659}
660
5175ae87
KZ
661/**
662 * fdisk_deassign_device:
663 * @cxt: context
664 * @nosync: disable fsync()
665 *
11eee4c4
KZ
666 * Close device and call fsync(). If the @cxt is nested context than the
667 * request is redirected to the parent.
7190b9b2
KZ
668 *
669 * Returns: 0 on success, < 0 on error.
5175ae87 670 */
6a632136 671int fdisk_deassign_device(struct fdisk_context *cxt, int nosync)
a57639e1
KZ
672{
673 assert(cxt);
674 assert(cxt->dev_fd >= 0);
675
11eee4c4
KZ
676 if (cxt->parent) {
677 int rc = fdisk_deassign_device(cxt->parent, nosync);
678
13633a81
KZ
679 if (!rc)
680 rc = init_nested_from_parent(cxt, 0);
11eee4c4
KZ
681 return rc;
682 }
683
2469ba36
KZ
684 DBG(CXT, ul_debugobj(cxt, "de-assigning device %s", cxt->dev_path));
685
2aeff761 686 if (cxt->readonly)
bc787727 687 close(cxt->dev_fd);
bc787727
KZ
688 else {
689 if (fsync(cxt->dev_fd) || close(cxt->dev_fd)) {
690 fdisk_warn(cxt, _("%s: close device failed"),
691 cxt->dev_path);
692 return -errno;
693 }
a57639e1 694
2aeff761
KZ
695 if (!nosync) {
696 fdisk_info(cxt, _("Syncing disks."));
697 sync();
698 }
bc787727 699 }
152788aa
KZ
700
701 free(cxt->dev_path);
13633a81 702 cxt->dev_path = NULL;
152788aa 703
a57639e1 704 cxt->dev_fd = -1;
152788aa 705
a57639e1
KZ
706 return 0;
707}
708
2469ba36
KZ
709/**
710 * fdisk_reassign_device:
711 * @cxt: context
712 *
713 * This function is "hard reset" of the context and it does not write anything
714 * to the device. All in-memory changes associated with the context will be
715 * lost. It's recommended to use this function after some fatal problem when the
716 * context (and label specific driver) is in an undefined state.
717 *
718 * Returns: 0 on success, < 0 on error.
719 */
720int fdisk_reassign_device(struct fdisk_context *cxt)
721{
722 char *devname;
723 int rdonly, rc;
724
725 assert(cxt);
726 assert(cxt->dev_fd >= 0);
727
728 DBG(CXT, ul_debugobj(cxt, "re-assigning device %s", cxt->dev_path));
729
730 devname = strdup(cxt->dev_path);
731 if (!devname)
732 return -ENOMEM;
733
734 rdonly = cxt->readonly;
735
736 fdisk_deassign_device(cxt, 1);
737 rc = fdisk_assign_device(cxt, devname, rdonly);
738 free(devname);
739
740 return rc;
741}
742
6a1889b0
KZ
743/**
744 * fdisk_reread_partition_table:
745 * @cxt: context
746 *
747 * Force *kernel* to re-read partition table on block devices.
748 *
749 * Returns: 0 on success, < 0 in case of error.
750 */
751int fdisk_reread_partition_table(struct fdisk_context *cxt)
752{
2db3cc4c 753 int i = 0;
6a1889b0
KZ
754
755 assert(cxt);
756 assert(cxt->dev_fd >= 0);
757
2db3cc4c
KZ
758 if (!S_ISBLK(cxt->dev_st.st_mode))
759 return 0;
760 else {
6a1889b0
KZ
761 DBG(CXT, ul_debugobj(cxt, "calling re-read ioctl"));
762 sync();
763#ifdef BLKRRPART
764 fdisk_info(cxt, _("Calling ioctl() to re-read partition table."));
765 i = ioctl(cxt->dev_fd, BLKRRPART);
766#else
767 errno = ENOSYS;
768 i = 1;
769#endif
770 }
771
772 if (i) {
773 fdisk_warn(cxt, _("Re-reading the partition table failed."));
774 fdisk_info(cxt, _(
775 "The kernel still uses the old table. The "
776 "new table will be used at the next reboot "
777 "or after you run partprobe(8) or kpartx(8)."));
778 return -errno;
779 }
780
781 return 0;
782}
783
18751601 784#ifdef __linux__
1dd63a3b
KZ
785static inline int add_to_partitions_array(
786 struct fdisk_partition ***ary,
787 struct fdisk_partition *pa,
788 size_t *n, size_t nmax)
789{
790 if (!*ary) {
791 *ary = calloc(nmax, sizeof(struct fdisk_partition *));
792 if (!*ary)
793 return -ENOMEM;
794 }
795 (*ary)[*n] = pa;
796 (*n)++;
797 return 0;
798}
18751601 799#endif
1dd63a3b
KZ
800
801/**
802 * fdisk_reread_changes:
803 * @cxt: context
804 * @org: original layout (on disk)
805 *
806 * Like fdisk_reread_partition_table() but don't forces kernel re-read all
807 * partition table. The BLKPG_* ioctls are used for individual partitions. The
808 * advantage is that unmodified partitions maybe mounted.
809 *
5ecd6185 810 * The function behavies like fdisk_reread_partition_table() on systems where
73afd3f8 811 * are no available BLKPG_* ioctls.
5ecd6185 812 *
1dd63a3b
KZ
813 * Returns: <0 on error, or 0.
814 */
5ecd6185 815#ifdef __linux__
1dd63a3b
KZ
816int fdisk_reread_changes(struct fdisk_context *cxt, struct fdisk_table *org)
817{
818 struct fdisk_table *tb = NULL;
819 struct fdisk_iter itr;
820 struct fdisk_partition *pa;
821 struct fdisk_partition **rem = NULL, **add = NULL, **upd = NULL;
822 int change, rc = 0, err = 0;
823 size_t nparts, i, nadds = 0, nupds = 0, nrems = 0;
824
825 DBG(CXT, ul_debugobj(cxt, "rereading changes"));
826
827 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
828
829 /* the current layout */
830 fdisk_get_partitions(cxt, &tb);
831 /* maximal number of partitions */
832 nparts = max(fdisk_table_get_nents(tb), fdisk_table_get_nents(org));
833
834 while (fdisk_diff_tables(org, tb, &itr, &pa, &change) == 0) {
835 if (change == FDISK_DIFF_UNCHANGED)
836 continue;
837 switch (change) {
838 case FDISK_DIFF_REMOVED:
839 rc = add_to_partitions_array(&rem, pa, &nrems, nparts);
840 break;
841 case FDISK_DIFF_ADDED:
842 rc = add_to_partitions_array(&add, pa, &nadds, nparts);
843 break;
844 case FDISK_DIFF_RESIZED:
845 rc = add_to_partitions_array(&upd, pa, &nupds, nparts);
846 break;
847 case FDISK_DIFF_MOVED:
848 rc = add_to_partitions_array(&rem, pa, &nrems, nparts);
7f3a9822
KZ
849 if (!rc)
850 rc = add_to_partitions_array(&add, pa, &nadds, nparts);
1dd63a3b
KZ
851 break;
852 }
853 if (rc != 0)
854 goto done;
855 }
856
857 for (i = 0; i < nrems; i++) {
858 pa = rem[i];
859 DBG(PART, ul_debugobj(pa, "#%zu calling BLKPG_DEL_PARTITION", pa->partno));
860 if (partx_del_partition(cxt->dev_fd, pa->partno + 1) != 0) {
c0eabc53 861 fdisk_warn(cxt, _("Failed to remove partition %zu from system"), pa->partno + 1);
1dd63a3b
KZ
862 err++;
863 }
864 }
865 for (i = 0; i < nupds; i++) {
866 pa = upd[i];
867 DBG(PART, ul_debugobj(pa, "#%zu calling BLKPG_RESIZE_PARTITION", pa->partno));
868 if (partx_resize_partition(cxt->dev_fd, pa->partno + 1, pa->start, pa->size) != 0) {
c0eabc53 869 fdisk_warn(cxt, _("Failed to update system information about partition %zu"), pa->partno + 1);
1dd63a3b
KZ
870 err++;
871 }
872 }
873 for (i = 0; i < nadds; i++) {
874 pa = add[i];
875 DBG(PART, ul_debugobj(pa, "#%zu calling BLKPG_ADD_PARTITION", pa->partno));
876 if (partx_add_partition(cxt->dev_fd, pa->partno + 1, pa->start, pa->size) != 0) {
c0eabc53 877 fdisk_warn(cxt, _("Failed to add partition %zu to system"), pa->partno + 1);
1dd63a3b
KZ
878 err++;
879 }
880 }
881 if (err)
882 fdisk_info(cxt, _(
883 "The kernel still uses the old partitions. The new "
884 "table will be used at the next reboot. "));
885done:
886 free(rem);
887 free(add);
888 free(upd);
889 fdisk_unref_table(tb);
890 return rc;
891}
5ecd6185
KZ
892#else
893int fdisk_reread_changes(struct fdisk_context *cxt,
894 struct fdisk_table *org __attribute__((__unused__))) {
895 return fdisk_reread_partition_table(cxt);
896}
897#endif
2db3cc4c 898
b9da1532
KZ
899/**
900 * fdisk_device_is_used:
901 * @cxt: context
902 *
903 * On systems where is no BLKRRPART ioctl the function returns zero and
904 * sets errno to ENOSYS.
905 *
906 * Returns: 1 if the device assigned to the context is used by system, or 0.
907 */
908int fdisk_device_is_used(struct fdisk_context *cxt)
909{
910 int rc = 0;
911
912 assert(cxt);
913 assert(cxt->dev_fd >= 0);
914
915 errno = 0;
916
917#ifdef BLKRRPART
918 /* it seems kernel always return EINVAL for BLKRRPART on loopdevices */
919 if (S_ISBLK(cxt->dev_st.st_mode)
920 && major(cxt->dev_st.st_rdev) != LOOPDEV_MAJOR) {
921 DBG(CXT, ul_debugobj(cxt, "calling re-read ioctl"));
922 rc = ioctl(cxt->dev_fd, BLKRRPART) != 0;
923 }
924#else
925 errno = ENOSYS;
926#endif
927 DBG(CXT, ul_debugobj(cxt, "device used: %s [errno=%d]", rc ? "TRUE" : "FALSE", errno));
928 return rc;
929}
930
5175ae87
KZ
931/**
932 * fdisk_is_readonly:
933 * @cxt: context
934 *
935 * Returns: 1 if device open readonly
936 */
6a632136 937int fdisk_is_readonly(struct fdisk_context *cxt)
e146ae4e
KZ
938{
939 assert(cxt);
940 return cxt->readonly;
941}
942
7526c305
KZ
943/**
944 * fdisk_is_regfile:
945 * @cxt: context
946 *
8d3e3e6b
KZ
947 * Since: 2.30
948 *
7526c305
KZ
949 * Returns: 1 if open file descriptor is regular file rather than a block device.
950 */
951int fdisk_is_regfile(struct fdisk_context *cxt)
952{
953 assert(cxt);
954 return S_ISREG(cxt->dev_st.st_mode);
955}
956
823f0fd1 957/**
c7119037 958 * fdisk_unref_context:
823f0fd1
DB
959 * @cxt: fdisk context
960 *
961 * Deallocates context struct.
962 */
c7119037 963void fdisk_unref_context(struct fdisk_context *cxt)
823f0fd1 964{
b9710f1f 965 unsigned i;
0c5d095e 966
823f0fd1
DB
967 if (!cxt)
968 return;
969
c7119037
KZ
970 cxt->refcount--;
971 if (cxt->refcount <= 0) {
972 DBG(CXT, ul_debugobj(cxt, "freeing context %p for %s", cxt, cxt->dev_path));
11eee4c4
KZ
973
974 reset_context(cxt); /* this is sensitive to parent<->child relationship! */
c7119037
KZ
975
976 /* deallocate label's private stuff */
977 for (i = 0; i < cxt->nlabels; i++) {
978 if (!cxt->labels[i])
979 continue;
980 if (cxt->labels[i]->op->free)
981 cxt->labels[i]->op->free(cxt->labels[i]);
982 else
983 free(cxt->labels[i]);
984 }
11eee4c4
KZ
985
986 fdisk_unref_context(cxt->parent);
987 cxt->parent = NULL;
988
c7119037 989 free(cxt);
0c5d095e 990 }
823f0fd1 991}
7845ca8d 992
cb7ce873 993
a5c1b0fa 994/**
6a632136
KZ
995 * fdisk_enable_details:
996 * @cxt: context
9e930041 997 * @enable: true/false
a5c1b0fa 998 *
6a632136
KZ
999 * Enables or disables "details" display mode. This function has effect to
1000 * fdisk_partition_to_string() function.
a5c1b0fa
KZ
1001 *
1002 * Returns: 0 on success, < 0 on error.
1003 */
6a632136 1004int fdisk_enable_details(struct fdisk_context *cxt, int enable)
a5c1b0fa
KZ
1005{
1006 assert(cxt);
1007 cxt->display_details = enable ? 1 : 0;
1008 return 0;
1009}
1010
6a632136
KZ
1011/**
1012 * fdisk_is_details:
1013 * @cxt: context
1014 *
1015 * Returns: 1 if details are enabled
1016 */
1017int fdisk_is_details(struct fdisk_context *cxt)
a5c1b0fa
KZ
1018{
1019 assert(cxt);
1020 return cxt->display_details == 1;
1021}
cb7ce873 1022
c10937dc 1023/**
6a632136
KZ
1024 * fdisk_enable_listonly:
1025 * @cxt: context
9e930041 1026 * @enable: true/false
c10937dc
KZ
1027 *
1028 * Just list partition only, don't care about another details, mistakes, ...
1029 *
1030 * Returns: 0 on success, < 0 on error.
1031 */
6a632136 1032int fdisk_enable_listonly(struct fdisk_context *cxt, int enable)
c10937dc
KZ
1033{
1034 assert(cxt);
1035 cxt->listonly = enable ? 1 : 0;
1036 return 0;
1037}
1038
6a632136
KZ
1039/**
1040 * fdisk_is_listonly:
1041 * @cxt: context
1042 *
1043 * Returns: 1 if list-only mode enabled
1044 */
1045int fdisk_is_listonly(struct fdisk_context *cxt)
c10937dc
KZ
1046{
1047 assert(cxt);
1048 return cxt->listonly == 1;
1049}
1050
1051
6a632136
KZ
1052/**
1053 * fdisk_set_unit:
1054 * @cxt: context
cb7ce873
KZ
1055 * @str: "cylinder" or "sector".
1056 *
1057 * This is pure shit, unfortunately for example Sun addresses begin of the
1058 * partition by cylinders...
6a632136 1059 *
9e930041 1060 * Returns: 0 on success, <0 on error.
cb7ce873 1061 */
6a632136 1062int fdisk_set_unit(struct fdisk_context *cxt, const char *str)
cb7ce873
KZ
1063{
1064 assert(cxt);
1065
1066 cxt->display_in_cyl_units = 0;
1067
1068 if (!str)
1069 return 0;
1070
1071 if (strcmp(str, "cylinder") == 0 || strcmp(str, "cylinders") == 0)
1072 cxt->display_in_cyl_units = 1;
1073
1074 else if (strcmp(str, "sector") == 0 || strcmp(str, "sectors") == 0)
1075 cxt->display_in_cyl_units = 0;
1076
6a632136 1077 DBG(CXT, ul_debugobj(cxt, "display unit: %s", fdisk_get_unit(cxt, 0)));
cb7ce873
KZ
1078 return 0;
1079}
1080
6a632136
KZ
1081/**
1082 * fdisk_get_unit:
1083 * @cxt: context
705854f3 1084 * @n: FDISK_PLURAL or FDISK_SINGULAR
6a632136
KZ
1085 *
1086 * Returns: unit name.
1087 */
1088const char *fdisk_get_unit(struct fdisk_context *cxt, int n)
cb7ce873
KZ
1089{
1090 assert(cxt);
1091
6a632136 1092 if (fdisk_use_cylinders(cxt))
cb7ce873
KZ
1093 return P_("cylinder", "cylinders", n);
1094 return P_("sector", "sectors", n);
1095}
1096
6a632136
KZ
1097/**
1098 * fdisk_use_cylinders:
705854f3 1099 * @cxt: context
6a632136 1100 *
705854f3 1101 * Returns: 1 if user wants to display in cylinders.
6a632136
KZ
1102 */
1103int fdisk_use_cylinders(struct fdisk_context *cxt)
cb7ce873
KZ
1104{
1105 assert(cxt);
1106 return cxt->display_in_cyl_units == 1;
1107}
1108
6a632136
KZ
1109/**
1110 * fdisk_get_units_per_sector:
1111 * @cxt: context
1112 *
1bcf491a 1113 * This is necessary only for brain dead situations when we use "cylinders";
6a632136
KZ
1114 *
1115 * Returns: number of "units" per sector, default is 1 if display unit is sector.
cb7ce873 1116 */
6a632136 1117unsigned int fdisk_get_units_per_sector(struct fdisk_context *cxt)
cb7ce873
KZ
1118{
1119 assert(cxt);
1120
6a632136 1121 if (fdisk_use_cylinders(cxt)) {
cb7ce873
KZ
1122 assert(cxt->geom.heads);
1123 return cxt->geom.heads * cxt->geom.sectors;
1124 }
1125 return 1;
1126}
6a632136
KZ
1127
1128/**
1129 * fdisk_get_optimal_iosize:
1130 * @cxt: context
1131 *
6b11aad2
KZ
1132 * The optimal I/O is optional and does not have to be provided by device,
1133 * anyway libfdisk never returns zero. If the optimal I/O size is not provided
1134 * then libfdisk returns minimal I/O size or sector size.
1135 *
7190b9b2 1136 * Returns: optimal I/O size in bytes.
6a632136
KZ
1137 */
1138unsigned long fdisk_get_optimal_iosize(struct fdisk_context *cxt)
1139{
1140 assert(cxt);
6b11aad2 1141 return cxt->optimal_io_size ? cxt->optimal_io_size : cxt->io_size;
6a632136
KZ
1142}
1143
1144/**
1145 * fdisk_get_minimal_iosize:
1146 * @cxt: context
1147 *
7190b9b2 1148 * Returns: minimal I/O size in bytes
6a632136 1149 */
1753a234 1150unsigned long fdisk_get_minimal_iosize(struct fdisk_context *cxt)
6a632136
KZ
1151{
1152 assert(cxt);
1153 return cxt->min_io_size;
1154}
1155
1156/**
1157 * fdisk_get_physector_size:
1158 * @cxt: context
1159 *
7190b9b2 1160 * Returns: physical sector size in bytes
6a632136
KZ
1161 */
1162unsigned long fdisk_get_physector_size(struct fdisk_context *cxt)
1163{
1164 assert(cxt);
1165 return cxt->phy_sector_size;
1166}
1167
1168/**
1169 * fdisk_get_sector_size:
1170 * @cxt: context
1171 *
7190b9b2 1172 * Returns: logical sector size in bytes
6a632136
KZ
1173 */
1174unsigned long fdisk_get_sector_size(struct fdisk_context *cxt)
1175{
1176 assert(cxt);
1177 return cxt->sector_size;
1178}
1179
1180/**
1181 * fdisk_get_alignment_offset
1182 * @cxt: context
1183 *
7190b9b2
KZ
1184 * The alignment offset is offset between logical and physical sectors. For
1185 * backward compatibility the first logical sector on 4K disks does no have to
1186 * start on the same place like physical sectors.
1187 *
1188 * Returns: alignment offset in bytes
6a632136
KZ
1189 */
1190unsigned long fdisk_get_alignment_offset(struct fdisk_context *cxt)
1191{
1192 assert(cxt);
1193 return cxt->alignment_offset;
1194}
1195
1196/**
1197 * fdisk_get_grain_size:
1198 * @cxt: context
1199 *
7190b9b2 1200 * Returns: grain in bytes used to align partitions (usually 1MiB)
6a632136
KZ
1201 */
1202unsigned long fdisk_get_grain_size(struct fdisk_context *cxt)
1203{
1204 assert(cxt);
1205 return cxt->grain;
1206}
1207
1208/**
1209 * fdisk_get_first_lba:
1210 * @cxt: context
1211 *
1212 * Returns: first possible LBA on disk for data partitions.
1213 */
0073a4cf 1214fdisk_sector_t fdisk_get_first_lba(struct fdisk_context *cxt)
6a632136
KZ
1215{
1216 assert(cxt);
1217 return cxt->first_lba;
1218}
1219
6d37c2ce
KZ
1220/**
1221 * fdisk_set_first_lba:
1222 * @cxt: fdisk context
7190b9b2 1223 * @lba: first possible logical sector for data
6d37c2ce
KZ
1224 *
1225 * It's strongly recommended to use the default library setting. The first LBA
9e930041 1226 * is always reset by fdisk_assign_device(), fdisk_override_geometry()
6d37c2ce
KZ
1227 * and fdisk_reset_alignment(). This is very low level function and library
1228 * does not check if your setting makes any sense.
1229 *
7190b9b2
KZ
1230 * This function is necessary only when you want to work with very unusual
1231 * partition tables like GPT protective MBR or hybrid partition tables on
1232 * bootable media where the first partition may start on very crazy offsets.
1233 *
8a74df7f
KZ
1234 * Note that this function changes only runtime information. It does not update
1235 * any range in on-disk partition table. For example GPT Header contains First
1236 * and Last usable LBA fields. These fields are not updated by this function.
1237 * Be careful.
1238 *
6d37c2ce
KZ
1239 * Returns: 0 on success, <0 on error.
1240 */
0073a4cf 1241fdisk_sector_t fdisk_set_first_lba(struct fdisk_context *cxt, fdisk_sector_t lba)
6d37c2ce
KZ
1242{
1243 assert(cxt);
1244 DBG(CXT, ul_debugobj(cxt, "setting first LBA from %ju to %ju",
1245 (uintmax_t) cxt->first_lba, (uintmax_t) lba));
1246 cxt->first_lba = lba;
1247 return 0;
1248}
1249
1250/**
1251 * fdisk_get_last_lba:
1252 * @cxt: fdisk context
1253 *
1254 * Note that the device has to be already assigned.
1255 *
1256 * Returns: last possible LBA on device
1257 */
0073a4cf 1258fdisk_sector_t fdisk_get_last_lba(struct fdisk_context *cxt)
6d37c2ce
KZ
1259{
1260 return cxt->last_lba;
1261}
1262
1263/**
1264 * fdisk_set_last_lba:
1265 * @cxt: fdisk context
7190b9b2 1266 * @lba: last possible logical sector
6d37c2ce
KZ
1267 *
1268 * It's strongly recommended to use the default library setting. The last LBA
9e930041 1269 * is always reset by fdisk_assign_device(), fdisk_override_geometry() and
6d37c2ce
KZ
1270 * fdisk_reset_alignment().
1271 *
7190b9b2 1272 * The default is number of sectors on the device, but maybe modified by the
dee59a1e 1273 * current disklabel driver (for example GPT uses the end of disk for backup
7190b9b2
KZ
1274 * header, so last_lba is smaller than total number of sectors).
1275 *
6d37c2ce
KZ
1276 * Returns: 0 on success, <0 on error.
1277 */
0073a4cf 1278fdisk_sector_t fdisk_set_last_lba(struct fdisk_context *cxt, fdisk_sector_t lba)
6d37c2ce
KZ
1279{
1280 assert(cxt);
1281
083c35b9 1282 if (lba > cxt->total_sectors - 1 || lba < 1)
6d37c2ce
KZ
1283 return -ERANGE;
1284 cxt->last_lba = lba;
1285 return 0;
1286}
1287
354f8cc8
KZ
1288/**
1289 * fdisk_set_size_unit:
1290 * @cxt: fdisk context
1291 * @unit: FDISK_SIZEUNIT_*
1292 *
1293 * Sets unit for SIZE output field (see fdisk_partition_to_string()).
1294 *
1295 * Returns: 0 on success, <0 on error.
1296 */
1297int fdisk_set_size_unit(struct fdisk_context *cxt, int unit)
1298{
1299 assert(cxt);
1300 cxt->sizeunit = unit;
1301 return 0;
1302}
1303
1304/**
1305 * fdisk_get_size_unit:
1306 * @cxt: fdisk context
1307 *
1308 * Gets unit for SIZE output field (see fdisk_partition_to_string()).
1309 *
1310 * Returns: unit
1311 */
f3aca7ab 1312int fdisk_get_size_unit(struct fdisk_context *cxt)
354f8cc8
KZ
1313{
1314 assert(cxt);
1315 return cxt->sizeunit;
1316}
6d37c2ce 1317
6a632136
KZ
1318/**
1319 * fdisk_get_nsectors:
1320 * @cxt: context
1321 *
7190b9b2 1322 * Returns: size of the device in logical sectors.
6a632136 1323 */
0073a4cf 1324fdisk_sector_t fdisk_get_nsectors(struct fdisk_context *cxt)
6a632136
KZ
1325{
1326 assert(cxt);
1327 return cxt->total_sectors;
1328}
1329
1330/**
1331 * fdisk_get_devname:
1332 * @cxt: context
1333 *
1334 * Returns: device name.
1335 */
1336const char *fdisk_get_devname(struct fdisk_context *cxt)
1337{
1338 assert(cxt);
1339 return cxt->dev_path;
1340}
aa36c2cf 1341
745801e4
KZ
1342/**
1343 * fdisk_get_devno:
1344 * @cxt: context
1345 *
1346 * Returns: device number or zero for non-block devices
cbfd67cf
KZ
1347 *
1348 * Since: 2.33
745801e4
KZ
1349 */
1350dev_t fdisk_get_devno(struct fdisk_context *cxt)
1351{
1352 assert(cxt);
1353 return S_ISBLK(cxt->dev_st.st_mode) ? cxt->dev_st.st_rdev : 0;
1354}
1355
1356/**
1357 * fdisk_get_devmodel:
1358 * @cxt: context
1359 *
1360 * Returns: device model string or NULL.
cbfd67cf
KZ
1361 *
1362 * Since: 2.33
745801e4 1363 */
e5e3a87c 1364#ifdef __linux__
745801e4
KZ
1365const char *fdisk_get_devmodel(struct fdisk_context *cxt)
1366{
745801e4
KZ
1367 assert(cxt);
1368
1369 if (cxt->dev_model_probed)
1370 return cxt->dev_model;
1371
1372 if (fdisk_get_devno(cxt)) {
1373 struct path_cxt *pc = ul_new_sysfs_path(fdisk_get_devno(cxt), NULL, NULL);
1374
1375 if (pc) {
1376 ul_path_read_string(pc, &cxt->dev_model, "device/model");
1377 ul_unref_path(pc);
1378 }
1379 }
1380 cxt->dev_model_probed = 1;
1381 return cxt->dev_model;
e5e3a87c 1382}
745801e4 1383#else
e5e3a87c
RM
1384const char *fdisk_get_devmodel(struct fdisk_context *cxt __attribute__((__unused__)))
1385{
745801e4 1386 return NULL;
745801e4 1387}
e5e3a87c 1388#endif
745801e4 1389
1753a234
KZ
1390/**
1391 * fdisk_get_devfd:
1392 * @cxt: context
1393 *
9e930041 1394 * Returns: device file descriptor.
1753a234
KZ
1395 */
1396int fdisk_get_devfd(struct fdisk_context *cxt)
1397{
1398 assert(cxt);
1399 return cxt->dev_fd;
1400}
1401
1402/**
1403 * fdisk_get_geom_heads:
1404 * @cxt: context
1405 *
1406 * Returns: number of geometry heads.
1407 */
1408unsigned int fdisk_get_geom_heads(struct fdisk_context *cxt)
1409{
1410 assert(cxt);
1411 return cxt->geom.heads;
1412}
1413/**
1414 * fdisk_get_geom_sectors:
1415 * @cxt: context
1416 *
1417 * Returns: number of geometry sectors.
1418 */
0073a4cf 1419fdisk_sector_t fdisk_get_geom_sectors(struct fdisk_context *cxt)
1753a234
KZ
1420{
1421 assert(cxt);
1422 return cxt->geom.sectors;
1423
1424}
1425
1426/**
1427 * fdisk_get_geom_cylinders:
1428 * @cxt: context
1429 *
1430 * Returns: number of geometry cylinders
1431 */
0073a4cf 1432fdisk_sector_t fdisk_get_geom_cylinders(struct fdisk_context *cxt)
1753a234
KZ
1433{
1434 assert(cxt);
1435 return cxt->geom.cylinders;
1436}
aa36c2cf 1437
72d2965c
KZ
1438int fdisk_missing_geometry(struct fdisk_context *cxt)
1439{
1440 int rc;
1441
72d2965c
KZ
1442 if (!cxt || !cxt->label)
1443 return 0;
1444
1445 rc = (fdisk_label_require_geometry(cxt->label) &&
1446 (!cxt->geom.heads || !cxt->geom.sectors
1447 || !cxt->geom.cylinders));
1448
1449 if (rc && !fdisk_is_listonly(cxt))
1450 fdisk_warnx(cxt, _("Incomplete geometry setting."));
1451
1452 return rc;
1453}
aa36c2cf 1454