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