]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libfdisk/src/script.c
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_script
*dp
, 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(dp
, 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
;
274 fi
= script_get_header(dp
, name
);
276 return 0; /* want to remove header that does not exist, success */
279 DBG(SCRIPT
, ul_debugobj(dp
, "freeing header %s", name
));
281 /* no data, remove the header */
282 fdisk_script_free_header(dp
, fi
);
287 DBG(SCRIPT
, ul_debugobj(dp
, "setting new header %s='%s'", name
, data
));
290 fi
= calloc(1, sizeof(*fi
));
293 INIT_LIST_HEAD(&fi
->headers
);
294 fi
->name
= strdup(name
);
295 fi
->data
= strdup(data
);
296 if (!fi
->data
|| !fi
->name
) {
297 fdisk_script_free_header(dp
, fi
);
300 list_add_tail(&fi
->headers
, &dp
->headers
);
302 /* update existing */
303 char *x
= strdup(data
);
305 DBG(SCRIPT
, ul_debugobj(dp
, "update '%s' header '%s' -> '%s'", name
, fi
->data
, data
));
313 if (strcmp(name
, "label") == 0)
320 * fdisk_script_get_table:
323 * The table (container with partitions) is possible to create by
324 * fdisk_script_read_context() or fdisk_script_read_file(), otherwise
325 * this function returns NULL.
327 * Returns: NULL or script.
329 struct fdisk_table
*fdisk_script_get_table(struct fdisk_script
*dp
)
332 return dp
? dp
->table
: NULL
;
335 static struct fdisk_label
*script_get_label(struct fdisk_script
*dp
)
341 dp
->label
= fdisk_get_label(dp
->cxt
,
342 fdisk_script_get_header(dp
, "label"));
343 DBG(SCRIPT
, ul_debugobj(dp
, "label '%s'", dp
->label
? dp
->label
->name
: ""));
349 * fdisk_script_get_nlines:
352 * Returns: number of parsed lines or <0 on error.
354 int fdisk_script_get_nlines(struct fdisk_script
*dp
)
361 * fdisk_script_read_context:
365 * Reads data from the @cxt context (on disk partition table) into the script.
366 * If the context is no specified than defaults to context used for fdisk_new_script().
368 * Return: 0 on success, <0 on error.
370 int fdisk_script_read_context(struct fdisk_script
*dp
, struct fdisk_context
*cxt
)
372 struct fdisk_label
*lb
;
384 DBG(SCRIPT
, ul_debugobj(dp
, "reading context into script"));
385 fdisk_reset_script(dp
);
387 lb
= fdisk_get_label(cxt
, NULL
);
391 /* allocate and fill new table */
392 rc
= fdisk_get_partitions(cxt
, &dp
->table
);
396 /* generate headers */
397 rc
= fdisk_script_set_header(dp
, "label", fdisk_label_get_name(lb
));
399 if (!rc
&& fdisk_get_disklabel_id(cxt
, &p
) == 0 && p
) {
400 rc
= fdisk_script_set_header(dp
, "label-id", p
);
403 if (!rc
&& cxt
->dev_path
)
404 rc
= fdisk_script_set_header(dp
, "device", cxt
->dev_path
);
406 rc
= fdisk_script_set_header(dp
, "unit", "sectors");
408 if (!rc
&& fdisk_is_label(cxt
, GPT
)) {
409 struct fdisk_labelitem item
;
412 rc
= fdisk_get_disklabel_item(cxt
, GPT_LABELITEM_FIRSTLBA
, &item
);
414 snprintf(buf
, sizeof(buf
), "%ju", item
.data
.num64
);
415 rc
= fdisk_script_set_header(dp
, "first-lba", buf
);
420 rc
= fdisk_get_disklabel_item(cxt
, GPT_LABELITEM_LASTLBA
, &item
);
422 snprintf(buf
, sizeof(buf
), "%ju", item
.data
.num64
);
423 rc
= fdisk_script_set_header(dp
, "last-lba", buf
);
430 DBG(SCRIPT
, ul_debugobj(dp
, "read context done [rc=%d]", rc
));
435 * fdisk_script_enable_json:
439 * Disable/Enable JSON output format.
441 * Returns: 0 on success, <0 on error.
443 int fdisk_script_enable_json(struct fdisk_script
*dp
, int json
)
451 static void fput_indent(int indent
, FILE *f
)
455 for (i
= 0; i
<= indent
; i
++)
459 static int write_file_json(struct fdisk_script
*dp
, FILE *f
)
462 struct fdisk_partition
*pa
;
463 struct fdisk_iter itr
;
464 const char *devname
= NULL
;
465 int ct
= 0, indent
= 0;
470 DBG(SCRIPT
, ul_debugobj(dp
, "writing json dump to file"));
474 fput_indent(indent
, f
);
475 fputs("\"partitiontable\": {\n", f
);
479 list_for_each(h
, &dp
->headers
) {
480 struct fdisk_scriptheader
*fi
= list_entry(h
, struct fdisk_scriptheader
, headers
);
481 const char *name
= fi
->name
;
484 if (strcmp(name
, "first-lba") == 0) {
487 } else if (strcmp(name
, "last-lba") == 0) {
490 } else if (strcmp(name
, "label-id") == 0)
493 fput_indent(indent
, f
);
494 fputs_quoted_lower(name
, f
);
497 fputs_quoted(fi
->data
, f
);
500 if (!dp
->table
&& fi
== list_last_entry(&dp
->headers
, struct fdisk_scriptheader
, headers
))
505 if (strcmp(name
, "device") == 0)
511 DBG(SCRIPT
, ul_debugobj(dp
, "script table empty"));
515 DBG(SCRIPT
, ul_debugobj(dp
, "%zu entries", fdisk_table_get_nents(dp
->table
)));
517 fput_indent(indent
, f
);
518 fputs("\"partitions\": [\n", f
);
521 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
522 while (fdisk_table_next_partition(dp
->table
, &itr
, &pa
) == 0) {
526 fput_indent(indent
, f
);
529 p
= fdisk_partname(devname
, pa
->partno
+ 1);
531 DBG(SCRIPT
, ul_debugobj(dp
, "write %s entry", p
));
532 fputs("\"node\": ", f
);
536 if (fdisk_partition_has_start(pa
))
537 fprintf(f
, ", \"start\": %ju", pa
->start
);
538 if (fdisk_partition_has_size(pa
))
539 fprintf(f
, ", \"size\": %ju", pa
->size
);
541 if (pa
->type
&& fdisk_parttype_get_string(pa
->type
))
542 fprintf(f
, ", \"type\": \"%s\"", fdisk_parttype_get_string(pa
->type
));
544 fprintf(f
, ", \"type\": \"%x\"", fdisk_parttype_get_code(pa
->type
));
547 fprintf(f
, ", \"uuid\": \"%s\"", pa
->uuid
);
548 if (pa
->name
&& *pa
->name
) {
549 fputs(", \"name\": ", f
),
550 fputs_quoted(pa
->name
, f
);
553 /* for MBR attr=80 means bootable */
555 struct fdisk_label
*lb
= script_get_label(dp
);
557 if (!lb
|| fdisk_label_get_type(lb
) != FDISK_DISKLABEL_DOS
)
558 fprintf(f
, ", \"attrs\": \"%s\"", pa
->attrs
);
560 if (fdisk_partition_is_bootable(pa
))
561 fprintf(f
, ", \"bootable\": true");
563 if (ct
< fdisk_table_get_nents(dp
->table
))
570 fput_indent(indent
, f
);
574 fput_indent(indent
, f
);
577 DBG(SCRIPT
, ul_debugobj(dp
, "write script done"));
581 static int write_file_sfdisk(struct fdisk_script
*dp
, FILE *f
)
584 struct fdisk_partition
*pa
;
585 struct fdisk_iter itr
;
586 const char *devname
= NULL
;
591 DBG(SCRIPT
, ul_debugobj(dp
, "writing sfdisk-like script to file"));
594 list_for_each(h
, &dp
->headers
) {
595 struct fdisk_scriptheader
*fi
= list_entry(h
, struct fdisk_scriptheader
, headers
);
596 fprintf(f
, "%s: %s\n", fi
->name
, fi
->data
);
597 if (strcmp(fi
->name
, "device") == 0)
602 DBG(SCRIPT
, ul_debugobj(dp
, "script table empty"));
606 DBG(SCRIPT
, ul_debugobj(dp
, "%zu entries", fdisk_table_get_nents(dp
->table
)));
610 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
611 while (fdisk_table_next_partition(dp
->table
, &itr
, &pa
) == 0) {
615 p
= fdisk_partname(devname
, pa
->partno
+ 1);
617 DBG(SCRIPT
, ul_debugobj(dp
, "write %s entry", p
));
618 fprintf(f
, "%s :", p
);
620 fprintf(f
, "%zu :", pa
->partno
+ 1);
622 if (fdisk_partition_has_start(pa
))
623 fprintf(f
, " start=%12ju", pa
->start
);
624 if (fdisk_partition_has_size(pa
))
625 fprintf(f
, ", size=%12ju", pa
->size
);
627 if (pa
->type
&& fdisk_parttype_get_string(pa
->type
))
628 fprintf(f
, ", type=%s", fdisk_parttype_get_string(pa
->type
));
630 fprintf(f
, ", type=%x", fdisk_parttype_get_code(pa
->type
));
633 fprintf(f
, ", uuid=%s", pa
->uuid
);
634 if (pa
->name
&& *pa
->name
)
635 fprintf(f
, ", name=\"%s\"", pa
->name
);
637 /* for MBR attr=80 means bootable */
639 struct fdisk_label
*lb
= script_get_label(dp
);
641 if (!lb
|| fdisk_label_get_type(lb
) != FDISK_DISKLABEL_DOS
)
642 fprintf(f
, ", attrs=\"%s\"", pa
->attrs
);
644 if (fdisk_partition_is_bootable(pa
))
645 fprintf(f
, ", bootable");
649 DBG(SCRIPT
, ul_debugobj(dp
, "write script done"));
654 * fdisk_script_write_file:
658 * Writes script @dp to the ile @f.
660 * Returns: 0 on success, <0 on error.
662 int fdisk_script_write_file(struct fdisk_script
*dp
, FILE *f
)
667 return write_file_json(dp
, f
);
669 return write_file_sfdisk(dp
, f
);
672 static inline int is_header_line(const char *s
)
674 const char *p
= strchr(s
, ':');
676 if (!p
|| p
== s
|| !*(p
+ 1) || strchr(s
, '='))
682 /* parses "<name>: value", note modifies @s*/
683 static int parse_line_header(struct fdisk_script
*dp
, char *s
)
688 DBG(SCRIPT
, ul_debugobj(dp
, " parse header '%s'", s
));
694 value
= strchr(s
, ':');
700 ltrim_whitespace((unsigned char *) name
);
701 rtrim_whitespace((unsigned char *) name
);
702 ltrim_whitespace((unsigned char *) value
);
703 rtrim_whitespace((unsigned char *) value
);
705 if (strcmp(name
, "label") == 0) {
706 if (dp
->cxt
&& !fdisk_get_label(dp
->cxt
, value
))
707 goto done
; /* unknown label name */
708 } else if (strcmp(name
, "unit") == 0) {
709 if (strcmp(value
, "sectors") != 0)
710 goto done
; /* only "sectors" supported */
711 } else if (strcmp(name
, "label-id") == 0
712 || strcmp(name
, "device") == 0
713 || strcmp(name
, "first-lba") == 0
714 || strcmp(name
, "last-lba") == 0) {
715 ; /* whatever is posssible */
717 goto done
; /* unknown header */
720 rc
= fdisk_script_set_header(dp
, name
, value
);
723 DBG(SCRIPT
, ul_debugobj(dp
, "header parse error: "
724 "[rc=%d, name='%s', value='%s']",
730 /* returns zero terminated string with next token and @str is updated */
731 static char *next_token(char **str
)
733 char *tk_begin
= NULL
,
739 for (p
= *str
; p
&& *p
; p
++) {
743 tk_begin
= *p
== '"' ? p
+ 1 : p
;
749 if (isblank(*p
) || *p
== ',' || *p
== ';' || *p
== '"' )
751 else if (*(p
+ 1) == '\0')
753 if (tk_begin
&& tk_end
)
759 end
= isblank(*tk_end
) ? (char *) skip_blank(tk_end
) : tk_end
;
760 if (*end
== ',' || *end
== ';')
768 static int next_number(char **s
, uint64_t *num
, int *power
)
778 rc
= parse_size(tk
, (uintmax_t *) num
, power
);
782 static int next_string(char **s
, char **str
)
793 rc
= !*str
? -ENOMEM
: 0;
798 static int partno_from_devname(char *s
)
804 sz
= rtrim_whitespace((unsigned char *)s
);
807 while (p
> s
&& isdigit(*(p
- 1)))
811 pno
= strtol(p
, &end
, 10);
812 if (errno
|| !end
|| p
== end
)
818 * <device>: start=<num>, size=<num>, type=<string>, ...
820 static int parse_line_nameval(struct fdisk_script
*dp
, char *s
)
823 struct fdisk_partition
*pa
;
831 DBG(SCRIPT
, ul_debugobj(dp
, " parse script line: '%s'", s
));
833 pa
= fdisk_new_partition();
837 fdisk_partition_start_follow_default(pa
, 1);
838 fdisk_partition_end_follow_default(pa
, 1);
839 fdisk_partition_partno_follow_default(pa
, 1);
844 if (p
&& (!x
|| p
< x
)) {
848 pno
= partno_from_devname(s
);
850 fdisk_partition_partno_follow_default(pa
, 0);
851 fdisk_partition_set_partno(pa
, pno
);
856 while (rc
== 0 && p
&& *p
) {
858 DBG(SCRIPT
, ul_debugobj(dp
, " parsing '%s'", p
));
859 p
= (char *) skip_blank(p
);
861 if (!strncasecmp(p
, "start=", 6)) {
864 rc
= next_number(&p
, &num
, &pow
);
866 if (pow
) /* specified as <num><suffix> */
867 num
/= dp
->cxt
->sector_size
;
868 fdisk_partition_set_start(pa
, num
);
869 fdisk_partition_start_follow_default(pa
, 0);
871 } else if (!strncasecmp(p
, "size=", 5)) {
875 rc
= next_number(&p
, &num
, &pow
);
877 if (pow
) /* specified as <num><suffix> */
878 num
/= dp
->cxt
->sector_size
;
879 else /* specified as number of sectors */
880 fdisk_partition_size_explicit(pa
, 1);
881 fdisk_partition_set_size(pa
, num
);
882 fdisk_partition_end_follow_default(pa
, 0);
885 } else if (!strncasecmp(p
, "bootable", 8)) {
886 char *tk
= next_token(&p
);
887 if (strcmp(tk
, "bootable") == 0)
892 } else if (!strncasecmp(p
, "attrs=", 6)) {
894 rc
= next_string(&p
, &pa
->attrs
);
896 } else if (!strncasecmp(p
, "uuid=", 5)) {
898 rc
= next_string(&p
, &pa
->uuid
);
900 } else if (!strncasecmp(p
, "name=", 5)) {
902 rc
= next_string(&p
, &pa
->name
);
904 } else if (!strncasecmp(p
, "type=", 5) ||
906 !strncasecmp(p
, "Id=", 3)) { /* backward compatiility */
909 p
+= (*p
== 'I' ? 3 : 5); /* "Id=" or "type=" */
911 rc
= next_string(&p
, &type
);
914 pa
->type
= fdisk_label_parse_parttype(
915 script_get_label(dp
), type
);
920 fdisk_unref_parttype(pa
->type
);
926 DBG(SCRIPT
, ul_debugobj(dp
, "script parse error: unknown field '%s'", p
));
933 rc
= fdisk_table_add_partition(dp
->table
, pa
);
935 DBG(SCRIPT
, ul_debugobj(dp
, "script parse error: [rc=%d]", rc
));
937 fdisk_unref_partition(pa
);
941 /* original sfdisk supports partition types shortcuts like 'L' = Linux native
943 static struct fdisk_parttype
*translate_type_shortcuts(struct fdisk_script
*dp
, char *str
)
945 struct fdisk_label
*lb
;
946 const char *type
= NULL
;
948 if (strlen(str
) != 1)
951 lb
= script_get_label(dp
);
955 if (lb
->id
== FDISK_DISKLABEL_DOS
) {
957 case 'L': /* Linux */
963 case 'E': /* Dos extended */
966 case 'X': /* Linux extended */
970 } else if (lb
->id
== FDISK_DISKLABEL_GPT
) {
972 case 'L': /* Linux */
973 type
= "0FC63DAF-8483-4772-8E79-3D69D8477DE4";
976 type
= "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F";
979 type
= "933AC7E1-2EB4-4F13-B844-0E14E2AEF915";
984 return type
? fdisk_label_parse_parttype(lb
, type
) : NULL
;
990 #define alone_sign(_sign, _p) (_sign && (*_p == '\0' || isblank(*_p)))
993 * <start>, <size>, <type>, <bootable>, ...
995 static int parse_line_valcommas(struct fdisk_script
*dp
, char *s
)
999 struct fdisk_partition
*pa
;
1000 enum { ITEM_START
, ITEM_SIZE
, ITEM_TYPE
, ITEM_BOOTABLE
};
1006 pa
= fdisk_new_partition();
1010 fdisk_partition_start_follow_default(pa
, 1);
1011 fdisk_partition_end_follow_default(pa
, 1);
1012 fdisk_partition_partno_follow_default(pa
, 1);
1014 while (rc
== 0 && p
&& *p
) {
1019 p
= (char *) skip_blank(p
);
1022 if (item
!= ITEM_BOOTABLE
) {
1023 sign
= *p
== '-' ? TK_MINUS
: *p
== '+' ? TK_PLUS
: 0;
1028 DBG(SCRIPT
, ul_debugobj(dp
, " parsing item %d ('%s')", item
, p
));
1033 if (*p
== ',' || *p
== ';' || alone_sign(sign
, p
))
1034 fdisk_partition_start_follow_default(pa
, 1);
1038 rc
= next_number(&p
, &num
, &pow
);
1040 if (pow
) /* specified as <num><suffix> */
1041 num
/= dp
->cxt
->sector_size
;
1042 fdisk_partition_set_start(pa
, num
);
1043 pa
->movestart
= sign
== TK_MINUS
? FDISK_MOVE_DOWN
:
1044 sign
== TK_PLUS
? FDISK_MOVE_UP
:
1047 fdisk_partition_start_follow_default(pa
, 0);
1051 if (*p
== ',' || *p
== ';' || alone_sign(sign
, p
)) {
1052 fdisk_partition_end_follow_default(pa
, 1);
1053 if (sign
== TK_PLUS
)
1054 /* alone '+' means use all possible space, elone '-' means nothing */
1055 pa
->resize
= FDISK_RESIZE_ENLARGE
;
1058 rc
= next_number(&p
, &num
, &pow
);
1060 if (pow
) /* specified as <size><suffix> */
1061 num
/= dp
->cxt
->sector_size
;
1062 else /* specified as number of sectors */
1063 fdisk_partition_size_explicit(pa
, 1);
1064 fdisk_partition_set_size(pa
, num
);
1065 pa
->resize
= sign
== TK_MINUS
? FDISK_RESIZE_REDUCE
:
1066 sign
== TK_PLUS
? FDISK_RESIZE_ENLARGE
:
1069 fdisk_partition_end_follow_default(pa
, 0);
1073 if (*p
== ',' || *p
== ';' || alone_sign(sign
, p
))
1074 break; /* use default type */
1076 rc
= next_string(&p
, &str
);
1080 pa
->type
= translate_type_shortcuts(dp
, str
);
1082 pa
->type
= fdisk_label_parse_parttype(
1083 script_get_label(dp
), str
);
1088 fdisk_unref_parttype(pa
->type
);
1094 if (*p
== ',' || *p
== ';')
1097 char *tk
= next_token(&p
);
1098 if (tk
&& *tk
== '*' && *(tk
+ 1) == '\0')
1100 else if (tk
&& *tk
== '-' && *(tk
+ 1) == '\0')
1102 else if (tk
&& *tk
== '+' && *(tk
+ 1) == '\0')
1117 rc
= fdisk_table_add_partition(dp
->table
, pa
);
1119 DBG(SCRIPT
, ul_debugobj(dp
, "script parse error: [rc=%d]", rc
));
1121 fdisk_unref_partition(pa
);
1126 int fdisk_script_read_buffer(struct fdisk_script
*dp
, char *s
)
1133 DBG(SCRIPT
, ul_debugobj(dp
, " parsing buffer"));
1135 s
= (char *) skip_blank(s
);
1137 return 0; /* nothing baby, ignore */
1140 dp
->table
= fdisk_new_table();
1145 /* parse header lines only if no partition specified yet */
1146 if (fdisk_table_is_empty(dp
->table
) && is_header_line(s
))
1147 rc
= parse_line_header(dp
, s
);
1149 /* parse script format */
1150 else if (strchr(s
, '='))
1151 rc
= parse_line_nameval(dp
, s
);
1153 /* parse simple <value>, ... format */
1155 rc
= parse_line_valcommas(dp
, s
);
1158 DBG(SCRIPT
, ul_debugobj(dp
, "%zu: parse error [rc=%d]",
1164 * fdisk_script_set_fgets:
1166 * @fn_fgets: callback function
1168 * The library uses fgets() function to read the next line from the script.
1169 * This default maybe overrided to another function. Note that the function has
1170 * to return the line terminated by \n (for example readline(3) removes \n).
1172 * Return: 0 on success, <0 on error
1174 int fdisk_script_set_fgets(struct fdisk_script
*dp
,
1175 char *(*fn_fgets
)(struct fdisk_script
*, char *, size_t, FILE *))
1179 dp
->fn_fgets
= fn_fgets
;
1184 * fdisk_script_read_line:
1187 * @buf: buffer to store one line of the file
1188 * @bufsz: buffer size
1190 * Reads next line into dump.
1192 * Returns: 0 on success, <0 on error, 1 when nothing to read.
1194 int fdisk_script_read_line(struct fdisk_script
*dp
, FILE *f
, char *buf
, size_t bufsz
)
1201 DBG(SCRIPT
, ul_debugobj(dp
, " parsing line %zu", dp
->nlines
));
1203 /* read the next non-blank non-comment line */
1206 if (dp
->fn_fgets(dp
, buf
, bufsz
, f
) == NULL
)
1208 } else if (fgets(buf
, bufsz
, f
) == NULL
)
1212 s
= strchr(buf
, '\n');
1214 /* Missing final newline? Otherwise an extremely */
1215 /* long line - assume file was corrupted */
1217 DBG(SCRIPT
, ul_debugobj(dp
, "no final newline"));
1218 s
= strchr(buf
, '\0');
1220 DBG(SCRIPT
, ul_debugobj(dp
,
1221 "%zu: missing newline at line", dp
->nlines
));
1227 if (--s
>= buf
&& *s
== '\r')
1229 s
= (char *) skip_blank(buf
);
1230 } while (*s
== '\0' || *s
== '#');
1232 return fdisk_script_read_buffer(dp
, s
);
1237 * fdisk_script_read_file:
1241 * Reads file @f into script @dp.
1243 * Returns: 0 on success, <0 on error.
1245 int fdisk_script_read_file(struct fdisk_script
*dp
, FILE *f
)
1253 DBG(SCRIPT
, ul_debugobj(dp
, "parsing file"));
1256 rc
= fdisk_script_read_line(dp
, f
, buf
, sizeof(buf
));
1262 rc
= 0; /* end of file */
1264 DBG(SCRIPT
, ul_debugobj(dp
, "parsing file done [rc=%d]", rc
));
1271 * @dp: script (or NULL to remove previous reference)
1273 * Sets reference to the @dp script. The script headers might be used by label
1274 * drivers to overwrite built-in defaults (for example disk label Id) and label
1275 * driver might optimize the default semantic to be more usable for scripts
1276 * (for example to not ask for primary/logical/extended partition type).
1278 * Note that script also contains reference to the fdisk context (see
1279 * fdisk_new_script()). This context may be completely independent on
1280 * context used for fdisk_set_script().
1282 * Returns: <0 on error, 0 on success.
1284 int fdisk_set_script(struct fdisk_context
*cxt
, struct fdisk_script
*dp
)
1290 fdisk_unref_script(cxt
->script
);
1295 DBG(CXT
, ul_debugobj(cxt
, "setting reference to script %p", cxt
->script
));
1296 fdisk_ref_script(cxt
->script
);
1306 * Returns: the current script or NULL.
1308 struct fdisk_script
*fdisk_get_script(struct fdisk_context
*cxt
)
1315 * fdisk_apply_script_headers:
1319 * Associte context @cxt with script @dp and creates a new empty disklabel.
1321 * Returns: 0 on success, <0 on error.
1323 int fdisk_apply_script_headers(struct fdisk_context
*cxt
, struct fdisk_script
*dp
)
1330 DBG(SCRIPT
, ul_debugobj(dp
, "applying script headers"));
1331 fdisk_set_script(cxt
, dp
);
1333 /* create empty label */
1334 name
= fdisk_script_get_header(dp
, "label");
1338 return fdisk_create_disklabel(cxt
, name
);
1342 * fdisk_apply_script:
1346 * This function creates a new disklabel and partition within context @cxt. You
1347 * have to call fdisk_write_disklabel() to apply changes to the device.
1349 * Returns: 0 on error, <0 on error.
1351 int fdisk_apply_script(struct fdisk_context
*cxt
, struct fdisk_script
*dp
)
1354 struct fdisk_script
*old
;
1359 DBG(CXT
, ul_debugobj(cxt
, "applying script %p", dp
));
1361 old
= fdisk_get_script(cxt
);
1363 /* create empty disk label */
1364 rc
= fdisk_apply_script_headers(cxt
, dp
);
1366 /* create partitions */
1367 if (!rc
&& dp
->table
)
1368 rc
= fdisk_apply_table(cxt
, dp
->table
);
1370 fdisk_set_script(cxt
, old
);
1371 DBG(CXT
, ul_debugobj(cxt
, "script done [rc=%d]", rc
));
1376 int test_dump(struct fdisk_test
*ts
, int argc
, char *argv
[])
1378 char *devname
= argv
[1];
1379 struct fdisk_context
*cxt
;
1380 struct fdisk_script
*dp
;
1382 cxt
= fdisk_new_context();
1383 fdisk_assign_device(cxt
, devname
, 1);
1385 dp
= fdisk_new_script(cxt
);
1386 fdisk_script_read_context(dp
, NULL
);
1388 fdisk_script_write_file(dp
, stdout
);
1389 fdisk_unref_script(dp
);
1390 fdisk_unref_context(cxt
);
1395 int test_read(struct fdisk_test
*ts
, int argc
, char *argv
[])
1397 char *filename
= argv
[1];
1398 struct fdisk_script
*dp
;
1399 struct fdisk_context
*cxt
;
1402 if (!(f
= fopen(filename
, "r")))
1403 err(EXIT_FAILURE
, "%s: cannot open", filename
);
1405 cxt
= fdisk_new_context();
1406 dp
= fdisk_new_script(cxt
);
1408 fdisk_script_read_file(dp
, f
);
1411 fdisk_script_write_file(dp
, stdout
);
1412 fdisk_unref_script(dp
);
1413 fdisk_unref_context(cxt
);
1418 int test_stdin(struct fdisk_test
*ts
, int argc
, char *argv
[])
1421 struct fdisk_script
*dp
;
1422 struct fdisk_context
*cxt
;
1425 cxt
= fdisk_new_context();
1426 dp
= fdisk_new_script(cxt
);
1427 fdisk_script_set_header(dp
, "label", "dos");
1429 printf("<start>, <size>, <type>, <bootable: *|->\n");
1431 struct fdisk_partition
*pa
;
1432 size_t n
= fdisk_table_get_nents(dp
->table
);
1434 printf(" #%zu :\n", n
+ 1);
1435 rc
= fdisk_script_read_line(dp
, stdin
, buf
, sizeof(buf
));
1438 pa
= fdisk_table_get_partition(dp
->table
, n
);
1439 printf(" #%zu %12ju %12ju\n", n
+ 1,
1440 fdisk_partition_get_start(pa
),
1441 fdisk_partition_get_size(pa
));
1446 fdisk_script_write_file(dp
, stdout
);
1447 fdisk_unref_script(dp
);
1448 fdisk_unref_context(cxt
);
1453 int test_apply(struct fdisk_test
*ts
, int argc
, char *argv
[])
1455 char *devname
= argv
[1], *scriptname
= argv
[2];
1456 struct fdisk_context
*cxt
;
1457 struct fdisk_script
*dp
= NULL
;
1458 struct fdisk_table
*tb
= NULL
;
1459 struct fdisk_iter
*itr
= NULL
;
1460 struct fdisk_partition
*pa
= NULL
;
1463 cxt
= fdisk_new_context();
1464 fdisk_assign_device(cxt
, devname
, 0);
1466 dp
= fdisk_new_script_from_file(cxt
, scriptname
);
1470 rc
= fdisk_apply_script(cxt
, dp
);
1473 fdisk_unref_script(dp
);
1476 fdisk_list_disklabel(cxt
);
1477 fdisk_get_partitions(cxt
, &tb
);
1479 itr
= fdisk_new_iter(FDISK_ITER_FORWARD
);
1480 while (fdisk_table_next_partition(tb
, itr
, &pa
) == 0) {
1481 printf(" #%zu %12ju %12ju\n", fdisk_partition_get_partno(pa
),
1482 fdisk_partition_get_start(pa
),
1483 fdisk_partition_get_size(pa
));
1487 fdisk_free_iter(itr
);
1488 fdisk_unref_table(tb
);
1490 /*fdisk_write_disklabel(cxt);*/
1491 fdisk_unref_context(cxt
);
1495 int main(int argc
, char *argv
[])
1497 struct fdisk_test tss
[] = {
1498 { "--dump", test_dump
, "<device> dump PT as script" },
1499 { "--read", test_read
, "<file> read PT script from file" },
1500 { "--apply", test_apply
, "<device> <file> try apply script from file to device" },
1501 { "--stdin", test_stdin
, " read input like sfdisk" },
1505 return fdisk_run_test(tss
, argc
, argv
);