]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libfdisk/src/ask.c
libfdisk: add comment to fdisk_set_first_lba()
[thirdparty/util-linux.git] / libfdisk / src / ask.c
CommitLineData
7845ca8d 1
4114da08 2#include "strutils.h"
7845ca8d
KZ
3#include "fdiskP.h"
4
a3d83488
KZ
5/**
6 * SECTION: ask
705854f3
KZ
7 * @title: Ask
8 * @short_description: interface for dialog driven partitioning, warning and info messages
a3d83488
KZ
9 *
10 */
20f878fe 11
a3d83488 12static void fdisk_ask_menu_reset_items(struct fdisk_ask *ask);
20f878fe 13
a1ef792f
KZ
14
15/**
16 * fdisk_set_ask:
17 * @cxt: context
18 * @ask_cb: callback
19 * @data: callback data
20 *
21 * Set callback for dialog driven partitioning and library warnings/errors.
22 *
23 * Returns: 0 on success, < 0 on error.
24 */
25int fdisk_set_ask(struct fdisk_context *cxt,
26 int (*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *),
27 void *data)
28{
29 assert(cxt);
30
31 cxt->ask_cb = ask_cb;
32 cxt->ask_data = data;
33 return 0;
34}
35
4114da08
KZ
36struct fdisk_ask *fdisk_new_ask(void)
37{
d71bd2f0
KZ
38 struct fdisk_ask *ask = calloc(1, sizeof(struct fdisk_ask));
39 DBG(ASK, ul_debugobj(ask, "alloc"));
a3d83488 40 ask->refcount = 1;
d71bd2f0 41 return ask;
4114da08
KZ
42}
43
44void fdisk_reset_ask(struct fdisk_ask *ask)
45{
a3d83488
KZ
46 int refcount;
47
4114da08 48 assert(ask);
4114da08 49 free(ask->query);
ab6ea0e8 50
d71bd2f0 51 DBG(ASK, ul_debugobj(ask, "reset"));
a3d83488 52 refcount = ask->refcount;
d71bd2f0 53
20f878fe
KZ
54 if (fdisk_is_ask(ask, MENU))
55 fdisk_ask_menu_reset_items(ask);
56
4114da08 57 memset(ask, 0, sizeof(*ask));
a3d83488 58 ask->refcount = refcount;
4114da08
KZ
59}
60
a3d83488
KZ
61/**
62 * fdisk_ref_ask:
63 * @ask: ask instance
64 *
9e930041 65 * Increments reference counter.
a3d83488
KZ
66 */
67void fdisk_ref_ask(struct fdisk_ask *ask)
68{
69 if (ask)
70 ask->refcount++;
71}
72
73
74/**
75 * fdisk_unref_ask:
76 * @ask: ask instance
77 *
9e930041 78 * Decrements reference counter, on zero the @ask is automatically
a3d83488
KZ
79 * deallocated.
80 */
81void fdisk_unref_ask(struct fdisk_ask *ask)
4114da08
KZ
82{
83 if (!ask)
84 return;
a3d83488
KZ
85 ask->refcount--;
86
87 if (ask->refcount <= 0) {
88 fdisk_reset_ask(ask);
89 DBG(ASK, ul_debugobj(ask, "free"));
90 free(ask);
91 }
4114da08 92}
7845ca8d 93
0477369a
KZ
94/**
95 * fdisk_ask_get_query:
96 * @ask: ask instance
97 *
98 * Returns: pointer to dialog string.
99 */
4114da08 100const char *fdisk_ask_get_query(struct fdisk_ask *ask)
7845ca8d
KZ
101{
102 assert(ask);
103 return ask->query;
104}
105
4114da08
KZ
106int fdisk_ask_set_query(struct fdisk_ask *ask, const char *str)
107{
108 assert(ask);
deb1c903 109 return strdup_to_struct_member(ask, query, str);
4114da08
KZ
110}
111
0477369a
KZ
112/**
113 * fdisk_ask_get_type:
114 * @ask: ask instance
115 *
116 * Returns: FDISK_ASKTYPE_*
117 */
7845ca8d
KZ
118int fdisk_ask_get_type(struct fdisk_ask *ask)
119{
120 assert(ask);
121 return ask->type;
122}
123
4114da08
KZ
124int fdisk_ask_set_type(struct fdisk_ask *ask, int type)
125{
126 assert(ask);
127 ask->type = type;
128 return 0;
129}
130
131int fdisk_do_ask(struct fdisk_context *cxt, struct fdisk_ask *ask)
132{
133 int rc;
134
135 assert(ask);
136 assert(cxt);
137
d71bd2f0 138 DBG(ASK, ul_debugobj(ask, "do_ask for '%s'",
ffcf0540
KZ
139 ask->query ? ask->query :
140 ask->type == FDISK_ASKTYPE_INFO ? "info" :
141 ask->type == FDISK_ASKTYPE_WARNX ? "warnx" :
142 ask->type == FDISK_ASKTYPE_WARN ? "warn" :
143 "?nothing?"));
4114da08 144
992f7cba
KZ
145 if (!fdisk_has_dialogs(cxt) &&
146 !(ask->type == FDISK_ASKTYPE_INFO ||
147 ask->type == FDISK_ASKTYPE_WARNX ||
148 ask->type == FDISK_ASKTYPE_WARN)) {
149 DBG(ASK, ul_debugobj(ask, "dialogs disabled"));
150 return -EINVAL;
151 }
152
4114da08 153 if (!cxt->ask_cb) {
d71bd2f0 154 DBG(ASK, ul_debugobj(ask, "no ask callback specified!"));
4114da08
KZ
155 return -EINVAL;
156 }
157
158 rc = cxt->ask_cb(cxt, ask, cxt->ask_data);
159
d71bd2f0 160 DBG(ASK, ul_debugobj(ask, "do_ask done [rc=%d]", rc));
4114da08
KZ
161 return rc;
162}
163
ab6ea0e8 164#define is_number_ask(a) (fdisk_is_ask(a, NUMBER) || fdisk_is_ask(a, OFFSET))
4114da08 165
1c01e44f
KZ
166/**
167 * fdisk_ask_number_get_range:
168 * @ask: ask instance
169 *
170 * Returns: string with range (e.g. "1,3,5-10")
171 */
7845ca8d
KZ
172const char *fdisk_ask_number_get_range(struct fdisk_ask *ask)
173{
174 assert(ask);
ab6ea0e8 175 assert(is_number_ask(ask));
7845ca8d
KZ
176 return ask->data.num.range;
177}
4114da08
KZ
178
179int fdisk_ask_number_set_range(struct fdisk_ask *ask, const char *range)
180{
181 assert(ask);
5673f30d
KZ
182 assert(is_number_ask(ask));
183 ask->data.num.range = range;
184 return 0;
4114da08
KZ
185}
186
1c01e44f
KZ
187/**
188 * fdisk_ask_number_get_default:
189 * @ask: ask instance
190 *
191 * Returns: default number
192 *
193 */
7845ca8d
KZ
194uint64_t fdisk_ask_number_get_default(struct fdisk_ask *ask)
195{
196 assert(ask);
ab6ea0e8 197 assert(is_number_ask(ask));
7845ca8d
KZ
198 return ask->data.num.dfl;
199}
200
4114da08
KZ
201int fdisk_ask_number_set_default(struct fdisk_ask *ask, uint64_t dflt)
202{
203 assert(ask);
204 ask->data.num.dfl = dflt;
205 return 0;
206}
207
1c01e44f 208/**
705854f3 209 * fdisk_ask_number_get_low:
1c01e44f
KZ
210 * @ask: ask instance
211 *
212 * Returns: minimal possible number when ask for numbers in range
213 */
7845ca8d
KZ
214uint64_t fdisk_ask_number_get_low(struct fdisk_ask *ask)
215{
216 assert(ask);
ab6ea0e8 217 assert(is_number_ask(ask));
7845ca8d
KZ
218 return ask->data.num.low;
219}
220
4114da08
KZ
221int fdisk_ask_number_set_low(struct fdisk_ask *ask, uint64_t low)
222{
223 assert(ask);
224 ask->data.num.low = low;
225 return 0;
226}
227
1c01e44f 228/**
705854f3 229 * fdisk_ask_number_get_high:
1c01e44f
KZ
230 * @ask: ask instance
231 *
232 * Returns: maximal possible number when ask for numbers in range
233 */
7845ca8d
KZ
234uint64_t fdisk_ask_number_get_high(struct fdisk_ask *ask)
235{
236 assert(ask);
ab6ea0e8 237 assert(is_number_ask(ask));
7845ca8d
KZ
238 return ask->data.num.hig;
239}
240
4114da08
KZ
241int fdisk_ask_number_set_high(struct fdisk_ask *ask, uint64_t high)
242{
243 assert(ask);
244 ask->data.num.hig = high;
245 return 0;
246}
247
1c01e44f
KZ
248/**
249 * fdisk_ask_number_get_result:
250 * @ask: ask instance
251 *
252 * Returns: result
253 */
4114da08
KZ
254uint64_t fdisk_ask_number_get_result(struct fdisk_ask *ask)
255{
256 assert(ask);
ab6ea0e8 257 assert(is_number_ask(ask));
4114da08
KZ
258 return ask->data.num.result;
259}
260
1c01e44f
KZ
261/**
262 * fdisk_ask_number_set_result:
263 * @ask: ask instance
705854f3 264 * @result: dialog result
1c01e44f
KZ
265 *
266 * Returns: 0 on success, <0 on error
267 */
7845ca8d
KZ
268int fdisk_ask_number_set_result(struct fdisk_ask *ask, uint64_t result)
269{
270 assert(ask);
271 ask->data.num.result = result;
272 return 0;
273}
274
1c01e44f
KZ
275/**
276 * fdisk_ask_number_get_base:
277 * @ask: ask instance
278 *
705854f3 279 * Returns: base when user specify number in relative notation (+size)
1c01e44f 280 */
4114da08
KZ
281uint64_t fdisk_ask_number_get_base(struct fdisk_ask *ask)
282{
283 assert(ask);
ab6ea0e8 284 assert(is_number_ask(ask));
4114da08
KZ
285 return ask->data.num.base;
286}
287
288int fdisk_ask_number_set_base(struct fdisk_ask *ask, uint64_t base)
289{
290 assert(ask);
291 ask->data.num.base = base;
292 return 0;
293}
294
1c01e44f
KZ
295/**
296 * fdisk_ask_number_get_unit:
297 * @ask: ask instance
298 *
299 * Returns: number of bytes per the unit
300 */
4114da08
KZ
301uint64_t fdisk_ask_number_get_unit(struct fdisk_ask *ask)
302{
303 assert(ask);
ab6ea0e8 304 assert(is_number_ask(ask));
4114da08
KZ
305 return ask->data.num.unit;
306}
307
308int fdisk_ask_number_set_unit(struct fdisk_ask *ask, uint64_t unit)
309{
310 assert(ask);
311 ask->data.num.unit = unit;
312 return 0;
313}
314
315int fdisk_ask_number_is_relative(struct fdisk_ask *ask)
316{
317 assert(ask);
ab6ea0e8 318 assert(is_number_ask(ask));
4114da08
KZ
319 return ask->data.num.relative;
320}
321
757cefbb
AG
322/**
323 * fdisk_ask_number_is_wrap_negative:
324 * @ask: ask instance
325 *
326 * The wrap-negative flag allows to accept negative number from user. In this
327 * case the dialog result is calculated as "high - num" (-N from high limit).
328 *
329 * Returns: 1 or 0.
330 *
331 * Since: 2.33
332 */
333int fdisk_ask_number_is_wrap_negative(struct fdisk_ask *ask)
334{
335 assert(ask);
336 assert(is_number_ask(ask));
337 return ask->data.num.wrap_negative;
338}
339
1c01e44f
KZ
340/**
341 * fdisk_ask_number_set_relative
342 * @ask: ask instance
343 * @relative: 0 or 1
344 *
345 * Inform libfdisk that user specified number in relative notation rather than
346 * by explicit number. This info allows to fdisk do some optimization (e.g.
9e930041 347 * align end of partition, etc.)
1c01e44f
KZ
348 *
349 * Returns: 0 on success, <0 on error
350 */
4114da08
KZ
351int fdisk_ask_number_set_relative(struct fdisk_ask *ask, int relative)
352{
353 assert(ask);
354 ask->data.num.relative = relative ? 1 : 0;
355 return 0;
356}
357
1c01e44f
KZ
358/**
359 * fdisk_ask_number_inchars:
360 * @ask: ask instance
361 *
362 * For example for BSD is normal to address partition by chars rather than by
363 * number (first partition is 'a').
364 *
365 * Returns: 1 if number should be presented as chars
366 *
367 */
181aab40
KZ
368int fdisk_ask_number_inchars(struct fdisk_ask *ask)
369{
370 assert(ask);
371 assert(is_number_ask(ask));
372 return ask->data.num.inchars;
373}
374
757cefbb
AG
375int fdisk_ask_number_set_wrap_negative(struct fdisk_ask *ask, int wrap_negative)
376{
377 assert(ask);
378 ask->data.num.wrap_negative = wrap_negative ? 1 : 0;
379 return 0;
380}
381
7845ca8d
KZ
382/*
383 * Generates string with list ranges (e.g. 1,2,5-8) for the 'cur'
384 */
181aab40 385#define tochar(num) ((int) ('a' + num - 1))
7845ca8d 386static char *mk_string_list(char *ptr, size_t *len, size_t *begin,
181aab40 387 size_t *run, ssize_t cur, int inchar)
7845ca8d
KZ
388{
389 int rlen;
390
391 if (cur != -1) {
392 if (!*begin) { /* begin of the list */
393 *begin = cur + 1;
394 return ptr;
395 }
396
b9710f1f 397 if (*begin + *run == (size_t)cur) { /* no gap, continue */
7845ca8d
KZ
398 (*run)++;
399 return ptr;
400 }
401 } else if (!*begin) {
402 *ptr = '\0';
403 return ptr; /* end of empty list */
404 }
405
406 /* add to the list */
407 if (!*run)
181aab40 408 rlen = inchar ? snprintf(ptr, *len, "%c,", tochar(*begin)) :
e39966c6 409 snprintf(ptr, *len, "%zu,", *begin);
7845ca8d 410 else if (*run == 1)
181aab40
KZ
411 rlen = inchar ?
412 snprintf(ptr, *len, "%c,%c,", tochar(*begin), tochar(*begin + 1)) :
e39966c6 413 snprintf(ptr, *len, "%zu,%zu,", *begin, *begin + 1);
7845ca8d 414 else
181aab40
KZ
415 rlen = inchar ?
416 snprintf(ptr, *len, "%c-%c,", tochar(*begin), tochar(*begin + *run)) :
e39966c6 417 snprintf(ptr, *len, "%zu-%zu,", *begin, *begin + *run);
7845ca8d 418
06fa5817 419 if (rlen < 0 || (size_t) rlen >= *len)
7845ca8d
KZ
420 return NULL;
421
422 ptr += rlen;
06fa5817 423 *len -= rlen;
7845ca8d
KZ
424
425 if (cur == -1 && *begin) {
426 /* end of the list */
427 *(ptr - 1) = '\0'; /* remove tailing ',' from the list */
428 return ptr;
429 }
430
431 *begin = cur + 1;
432 *run = 0;
433
434 return ptr;
435}
436
2ae3d038
KZ
437/**
438 * fdisk_ask_partnum:
439 * @cxt: context
440 * @partnum: returns partition number
441 * @wantnew: 0|1
442 *
1c01e44f 443 * High-level API to ask for used or unused partition number.
2ae3d038
KZ
444 *
445 * Returns: 0 on success, < 0 on error, 1 if no free/used partition
446 */
7845ca8d
KZ
447int fdisk_ask_partnum(struct fdisk_context *cxt, size_t *partnum, int wantnew)
448{
181aab40 449 int rc = 0, inchar = 0;
7845ca8d
KZ
450 char range[BUFSIZ], *ptr = range;
451 size_t i, len = sizeof(range), begin = 0, run = 0;
4114da08
KZ
452 struct fdisk_ask *ask = NULL;
453 __typeof__(ask->data.num) *num;
7845ca8d
KZ
454
455 assert(cxt);
456 assert(cxt->label);
457 assert(partnum);
458
181aab40
KZ
459 if (cxt->label && cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO)
460 inchar = 1;
461
88141067 462 DBG(ASK, ul_debug("%s: asking for %s partition number "
e39966c6 463 "(max: %zu, inchar: %s)",
1c736ff3 464 cxt->label ? cxt->label->name : "???",
181aab40 465 wantnew ? "new" : "used",
1c736ff3 466 cxt->label ? cxt->label->nparts_max : 0,
181aab40 467 inchar ? "yes" : "not"));
7845ca8d 468
4114da08
KZ
469 ask = fdisk_new_ask();
470 if (!ask)
471 return -ENOMEM;
472
c6d69264 473 fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
4114da08
KZ
474 num = &ask->data.num;
475
181aab40
KZ
476 ask->data.num.inchars = inchar ? 1 : 0;
477
7845ca8d 478 for (i = 0; i < cxt->label->nparts_max; i++) {
8c0a7f91 479 int used = fdisk_is_partition_used(cxt, i);
7845ca8d 480
8c0a7f91 481 if (wantnew && !used) {
181aab40 482 ptr = mk_string_list(ptr, &len, &begin, &run, i, inchar);
4114da08
KZ
483 if (!ptr) {
484 rc = -EINVAL;
485 break;
486 }
7845ca8d
KZ
487 if (!num->low)
488 num->dfl = num->low = i + 1;
489 num->hig = i + 1;
8c0a7f91 490 } else if (!wantnew && used) {
181aab40 491 ptr = mk_string_list(ptr, &len, &begin, &run, i, inchar);
7845ca8d
KZ
492 if (!num->low)
493 num->low = i + 1;
494 num->dfl = num->hig = i + 1;
495 }
496 }
497
fdbd7bb9 498 DBG(ASK, ul_debugobj(ask, "ask limits: low: %"PRIu64", high: %"PRIu64", default: %"PRIu64"",
c6d69264
KZ
499 num->low, num->hig, num->dfl));
500
501 if (!rc && !wantnew && num->low == num->hig) {
502 if (num->low > 0) {
9e930041 503 /* only one existing partition, don't ask, return the number */
c6d69264 504 fdisk_ask_number_set_result(ask, num->low);
829f4206 505 fdisk_info(cxt, _("Selected partition %ju"), num->low);
c6d69264
KZ
506
507 } else if (num->low == 0) {
8d32ade5 508 fdisk_warnx(cxt, _("No partition is defined yet!"));
c6d69264
KZ
509 rc = 1;
510 }
511 goto dont_ask;
512 }
513 if (!rc && wantnew && num->low == num->hig) {
514 if (num->low > 0) {
515 /* only one free partition, don't ask, return the number */
516 fdisk_ask_number_set_result(ask, num->low);
829f4206 517 fdisk_info(cxt, _("Selected partition %ju"), num->low);
c6d69264
KZ
518 }
519 if (num->low == 0) {
8d32ade5 520 fdisk_warnx(cxt, _("No free partition available!"));
c6d69264
KZ
521 rc = 1;
522 }
523 goto dont_ask;
524 }
4114da08 525 if (!rc) {
181aab40 526 mk_string_list(ptr, &len, &begin, &run, -1, inchar); /* terminate the list */
4114da08
KZ
527 rc = fdisk_ask_number_set_range(ask, range);
528 }
4114da08
KZ
529 if (!rc)
530 rc = fdisk_ask_set_query(ask, _("Partition number"));
4114da08
KZ
531 if (!rc)
532 rc = fdisk_do_ask(cxt, ask);
c6d69264
KZ
533
534dont_ask:
4114da08
KZ
535 if (!rc) {
536 *partnum = fdisk_ask_number_get_result(ask);
537 if (*partnum)
538 *partnum -= 1;
7845ca8d 539 }
fdbd7bb9 540 DBG(ASK, ul_debugobj(ask, "result: %"PRIu64" [rc=%d]\n", fdisk_ask_number_get_result(ask), rc));
a3d83488 541 fdisk_unref_ask(ask);
7845ca8d
KZ
542 return rc;
543}
544
1c01e44f
KZ
545/**
546 * fdisk_ask_number:
547 * @cxt: context
548 * @low: minimal possible number
549 * @dflt: default suggestion
550 * @high: maximal possible number
551 * @query: question string
552 * @result: returns result
553 *
554 * Returns: 0 on success, <0 on error.
555 */
24fc19a1
KZ
556int fdisk_ask_number(struct fdisk_context *cxt,
557 uintmax_t low,
558 uintmax_t dflt,
559 uintmax_t high,
560 const char *query,
561 uintmax_t *result)
562{
563 struct fdisk_ask *ask;
564 int rc;
565
566 assert(cxt);
567
568 ask = fdisk_new_ask();
569 if (!ask)
570 return -ENOMEM;
571
572 rc = fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
573 if (!rc)
574 fdisk_ask_number_set_low(ask, low);
575 if (!rc)
576 fdisk_ask_number_set_default(ask, dflt);
577 if (!rc)
578 fdisk_ask_number_set_high(ask, high);
579 if (!rc)
580 fdisk_ask_set_query(ask, query);
581 if (!rc)
582 rc = fdisk_do_ask(cxt, ask);
583 if (!rc)
584 *result = fdisk_ask_number_get_result(ask);
585
d71bd2f0 586 DBG(ASK, ul_debugobj(ask, "result: %ju [rc=%d]\n", *result, rc));
a3d83488 587 fdisk_unref_ask(ask);
24fc19a1
KZ
588 return rc;
589}
590
1c01e44f
KZ
591/**
592 * fdisk_ask_string_get_result:
593 * @ask: ask instance
594 *
595 * Returns: pointer to dialog result
596 */
34b06299
KZ
597char *fdisk_ask_string_get_result(struct fdisk_ask *ask)
598{
599 assert(ask);
600 assert(fdisk_is_ask(ask, STRING));
601 return ask->data.str.result;
602}
603
1c01e44f
KZ
604/**
605 * fdisk_ask_string_set_result:
606 * @ask: ask instance
607 * @result: pointer to allocated buffer with string
608 *
609 * You don't have to care about the @result deallocation, libfdisk is going to
610 * deallocate the result when destroy @ask instance.
611 *
612 * Returns: 0 on success, <0 on error
34b06299
KZ
613 */
614int fdisk_ask_string_set_result(struct fdisk_ask *ask, char *result)
615{
616 assert(ask);
617 ask->data.str.result = result;
618 return 0;
619}
620
1c01e44f
KZ
621/**
622 * fdisk_ask_string:
623 * @cxt: context:
624 * @query: question string
625 * @result: returns allocated buffer
626 *
627 * High-level API to ask for strings. Don't forget to deallocate the @result.
628 *
629 * Returns: 0 on success, <0 on error.
34b06299
KZ
630 */
631int fdisk_ask_string(struct fdisk_context *cxt,
632 const char *query,
633 char **result)
634{
635 struct fdisk_ask *ask;
636 int rc;
637
638 assert(cxt);
639
640 ask = fdisk_new_ask();
641 if (!ask)
642 return -ENOMEM;
643
644 rc = fdisk_ask_set_type(ask, FDISK_ASKTYPE_STRING);
645 if (!rc)
646 fdisk_ask_set_query(ask, query);
647 if (!rc)
648 rc = fdisk_do_ask(cxt, ask);
649 if (!rc)
650 *result = fdisk_ask_string_get_result(ask);
651
d71bd2f0 652 DBG(ASK, ul_debugobj(ask, "result: %s [rc=%d]\n", *result, rc));
a3d83488 653 fdisk_unref_ask(ask);
34b06299
KZ
654 return rc;
655}
656
1c01e44f
KZ
657/**
658 * fdisk_ask_yesno:
659 * @cxt: context
660 * @query: question string
661 * @result: returns 0 (no) or 1 (yes)
662 *
9e930041 663 * High-level API to ask Yes/No questions
1c01e44f
KZ
664 *
665 * Returns: 0 on success, <0 on error
666 */
ccf48af5
KZ
667int fdisk_ask_yesno(struct fdisk_context *cxt,
668 const char *query,
669 int *result)
670{
671 struct fdisk_ask *ask;
672 int rc;
673
674 assert(cxt);
675
676 ask = fdisk_new_ask();
677 if (!ask)
678 return -ENOMEM;
679
680 rc = fdisk_ask_set_type(ask, FDISK_ASKTYPE_YESNO);
681 if (!rc)
682 fdisk_ask_set_query(ask, query);
683 if (!rc)
684 rc = fdisk_do_ask(cxt, ask);
685 if (!rc)
2d129032 686 *result = fdisk_ask_yesno_get_result(ask) == 1 ? 1 : 0;
ccf48af5 687
d71bd2f0 688 DBG(ASK, ul_debugobj(ask, "result: %d [rc=%d]\n", *result, rc));
a3d83488 689 fdisk_unref_ask(ask);
ccf48af5
KZ
690 return rc;
691}
692
1c01e44f
KZ
693/**
694 * fdisk_ask_yesno_get_result:
695 * @ask: ask instance
696 *
697 * Returns: 0 or 1
698 */
699int fdisk_ask_yesno_get_result(struct fdisk_ask *ask)
ccf48af5
KZ
700{
701 assert(ask);
702 assert(fdisk_is_ask(ask, YESNO));
703 return ask->data.yesno.result;
704}
705
1c01e44f
KZ
706/**
707 * fdisk_ask_yesno_set_result:
708 * @ask: ask instance
709 * @result: 1 or 0
710 *
711 * Returns: 0 on success, <0 on error
712 */
713int fdisk_ask_yesno_set_result(struct fdisk_ask *ask, int result)
ccf48af5
KZ
714{
715 assert(ask);
716 ask->data.yesno.result = result;
717 return 0;
718}
719
20f878fe
KZ
720/*
721 * menu
722 */
723int fdisk_ask_menu_set_default(struct fdisk_ask *ask, int dfl)
724{
725 assert(ask);
726 assert(fdisk_is_ask(ask, MENU));
727 ask->data.menu.dfl = dfl;
728 return 0;
729}
730
1c01e44f
KZ
731/**
732 * fdisk_ask_menu_get_default:
733 * @ask: ask instance
734 *
735 * Returns: default menu item key
736 */
20f878fe
KZ
737int fdisk_ask_menu_get_default(struct fdisk_ask *ask)
738{
739 assert(ask);
740 assert(fdisk_is_ask(ask, MENU));
741 return ask->data.menu.dfl;
742}
743
1c01e44f
KZ
744/**
745 * fdisk_ask_menu_set_result:
746 * @ask: ask instance
747 * @key: result
748 *
749 * Returns: 0 on success, <0 on error
750 */
20f878fe
KZ
751int fdisk_ask_menu_set_result(struct fdisk_ask *ask, int key)
752{
753 assert(ask);
754 assert(fdisk_is_ask(ask, MENU));
755 ask->data.menu.result = key;
d71bd2f0 756 DBG(ASK, ul_debugobj(ask, "menu result: %c\n", key));
20f878fe
KZ
757 return 0;
758
759}
760
1c01e44f
KZ
761/**
762 * fdisk_ask_menu_get_result:
763 * @ask: ask instance
764 * @key: returns selected menu item key
765 *
766 * Returns: 0 on success, <0 on error.
767 */
20f878fe
KZ
768int fdisk_ask_menu_get_result(struct fdisk_ask *ask, int *key)
769{
770 assert(ask);
771 assert(fdisk_is_ask(ask, MENU));
772 if (key)
773 *key = ask->data.menu.result;
774 return 0;
775}
776
1c01e44f
KZ
777/**
778 * fdisk_ask_menu_get_item:
779 * @ask: ask menu instance
780 * @idx: wanted menu item index
781 * @key: returns key of the menu item
782 * @name: returns name of the menu item
783 * @desc: returns description of the menu item
784 *
785 * Returns: 0 on success, <0 on error, >0 if idx out-of-range
786 */
20f878fe
KZ
787int fdisk_ask_menu_get_item(struct fdisk_ask *ask, size_t idx, int *key,
788 const char **name, const char **desc)
789{
790 size_t i;
791 struct ask_menuitem *mi;
792
793 assert(ask);
794 assert(fdisk_is_ask(ask, MENU));
795
796 for (i = 0, mi = ask->data.menu.first; mi; mi = mi->next, i++) {
797 if (i == idx)
798 break;
799 }
800
801 if (!mi)
802 return 1; /* no more items */
803 if (key)
804 *key = mi->key;
805 if (name)
806 *name = mi->name;
807 if (desc)
808 *desc = mi->desc;
809 return 0;
810}
811
812static void fdisk_ask_menu_reset_items(struct fdisk_ask *ask)
813{
814 struct ask_menuitem *mi;
815
816 assert(ask);
817 assert(fdisk_is_ask(ask, MENU));
818
819 for (mi = ask->data.menu.first; mi; ) {
820 struct ask_menuitem *next = mi->next;
821 free(mi);
822 mi = next;
823 }
824}
825
1c01e44f
KZ
826/**
827 * fdisk_ask_menu_get_nitems:
828 * @ask: ask instance
829 *
830 * Returns: number of menu items
831 */
20f878fe
KZ
832size_t fdisk_ask_menu_get_nitems(struct fdisk_ask *ask)
833{
834 struct ask_menuitem *mi;
835 size_t n;
836
837 assert(ask);
838 assert(fdisk_is_ask(ask, MENU));
839
840 for (n = 0, mi = ask->data.menu.first; mi; mi = mi->next, n++);
841
842 return n;
843}
844
845int fdisk_ask_menu_add_item(struct fdisk_ask *ask, int key,
846 const char *name, const char *desc)
847{
848 struct ask_menuitem *mi;
849
850 assert(ask);
851 assert(fdisk_is_ask(ask, MENU));
852
853 mi = calloc(1, sizeof(*mi));
854 if (!mi)
855 return -ENOMEM;
856 mi->key = key;
857 mi->name = name;
858 mi->desc = desc;
859
860 if (!ask->data.menu.first)
861 ask->data.menu.first = mi;
862 else {
863 struct ask_menuitem *last = ask->data.menu.first;
864
865 while (last->next)
866 last = last->next;
867 last->next = mi;
868 }
869
d71bd2f0 870 DBG(ASK, ul_debugobj(ask, "new menu item: %c, \"%s\" (%s)\n", mi->key, mi->name, mi->desc));
20f878fe
KZ
871 return 0;
872}
873
874
875/*
876 * print-like
877 */
878
ab6ea0e8
KZ
879#define is_print_ask(a) (fdisk_is_ask(a, WARN) || fdisk_is_ask(a, WARNX) || fdisk_is_ask(a, INFO))
880
1c01e44f
KZ
881/**
882 * fdisk_ask_print_get_errno:
883 * @ask: ask instance
884 *
885 * Returns: error number for warning/error messages
886 */
ab6ea0e8
KZ
887int fdisk_ask_print_get_errno(struct fdisk_ask *ask)
888{
889 assert(ask);
890 assert(is_print_ask(ask));
891 return ask->data.print.errnum;
892}
893
894int fdisk_ask_print_set_errno(struct fdisk_ask *ask, int errnum)
895{
896 assert(ask);
897 ask->data.print.errnum = errnum;
898 return 0;
899}
900
1c01e44f
KZ
901/**
902 * fdisk_ask_print_get_mesg:
903 * @ask: ask instance
904 *
905 * Returns: pointer to message
906 */
ab6ea0e8
KZ
907const char *fdisk_ask_print_get_mesg(struct fdisk_ask *ask)
908{
909 assert(ask);
910 assert(is_print_ask(ask));
911 return ask->data.print.mesg;
912}
913
914/* does not reallocate the message! */
915int fdisk_ask_print_set_mesg(struct fdisk_ask *ask, const char *mesg)
916{
917 assert(ask);
918 ask->data.print.mesg = mesg;
919 return 0;
920}
921
ab6ea0e8 922static int do_vprint(struct fdisk_context *cxt, int errnum, int type,
0477369a 923 const char *fmt, va_list va)
ab6ea0e8
KZ
924{
925 struct fdisk_ask *ask;
926 int rc;
4fb18cde 927 char *mesg;
ab6ea0e8
KZ
928
929 assert(cxt);
930
4fb18cde
KZ
931 if (vasprintf(&mesg, fmt, va) < 0)
932 return -ENOMEM;
933
ab6ea0e8 934 ask = fdisk_new_ask();
4fb18cde
KZ
935 if (!ask) {
936 free(mesg);
ab6ea0e8 937 return -ENOMEM;
4fb18cde 938 }
ab6ea0e8
KZ
939
940 fdisk_ask_set_type(ask, type);
4fb18cde 941 fdisk_ask_print_set_mesg(ask, mesg);
ab6ea0e8
KZ
942 if (errnum >= 0)
943 fdisk_ask_print_set_errno(ask, errnum);
944 rc = fdisk_do_ask(cxt, ask);
945
a3d83488 946 fdisk_unref_ask(ask);
4fb18cde 947 free(mesg);
ab6ea0e8
KZ
948 return rc;
949}
950
1c01e44f
KZ
951/**
952 * fdisk_info:
953 * @cxt: context
954 * @fmt: printf-like formatted string
9e930041 955 * @...: variable parameters
1c01e44f
KZ
956 *
957 * High-level API to print info messages,
958 *
959 * Returns: 0 on success, <0 on error
960 */
ab6ea0e8
KZ
961int fdisk_info(struct fdisk_context *cxt, const char *fmt, ...)
962{
963 int rc;
964 va_list ap;
965
966 assert(cxt);
967 va_start(ap, fmt);
0477369a 968 rc = do_vprint(cxt, -1, FDISK_ASKTYPE_INFO, fmt, ap);
dd00d1b2
KZ
969 va_end(ap);
970 return rc;
dd00d1b2
KZ
971}
972
1c01e44f
KZ
973/**
974 * fdisk_info:
975 * @cxt: context
976 * @fmt: printf-like formatted string
9e930041 977 * @...: variable parameters
1c01e44f
KZ
978 *
979 * High-level API to print warning message (errno expected)
980 *
981 * Returns: 0 on success, <0 on error
982 */
ab6ea0e8
KZ
983int fdisk_warn(struct fdisk_context *cxt, const char *fmt, ...)
984{
985 int rc;
986 va_list ap;
987
988 assert(cxt);
989 va_start(ap, fmt);
0477369a 990 rc = do_vprint(cxt, errno, FDISK_ASKTYPE_WARN, fmt, ap);
ab6ea0e8
KZ
991 va_end(ap);
992 return rc;
993}
994
1c01e44f
KZ
995/**
996 * fdisk_warnx:
997 * @cxt: context
998 * @fmt: printf-like formatted string
705854f3 999 * @...: variable options
1c01e44f
KZ
1000 *
1001 * High-level API to print warning message
1002 *
1003 * Returns: 0 on success, <0 on error
1004 */
ab6ea0e8
KZ
1005int fdisk_warnx(struct fdisk_context *cxt, const char *fmt, ...)
1006{
1007 int rc;
1008 va_list ap;
1009
1010 assert(cxt);
1011 va_start(ap, fmt);
0477369a 1012 rc = do_vprint(cxt, -1, FDISK_ASKTYPE_WARNX, fmt, ap);
ab6ea0e8
KZ
1013 va_end(ap);
1014 return rc;
1015}
7845ca8d 1016
b4bfbadd
KZ
1017int fdisk_info_new_partition(
1018 struct fdisk_context *cxt,
0073a4cf 1019 int num, fdisk_sector_t start, fdisk_sector_t stop,
b4bfbadd
KZ
1020 struct fdisk_parttype *t)
1021{
1022 int rc;
1023 char *str = size_to_human_string(SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE,
1024 (uint64_t)(stop - start + 1) * cxt->sector_size);
1025
0477369a 1026 rc = fdisk_info(cxt,
513d5462 1027 _("Created a new partition %d of type '%s' and of size %s."),
b4bfbadd
KZ
1028 num, t ? t->name : _("Unknown"), str);
1029 free(str);
1030 return rc;
1031}
1032
7845ca8d 1033#ifdef TEST_PROGRAM
5fde1d9f 1034static int test_ranges(struct fdisk_test *ts, int argc, char *argv[])
7845ca8d
KZ
1035{
1036 /* 1 - 3, 6, 8, 9, 11 13 */
1037 size_t nums[] = { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1 };
1038 size_t numx[] = { 0, 0, 0 };
1039 char range[BUFSIZ], *ptr = range;
1040 size_t i, len = sizeof(range), begin = 0, run = 0;
1041
1042 for (i = 0; i < ARRAY_SIZE(nums); i++) {
1043 if (!nums[i])
1044 continue;
c66a03c8 1045 ptr = mk_string_list(ptr, &len, &begin, &run, i, 0);
7845ca8d 1046 }
c66a03c8 1047 mk_string_list(ptr, &len, &begin, &run, -1, 0);
7845ca8d
KZ
1048 printf("list: '%s'\n", range);
1049
1050 ptr = range;
1051 len = sizeof(range), begin = 0, run = 0;
1052 for (i = 0; i < ARRAY_SIZE(numx); i++) {
1053 if (!numx[i])
1054 continue;
c66a03c8 1055 ptr = mk_string_list(ptr, &len, &begin, &run, i, 0);
7845ca8d 1056 }
c66a03c8 1057 mk_string_list(ptr, &len, &begin, &run, -1, 0);
7845ca8d
KZ
1058 printf("empty list: '%s'\n", range);
1059
1060 return 0;
1061}
1062
1063int main(int argc, char *argv[])
1064{
1065 struct fdisk_test tss[] = {
1066 { "--ranges", test_ranges, "generates ranges" },
1067 { NULL }
1068 };
1069
1070 return fdisk_run_test(tss, argc, argv);
1071}
1072
1073#endif