4 #include "carefulputc.h"
9 * @short_description: text based sfdisk compatible description of partition table
11 * The libfdisk scripts are based on original sfdisk script (dumps). Each
12 * script has two parts: script headers and partition table entries
15 * For more details about script format see sfdisk man page.
18 /* script header (e.g. unit: sectors) */
19 struct fdisk_scriptheader
{
20 struct list_head headers
;
25 /* script control struct */
27 struct fdisk_table
*table
;
28 struct list_head headers
;
29 struct fdisk_context
*cxt
;
32 char *(*fn_fgets
)(struct fdisk_script
*, char *, size_t, FILE *);
37 struct fdisk_label
*label
;
39 unsigned int json
: 1; /* JSON output */
43 static void fdisk_script_free_header(struct fdisk_scriptheader
*fi
)
48 DBG(SCRIPT
, ul_debugobj(fi
, "free header %s", fi
->name
));
51 list_del(&fi
->headers
);
59 * The script hold fdisk_table and additional information to read/write
62 * Returns: newly allocated script struct.
64 struct fdisk_script
*fdisk_new_script(struct fdisk_context
*cxt
)
66 struct fdisk_script
*dp
= NULL
;
68 dp
= calloc(1, sizeof(*dp
));
72 DBG(SCRIPT
, ul_debugobj(dp
, "alloc"));
75 fdisk_ref_context(cxt
);
77 dp
->table
= fdisk_new_table();
79 fdisk_unref_script(dp
);
83 INIT_LIST_HEAD(&dp
->headers
);
88 * fdisk_new_script_from_file:
90 * @filename: path to the script file
92 * Allocates a new script and reads script from @filename.
94 * Returns: new script instance or NULL in case of error (check errno for more details).
96 struct fdisk_script
*fdisk_new_script_from_file(struct fdisk_context
*cxt
,
101 struct fdisk_script
*dp
, *res
= NULL
;
106 DBG(SCRIPT
, ul_debug("opening %s", filename
));
107 f
= fopen(filename
, "r");
111 dp
= fdisk_new_script(cxt
);
115 rc
= fdisk_script_read_file(dp
, f
);
125 fdisk_unref_script(dp
);
134 * @dp: script pointer
136 * Incremparts reference counter.
138 void fdisk_ref_script(struct fdisk_script
*dp
)
144 static void fdisk_reset_script(struct fdisk_script
*dp
)
148 DBG(SCRIPT
, ul_debugobj(dp
, "reset"));
149 fdisk_unref_table(dp
->table
);
152 while (!list_empty(&dp
->headers
)) {
153 struct fdisk_scriptheader
*fi
= list_entry(dp
->headers
.next
,
154 struct fdisk_scriptheader
, headers
);
155 fdisk_script_free_header(fi
);
157 INIT_LIST_HEAD(&dp
->headers
);
161 * fdisk_unref_script:
162 * @dp: script pointer
164 * De-incremparts reference counter, on zero the @dp is automatically
167 void fdisk_unref_script(struct fdisk_script
*dp
)
173 if (dp
->refcount
<= 0) {
174 fdisk_reset_script(dp
);
175 fdisk_unref_context(dp
->cxt
);
176 DBG(SCRIPT
, ul_debugobj(dp
, "free script"));
182 * fdisk_script_set_userdata
186 * Sets data usable for example in callbacks (e.g fdisk_script_set_fgets()).
188 * Returns: 0 on success, <0 on error.
190 int fdisk_script_set_userdata(struct fdisk_script
*dp
, void *data
)
198 * fdisk_script_get_userdata
201 * Returns: user data or NULL.
203 void *fdisk_script_get_userdata(struct fdisk_script
*dp
)
209 static struct fdisk_scriptheader
*script_get_header(struct fdisk_script
*dp
,
214 list_for_each(p
, &dp
->headers
) {
215 struct fdisk_scriptheader
*fi
= list_entry(p
, struct fdisk_scriptheader
, headers
);
217 if (strcasecmp(fi
->name
, name
) == 0)
225 * fdisk_script_get_header:
226 * @dp: script instance
229 * Returns: pointer to header data or NULL.
231 const char *fdisk_script_get_header(struct fdisk_script
*dp
, const char *name
)
233 struct fdisk_scriptheader
*fi
;
238 fi
= script_get_header(dp
, name
);
239 return fi
? fi
->data
: NULL
;
244 * fdisk_script_set_header:
245 * @dp: script instance
247 * @data: header data (or NULL)
249 * The headers are used as global options for whole partition
250 * table, always one header per line.
252 * If no @data is specified then the header is removed. If header does not exist
253 * and @data is specified then a new header is added.
255 * Note that libfdisk allows to specify arbitrary custom header, the default
256 * build-in headers are "unit" and "label", and some label specific headers
257 * (for example "uuid" and "name" for GPT).
259 * Returns: 0 on success, <0 on error
261 int fdisk_script_set_header(struct fdisk_script
*dp
,
265 struct fdisk_scriptheader
*fi
;
270 fi
= script_get_header(dp
, name
);
272 return 0; /* want to remove header that does not exist, success */
275 DBG(SCRIPT
, ul_debugobj(dp
, "freeing header %s", name
));
277 /* no data, remove the header */
278 fdisk_script_free_header(fi
);
283 DBG(SCRIPT
, ul_debugobj(dp
, "setting new header %s='%s'", name
, data
));
286 fi
= calloc(1, sizeof(*fi
));
289 INIT_LIST_HEAD(&fi
->headers
);
290 fi
->name
= strdup(name
);
291 fi
->data
= strdup(data
);
292 if (!fi
->data
|| !fi
->name
) {
293 fdisk_script_free_header(fi
);
296 list_add_tail(&fi
->headers
, &dp
->headers
);
298 /* update existing */
299 char *x
= strdup(data
);
301 DBG(SCRIPT
, ul_debugobj(dp
, "update '%s' header '%s' -> '%s'", name
, fi
->data
, data
));
309 if (strcmp(name
, "label") == 0)
316 * fdisk_script_get_table:
319 * The table (container with partitions) is possible to create by
320 * fdisk_script_read_context() or fdisk_script_read_file(), otherwise
321 * this function returns NULL.
323 * Returns: NULL or script.
325 struct fdisk_table
*fdisk_script_get_table(struct fdisk_script
*dp
)
328 return dp
? dp
->table
: NULL
;
331 static struct fdisk_label
*script_get_label(struct fdisk_script
*dp
)
337 dp
->label
= fdisk_get_label(dp
->cxt
,
338 fdisk_script_get_header(dp
, "label"));
339 DBG(SCRIPT
, ul_debugobj(dp
, "label '%s'", dp
->label
? dp
->label
->name
: ""));
345 * fdisk_script_get_nlines:
348 * Returns: number of parsed lines or <0 on error.
350 int fdisk_script_get_nlines(struct fdisk_script
*dp
)
357 * fdisk_script_read_context:
361 * Reads data from the @cxt context (on disk partition table) into the script.
362 * If the context is no specified than defaults to context used for fdisk_new_script().
364 * Return: 0 on success, <0 on error.
366 int fdisk_script_read_context(struct fdisk_script
*dp
, struct fdisk_context
*cxt
)
368 struct fdisk_label
*lb
;
372 if (!dp
|| (!cxt
&& !dp
->cxt
))
378 DBG(SCRIPT
, ul_debugobj(dp
, "reading context into script"));
379 fdisk_reset_script(dp
);
381 lb
= fdisk_get_label(cxt
, NULL
);
385 /* allocate and fill new table */
386 rc
= fdisk_get_partitions(cxt
, &dp
->table
);
390 /* generate headers */
391 rc
= fdisk_script_set_header(dp
, "label", fdisk_label_get_name(lb
));
393 if (!rc
&& fdisk_get_disklabel_id(cxt
, &p
) == 0 && p
) {
394 rc
= fdisk_script_set_header(dp
, "label-id", p
);
397 if (!rc
&& cxt
->dev_path
)
398 rc
= fdisk_script_set_header(dp
, "device", cxt
->dev_path
);
400 rc
= fdisk_script_set_header(dp
, "unit", "sectors");
402 if (!rc
&& fdisk_is_label(cxt
, GPT
)) {
403 struct fdisk_labelitem item
;
407 rc
= fdisk_get_disklabel_item(cxt
, GPT_LABELITEM_FIRSTLBA
, &item
);
409 snprintf(buf
, sizeof(buf
), "%"PRIu64
, item
.data
.num64
);
410 rc
= fdisk_script_set_header(dp
, "first-lba", buf
);
415 rc
= fdisk_get_disklabel_item(cxt
, GPT_LABELITEM_LASTLBA
, &item
);
417 snprintf(buf
, sizeof(buf
), "%"PRIu64
, item
.data
.num64
);
418 rc
= fdisk_script_set_header(dp
, "last-lba", buf
);
423 size_t n
= fdisk_get_npartitions(cxt
);
424 if (n
!= FDISK_GPT_NPARTITIONS_DEFAULT
) {
425 snprintf(buf
, sizeof(buf
), "%zu", n
);
426 rc
= fdisk_script_set_header(dp
, "table-length", buf
);
431 DBG(SCRIPT
, ul_debugobj(dp
, "read context done [rc=%d]", rc
));
436 * fdisk_script_enable_json:
440 * Disable/Enable JSON output format.
442 * Returns: 0 on success, <0 on error.
444 int fdisk_script_enable_json(struct fdisk_script
*dp
, int json
)
452 static void fput_indent(int indent
, FILE *f
)
456 for (i
= 0; i
<= indent
; i
++)
460 static int write_file_json(struct fdisk_script
*dp
, FILE *f
)
463 struct fdisk_partition
*pa
;
464 struct fdisk_iter itr
;
465 const char *devname
= NULL
;
466 int ct
= 0, indent
= 0;
471 DBG(SCRIPT
, ul_debugobj(dp
, "writing json dump to file"));
475 fput_indent(indent
, f
);
476 fputs("\"partitiontable\": {\n", f
);
480 list_for_each(h
, &dp
->headers
) {
481 struct fdisk_scriptheader
*fi
= list_entry(h
, struct fdisk_scriptheader
, headers
);
482 const char *name
= fi
->name
;
485 if (strcmp(name
, "first-lba") == 0) {
488 } else if (strcmp(name
, "last-lba") == 0) {
491 } else if (strcmp(name
, "label-id") == 0)
494 fput_indent(indent
, f
);
495 fputs_quoted_lower(name
, f
);
498 fputs_quoted(fi
->data
, f
);
501 if (!dp
->table
&& fi
== list_last_entry(&dp
->headers
, struct fdisk_scriptheader
, headers
))
506 if (strcmp(name
, "device") == 0)
512 DBG(SCRIPT
, ul_debugobj(dp
, "script table empty"));
516 DBG(SCRIPT
, ul_debugobj(dp
, "%zu entries", fdisk_table_get_nents(dp
->table
)));
518 fput_indent(indent
, f
);
519 fputs("\"partitions\": [\n", f
);
522 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
523 while (fdisk_table_next_partition(dp
->table
, &itr
, &pa
) == 0) {
527 fput_indent(indent
, f
);
530 p
= fdisk_partname(devname
, pa
->partno
+ 1);
532 DBG(SCRIPT
, ul_debugobj(dp
, "write %s entry", p
));
533 fputs("\"node\": ", f
);
537 if (fdisk_partition_has_start(pa
))
538 fprintf(f
, ", \"start\": %ju", (uintmax_t)pa
->start
);
539 if (fdisk_partition_has_size(pa
))
540 fprintf(f
, ", \"size\": %ju", (uintmax_t)pa
->size
);
542 if (pa
->type
&& fdisk_parttype_get_string(pa
->type
))
543 fprintf(f
, ", \"type\": \"%s\"", fdisk_parttype_get_string(pa
->type
));
545 fprintf(f
, ", \"type\": \"%x\"", fdisk_parttype_get_code(pa
->type
));
548 fprintf(f
, ", \"uuid\": \"%s\"", pa
->uuid
);
549 if (pa
->name
&& *pa
->name
) {
550 fputs(", \"name\": ", f
),
551 fputs_quoted(pa
->name
, f
);
554 /* for MBR attr=80 means bootable */
556 struct fdisk_label
*lb
= script_get_label(dp
);
558 if (!lb
|| fdisk_label_get_type(lb
) != FDISK_DISKLABEL_DOS
)
559 fprintf(f
, ", \"attrs\": \"%s\"", pa
->attrs
);
561 if (fdisk_partition_is_bootable(pa
))
562 fprintf(f
, ", \"bootable\": true");
564 if ((size_t)ct
< fdisk_table_get_nents(dp
->table
))
571 fput_indent(indent
, f
);
575 fput_indent(indent
, f
);
578 DBG(SCRIPT
, ul_debugobj(dp
, "write script done"));
582 static int write_file_sfdisk(struct fdisk_script
*dp
, FILE *f
)
585 struct fdisk_partition
*pa
;
586 struct fdisk_iter itr
;
587 const char *devname
= NULL
;
592 DBG(SCRIPT
, ul_debugobj(dp
, "writing sfdisk-like script to file"));
595 list_for_each(h
, &dp
->headers
) {
596 struct fdisk_scriptheader
*fi
= list_entry(h
, struct fdisk_scriptheader
, headers
);
597 fprintf(f
, "%s: %s\n", fi
->name
, fi
->data
);
598 if (strcmp(fi
->name
, "device") == 0)
603 DBG(SCRIPT
, ul_debugobj(dp
, "script table empty"));
607 DBG(SCRIPT
, ul_debugobj(dp
, "%zu entries", fdisk_table_get_nents(dp
->table
)));
611 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
612 while (fdisk_table_next_partition(dp
->table
, &itr
, &pa
) == 0) {
616 p
= fdisk_partname(devname
, pa
->partno
+ 1);
618 DBG(SCRIPT
, ul_debugobj(dp
, "write %s entry", p
));
619 fprintf(f
, "%s :", p
);
621 fprintf(f
, "%zu :", pa
->partno
+ 1);
623 if (fdisk_partition_has_start(pa
))
624 fprintf(f
, " start=%12ju", (uintmax_t)pa
->start
);
625 if (fdisk_partition_has_size(pa
))
626 fprintf(f
, ", size=%12ju", (uintmax_t)pa
->size
);
628 if (pa
->type
&& fdisk_parttype_get_string(pa
->type
))
629 fprintf(f
, ", type=%s", fdisk_parttype_get_string(pa
->type
));
631 fprintf(f
, ", type=%x", fdisk_parttype_get_code(pa
->type
));
634 fprintf(f
, ", uuid=%s", pa
->uuid
);
635 if (pa
->name
&& *pa
->name
)
636 fprintf(f
, ", name=\"%s\"", pa
->name
);
638 /* for MBR attr=80 means bootable */
640 struct fdisk_label
*lb
= script_get_label(dp
);
642 if (!lb
|| fdisk_label_get_type(lb
) != FDISK_DISKLABEL_DOS
)
643 fprintf(f
, ", attrs=\"%s\"", pa
->attrs
);
645 if (fdisk_partition_is_bootable(pa
))
646 fprintf(f
, ", bootable");
650 DBG(SCRIPT
, ul_debugobj(dp
, "write script done"));
655 * fdisk_script_write_file:
659 * Writes script @dp to the ile @f.
661 * Returns: 0 on success, <0 on error.
663 int fdisk_script_write_file(struct fdisk_script
*dp
, FILE *f
)
668 return write_file_json(dp
, f
);
670 return write_file_sfdisk(dp
, f
);
673 static inline int is_header_line(const char *s
)
675 const char *p
= strchr(s
, ':');
677 if (!p
|| p
== s
|| !*(p
+ 1) || strchr(s
, '='))
683 /* parses "<name>: value", note modifies @s*/
684 static int parse_line_header(struct fdisk_script
*dp
, char *s
)
689 DBG(SCRIPT
, ul_debugobj(dp
, " parse header '%s'", s
));
695 value
= strchr(s
, ':');
701 ltrim_whitespace((unsigned char *) name
);
702 rtrim_whitespace((unsigned char *) name
);
703 ltrim_whitespace((unsigned char *) value
);
704 rtrim_whitespace((unsigned char *) value
);
706 if (strcmp(name
, "label") == 0) {
707 if (dp
->cxt
&& !fdisk_get_label(dp
->cxt
, value
))
708 goto done
; /* unknown label name */
709 } else if (strcmp(name
, "unit") == 0) {
710 if (strcmp(value
, "sectors") != 0)
711 goto done
; /* only "sectors" supported */
712 } else if (strcmp(name
, "label-id") == 0
713 || strcmp(name
, "device") == 0
714 || strcmp(name
, "first-lba") == 0
715 || strcmp(name
, "last-lba") == 0
716 || strcmp(name
, "table-length") == 0) {
717 ; /* whatever is posssible */
719 goto done
; /* unknown header */
722 rc
= fdisk_script_set_header(dp
, name
, value
);
725 DBG(SCRIPT
, ul_debugobj(dp
, "header parse error: "
726 "[rc=%d, name='%s', value='%s']",
732 /* returns zero terminated string with next token and @str is updated */
733 static char *next_token(char **str
)
735 char *tk_begin
= NULL
,
741 for (p
= *str
; p
&& *p
; p
++) {
745 tk_begin
= *p
== '"' ? p
+ 1 : p
;
751 if (isblank(*p
) || *p
== ',' || *p
== ';' || *p
== '"' )
753 else if (*(p
+ 1) == '\0')
755 if (tk_begin
&& tk_end
)
761 end
= isblank(*tk_end
) ? (char *) skip_blank(tk_end
) : tk_end
;
762 if (*end
== ',' || *end
== ';')
770 static int next_number(char **s
, uint64_t *num
, int *power
)
780 rc
= parse_size(tk
, (uintmax_t *) num
, power
);
784 static int next_string(char **s
, char **str
)
795 rc
= !*str
? -ENOMEM
: 0;
800 static int partno_from_devname(char *s
)
806 sz
= rtrim_whitespace((unsigned char *)s
);
809 while (p
> s
&& isdigit(*(p
- 1)))
813 pno
= strtol(p
, &end
, 10);
814 if (errno
|| !end
|| p
== end
)
820 * <device>: start=<num>, size=<num>, type=<string>, ...
822 static int parse_line_nameval(struct fdisk_script
*dp
, char *s
)
825 struct fdisk_partition
*pa
;
833 DBG(SCRIPT
, ul_debugobj(dp
, " parse script line: '%s'", s
));
835 pa
= fdisk_new_partition();
839 fdisk_partition_start_follow_default(pa
, 1);
840 fdisk_partition_end_follow_default(pa
, 1);
841 fdisk_partition_partno_follow_default(pa
, 1);
846 if (p
&& (!x
|| p
< x
)) {
850 pno
= partno_from_devname(s
);
852 fdisk_partition_partno_follow_default(pa
, 0);
853 fdisk_partition_set_partno(pa
, pno
);
858 while (rc
== 0 && p
&& *p
) {
860 DBG(SCRIPT
, ul_debugobj(dp
, " parsing '%s'", p
));
861 p
= (char *) skip_blank(p
);
863 if (!strncasecmp(p
, "start=", 6)) {
866 rc
= next_number(&p
, &num
, &pow
);
868 if (pow
) /* specified as <num><suffix> */
869 num
/= dp
->cxt
->sector_size
;
870 fdisk_partition_set_start(pa
, num
);
871 fdisk_partition_start_follow_default(pa
, 0);
873 } else if (!strncasecmp(p
, "size=", 5)) {
877 rc
= next_number(&p
, &num
, &pow
);
879 if (pow
) /* specified as <num><suffix> */
880 num
/= dp
->cxt
->sector_size
;
881 else /* specified as number of sectors */
882 fdisk_partition_size_explicit(pa
, 1);
883 fdisk_partition_set_size(pa
, num
);
884 fdisk_partition_end_follow_default(pa
, 0);
887 } else if (!strncasecmp(p
, "bootable", 8)) {
888 char *tk
= next_token(&p
);
889 if (strcmp(tk
, "bootable") == 0)
894 } else if (!strncasecmp(p
, "attrs=", 6)) {
896 rc
= next_string(&p
, &pa
->attrs
);
898 } else if (!strncasecmp(p
, "uuid=", 5)) {
900 rc
= next_string(&p
, &pa
->uuid
);
902 } else if (!strncasecmp(p
, "name=", 5)) {
904 rc
= next_string(&p
, &pa
->name
);
906 } else if (!strncasecmp(p
, "type=", 5) ||
908 !strncasecmp(p
, "Id=", 3)) { /* backward compatiility */
911 p
+= (*p
== 'I' ? 3 : 5); /* "Id=" or "type=" */
913 rc
= next_string(&p
, &type
);
916 pa
->type
= fdisk_label_parse_parttype(
917 script_get_label(dp
), type
);
922 fdisk_unref_parttype(pa
->type
);
928 DBG(SCRIPT
, ul_debugobj(dp
, "script parse error: unknown field '%s'", p
));
935 rc
= fdisk_table_add_partition(dp
->table
, pa
);
937 DBG(SCRIPT
, ul_debugobj(dp
, "script parse error: [rc=%d]", rc
));
939 fdisk_unref_partition(pa
);
943 /* original sfdisk supports partition types shortcuts like 'L' = Linux native
945 static struct fdisk_parttype
*translate_type_shortcuts(struct fdisk_script
*dp
, char *str
)
947 struct fdisk_label
*lb
;
948 const char *type
= NULL
;
950 if (strlen(str
) != 1)
953 lb
= script_get_label(dp
);
957 if (lb
->id
== FDISK_DISKLABEL_DOS
) {
959 case 'L': /* Linux */
965 case 'E': /* Dos extended */
968 case 'X': /* Linux extended */
971 case 'U': /* UEFI system */
975 } else if (lb
->id
== FDISK_DISKLABEL_GPT
) {
977 case 'L': /* Linux */
978 type
= "0FC63DAF-8483-4772-8E79-3D69D8477DE4";
981 type
= "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F";
984 type
= "933AC7E1-2EB4-4F13-B844-0E14E2AEF915";
986 case 'U': /* UEFI system */
987 type
= "C12A7328-F81F-11D2-BA4B-00A0C93EC93B";
992 return type
? fdisk_label_parse_parttype(lb
, type
) : NULL
;
998 #define alone_sign(_sign, _p) (_sign && (*_p == '\0' || isblank(*_p)))
1001 * <start>, <size>, <type>, <bootable>, ...
1003 static int parse_line_valcommas(struct fdisk_script
*dp
, char *s
)
1007 struct fdisk_partition
*pa
;
1008 enum { ITEM_START
, ITEM_SIZE
, ITEM_TYPE
, ITEM_BOOTABLE
};
1014 pa
= fdisk_new_partition();
1018 fdisk_partition_start_follow_default(pa
, 1);
1019 fdisk_partition_end_follow_default(pa
, 1);
1020 fdisk_partition_partno_follow_default(pa
, 1);
1022 while (rc
== 0 && p
&& *p
) {
1027 p
= (char *) skip_blank(p
);
1030 if (item
!= ITEM_BOOTABLE
) {
1031 sign
= *p
== '-' ? TK_MINUS
: *p
== '+' ? TK_PLUS
: 0;
1036 DBG(SCRIPT
, ul_debugobj(dp
, " parsing item %d ('%s')", item
, p
));
1041 if (*p
== ',' || *p
== ';' || alone_sign(sign
, p
))
1042 fdisk_partition_start_follow_default(pa
, 1);
1046 rc
= next_number(&p
, &num
, &pow
);
1048 if (pow
) /* specified as <num><suffix> */
1049 num
/= dp
->cxt
->sector_size
;
1050 fdisk_partition_set_start(pa
, num
);
1051 pa
->movestart
= sign
== TK_MINUS
? FDISK_MOVE_DOWN
:
1052 sign
== TK_PLUS
? FDISK_MOVE_UP
:
1055 fdisk_partition_start_follow_default(pa
, 0);
1059 if (*p
== ',' || *p
== ';' || alone_sign(sign
, p
)) {
1060 fdisk_partition_end_follow_default(pa
, 1);
1061 if (sign
== TK_PLUS
)
1062 /* alone '+' means use all possible space, elone '-' means nothing */
1063 pa
->resize
= FDISK_RESIZE_ENLARGE
;
1066 rc
= next_number(&p
, &num
, &pow
);
1068 if (pow
) /* specified as <size><suffix> */
1069 num
/= dp
->cxt
->sector_size
;
1070 else /* specified as number of sectors */
1071 fdisk_partition_size_explicit(pa
, 1);
1072 fdisk_partition_set_size(pa
, num
);
1073 pa
->resize
= sign
== TK_MINUS
? FDISK_RESIZE_REDUCE
:
1074 sign
== TK_PLUS
? FDISK_RESIZE_ENLARGE
:
1077 fdisk_partition_end_follow_default(pa
, 0);
1081 if (*p
== ',' || *p
== ';' || alone_sign(sign
, p
))
1082 break; /* use default type */
1084 rc
= next_string(&p
, &str
);
1088 pa
->type
= translate_type_shortcuts(dp
, str
);
1090 pa
->type
= fdisk_label_parse_parttype(
1091 script_get_label(dp
), str
);
1096 fdisk_unref_parttype(pa
->type
);
1102 if (*p
== ',' || *p
== ';')
1105 char *tk
= next_token(&p
);
1106 if (tk
&& *tk
== '*' && *(tk
+ 1) == '\0')
1108 else if (tk
&& *tk
== '-' && *(tk
+ 1) == '\0')
1110 else if (tk
&& *tk
== '+' && *(tk
+ 1) == '\0')
1125 rc
= fdisk_table_add_partition(dp
->table
, pa
);
1127 DBG(SCRIPT
, ul_debugobj(dp
, "script parse error: [rc=%d]", rc
));
1129 fdisk_unref_partition(pa
);
1134 static int fdisk_script_read_buffer(struct fdisk_script
*dp
, char *s
)
1141 DBG(SCRIPT
, ul_debugobj(dp
, " parsing buffer"));
1143 s
= (char *) skip_blank(s
);
1145 return 0; /* nothing baby, ignore */
1148 dp
->table
= fdisk_new_table();
1153 /* parse header lines only if no partition specified yet */
1154 if (fdisk_table_is_empty(dp
->table
) && is_header_line(s
))
1155 rc
= parse_line_header(dp
, s
);
1157 /* parse script format */
1158 else if (strchr(s
, '='))
1159 rc
= parse_line_nameval(dp
, s
);
1161 /* parse simple <value>, ... format */
1163 rc
= parse_line_valcommas(dp
, s
);
1166 DBG(SCRIPT
, ul_debugobj(dp
, "%zu: parse error [rc=%d]",
1172 * fdisk_script_set_fgets:
1174 * @fn_fgets: callback function
1176 * The library uses fgets() function to read the next line from the script.
1177 * This default maybe overrided to another function. Note that the function has
1178 * to return the line terminated by \n (for example readline(3) removes \n).
1180 * Return: 0 on success, <0 on error
1182 int fdisk_script_set_fgets(struct fdisk_script
*dp
,
1183 char *(*fn_fgets
)(struct fdisk_script
*, char *, size_t, FILE *))
1187 dp
->fn_fgets
= fn_fgets
;
1192 * fdisk_script_read_line:
1195 * @buf: buffer to store one line of the file
1196 * @bufsz: buffer size
1198 * Reads next line into dump.
1200 * Returns: 0 on success, <0 on error, 1 when nothing to read.
1202 int fdisk_script_read_line(struct fdisk_script
*dp
, FILE *f
, char *buf
, size_t bufsz
)
1209 DBG(SCRIPT
, ul_debugobj(dp
, " parsing line %zu", dp
->nlines
));
1211 /* read the next non-blank non-comment line */
1214 if (dp
->fn_fgets(dp
, buf
, bufsz
, f
) == NULL
)
1216 } else if (fgets(buf
, bufsz
, f
) == NULL
)
1220 s
= strchr(buf
, '\n');
1222 /* Missing final newline? Otherwise an extremely */
1223 /* long line - assume file was corrupted */
1225 DBG(SCRIPT
, ul_debugobj(dp
, "no final newline"));
1226 s
= strchr(buf
, '\0');
1228 DBG(SCRIPT
, ul_debugobj(dp
,
1229 "%zu: missing newline at line", dp
->nlines
));
1235 if (--s
>= buf
&& *s
== '\r')
1237 s
= (char *) skip_blank(buf
);
1238 } while (*s
== '\0' || *s
== '#');
1240 return fdisk_script_read_buffer(dp
, s
);
1245 * fdisk_script_read_file:
1249 * Reads file @f into script @dp.
1251 * Returns: 0 on success, <0 on error.
1253 int fdisk_script_read_file(struct fdisk_script
*dp
, FILE *f
)
1261 DBG(SCRIPT
, ul_debugobj(dp
, "parsing file"));
1264 rc
= fdisk_script_read_line(dp
, f
, buf
, sizeof(buf
));
1270 rc
= 0; /* end of file */
1272 DBG(SCRIPT
, ul_debugobj(dp
, "parsing file done [rc=%d]", rc
));
1279 * @dp: script (or NULL to remove previous reference)
1281 * Sets reference to the @dp script and remove reference to the previously used
1284 * The script headers might be used by label drivers to overwrite
1285 * built-in defaults (for example disk label Id) and label driver might
1286 * optimize the default semantic to be more usable for scripts (for example to
1287 * not ask for primary/logical/extended partition type).
1289 * Note that script also contains reference to the fdisk context (see
1290 * fdisk_new_script()). This context may be completely independent on
1291 * context used for fdisk_set_script().
1293 * Returns: <0 on error, 0 on success.
1295 int fdisk_set_script(struct fdisk_context
*cxt
, struct fdisk_script
*dp
)
1301 fdisk_unref_script(cxt
->script
);
1306 DBG(CXT
, ul_debugobj(cxt
, "setting reference to script %p", cxt
->script
));
1307 fdisk_ref_script(cxt
->script
);
1317 * Returns: the current script or NULL.
1319 struct fdisk_script
*fdisk_get_script(struct fdisk_context
*cxt
)
1326 * fdisk_apply_script_headers:
1330 * Associte context @cxt with script @dp and creates a new empty disklabel.
1332 * Returns: 0 on success, <0 on error.
1334 int fdisk_apply_script_headers(struct fdisk_context
*cxt
, struct fdisk_script
*dp
)
1343 DBG(SCRIPT
, ul_debugobj(dp
, "applying script headers"));
1344 fdisk_set_script(cxt
, dp
);
1346 /* create empty label */
1347 name
= fdisk_script_get_header(dp
, "label");
1351 rc
= fdisk_create_disklabel(cxt
, name
);
1355 str
= fdisk_script_get_header(dp
, "table-length");
1359 rc
= parse_size(str
, &sz
, NULL
);
1361 rc
= fdisk_gpt_set_npartitions(cxt
, sz
);
1368 * fdisk_apply_script:
1372 * This function creates a new disklabel and partition within context @cxt. You
1373 * have to call fdisk_write_disklabel() to apply changes to the device.
1375 * Returns: 0 on error, <0 on error.
1377 int fdisk_apply_script(struct fdisk_context
*cxt
, struct fdisk_script
*dp
)
1380 struct fdisk_script
*old
;
1385 DBG(CXT
, ul_debugobj(cxt
, "applying script %p", dp
));
1387 old
= fdisk_get_script(cxt
);
1388 fdisk_ref_script(old
);
1390 /* create empty disk label */
1391 rc
= fdisk_apply_script_headers(cxt
, dp
);
1393 /* create partitions */
1394 if (!rc
&& dp
->table
)
1395 rc
= fdisk_apply_table(cxt
, dp
->table
);
1397 fdisk_set_script(cxt
, old
);
1398 fdisk_unref_script(old
);
1400 DBG(CXT
, ul_debugobj(cxt
, "script done [rc=%d]", rc
));
1405 static int test_dump(struct fdisk_test
*ts
, int argc
, char *argv
[])
1407 char *devname
= argv
[1];
1408 struct fdisk_context
*cxt
;
1409 struct fdisk_script
*dp
;
1411 cxt
= fdisk_new_context();
1412 fdisk_assign_device(cxt
, devname
, 1);
1414 dp
= fdisk_new_script(cxt
);
1415 fdisk_script_read_context(dp
, NULL
);
1417 fdisk_script_write_file(dp
, stdout
);
1418 fdisk_unref_script(dp
);
1419 fdisk_unref_context(cxt
);
1424 static int test_read(struct fdisk_test
*ts
, int argc
, char *argv
[])
1426 char *filename
= argv
[1];
1427 struct fdisk_script
*dp
;
1428 struct fdisk_context
*cxt
;
1431 if (!(f
= fopen(filename
, "r")))
1432 err(EXIT_FAILURE
, "%s: cannot open", filename
);
1434 cxt
= fdisk_new_context();
1435 dp
= fdisk_new_script(cxt
);
1437 fdisk_script_read_file(dp
, f
);
1440 fdisk_script_write_file(dp
, stdout
);
1441 fdisk_unref_script(dp
);
1442 fdisk_unref_context(cxt
);
1447 static int test_stdin(struct fdisk_test
*ts
, int argc
, char *argv
[])
1450 struct fdisk_script
*dp
;
1451 struct fdisk_context
*cxt
;
1454 cxt
= fdisk_new_context();
1455 dp
= fdisk_new_script(cxt
);
1456 fdisk_script_set_header(dp
, "label", "dos");
1458 printf("<start>, <size>, <type>, <bootable: *|->\n");
1460 struct fdisk_partition
*pa
;
1461 size_t n
= fdisk_table_get_nents(dp
->table
);
1463 printf(" #%zu :\n", n
+ 1);
1464 rc
= fdisk_script_read_line(dp
, stdin
, buf
, sizeof(buf
));
1467 pa
= fdisk_table_get_partition(dp
->table
, n
);
1468 printf(" #%zu %12ju %12ju\n", n
+ 1,
1469 (uintmax_t)fdisk_partition_get_start(pa
),
1470 (uintmax_t)fdisk_partition_get_size(pa
));
1475 fdisk_script_write_file(dp
, stdout
);
1476 fdisk_unref_script(dp
);
1477 fdisk_unref_context(cxt
);
1482 static int test_apply(struct fdisk_test
*ts
, int argc
, char *argv
[])
1484 char *devname
= argv
[1], *scriptname
= argv
[2];
1485 struct fdisk_context
*cxt
;
1486 struct fdisk_script
*dp
= NULL
;
1487 struct fdisk_table
*tb
= NULL
;
1488 struct fdisk_iter
*itr
= NULL
;
1489 struct fdisk_partition
*pa
= NULL
;
1492 cxt
= fdisk_new_context();
1493 fdisk_assign_device(cxt
, devname
, 0);
1495 dp
= fdisk_new_script_from_file(cxt
, scriptname
);
1499 rc
= fdisk_apply_script(cxt
, dp
);
1502 fdisk_unref_script(dp
);
1505 fdisk_list_disklabel(cxt
);
1506 fdisk_get_partitions(cxt
, &tb
);
1508 itr
= fdisk_new_iter(FDISK_ITER_FORWARD
);
1509 while (fdisk_table_next_partition(tb
, itr
, &pa
) == 0) {
1510 printf(" #%zu %12ju %12ju\n", fdisk_partition_get_partno(pa
),
1511 (uintmax_t)fdisk_partition_get_start(pa
),
1512 (uintmax_t)fdisk_partition_get_size(pa
));
1516 fdisk_free_iter(itr
);
1517 fdisk_unref_table(tb
);
1519 /*fdisk_write_disklabel(cxt);*/
1520 fdisk_unref_context(cxt
);
1524 int main(int argc
, char *argv
[])
1526 struct fdisk_test tss
[] = {
1527 { "--dump", test_dump
, "<device> dump PT as script" },
1528 { "--read", test_read
, "<file> read PT script from file" },
1529 { "--apply", test_apply
, "<device> <file> try apply script from file to device" },
1530 { "--stdin", test_stdin
, " read input like sfdisk" },
1534 return fdisk_run_test(tss
, argc
, argv
);