]>
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_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
;
406 rc
= fdisk_get_disklabel_item(cxt
, GPT_LABELITEM_FIRSTLBA
, &item
);
408 snprintf(buf
, sizeof(buf
), "%"PRIu64
, 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
), "%"PRIu64
, 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", (uintmax_t)pa
->start
);
532 if (fdisk_partition_has_size(pa
))
533 fprintf(f
, ", \"size\": %ju", (uintmax_t)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 ((size_t)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", (uintmax_t)pa
->start
);
618 if (fdisk_partition_has_size(pa
))
619 fprintf(f
, ", size=%12ju", (uintmax_t)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 */
963 case 'U': /* UEFI system */
967 } else if (lb
->id
== FDISK_DISKLABEL_GPT
) {
969 case 'L': /* Linux */
970 type
= "0FC63DAF-8483-4772-8E79-3D69D8477DE4";
973 type
= "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F";
976 type
= "933AC7E1-2EB4-4F13-B844-0E14E2AEF915";
978 case 'U': /* UEFI system */
979 type
= "C12A7328-F81F-11D2-BA4B-00A0C93EC93B";
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 static 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 and remove reference to the previously used
1276 * The script headers might be used by label drivers to overwrite
1277 * built-in defaults (for example disk label Id) and label driver might
1278 * optimize the default semantic to be more usable for scripts (for example to
1279 * not ask for primary/logical/extended partition type).
1281 * Note that script also contains reference to the fdisk context (see
1282 * fdisk_new_script()). This context may be completely independent on
1283 * context used for fdisk_set_script().
1285 * Returns: <0 on error, 0 on success.
1287 int fdisk_set_script(struct fdisk_context
*cxt
, struct fdisk_script
*dp
)
1293 fdisk_unref_script(cxt
->script
);
1298 DBG(CXT
, ul_debugobj(cxt
, "setting reference to script %p", cxt
->script
));
1299 fdisk_ref_script(cxt
->script
);
1309 * Returns: the current script or NULL.
1311 struct fdisk_script
*fdisk_get_script(struct fdisk_context
*cxt
)
1318 * fdisk_apply_script_headers:
1322 * Associte context @cxt with script @dp and creates a new empty disklabel.
1324 * Returns: 0 on success, <0 on error.
1326 int fdisk_apply_script_headers(struct fdisk_context
*cxt
, struct fdisk_script
*dp
)
1333 DBG(SCRIPT
, ul_debugobj(dp
, "applying script headers"));
1334 fdisk_set_script(cxt
, dp
);
1336 /* create empty label */
1337 name
= fdisk_script_get_header(dp
, "label");
1341 return fdisk_create_disklabel(cxt
, name
);
1345 * fdisk_apply_script:
1349 * This function creates a new disklabel and partition within context @cxt. You
1350 * have to call fdisk_write_disklabel() to apply changes to the device.
1352 * Returns: 0 on error, <0 on error.
1354 int fdisk_apply_script(struct fdisk_context
*cxt
, struct fdisk_script
*dp
)
1357 struct fdisk_script
*old
;
1362 DBG(CXT
, ul_debugobj(cxt
, "applying script %p", dp
));
1364 old
= fdisk_get_script(cxt
);
1365 fdisk_ref_script(old
);
1367 /* create empty disk label */
1368 rc
= fdisk_apply_script_headers(cxt
, dp
);
1370 /* create partitions */
1371 if (!rc
&& dp
->table
)
1372 rc
= fdisk_apply_table(cxt
, dp
->table
);
1374 fdisk_set_script(cxt
, old
);
1375 fdisk_unref_script(old
);
1377 DBG(CXT
, ul_debugobj(cxt
, "script done [rc=%d]", rc
));
1382 static int test_dump(struct fdisk_test
*ts
, int argc
, char *argv
[])
1384 char *devname
= argv
[1];
1385 struct fdisk_context
*cxt
;
1386 struct fdisk_script
*dp
;
1388 cxt
= fdisk_new_context();
1389 fdisk_assign_device(cxt
, devname
, 1);
1391 dp
= fdisk_new_script(cxt
);
1392 fdisk_script_read_context(dp
, NULL
);
1394 fdisk_script_write_file(dp
, stdout
);
1395 fdisk_unref_script(dp
);
1396 fdisk_unref_context(cxt
);
1401 static int test_read(struct fdisk_test
*ts
, int argc
, char *argv
[])
1403 char *filename
= argv
[1];
1404 struct fdisk_script
*dp
;
1405 struct fdisk_context
*cxt
;
1408 if (!(f
= fopen(filename
, "r")))
1409 err(EXIT_FAILURE
, "%s: cannot open", filename
);
1411 cxt
= fdisk_new_context();
1412 dp
= fdisk_new_script(cxt
);
1414 fdisk_script_read_file(dp
, f
);
1417 fdisk_script_write_file(dp
, stdout
);
1418 fdisk_unref_script(dp
);
1419 fdisk_unref_context(cxt
);
1424 static int test_stdin(struct fdisk_test
*ts
, int argc
, char *argv
[])
1427 struct fdisk_script
*dp
;
1428 struct fdisk_context
*cxt
;
1431 cxt
= fdisk_new_context();
1432 dp
= fdisk_new_script(cxt
);
1433 fdisk_script_set_header(dp
, "label", "dos");
1435 printf("<start>, <size>, <type>, <bootable: *|->\n");
1437 struct fdisk_partition
*pa
;
1438 size_t n
= fdisk_table_get_nents(dp
->table
);
1440 printf(" #%zu :\n", n
+ 1);
1441 rc
= fdisk_script_read_line(dp
, stdin
, buf
, sizeof(buf
));
1444 pa
= fdisk_table_get_partition(dp
->table
, n
);
1445 printf(" #%zu %12ju %12ju\n", n
+ 1,
1446 (uintmax_t)fdisk_partition_get_start(pa
),
1447 (uintmax_t)fdisk_partition_get_size(pa
));
1452 fdisk_script_write_file(dp
, stdout
);
1453 fdisk_unref_script(dp
);
1454 fdisk_unref_context(cxt
);
1459 static int test_apply(struct fdisk_test
*ts
, int argc
, char *argv
[])
1461 char *devname
= argv
[1], *scriptname
= argv
[2];
1462 struct fdisk_context
*cxt
;
1463 struct fdisk_script
*dp
= NULL
;
1464 struct fdisk_table
*tb
= NULL
;
1465 struct fdisk_iter
*itr
= NULL
;
1466 struct fdisk_partition
*pa
= NULL
;
1469 cxt
= fdisk_new_context();
1470 fdisk_assign_device(cxt
, devname
, 0);
1472 dp
= fdisk_new_script_from_file(cxt
, scriptname
);
1476 rc
= fdisk_apply_script(cxt
, dp
);
1479 fdisk_unref_script(dp
);
1482 fdisk_list_disklabel(cxt
);
1483 fdisk_get_partitions(cxt
, &tb
);
1485 itr
= fdisk_new_iter(FDISK_ITER_FORWARD
);
1486 while (fdisk_table_next_partition(tb
, itr
, &pa
) == 0) {
1487 printf(" #%zu %12ju %12ju\n", fdisk_partition_get_partno(pa
),
1488 (uintmax_t)fdisk_partition_get_start(pa
),
1489 (uintmax_t)fdisk_partition_get_size(pa
));
1493 fdisk_free_iter(itr
);
1494 fdisk_unref_table(tb
);
1496 /*fdisk_write_disklabel(cxt);*/
1497 fdisk_unref_context(cxt
);
1501 int main(int argc
, char *argv
[])
1503 struct fdisk_test tss
[] = {
1504 { "--dump", test_dump
, "<device> dump PT as script" },
1505 { "--read", test_read
, "<file> read PT script from file" },
1506 { "--apply", test_apply
, "<device> <file> try apply script from file to device" },
1507 { "--stdin", test_stdin
, " read input like sfdisk" },
1511 return fdisk_run_test(tss
, argc
, argv
);