--- /dev/null
+
+#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
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));
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;
}
/**
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;
+}
#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 { \
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 */
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,
/* 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 */
return 0;
}
+ DBG(LABEL, dbgprint("no label found"));
return 1; /* not found */
}
/**
* 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;
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;
}
struct fdisk_context;
struct fdisk_label;
struct fdisk_parttype;
+struct fdisk_ask;
/*
* Supported partition table types (labels)
};
enum {
- FDISK_PARTSTAT_NONE,
+ FDISK_PARTSTAT_NONE = 0,
FDISK_PARTSTAT_USED /* partition used */
};
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);
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);
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