]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libfdisk/src/context.c
libfdisk: clean up API (alignment.c)
[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
6a632136
KZ
7/**
8 * fdisk_new_context:
9 *
10 * Returns: newly allocated libfdisk handler
11 */
4e0e8253 12struct fdisk_context *fdisk_new_context(void)
0c5d095e
KZ
13{
14 struct fdisk_context *cxt;
0c5d095e
KZ
15
16 cxt = calloc(1, sizeof(*cxt));
17 if (!cxt)
18 return NULL;
19
d71bd2f0 20 DBG(CXT, ul_debugobj(cxt, "alloc"));
4e0e8253
KZ
21 cxt->dev_fd = -1;
22
0c5d095e
KZ
23 /*
24 * Allocate label specific structs.
25 *
26 * This is necessary (for example) to store label specific
27 * context setting.
28 */
29 cxt->labels[ cxt->nlabels++ ] = fdisk_new_gpt_label(cxt);
30 cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt);
b4fb2a61 31 cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt);
0c5d095e
KZ
32 cxt->labels[ cxt->nlabels++ ] = fdisk_new_sgi_label(cxt);
33 cxt->labels[ cxt->nlabels++ ] = fdisk_new_sun_label(cxt);
34
0c5d095e
KZ
35 return cxt;
36}
37
6a632136
KZ
38/**
39 * fdisk_new_nested_context:
40 * @parent: parental context
41 * @name: optional label name (e.g. "bsd")
42 *
43 * This is supported for MBR+BSD and GPT+pMBR only.
44 *
45 * Returns: new context for nested partiton table.
46 */
01b20713
KZ
47struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent,
48 const char *name)
49{
50 struct fdisk_context *cxt;
8a9256f9 51 struct fdisk_label *lb = NULL;
01b20713
KZ
52
53 assert(parent);
01b20713
KZ
54
55 cxt = calloc(1, sizeof(*cxt));
56 if (!cxt)
57 return NULL;
58
d71bd2f0 59 DBG(CXT, ul_debugobj(parent, "alloc nested [%p]", cxt));
01b20713
KZ
60 cxt->dev_fd = parent->dev_fd;
61 cxt->parent = parent;
62
63 cxt->io_size = parent->io_size;
64 cxt->optimal_io_size = parent->optimal_io_size;
65 cxt->min_io_size = parent->min_io_size;
66 cxt->phy_sector_size = parent->phy_sector_size;
67 cxt->sector_size = parent->sector_size;
68 cxt->alignment_offset = parent->alignment_offset;
69 cxt->grain = parent->grain;
70 cxt->first_lba = parent->first_lba;
71 cxt->total_sectors = parent->total_sectors;
d17c584a 72 cxt->firstsector = parent->firstsector;
01b20713 73
b720e0d7
KZ
74 cxt->ask_cb = parent->ask_cb;
75 cxt->ask_data = parent->ask_data;
76
01b20713
KZ
77 cxt->geom = parent->geom;
78
d17c584a
KZ
79 if (name) {
80 if (strcmp(name, "bsd") == 0)
81 lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt);
82 else if (strcmp(name, "dos") == 0)
83 lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt);
84 }
8a9256f9
KZ
85
86 if (lb) {
d71bd2f0 87 DBG(CXT, ul_debugobj(cxt, "probing for nested %s", lb->name));
8a9256f9
KZ
88
89 cxt->label = lb;
90
91 if (lb->op->probe(cxt) == 1)
6a632136 92 __fdisk_switch_label(cxt, lb);
8a9256f9 93 else {
d71bd2f0 94 DBG(CXT, ul_debugobj(cxt, "not found %s label", lb->name));
8a9256f9
KZ
95 if (lb->op->deinit)
96 lb->op->deinit(lb);
97 cxt->label = NULL;
98 }
99 }
01b20713
KZ
100
101 return cxt;
102}
103
104
6a632136
KZ
105/**
106 * fdisk_get_label:
107 * @cxt: context instance
108 * @name: label name (e.g. "gpt")
109 *
110 * If no @name specified then returns the current context label.
111 *
112 * Returns: label struct or NULL in case of error.
852ce62b 113 */
6a632136 114struct fdisk_label *fdisk_get_label(struct fdisk_context *cxt, const char *name)
0c5d095e
KZ
115{
116 size_t i;
117
118 assert(cxt);
119
852ce62b
KZ
120 if (!name)
121 return cxt->label;
122
0c5d095e 123 for (i = 0; i < cxt->nlabels; i++)
7ab242ec
KZ
124 if (cxt->labels[i]
125 && strcmp(cxt->labels[i]->name, name) == 0)
0c5d095e
KZ
126 return cxt->labels[i];
127
d71bd2f0 128 DBG(CXT, ul_debugobj(cxt, "failed to found %s label driver", name));
0c5d095e
KZ
129 return NULL;
130}
131
6a632136
KZ
132/**
133 * fdisk_next_label:
134 * @cxt: context instance
135 * @lb: returns pointer to the next label
136 *
137 * <informalexample>
138 * <programlisting>
139 * // print all supported labels
140 * struct fdisk_context *cxt = fdisk_new_context();
141 * struct fdisk_label *lb = NULL;
142 *
143 * while (fdisk_next_label(cxt, &lb) == 0)
144 * print("label name: %s\n", fdisk_label_get_name(lb));
145 * fdisk_free_context(cxt);
146 * </programlisting>
147 * </informalexample>
148 *
149 * Returns: <0 in case of error, 0 on success, 1 at the end.
150 */
151int fdisk_next_label(struct fdisk_context *cxt, struct fdisk_label **lb)
7a188aed
KZ
152{
153 size_t i;
154 struct fdisk_label *res = NULL;
155
156 if (!lb || !cxt)
157 return -EINVAL;
158
159 if (!*lb)
160 res = cxt->labels[0];
161 else {
162 for (i = 1; i < cxt->nlabels; i++) {
163 if (*lb == cxt->labels[i - 1]) {
164 res = cxt->labels[i];
165 break;
166 }
167 }
168 }
169
170 *lb = res;
171 return res ? 0 : 1;
172}
173
6a632136
KZ
174/**
175 * fdisk_get_nlabels:
176 * @cxt: context
177 *
178 * Returns: number of supported label types
179 */
180size_t fdisk_get_nlabels(struct fdisk_context *cxt)
7aa0d529
KZ
181{
182 return cxt ? cxt->nlabels : 0;
183}
184
6a632136 185int __fdisk_switch_label(struct fdisk_context *cxt, struct fdisk_label *lb)
53b422ab 186{
7a188aed
KZ
187 if (!lb || !cxt)
188 return -EINVAL;
189 if (lb->disabled) {
d71bd2f0 190 DBG(CXT, ul_debugobj(cxt, "*** attempt to switch to disabled label %s -- ignore!", lb->name));
53b422ab 191 return -EINVAL;
7a188aed 192 }
53b422ab 193 cxt->label = lb;
d71bd2f0 194 DBG(CXT, ul_debugobj(cxt, "--> switching context to %s!", lb->name));
53b422ab
KZ
195 return 0;
196}
197
6a632136
KZ
198/**
199 * fdisk_switch_label:
200 * @cxt: context
201 * @name: label name (e.g. "gpt")
202 *
203 * Forces libfdisk to use the label driver.
204 *
205 * Returns: 0 on succes, <0 in case of error.
206 */
207int fdisk_switch_label(struct fdisk_context *cxt, const char *name)
53b422ab 208{
6a632136 209 return __fdisk_switch_label(cxt, fdisk_get_label(cxt, name));
53b422ab
KZ
210}
211
212
4e0e8253
KZ
213static void reset_context(struct fdisk_context *cxt)
214{
7845ca8d 215 size_t i;
4e0e8253 216
d71bd2f0 217 DBG(CXT, ul_debugobj(cxt, "*** resetting context"));
0559e742
KZ
218
219 /* reset drives' private data */
220 for (i = 0; i < cxt->nlabels; i++)
221 fdisk_deinit_label(cxt->labels[i]);
4e0e8253 222
4e0e8253 223 /* free device specific stuff */
01b20713 224 if (!cxt->parent && cxt->dev_fd > -1)
4e0e8253
KZ
225 close(cxt->dev_fd);
226 free(cxt->dev_path);
d17c584a
KZ
227
228 if (cxt->parent == NULL || cxt->parent->firstsector != cxt->firstsector)
229 free(cxt->firstsector);
4e0e8253 230
4e0e8253
KZ
231 /* initialize */
232 cxt->dev_fd = -1;
7845ca8d
KZ
233 cxt->dev_path = NULL;
234 cxt->firstsector = NULL;
7c2cfb18 235 cxt->firstsector_bufsz = 0;
7845ca8d 236
1653f0b0 237 fdisk_zeroize_device_properties(cxt);
7845ca8d
KZ
238
239 cxt->label = NULL;
4e0e8253
KZ
240}
241
6e876a98
KZ
242/*
243 * This function prints a warning if the device is not wiped (e.g. wipefs(8).
244 * Please don't call this function if there is already a PT.
245 *
246 * Returns: 0 if nothing found, < 0 on error, 1 if found a signature
247 */
248static int warn_wipe(struct fdisk_context *cxt)
249{
250#ifdef HAVE_LIBBLKID
251 blkid_probe pr;
252#endif
253 int rc = 0;
254
255 assert(cxt);
256
257 if (fdisk_dev_has_disklabel(cxt) || cxt->dev_fd < 0)
258 return -EINVAL;
259#ifdef HAVE_LIBBLKID
d71bd2f0 260 DBG(CXT, ul_debugobj(cxt, "wipe check: initialize libblkid prober"));
6e876a98
KZ
261
262 pr = blkid_new_probe();
263 if (!pr)
264 return -ENOMEM;
265 rc = blkid_probe_set_device(pr, cxt->dev_fd, 0, 0);
266 if (rc)
267 return rc;
268
269 blkid_probe_enable_superblocks(pr, 1);
270 blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE);
271 blkid_probe_enable_partitions(pr, 1);
272
273 /* we care about the first found FS/raid, so don't call blkid_do_probe()
274 * in loop or don't use blkid_do_fullprobe() ... */
275 rc = blkid_do_probe(pr);
276 if (rc == 0) {
277 const char *name = NULL;
278
279 if (blkid_probe_lookup_value(pr, "TYPE", &name, 0) == 0 ||
280 blkid_probe_lookup_value(pr, "PTTYPE", &name, 0) == 0) {
281 fdisk_warnx(cxt, _(
282 "%s: device contains a valid '%s' signature, it's "
283 "strongly recommended to wipe the device by command wipefs(8) "
284 "if this setup is unexpected to avoid "
285 "possible collisions."), cxt->dev_path, name);
286 rc = 1;
287 }
288 }
289
290 blkid_free_probe(pr);
291#endif
292 return rc;
293}
294
823f0fd1 295/**
6a632136 296 * fdisk_assign_device:
537187be 297 * @fname: path to the device to be handled
25b529fe
DB
298 * @readonly: how to open the device
299 *
6a632136
KZ
300 * Open the device, discovery topology, geometry, and detect disklabel.
301 *
58c41e15 302 * Returns: 0 on success, < 0 on error.
823f0fd1 303 */
6a632136
KZ
304int fdisk_assign_device(struct fdisk_context *cxt,
305 const char *fname, int readonly)
823f0fd1 306{
4e0e8253 307 int fd;
823f0fd1 308
d71bd2f0 309 DBG(CXT, ul_debugobj(cxt, "assigning device %s", fname));
4e0e8253
KZ
310 assert(cxt);
311
312 reset_context(cxt);
95f9f309 313
e146ae4e
KZ
314 fd = open(fname, (readonly ? O_RDONLY : O_RDWR ) | O_CLOEXEC);
315 if (fd < 0)
316 return -errno;
823f0fd1 317
e146ae4e 318 cxt->readonly = readonly;
823f0fd1
DB
319 cxt->dev_fd = fd;
320 cxt->dev_path = strdup(fname);
321 if (!cxt->dev_path)
322 goto fail;
618882d6 323
aa42788d
KZ
324 fdisk_discover_topology(cxt);
325 fdisk_discover_geometry(cxt);
823f0fd1 326
3eb78aa7
KZ
327 if (fdisk_read_firstsector(cxt) < 0)
328 goto fail;
329
9a5e29e9
KZ
330 /* detect labels and apply labes specific stuff (e.g geomery)
331 * to the context */
7ce10975 332 fdisk_probe_labels(cxt);
1653f0b0
KZ
333
334 /* let's apply user geometry *after* label prober
335 * to make it possible to override in-label setting */
336 fdisk_apply_user_device_properties(cxt);
9a5e29e9 337
6e876a98
KZ
338 /* warn about obsolete stuff on the device if we aren't in
339 * list-only mode and there is not PT yet */
6a632136 340 if (!fdisk_is_listonly(cxt) && !fdisk_dev_has_disklabel(cxt))
6e876a98
KZ
341 warn_wipe(cxt);
342
d71bd2f0
KZ
343 DBG(CXT, ul_debugobj(cxt, "initialized for %s [%s]",
344 fname, readonly ? "READ-ONLY" : "READ-WRITE"));
4e0e8253 345 return 0;
823f0fd1 346fail:
d71bd2f0 347 DBG(CXT, ul_debugobj(cxt, "failed to assign device"));
4e0e8253 348 return -errno;
823f0fd1
DB
349}
350
6a632136 351int fdisk_deassign_device(struct fdisk_context *cxt, int nosync)
a57639e1
KZ
352{
353 assert(cxt);
354 assert(cxt->dev_fd >= 0);
355
bc787727
KZ
356 if (cxt->readonly || nosync)
357 close(cxt->dev_fd);
a57639e1 358
bc787727
KZ
359 else {
360 if (fsync(cxt->dev_fd) || close(cxt->dev_fd)) {
361 fdisk_warn(cxt, _("%s: close device failed"),
362 cxt->dev_path);
363 return -errno;
364 }
a57639e1 365
bc787727
KZ
366 fdisk_info(cxt, _("Syncing disks."));
367 sync();
368 }
a57639e1
KZ
369 cxt->dev_fd = -1;
370 return 0;
371}
372
6a632136 373int fdisk_is_readonly(struct fdisk_context *cxt)
e146ae4e
KZ
374{
375 assert(cxt);
376 return cxt->readonly;
377}
378
823f0fd1
DB
379/**
380 * fdisk_free_context:
381 * @cxt: fdisk context
382 *
383 * Deallocates context struct.
384 */
385void fdisk_free_context(struct fdisk_context *cxt)
386{
0c5d095e
KZ
387 int i;
388
823f0fd1
DB
389 if (!cxt)
390 return;
391
d71bd2f0 392 DBG(CXT, ul_debugobj(cxt, "freeing context %p for %s", cxt, cxt->dev_path));
4e0e8253 393 reset_context(cxt);
0c5d095e
KZ
394
395 /* deallocate label's private stuff */
396 for (i = 0; i < cxt->nlabels; i++) {
397 if (!cxt->labels[i])
398 continue;
399 if (cxt->labels[i]->op->free)
400 cxt->labels[i]->op->free(cxt->labels[i]);
401 else
402 free(cxt->labels[i]);
403 }
404
823f0fd1
DB
405 free(cxt);
406}
7845ca8d
KZ
407
408/**
6a632136 409 * fdisk_set_ask:
7845ca8d
KZ
410 * @cxt: context
411 * @ask_cb: callback
412 * @data: callback data
413 *
6a632136
KZ
414 * Set callbacks for dialog driven partitioning and library warnings/errors.
415 *
58c41e15 416 * Returns: 0 on success, < 0 on error.
7845ca8d 417 */
6a632136 418int fdisk_set_ask(struct fdisk_context *cxt,
7845ca8d
KZ
419 int (*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *),
420 void *data)
421{
422 assert(cxt);
423
424 cxt->ask_cb = ask_cb;
425 cxt->ask_data = data;
426 return 0;
427}
cb7ce873 428
a5c1b0fa 429/**
6a632136
KZ
430 * fdisk_enable_details:
431 * @cxt: context
432 * @enable: true/flase
a5c1b0fa 433 *
6a632136
KZ
434 * Enables or disables "details" display mode. This function has effect to
435 * fdisk_partition_to_string() function.
a5c1b0fa
KZ
436 *
437 * Returns: 0 on success, < 0 on error.
438 */
6a632136 439int fdisk_enable_details(struct fdisk_context *cxt, int enable)
a5c1b0fa
KZ
440{
441 assert(cxt);
442 cxt->display_details = enable ? 1 : 0;
443 return 0;
444}
445
6a632136
KZ
446/**
447 * fdisk_is_details:
448 * @cxt: context
449 *
450 * Returns: 1 if details are enabled
451 */
452int fdisk_is_details(struct fdisk_context *cxt)
a5c1b0fa
KZ
453{
454 assert(cxt);
455 return cxt->display_details == 1;
456}
cb7ce873 457
c10937dc 458/**
6a632136
KZ
459 * fdisk_enable_listonly:
460 * @cxt: context
461 * @enable: true/flase
c10937dc
KZ
462 *
463 * Just list partition only, don't care about another details, mistakes, ...
464 *
465 * Returns: 0 on success, < 0 on error.
466 */
6a632136 467int fdisk_enable_listonly(struct fdisk_context *cxt, int enable)
c10937dc
KZ
468{
469 assert(cxt);
470 cxt->listonly = enable ? 1 : 0;
471 return 0;
472}
473
6a632136
KZ
474/**
475 * fdisk_is_listonly:
476 * @cxt: context
477 *
478 * Returns: 1 if list-only mode enabled
479 */
480int fdisk_is_listonly(struct fdisk_context *cxt)
c10937dc
KZ
481{
482 assert(cxt);
483 return cxt->listonly == 1;
484}
485
486
6a632136
KZ
487/**
488 * fdisk_set_unit:
489 * @cxt: context
cb7ce873
KZ
490 * @str: "cylinder" or "sector".
491 *
492 * This is pure shit, unfortunately for example Sun addresses begin of the
493 * partition by cylinders...
6a632136
KZ
494 *
495 * Returns: 0 on succes, <0 on error.
cb7ce873 496 */
6a632136 497int fdisk_set_unit(struct fdisk_context *cxt, const char *str)
cb7ce873
KZ
498{
499 assert(cxt);
500
501 cxt->display_in_cyl_units = 0;
502
503 if (!str)
504 return 0;
505
506 if (strcmp(str, "cylinder") == 0 || strcmp(str, "cylinders") == 0)
507 cxt->display_in_cyl_units = 1;
508
509 else if (strcmp(str, "sector") == 0 || strcmp(str, "sectors") == 0)
510 cxt->display_in_cyl_units = 0;
511
6a632136 512 DBG(CXT, ul_debugobj(cxt, "display unit: %s", fdisk_get_unit(cxt, 0)));
cb7ce873
KZ
513 return 0;
514}
515
6a632136
KZ
516/**
517 * fdisk_get_unit:
518 * @cxt: context
519 *
520 * Returns: unit name.
521 */
522const char *fdisk_get_unit(struct fdisk_context *cxt, int n)
cb7ce873
KZ
523{
524 assert(cxt);
525
6a632136 526 if (fdisk_use_cylinders(cxt))
cb7ce873
KZ
527 return P_("cylinder", "cylinders", n);
528 return P_("sector", "sectors", n);
529}
530
6a632136
KZ
531/**
532 * fdisk_use_cylinders:
533 * @@cxt: context
534 *
535 * Returns 1 if user wants to display in cylinders.
536 */
537int fdisk_use_cylinders(struct fdisk_context *cxt)
cb7ce873
KZ
538{
539 assert(cxt);
540 return cxt->display_in_cyl_units == 1;
541}
542
6a632136
KZ
543/**
544 * fdisk_get_units_per_sector:
545 * @cxt: context
546 *
547 * This is neccessary only for brain dead situations when we use "cylinders";
548 *
549 * Returns: number of "units" per sector, default is 1 if display unit is sector.
cb7ce873 550 */
6a632136 551unsigned int fdisk_get_units_per_sector(struct fdisk_context *cxt)
cb7ce873
KZ
552{
553 assert(cxt);
554
6a632136 555 if (fdisk_use_cylinders(cxt)) {
cb7ce873
KZ
556 assert(cxt->geom.heads);
557 return cxt->geom.heads * cxt->geom.sectors;
558 }
559 return 1;
560}
6a632136
KZ
561
562/**
563 * fdisk_get_optimal_iosize:
564 * @cxt: context
565 *
566 * Returns: optimal I/O size
567 */
568unsigned long fdisk_get_optimal_iosize(struct fdisk_context *cxt)
569{
570 assert(cxt);
571 return cxt->optimal_io_size;
572}
573
574/**
575 * fdisk_get_minimal_iosize:
576 * @cxt: context
577 *
578 * Returns: minimal I/O size
579 */
580unsigned long fdisk_get_minimal_size(struct fdisk_context *cxt)
581{
582 assert(cxt);
583 return cxt->min_io_size;
584}
585
586/**
587 * fdisk_get_physector_size:
588 * @cxt: context
589 *
590 * Returns: physical sector size
591 */
592unsigned long fdisk_get_physector_size(struct fdisk_context *cxt)
593{
594 assert(cxt);
595 return cxt->phy_sector_size;
596}
597
598/**
599 * fdisk_get_sector_size:
600 * @cxt: context
601 *
602 * Returns: sector size
603 */
604unsigned long fdisk_get_sector_size(struct fdisk_context *cxt)
605{
606 assert(cxt);
607 return cxt->sector_size;
608}
609
610/**
611 * fdisk_get_alignment_offset
612 * @cxt: context
613 *
614 * Returns: alignment offset (used by 4K disks for backward compatibility with DOS tools).
615 */
616unsigned long fdisk_get_alignment_offset(struct fdisk_context *cxt)
617{
618 assert(cxt);
619 return cxt->alignment_offset;
620}
621
622/**
623 * fdisk_get_grain_size:
624 * @cxt: context
625 *
626 * Returns: usual grain used to align partitions
627 */
628unsigned long fdisk_get_grain_size(struct fdisk_context *cxt)
629{
630 assert(cxt);
631 return cxt->grain;
632}
633
634/**
635 * fdisk_get_first_lba:
636 * @cxt: context
637 *
638 * Returns: first possible LBA on disk for data partitions.
639 */
8d605c88 640sector_t fdisk_get_first_lba(struct fdisk_context *cxt)
6a632136
KZ
641{
642 assert(cxt);
643 return cxt->first_lba;
644}
645
646/**
647 * fdisk_get_nsectors:
648 * @cxt: context
649 *
650 * Returns: size of the device in (real) sectors.
651 */
8d605c88 652sector_t fdisk_get_nsectors(struct fdisk_context *cxt)
6a632136
KZ
653{
654 assert(cxt);
655 return cxt->total_sectors;
656}
657
658/**
659 * fdisk_get_devname:
660 * @cxt: context
661 *
662 * Returns: device name.
663 */
664const char *fdisk_get_devname(struct fdisk_context *cxt)
665{
666 assert(cxt);
667 return cxt->dev_path;
668}