]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: extend "ask" API, add support for offsets
authorKarel Zak <kzak@redhat.com>
Tue, 29 Jan 2013 14:28:30 +0000 (15:28 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 11 Mar 2013 12:00:55 +0000 (13:00 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
fdisks/fdisk-ask.c
libfdisk/src/ask.c
libfdisk/src/fdiskP.h
libfdisk/src/gpt.c
libfdisk/src/libfdisk.h

index ebfb404bb218c2e6b0ebbd9d04651d101fa3f036..c27deae76d8666978eb5f27c5072dce764eaa937 100644 (file)
@@ -51,40 +51,40 @@ static int ask_number(struct fdisk_context *cxt,
                      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"));
                }
@@ -93,6 +93,77 @@ static int ask_number(struct fdisk_context *cxt,
        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__)))
 {
@@ -104,7 +175,10 @@ int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask,
        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;
index a5ee2f559155b55a70c8d3f7ce3499e3686e1305..fc0214d26ee42a5b2c1b3dcfdac23bdab3272158 100644 (file)
 
+#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);
@@ -44,6 +134,46 @@ int fdisk_ask_number_set_result(struct fdisk_ask *ask, uint64_t result)
        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'
  */
@@ -97,39 +227,41 @@ static char *mk_string_list(char *ptr, size_t *len, size_t *begin,
        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;
@@ -141,20 +273,28 @@ int fdisk_ask_partnum(struct fdisk_context *cxt, size_t *partnum, int wantnew)
                }
        }
 
-       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;
 }
 
@@ -167,20 +307,6 @@ struct fdisk_label *fdisk_new_mac_label(struct fdisk_context *cxt) { return NULL
 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 */
index 58c8393cc6af308367ad5b75523f76ca4c6ba875..b1de7036c2cc4a0d171af8668758fcc482c3e894 100644 (file)
@@ -212,28 +212,24 @@ extern struct fdisk_label *fdisk_new_sun_label(struct fdisk_context *cxt);
  * 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 */
index 520416c45c34d84e2bd64237f19f6490e75a59d6..278cb1853db6bfe3109ea7d9646599c2d5554788 100644 (file)
 #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
@@ -1564,6 +1553,8 @@ static int gpt_add_partition(
        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);
@@ -1608,35 +1599,48 @@ static int gpt_add_partition(
 
        /* 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;
        }
@@ -1650,7 +1654,10 @@ static int gpt_add_partition(
                fdisk_label_set_changed(cxt->label, 1);
        }
 
-       return 0;
+       rc = 0;
+done:
+       fdisk_free_ask(ask);
+       return rc;
 }
 
 /*
index a19849dc4d1ac577ae860d948d0abba850af1170..8cf5d65e1cad84f52eb42db180f5bc24cfcbb1d6 100644 (file)
@@ -49,6 +49,12 @@ enum {
        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);
 
@@ -111,13 +117,31 @@ extern int fdisk_dos_enable_compatible(struct fdisk_label *lb, int enable);
 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
 }