summaryrefslogtreecommitdiffstats
path: root/fdisks/fdisk.c
diff options
context:
space:
mode:
authorKarel Zak2014-03-10 13:55:43 +0100
committerKarel Zak2014-03-11 11:35:15 +0100
commitd6b3ba417b043b76d651fa7e05f6209f12f5135b (patch)
treee2fcade9a6de16cb245d4e4d06d7ab29a405c46d /fdisks/fdisk.c
parentsfdisk: merge partname.c (diff)
downloadkernel-qcow2-util-linux-d6b3ba417b043b76d651fa7e05f6209f12f5135b.tar.gz
kernel-qcow2-util-linux-d6b3ba417b043b76d651fa7e05f6209f12f5135b.tar.xz
kernel-qcow2-util-linux-d6b3ba417b043b76d651fa7e05f6209f12f5135b.zip
fdisk: merge fdisk-ask.c to fdisk.c
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'fdisks/fdisk.c')
-rw-r--r--fdisks/fdisk.c361
1 files changed, 361 insertions, 0 deletions
diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c
index d2494ef9f..e003baf64 100644
--- a/fdisks/fdisk.c
+++ b/fdisks/fdisk.c
@@ -71,6 +71,367 @@ static void __attribute__ ((__noreturn__)) usage(FILE *out)
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
}
+
+
+int get_user_reply(struct fdisk_context *cxt, const char *prompt,
+ char *buf, size_t bufsz)
+{
+ char *p;
+ size_t sz;
+
+ do {
+ fputs(prompt, stdout);
+ fflush(stdout);
+
+ if (!fgets(buf, bufsz, stdin)) {
+ if (fdisk_label_is_changed(cxt->label)) {
+ fprintf(stderr, _("\nDo you really want to quit? "));
+
+ if (fgets(buf, bufsz, stdin) && !rpmatch(buf))
+ continue;
+ }
+ fdisk_free_context(cxt);
+ exit(EXIT_FAILURE);
+ } else
+ break;
+ } while (1);
+
+ for (p = buf; *p && !isgraph(*p); p++); /* get first non-blank */
+
+ if (p > buf)
+ memmove(buf, p, p - buf); /* remove blank space */
+ sz = strlen(buf);
+ if (sz && *(buf + sz - 1) == '\n')
+ *(buf + sz - 1) = '\0';
+
+ DBG(ASK, dbgprint("user's reply: >>>%s<<<", buf));
+ return 0;
+}
+
+static int ask_menu(struct fdisk_context *cxt, struct fdisk_ask *ask,
+ char *buf, size_t bufsz)
+
+{
+ const char *q = fdisk_ask_get_query(ask);
+ int dft = fdisk_ask_menu_get_default(ask);
+
+ if (q) {
+ fputs(q, stdout); /* print header */
+ fputc('\n', stdout);
+ }
+
+ do {
+ char prompt[128];
+ int key, c;
+ const char *name, *desc;
+ size_t i = 0;
+
+ /* print menu items */
+ while (fdisk_ask_menu_get_item(ask, i++, &key, &name, &desc) == 0)
+ fprintf(stdout, " %c %s (%s)\n", key, name, desc);
+
+ /* ask for key */
+ snprintf(prompt, sizeof(prompt), _("Select (default %c): "), dft);
+ get_user_reply(cxt, prompt, buf, bufsz);
+ if (!*buf) {
+ fdisk_info(cxt, _("Using default response %c."), dft);
+ c = dft;
+ } else
+ c = tolower(buf[0]);
+
+ /* check result */
+ i = 0;
+ while (fdisk_ask_menu_get_item(ask, i++, &key, NULL, NULL) == 0) {
+ if (c == key) {
+ fdisk_ask_menu_set_result(ask, c);
+ return 0; /* success */
+ }
+ }
+ fdisk_warnx(cxt, _("Value out of range."));
+ } while (1);
+
+ return -EINVAL;
+}
+
+
+#define tochar(num) ((int) ('a' + num - 1))
+static int ask_number(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);
+ int inchar = fdisk_ask_number_inchars(ask);
+
+ assert(q);
+
+ DBG(ASK, dbgprint("asking for number "
+ "['%s', <%ju,%ju>, default=%ju, range: %s]",
+ q, low, high, dflt, range));
+
+ if (range && dflt >= low && dflt <= high) {
+ if (inchar)
+ snprintf(prompt, sizeof(prompt), _("%s (%s, default %c): "),
+ q, range, tochar(dflt));
+ else
+ snprintf(prompt, sizeof(prompt), _("%s (%s, default %ju): "),
+ q, range, dflt);
+
+ } else if (dflt >= low && dflt <= high) {
+ if (inchar)
+ snprintf(prompt, sizeof(prompt), _("%s (%c-%c, default %c): "),
+ q, tochar(low), tochar(high), tochar(dflt));
+ else
+ snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju, default %ju): "),
+ q, low, high, dflt);
+ } else if (inchar)
+ snprintf(prompt, sizeof(prompt), _("%s (%c-%c): "),
+ q, tochar(low), tochar(high));
+ else
+ snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju): "),
+ q, low, high);
+
+ do {
+ int rc = get_user_reply(cxt, prompt, buf, bufsz);
+ uint64_t num;
+
+ if (rc)
+ return rc;
+ if (!*buf && dflt >= low && dflt <= high)
+ return fdisk_ask_number_set_result(ask, dflt);
+
+ if (isdigit_string(buf)) {
+ char *end;
+
+ errno = 0;
+ num = strtoumax(buf, &end, 10);
+ if (errno || buf == end || (end && *end))
+ continue;
+ } else if (inchar && isalpha(*buf)) {
+ num = tolower(*buf) - 'a' + 1;
+ } else
+ rc = -EINVAL;
+
+ if (rc == 0 && num >= low && num <= high)
+ return fdisk_ask_number_set_result(ask, num);
+
+ fdisk_warnx(cxt, _("Value out of range."));
+ } while (1);
+
+ 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', <%ju,%ju>, base=%ju, default=%ju, range: %s]",
+ q, low, high, base, dflt, range));
+
+ if (range && dflt >= low && dflt <= high)
+ snprintf(prompt, sizeof(prompt), _("%s (%s, default %ju): "), q, range, dflt);
+ else if (dflt >= low && dflt <= high)
+ snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju, default %ju): "), q, low, high, dflt);
+ else
+ snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju): "), 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 >= low && dflt <= high)
+ 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: %ju", 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: %ju [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);
+ }
+ fdisk_warnx(cxt, _("Value out of range."));
+ } while (1);
+
+ return -1;
+}
+
+static unsigned int info_count;
+
+static void fputs_info(struct fdisk_ask *ask, FILE *out, char *buf, size_t bufsz)
+{
+ const char *msg;
+ unsigned int flags;
+
+ assert(ask);
+
+ msg = fdisk_ask_print_get_mesg(ask);
+ flags = fdisk_ask_get_flags(ask);
+
+ if (!msg)
+ return;
+ if (info_count == 1)
+ fputc('\n', out);
+ if (flags == 0 || !colors_wanted())
+ goto simple;
+
+ if (flags & FDISK_INFO_COLON) {
+ size_t sz;
+ char *sep = _(": ");
+ char *p = strstr(msg, sep);
+
+ if (!p)
+ goto simple;
+
+ sz = strlen(sep);
+ strncpy(buf, msg, bufsz);
+ buf[p - msg + sz] = '\0';
+
+ color_enable(UL_COLOR_BROWN);
+ fputs(buf, out);
+ color_disable();
+ fputs(p + sz, out);
+
+ } else if (flags & FDISK_INFO_SUCCESS) {
+ color_enable(UL_COLOR_BOLD);
+ fputs(msg, out);
+ color_disable();
+ } else {
+simple:
+ fputs(msg, out);
+ }
+ fputc('\n', out);
+}
+
+int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask,
+ void *data __attribute__((__unused__)))
+{
+ int rc = 0;
+ char buf[BUFSIZ];
+
+ assert(cxt);
+ assert(ask);
+
+ if (fdisk_ask_get_type(ask) != FDISK_ASKTYPE_INFO)
+ info_count = 0;
+
+ switch(fdisk_ask_get_type(ask)) {
+ case FDISK_ASKTYPE_MENU:
+ return ask_menu(cxt, ask, buf, sizeof(buf));
+ case FDISK_ASKTYPE_NUMBER:
+ return ask_number(cxt, ask, buf, sizeof(buf));
+ case FDISK_ASKTYPE_OFFSET:
+ return ask_offset(cxt, ask, buf, sizeof(buf));
+ case FDISK_ASKTYPE_INFO:
+ info_count++;
+ fputs_info(ask, stdout, buf, sizeof(buf));
+ break;
+ case FDISK_ASKTYPE_WARNX:
+ color_fenable(UL_COLOR_RED, stderr);
+ fputs(fdisk_ask_print_get_mesg(ask), stderr);
+ color_fdisable(stderr);
+ fputc('\n', stderr);
+ break;
+ case FDISK_ASKTYPE_WARN:
+ color_fenable(UL_COLOR_RED, stderr);
+ fputs(fdisk_ask_print_get_mesg(ask), stderr);
+ errno = fdisk_ask_print_get_errno(ask);
+ fprintf(stderr, ": %m\n");
+ color_fdisable(stderr);
+ break;
+ case FDISK_ASKTYPE_YESNO:
+ fputc('\n', stdout);
+ fputs(fdisk_ask_get_query(ask), stdout);
+ rc = get_user_reply(cxt, _(" [Y]es/[N]o: "), buf, sizeof(buf));
+ if (rc == 0)
+ fdisk_ask_yesno_set_result(ask, rpmatch(buf));
+ DBG(ASK, dbgprint("yes-no ask: reply '%s' [rc=%d]", buf, rc));
+ break;
+ case FDISK_ASKTYPE_STRING:
+ {
+ char prmt[BUFSIZ];
+ snprintf(prmt, sizeof(prmt), "%s: ", fdisk_ask_get_query(ask));
+ fputc('\n', stdout);
+ rc = get_user_reply(cxt, prmt, buf, sizeof(buf));
+ if (rc == 0)
+ fdisk_ask_string_set_result(ask, xstrdup(buf));
+ DBG(ASK, dbgprint("string ask: reply '%s' [rc=%d]", buf, rc));
+ break;
+ }
+ default:
+ warnx(_("internal error: unsupported dialog type %d"), fdisk_ask_get_type(ask));
+ return -EINVAL;
+ }
+ return rc;
+}
+
+struct fdisk_parttype *ask_partition_type(struct fdisk_context *cxt)
+{
+ const char *q;
+
+ if (!cxt || !cxt->label || !cxt->label->nparttypes)
+ return NULL;
+
+ q = fdisk_is_parttype_string(cxt) ?
+ _("Partition type (type L to list all types): ") :
+ _("Hex code (type L to list all codes): ");
+ do {
+ char buf[256];
+ int rc = get_user_reply(cxt, q, buf, sizeof(buf));
+
+ if (rc)
+ break;
+
+ if (buf[1] == '\0' && toupper(*buf) == 'L')
+ list_partition_types(cxt);
+ else if (*buf)
+ return fdisk_parse_parttype(cxt, buf);
+ } while (1);
+
+ return NULL;
+}
+
void list_partition_types(struct fdisk_context *cxt)
{
struct fdisk_parttype *types;