]>
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
;
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(dp
, 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(dp
, 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
;
406 rc
= fdisk_get_disklabel_item(cxt
, GPT_LABELITEM_FIRSTLBA
, &item
);
408 snprintf(buf
, sizeof(buf
), "%ju", item
.data
.num64
);
409 rc
= fdisk_script_set_header(dp
, "first-lba", buf
);
414 rc
= fdisk_get_disklabel_item(cxt
, GPT_LABELITEM_LASTLBA
, &item
);
416 snprintf(buf
, sizeof(buf
), "%ju", item
.data
.num64
);
417 rc
= fdisk_script_set_header(dp
, "last-lba", buf
);
424 DBG(SCRIPT
, ul_debugobj(dp
, "read context done [rc=%d]", rc
));
429 * fdisk_script_enable_json:
433 * Disable/Enable JSON output format.
435 * Returns: 0 on success, <0 on error.
437 int fdisk_script_enable_json(struct fdisk_script
*dp
, int json
)
445 static void fput_indent(int indent
, FILE *f
)
449 for (i
= 0; i
<= indent
; i
++)
453 static int write_file_json(struct fdisk_script
*dp
, FILE *f
)
456 struct fdisk_partition
*pa
;
457 struct fdisk_iter itr
;
458 const char *devname
= NULL
;
459 int ct
= 0, indent
= 0;
464 DBG(SCRIPT
, ul_debugobj(dp
, "writing json dump to file"));
468 fput_indent(indent
, f
);
469 fputs("\"partitiontable\": {\n", f
);
473 list_for_each(h
, &dp
->headers
) {
474 struct fdisk_scriptheader
*fi
= list_entry(h
, struct fdisk_scriptheader
, headers
);
475 const char *name
= fi
->name
;
478 if (strcmp(name
, "first-lba") == 0) {
481 } else if (strcmp(name
, "last-lba") == 0) {
484 } else if (strcmp(name
, "label-id") == 0)
487 fput_indent(indent
, f
);
488 fputs_quoted_lower(name
, f
);
491 fputs_quoted(fi
->data
, f
);
494 if (!dp
->table
&& fi
== list_last_entry(&dp
->headers
, struct fdisk_scriptheader
, headers
))
499 if (strcmp(name
, "device") == 0)
505 DBG(SCRIPT
, ul_debugobj(dp
, "script table empty"));
509 DBG(SCRIPT
, ul_debugobj(dp
, "%zu entries", fdisk_table_get_nents(dp
->table
)));
511 fput_indent(indent
, f
);
512 fputs("\"partitions\": [\n", f
);
515 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
516 while (fdisk_table_next_partition(dp
->table
, &itr
, &pa
) == 0) {
520 fput_indent(indent
, f
);
523 p
= fdisk_partname(devname
, pa
->partno
+ 1);
525 DBG(SCRIPT
, ul_debugobj(dp
, "write %s entry", p
));
526 fputs("\"node\": ", f
);
530 if (fdisk_partition_has_start(pa
))
531 fprintf(f
, ", \"start\": %ju", pa
->start
);
532 if (fdisk_partition_has_size(pa
))
533 fprintf(f
, ", \"size\": %ju", pa
->size
);
535 if (pa
->type
&& fdisk_parttype_get_string(pa
->type
))
536 fprintf(f
, ", \"type\": \"%s\"", fdisk_parttype_get_string(pa
->type
));
538 fprintf(f
, ", \"type\": \"%x\"", fdisk_parttype_get_code(pa
->type
));
541 fprintf(f
, ", \"uuid\": \"%s\"", pa
->uuid
);
542 if (pa
->name
&& *pa
->name
) {
543 fputs(", \"name\": ", f
),
544 fputs_quoted(pa
->name
, f
);
547 /* for MBR attr=80 means bootable */
549 struct fdisk_label
*lb
= script_get_label(dp
);
551 if (!lb
|| fdisk_label_get_type(lb
) != FDISK_DISKLABEL_DOS
)
552 fprintf(f
, ", \"attrs\": \"%s\"", pa
->attrs
);
554 if (fdisk_partition_is_bootable(pa
))
555 fprintf(f
, ", \"bootable\": true");
557 if (ct
< fdisk_table_get_nents(dp
->table
))
564 fput_indent(indent
, f
);
568 fput_indent(indent
, f
);
571 DBG(SCRIPT
, ul_debugobj(dp
, "write script done"));
575 static int write_file_sfdisk(struct fdisk_script
*dp
, FILE *f
)
578 struct fdisk_partition
*pa
;
579 struct fdisk_iter itr
;
580 const char *devname
= NULL
;
585 DBG(SCRIPT
, ul_debugobj(dp
, "writing sfdisk-like script to file"));
588 list_for_each(h
, &dp
->headers
) {
589 struct fdisk_scriptheader
*fi
= list_entry(h
, struct fdisk_scriptheader
, headers
);
590 fprintf(f
, "%s: %s\n", fi
->name
, fi
->data
);
591 if (strcmp(fi
->name
, "device") == 0)
596 DBG(SCRIPT
, ul_debugobj(dp
, "script table empty"));
600 DBG(SCRIPT
, ul_debugobj(dp
, "%zu entries", fdisk_table_get_nents(dp
->table
)));
604 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
605 while (fdisk_table_next_partition(dp
->table
, &itr
, &pa
) == 0) {
609 p
= fdisk_partname(devname
, pa
->partno
+ 1);
611 DBG(SCRIPT
, ul_debugobj(dp
, "write %s entry", p
));
612 fprintf(f
, "%s :", p
);
614 fprintf(f
, "%zu :", pa
->partno
+ 1);
616 if (fdisk_partition_has_start(pa
))
617 fprintf(f
, " start=%12ju", pa
->start
);
618 if (fdisk_partition_has_size(pa
))
619 fprintf(f
, ", size=%12ju", pa
->size
);
621 if (pa
->type
&& fdisk_parttype_get_string(pa
->type
))
622 fprintf(f
, ", type=%s", fdisk_parttype_get_string(pa
->type
));
624 fprintf(f
, ", type=%x", fdisk_parttype_get_code(pa
->type
));
627 fprintf(f
, ", uuid=%s", pa
->uuid
);
628 if (pa
->name
&& *pa
->name
)
629 fprintf(f
, ", name=\"%s\"", pa
->name
);
631 /* for MBR attr=80 means bootable */
633 struct fdisk_label
*lb
= script_get_label(dp
);
635 if (!lb
|| fdisk_label_get_type(lb
) != FDISK_DISKLABEL_DOS
)
636 fprintf(f
, ", attrs=\"%s\"", pa
->attrs
);
638 if (fdisk_partition_is_bootable(pa
))
639 fprintf(f
, ", bootable");
643 DBG(SCRIPT
, ul_debugobj(dp
, "write script done"));
648 * fdisk_script_write_file:
652 * Writes script @dp to the ile @f.
654 * Returns: 0 on success, <0 on error.
656 int fdisk_script_write_file(struct fdisk_script
*dp
, FILE *f
)
661 return write_file_json(dp
, f
);
663 return write_file_sfdisk(dp
, f
);
666 static inline int is_header_line(const char *s
)
668 const char *p
= strchr(s
, ':');
670 if (!p
|| p
== s
|| !*(p
+ 1) || strchr(s
, '='))
676 /* parses "<name>: value", note modifies @s*/
677 static int parse_line_header(struct fdisk_script
*dp
, char *s
)
682 DBG(SCRIPT
, ul_debugobj(dp
, " parse header '%s'", s
));
688 value
= strchr(s
, ':');
694 ltrim_whitespace((unsigned char *) name
);
695 rtrim_whitespace((unsigned char *) name
);
696 ltrim_whitespace((unsigned char *) value
);
697 rtrim_whitespace((unsigned char *) value
);
699 if (strcmp(name
, "label") == 0) {
700 if (dp
->cxt
&& !fdisk_get_label(dp
->cxt
, value
))
701 goto done
; /* unknown label name */
702 } else if (strcmp(name
, "unit") == 0) {
703 if (strcmp(value
, "sectors") != 0)
704 goto done
; /* only "sectors" supported */
705 } else if (strcmp(name
, "label-id") == 0
706 || strcmp(name
, "device") == 0
707 || strcmp(name
, "first-lba") == 0
708 || strcmp(name
, "last-lba") == 0) {
709 ; /* whatever is posssible */
711 goto done
; /* unknown header */
714 rc
= fdisk_script_set_header(dp
, name
, value
);
717 DBG(SCRIPT
, ul_debugobj(dp
, "header parse error: "
718 "[rc=%d, name='%s', value='%s']",
724 /* returns zero terminated string with next token and @str is updated */
725 static char *next_token(char **str
)
727 char *tk_begin
= NULL
,
733 for (p
= *str
; p
&& *p
; p
++) {
737 tk_begin
= *p
== '"' ? p
+ 1 : p
;
743 if (isblank(*p
) || *p
== ',' || *p
== ';' || *p
== '"' )
745 else if (*(p
+ 1) == '\0')
747 if (tk_begin
&& tk_end
)
753 end
= isblank(*tk_end
) ? (char *) skip_blank(tk_end
) : tk_end
;
754 if (*end
== ',' || *end
== ';')
762 static int next_number(char **s
, uint64_t *num
, int *power
)
772 rc
= parse_size(tk
, (uintmax_t *) num
, power
);
776 static int next_string(char **s
, char **str
)
787 rc
= !*str
? -ENOMEM
: 0;
792 static int partno_from_devname(char *s
)
798 sz
= rtrim_whitespace((unsigned char *)s
);
801 while (p
> s
&& isdigit(*(p
- 1)))
805 pno
= strtol(p
, &end
, 10);
806 if (errno
|| !end
|| p
== end
)
812 * <device>: start=<num>, size=<num>, type=<string>, ...
814 static int parse_line_nameval(struct fdisk_script
*dp
, char *s
)
817 struct fdisk_partition
*pa
;
825 DBG(SCRIPT
, ul_debugobj(dp
, " parse script line: '%s'", s
));
827 pa
= fdisk_new_partition();
831 fdisk_partition_start_follow_default(pa
, 1);
832 fdisk_partition_end_follow_default(pa
, 1);
833 fdisk_partition_partno_follow_default(pa
, 1);
838 if (p
&& (!x
|| p
< x
)) {
842 pno
= partno_from_devname(s
);
844 fdisk_partition_partno_follow_default(pa
, 0);
845 fdisk_partition_set_partno(pa
, pno
);
850 while (rc
== 0 && p
&& *p
) {
852 DBG(SCRIPT
, ul_debugobj(dp
, " parsing '%s'", p
));
853 p
= (char *) skip_blank(p
);
855 if (!strncasecmp(p
, "start=", 6)) {
858 rc
= next_number(&p
, &num
, &pow
);
860 if (pow
) /* specified as <num><suffix> */
861 num
/= dp
->cxt
->sector_size
;
862 fdisk_partition_set_start(pa
, num
);
863 fdisk_partition_start_follow_default(pa
, 0);
865 } else if (!strncasecmp(p
, "size=", 5)) {
869 rc
= next_number(&p
, &num
, &pow
);
871 if (pow
) /* specified as <num><suffix> */
872 num
/= dp
->cxt
->sector_size
;
873 else /* specified as number of sectors */
874 fdisk_partition_size_explicit(pa
, 1);
875 fdisk_partition_set_size(pa
, num
);
876 fdisk_partition_end_follow_default(pa
, 0);
879 } else if (!strncasecmp(p
, "bootable", 8)) {
880 char *tk
= next_token(&p
);
881 if (strcmp(tk
, "bootable") == 0)
886 } else if (!strncasecmp(p
, "attrs=", 6)) {
888 rc
= next_string(&p
, &pa
->attrs
);
890 } else if (!strncasecmp(p
, "uuid=", 5)) {
892 rc
= next_string(&p
, &pa
->uuid
);
894 } else if (!strncasecmp(p
, "name=", 5)) {
896 rc
= next_string(&p
, &pa
->name
);
898 } else if (!strncasecmp(p
, "type=", 5) ||
900 !strncasecmp(p
, "Id=", 3)) { /* backward compatiility */
903 p
+= (*p
== 'I' ? 3 : 5); /* "Id=" or "type=" */
905 rc
= next_string(&p
, &type
);
908 pa
->type
= fdisk_label_parse_parttype(
909 script_get_label(dp
), type
);
914 fdisk_unref_parttype(pa
->type
);
920 DBG(SCRIPT
, ul_debugobj(dp
, "script parse error: unknown field '%s'", p
));
927 rc
= fdisk_table_add_partition(dp
->table
, pa
);
929 DBG(SCRIPT
, ul_debugobj(dp
, "script parse error: [rc=%d]", rc
));
931 fdisk_unref_partition(pa
);
935 /* original sfdisk supports partition types shortcuts like 'L' = Linux native
937 static struct fdisk_parttype
*translate_type_shortcuts(struct fdisk_script
*dp
, char *str
)
939 struct fdisk_label
*lb
;
940 const char *type
= NULL
;
942 if (strlen(str
) != 1)
945 lb
= script_get_label(dp
);
949 if (lb
->id
== FDISK_DISKLABEL_DOS
) {
951 case 'L': /* Linux */
957 case 'E': /* Dos extended */
960 case 'X': /* Linux extended */
964 } else if (lb
->id
== FDISK_DISKLABEL_GPT
) {
966 case 'L': /* Linux */
967 type
= "0FC63DAF-8483-4772-8E79-3D69D8477DE4";
970 type
= "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F";
973 type
= "933AC7E1-2EB4-4F13-B844-0E14E2AEF915";
978 return type
? fdisk_label_parse_parttype(lb
, type
) : NULL
;
984 #define alone_sign(_sign, _p) (_sign && (*_p == '\0' || isblank(*_p)))
987 * <start>, <size>, <type>, <bootable>, ...
989 static int parse_line_valcommas(struct fdisk_script
*dp
, char *s
)
993 struct fdisk_partition
*pa
;
994 enum { ITEM_START
, ITEM_SIZE
, ITEM_TYPE
, ITEM_BOOTABLE
};
1000 pa
= fdisk_new_partition();
1004 fdisk_partition_start_follow_default(pa
, 1);
1005 fdisk_partition_end_follow_default(pa
, 1);
1006 fdisk_partition_partno_follow_default(pa
, 1);
1008 while (rc
== 0 && p
&& *p
) {
1013 p
= (char *) skip_blank(p
);
1016 if (item
!= ITEM_BOOTABLE
) {
1017 sign
= *p
== '-' ? TK_MINUS
: *p
== '+' ? TK_PLUS
: 0;
1022 DBG(SCRIPT
, ul_debugobj(dp
, " parsing item %d ('%s')", item
, p
));
1027 if (*p
== ',' || *p
== ';' || alone_sign(sign
, p
))
1028 fdisk_partition_start_follow_default(pa
, 1);
1032 rc
= next_number(&p
, &num
, &pow
);
1034 if (pow
) /* specified as <num><suffix> */
1035 num
/= dp
->cxt
->sector_size
;
1036 fdisk_partition_set_start(pa
, num
);
1037 pa
->movestart
= sign
== TK_MINUS
? FDISK_MOVE_DOWN
:
1038 sign
== TK_PLUS
? FDISK_MOVE_UP
:
1041 fdisk_partition_start_follow_default(pa
, 0);
1045 if (*p
== ',' || *p
== ';' || alone_sign(sign
, p
)) {
1046 fdisk_partition_end_follow_default(pa
, 1);
1047 if (sign
== TK_PLUS
)
1048 /* alone '+' means use all possible space, elone '-' means nothing */
1049 pa
->resize
= FDISK_RESIZE_ENLARGE
;
1052 rc
= next_number(&p
, &num
, &pow
);
1054 if (pow
) /* specified as <size><suffix> */
1055 num
/= dp
->cxt
->sector_size
;
1056 else /* specified as number of sectors */
1057 fdisk_partition_size_explicit(pa
, 1);
1058 fdisk_partition_set_size(pa
, num
);
1059 pa
->resize
= sign
== TK_MINUS
? FDISK_RESIZE_REDUCE
:
1060 sign
== TK_PLUS
? FDISK_RESIZE_ENLARGE
:
1063 fdisk_partition_end_follow_default(pa
, 0);
1067 if (*p
== ',' || *p
== ';' || alone_sign(sign
, p
))
1068 break; /* use default type */
1070 rc
= next_string(&p
, &str
);
1074 pa
->type
= translate_type_shortcuts(dp
, str
);
1076 pa
->type
= fdisk_label_parse_parttype(
1077 script_get_label(dp
), str
);
1082 fdisk_unref_parttype(pa
->type
);
1088 if (*p
== ',' || *p
== ';')
1091 char *tk
= next_token(&p
);
1092 if (tk
&& *tk
== '*' && *(tk
+ 1) == '\0')
1094 else if (tk
&& *tk
== '-' && *(tk
+ 1) == '\0')
1096 else if (tk
&& *tk
== '+' && *(tk
+ 1) == '\0')
1111 rc
= fdisk_table_add_partition(dp
->table
, pa
);
1113 DBG(SCRIPT
, ul_debugobj(dp
, "script parse error: [rc=%d]", rc
));
1115 fdisk_unref_partition(pa
);
1120 int fdisk_script_read_buffer(struct fdisk_script
*dp
, char *s
)
1127 DBG(SCRIPT
, ul_debugobj(dp
, " parsing buffer"));
1129 s
= (char *) skip_blank(s
);
1131 return 0; /* nothing baby, ignore */
1134 dp
->table
= fdisk_new_table();
1139 /* parse header lines only if no partition specified yet */
1140 if (fdisk_table_is_empty(dp
->table
) && is_header_line(s
))
1141 rc
= parse_line_header(dp
, s
);
1143 /* parse script format */
1144 else if (strchr(s
, '='))
1145 rc
= parse_line_nameval(dp
, s
);
1147 /* parse simple <value>, ... format */
1149 rc
= parse_line_valcommas(dp
, s
);
1152 DBG(SCRIPT
, ul_debugobj(dp
, "%zu: parse error [rc=%d]",
1158 * fdisk_script_set_fgets:
1160 * @fn_fgets: callback function
1162 * The library uses fgets() function to read the next line from the script.
1163 * This default maybe overrided to another function. Note that the function has
1164 * to return the line terminated by \n (for example readline(3) removes \n).
1166 * Return: 0 on success, <0 on error
1168 int fdisk_script_set_fgets(struct fdisk_script
*dp
,
1169 char *(*fn_fgets
)(struct fdisk_script
*, char *, size_t, FILE *))
1173 dp
->fn_fgets
= fn_fgets
;
1178 * fdisk_script_read_line:
1181 * @buf: buffer to store one line of the file
1182 * @bufsz: buffer size
1184 * Reads next line into dump.
1186 * Returns: 0 on success, <0 on error, 1 when nothing to read.
1188 int fdisk_script_read_line(struct fdisk_script
*dp
, FILE *f
, char *buf
, size_t bufsz
)
1195 DBG(SCRIPT
, ul_debugobj(dp
, " parsing line %zu", dp
->nlines
));
1197 /* read the next non-blank non-comment line */
1200 if (dp
->fn_fgets(dp
, buf
, bufsz
, f
) == NULL
)
1202 } else if (fgets(buf
, bufsz
, f
) == NULL
)
1206 s
= strchr(buf
, '\n');
1208 /* Missing final newline? Otherwise an extremely */
1209 /* long line - assume file was corrupted */
1211 DBG(SCRIPT
, ul_debugobj(dp
, "no final newline"));
1212 s
= strchr(buf
, '\0');
1214 DBG(SCRIPT
, ul_debugobj(dp
,
1215 "%zu: missing newline at line", dp
->nlines
));
1221 if (--s
>= buf
&& *s
== '\r')
1223 s
= (char *) skip_blank(buf
);
1224 } while (*s
== '\0' || *s
== '#');
1226 return fdisk_script_read_buffer(dp
, s
);
1231 * fdisk_script_read_file:
1235 * Reads file @f into script @dp.
1237 * Returns: 0 on success, <0 on error.
1239 int fdisk_script_read_file(struct fdisk_script
*dp
, FILE *f
)
1247 DBG(SCRIPT
, ul_debugobj(dp
, "parsing file"));
1250 rc
= fdisk_script_read_line(dp
, f
, buf
, sizeof(buf
));
1256 rc
= 0; /* end of file */
1258 DBG(SCRIPT
, ul_debugobj(dp
, "parsing file done [rc=%d]", rc
));
1265 * @dp: script (or NULL to remove previous reference)
1267 * Sets reference to the @dp script. The script headers might be used by label
1268 * drivers to overwrite built-in defaults (for example disk label Id) and label
1269 * driver might optimize the default semantic to be more usable for scripts
1270 * (for example to not ask for primary/logical/extended partition type).
1272 * Note that script also contains reference to the fdisk context (see
1273 * fdisk_new_script()). This context may be completely independent on
1274 * context used for fdisk_set_script().
1276 * Returns: <0 on error, 0 on success.
1278 int fdisk_set_script(struct fdisk_context
*cxt
, struct fdisk_script
*dp
)
1284 fdisk_unref_script(cxt
->script
);
1289 DBG(CXT
, ul_debugobj(cxt
, "setting reference to script %p", cxt
->script
));
1290 fdisk_ref_script(cxt
->script
);
1300 * Returns: the current script or NULL.
1302 struct fdisk_script
*fdisk_get_script(struct fdisk_context
*cxt
)
1309 * fdisk_apply_script_headers:
1313 * Associte context @cxt with script @dp and creates a new empty disklabel.
1315 * Returns: 0 on success, <0 on error.
1317 int fdisk_apply_script_headers(struct fdisk_context
*cxt
, struct fdisk_script
*dp
)
1324 DBG(SCRIPT
, ul_debugobj(dp
, "applying script headers"));
1325 fdisk_set_script(cxt
, dp
);
1327 /* create empty label */
1328 name
= fdisk_script_get_header(dp
, "label");
1332 return fdisk_create_disklabel(cxt
, name
);
1336 * fdisk_apply_script:
1340 * This function creates a new disklabel and partition within context @cxt. You
1341 * have to call fdisk_write_disklabel() to apply changes to the device.
1343 * Returns: 0 on error, <0 on error.
1345 int fdisk_apply_script(struct fdisk_context
*cxt
, struct fdisk_script
*dp
)
1348 struct fdisk_script
*old
;
1353 DBG(CXT
, ul_debugobj(cxt
, "applying script %p", dp
));
1355 old
= fdisk_get_script(cxt
);
1357 /* create empty disk label */
1358 rc
= fdisk_apply_script_headers(cxt
, dp
);
1360 /* create partitions */
1361 if (!rc
&& dp
->table
)
1362 rc
= fdisk_apply_table(cxt
, dp
->table
);
1364 fdisk_set_script(cxt
, old
);
1365 DBG(CXT
, ul_debugobj(cxt
, "script done [rc=%d]", rc
));
1370 int test_dump(struct fdisk_test
*ts
, int argc
, char *argv
[])
1372 char *devname
= argv
[1];
1373 struct fdisk_context
*cxt
;
1374 struct fdisk_script
*dp
;
1376 cxt
= fdisk_new_context();
1377 fdisk_assign_device(cxt
, devname
, 1);
1379 dp
= fdisk_new_script(cxt
);
1380 fdisk_script_read_context(dp
, NULL
);
1382 fdisk_script_write_file(dp
, stdout
);
1383 fdisk_unref_script(dp
);
1384 fdisk_unref_context(cxt
);
1389 int test_read(struct fdisk_test
*ts
, int argc
, char *argv
[])
1391 char *filename
= argv
[1];
1392 struct fdisk_script
*dp
;
1393 struct fdisk_context
*cxt
;
1396 if (!(f
= fopen(filename
, "r")))
1397 err(EXIT_FAILURE
, "%s: cannot open", filename
);
1399 cxt
= fdisk_new_context();
1400 dp
= fdisk_new_script(cxt
);
1402 fdisk_script_read_file(dp
, f
);
1405 fdisk_script_write_file(dp
, stdout
);
1406 fdisk_unref_script(dp
);
1407 fdisk_unref_context(cxt
);
1412 int test_stdin(struct fdisk_test
*ts
, int argc
, char *argv
[])
1415 struct fdisk_script
*dp
;
1416 struct fdisk_context
*cxt
;
1419 cxt
= fdisk_new_context();
1420 dp
= fdisk_new_script(cxt
);
1421 fdisk_script_set_header(dp
, "label", "dos");
1423 printf("<start>, <size>, <type>, <bootable: *|->\n");
1425 struct fdisk_partition
*pa
;
1426 size_t n
= fdisk_table_get_nents(dp
->table
);
1428 printf(" #%zu :\n", n
+ 1);
1429 rc
= fdisk_script_read_line(dp
, stdin
, buf
, sizeof(buf
));
1432 pa
= fdisk_table_get_partition(dp
->table
, n
);
1433 printf(" #%zu %12ju %12ju\n", n
+ 1,
1434 fdisk_partition_get_start(pa
),
1435 fdisk_partition_get_size(pa
));
1440 fdisk_script_write_file(dp
, stdout
);
1441 fdisk_unref_script(dp
);
1442 fdisk_unref_context(cxt
);
1447 int test_apply(struct fdisk_test
*ts
, int argc
, char *argv
[])
1449 char *devname
= argv
[1], *scriptname
= argv
[2];
1450 struct fdisk_context
*cxt
;
1451 struct fdisk_script
*dp
= NULL
;
1452 struct fdisk_table
*tb
= NULL
;
1453 struct fdisk_iter
*itr
= NULL
;
1454 struct fdisk_partition
*pa
= NULL
;
1457 cxt
= fdisk_new_context();
1458 fdisk_assign_device(cxt
, devname
, 0);
1460 dp
= fdisk_new_script_from_file(cxt
, scriptname
);
1464 rc
= fdisk_apply_script(cxt
, dp
);
1467 fdisk_unref_script(dp
);
1470 fdisk_list_disklabel(cxt
);
1471 fdisk_get_partitions(cxt
, &tb
);
1473 itr
= fdisk_new_iter(FDISK_ITER_FORWARD
);
1474 while (fdisk_table_next_partition(tb
, itr
, &pa
) == 0) {
1475 printf(" #%zu %12ju %12ju\n", fdisk_partition_get_partno(pa
),
1476 fdisk_partition_get_start(pa
),
1477 fdisk_partition_get_size(pa
));
1481 fdisk_free_iter(itr
);
1482 fdisk_unref_table(tb
);
1484 /*fdisk_write_disklabel(cxt);*/
1485 fdisk_unref_context(cxt
);
1489 int main(int argc
, char *argv
[])
1491 struct fdisk_test tss
[] = {
1492 { "--dump", test_dump
, "<device> dump PT as script" },
1493 { "--read", test_read
, "<file> read PT script from file" },
1494 { "--apply", test_apply
, "<device> <file> try apply script from file to device" },
1495 { "--stdin", test_stdin
, " read input like sfdisk" },
1499 return fdisk_run_test(tss
, argc
, argv
);