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