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