]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: add "ask" interface
authorKarel Zak <kzak@redhat.com>
Mon, 28 Jan 2013 15:14:21 +0000 (16:14 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 11 Mar 2013 12:00:54 +0000 (13:00 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
libfdisk/src/Makemodule.am
libfdisk/src/ask.c [new file with mode: 0644]
libfdisk/src/context.c
libfdisk/src/fdiskP.h
libfdisk/src/label.c
libfdisk/src/libfdisk.h

index eb40a3f1af4cfdceb358186bbfa9dc5b864a82d7..fbfb1b4f21d93fddb10468e4a546f05b26b3a066 100644 (file)
@@ -11,6 +11,7 @@ libfdisk_la_SOURCES = \
        \
        libfdisk/src/init.c \
        libfdisk/src/test.c \
+       libfdisk/src/ask.c \
        libfdisk/src/alignment.c \
        libfdisk/src/label.c \
        libfdisk/src/utils.c \
@@ -39,6 +40,10 @@ endif
 
 libfdisk_la_DEPENDENCIES = $(libfdisk_la_LIBADD)
 
+
+check_PROGRAMS += \
+       test_fdisk_ask
+
 libfdisk_tests_cflags  = -DTEST_PROGRAM $(libfdisk_la_CFLAGS)
 libfdisk_tests_ldflags = -static
 libfdisk_tests_ldadd   = libfdisk.la
@@ -50,3 +55,8 @@ endif
 if BUILD_LIBUUID
 libfdisk_tests_ldflags += libuuid.la
 endif
+
+test_fdisk_ask_SOURCES = libfdisk/src/ask.c
+test_fdisk_ask_CFLAGS = $(libfdisk_tests_cflags)
+test_fdisk_ask_LDFLAGS = $(libfdisk_tests_ldflags)
+test_fdisk_ask_LDADD = $(libfdisk_tests_ldadd)
diff --git a/libfdisk/src/ask.c b/libfdisk/src/ask.c
new file mode 100644 (file)
index 0000000..a5ee2f5
--- /dev/null
@@ -0,0 +1,223 @@
+
+#include "fdiskP.h"
+
+
+const char *fdisk_ask_get_question(struct fdisk_ask *ask)
+{
+       assert(ask);
+       return ask->query;
+}
+
+int fdisk_ask_get_type(struct fdisk_ask *ask)
+{
+       assert(ask);
+       return ask->type;
+}
+
+const char *fdisk_ask_number_get_range(struct fdisk_ask *ask)
+{
+       assert(ask);
+       return ask->data.num.range;
+}
+uint64_t fdisk_ask_number_get_default(struct fdisk_ask *ask)
+{
+       assert(ask);
+       return ask->data.num.dfl;
+}
+
+uint64_t fdisk_ask_number_get_low(struct fdisk_ask *ask)
+{
+       assert(ask);
+       return ask->data.num.low;
+}
+
+uint64_t fdisk_ask_number_get_high(struct fdisk_ask *ask)
+{
+       assert(ask);
+       return ask->data.num.hig;
+}
+
+int fdisk_ask_number_set_result(struct fdisk_ask *ask, uint64_t result)
+{
+       assert(ask);
+       ask->data.num.result = result;
+       return 0;
+}
+
+/*
+ * Generates string with list ranges (e.g. 1,2,5-8) for the 'cur'
+ */
+static char *mk_string_list(char *ptr, size_t *len, size_t *begin,
+                           size_t *run, ssize_t cur)
+{
+       int rlen;
+
+       if (cur != -1) {
+               if (!*begin) {                  /* begin of the list */
+                       *begin = cur + 1;
+                       return ptr;
+               }
+
+               if (*begin + *run == cur) {     /* no gap, continue */
+                       (*run)++;
+                       return ptr;
+               }
+       } else if (!*begin) {
+               *ptr = '\0';
+               return ptr;             /* end of empty list */
+       }
+
+                                       /* add to the list */
+       if (!*run)
+               rlen = snprintf(ptr, *len, "%zd,", *begin);
+       else if (*run == 1)
+               rlen = snprintf(ptr, *len, "%zd,%zd,", *begin, *begin + 1);
+       else
+               rlen = snprintf(ptr, *len, "%zd-%zd,", *begin, *begin + *run);
+
+       if (rlen < 0 || (size_t) rlen + 1 > *len)
+               return NULL;
+
+       ptr += rlen;
+
+       if (rlen > 0 && *len > (size_t) rlen)
+               *len -= rlen;
+       else
+               *len = 0;
+
+       if (cur == -1 && *begin) {
+               /* end of the list */
+               *(ptr - 1) = '\0';      /* remove tailing ',' from the list */
+               return ptr;
+       }
+
+       *begin = cur + 1;
+       *run = 0;
+
+       return ptr;
+}
+
+int fdisk_ask_partnum(struct fdisk_context *cxt, size_t *partnum, int wantnew)
+{
+       int rc;
+       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;
+
+       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->nparts_max));
+
+       for (i = 0; i < cxt->label->nparts_max; i++) {
+               int status = 0;
+
+               rc = fdisk_partition_get_status(cxt, i, &status);
+               if (rc)
+                       return rc;
+
+               if (wantnew && !(status & FDISK_PARTSTAT_USED)) {
+                       ptr = mk_string_list(ptr, &len, &begin, &run, i);
+                       if (!ptr)
+                               return -EINVAL;
+                       if (!num->low)
+                               num->dfl = num->low = i + 1;
+                       num->hig = i + 1;
+               } else if (!wantnew && (status & FDISK_PARTSTAT_USED)) {
+                       ptr = mk_string_list(ptr, &len, &begin, &run, i);
+                       if (!num->low)
+                               num->low = i + 1;
+                       num->dfl = num->hig = i + 1;
+               }
+       }
+
+       if (wantnew && num->low == 0 && num->hig == 0) {
+               DBG(ASK, dbgprint("no free partition"));
+               return 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));
+       return rc;
+}
+
+
+#ifdef TEST_PROGRAM
+struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt) { return NULL; }
+struct fdisk_label *fdisk_new_aix_label(struct fdisk_context *cxt) { return NULL; }
+struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt) { return NULL; }
+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 */
+       size_t nums[] = { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1 };
+       size_t numx[] = { 0, 0, 0 };
+       char range[BUFSIZ], *ptr = range;
+       size_t i, len = sizeof(range), begin = 0, run = 0;
+
+       for (i = 0; i < ARRAY_SIZE(nums); i++) {
+               if (!nums[i])
+                       continue;
+               ptr = mk_string_list(ptr, &len, &begin, &run, i);
+       }
+       mk_string_list(ptr, &len, &begin, &run, -1);
+       printf("list: '%s'\n", range);
+
+       ptr = range;
+       len = sizeof(range), begin = 0, run = 0;
+       for (i = 0; i < ARRAY_SIZE(numx); i++) {
+               if (!numx[i])
+                       continue;
+               ptr = mk_string_list(ptr, &len, &begin, &run, i);
+       }
+       mk_string_list(ptr, &len, &begin, &run, -1);
+       printf("empty list: '%s'\n", range);
+
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       struct fdisk_test tss[] = {
+       { "--ranges",  test_ranges,    "generates ranges" },
+       { NULL }
+       };
+
+       return fdisk_run_test(tss, argc, argv);
+}
+
+#endif
index 908889b4f120e4bd442f4b84c617de7cc63d71d1..4a2faf97d616c860212cc05734caa1ad708cb1a9 100644 (file)
@@ -68,8 +68,7 @@ int fdisk_context_switch_label(struct fdisk_context *cxt, const char *name)
 
 static void reset_context(struct fdisk_context *cxt)
 {
-       size_t nlbs, i;
-       struct fdisk_label *lbs[ ARRAY_SIZE(cxt->labels) ];
+       size_t i;
 
        DBG(CONTEXT, dbgprint("\n-----\nresetting context %p", cxt));
 
@@ -77,25 +76,30 @@ static void reset_context(struct fdisk_context *cxt)
        for (i = 0; i < cxt->nlabels; i++)
                fdisk_deinit_label(cxt->labels[i]);
 
-       /* remember permanent setting */
-       memcpy(lbs, cxt->labels, sizeof(lbs));
-       nlbs = cxt->nlabels;
-
        /* free device specific stuff */
        if (cxt->dev_fd > -1)
                close(cxt->dev_fd);
        free(cxt->dev_path);
        free(cxt->firstsector);
 
-       /* the reset */
-       memset(cxt, 0, sizeof(*cxt));
-
        /* initialize */
        cxt->dev_fd = -1;
-
-       /* set permanent setting */
-       memcpy(cxt->labels, lbs, sizeof(lbs));
-       cxt->nlabels = nlbs;
+       cxt->dev_path = NULL;
+       cxt->firstsector = NULL;
+
+       cxt->io_size = 0;
+       cxt->optimal_io_size = 0;
+       cxt->min_io_size = 0;
+       cxt->phy_sector_size = 0;
+       cxt->sector_size = 0;
+       cxt->alignment_offset = 0;
+       cxt->grain = 0;
+       cxt->first_lba = 0;
+       cxt->total_sectors = 0;
+
+       memset(&cxt->geom, 0, sizeof(struct fdisk_geometry));
+
+       cxt->label = NULL;
 }
 
 /**
@@ -178,3 +182,22 @@ void fdisk_free_context(struct fdisk_context *cxt)
 
        free(cxt);
 }
+
+/**
+ * fdisk_context_set_ask:
+ * @cxt: context
+ * @ask_cb: callback
+ * @data: callback data
+ *
+ * Returns: 0 on sucess, < 0 on error.
+ */
+int fdisk_context_set_ask(struct fdisk_context *cxt,
+               int (*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *),
+               void *data)
+{
+       assert(cxt);
+
+       cxt->ask_cb = ask_cb;
+       cxt->ask_data = data;
+       return 0;
+}
index 3a40bb449a59420f28eaa648497417e85afb6734..58c8393cc6af308367ad5b75523f76ca4c6ba875 100644 (file)
@@ -47,6 +47,7 @@
 #define FDISK_DEBUG_TOPOLOGY    (1 << 3)
 #define FDISK_DEBUG_GEOMETRY    (1 << 4)
 #define FDISK_DEBUG_LABEL       (1 << 5)
+#define FDISK_DEBUG_ASK         (1 << 6)
 #define FDISK_DEBUG_ALL                0xFFFF
 
 # define ON_DBG(m, x)  do { \
@@ -206,6 +207,33 @@ extern struct fdisk_label *fdisk_new_mac_label(struct fdisk_context *cxt);
 extern struct fdisk_label *fdisk_new_sgi_label(struct fdisk_context *cxt);
 extern struct fdisk_label *fdisk_new_sun_label(struct fdisk_context *cxt);
 
+
+/* fdisk dialog -- note that nothing from this stuff will be directly exported,
+ * we will have get/set() function for everything.
+ */
+struct fdisk_ask {
+       const char      *name;
+       int             type;           /* FDISK_ASKTYPE_* */
+
+       char            *query;
+       char            *hint;
+
+       union {
+               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 */
+               } num;
+       } data;
+};
+
+enum {
+       FDISK_ASKTYPE_NONE,
+       FDISK_ASKTYPE_NUMBER
+};
+
 struct fdisk_context {
        int dev_fd;         /* device descriptor */
        char *dev_path;     /* device path */
@@ -232,8 +260,10 @@ struct fdisk_context {
        size_t nlabels;                 /* number of initialized label drivers */
        struct fdisk_label *labels[8];  /* all supported labels,
                                         * FIXME: use any enum rather than hardcoded number */
-};
 
+       int     (*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *);  /* fdisk dialogs callback */
+       void    *ask_data;              /* ask_cb() data */
+};
 
 /* context.c */
 extern int __fdisk_context_switch_label(struct fdisk_context *cxt,
@@ -276,4 +306,7 @@ extern void fdisk_deinit_label(struct fdisk_label *lb);
 /* gpt.c -- temporary bypass library API... */
 extern void gpt_list_table(struct fdisk_context *cxt, int xtra);
 
+/* ask.c */
+extern int fdisk_ask_partnum(struct fdisk_context *cxt, size_t *partnum, int wantnew);
+
 #endif /* _LIBFDISK_PRIVATE_H */
index e631154817fd85a4eb6b70314a91495974cb2b52..f80bf66b126710f288b480f8de81ab62f9ee32d2 100644 (file)
@@ -34,6 +34,7 @@ int fdisk_probe_labels(struct fdisk_context *cxt)
                return 0;
        }
 
+       DBG(LABEL, dbgprint("no label found"));
        return 1; /* not found */
 }
 
@@ -100,21 +101,31 @@ int fdisk_verify_disklabel(struct fdisk_context *cxt)
 /**
  * fdisk_add_partition:
  * @cxt: fdisk context
- * @partnum: partition number to create
  * @t: partition type to create or NULL for label-specific default
  *
  * Creates a new partition, with number @partnum and type @parttype.
  *
  * Returns 0.
  */
-int fdisk_add_partition(struct fdisk_context *cxt, size_t partnum,
+int fdisk_add_partition(struct fdisk_context *cxt,
                        struct fdisk_parttype *t)
 {
+       size_t partnum = 0;
+
+       assert(cxt);
+       assert(cxt->label);
+
        if (!cxt || !cxt->label)
                return -EINVAL;
        if (!cxt->label->op->part_add)
                return -ENOSYS;
 
+       if (!(cxt->label->flags & FDISK_LABEL_FL_ADDPART_NOPARTNO)) {
+               int rc = fdisk_ask_partnum(cxt, &partnum, 1);
+               if (rc)
+                       return rc;
+       }
+
        DBG(LABEL, dbgprint("adding new partition number %zd", partnum));
        cxt->label->op->part_add(cxt, partnum, t);
        return 0;
@@ -243,12 +254,17 @@ int fdisk_partition_get_status(struct fdisk_context *cxt,
                               size_t partnum,
                               int *status)
 {
+       int rc;
+
        if (!cxt || !cxt->label)
                return -EINVAL;
        if (!cxt->label->op->part_get_status)
                return -ENOSYS;
 
-       return cxt->label->op->part_get_status(cxt, partnum, status);
+       rc = cxt->label->op->part_get_status(cxt, partnum, status);
+
+       /* DBG(LABEL, dbgprint("partition: %zd: status: 0x%04x [rc=%d]", partnum, *status, rc)); */
+       return rc;
 }
 
 
index 18b14163ec0ca5581bd855d1609f2bb23cc8c001..a19849dc4d1ac577ae860d948d0abba850af1170 100644 (file)
@@ -28,6 +28,7 @@ extern "C" {
 struct fdisk_context;
 struct fdisk_label;
 struct fdisk_parttype;
+struct fdisk_ask;
 
 /*
  * Supported partition table types (labels)
@@ -44,7 +45,7 @@ enum fdisk_labeltype {
 };
 
 enum {
-       FDISK_PARTSTAT_NONE,
+       FDISK_PARTSTAT_NONE = 0,
        FDISK_PARTSTAT_USED     /* partition used */
 };
 
@@ -55,6 +56,10 @@ extern void fdisk_init_debug(int mask);
 extern struct fdisk_context *fdisk_new_context(void);
 extern void fdisk_free_context(struct fdisk_context *cxt);
 
+extern int fdisk_context_set_ask(struct fdisk_context *cxt,
+                       int (*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *),
+                       void *data);
+
 extern int fdisk_context_assign_device(struct fdisk_context *cxt,
                                const char *fname, int readonly);
 
@@ -85,7 +90,7 @@ extern int fdisk_write_disklabel(struct fdisk_context *cxt);
 extern int fdisk_verify_disklabel(struct fdisk_context *cxt);
 extern int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name);
 
-extern int fdisk_add_partition(struct fdisk_context *cxt, size_t partnum, struct fdisk_parttype *t);
+extern int fdisk_add_partition(struct fdisk_context *cxt, struct fdisk_parttype *t);
 extern int fdisk_delete_partition(struct fdisk_context *cxt, size_t partnum);
 
 extern struct fdisk_parttype *fdisk_get_partition_type(struct fdisk_context *cxt, size_t partnum);
@@ -105,6 +110,15 @@ extern int fdisk_reset_alignment(struct fdisk_context *cxt);
 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 int fdisk_ask_get_type(struct fdisk_ask *ask);
+extern const char *fdisk_ask_number_get_range(struct fdisk_ask *ask);
+extern uint64_t fdisk_ask_number_get_default(struct fdisk_ask *ask);
+extern uint64_t fdisk_ask_number_get_low(struct fdisk_ask *ask);
+extern uint64_t fdisk_ask_number_get_high(struct fdisk_ask *ask);
+extern int fdisk_ask_number_set_result(struct fdisk_ask *ask, uint64_t result);
+
 #ifdef __cplusplus
 }
 #endif