1 /*
2 * fdiskP.h - private library header file
3 *
4 * Copyright (C) 2012 Karel Zak <kzak@redhat.com>
5 *
6 * This file may be redistributed under the terms of the
7 * GNU Lesser General Public License.
8 */
9
10 #ifndef _LIBFDISK_PRIVATE_H
11 #define _LIBFDISK_PRIVATE_H
12
13 #include <errno.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <uuid.h>
20
21 #include "c.h"
22 #include "libfdisk.h"
23
24 #include "list.h"
25 #include "debug.h"
26 #include <stdio.h>
27 #include <stdarg.h>
28
29 /*
30 * Debug
31 */
32 #define LIBFDISK_DEBUG_HELP (1 << 0)
33 #define LIBFDISK_DEBUG_INIT (1 << 1)
34 #define LIBFDISK_DEBUG_CXT (1 << 2)
35 #define LIBFDISK_DEBUG_LABEL (1 << 3)
36 #define LIBFDISK_DEBUG_ASK (1 << 4)
37 #define LIBFDISK_DEBUG_PART (1 << 6)
38 #define LIBFDISK_DEBUG_PARTTYPE (1 << 7)
39 #define LIBFDISK_DEBUG_TAB (1 << 8)
40 #define LIBFDISK_DEBUG_SCRIPT (1 << 9)
41 #define LIBFDISK_DEBUG_WIPE (1 << 10)
42 #define LIBFDISK_DEBUG_ITEM (1 << 11)
43 #define LIBFDISK_DEBUG_GPT (1 << 12)
44 #define LIBFDISK_DEBUG_ALL 0xFFFF
45
46 UL_DEBUG_DECLARE_MASK(libfdisk);
47 #define DBG(m, x) __UL_DBG(libfdisk, LIBFDISK_DEBUG_, m, x)
48 #define ON_DBG(m, x) __UL_DBG_CALL(libfdisk, LIBFDISK_DEBUG_, m, x)
49 #define DBG_FLUSH __UL_DBG_FLUSH(libfdisk, LIBFDISK_DEBUG_)
50
51 #define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(libfdisk)
52 #include "debugobj.h"
53
54 /*
55 * NLS -- the library has to be independent on main program, so define
56 * UL_TEXTDOMAIN_EXPLICIT before you include nls.h.
57 *
58 * Now we use util-linux.po (=PACKAGE), rather than maintain the texts
59 * in the separate libfdisk.po file.
60 */
61 #define LIBFDISK_TEXTDOMAIN PACKAGE
62 #define UL_TEXTDOMAIN_EXPLICIT LIBFDISK_TEXTDOMAIN
63 #include "nls.h"
64
65
66 #ifdef TEST_PROGRAM
67 struct fdisk_test {
68 const char *name;
69 int (*body)(struct fdisk_test *ts, int argc, char *argv[]);
70 const char *usage;
71 };
72
73 /* test.c */
74 extern int fdisk_run_test(struct fdisk_test *tests, int argc, char *argv[]);
75 #endif
76
77 #define FDISK_GPT_NPARTITIONS_DEFAULT 128
78
79 /*
80 * Generic iterator
81 */
82 struct fdisk_iter {
83 struct list_head *p; /* current position */
84 struct list_head *head; /* start position */
85 int direction; /* FDISK_ITER_{FOR,BACK}WARD */
86 };
87
88 #define IS_ITER_FORWARD(_i) ((_i)->direction == FDISK_ITER_FORWARD)
89 #define IS_ITER_BACKWARD(_i) ((_i)->direction == FDISK_ITER_BACKWARD)
90
91 #define FDISK_ITER_INIT(itr, list) \
92 do { \
93 (itr)->p = IS_ITER_FORWARD(itr) ? \
94 (list)->next : (list)->prev; \
95 (itr)->head = (list); \
96 } while(0)
97
98 #define FDISK_ITER_ITERATE(itr, res, restype, member) \
99 do { \
100 res = list_entry((itr)->p, restype, member); \
101 (itr)->p = IS_ITER_FORWARD(itr) ? \
102 (itr)->p->next : (itr)->p->prev; \
103 } while(0)
104
105 /*
106 * Partition types
107 */
108 struct fdisk_parttype {
109 unsigned int code; /* type as number or zero */
110 char *name; /* description */
111 char *typestr; /* type as string or NULL */
112
113 unsigned int flags; /* FDISK_PARTTYPE_* flags */
114 int refcount; /* reference counter for allocated types */
115 };
116
117 enum {
118 FDISK_PARTTYPE_UNKNOWN = (1 << 1),
119 FDISK_PARTTYPE_INVISIBLE = (1 << 2),
120 FDISK_PARTTYPE_ALLOCATED = (1 << 3)
121 };
122
123 #define fdisk_parttype_is_invisible(_x) ((_x) && ((_x)->flags & FDISK_PARTTYPE_INVISIBLE))
124 #define fdisk_parttype_is_allocated(_x) ((_x) && ((_x)->flags & FDISK_PARTTYPE_ALLOCATED))
125
126 /*
127 * Shortcut (used for partition types)
128 */
129 struct fdisk_shortcut {
130 const char *shortcut; /* shortcut, usually one letter (e.h. "H") */
131 const char *alias; /* human readable alias (e.g. "home") */
132 const char *data; /* for example partition type */
133
134 unsigned int deprecated : 1;
135 };
136
137 struct fdisk_partition {
138 int refcount; /* reference counter */
139
140 size_t partno; /* partition number */
141 size_t parent_partno; /* for logical partitions */
142
143 fdisk_sector_t start; /* first sectors */
144 fdisk_sector_t size; /* size in sectors */
145
146 int movestart; /* FDISK_MOVE_* (scripts only) */
147 int resize; /* FDISK_RESIZE_* (scripts only) */
148
149 char *name; /* partition name */
150 char *uuid; /* partition UUID */
151 char *attrs; /* partition flags/attributes converted to string */
152 struct fdisk_parttype *type; /* partition type */
153
154 char *fstype; /* filesystem type */
155 char *fsuuid; /* filesystem uuid */
156 char *fslabel; /* filesystem label */
157
158 struct list_head parts; /* list of partitions */
159
160 /* extra fields for partition_to_string() */
161 char start_post; /* start postfix (e.g. '+') */
162 char end_post; /* end postfix */
163 char size_post; /* size postfix */
164
165 uint64_t fsize; /* bsd junk */
166 uint64_t bsize;
167 uint64_t cpg;
168
169 char *start_chs; /* start C/H/S in string */
170 char *end_chs; /* end C/H/S in string */
171
172 unsigned int boot; /* MBR: bootable */
173
174 unsigned int container : 1, /* container partition (e.g. extended partition) */
175 end_follow_default : 1, /* use default end */
176 freespace : 1, /* this is free space */
177 partno_follow_default : 1, /* use default partno */
178 size_explicit : 1, /* don't align the size */
179 start_follow_default : 1, /* use default start */
180 fs_probed : 1, /* already probed by blkid */
181 used : 1, /* partition already used */
182 wholedisk : 1; /* special system partition */
183 };
184
185 enum {
186 FDISK_MOVE_NONE = 0,
187 FDISK_MOVE_DOWN = -1,
188 FDISK_MOVE_UP = 1
189 };
190
191 enum {
192 FDISK_RESIZE_NONE = 0,
193 FDISK_RESIZE_REDUCE = -1,
194 FDISK_RESIZE_ENLARGE = 1
195 };
196
197 #define FDISK_INIT_UNDEF(_x) ((_x) = (__typeof__(_x)) -1)
198 #define FDISK_IS_UNDEF(_x) ((_x) == (__typeof__(_x)) -1)
199
200 struct fdisk_table {
201 struct list_head parts; /* partitions */
202 int refcount;
203 size_t nents; /* number of partitions */
204 };
205
206 /*
207 * Legacy CHS based geometry
208 */
209 struct fdisk_geometry {
210 unsigned int heads;
211 fdisk_sector_t sectors;
212 fdisk_sector_t cylinders;
213 };
214
215 /*
216 * Label specific operations
217 */
218 struct fdisk_label_operations {
219 /* probe disk label */
220 int (*probe)(struct fdisk_context *cxt);
221 /* write in-memory changes to disk */
222 int (*write)(struct fdisk_context *cxt);
223 /* verify the partition table */
224 int (*verify)(struct fdisk_context *cxt);
225 /* create new disk label */
226 int (*create)(struct fdisk_context *cxt);
227 /* returns offset and size of the 'n' part of the PT */
228 int (*locate)(struct fdisk_context *cxt, int n, const char **name,
229 uint64_t *offset, size_t *size);
230 /* reorder partitions */
231 int (*reorder)(struct fdisk_context *cxt);
232 /* get details from label */
233 int (*get_item)(struct fdisk_context *cxt, struct fdisk_labelitem *item);
234 /* set disk label ID */
235 int (*set_id)(struct fdisk_context *cxt, const char *str);
236
237
238 /* new partition */
239 int (*add_part)(struct fdisk_context *cxt, struct fdisk_partition *pa,
240 size_t *partno);
241 /* delete partition */
242 int (*del_part)(struct fdisk_context *cxt, size_t partnum);
243
244 /* fill in partition struct */
245 int (*get_part)(struct fdisk_context *cxt, size_t n,
246 struct fdisk_partition *pa);
247 /* modify partition */
248 int (*set_part)(struct fdisk_context *cxt, size_t n,
249 struct fdisk_partition *pa);
250
251 /* return state of the partition */
252 int (*part_is_used)(struct fdisk_context *cxt, size_t partnum);
253
254 int (*part_toggle_flag)(struct fdisk_context *cxt, size_t i, unsigned long flag);
255
256 /* refresh alignment setting */
257 int (*reset_alignment)(struct fdisk_context *cxt);
258
259 /* free in-memory label stuff */
260 void (*free)(struct fdisk_label *lb);
261
262 /* deinit in-memory label stuff */
263 void (*deinit)(struct fdisk_label *lb);
264 };
265
266 /*
267 * The fields describes how to display libfdisk_partition
268 */
269 struct fdisk_field {
270 int id; /* FDISK_FIELD_* */
271 const char *name; /* field name */
272 double width; /* field width (compatible with libsmartcols whint) */
273 int flags; /* FDISK_FIELDFL_* */
274 };
275
276 /* note that the defaults is to display a column always */
277 enum {
278 FDISK_FIELDFL_DETAIL = (1 << 1), /* only display if fdisk_is_details() */
279 FDISK_FIELDFL_EYECANDY = (1 << 2), /* don't display if fdisk_is_details() */
280 FDISK_FIELDFL_NUMBER = (1 << 3), /* column display numbers */
281 };
282
283 /*
284 * Generic label
285 */
286 struct fdisk_label {
287 const char *name; /* label name */
288 enum fdisk_labeltype id; /* FDISK_DISKLABEL_* */
289 struct fdisk_parttype *parttypes; /* supported partitions types */
290 size_t nparttypes; /* number of items in parttypes[] */
291
292 const struct fdisk_shortcut *parttype_cuts; /* partition type shortcuts */
293 size_t nparttype_cuts; /* number of items in parttype_cuts */
294
295 size_t nparts_max; /* maximal number of partitions */
296 size_t nparts_cur; /* number of currently used partitions */
297
298 int flags; /* FDISK_LABEL_FL_* flags */
299
300 struct fdisk_geometry geom_min; /* minimal geometry */
301 struct fdisk_geometry geom_max; /* maximal geometry */
302
303 unsigned int changed:1, /* label has been modified */
304 disabled:1; /* this driver is disabled at all */
305
306 const struct fdisk_field *fields; /* all possible fields */
307 size_t nfields;
308
309 const struct fdisk_label_operations *op;
310 };
311
312
313 /* label driver flags */
314 enum {
315 FDISK_LABEL_FL_REQUIRE_GEOMETRY = (1 << 2),
316 FDISK_LABEL_FL_INCHARS_PARTNO = (1 << 3)
317 };
318
319 /* label allocators */
320 extern struct fdisk_label *fdisk_new_gpt_label(struct fdisk_context *cxt);
321 extern struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt);
322 extern struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt);
323 extern struct fdisk_label *fdisk_new_sgi_label(struct fdisk_context *cxt);
324 extern struct fdisk_label *fdisk_new_sun_label(struct fdisk_context *cxt);
325
326
327 struct ask_menuitem {
328 char key;
329 const char *name;
330 const char *desc;
331
332 struct ask_menuitem *next;
333 };
334
335 /* fdisk dialog -- note that nothing from this stuff will be directly exported,
336 * we will have get/set() function for everything.
337 */
338 struct fdisk_ask {
339 int type; /* FDISK_ASKTYPE_* */
340 char *query;
341
342 int refcount;
343
344 union {
345 /* FDISK_ASKTYPE_{NUMBER,OFFSET} */
346 struct ask_number {
347 uint64_t hig; /* high limit */
348 uint64_t low; /* low limit */
349 uint64_t dfl; /* default */
350 uint64_t result;
351 uint64_t base; /* for relative results */
352 uint64_t unit; /* unit for offsets */
353 const char *range; /* by library generated list */
354 unsigned int relative :1,
355 inchars :1,
356 wrap_negative :1;
357 } num;
358 /* FDISK_ASKTYPE_{WARN,WARNX,..} */
359 struct ask_print {
360 const char *mesg;
361 int errnum; /* errno */
362 } print;
363 /* FDISK_ASKTYPE_YESNO */
364 struct ask_yesno {
365 int result; /* TRUE or FALSE */
366 } yesno;
367 /* FDISK_ASKTYPE_STRING */
368 struct ask_string {
369 char *result; /* allocated */
370 } str;
371 /* FDISK_ASKTYPE_MENU */
372 struct ask_menu {
373 int dfl; /* default menu item */
374 int result;
375 struct ask_menuitem *first;
376 } menu;
377 } data;
378 };
379
380 struct fdisk_context {
381 int dev_fd; /* device descriptor */
382 char *dev_path; /* device path */
383 char *dev_model; /* on linux /sys/block/<name>/device/model or NULL */
384 struct stat dev_st; /* stat(2) result */
385
386 int refcount;
387
388 unsigned char *firstsector; /* buffer with master boot record */
389 unsigned long firstsector_bufsz;
390
391
392 /* topology */
393 unsigned long io_size; /* I/O size used by fdisk */
394 unsigned long optimal_io_size; /* optional I/O returned by device */
395 unsigned long min_io_size; /* minimal I/O size */
396 unsigned long phy_sector_size; /* physical size */
397 unsigned long sector_size; /* logical size */
398 unsigned long alignment_offset;
399
400 unsigned int readonly : 1, /* don't write to the device */
401 display_in_cyl_units : 1, /* for obscure labels */
402 display_details : 1, /* expert display mode */
403 protect_bootbits : 1, /* don't zeroize first sector */
404 pt_collision : 1, /* another PT detected by libblkid */
405 no_disalogs : 1, /* disable dialog-driven partititoning */
406 dev_model_probed : 1, /* tried to read from sys */
407 is_priv : 1, /* open by libfdisk */
408 is_excl : 1, /* open with O_EXCL */
409 listonly : 1; /* list partition, nothing else */
410
411 char *collision; /* name of already existing FS/PT */
412 struct list_head wipes; /* list of areas to wipe before write */
413
414 int sizeunit; /* SIZE fields, FDISK_SIZEUNIT_* */
415
416 /* alignment */
417 unsigned long grain; /* alignment unit */
418 fdisk_sector_t first_lba; /* recommended begin of the first partition */
419 fdisk_sector_t last_lba; /* recommended end of last partition */
420
421 /* geometry */
422 fdisk_sector_t total_sectors; /* in logical sectors */
423 struct fdisk_geometry geom;
424
425 /* user setting to overwrite device default */
426 struct fdisk_geometry user_geom;
427 unsigned long user_pyh_sector;
428 unsigned long user_log_sector;
429 unsigned long user_grain;
430
431 struct fdisk_label *label; /* current label, pointer to labels[] */
432
433 size_t nlabels; /* number of initialized label drivers */
434 struct fdisk_label *labels[8]; /* all supported labels,
435 * FIXME: use any enum rather than hardcoded number */
436
437 int (*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *); /* fdisk dialogs callback */
438 void *ask_data; /* ask_cb() data */
439
440 struct fdisk_context *parent; /* for nested PT */
441 struct fdisk_script *script; /* what we want to follow */
442 };
443
444 /* table */
445 enum {
446 FDISK_DIFF_UNCHANGED = 0,
447 FDISK_DIFF_REMOVED,
448 FDISK_DIFF_ADDED,
449 FDISK_DIFF_MOVED,
450 FDISK_DIFF_RESIZED
451 };
452 extern int fdisk_diff_tables(struct fdisk_table *a, struct fdisk_table *b,
453 struct fdisk_iter *itr,
454 struct fdisk_partition **res, int *change);
455 extern void fdisk_debug_print_table(struct fdisk_table *tb);
456
457
458 /* context.c */
459 extern int __fdisk_switch_label(struct fdisk_context *cxt,
460 struct fdisk_label *lb);
461 extern int fdisk_missing_geometry(struct fdisk_context *cxt);
462
463 /* alignment.c */
464 fdisk_sector_t fdisk_scround(struct fdisk_context *cxt, fdisk_sector_t num);
465 fdisk_sector_t fdisk_cround(struct fdisk_context *cxt, fdisk_sector_t num);
466
467 extern int fdisk_discover_geometry(struct fdisk_context *cxt);
468 extern int fdisk_discover_topology(struct fdisk_context *cxt);
469
470 extern int fdisk_has_user_device_geometry(struct fdisk_context *cxt);
471 extern int fdisk_apply_user_device_properties(struct fdisk_context *cxt);
472 extern int fdisk_apply_label_device_properties(struct fdisk_context *cxt);
473 extern void fdisk_zeroize_device_properties(struct fdisk_context *cxt);
474
475 /* utils.c */
476 extern int fdisk_init_firstsector_buffer(struct fdisk_context *cxt,
477 unsigned int protect_off, unsigned int protect_size);
478 extern int fdisk_read_firstsector(struct fdisk_context *cxt);
479
480 /* label.c */
481 extern int fdisk_probe_labels(struct fdisk_context *cxt);
482 extern void fdisk_deinit_label(struct fdisk_label *lb);
483
484 struct fdisk_labelitem {
485 int refcount; /* reference counter */
486 int id; /* <label>_ITEM_* */
487 char type; /* s = string, j = uint64 */
488 const char *name; /* human readable name */
489
490 union {
491 char *str;
492 uint64_t num64;
493 } data;
494 };
495
496 /* Use only internally for non-allocated items, never use
497 * refcouting for such items!
498 */
499 #define FDISK_LABELITEM_INIT { .type = 0, .refcount = 0 }
500
501 /* ask.c */
502 struct fdisk_ask *fdisk_new_ask(void);
503 void fdisk_reset_ask(struct fdisk_ask *ask);
504 int fdisk_ask_set_query(struct fdisk_ask *ask, const char *str);
505 int fdisk_ask_set_type(struct fdisk_ask *ask, int type);
506 int fdisk_do_ask(struct fdisk_context *cxt, struct fdisk_ask *ask);
507 int fdisk_ask_number_set_range(struct fdisk_ask *ask, const char *range);
508 int fdisk_ask_number_set_default(struct fdisk_ask *ask, uint64_t dflt);
509 int fdisk_ask_number_set_low(struct fdisk_ask *ask, uint64_t low);
510 int fdisk_ask_number_set_high(struct fdisk_ask *ask, uint64_t high);
511 int fdisk_ask_number_set_base(struct fdisk_ask *ask, uint64_t base);
512 int fdisk_ask_number_set_unit(struct fdisk_ask *ask, uint64_t unit);
513 int fdisk_ask_number_is_relative(struct fdisk_ask *ask);
514 int fdisk_ask_number_set_wrap_negative(struct fdisk_ask *ask, int wrap_negative);
515 int fdisk_ask_menu_set_default(struct fdisk_ask *ask, int dfl);
516 int fdisk_ask_menu_add_item(struct fdisk_ask *ask, int key,
517 const char *name, const char *desc);
518 int fdisk_ask_print_set_errno(struct fdisk_ask *ask, int errnum);
519 int fdisk_ask_print_set_mesg(struct fdisk_ask *ask, const char *mesg);
520 int fdisk_info_new_partition(
521 struct fdisk_context *cxt,
522 int num, fdisk_sector_t start, fdisk_sector_t stop,
523 struct fdisk_parttype *t);
524
525 /* dos.c */
526 extern struct dos_partition *fdisk_dos_get_partition(
527 struct fdisk_context *cxt,
528 size_t i);
529
530 /* wipe.c */
531 void fdisk_free_wipe_areas(struct fdisk_context *cxt);
532 int fdisk_set_wipe_area(struct fdisk_context *cxt, uint64_t start, uint64_t size, int enable);
533 int fdisk_do_wipe(struct fdisk_context *cxt);
534 int fdisk_has_wipe_area(struct fdisk_context *cxt, uint64_t start, uint64_t size);
535 int fdisk_check_collisions(struct fdisk_context *cxt);
536
537 /* parttype.c */
538 const char *fdisk_label_translate_type_shortcut(const struct fdisk_label *lb, char *cut);
539
540 #endif /* _LIBFDISK_PRIVATE_H */