]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libfdisk/src/ask.c
libfdisk: use new debug functions
[thirdparty/util-linux.git] / libfdisk / src / ask.c
1
2 #include "strutils.h"
3
4 #include "fdiskP.h"
5
6 static void fdisk_ask_menu_reset_items(struct fdisk_ask *ask);
7
8
9 struct fdisk_ask *fdisk_new_ask(void)
10 {
11 return calloc(1, sizeof(struct fdisk_ask));
12 }
13
14 void fdisk_reset_ask(struct fdisk_ask *ask)
15 {
16 assert(ask);
17 free(ask->query);
18
19 if (fdisk_is_ask(ask, MENU))
20 fdisk_ask_menu_reset_items(ask);
21
22 memset(ask, 0, sizeof(*ask));
23 }
24
25 void fdisk_free_ask(struct fdisk_ask *ask)
26 {
27 if (!ask)
28 return;
29 fdisk_reset_ask(ask);
30 free(ask);
31 }
32
33 const char *fdisk_ask_get_query(struct fdisk_ask *ask)
34 {
35 assert(ask);
36 return ask->query;
37 }
38
39 int fdisk_ask_set_query(struct fdisk_ask *ask, const char *str)
40 {
41 assert(ask);
42 return !strdup_to_struct_member(ask, query, str) ? -ENOMEM : 0;
43 }
44
45 int fdisk_ask_get_type(struct fdisk_ask *ask)
46 {
47 assert(ask);
48 return ask->type;
49 }
50
51 int fdisk_ask_set_type(struct fdisk_ask *ask, int type)
52 {
53 assert(ask);
54 ask->type = type;
55 return 0;
56 }
57
58 unsigned int fdisk_ask_get_flags(struct fdisk_ask *ask)
59 {
60 assert(ask);
61 return ask->flags;
62 }
63
64 int fdisk_ask_set_flags(struct fdisk_ask *ask, unsigned int flags)
65 {
66 assert(ask);
67 ask->flags = flags;
68 return 0;
69 }
70
71 int fdisk_do_ask(struct fdisk_context *cxt, struct fdisk_ask *ask)
72 {
73 int rc;
74
75 assert(ask);
76 assert(cxt);
77
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" :
83 "?nothing?"));
84
85 if (!cxt->ask_cb) {
86 DBG(ASK, ul_debug("no ask callback specified!"));
87 return -EINVAL;
88 }
89
90 rc = cxt->ask_cb(cxt, ask, cxt->ask_data);
91
92 DBG(ASK, ul_debug("do_ask done [rc=%d]", rc));
93 return rc;
94 }
95
96 #define is_number_ask(a) (fdisk_is_ask(a, NUMBER) || fdisk_is_ask(a, OFFSET))
97
98 const char *fdisk_ask_number_get_range(struct fdisk_ask *ask)
99 {
100 assert(ask);
101 assert(is_number_ask(ask));
102 return ask->data.num.range;
103 }
104
105 int fdisk_ask_number_set_range(struct fdisk_ask *ask, const char *range)
106 {
107 assert(ask);
108 assert(is_number_ask(ask));
109 ask->data.num.range = range;
110 return 0;
111 }
112
113 uint64_t fdisk_ask_number_get_default(struct fdisk_ask *ask)
114 {
115 assert(ask);
116 assert(is_number_ask(ask));
117 return ask->data.num.dfl;
118 }
119
120 int fdisk_ask_number_set_default(struct fdisk_ask *ask, uint64_t dflt)
121 {
122 assert(ask);
123 ask->data.num.dfl = dflt;
124 return 0;
125 }
126
127 uint64_t fdisk_ask_number_get_low(struct fdisk_ask *ask)
128 {
129 assert(ask);
130 assert(is_number_ask(ask));
131 return ask->data.num.low;
132 }
133
134 int fdisk_ask_number_set_low(struct fdisk_ask *ask, uint64_t low)
135 {
136 assert(ask);
137 ask->data.num.low = low;
138 return 0;
139 }
140
141 uint64_t fdisk_ask_number_get_high(struct fdisk_ask *ask)
142 {
143 assert(ask);
144 assert(is_number_ask(ask));
145 return ask->data.num.hig;
146 }
147
148 int fdisk_ask_number_set_high(struct fdisk_ask *ask, uint64_t high)
149 {
150 assert(ask);
151 ask->data.num.hig = high;
152 return 0;
153 }
154
155 uint64_t fdisk_ask_number_get_result(struct fdisk_ask *ask)
156 {
157 assert(ask);
158 assert(is_number_ask(ask));
159 return ask->data.num.result;
160 }
161
162 int fdisk_ask_number_set_result(struct fdisk_ask *ask, uint64_t result)
163 {
164 assert(ask);
165 ask->data.num.result = result;
166 return 0;
167 }
168
169 uint64_t fdisk_ask_number_get_base(struct fdisk_ask *ask)
170 {
171 assert(ask);
172 assert(is_number_ask(ask));
173 return ask->data.num.base;
174 }
175
176 int fdisk_ask_number_set_base(struct fdisk_ask *ask, uint64_t base)
177 {
178 assert(ask);
179 ask->data.num.base = base;
180 return 0;
181 }
182
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)
185 {
186 assert(ask);
187 assert(is_number_ask(ask));
188 return ask->data.num.unit;
189 }
190
191 int fdisk_ask_number_set_unit(struct fdisk_ask *ask, uint64_t unit)
192 {
193 assert(ask);
194 ask->data.num.unit = unit;
195 return 0;
196 }
197
198 int fdisk_ask_number_is_relative(struct fdisk_ask *ask)
199 {
200 assert(ask);
201 assert(is_number_ask(ask));
202 return ask->data.num.relative;
203 }
204
205 int fdisk_ask_number_set_relative(struct fdisk_ask *ask, int relative)
206 {
207 assert(ask);
208 ask->data.num.relative = relative ? 1 : 0;
209 return 0;
210 }
211
212 int fdisk_ask_number_inchars(struct fdisk_ask *ask)
213 {
214 assert(ask);
215 assert(is_number_ask(ask));
216 return ask->data.num.inchars;
217 }
218
219 /*
220 * Generates string with list ranges (e.g. 1,2,5-8) for the 'cur'
221 */
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)
225 {
226 int rlen;
227
228 if (cur != -1) {
229 if (!*begin) { /* begin of the list */
230 *begin = cur + 1;
231 return ptr;
232 }
233
234 if (*begin + *run == cur) { /* no gap, continue */
235 (*run)++;
236 return ptr;
237 }
238 } else if (!*begin) {
239 *ptr = '\0';
240 return ptr; /* end of empty list */
241 }
242
243 /* add to the list */
244 if (!*run)
245 rlen = inchar ? snprintf(ptr, *len, "%c,", tochar(*begin)) :
246 snprintf(ptr, *len, "%zu,", *begin);
247 else if (*run == 1)
248 rlen = inchar ?
249 snprintf(ptr, *len, "%c,%c,", tochar(*begin), tochar(*begin + 1)) :
250 snprintf(ptr, *len, "%zu,%zu,", *begin, *begin + 1);
251 else
252 rlen = inchar ?
253 snprintf(ptr, *len, "%c-%c,", tochar(*begin), tochar(*begin + *run)) :
254 snprintf(ptr, *len, "%zu-%zu,", *begin, *begin + *run);
255
256 if (rlen < 0 || (size_t) rlen + 1 > *len)
257 return NULL;
258
259 ptr += rlen;
260
261 if (rlen > 0 && *len > (size_t) rlen)
262 *len -= rlen;
263 else
264 *len = 0;
265
266 if (cur == -1 && *begin) {
267 /* end of the list */
268 *(ptr - 1) = '\0'; /* remove tailing ',' from the list */
269 return ptr;
270 }
271
272 *begin = cur + 1;
273 *run = 0;
274
275 return ptr;
276 }
277
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)
280 {
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;
286
287 assert(cxt);
288 assert(cxt->label);
289 assert(partnum);
290
291 if (cxt->label && cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO)
292 inchar = 1;
293
294 DBG(ASK, ul_debug("%s: asking for %s partition number "
295 "(max: %zu, inchar: %s)",
296 cxt->label->name,
297 wantnew ? "new" : "used",
298 cxt->label->nparts_max,
299 inchar ? "yes" : "not"));
300
301 ask = fdisk_new_ask();
302 if (!ask)
303 return -ENOMEM;
304
305 fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
306 num = &ask->data.num;
307
308 ask->data.num.inchars = inchar ? 1 : 0;
309
310 for (i = 0; i < cxt->label->nparts_max; i++) {
311 int used = fdisk_is_partition_used(cxt, i);
312
313 if (wantnew && !used) {
314 ptr = mk_string_list(ptr, &len, &begin, &run, i, inchar);
315 if (!ptr) {
316 rc = -EINVAL;
317 break;
318 }
319 if (!num->low)
320 num->dfl = num->low = i + 1;
321 num->hig = i + 1;
322 } else if (!wantnew && used) {
323 ptr = mk_string_list(ptr, &len, &begin, &run, i, inchar);
324 if (!num->low)
325 num->low = i + 1;
326 num->dfl = num->hig = i + 1;
327 }
328 }
329
330 DBG(ASK, ul_debug("ask limits: low: %ju, high: %ju, default: %ju",
331 num->low, num->hig, num->dfl));
332
333 if (!rc && !wantnew && num->low == num->hig) {
334 if (num->low > 0) {
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);
338
339 } else if (num->low == 0) {
340 fdisk_warnx(cxt, _("No partition is defined yet!"));
341 rc = 1;
342 }
343 goto dont_ask;
344 }
345 if (!rc && wantnew && num->low == num->hig) {
346 if (num->low > 0) {
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);
350 }
351 if (num->low == 0) {
352 fdisk_warnx(cxt, _("No free partition available!"));
353 rc = 1;
354 }
355 goto dont_ask;
356 }
357 if (!rc) {
358 mk_string_list(ptr, &len, &begin, &run, -1, inchar); /* terminate the list */
359 rc = fdisk_ask_number_set_range(ask, range);
360 }
361 if (!rc)
362 rc = fdisk_ask_set_query(ask, _("Partition number"));
363 if (!rc)
364 rc = fdisk_do_ask(cxt, ask);
365
366 dont_ask:
367 if (!rc) {
368 *partnum = fdisk_ask_number_get_result(ask);
369 if (*partnum)
370 *partnum -= 1;
371 }
372 DBG(ASK, ul_debug("result: %ju [rc=%d]\n", fdisk_ask_number_get_result(ask), rc));
373 fdisk_free_ask(ask);
374 return rc;
375 }
376
377 /* very basic wraper to ask numbers */
378 int fdisk_ask_number(struct fdisk_context *cxt,
379 uintmax_t low,
380 uintmax_t dflt,
381 uintmax_t high,
382 const char *query,
383 uintmax_t *result)
384 {
385 struct fdisk_ask *ask;
386 int rc;
387
388 assert(cxt);
389
390 ask = fdisk_new_ask();
391 if (!ask)
392 return -ENOMEM;
393
394 rc = fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
395 if (!rc)
396 fdisk_ask_number_set_low(ask, low);
397 if (!rc)
398 fdisk_ask_number_set_default(ask, dflt);
399 if (!rc)
400 fdisk_ask_number_set_high(ask, high);
401 if (!rc)
402 fdisk_ask_set_query(ask, query);
403 if (!rc)
404 rc = fdisk_do_ask(cxt, ask);
405 if (!rc)
406 *result = fdisk_ask_number_get_result(ask);
407
408 fdisk_free_ask(ask);
409 DBG(ASK, ul_debug("result: %ju [rc=%d]\n", *result, rc));
410 return rc;
411 }
412
413 char *fdisk_ask_string_get_result(struct fdisk_ask *ask)
414 {
415 assert(ask);
416 assert(fdisk_is_ask(ask, STRING));
417 return ask->data.str.result;
418 }
419
420 /*
421 * The @result has to be poiter to the allocated buffer.
422 */
423 int fdisk_ask_string_set_result(struct fdisk_ask *ask, char *result)
424 {
425 assert(ask);
426 ask->data.str.result = result;
427 return 0;
428 }
429
430 /*
431 * Don't forget to deallocate @result.
432 */
433 int fdisk_ask_string(struct fdisk_context *cxt,
434 const char *query,
435 char **result)
436 {
437 struct fdisk_ask *ask;
438 int rc;
439
440 assert(cxt);
441
442 ask = fdisk_new_ask();
443 if (!ask)
444 return -ENOMEM;
445
446 rc = fdisk_ask_set_type(ask, FDISK_ASKTYPE_STRING);
447 if (!rc)
448 fdisk_ask_set_query(ask, query);
449 if (!rc)
450 rc = fdisk_do_ask(cxt, ask);
451 if (!rc)
452 *result = fdisk_ask_string_get_result(ask);
453
454 fdisk_free_ask(ask);
455 DBG(ASK, ul_debug("result: %s [rc=%d]\n", *result, rc));
456 return rc;
457 }
458
459 int fdisk_ask_yesno(struct fdisk_context *cxt,
460 const char *query,
461 int *result)
462 {
463 struct fdisk_ask *ask;
464 int rc;
465
466 assert(cxt);
467
468 ask = fdisk_new_ask();
469 if (!ask)
470 return -ENOMEM;
471
472 rc = fdisk_ask_set_type(ask, FDISK_ASKTYPE_YESNO);
473 if (!rc)
474 fdisk_ask_set_query(ask, query);
475 if (!rc)
476 rc = fdisk_do_ask(cxt, ask);
477 if (!rc)
478 *result = fdisk_ask_yesno_get_result(ask);
479
480 fdisk_free_ask(ask);
481 DBG(ASK, ul_debug("result: %d [rc=%d]\n", *result, rc));
482 return rc;
483 }
484
485 uint64_t fdisk_ask_yesno_get_result(struct fdisk_ask *ask)
486 {
487 assert(ask);
488 assert(fdisk_is_ask(ask, YESNO));
489 return ask->data.yesno.result;
490 }
491
492 int fdisk_ask_yesno_set_result(struct fdisk_ask *ask, uint64_t result)
493 {
494 assert(ask);
495 ask->data.yesno.result = result;
496 return 0;
497 }
498
499 /*
500 * menu
501 */
502 int fdisk_ask_menu_set_default(struct fdisk_ask *ask, int dfl)
503 {
504 assert(ask);
505 assert(fdisk_is_ask(ask, MENU));
506 ask->data.menu.dfl = dfl;
507 return 0;
508 }
509
510 int fdisk_ask_menu_get_default(struct fdisk_ask *ask)
511 {
512 assert(ask);
513 assert(fdisk_is_ask(ask, MENU));
514 return ask->data.menu.dfl;
515 }
516
517 int fdisk_ask_menu_set_result(struct fdisk_ask *ask, int key)
518 {
519 assert(ask);
520 assert(fdisk_is_ask(ask, MENU));
521 ask->data.menu.result = key;
522 DBG(ASK, ul_debug("menu result: %c\n", key));
523 return 0;
524
525 }
526
527 int fdisk_ask_menu_get_result(struct fdisk_ask *ask, int *key)
528 {
529 assert(ask);
530 assert(fdisk_is_ask(ask, MENU));
531 if (key)
532 *key = ask->data.menu.result;
533 return 0;
534 }
535
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)
539 {
540 size_t i;
541 struct ask_menuitem *mi;
542
543 assert(ask);
544 assert(fdisk_is_ask(ask, MENU));
545
546 for (i = 0, mi = ask->data.menu.first; mi; mi = mi->next, i++) {
547 if (i == idx)
548 break;
549 }
550
551 if (!mi)
552 return 1; /* no more items */
553 if (key)
554 *key = mi->key;
555 if (name)
556 *name = mi->name;
557 if (desc)
558 *desc = mi->desc;
559 return 0;
560 }
561
562 static void fdisk_ask_menu_reset_items(struct fdisk_ask *ask)
563 {
564 struct ask_menuitem *mi;
565
566 assert(ask);
567 assert(fdisk_is_ask(ask, MENU));
568
569 for (mi = ask->data.menu.first; mi; ) {
570 struct ask_menuitem *next = mi->next;
571 free(mi);
572 mi = next;
573 }
574 }
575
576 size_t fdisk_ask_menu_get_nitems(struct fdisk_ask *ask)
577 {
578 struct ask_menuitem *mi;
579 size_t n;
580
581 assert(ask);
582 assert(fdisk_is_ask(ask, MENU));
583
584 for (n = 0, mi = ask->data.menu.first; mi; mi = mi->next, n++);
585
586 return n;
587 }
588
589 int fdisk_ask_menu_add_item(struct fdisk_ask *ask, int key,
590 const char *name, const char *desc)
591 {
592 struct ask_menuitem *mi;
593
594 assert(ask);
595 assert(fdisk_is_ask(ask, MENU));
596
597 mi = calloc(1, sizeof(*mi));
598 if (!mi)
599 return -ENOMEM;
600 mi->key = key;
601 mi->name = name;
602 mi->desc = desc;
603
604 if (!ask->data.menu.first)
605 ask->data.menu.first = mi;
606 else {
607 struct ask_menuitem *last = ask->data.menu.first;
608
609 while (last->next)
610 last = last->next;
611 last->next = mi;
612 }
613
614 DBG(ASK, ul_debug("new menu item: %c, \"%s\" (%s)\n", mi->key, mi->name, mi->desc));
615 return 0;
616 }
617
618
619 /*
620 * print-like
621 */
622
623 #define is_print_ask(a) (fdisk_is_ask(a, WARN) || fdisk_is_ask(a, WARNX) || fdisk_is_ask(a, INFO))
624
625 int fdisk_ask_print_get_errno(struct fdisk_ask *ask)
626 {
627 assert(ask);
628 assert(is_print_ask(ask));
629 return ask->data.print.errnum;
630 }
631
632 int fdisk_ask_print_set_errno(struct fdisk_ask *ask, int errnum)
633 {
634 assert(ask);
635 ask->data.print.errnum = errnum;
636 return 0;
637 }
638
639 const char *fdisk_ask_print_get_mesg(struct fdisk_ask *ask)
640 {
641 assert(ask);
642 assert(is_print_ask(ask));
643 return ask->data.print.mesg;
644 }
645
646 /* does not reallocate the message! */
647 int fdisk_ask_print_set_mesg(struct fdisk_ask *ask, const char *mesg)
648 {
649 assert(ask);
650 ask->data.print.mesg = mesg;
651 return 0;
652 }
653
654 static int do_vprint(struct fdisk_context *cxt, int errnum, int type,
655 unsigned int flags, const char *fmt, va_list va)
656 {
657 struct fdisk_ask *ask;
658 int rc;
659 char *mesg;
660
661 assert(cxt);
662
663 if (vasprintf(&mesg, fmt, va) < 0)
664 return -ENOMEM;
665
666 ask = fdisk_new_ask();
667 if (!ask) {
668 free(mesg);
669 return -ENOMEM;
670 }
671
672 fdisk_ask_set_type(ask, type);
673 fdisk_ask_set_flags(ask, flags);
674 fdisk_ask_print_set_mesg(ask, mesg);
675 if (errnum >= 0)
676 fdisk_ask_print_set_errno(ask, errnum);
677 rc = fdisk_do_ask(cxt, ask);
678
679 fdisk_free_ask(ask);
680 free(mesg);
681 return rc;
682 }
683
684 int fdisk_info(struct fdisk_context *cxt, const char *fmt, ...)
685 {
686 int rc;
687 va_list ap;
688
689 assert(cxt);
690 va_start(ap, fmt);
691 rc = do_vprint(cxt, -1, FDISK_ASKTYPE_INFO, 0, fmt, ap);
692 va_end(ap);
693 return rc;
694 }
695
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, ...)
699 {
700 int rc;
701 va_list ap;
702
703 assert(cxt);
704 va_start(ap, fmt);
705 rc = do_vprint(cxt, -1, FDISK_ASKTYPE_INFO, flags, fmt, ap);
706 va_end(ap);
707 return rc;
708
709 }
710
711 int fdisk_colon(struct fdisk_context *cxt, const char *fmt, ...)
712 {
713 int rc;
714 va_list ap;
715
716 assert(cxt);
717 va_start(ap, fmt);
718 rc = do_vprint(cxt, -1, FDISK_ASKTYPE_INFO, FDISK_INFO_COLON, fmt, ap);
719 va_end(ap);
720 return rc;
721
722 }
723
724 int fdisk_warn(struct fdisk_context *cxt, const char *fmt, ...)
725 {
726 int rc;
727 va_list ap;
728
729 assert(cxt);
730 va_start(ap, fmt);
731 rc = do_vprint(cxt, errno, FDISK_ASKTYPE_WARN, 0, fmt, ap);
732 va_end(ap);
733 return rc;
734 }
735
736 int fdisk_warnx(struct fdisk_context *cxt, const char *fmt, ...)
737 {
738 int rc;
739 va_list ap;
740
741 assert(cxt);
742 va_start(ap, fmt);
743 rc = do_vprint(cxt, -1, FDISK_ASKTYPE_WARNX, 0, fmt, ap);
744 va_end(ap);
745 return rc;
746 }
747
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)
752 {
753 int rc;
754 char *str = size_to_human_string(SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE,
755 (uint64_t)(stop - start + 1) * cxt->sector_size);
756
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);
760 free(str);
761 return rc;
762 }
763
764 #ifdef TEST_PROGRAM
765 int test_ranges(struct fdisk_test *ts, int argc, char *argv[])
766 {
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;
772
773 for (i = 0; i < ARRAY_SIZE(nums); i++) {
774 if (!nums[i])
775 continue;
776 ptr = mk_string_list(ptr, &len, &begin, &run, i, 0);
777 }
778 mk_string_list(ptr, &len, &begin, &run, -1, 0);
779 printf("list: '%s'\n", range);
780
781 ptr = range;
782 len = sizeof(range), begin = 0, run = 0;
783 for (i = 0; i < ARRAY_SIZE(numx); i++) {
784 if (!numx[i])
785 continue;
786 ptr = mk_string_list(ptr, &len, &begin, &run, i, 0);
787 }
788 mk_string_list(ptr, &len, &begin, &run, -1, 0);
789 printf("empty list: '%s'\n", range);
790
791 return 0;
792 }
793
794 int main(int argc, char *argv[])
795 {
796 struct fdisk_test tss[] = {
797 { "--ranges", test_ranges, "generates ranges" },
798 { NULL }
799 };
800
801 return fdisk_run_test(tss, argc, argv);
802 }
803
804 #endif