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