char *buf, size_t bufsz)
{
char prompt[128] = { '\0' };
- const char *q = fdisk_ask_get_question(ask);
+ const char *q = fdisk_ask_get_query(ask);
const char *range = fdisk_ask_number_get_range(ask);
- uint64_t dfl = fdisk_ask_number_get_default(ask),
+ uint64_t dflt = fdisk_ask_number_get_default(ask),
low = fdisk_ask_number_get_low(ask),
- hig = fdisk_ask_number_get_high(ask);
+ high = fdisk_ask_number_get_high(ask);
assert(q);
- DBG(ASK, dbgprint("asking for number ['%s', <%jd,%jd>, default: %jd, range: %s]",
- q, low, hig, dfl, range));
-
- if (range && dfl)
- snprintf(prompt, sizeof(prompt), _("%s (%s, default %jd): "), q, range, dfl);
- else if (dfl)
- snprintf(prompt, sizeof(prompt), _("%s (%jd-%jd, default %jd): "), q, low, hig, dfl);
+ DBG(ASK, dbgprint("asking for number ['%s', <%jd,%jd>, default=%jd, range: %s]",
+ q, low, high, dflt, range));
+ if (range && dflt)
+ snprintf(prompt, sizeof(prompt), _("%s (%s, default %jd): "), q, range, dflt);
+ else if (dflt)
+ snprintf(prompt, sizeof(prompt), _("%s (%jd-%jd, default %jd): "), q, low, high, dflt);
else
- snprintf(prompt, sizeof(prompt), _("%s (%jd-%jd): "), q, low, hig);
+ snprintf(prompt, sizeof(prompt), _("%s (%jd-%jd): "), q, low, high);
do {
- uint64_t num;
int rc = get_user_reply(cxt, prompt, buf, bufsz);
+
if (rc)
return rc;
-
- if (!*buf && dfl)
- return fdisk_ask_number_set_result(ask, dfl);
+ if (!*buf && dflt)
+ return fdisk_ask_number_set_result(ask, dflt);
else if (isdigit_string(buf)) {
char *end;
+ uint64_t num;
+
errno = 0;
num = strtoumax(buf, &end, 10);
if (errno || buf == end || (end && *end))
continue;
- if (num >= low && num <= hig)
+ if (num >= low && num <= high)
return fdisk_ask_number_set_result(ask, num);
printf(_("Value out of range.\n"));
}
return -1;
}
+static int ask_offset(struct fdisk_context *cxt,
+ struct fdisk_ask *ask,
+ char *buf, size_t bufsz)
+{
+ char prompt[128] = { '\0' };
+ const char *q = fdisk_ask_get_query(ask);
+ const char *range = fdisk_ask_number_get_range(ask);
+
+ uint64_t dflt = fdisk_ask_number_get_default(ask),
+ low = fdisk_ask_number_get_low(ask),
+ high = fdisk_ask_number_get_high(ask),
+ base = fdisk_ask_number_get_base(ask);
+
+ assert(q);
+
+ DBG(ASK, dbgprint("asking for offset ['%s', <%jd,%jd>, base=%jd, default=%jd, range: %s]",
+ q, low, high, base, dflt, range));
+
+ if (range && dflt)
+ snprintf(prompt, sizeof(prompt), _("%s (%s, default %jd): "), q, range, dflt);
+ else if (dflt)
+ snprintf(prompt, sizeof(prompt), _("%s (%jd-%jd, default %jd): "), q, low, high, dflt);
+ else
+ snprintf(prompt, sizeof(prompt), _("%s (%jd-%jd): "), q, low, high);
+
+ do {
+ uint64_t num = 0;
+ char sig = 0, *p;
+ int pwr = 0;
+
+ int rc = get_user_reply(cxt, prompt, buf, bufsz);
+ if (rc)
+ return rc;
+ if (!*buf && dflt)
+ return fdisk_ask_number_set_result(ask, dflt);
+
+ p = buf;
+ if (*p == '+' || *p == '-') {
+ sig = *buf;
+ p++;
+ }
+
+ rc = parse_size(p, &num, &pwr);
+ if (rc)
+ continue;
+ DBG(ASK, dbgprint("parsed size: %jd", num));
+ if (sig && pwr) {
+ /* +{size}{K,M,...} specified, the "num" is in bytes */
+ uint64_t unit = fdisk_ask_number_get_unit(ask);
+ num += unit/2; /* round */
+ num /= unit;
+ }
+ if (sig == '+')
+ num += base;
+ else if (sig == '-')
+ num = base - num;
+
+ DBG(ASK, dbgprint("final offset: %jd [sig: %c, power: %d, %s]",
+ num, sig, pwr,
+ sig ? "relative" : "absolute"));
+ if (num >= low && num <= high) {
+ if (sig)
+ fdisk_ask_number_set_relative(ask, 1);
+ return fdisk_ask_number_set_result(ask, num);
+ }
+ printf(_("Value out of range.\n"));
+ } while (1);
+
+ return -1;
+}
+
int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask,
void *data __attribute__((__unused__)))
{
switch(fdisk_ask_get_type(ask)) {
case FDISK_ASKTYPE_NUMBER:
return ask_number(cxt, ask, buf, sizeof(buf));
+ case FDISK_ASKTYPE_OFFSET:
+ return ask_offset(cxt, ask, buf, sizeof(buf));
default:
+ warnx(_("internal error: unssuported dialog type %d"), fdisk_ask_get_type(ask));
return -EINVAL;
}
return 0;
+#include "strutils.h"
+
#include "fdiskP.h"
+struct fdisk_ask *fdisk_new_ask(void)
+{
+ return calloc(1, sizeof(struct fdisk_ask));
+}
+
+void fdisk_reset_ask(struct fdisk_ask *ask)
+{
+ assert(ask);
+ free(ask->data.num.range);
+ free(ask->query);
+ memset(ask, 0, sizeof(*ask));
+}
+
+void fdisk_free_ask(struct fdisk_ask *ask)
+{
+ if (!ask)
+ return;
+ fdisk_reset_ask(ask);
+ free(ask);
+}
-const char *fdisk_ask_get_question(struct fdisk_ask *ask)
+const char *fdisk_ask_get_query(struct fdisk_ask *ask)
{
assert(ask);
return ask->query;
}
+int fdisk_ask_set_query(struct fdisk_ask *ask, const char *str)
+{
+ assert(ask);
+ return !strdup_to_struct_member(ask, query, str) ? -ENOMEM : 0;
+}
+
int fdisk_ask_get_type(struct fdisk_ask *ask)
{
assert(ask);
return ask->type;
}
+int fdisk_ask_set_type(struct fdisk_ask *ask, int type)
+{
+ assert(ask);
+ ask->type = type;
+ return 0;
+}
+
+int fdisk_do_ask(struct fdisk_context *cxt, struct fdisk_ask *ask)
+{
+ int rc;
+
+ assert(ask);
+ assert(cxt);
+
+ DBG(ASK, dbgprint("asking for '%s'", ask->query));
+
+ if (!cxt->ask_cb) {
+ DBG(ASK, dbgprint("no ask callback specified!"));
+ return -EINVAL;
+ }
+
+ rc = cxt->ask_cb(cxt, ask, cxt->ask_data);
+
+ DBG(ASK, dbgprint("do_ask done [rc=%d]", rc));
+ return rc;
+}
+
+
const char *fdisk_ask_number_get_range(struct fdisk_ask *ask)
{
assert(ask);
return ask->data.num.range;
}
+
+int fdisk_ask_number_set_range(struct fdisk_ask *ask, const char *range)
+{
+ assert(ask);
+ return !strdup_to_struct_member(ask, data.num.range, range) ? -ENOMEM : 0;
+}
+
uint64_t fdisk_ask_number_get_default(struct fdisk_ask *ask)
{
assert(ask);
return ask->data.num.dfl;
}
+int fdisk_ask_number_set_default(struct fdisk_ask *ask, uint64_t dflt)
+{
+ assert(ask);
+ ask->data.num.dfl = dflt;
+ return 0;
+}
+
uint64_t fdisk_ask_number_get_low(struct fdisk_ask *ask)
{
assert(ask);
return ask->data.num.low;
}
+int fdisk_ask_number_set_low(struct fdisk_ask *ask, uint64_t low)
+{
+ assert(ask);
+ ask->data.num.low = low;
+ return 0;
+}
+
uint64_t fdisk_ask_number_get_high(struct fdisk_ask *ask)
{
assert(ask);
return ask->data.num.hig;
}
+int fdisk_ask_number_set_high(struct fdisk_ask *ask, uint64_t high)
+{
+ assert(ask);
+ ask->data.num.hig = high;
+ return 0;
+}
+
+uint64_t fdisk_ask_number_get_result(struct fdisk_ask *ask)
+{
+ assert(ask);
+ return ask->data.num.result;
+}
+
int fdisk_ask_number_set_result(struct fdisk_ask *ask, uint64_t result)
{
assert(ask);
return 0;
}
+uint64_t fdisk_ask_number_get_base(struct fdisk_ask *ask)
+{
+ assert(ask);
+ return ask->data.num.base;
+}
+
+int fdisk_ask_number_set_base(struct fdisk_ask *ask, uint64_t base)
+{
+ assert(ask);
+ ask->data.num.base = base;
+ return 0;
+}
+
+/* if numbers are not in bytes, then specify number of bytes per the unit */
+uint64_t fdisk_ask_number_get_unit(struct fdisk_ask *ask)
+{
+ assert(ask);
+ return ask->data.num.unit;
+}
+
+int fdisk_ask_number_set_unit(struct fdisk_ask *ask, uint64_t unit)
+{
+ assert(ask);
+ ask->data.num.unit = unit;
+ return 0;
+}
+
+int fdisk_ask_number_is_relative(struct fdisk_ask *ask)
+{
+ assert(ask);
+ return ask->data.num.relative;
+}
+
+int fdisk_ask_number_set_relative(struct fdisk_ask *ask, int relative)
+{
+ assert(ask);
+ ask->data.num.relative = relative ? 1 : 0;
+ return 0;
+}
+
/*
* Generates string with list ranges (e.g. 1,2,5-8) for the 'cur'
*/
return ptr;
}
+/* returns: 1=0 on success, < 0 on error, 1 if no free partition */
int fdisk_ask_partnum(struct fdisk_context *cxt, size_t *partnum, int wantnew)
{
- int rc;
+ int rc = 0;
char range[BUFSIZ], *ptr = range;
size_t i, len = sizeof(range), begin = 0, run = 0;
- struct fdisk_ask ask = { .name = "partnum" };
- __typeof__(ask.data.num) *num = &ask.data.num;
+ struct fdisk_ask *ask = NULL;
+ __typeof__(ask->data.num) *num;
assert(cxt);
assert(cxt->label);
assert(partnum);
- if (!cxt->ask_cb) {
- DBG(ASK, dbgprint("no ask callback specified!"));
- return -EINVAL; /* ask callback undefined */
- }
-
DBG(ASK, dbgprint("%s: asking for %s partition number (max: %zd)",
- cxt->label->name,
- wantnew ? "new" : "used",
+ cxt->label->name, wantnew ? "new" : "used",
cxt->label->nparts_max));
+ ask = fdisk_new_ask();
+ if (!ask)
+ return -ENOMEM;
+
+ num = &ask->data.num;
+
for (i = 0; i < cxt->label->nparts_max; i++) {
int status = 0;
rc = fdisk_partition_get_status(cxt, i, &status);
if (rc)
- return rc;
-
+ break;
if (wantnew && !(status & FDISK_PARTSTAT_USED)) {
ptr = mk_string_list(ptr, &len, &begin, &run, i);
- if (!ptr)
- return -EINVAL;
+ if (!ptr) {
+ rc = -EINVAL;
+ break;
+ }
if (!num->low)
num->dfl = num->low = i + 1;
num->hig = i + 1;
}
}
- if (wantnew && num->low == 0 && num->hig == 0) {
+ if (!rc) {
+ mk_string_list(ptr, &len, &begin, &run, -1); /* terminate the list */
+ rc = fdisk_ask_number_set_range(ask, range);
+ }
+ if (!rc && wantnew && num->low == 0 && num->hig == 0) {
DBG(ASK, dbgprint("no free partition"));
- return 1;
+ rc = 1;
+ }
+ if (!rc)
+ rc = fdisk_ask_set_query(ask, _("Partition number"));
+ if (!rc)
+ rc = fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
+ if (!rc)
+ rc = fdisk_do_ask(cxt, ask);
+ if (!rc) {
+ *partnum = fdisk_ask_number_get_result(ask);
+ if (*partnum)
+ *partnum -= 1;
}
- mk_string_list(ptr, &len, &begin, &run, -1); /* terminate the list */
- num->range = range;
-
- ask.query = _("Partition number");
- ask.type = FDISK_ASKTYPE_NUMBER;
-
- rc = cxt->ask_cb(cxt, &ask, cxt->ask_data);
- *partnum = num->result ? num->result - 1 : 0;
- DBG(ASK, dbgprint("result: %zd [rc=%d]\n", num->result, rc));
+ fdisk_free_ask(ask);
+ DBG(ASK, dbgprint("result: %zd [rc=%d]\n", *partnum, rc));
return rc;
}
struct fdisk_label *fdisk_new_sgi_label(struct fdisk_context *cxt) { return NULL; }
struct fdisk_label *fdisk_new_sun_label(struct fdisk_context *cxt) { return NULL; }
-unsigned int read_int_with_suffix(struct fdisk_context *cxt,
- unsigned int low, unsigned int dflt, unsigned int high,
- unsigned int base, char *mesg, int *is_suffix_used)
-{
- return 0;
-}
-
-unsigned int read_int(struct fdisk_context *cxt,
- unsigned int low, unsigned int dflt,
- unsigned int high, unsigned int base, char *mesg)
-{
- return 0;
-}
-
int test_ranges(struct fdisk_test *ts, int argc, char *argv[])
{
/* 1 - 3, 6, 8, 9, 11 13 */
* we will have get/set() function for everything.
*/
struct fdisk_ask {
- const char *name;
int type; /* FDISK_ASKTYPE_* */
-
char *query;
- char *hint;
union {
+ /* FDISK_ASKTYPE_{NUMBER,OFFSET} */
struct ask_number {
uint64_t hig; /* high limit */
uint64_t low; /* low limit */
uint64_t dfl; /* default */
uint64_t result;
- const char *range; /* by library generated list */
+ uint64_t base; /* for relative results */
+ uint64_t unit; /* unit for offsets */
+ char *range; /* by library generated list */
+ unsigned int relative:1;
} num;
} data;
};
-enum {
- FDISK_ASKTYPE_NONE,
- FDISK_ASKTYPE_NUMBER
-};
-
struct fdisk_context {
int dev_fd; /* device descriptor */
char *dev_path; /* device path */
#include "strutils.h"
#include "all-io.h"
-/* temporary -- exported from fdisk/sfdisk.c
- * TODO: use fdisk_dialog API
- */
-extern unsigned int read_int(struct fdisk_context *cxt,
- unsigned int low, unsigned int dflt,
- unsigned int high, unsigned int base, char *mesg);
-
-extern unsigned int read_int_with_suffix(struct fdisk_context *cxt,
- unsigned int low, unsigned int dflt, unsigned int high,
- unsigned int base, char *mesg, int *is_suffix_used);
-
#define GPT_HEADER_SIGNATURE 0x5452415020494645LL /* EFI PART */
#define GPT_HEADER_REVISION_V1_02 0x00010200
#define GPT_HEADER_REVISION_V1_00 0x00010000
struct fdisk_gpt_label *gpt;
struct gpt_header *pheader;
struct gpt_entry *ents;
+ struct fdisk_ask *ask = NULL;
+ int rc;
assert(cxt);
assert(cxt->label);
/* get user input for first and last sectors of the new partition */
for (;;) {
- int is_suffix_used = 0;
-
- /* first sector */
- user_f = read_int(cxt, disk_f, /* minimal */
- dflt_f, /* default */
- disk_l, /* maximal */
- 0, _("First sector"));
-
- if (user_f < disk_f || user_f > disk_l)
- continue; /* bug in read_int() dialog? */
-
+ if (!ask)
+ ask = fdisk_new_ask();
+ else
+ fdisk_reset_ask(ask);
+
+ /* First sector */
+ fdisk_ask_set_query(ask, _("First sector"));
+ fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
+ fdisk_ask_number_set_low(ask, disk_f); /* minimal */
+ fdisk_ask_number_set_default(ask, dflt_f); /* default */
+ fdisk_ask_number_set_high(ask, disk_l); /* maximal */
+
+ rc = fdisk_do_ask(cxt, ask);
+ if (rc)
+ goto done;
+
+ user_f = fdisk_ask_number_get_result(ask);
if (user_f != find_first_available(pheader, ents, user_f)) {
printf(_("Sector %ju already used\n"), user_f);
continue;
}
+ fdisk_reset_ask(ask);
+
/* Last sector */
dflt_l = find_last_free(pheader, ents, user_f);
- user_l = read_int_with_suffix(cxt,
- user_f, /* minimal */
- dflt_l, /* default */
- dflt_l, /* maximal */
- user_f, /* base for relative input */
- _("Last sector, +sectors or +size{K,M,G}"),
- &is_suffix_used);
-
- if (is_suffix_used)
- user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1;
+ fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}"));
+ fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);
+ fdisk_ask_number_set_low(ask, user_f); /* minimal */
+ fdisk_ask_number_set_default(ask, dflt_l); /* default */
+ fdisk_ask_number_set_high(ask, dflt_l); /* maximal */
+ fdisk_ask_number_set_base(ask, user_f); /* base for relative input */
+ fdisk_ask_number_set_unit(ask, cxt->sector_size);
+
+ rc = fdisk_do_ask(cxt, ask);
+ if (rc)
+ goto done;
+
+ user_l = fdisk_ask_number_get_result(ask);
+ if (fdisk_ask_number_is_relative(ask))
+ user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1;
if (user_l > user_f && user_l <= disk_l)
break;
}
fdisk_label_set_changed(cxt->label, 1);
}
- return 0;
+ rc = 0;
+done:
+ fdisk_free_ask(ask);
+ return rc;
}
/*
FDISK_PARTSTAT_USED /* partition used */
};
+enum {
+ FDISK_ASKTYPE_NONE = 0,
+ FDISK_ASKTYPE_NUMBER,
+ FDISK_ASKTYPE_OFFSET,
+};
+
/* init.c */
extern void fdisk_init_debug(int mask);
extern int fdisk_dos_is_compatible(struct fdisk_label *lb);
/* ask.c */
-extern const char *fdisk_ask_get_question(struct fdisk_ask *ask);
+extern struct fdisk_ask *fdisk_new_ask(void);
+extern void fdisk_reset_ask(struct fdisk_ask *ask);
+extern void fdisk_free_ask(struct fdisk_ask *ask);
+extern const char *fdisk_ask_get_query(struct fdisk_ask *ask);
+extern int fdisk_ask_set_query(struct fdisk_ask *ask, const char *str);
extern int fdisk_ask_get_type(struct fdisk_ask *ask);
+extern int fdisk_ask_set_type(struct fdisk_ask *ask, int type);
+extern int fdisk_do_ask(struct fdisk_context *cxt, struct fdisk_ask *ask);
+
extern const char *fdisk_ask_number_get_range(struct fdisk_ask *ask);
+extern int fdisk_ask_number_set_range(struct fdisk_ask *ask, const char *range);
extern uint64_t fdisk_ask_number_get_default(struct fdisk_ask *ask);
+extern int fdisk_ask_number_set_default(struct fdisk_ask *ask, uint64_t dflt);
extern uint64_t fdisk_ask_number_get_low(struct fdisk_ask *ask);
+extern int fdisk_ask_number_set_low(struct fdisk_ask *ask, uint64_t low);
extern uint64_t fdisk_ask_number_get_high(struct fdisk_ask *ask);
+extern int fdisk_ask_number_set_high(struct fdisk_ask *ask, uint64_t high);
+extern uint64_t fdisk_ask_number_get_base(struct fdisk_ask *ask);
+extern int fdisk_ask_number_set_base(struct fdisk_ask *ask, uint64_t base);
+extern uint64_t fdisk_ask_number_get_unit(struct fdisk_ask *ask);
+extern int fdisk_ask_number_set_unit(struct fdisk_ask *ask, uint64_t unit);
+extern uint64_t fdisk_ask_number_get_result(struct fdisk_ask *ask);
extern int fdisk_ask_number_set_result(struct fdisk_ask *ask, uint64_t result);
+extern int fdisk_ask_number_set_relative(struct fdisk_ask *ask, int relative);
+extern int fdisk_ask_number_is_relative(struct fdisk_ask *ask);
#ifdef __cplusplus
}