]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libfdisk/src/context.c
libfdisk: check for collisions when create new label
[thirdparty/util-linux.git] / libfdisk / src / context.c
CommitLineData
6e876a98
KZ
1#ifdef HAVE_LIBBLKID
2# include <blkid.h>
3#endif
823f0fd1 4
f4be9e2b 5#include "fdiskP.h"
f7b1f75e 6
5175ae87
KZ
7
8/**
9 * SECTION: context
705854f3
KZ
10 * @title: Context
11 * @short_description: stores info about device, labels etc.
5175ae87 12 *
7190b9b2 13 * The library distinguish between three types of partitioning objects.
5175ae87
KZ
14 *
15 * on-disk data
7190b9b2
KZ
16 * - disk label specific
17 * - probed and read by disklabel drivers when assign device to the context
18 * or when switch to another disk label type
19 * - only fdisk_write_disklabel() modify on-disk data
5175ae87
KZ
20 *
21 * in-memory data
7190b9b2
KZ
22 * - generic data and disklabel specific data stored in struct fdisk_label
23 * - all partitioning operations are based on in-memory data only
5175ae87
KZ
24 *
25 * struct fdisk_partition
7190b9b2
KZ
26 * - provides abstraction to present partitions to users
27 * - fdisk_partition is possible to gather to fdisk_table container
28 * - used as unified template for new partitions
29 * - the struct fdisk_partition is always completely independent object and
30 * any change to the object has no effect to in-memory (or on-disk) label data
5175ae87
KZ
31 */
32
6a632136
KZ
33/**
34 * fdisk_new_context:
35 *
36 * Returns: newly allocated libfdisk handler
37 */
4e0e8253 38struct fdisk_context *fdisk_new_context(void)
0c5d095e
KZ
39{
40 struct fdisk_context *cxt;
0c5d095e
KZ
41
42 cxt = calloc(1, sizeof(*cxt));
43 if (!cxt)
44 return NULL;
45
d71bd2f0 46 DBG(CXT, ul_debugobj(cxt, "alloc"));
4e0e8253 47 cxt->dev_fd = -1;
c7119037 48 cxt->refcount = 1;
4e0e8253 49
131e38a2
KZ
50 INIT_LIST_HEAD(&cxt->wipes);
51
0c5d095e
KZ
52 /*
53 * Allocate label specific structs.
54 *
55 * This is necessary (for example) to store label specific
56 * context setting.
57 */
58 cxt->labels[ cxt->nlabels++ ] = fdisk_new_gpt_label(cxt);
59 cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt);
b4fb2a61 60 cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt);
0c5d095e
KZ
61 cxt->labels[ cxt->nlabels++ ] = fdisk_new_sgi_label(cxt);
62 cxt->labels[ cxt->nlabels++ ] = fdisk_new_sun_label(cxt);
63
0c5d095e
KZ
64 return cxt;
65}
66
13633a81 67static int init_nested_from_parent(struct fdisk_context *cxt, int isnew)
11eee4c4
KZ
68{
69 struct fdisk_context *parent;
70
71 assert(cxt);
72 assert(cxt->parent);
73
74 parent = cxt->parent;
75
11eee4c4
KZ
76 cxt->alignment_offset = parent->alignment_offset;
77 cxt->ask_cb = parent->ask_cb;
78 cxt->ask_data = parent->ask_data;
79 cxt->dev_fd = parent->dev_fd;
80 cxt->first_lba = parent->first_lba;
81 cxt->firstsector_bufsz = parent->firstsector_bufsz;
82 cxt->firstsector = parent->firstsector;
83 cxt->geom = parent->geom;
84 cxt->grain = parent->grain;
85 cxt->io_size = parent->io_size;
86 cxt->last_lba = parent->last_lba;
87 cxt->min_io_size = parent->min_io_size;
88 cxt->optimal_io_size = parent->optimal_io_size;
89 cxt->phy_sector_size = parent->phy_sector_size;
90 cxt->readonly = parent->readonly;
91 cxt->script = parent->script;
92 fdisk_ref_script(cxt->script);
93 cxt->sector_size = parent->sector_size;
94 cxt->total_sectors = parent->total_sectors;
95 cxt->user_geom = parent->user_geom;
96 cxt->user_log_sector = parent->user_log_sector;
97 cxt->user_pyh_sector = parent->user_pyh_sector;
98
3457d90e 99 /* parent <--> nested independent setting, initialize for new nested
11eee4c4
KZ
100 * contexts only */
101 if (isnew) {
102 cxt->listonly = parent->listonly;
103 cxt->display_details = parent->display_details;
104 cxt->display_in_cyl_units = parent->display_in_cyl_units;
3457d90e 105 cxt->protect_bootbits = parent->protect_bootbits;
11eee4c4
KZ
106 }
107
13633a81
KZ
108 free(cxt->dev_path);
109 cxt->dev_path = NULL;
110
111 if (parent->dev_path) {
112 cxt->dev_path = strdup(parent->dev_path);
113 if (!cxt->dev_path)
114 return -ENOMEM;
115 }
116
131e38a2
KZ
117 INIT_LIST_HEAD(&cxt->wipes);
118
13633a81 119 return 0;
11eee4c4
KZ
120}
121
6a632136
KZ
122/**
123 * fdisk_new_nested_context:
124 * @parent: parental context
125 * @name: optional label name (e.g. "bsd")
126 *
11eee4c4
KZ
127 * Create a new nested fdisk context for nested disk labels (e.g. BSD or PMBR).
128 * The function also probes for the nested label on the device if device is
129 * already assigned to parent.
130 *
131 * The new context is initialized according to @parent and both context shares
132 * some settings and file descriptor to the device. The child propagate some
133 * changes (like fdisk_assign_device()) to parent, but it does not work
134 * vice-versa. The behavior is undefined if you assign another device to
135 * parent.
6a632136 136 *
11eee4c4 137 * Returns: new context for nested partition table.
6a632136 138 */
01b20713
KZ
139struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent,
140 const char *name)
141{
142 struct fdisk_context *cxt;
8a9256f9 143 struct fdisk_label *lb = NULL;
01b20713
KZ
144
145 assert(parent);
01b20713
KZ
146
147 cxt = calloc(1, sizeof(*cxt));
148 if (!cxt)
149 return NULL;
150
4a79a8f1 151 DBG(CXT, ul_debugobj(parent, "alloc nested [%p] [name=%s]", cxt, name));
c7119037 152 cxt->refcount = 1;
01b20713 153
11eee4c4
KZ
154 fdisk_ref_context(parent);
155 cxt->parent = parent;
b720e0d7 156
9c321dfb
KZ
157 if (init_nested_from_parent(cxt, 1) != 0) {
158 cxt->parent = NULL;
159 fdisk_unref_context(cxt);
13633a81 160 return NULL;
9c321dfb 161 }
01b20713 162
d17c584a 163 if (name) {
4a79a8f1 164 if (strcasecmp(name, "bsd") == 0)
d17c584a 165 lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt);
4a79a8f1 166 else if (strcasecmp(name, "dos") == 0 || strcasecmp(name, "mbr") == 0)
d17c584a
KZ
167 lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt);
168 }
8a9256f9 169
11eee4c4 170 if (lb && parent->dev_fd >= 0) {
d71bd2f0 171 DBG(CXT, ul_debugobj(cxt, "probing for nested %s", lb->name));
8a9256f9
KZ
172
173 cxt->label = lb;
174
175 if (lb->op->probe(cxt) == 1)
6a632136 176 __fdisk_switch_label(cxt, lb);
8a9256f9 177 else {
d71bd2f0 178 DBG(CXT, ul_debugobj(cxt, "not found %s label", lb->name));
8a9256f9
KZ
179 if (lb->op->deinit)
180 lb->op->deinit(lb);
181 cxt->label = NULL;
182 }
183 }
01b20713
KZ
184
185 return cxt;
186}
187
188
62a9ef3e
KZ
189/**
190 * fdisk_ref_context:
191 * @cxt: context pointer
192 *
7190b9b2 193 * Increments reference counter.
62a9ef3e
KZ
194 */
195void fdisk_ref_context(struct fdisk_context *cxt)
196{
197 if (cxt)
198 cxt->refcount++;
199}
200
6a632136
KZ
201/**
202 * fdisk_get_label:
203 * @cxt: context instance
204 * @name: label name (e.g. "gpt")
205 *
206 * If no @name specified then returns the current context label.
207 *
3c5ee57c 208 * The label is allocated and maintained within the context #cxt. There is
9e930041 209 * nothing like reference counting for labels, you cannot deallocate the
3c5ee57c
KZ
210 * label.
211 *
6a632136 212 * Returns: label struct or NULL in case of error.
852ce62b 213 */
6a632136 214struct fdisk_label *fdisk_get_label(struct fdisk_context *cxt, const char *name)
0c5d095e
KZ
215{
216 size_t i;
217
218 assert(cxt);
219
852ce62b
KZ
220 if (!name)
221 return cxt->label;
4a79a8f1
KZ
222 else if (strcasecmp(name, "mbr") == 0)
223 name = "dos";
852ce62b 224
0c5d095e 225 for (i = 0; i < cxt->nlabels; i++)
7ab242ec 226 if (cxt->labels[i]
4a79a8f1 227 && strcasecmp(cxt->labels[i]->name, name) == 0)
0c5d095e
KZ
228 return cxt->labels[i];
229
d71bd2f0 230 DBG(CXT, ul_debugobj(cxt, "failed to found %s label driver", name));
0c5d095e
KZ
231 return NULL;
232}
233
6a632136
KZ
234/**
235 * fdisk_next_label:
236 * @cxt: context instance
237 * @lb: returns pointer to the next label
238 *
239 * <informalexample>
240 * <programlisting>
241 * // print all supported labels
242 * struct fdisk_context *cxt = fdisk_new_context();
243 * struct fdisk_label *lb = NULL;
244 *
245 * while (fdisk_next_label(cxt, &lb) == 0)
246 * print("label name: %s\n", fdisk_label_get_name(lb));
c7119037 247 * fdisk_unref_context(cxt);
6a632136
KZ
248 * </programlisting>
249 * </informalexample>
250 *
251 * Returns: <0 in case of error, 0 on success, 1 at the end.
252 */
253int fdisk_next_label(struct fdisk_context *cxt, struct fdisk_label **lb)
7a188aed
KZ
254{
255 size_t i;
256 struct fdisk_label *res = NULL;
257
258 if (!lb || !cxt)
259 return -EINVAL;
260
261 if (!*lb)
262 res = cxt->labels[0];
263 else {
264 for (i = 1; i < cxt->nlabels; i++) {
265 if (*lb == cxt->labels[i - 1]) {
266 res = cxt->labels[i];
267 break;
268 }
269 }
270 }
271
272 *lb = res;
273 return res ? 0 : 1;
274}
275
6a632136
KZ
276/**
277 * fdisk_get_nlabels:
278 * @cxt: context
279 *
280 * Returns: number of supported label types
281 */
282size_t fdisk_get_nlabels(struct fdisk_context *cxt)
7aa0d529
KZ
283{
284 return cxt ? cxt->nlabels : 0;
285}
286
6a632136 287int __fdisk_switch_label(struct fdisk_context *cxt, struct fdisk_label *lb)
53b422ab 288{
7a188aed
KZ
289 if (!lb || !cxt)
290 return -EINVAL;
291 if (lb->disabled) {
d71bd2f0 292 DBG(CXT, ul_debugobj(cxt, "*** attempt to switch to disabled label %s -- ignore!", lb->name));
53b422ab 293 return -EINVAL;
7a188aed 294 }
53b422ab 295 cxt->label = lb;
d71bd2f0 296 DBG(CXT, ul_debugobj(cxt, "--> switching context to %s!", lb->name));
53b422ab
KZ
297 return 0;
298}
299
aa36c2cf
KZ
300/**
301 * fdisk_has_label:
302 * @cxt: fdisk context
303 *
304 * Returns: return 1 if there is label on the device.
305 */
306int fdisk_has_label(struct fdisk_context *cxt)
307{
308 return cxt && cxt->label;
309}
310
3457d90e
KZ
311/**
312 * fdisk_has_protected_bootbits:
313 * @cxt: fdisk context
314 *
315 * Returns: return 1 if boot bits protection enabled.
316 */
317int fdisk_has_protected_bootbits(struct fdisk_context *cxt)
318{
319 return cxt && cxt->protect_bootbits;
320}
321
322/**
323 * fdisk_enable_bootbits_protection:
324 * @cxt: fdisk context
325 * @enable: 1 or 0
326 *
327 * The library zeroizes all the first sector when create a new disk label by
328 * default. This function allows to control this behavior. For now it's
329 * supported for MBR and GPT.
330 *
331 * Returns: 0 on success, < 0 on error.
332 */
333int fdisk_enable_bootbits_protection(struct fdisk_context *cxt, int enable)
334{
335 if (!cxt)
336 return -EINVAL;
337 cxt->protect_bootbits = enable ? 1 : 0;
338 return 0;
339}
340
6cbb7371
KZ
341/**
342 * fdisk_enable_wipe
343 * @cxt: fdisk context
344 * @enable: 1 or 0
345 *
bd3457b8
KZ
346 * The library removes all PT/filesystem/RAID signatures before it writes
347 * partition table. The probing area where it looks for signatures is from
131e38a2
KZ
348 * the begin of the disk. The device is wiped by libblkid.
349 *
350 * See also fdisk_wipe_partition().
351 *
6cbb7371
KZ
352 * Returns: 0 on success, < 0 on error.
353 */
354int fdisk_enable_wipe(struct fdisk_context *cxt, int enable)
355{
356 if (!cxt)
357 return -EINVAL;
131e38a2 358
bd3457b8 359 fdisk_set_wipe_area(cxt, 0, cxt->total_sectors, enable);
6cbb7371
KZ
360 return 0;
361}
362
363/**
364 * fdisk_has_wipe
365 * @cxt: fdisk context
366 *
367 * Returns the current wipe setting. See fdisk_enable_wipe().
368 *
369 * Returns: 0 on success, < 0 on error.
370 */
371int fdisk_has_wipe(struct fdisk_context *cxt)
372{
131e38a2
KZ
373 if (!cxt)
374 return 0;
375
bd3457b8 376 return fdisk_has_wipe_area(cxt, 0, cxt->total_sectors);
6cbb7371
KZ
377}
378
379
380/**
381 * fdisk_get_collision
382 * @cxt: fdisk context
383 *
384 * Returns: name of the filesystem or RAID detected on the device or NULL.
385 */
386const char *fdisk_get_collision(struct fdisk_context *cxt)
387{
388 return cxt->collision;
389}
390
59c8e95b
KZ
391/**
392 * fdisk_get_npartitions:
393 * @cxt: context
394 *
7190b9b2
KZ
395 * The maximal number of the partitions depends on disklabel and does not
396 * have to describe the real limit of PT.
397 *
398 * For example the limit for MBR without extend partition is 4, with extended
399 * partition it's unlimited (so the function returns the current number of all
400 * partitions in this case).
401 *
402 * And for example for GPT it depends on space allocated on disk for array of
403 * entry records (usually 128).
404 *
405 * It's fine to use fdisk_get_npartitions() in loops, but don't forget that
406 * partition may be unused (see fdisk_is_partition_used()).
407 *
408 * <informalexample>
409 * <programlisting>
410 * struct fdisk_partition *pa = NULL;
411 * size_t i, nmax = fdisk_get_npartitions(cxt);
412 *
413 * for (i = 0; i < nmax; i++) {
414 * if (!fdisk_is_partition_used(cxt, i))
415 * continue;
416 * ... do something ...
417 * }
418 * </programlisting>
419 * </informalexample>
420 *
421 * Note that the recommended way to list partitions is to use
422 * fdisk_get_partitions() and struct fdisk_table than ask disk driver for each
423 * individual partitions.
424 *
59c8e95b
KZ
425 * Returns: maximal number of partitions for the current label.
426 */
427size_t fdisk_get_npartitions(struct fdisk_context *cxt)
428{
429 return cxt && cxt->label ? cxt->label->nparts_max : 0;
430}
431
aa36c2cf
KZ
432/**
433 * fdisk_is_labeltype:
434 * @cxt: fdisk context
1753a234 435 * @id: FDISK_DISKLABEL_*
aa36c2cf 436 *
5175ae87 437 * See also fdisk_is_label() macro in libfdisk.h.
4af064f3 438 *
705854f3 439 * Returns: return 1 if the current label is @id
aa36c2cf 440 */
1753a234 441int fdisk_is_labeltype(struct fdisk_context *cxt, enum fdisk_labeltype id)
aa36c2cf 442{
1753a234 443 assert(cxt);
1753a234 444
b9710f1f 445 return cxt->label && (unsigned)fdisk_label_get_type(cxt->label) == id;
1753a234
KZ
446}
447
448/**
449 * fdisk_get_parent:
450 * @cxt: nested fdisk context
451 *
452 * Returns: pointer to parental context, or NULL
453 */
454struct fdisk_context *fdisk_get_parent(struct fdisk_context *cxt)
455{
456 assert(cxt);
457 return cxt->parent;
aa36c2cf 458}
53b422ab 459
4e0e8253
KZ
460static void reset_context(struct fdisk_context *cxt)
461{
7845ca8d 462 size_t i;
4e0e8253 463
d71bd2f0 464 DBG(CXT, ul_debugobj(cxt, "*** resetting context"));
0559e742
KZ
465
466 /* reset drives' private data */
467 for (i = 0; i < cxt->nlabels; i++)
468 fdisk_deinit_label(cxt->labels[i]);
4e0e8253 469
11eee4c4
KZ
470 if (cxt->parent) {
471 /* the first sector may be independent on parent */
472 if (cxt->parent->firstsector != cxt->firstsector)
473 free(cxt->firstsector);
474 } else {
475 /* we close device only in primary context */
476 if (cxt->dev_fd > -1)
477 close(cxt->dev_fd);
d17c584a 478 free(cxt->firstsector);
11eee4c4 479 }
4e0e8253 480
13633a81 481 free(cxt->dev_path);
7845ca8d 482 cxt->dev_path = NULL;
13633a81 483
6cbb7371
KZ
484 free(cxt->collision);
485 cxt->collision = NULL;
486
7526c305
KZ
487 memset(&cxt->dev_st, 0, sizeof(cxt->dev_st));
488
13633a81 489 cxt->dev_fd = -1;
7845ca8d 490 cxt->firstsector = NULL;
7c2cfb18 491 cxt->firstsector_bufsz = 0;
7845ca8d 492
1653f0b0 493 fdisk_zeroize_device_properties(cxt);
11eee4c4 494
9138d6f9 495 fdisk_unref_script(cxt->script);
11eee4c4 496 cxt->script = NULL;
7845ca8d
KZ
497
498 cxt->label = NULL;
131e38a2
KZ
499
500 fdisk_free_wipe_areas(cxt);
4e0e8253
KZ
501}
502
823f0fd1 503/**
6a632136 504 * fdisk_assign_device:
11eee4c4 505 * @cxt: context
537187be 506 * @fname: path to the device to be handled
25b529fe
DB
507 * @readonly: how to open the device
508 *
11eee4c4
KZ
509 * Open the device, discovery topology, geometry, detect disklabel and switch
510 * the current label driver to reflect the probing result.
6a632136 511 *
11eee4c4
KZ
512 * Note that this function resets all generic setting in context. If the @cxt
513 * is nested context then the device is assigned to the parental context and
514 * necessary properties are copied to the @cxt. The change is propagated in
515 * child->parent direction only. It's impossible to use a different device for
516 * primary and nested contexts.
347a7f77 517 *
58c41e15 518 * Returns: 0 on success, < 0 on error.
823f0fd1 519 */
6a632136
KZ
520int fdisk_assign_device(struct fdisk_context *cxt,
521 const char *fname, int readonly)
823f0fd1 522{
4e0e8253 523 int fd;
823f0fd1 524
d71bd2f0 525 DBG(CXT, ul_debugobj(cxt, "assigning device %s", fname));
4e0e8253
KZ
526 assert(cxt);
527
11eee4c4
KZ
528 /* redirect request to parent */
529 if (cxt->parent) {
530 int rc, org = fdisk_is_listonly(cxt->parent);
531
532 /* assign_device() is sensitive to "listonly" mode, so let's
7526c305 533 * follow the current context setting for the parent to avoid
11eee4c4
KZ
534 * unwanted extra warnings. */
535 fdisk_enable_listonly(cxt->parent, fdisk_is_listonly(cxt));
536
537 rc = fdisk_assign_device(cxt->parent, fname, readonly);
538 fdisk_enable_listonly(cxt->parent, org);
539
13633a81
KZ
540 if (!rc)
541 rc = init_nested_from_parent(cxt, 0);
11eee4c4
KZ
542 if (!rc)
543 fdisk_probe_labels(cxt);
544 return rc;
545 }
546
4e0e8253 547 reset_context(cxt);
95f9f309 548
e146ae4e
KZ
549 fd = open(fname, (readonly ? O_RDONLY : O_RDWR ) | O_CLOEXEC);
550 if (fd < 0)
551 return -errno;
823f0fd1 552
7526c305
KZ
553 fstat(fd, &cxt->dev_st);
554
e146ae4e 555 cxt->readonly = readonly;
823f0fd1
DB
556 cxt->dev_fd = fd;
557 cxt->dev_path = strdup(fname);
558 if (!cxt->dev_path)
559 goto fail;
618882d6 560
aa42788d
KZ
561 fdisk_discover_topology(cxt);
562 fdisk_discover_geometry(cxt);
823f0fd1 563
502dd53c
KZ
564 fdisk_apply_user_device_properties(cxt);
565
3eb78aa7
KZ
566 if (fdisk_read_firstsector(cxt) < 0)
567 goto fail;
568
7ce10975 569 fdisk_probe_labels(cxt);
1653f0b0 570
b2140d2f
KZ
571 fdisk_apply_label_device_properties(cxt);
572
6e876a98
KZ
573 /* warn about obsolete stuff on the device if we aren't in
574 * list-only mode and there is not PT yet */
37204dc6
KZ
575 if (!fdisk_is_listonly(cxt) && !fdisk_has_label(cxt)
576 && fdisk_check_collisions(cxt) < 0)
6cbb7371 577 goto fail;
6e876a98 578
d71bd2f0
KZ
579 DBG(CXT, ul_debugobj(cxt, "initialized for %s [%s]",
580 fname, readonly ? "READ-ONLY" : "READ-WRITE"));
4e0e8253 581 return 0;
823f0fd1 582fail:
d71bd2f0 583 DBG(CXT, ul_debugobj(cxt, "failed to assign device"));
4e0e8253 584 return -errno;
823f0fd1
DB
585}
586
5175ae87
KZ
587/**
588 * fdisk_deassign_device:
589 * @cxt: context
590 * @nosync: disable fsync()
591 *
11eee4c4
KZ
592 * Close device and call fsync(). If the @cxt is nested context than the
593 * request is redirected to the parent.
7190b9b2
KZ
594 *
595 * Returns: 0 on success, < 0 on error.
5175ae87 596 */
6a632136 597int fdisk_deassign_device(struct fdisk_context *cxt, int nosync)
a57639e1
KZ
598{
599 assert(cxt);
600 assert(cxt->dev_fd >= 0);
601
11eee4c4
KZ
602 if (cxt->parent) {
603 int rc = fdisk_deassign_device(cxt->parent, nosync);
604
13633a81
KZ
605 if (!rc)
606 rc = init_nested_from_parent(cxt, 0);
11eee4c4
KZ
607 return rc;
608 }
609
2aeff761 610 if (cxt->readonly)
bc787727 611 close(cxt->dev_fd);
bc787727
KZ
612 else {
613 if (fsync(cxt->dev_fd) || close(cxt->dev_fd)) {
614 fdisk_warn(cxt, _("%s: close device failed"),
615 cxt->dev_path);
616 return -errno;
617 }
a57639e1 618
2aeff761
KZ
619 if (!nosync) {
620 fdisk_info(cxt, _("Syncing disks."));
621 sync();
622 }
bc787727 623 }
152788aa
KZ
624
625 free(cxt->dev_path);
13633a81 626 cxt->dev_path = NULL;
152788aa 627
a57639e1 628 cxt->dev_fd = -1;
152788aa 629
a57639e1
KZ
630 return 0;
631}
632
5175ae87
KZ
633/**
634 * fdisk_is_readonly:
635 * @cxt: context
636 *
637 * Returns: 1 if device open readonly
638 */
6a632136 639int fdisk_is_readonly(struct fdisk_context *cxt)
e146ae4e
KZ
640{
641 assert(cxt);
642 return cxt->readonly;
643}
644
7526c305
KZ
645/**
646 * fdisk_is_regfile:
647 * @cxt: context
648 *
649 * Returns: 1 if open file descriptor is regular file rather than a block device.
650 */
651int fdisk_is_regfile(struct fdisk_context *cxt)
652{
653 assert(cxt);
654 return S_ISREG(cxt->dev_st.st_mode);
655}
656
823f0fd1 657/**
c7119037 658 * fdisk_unref_context:
823f0fd1
DB
659 * @cxt: fdisk context
660 *
661 * Deallocates context struct.
662 */
c7119037 663void fdisk_unref_context(struct fdisk_context *cxt)
823f0fd1 664{
b9710f1f 665 unsigned i;
0c5d095e 666
823f0fd1
DB
667 if (!cxt)
668 return;
669
c7119037
KZ
670 cxt->refcount--;
671 if (cxt->refcount <= 0) {
672 DBG(CXT, ul_debugobj(cxt, "freeing context %p for %s", cxt, cxt->dev_path));
11eee4c4
KZ
673
674 reset_context(cxt); /* this is sensitive to parent<->child relationship! */
c7119037
KZ
675
676 /* deallocate label's private stuff */
677 for (i = 0; i < cxt->nlabels; i++) {
678 if (!cxt->labels[i])
679 continue;
680 if (cxt->labels[i]->op->free)
681 cxt->labels[i]->op->free(cxt->labels[i]);
682 else
683 free(cxt->labels[i]);
684 }
11eee4c4
KZ
685
686 fdisk_unref_context(cxt->parent);
687 cxt->parent = NULL;
688
c7119037 689 free(cxt);
0c5d095e 690 }
823f0fd1 691}
7845ca8d 692
cb7ce873 693
a5c1b0fa 694/**
6a632136
KZ
695 * fdisk_enable_details:
696 * @cxt: context
9e930041 697 * @enable: true/false
a5c1b0fa 698 *
6a632136
KZ
699 * Enables or disables "details" display mode. This function has effect to
700 * fdisk_partition_to_string() function.
a5c1b0fa
KZ
701 *
702 * Returns: 0 on success, < 0 on error.
703 */
6a632136 704int fdisk_enable_details(struct fdisk_context *cxt, int enable)
a5c1b0fa
KZ
705{
706 assert(cxt);
707 cxt->display_details = enable ? 1 : 0;
708 return 0;
709}
710
6a632136
KZ
711/**
712 * fdisk_is_details:
713 * @cxt: context
714 *
715 * Returns: 1 if details are enabled
716 */
717int fdisk_is_details(struct fdisk_context *cxt)
a5c1b0fa
KZ
718{
719 assert(cxt);
720 return cxt->display_details == 1;
721}
cb7ce873 722
c10937dc 723/**
6a632136
KZ
724 * fdisk_enable_listonly:
725 * @cxt: context
9e930041 726 * @enable: true/false
c10937dc
KZ
727 *
728 * Just list partition only, don't care about another details, mistakes, ...
729 *
730 * Returns: 0 on success, < 0 on error.
731 */
6a632136 732int fdisk_enable_listonly(struct fdisk_context *cxt, int enable)
c10937dc
KZ
733{
734 assert(cxt);
735 cxt->listonly = enable ? 1 : 0;
736 return 0;
737}
738
6a632136
KZ
739/**
740 * fdisk_is_listonly:
741 * @cxt: context
742 *
743 * Returns: 1 if list-only mode enabled
744 */
745int fdisk_is_listonly(struct fdisk_context *cxt)
c10937dc
KZ
746{
747 assert(cxt);
748 return cxt->listonly == 1;
749}
750
751
6a632136
KZ
752/**
753 * fdisk_set_unit:
754 * @cxt: context
cb7ce873
KZ
755 * @str: "cylinder" or "sector".
756 *
757 * This is pure shit, unfortunately for example Sun addresses begin of the
758 * partition by cylinders...
6a632136 759 *
9e930041 760 * Returns: 0 on success, <0 on error.
cb7ce873 761 */
6a632136 762int fdisk_set_unit(struct fdisk_context *cxt, const char *str)
cb7ce873
KZ
763{
764 assert(cxt);
765
766 cxt->display_in_cyl_units = 0;
767
768 if (!str)
769 return 0;
770
771 if (strcmp(str, "cylinder") == 0 || strcmp(str, "cylinders") == 0)
772 cxt->display_in_cyl_units = 1;
773
774 else if (strcmp(str, "sector") == 0 || strcmp(str, "sectors") == 0)
775 cxt->display_in_cyl_units = 0;
776
6a632136 777 DBG(CXT, ul_debugobj(cxt, "display unit: %s", fdisk_get_unit(cxt, 0)));
cb7ce873
KZ
778 return 0;
779}
780
6a632136
KZ
781/**
782 * fdisk_get_unit:
783 * @cxt: context
705854f3 784 * @n: FDISK_PLURAL or FDISK_SINGULAR
6a632136
KZ
785 *
786 * Returns: unit name.
787 */
788const char *fdisk_get_unit(struct fdisk_context *cxt, int n)
cb7ce873
KZ
789{
790 assert(cxt);
791
6a632136 792 if (fdisk_use_cylinders(cxt))
cb7ce873
KZ
793 return P_("cylinder", "cylinders", n);
794 return P_("sector", "sectors", n);
795}
796
6a632136
KZ
797/**
798 * fdisk_use_cylinders:
705854f3 799 * @cxt: context
6a632136 800 *
705854f3 801 * Returns: 1 if user wants to display in cylinders.
6a632136
KZ
802 */
803int fdisk_use_cylinders(struct fdisk_context *cxt)
cb7ce873
KZ
804{
805 assert(cxt);
806 return cxt->display_in_cyl_units == 1;
807}
808
6a632136
KZ
809/**
810 * fdisk_get_units_per_sector:
811 * @cxt: context
812 *
1bcf491a 813 * This is necessary only for brain dead situations when we use "cylinders";
6a632136
KZ
814 *
815 * Returns: number of "units" per sector, default is 1 if display unit is sector.
cb7ce873 816 */
6a632136 817unsigned int fdisk_get_units_per_sector(struct fdisk_context *cxt)
cb7ce873
KZ
818{
819 assert(cxt);
820
6a632136 821 if (fdisk_use_cylinders(cxt)) {
cb7ce873
KZ
822 assert(cxt->geom.heads);
823 return cxt->geom.heads * cxt->geom.sectors;
824 }
825 return 1;
826}
6a632136
KZ
827
828/**
829 * fdisk_get_optimal_iosize:
830 * @cxt: context
831 *
6b11aad2
KZ
832 * The optimal I/O is optional and does not have to be provided by device,
833 * anyway libfdisk never returns zero. If the optimal I/O size is not provided
834 * then libfdisk returns minimal I/O size or sector size.
835 *
7190b9b2 836 * Returns: optimal I/O size in bytes.
6a632136
KZ
837 */
838unsigned long fdisk_get_optimal_iosize(struct fdisk_context *cxt)
839{
840 assert(cxt);
6b11aad2 841 return cxt->optimal_io_size ? cxt->optimal_io_size : cxt->io_size;
6a632136
KZ
842}
843
844/**
845 * fdisk_get_minimal_iosize:
846 * @cxt: context
847 *
7190b9b2 848 * Returns: minimal I/O size in bytes
6a632136 849 */
1753a234 850unsigned long fdisk_get_minimal_iosize(struct fdisk_context *cxt)
6a632136
KZ
851{
852 assert(cxt);
853 return cxt->min_io_size;
854}
855
856/**
857 * fdisk_get_physector_size:
858 * @cxt: context
859 *
7190b9b2 860 * Returns: physical sector size in bytes
6a632136
KZ
861 */
862unsigned long fdisk_get_physector_size(struct fdisk_context *cxt)
863{
864 assert(cxt);
865 return cxt->phy_sector_size;
866}
867
868/**
869 * fdisk_get_sector_size:
870 * @cxt: context
871 *
7190b9b2 872 * Returns: logical sector size in bytes
6a632136
KZ
873 */
874unsigned long fdisk_get_sector_size(struct fdisk_context *cxt)
875{
876 assert(cxt);
877 return cxt->sector_size;
878}
879
880/**
881 * fdisk_get_alignment_offset
882 * @cxt: context
883 *
7190b9b2
KZ
884 * The alignment offset is offset between logical and physical sectors. For
885 * backward compatibility the first logical sector on 4K disks does no have to
886 * start on the same place like physical sectors.
887 *
888 * Returns: alignment offset in bytes
6a632136
KZ
889 */
890unsigned long fdisk_get_alignment_offset(struct fdisk_context *cxt)
891{
892 assert(cxt);
893 return cxt->alignment_offset;
894}
895
896/**
897 * fdisk_get_grain_size:
898 * @cxt: context
899 *
7190b9b2 900 * Returns: grain in bytes used to align partitions (usually 1MiB)
6a632136
KZ
901 */
902unsigned long fdisk_get_grain_size(struct fdisk_context *cxt)
903{
904 assert(cxt);
905 return cxt->grain;
906}
907
908/**
909 * fdisk_get_first_lba:
910 * @cxt: context
911 *
912 * Returns: first possible LBA on disk for data partitions.
913 */
0073a4cf 914fdisk_sector_t fdisk_get_first_lba(struct fdisk_context *cxt)
6a632136
KZ
915{
916 assert(cxt);
917 return cxt->first_lba;
918}
919
6d37c2ce
KZ
920/**
921 * fdisk_set_first_lba:
922 * @cxt: fdisk context
7190b9b2 923 * @lba: first possible logical sector for data
6d37c2ce
KZ
924 *
925 * It's strongly recommended to use the default library setting. The first LBA
9e930041 926 * is always reset by fdisk_assign_device(), fdisk_override_geometry()
6d37c2ce
KZ
927 * and fdisk_reset_alignment(). This is very low level function and library
928 * does not check if your setting makes any sense.
929 *
7190b9b2
KZ
930 * This function is necessary only when you want to work with very unusual
931 * partition tables like GPT protective MBR or hybrid partition tables on
932 * bootable media where the first partition may start on very crazy offsets.
933 *
6d37c2ce
KZ
934 * Returns: 0 on success, <0 on error.
935 */
0073a4cf 936fdisk_sector_t fdisk_set_first_lba(struct fdisk_context *cxt, fdisk_sector_t lba)
6d37c2ce
KZ
937{
938 assert(cxt);
939 DBG(CXT, ul_debugobj(cxt, "setting first LBA from %ju to %ju",
940 (uintmax_t) cxt->first_lba, (uintmax_t) lba));
941 cxt->first_lba = lba;
942 return 0;
943}
944
945/**
946 * fdisk_get_last_lba:
947 * @cxt: fdisk context
948 *
949 * Note that the device has to be already assigned.
950 *
951 * Returns: last possible LBA on device
952 */
0073a4cf 953fdisk_sector_t fdisk_get_last_lba(struct fdisk_context *cxt)
6d37c2ce
KZ
954{
955 return cxt->last_lba;
956}
957
958/**
959 * fdisk_set_last_lba:
960 * @cxt: fdisk context
7190b9b2 961 * @lba: last possible logical sector
6d37c2ce
KZ
962 *
963 * It's strongly recommended to use the default library setting. The last LBA
9e930041 964 * is always reset by fdisk_assign_device(), fdisk_override_geometry() and
6d37c2ce
KZ
965 * fdisk_reset_alignment().
966 *
7190b9b2 967 * The default is number of sectors on the device, but maybe modified by the
dee59a1e 968 * current disklabel driver (for example GPT uses the end of disk for backup
7190b9b2
KZ
969 * header, so last_lba is smaller than total number of sectors).
970 *
6d37c2ce
KZ
971 * Returns: 0 on success, <0 on error.
972 */
0073a4cf 973fdisk_sector_t fdisk_set_last_lba(struct fdisk_context *cxt, fdisk_sector_t lba)
6d37c2ce
KZ
974{
975 assert(cxt);
976
083c35b9 977 if (lba > cxt->total_sectors - 1 || lba < 1)
6d37c2ce
KZ
978 return -ERANGE;
979 cxt->last_lba = lba;
980 return 0;
981}
982
354f8cc8
KZ
983/**
984 * fdisk_set_size_unit:
985 * @cxt: fdisk context
986 * @unit: FDISK_SIZEUNIT_*
987 *
988 * Sets unit for SIZE output field (see fdisk_partition_to_string()).
989 *
990 * Returns: 0 on success, <0 on error.
991 */
992int fdisk_set_size_unit(struct fdisk_context *cxt, int unit)
993{
994 assert(cxt);
995 cxt->sizeunit = unit;
996 return 0;
997}
998
999/**
1000 * fdisk_get_size_unit:
1001 * @cxt: fdisk context
1002 *
1003 * Gets unit for SIZE output field (see fdisk_partition_to_string()).
1004 *
1005 * Returns: unit
1006 */
f3aca7ab 1007int fdisk_get_size_unit(struct fdisk_context *cxt)
354f8cc8
KZ
1008{
1009 assert(cxt);
1010 return cxt->sizeunit;
1011}
6d37c2ce 1012
6a632136
KZ
1013/**
1014 * fdisk_get_nsectors:
1015 * @cxt: context
1016 *
7190b9b2 1017 * Returns: size of the device in logical sectors.
6a632136 1018 */
0073a4cf 1019fdisk_sector_t fdisk_get_nsectors(struct fdisk_context *cxt)
6a632136
KZ
1020{
1021 assert(cxt);
1022 return cxt->total_sectors;
1023}
1024
1025/**
1026 * fdisk_get_devname:
1027 * @cxt: context
1028 *
1029 * Returns: device name.
1030 */
1031const char *fdisk_get_devname(struct fdisk_context *cxt)
1032{
1033 assert(cxt);
1034 return cxt->dev_path;
1035}
aa36c2cf 1036
1753a234
KZ
1037/**
1038 * fdisk_get_devfd:
1039 * @cxt: context
1040 *
9e930041 1041 * Returns: device file descriptor.
1753a234
KZ
1042 */
1043int fdisk_get_devfd(struct fdisk_context *cxt)
1044{
1045 assert(cxt);
1046 return cxt->dev_fd;
1047}
1048
1049/**
1050 * fdisk_get_geom_heads:
1051 * @cxt: context
1052 *
1053 * Returns: number of geometry heads.
1054 */
1055unsigned int fdisk_get_geom_heads(struct fdisk_context *cxt)
1056{
1057 assert(cxt);
1058 return cxt->geom.heads;
1059}
1060/**
1061 * fdisk_get_geom_sectors:
1062 * @cxt: context
1063 *
1064 * Returns: number of geometry sectors.
1065 */
0073a4cf 1066fdisk_sector_t fdisk_get_geom_sectors(struct fdisk_context *cxt)
1753a234
KZ
1067{
1068 assert(cxt);
1069 return cxt->geom.sectors;
1070
1071}
1072
1073/**
1074 * fdisk_get_geom_cylinders:
1075 * @cxt: context
1076 *
1077 * Returns: number of geometry cylinders
1078 */
0073a4cf 1079fdisk_sector_t fdisk_get_geom_cylinders(struct fdisk_context *cxt)
1753a234
KZ
1080{
1081 assert(cxt);
1082 return cxt->geom.cylinders;
1083}
aa36c2cf 1084
72d2965c
KZ
1085int fdisk_missing_geometry(struct fdisk_context *cxt)
1086{
1087 int rc;
1088
72d2965c
KZ
1089 if (!cxt || !cxt->label)
1090 return 0;
1091
1092 rc = (fdisk_label_require_geometry(cxt->label) &&
1093 (!cxt->geom.heads || !cxt->geom.sectors
1094 || !cxt->geom.cylinders));
1095
1096 if (rc && !fdisk_is_listonly(cxt))
1097 fdisk_warnx(cxt, _("Incomplete geometry setting."));
1098
1099 return rc;
1100}
aa36c2cf 1101