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 		     private_fd : 1,		/* open by libfdisk */
408 		     listonly : 1;		/* list partition, nothing else */
409 
410 	char *collision;			/* name of already existing FS/PT */
411 	struct list_head wipes;			/* list of areas to wipe before write */
412 
413 	int sizeunit;				/* SIZE fields, FDISK_SIZEUNIT_* */
414 
415 	/* alignment */
416 	unsigned long grain;		/* alignment unit */
417 	fdisk_sector_t first_lba;		/* recommended begin of the first partition */
418 	fdisk_sector_t last_lba;		/* recommended end of last partition */
419 
420 	/* geometry */
421 	fdisk_sector_t total_sectors;	/* in logical sectors */
422 	struct fdisk_geometry geom;
423 
424 	/* user setting to overwrite device default */
425 	struct fdisk_geometry user_geom;
426 	unsigned long user_pyh_sector;
427 	unsigned long user_log_sector;
428 	unsigned long user_grain;
429 
430 	struct fdisk_label *label;	/* current label, pointer to labels[] */
431 
432 	size_t nlabels;			/* number of initialized label drivers */
433 	struct fdisk_label *labels[8];	/* all supported labels,
434 					 * FIXME: use any enum rather than hardcoded number */
435 
436 	int	(*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *);	/* fdisk dialogs callback */
437 	void	*ask_data;		/* ask_cb() data */
438 
439 	struct fdisk_context	*parent;	/* for nested PT */
440 	struct fdisk_script	*script;	/* what we want to follow */
441 };
442 
443 /* table */
444 enum {
445 	FDISK_DIFF_UNCHANGED = 0,
446 	FDISK_DIFF_REMOVED,
447 	FDISK_DIFF_ADDED,
448 	FDISK_DIFF_MOVED,
449 	FDISK_DIFF_RESIZED
450 };
451 extern int fdisk_diff_tables(struct fdisk_table *a, struct fdisk_table *b,
452 				struct fdisk_iter *itr,
453 				struct fdisk_partition **res, int *change);
454 extern void fdisk_debug_print_table(struct fdisk_table *tb);
455 
456 
457 /* context.c */
458 extern int __fdisk_switch_label(struct fdisk_context *cxt,
459 				    struct fdisk_label *lb);
460 extern int fdisk_missing_geometry(struct fdisk_context *cxt);
461 
462 /* alignment.c */
463 fdisk_sector_t fdisk_scround(struct fdisk_context *cxt, fdisk_sector_t num);
464 fdisk_sector_t fdisk_cround(struct fdisk_context *cxt, fdisk_sector_t num);
465 
466 extern int fdisk_discover_geometry(struct fdisk_context *cxt);
467 extern int fdisk_discover_topology(struct fdisk_context *cxt);
468 
469 extern int fdisk_has_user_device_geometry(struct fdisk_context *cxt);
470 extern int fdisk_apply_user_device_properties(struct fdisk_context *cxt);
471 extern int fdisk_apply_label_device_properties(struct fdisk_context *cxt);
472 extern void fdisk_zeroize_device_properties(struct fdisk_context *cxt);
473 
474 /* utils.c */
475 extern int fdisk_init_firstsector_buffer(struct fdisk_context *cxt,
476 			unsigned int protect_off, unsigned int protect_size);
477 extern int fdisk_read_firstsector(struct fdisk_context *cxt);
478 
479 /* label.c */
480 extern int fdisk_probe_labels(struct fdisk_context *cxt);
481 extern void fdisk_deinit_label(struct fdisk_label *lb);
482 
483 struct fdisk_labelitem {
484 	int		refcount;	/* reference counter */
485 	int		id;		/* <label>_ITEM_* */
486 	char		type;		/* s = string, j = uint64 */
487 	const char	*name;		/* human readable name */
488 
489 	union {
490 		char		*str;
491 		uint64_t	num64;
492 	} data;
493 };
494 
495 /* Use only internally for non-allocated items, never use
496  * refcouting for such items!
497  */
498 #define FDISK_LABELITEM_INIT	{ .type = 0, .refcount = 0 }
499 
500 /* ask.c */
501 struct fdisk_ask *fdisk_new_ask(void);
502 void fdisk_reset_ask(struct fdisk_ask *ask);
503 int fdisk_ask_set_query(struct fdisk_ask *ask, const char *str);
504 int fdisk_ask_set_type(struct fdisk_ask *ask, int type);
505 int fdisk_do_ask(struct fdisk_context *cxt, struct fdisk_ask *ask);
506 int fdisk_ask_number_set_range(struct fdisk_ask *ask, const char *range);
507 int fdisk_ask_number_set_default(struct fdisk_ask *ask, uint64_t dflt);
508 int fdisk_ask_number_set_low(struct fdisk_ask *ask, uint64_t low);
509 int fdisk_ask_number_set_high(struct fdisk_ask *ask, uint64_t high);
510 int fdisk_ask_number_set_base(struct fdisk_ask *ask, uint64_t base);
511 int fdisk_ask_number_set_unit(struct fdisk_ask *ask, uint64_t unit);
512 int fdisk_ask_number_is_relative(struct fdisk_ask *ask);
513 int fdisk_ask_number_set_wrap_negative(struct fdisk_ask *ask, int wrap_negative);
514 int fdisk_ask_menu_set_default(struct fdisk_ask *ask, int dfl);
515 int fdisk_ask_menu_add_item(struct fdisk_ask *ask, int key,
516 			const char *name, const char *desc);
517 int fdisk_ask_print_set_errno(struct fdisk_ask *ask, int errnum);
518 int fdisk_ask_print_set_mesg(struct fdisk_ask *ask, const char *mesg);
519 int fdisk_info_new_partition(
520 			struct fdisk_context *cxt,
521 			int num, fdisk_sector_t start, fdisk_sector_t stop,
522 			struct fdisk_parttype *t);
523 
524 /* dos.c */
525 extern struct dos_partition *fdisk_dos_get_partition(
526 				struct fdisk_context *cxt,
527 				size_t i);
528 
529 /* wipe.c */
530 void fdisk_free_wipe_areas(struct fdisk_context *cxt);
531 int fdisk_set_wipe_area(struct fdisk_context *cxt, uint64_t start, uint64_t size, int enable);
532 int fdisk_do_wipe(struct fdisk_context *cxt);
533 int fdisk_has_wipe_area(struct fdisk_context *cxt, uint64_t start, uint64_t size);
534 int fdisk_check_collisions(struct fdisk_context *cxt);
535 
536 /* parttype.c */
537 const char *fdisk_label_translate_type_shortcut(const struct fdisk_label *lb, char *cut);
538 
539 #endif /* _LIBFDISK_PRIVATE_H */
540