6 static void fdisk_ask_menu_reset_items(struct fdisk_ask
*ask
);
9 struct fdisk_ask
*fdisk_new_ask(void)
11 return calloc(1, sizeof(struct fdisk_ask
));
14 void fdisk_reset_ask(struct fdisk_ask
*ask
)
19 if (fdisk_is_ask(ask
, MENU
))
20 fdisk_ask_menu_reset_items(ask
);
22 memset(ask
, 0, sizeof(*ask
));
25 void fdisk_free_ask(struct fdisk_ask
*ask
)
33 const char *fdisk_ask_get_query(struct fdisk_ask
*ask
)
39 int fdisk_ask_set_query(struct fdisk_ask
*ask
, const char *str
)
42 return !strdup_to_struct_member(ask
, query
, str
) ? -ENOMEM
: 0;
45 int fdisk_ask_get_type(struct fdisk_ask
*ask
)
51 int fdisk_ask_set_type(struct fdisk_ask
*ask
, int type
)
58 unsigned int fdisk_ask_get_flags(struct fdisk_ask
*ask
)
64 int fdisk_ask_set_flags(struct fdisk_ask
*ask
, unsigned int flags
)
71 int fdisk_do_ask(struct fdisk_context
*cxt
, struct fdisk_ask
*ask
)
78 DBG(ASK
, ul_debug("do_ask for '%s'",
79 ask
->query
? ask
->query
:
80 ask
->type
== FDISK_ASKTYPE_INFO
? "info" :
81 ask
->type
== FDISK_ASKTYPE_WARNX
? "warnx" :
82 ask
->type
== FDISK_ASKTYPE_WARN
? "warn" :
86 DBG(ASK
, ul_debug("no ask callback specified!"));
90 rc
= cxt
->ask_cb(cxt
, ask
, cxt
->ask_data
);
92 DBG(ASK
, ul_debug("do_ask done [rc=%d]", rc
));
96 #define is_number_ask(a) (fdisk_is_ask(a, NUMBER) || fdisk_is_ask(a, OFFSET))
98 const char *fdisk_ask_number_get_range(struct fdisk_ask
*ask
)
101 assert(is_number_ask(ask
));
102 return ask
->data
.num
.range
;
105 int fdisk_ask_number_set_range(struct fdisk_ask
*ask
, const char *range
)
108 assert(is_number_ask(ask
));
109 ask
->data
.num
.range
= range
;
113 uint64_t fdisk_ask_number_get_default(struct fdisk_ask
*ask
)
116 assert(is_number_ask(ask
));
117 return ask
->data
.num
.dfl
;
120 int fdisk_ask_number_set_default(struct fdisk_ask
*ask
, uint64_t dflt
)
123 ask
->data
.num
.dfl
= dflt
;
127 uint64_t fdisk_ask_number_get_low(struct fdisk_ask
*ask
)
130 assert(is_number_ask(ask
));
131 return ask
->data
.num
.low
;
134 int fdisk_ask_number_set_low(struct fdisk_ask
*ask
, uint64_t low
)
137 ask
->data
.num
.low
= low
;
141 uint64_t fdisk_ask_number_get_high(struct fdisk_ask
*ask
)
144 assert(is_number_ask(ask
));
145 return ask
->data
.num
.hig
;
148 int fdisk_ask_number_set_high(struct fdisk_ask
*ask
, uint64_t high
)
151 ask
->data
.num
.hig
= high
;
155 uint64_t fdisk_ask_number_get_result(struct fdisk_ask
*ask
)
158 assert(is_number_ask(ask
));
159 return ask
->data
.num
.result
;
162 int fdisk_ask_number_set_result(struct fdisk_ask
*ask
, uint64_t result
)
165 ask
->data
.num
.result
= result
;
169 uint64_t fdisk_ask_number_get_base(struct fdisk_ask
*ask
)
172 assert(is_number_ask(ask
));
173 return ask
->data
.num
.base
;
176 int fdisk_ask_number_set_base(struct fdisk_ask
*ask
, uint64_t base
)
179 ask
->data
.num
.base
= base
;
183 /* if numbers are not in bytes, then specify number of bytes per the unit */
184 uint64_t fdisk_ask_number_get_unit(struct fdisk_ask
*ask
)
187 assert(is_number_ask(ask
));
188 return ask
->data
.num
.unit
;
191 int fdisk_ask_number_set_unit(struct fdisk_ask
*ask
, uint64_t unit
)
194 ask
->data
.num
.unit
= unit
;
198 int fdisk_ask_number_is_relative(struct fdisk_ask
*ask
)
201 assert(is_number_ask(ask
));
202 return ask
->data
.num
.relative
;
205 int fdisk_ask_number_set_relative(struct fdisk_ask
*ask
, int relative
)
208 ask
->data
.num
.relative
= relative
? 1 : 0;
212 int fdisk_ask_number_inchars(struct fdisk_ask
*ask
)
215 assert(is_number_ask(ask
));
216 return ask
->data
.num
.inchars
;
220 * Generates string with list ranges (e.g. 1,2,5-8) for the 'cur'
222 #define tochar(num) ((int) ('a' + num - 1))
223 static char *mk_string_list(char *ptr
, size_t *len
, size_t *begin
,
224 size_t *run
, ssize_t cur
, int inchar
)
229 if (!*begin
) { /* begin of the list */
234 if (*begin
+ *run
== cur
) { /* no gap, continue */
238 } else if (!*begin
) {
240 return ptr
; /* end of empty list */
243 /* add to the list */
245 rlen
= inchar
? snprintf(ptr
, *len
, "%c,", tochar(*begin
)) :
246 snprintf(ptr
, *len
, "%zu,", *begin
);
249 snprintf(ptr
, *len
, "%c,%c,", tochar(*begin
), tochar(*begin
+ 1)) :
250 snprintf(ptr
, *len
, "%zu,%zu,", *begin
, *begin
+ 1);
253 snprintf(ptr
, *len
, "%c-%c,", tochar(*begin
), tochar(*begin
+ *run
)) :
254 snprintf(ptr
, *len
, "%zu-%zu,", *begin
, *begin
+ *run
);
256 if (rlen
< 0 || (size_t) rlen
+ 1 > *len
)
261 if (rlen
> 0 && *len
> (size_t) rlen
)
266 if (cur
== -1 && *begin
) {
267 /* end of the list */
268 *(ptr
- 1) = '\0'; /* remove tailing ',' from the list */
278 /* returns: 1=0 on success, < 0 on error, 1 if no free/used partition */
279 int fdisk_ask_partnum(struct fdisk_context
*cxt
, size_t *partnum
, int wantnew
)
281 int rc
= 0, inchar
= 0;
282 char range
[BUFSIZ
], *ptr
= range
;
283 size_t i
, len
= sizeof(range
), begin
= 0, run
= 0;
284 struct fdisk_ask
*ask
= NULL
;
285 __typeof__(ask
->data
.num
) *num
;
291 if (cxt
->label
&& cxt
->label
->flags
& FDISK_LABEL_FL_INCHARS_PARTNO
)
294 DBG(ASK
, ul_debug("%s: asking for %s partition number "
295 "(max: %zu, inchar: %s)",
297 wantnew
? "new" : "used",
298 cxt
->label
->nparts_max
,
299 inchar
? "yes" : "not"));
301 ask
= fdisk_new_ask();
305 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_NUMBER
);
306 num
= &ask
->data
.num
;
308 ask
->data
.num
.inchars
= inchar
? 1 : 0;
310 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
311 int used
= fdisk_is_partition_used(cxt
, i
);
313 if (wantnew
&& !used
) {
314 ptr
= mk_string_list(ptr
, &len
, &begin
, &run
, i
, inchar
);
320 num
->dfl
= num
->low
= i
+ 1;
322 } else if (!wantnew
&& used
) {
323 ptr
= mk_string_list(ptr
, &len
, &begin
, &run
, i
, inchar
);
326 num
->dfl
= num
->hig
= i
+ 1;
330 DBG(ASK
, ul_debug("ask limits: low: %ju, high: %ju, default: %ju",
331 num
->low
, num
->hig
, num
->dfl
));
333 if (!rc
&& !wantnew
&& num
->low
== num
->hig
) {
335 /* only one existing partiton, don't ask, return the number */
336 fdisk_ask_number_set_result(ask
, num
->low
);
337 fdisk_info(cxt
, _("Selected partition %ju"), num
->low
);
339 } else if (num
->low
== 0) {
340 fdisk_warnx(cxt
, _("No partition is defined yet!"));
345 if (!rc
&& wantnew
&& num
->low
== num
->hig
) {
347 /* only one free partition, don't ask, return the number */
348 fdisk_ask_number_set_result(ask
, num
->low
);
349 fdisk_info(cxt
, _("Selected partition %ju"), num
->low
);
352 fdisk_warnx(cxt
, _("No free partition available!"));
358 mk_string_list(ptr
, &len
, &begin
, &run
, -1, inchar
); /* terminate the list */
359 rc
= fdisk_ask_number_set_range(ask
, range
);
362 rc
= fdisk_ask_set_query(ask
, _("Partition number"));
364 rc
= fdisk_do_ask(cxt
, ask
);
368 *partnum
= fdisk_ask_number_get_result(ask
);
372 DBG(ASK
, ul_debug("result: %ju [rc=%d]\n", fdisk_ask_number_get_result(ask
), rc
));
377 /* very basic wraper to ask numbers */
378 int fdisk_ask_number(struct fdisk_context
*cxt
,
385 struct fdisk_ask
*ask
;
390 ask
= fdisk_new_ask();
394 rc
= fdisk_ask_set_type(ask
, FDISK_ASKTYPE_NUMBER
);
396 fdisk_ask_number_set_low(ask
, low
);
398 fdisk_ask_number_set_default(ask
, dflt
);
400 fdisk_ask_number_set_high(ask
, high
);
402 fdisk_ask_set_query(ask
, query
);
404 rc
= fdisk_do_ask(cxt
, ask
);
406 *result
= fdisk_ask_number_get_result(ask
);
409 DBG(ASK
, ul_debug("result: %ju [rc=%d]\n", *result
, rc
));
413 char *fdisk_ask_string_get_result(struct fdisk_ask
*ask
)
416 assert(fdisk_is_ask(ask
, STRING
));
417 return ask
->data
.str
.result
;
421 * The @result has to be poiter to the allocated buffer.
423 int fdisk_ask_string_set_result(struct fdisk_ask
*ask
, char *result
)
426 ask
->data
.str
.result
= result
;
431 * Don't forget to deallocate @result.
433 int fdisk_ask_string(struct fdisk_context
*cxt
,
437 struct fdisk_ask
*ask
;
442 ask
= fdisk_new_ask();
446 rc
= fdisk_ask_set_type(ask
, FDISK_ASKTYPE_STRING
);
448 fdisk_ask_set_query(ask
, query
);
450 rc
= fdisk_do_ask(cxt
, ask
);
452 *result
= fdisk_ask_string_get_result(ask
);
455 DBG(ASK
, ul_debug("result: %s [rc=%d]\n", *result
, rc
));
459 int fdisk_ask_yesno(struct fdisk_context
*cxt
,
463 struct fdisk_ask
*ask
;
468 ask
= fdisk_new_ask();
472 rc
= fdisk_ask_set_type(ask
, FDISK_ASKTYPE_YESNO
);
474 fdisk_ask_set_query(ask
, query
);
476 rc
= fdisk_do_ask(cxt
, ask
);
478 *result
= fdisk_ask_yesno_get_result(ask
);
481 DBG(ASK
, ul_debug("result: %d [rc=%d]\n", *result
, rc
));
485 uint64_t fdisk_ask_yesno_get_result(struct fdisk_ask
*ask
)
488 assert(fdisk_is_ask(ask
, YESNO
));
489 return ask
->data
.yesno
.result
;
492 int fdisk_ask_yesno_set_result(struct fdisk_ask
*ask
, uint64_t result
)
495 ask
->data
.yesno
.result
= result
;
502 int fdisk_ask_menu_set_default(struct fdisk_ask
*ask
, int dfl
)
505 assert(fdisk_is_ask(ask
, MENU
));
506 ask
->data
.menu
.dfl
= dfl
;
510 int fdisk_ask_menu_get_default(struct fdisk_ask
*ask
)
513 assert(fdisk_is_ask(ask
, MENU
));
514 return ask
->data
.menu
.dfl
;
517 int fdisk_ask_menu_set_result(struct fdisk_ask
*ask
, int key
)
520 assert(fdisk_is_ask(ask
, MENU
));
521 ask
->data
.menu
.result
= key
;
522 DBG(ASK
, ul_debug("menu result: %c\n", key
));
527 int fdisk_ask_menu_get_result(struct fdisk_ask
*ask
, int *key
)
530 assert(fdisk_is_ask(ask
, MENU
));
532 *key
= ask
->data
.menu
.result
;
536 /* returns: 0 = success, <0 = error, >0 = idx out-of-range */
537 int fdisk_ask_menu_get_item(struct fdisk_ask
*ask
, size_t idx
, int *key
,
538 const char **name
, const char **desc
)
541 struct ask_menuitem
*mi
;
544 assert(fdisk_is_ask(ask
, MENU
));
546 for (i
= 0, mi
= ask
->data
.menu
.first
; mi
; mi
= mi
->next
, i
++) {
552 return 1; /* no more items */
562 static void fdisk_ask_menu_reset_items(struct fdisk_ask
*ask
)
564 struct ask_menuitem
*mi
;
567 assert(fdisk_is_ask(ask
, MENU
));
569 for (mi
= ask
->data
.menu
.first
; mi
; ) {
570 struct ask_menuitem
*next
= mi
->next
;
576 size_t fdisk_ask_menu_get_nitems(struct fdisk_ask
*ask
)
578 struct ask_menuitem
*mi
;
582 assert(fdisk_is_ask(ask
, MENU
));
584 for (n
= 0, mi
= ask
->data
.menu
.first
; mi
; mi
= mi
->next
, n
++);
589 int fdisk_ask_menu_add_item(struct fdisk_ask
*ask
, int key
,
590 const char *name
, const char *desc
)
592 struct ask_menuitem
*mi
;
595 assert(fdisk_is_ask(ask
, MENU
));
597 mi
= calloc(1, sizeof(*mi
));
604 if (!ask
->data
.menu
.first
)
605 ask
->data
.menu
.first
= mi
;
607 struct ask_menuitem
*last
= ask
->data
.menu
.first
;
614 DBG(ASK
, ul_debug("new menu item: %c, \"%s\" (%s)\n", mi
->key
, mi
->name
, mi
->desc
));
623 #define is_print_ask(a) (fdisk_is_ask(a, WARN) || fdisk_is_ask(a, WARNX) || fdisk_is_ask(a, INFO))
625 int fdisk_ask_print_get_errno(struct fdisk_ask
*ask
)
628 assert(is_print_ask(ask
));
629 return ask
->data
.print
.errnum
;
632 int fdisk_ask_print_set_errno(struct fdisk_ask
*ask
, int errnum
)
635 ask
->data
.print
.errnum
= errnum
;
639 const char *fdisk_ask_print_get_mesg(struct fdisk_ask
*ask
)
642 assert(is_print_ask(ask
));
643 return ask
->data
.print
.mesg
;
646 /* does not reallocate the message! */
647 int fdisk_ask_print_set_mesg(struct fdisk_ask
*ask
, const char *mesg
)
650 ask
->data
.print
.mesg
= mesg
;
654 static int do_vprint(struct fdisk_context
*cxt
, int errnum
, int type
,
655 unsigned int flags
, const char *fmt
, va_list va
)
657 struct fdisk_ask
*ask
;
663 if (vasprintf(&mesg
, fmt
, va
) < 0)
666 ask
= fdisk_new_ask();
672 fdisk_ask_set_type(ask
, type
);
673 fdisk_ask_set_flags(ask
, flags
);
674 fdisk_ask_print_set_mesg(ask
, mesg
);
676 fdisk_ask_print_set_errno(ask
, errnum
);
677 rc
= fdisk_do_ask(cxt
, ask
);
684 int fdisk_info(struct fdisk_context
*cxt
, const char *fmt
, ...)
691 rc
= do_vprint(cxt
, -1, FDISK_ASKTYPE_INFO
, 0, fmt
, ap
);
696 /* "smart" version, allows to set flags for the message */
697 int fdisk_sinfo(struct fdisk_context
*cxt
,
698 unsigned int flags
, const char *fmt
, ...)
705 rc
= do_vprint(cxt
, -1, FDISK_ASKTYPE_INFO
, flags
, fmt
, ap
);
711 int fdisk_colon(struct fdisk_context
*cxt
, const char *fmt
, ...)
718 rc
= do_vprint(cxt
, -1, FDISK_ASKTYPE_INFO
, FDISK_INFO_COLON
, fmt
, ap
);
724 int fdisk_warn(struct fdisk_context
*cxt
, const char *fmt
, ...)
731 rc
= do_vprint(cxt
, errno
, FDISK_ASKTYPE_WARN
, 0, fmt
, ap
);
736 int fdisk_warnx(struct fdisk_context
*cxt
, const char *fmt
, ...)
743 rc
= do_vprint(cxt
, -1, FDISK_ASKTYPE_WARNX
, 0, fmt
, ap
);
748 int fdisk_info_new_partition(
749 struct fdisk_context
*cxt
,
750 int num
, sector_t start
, sector_t stop
,
751 struct fdisk_parttype
*t
)
754 char *str
= size_to_human_string(SIZE_SUFFIX_3LETTER
| SIZE_SUFFIX_SPACE
,
755 (uint64_t)(stop
- start
+ 1) * cxt
->sector_size
);
757 rc
= fdisk_sinfo(cxt
, FDISK_INFO_SUCCESS
,
758 _("Created a new partition %d of type '%s' and of size %s."),
759 num
, t
? t
->name
: _("Unknown"), str
);
765 int test_ranges(struct fdisk_test
*ts
, int argc
, char *argv
[])
767 /* 1 - 3, 6, 8, 9, 11 13 */
768 size_t nums
[] = { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1 };
769 size_t numx
[] = { 0, 0, 0 };
770 char range
[BUFSIZ
], *ptr
= range
;
771 size_t i
, len
= sizeof(range
), begin
= 0, run
= 0;
773 for (i
= 0; i
< ARRAY_SIZE(nums
); i
++) {
776 ptr
= mk_string_list(ptr
, &len
, &begin
, &run
, i
, 0);
778 mk_string_list(ptr
, &len
, &begin
, &run
, -1, 0);
779 printf("list: '%s'\n", range
);
782 len
= sizeof(range
), begin
= 0, run
= 0;
783 for (i
= 0; i
< ARRAY_SIZE(numx
); i
++) {
786 ptr
= mk_string_list(ptr
, &len
, &begin
, &run
, i
, 0);
788 mk_string_list(ptr
, &len
, &begin
, &run
, -1, 0);
789 printf("empty list: '%s'\n", range
);
794 int main(int argc
, char *argv
[])
796 struct fdisk_test tss
[] = {
797 { "--ranges", test_ranges
, "generates ranges" },
801 return fdisk_run_test(tss
, argc
, argv
);