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