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