]>
Commit | Line | Data |
---|---|---|
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 | 12 | static 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 | */ | |
25 | int 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 |
36 | struct 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 | ||
44 | void 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 | */ |
67 | void 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 | */ | |
81 | void 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 | 100 | const char *fdisk_ask_get_query(struct fdisk_ask *ask) |
7845ca8d KZ |
101 | { |
102 | assert(ask); | |
103 | return ask->query; | |
104 | } | |
105 | ||
4114da08 KZ |
106 | int 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 |
118 | int fdisk_ask_get_type(struct fdisk_ask *ask) |
119 | { | |
120 | assert(ask); | |
121 | return ask->type; | |
122 | } | |
123 | ||
4114da08 KZ |
124 | int fdisk_ask_set_type(struct fdisk_ask *ask, int type) |
125 | { | |
126 | assert(ask); | |
127 | ask->type = type; | |
128 | return 0; | |
129 | } | |
130 | ||
131 | int 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 |
172 | const 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 | |
179 | int 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 |
194 | uint64_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 |
201 | int 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 |
214 | uint64_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 |
221 | int 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 |
234 | uint64_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 |
241 | int 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 |
254 | uint64_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 |
268 | int 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 |
281 | uint64_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 | ||
288 | int 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 |
301 | uint64_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 | ||
308 | int 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 | ||
315 | int 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 | */ | |
333 | int 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 |
351 | int 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 |
368 | int 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 |
375 | int 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 | 386 | static 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 |
447 | int 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 | |
534 | dont_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 |
556 | int 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 |
597 | char *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 | */ |
614 | int 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 | */ |
631 | int 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 |
667 | int 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 | */ | |
699 | int 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 | */ | |
713 | int 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 | */ | |
723 | int 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 |
737 | int 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 |
751 | int 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 |
768 | int 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 |
787 | int 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 | ||
812 | static 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 |
832 | size_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 | ||
845 | int 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 |
887 | int 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 | ||
894 | int 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 |
907 | const 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! */ | |
915 | int 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 | 922 | static 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 |
961 | int 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 |
983 | int 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 |
1005 | int 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 |
1017 | int 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 | 1034 | static 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 | ||
1063 | int 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 |