/*
* Low-level probe result
*/
-#define BLKID_PROBVAL_BUFSIZ 128
-
-#define BLKID_NVALS_SUBLKS 18
-#define BLKID_NVALS_TOPLGY 5
-#define BLKID_NVALS_PARTS 13
-
-/* Max number of all values in probing result */
-#define BLKID_NVALS (BLKID_NVALS_SUBLKS + \
- BLKID_NVALS_TOPLGY + \
- BLKID_NVALS_PARTS)
-
struct blkid_prval
{
- const char *name; /* value name */
- unsigned char data[BLKID_PROBVAL_BUFSIZ]; /* value data */
- size_t len; /* length of value data */
+ const char *name; /* value name */
+ unsigned char *data; /* value data */
+ size_t len; /* length of value data */
struct blkid_chain *chain; /* owner */
+ struct list_head prvals; /* list of results */
};
/*
struct blkid_chain chains[BLKID_NCHAINS]; /* array of chains */
struct blkid_chain *cur_chain; /* current chain */
- struct blkid_prval vals[BLKID_NVALS]; /* results */
- int nvals; /* number of assigned vals */
+ struct list_head vals; /* results */
struct blkid_struct_probe *parent; /* for clones */
struct blkid_struct_probe *disk_probe; /* whole-disk probing */
__attribute__((nonnull));
extern int blkid_probe_chain_copy_vals(blkid_probe pr,
struct blkid_chain *chn,
- struct blkid_prval *vals,
- int nvals)
+ struct list_head *vals)
__attribute__((nonnull));
extern struct blkid_prval *blkid_probe_assign_value(blkid_probe pr,
__attribute__((nonnull))
__attribute__((warn_unused_result));
-extern int blkid_probe_reset_last_value(blkid_probe pr)
- __attribute__((nonnull));
+extern void blkid_probe_free_val(struct blkid_prval *v);
+
+
extern void blkid_probe_append_vals(blkid_probe pr,
- struct blkid_prval *vals,
- int nvals)
+ struct list_head *vals)
__attribute__((nonnull));
extern struct blkid_chain *blkid_probe_get_chain(blkid_probe pr)
__attribute__((nonnull))
__attribute__((warn_unused_result));
+extern struct blkid_prval *blkid_probe_last_value(blkid_probe pr);
+
extern struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num)
__attribute__((nonnull))
__attribute__((warn_unused_result));
__attribute__((nonnull))
__attribute__((warn_unused_result));
+extern struct blkid_prval *blkid_probe_new_val(void)
+ __attribute__((warn_unused_result));
extern int blkid_probe_set_value(blkid_probe pr, const char *name,
unsigned char *data, size_t len)
__attribute__((nonnull));
+extern int blkid_probe_value_set_data(struct blkid_prval *v,
+ unsigned char *data, size_t len)
+ __attribute__((nonnull));
extern int blkid_probe_vsprintf_value(blkid_probe pr, const char *name,
const char *fmt, va_list ap)
(blkid_bmp_nwords(max_items) * sizeof(unsigned long))
/* encode.c */
+extern unsigned char *blkid_encode_alloc(size_t count, size_t *reslen);
extern size_t blkid_encode_to_utf8(int enc, unsigned char *dest, size_t len,
const unsigned char *src, size_t count)
__attribute__((nonnull));
return j;
}
+unsigned char *blkid_encode_alloc(size_t count, size_t *reslen)
+{
+ *reslen = (count * 3) + 1;
+ return calloc(1, *reslen);
+}
+
/**
* blkid_encode_string:
* @str: input string to be encoded
return 0;
v = blkid_probe_assign_value(pr, "PTUUID");
+ if (!v)
+ return -ENOMEM;
- blkid_unparse_uuid(uuid, (char *) v->data, sizeof(v->data));
v->len = 37;
+ v->data = calloc(1, v->len);
+ if (v->data) {
+ blkid_unparse_uuid(uuid, (char *) v->data, v->len);
+ return 0;
+ }
- return 0;
+ blkid_probe_free_val(v);
+ return -ENOMEM;
}
/* set PTUUID variable for non-binary API for tables where
int blkid_partitions_strcpy_ptuuid(blkid_probe pr, char *str)
{
struct blkid_chain *chn = blkid_probe_get_chain(pr);
- struct blkid_prval *v;
- size_t len;
if (chn->binary || !str || !*str)
return 0;
- len = strlen((char *) str);
- if (len > BLKID_PROBVAL_BUFSIZ)
- len = BLKID_PROBVAL_BUFSIZ;
-
- v = blkid_probe_assign_value(pr, "PTUUID");
- if (v) {
- if (len == BLKID_PROBVAL_BUFSIZ)
- len--; /* make a space for \0 */
+ if (!blkid_probe_set_value(pr, "PTUUID", (unsigned char *) str, strlen(str) + 1))
+ return -ENOMEM;
- memcpy((char *) v->data, str, len);
- v->data[len] = '\0';
- v->len = len + 1;
- return 0;
- }
- return -1;
+ return 0;
}
/**
#include "all-io.h"
#include "sysfs.h"
#include "strutils.h"
+#include "list.h"
/* chains */
extern const struct blkid_chaindrv superblocks_drv;
[BLKID_CHAIN_PARTS] = &partitions_drv
};
+static struct blkid_prval *blkid_probe_new_value(void);
static void blkid_probe_reset_vals(blkid_probe pr);
static void blkid_probe_reset_buffer(blkid_probe pr);
pr->chains[i].enabled = chains_drvs[i]->dflt_enabled;
}
INIT_LIST_HEAD(&pr->buffers);
+ INIT_LIST_HEAD(&pr->vals);
return pr;
}
free(pr);
}
+void blkid_probe_free_val(struct blkid_prval *v)
+{
+ if (!v)
+ return;
+
+ list_del(&v->prvals);
+ free(v->data);
+ free(v);
+}
/*
* Removes chain values from probing result.
*/
void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn)
{
- int nvals = pr->nvals;
- int i, x;
- for (x = 0, i = 0; i < pr->nvals; i++) {
- struct blkid_prval *v = &pr->vals[i];
+ struct list_head *p, *pnext;
- if (v->chain != chn && x == i) {
- x++;
- continue;
- }
- if (v->chain == chn) {
- --nvals;
- continue;
- }
- memcpy(&pr->vals[x++], v, sizeof(struct blkid_prval));
+ if (!pr || list_empty(&pr->vals))
+ return;
+
+ list_for_each_safe(p, pnext, &pr->vals) {
+ struct blkid_prval *v = list_entry(p,
+ struct blkid_prval, prvals);
+
+ if (v->chain == chn)
+ blkid_probe_free_val(v);
}
- pr->nvals = nvals;
}
static void blkid_probe_chain_reset_position(struct blkid_chain *chn)
chn->idx = -1;
}
+static struct blkid_prval *blkid_probe_deep_copy_val(struct blkid_prval *dest,
+ struct blkid_prval *src)
+{
+ memcpy(dest, src, sizeof(struct blkid_prval));
+
+ dest->data = malloc(src->len);
+ if (!dest->data)
+ return NULL;
+
+ memcpy(dest->data, src->data, src->len);
+
+ INIT_LIST_HEAD(&dest->prvals);
+
+ return dest;
+}
+
/*
- * Copies chain values from probing result to @vals, the max size of @vals is
- * @nvals and returns real number of values.
+ * Copies chain values from probing result to @vals.
*/
int blkid_probe_chain_copy_vals(blkid_probe pr, struct blkid_chain *chn,
- struct blkid_prval *vals, int nvals)
+ struct list_head *vals)
{
- int i, x;
+ struct list_head *p;
+ struct blkid_prval *new_v, *v;
- for (x = 0, i = 0; i < pr->nvals && x < nvals; i++) {
- struct blkid_prval *v = &pr->vals[i];
+ list_for_each(p, &pr->vals) {
+
+ v = list_entry(p, struct blkid_prval, prvals);
+
+ new_v = blkid_probe_new_value();
+ if (!new_v)
+ break;
if (v->chain != chn)
continue;
- memcpy(&vals[x++], v, sizeof(struct blkid_prval));
+
+ if (!blkid_probe_deep_copy_val(new_v, v))
+ break;
+
+ list_add_tail(&new_v->prvals, vals);
}
- return x;
+ return 0;
}
/*
* Appends values from @vals to the probing result
*/
-void blkid_probe_append_vals(blkid_probe pr, struct blkid_prval *vals, int nvals)
+void blkid_probe_append_vals(blkid_probe pr, struct list_head *vals)
{
- int i = 0;
-
- while (i < nvals && pr->nvals < BLKID_NVALS) {
- memcpy(&pr->vals[pr->nvals++], &vals[i++],
- sizeof(struct blkid_prval));
- }
-}
-
-static void blkid_probe_reset_vals(blkid_probe pr)
-{
- memset(pr->vals, 0, sizeof(pr->vals));
- pr->nvals = 0;
+ list_splice(vals, &pr->vals);
}
struct blkid_chain *blkid_probe_get_chain(blkid_probe pr)
return off ? bf->data + (off - bf->off) : bf->data;
}
-
static void blkid_probe_reset_buffer(blkid_probe pr)
{
uint64_t read_ct = 0, len_ct = 0;
INIT_LIST_HEAD(&pr->buffers);
}
+static void blkid_probe_reset_vals(blkid_probe pr)
+{
+ if (!pr || list_empty(&pr->vals))
+ return;
+
+ DBG(LOWPROBE, ul_debug("resetting results pr=%p", pr));
+
+ while (!list_empty(&pr->vals)) {
+ struct blkid_prval *v = list_entry(pr->vals.next,
+ struct blkid_prval, prvals);
+ blkid_probe_free_val(v);
+ }
+
+ INIT_LIST_HEAD(&pr->vals);
+}
+
/*
* Small devices need a special care.
*/
blkid_probe pr, const char *name)
{
struct blkid_prval *v;
-
if (!name)
return NULL;
- if (pr->nvals >= BLKID_NVALS)
+
+ v = blkid_probe_new_value();
+ if (!v)
return NULL;
- v = &pr->vals[pr->nvals];
v->name = name;
v->chain = pr->cur_chain;
- pr->nvals++;
+ list_add_tail(&v->prvals, &pr->vals);
DBG(LOWPROBE, ul_debug("assigning %s [%s]", name, v->chain->driver->name));
return v;
}
-int blkid_probe_reset_last_value(blkid_probe pr)
+static struct blkid_prval *blkid_probe_new_value(void)
{
- struct blkid_prval *v;
-
- if (pr == NULL || pr->nvals == 0)
- return -1;
+ struct blkid_prval *v = calloc(1, sizeof(struct blkid_prval));
+ if (!v)
+ return NULL;
- v = &pr->vals[pr->nvals - 1];
+ INIT_LIST_HEAD(&v->prvals);
- DBG(LOWPROBE, ul_debug("un-assigning %s [%s]", v->name, v->chain->driver->name));
+ return v;
+}
- memset(v, 0, sizeof(struct blkid_prval));
- pr->nvals--;
+/* Note that value data is always terminated by zero to keep things robust,
+ * this extra zero is not count to the value lenght. It's caller responsibility
+ * to set proper value lenght (for strings we count terminator to the lenght,
+ * for binary data it's without terminator).
+ */
+int blkid_probe_value_set_data(struct blkid_prval *v,
+ unsigned char *data, size_t len)
+{
+ v->data = calloc(1, len + 1); /* always terminate by \0 */
+ if (!v->data)
+ return -ENOMEM;
+ memcpy(v->data, data, len);
+ v->len = len;
return 0;
-
}
int blkid_probe_set_value(blkid_probe pr, const char *name,
{
struct blkid_prval *v;
- if (len > BLKID_PROBVAL_BUFSIZ)
- len = BLKID_PROBVAL_BUFSIZ;
-
v = blkid_probe_assign_value(pr, name);
if (!v)
return -1;
- memcpy(v->data, data, len);
- v->len = len;
- return 0;
+ return blkid_probe_value_set_data(v, data, len);
}
int blkid_probe_vsprintf_value(blkid_probe pr, const char *name,
v = blkid_probe_assign_value(pr, name);
if (!v)
- return -1;
+ return -ENOMEM;
- len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap);
+ len = vasprintf((char **) &v->data, fmt, ap);
- if (len <= 0 || (size_t) len >= sizeof(v->data)) {
- blkid_probe_reset_last_value(pr);
- return -1;
+ if (len <= 0) {
+ blkid_probe_free_val(v);
+ return len == 0 ? -EINVAL : -ENOMEM;
}
v->len = len + 1;
return 0;
*/
int blkid_probe_numof_values(blkid_probe pr)
{
+ int i = 0;
+ struct list_head *p;
if (!pr)
return -1;
- return pr->nvals;
+
+ list_for_each(p, &pr->vals)
+ ++i;
+ return i;
}
/**
return 0;
}
+struct blkid_prval *blkid_probe_last_value(blkid_probe pr)
+{
+ if (!pr || list_empty(&pr->vals))
+ return NULL;
+
+ return list_last_entry(&pr->vals, struct blkid_prval, prvals);
+}
+
+
struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num)
{
- if (!pr || num < 0 || num >= pr->nvals)
+ int i = 0;
+ struct list_head *p;
+
+ if (!pr || num < 0)
return NULL;
- return &pr->vals[num];
+ list_for_each(p, &pr->vals) {
+ if (i++ != num)
+ continue;
+ return list_entry(p, struct blkid_prval, prvals);
+ }
+ return NULL;
}
struct blkid_prval *__blkid_probe_lookup_value(blkid_probe pr, const char *name)
{
- int i;
+ struct list_head *p;
- if (!pr || !pr->nvals || !name)
+ if (!pr || list_empty(&pr->vals) || !name)
return NULL;
- for (i = 0; i < pr->nvals; i++) {
- struct blkid_prval *v = &pr->vals[i];
+ list_for_each(p, &pr->vals) {
+ struct blkid_prval *v = list_entry(p, struct blkid_prval,
+ prvals);
if (v->name && strcmp(name, v->name) == 0) {
DBG(LOWPROBE, ul_debug("returning %s value", v->name));
*/
static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn)
{
- struct blkid_prval vals[BLKID_NVALS_SUBLKS];
- int nvals = BLKID_NVALS_SUBLKS;
+ struct list_head vals;
int idx = -1;
int count = 0;
int intol = 0;
int rc;
+ INIT_LIST_HEAD(&vals);
+
if (pr->flags & BLKID_FL_NOSCAN_DEV)
return BLKID_PROBE_NONE;
if (count == 1) {
/* save the first result */
- nvals = blkid_probe_chain_copy_vals(pr, chn, vals, nvals);
+ blkid_probe_chain_copy_vals(pr, chn, &vals);
idx = chn->idx;
}
}
if (idx != -1) {
/* restore the first result */
blkid_probe_chain_reset_vals(pr, chn);
- blkid_probe_append_vals(pr, vals, nvals);
+ blkid_probe_append_vals(pr, &vals);
chn->idx = idx;
}
{
struct blkid_chain *chn = blkid_probe_get_chain(pr);
struct blkid_prval *v;
+ int rc = 0;
if (!(chn->flags & BLKID_SUBLKS_LABEL))
return 0;
v = blkid_probe_assign_value(pr, name);
if (!v)
- return -1;
+ return -ENOMEM;
- if (len >= BLKID_PROBVAL_BUFSIZ)
- len = BLKID_PROBVAL_BUFSIZ - 1; /* make a space for \0 */
-
- memcpy(v->data, data, len);
- v->data[len] = '\0';
+ rc = blkid_probe_value_set_data(v, data, len);
+ if (!rc) {
+ /* remove white spaces */
+ v->len = blkid_rtrim_whitespace(v->data) + 1;
+ if (v->len > 1)
+ v->len = blkid_ltrim_whitespace(v->data) + 1;
+ if (v->len > 1)
+ return 0;
+ }
- /* remove white spaces */
- v->len = blkid_rtrim_whitespace(v->data) + 1;
- if (v->len > 1)
- v->len = blkid_ltrim_whitespace(v->data) + 1;
+ blkid_probe_free_val(v);
+ return rc;
- if (v->len <= 1)
- blkid_probe_reset_last_value(pr); /* ignore empty */
- return 0;
}
int blkid_probe_set_utf8_id_label(blkid_probe pr, const char *name,
{
struct blkid_chain *chn = blkid_probe_get_chain(pr);
struct blkid_prval *v;
+ int rc = 0;
if (!(chn->flags & BLKID_SUBLKS_LABEL))
return 0;
v = blkid_probe_assign_value(pr, name);
if (!v)
- return -1;
+ return -ENOMEM;
- blkid_encode_to_utf8(enc, v->data, sizeof(v->data), data, len);
- v->len = blkid_rtrim_whitespace(v->data) + 1;
- if (v->len > 1)
- v->len = blkid_ltrim_whitespace(v->data) + 1;
+ v->data = blkid_encode_alloc(len, &v->len);
+ if (!v->data)
+ rc = -ENOMEM;
- if (v->len <= 1)
- blkid_probe_reset_last_value(pr);
- return 0;
+ if (!rc) {
+ blkid_encode_to_utf8(enc, v->data, v->len, data, len);
+ v->len = blkid_rtrim_whitespace(v->data) + 1;
+ if (v->len > 1)
+ v->len = blkid_ltrim_whitespace(v->data) + 1;
+ if (v->len > 1)
+ return 0;
+ }
+
+ blkid_probe_free_val(v);
+ return rc;
}
int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len)
{
struct blkid_chain *chn = blkid_probe_get_chain(pr);
struct blkid_prval *v;
- if (len > BLKID_PROBVAL_BUFSIZ)
- len = BLKID_PROBVAL_BUFSIZ;
+ int rc = 0;
if ((chn->flags & BLKID_SUBLKS_LABELRAW) &&
- blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
- return -1;
+ (rc = blkid_probe_set_value(pr, "LABEL_RAW", label, len)) < 0)
+ return rc;
+
if (!(chn->flags & BLKID_SUBLKS_LABEL))
return 0;
+
v = blkid_probe_assign_value(pr, "LABEL");
if (!v)
- return -1;
-
- if (len == BLKID_PROBVAL_BUFSIZ)
- len--; /* make a space for \0 */
+ return -ENOMEM;
- memcpy(v->data, label, len);
- v->data[len] = '\0';
+ rc = blkid_probe_value_set_data(v, label, len);
+ if (!rc) {
+ v->len = blkid_rtrim_whitespace(v->data) + 1;
+ if (v->len > 1)
+ return 0;
+ }
- v->len = blkid_rtrim_whitespace(v->data) + 1;
- if (v->len == 1)
- blkid_probe_reset_last_value(pr);
- return 0;
+ blkid_probe_free_val(v);
+ return rc;
}
int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label,
{
struct blkid_chain *chn = blkid_probe_get_chain(pr);
struct blkid_prval *v;
+ int rc = 0;
if ((chn->flags & BLKID_SUBLKS_LABELRAW) &&
- blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
- return -1;
+ (rc = blkid_probe_set_value(pr, "LABEL_RAW", label, len)) < 0)
+ return rc;
+
if (!(chn->flags & BLKID_SUBLKS_LABEL))
return 0;
+
v = blkid_probe_assign_value(pr, "LABEL");
if (!v)
- return -1;
+ return -ENOMEM;
- blkid_encode_to_utf8(enc, v->data, sizeof(v->data), label, len);
- v->len = blkid_rtrim_whitespace(v->data) + 1;
- if (v->len == 1)
- blkid_probe_reset_last_value(pr);
- return 0;
+ v->data = blkid_encode_alloc(len, &v->len);
+ if (!v->data)
+ rc = -ENOMEM;
+ if (!rc) {
+ blkid_encode_to_utf8(enc, v->data, v->len, label, len);
+ v->len = blkid_rtrim_whitespace(v->data) + 1;
+ if (v->len > 1)
+ return 0;
+ }
+
+ blkid_probe_free_val(v);
+ return rc;
}
int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid,
size_t len, const char *fmt, ...)
{
struct blkid_chain *chn = blkid_probe_get_chain(pr);
- int rc = -1;
va_list ap;
-
- if (len > BLKID_PROBVAL_BUFSIZ)
- len = BLKID_PROBVAL_BUFSIZ;
+ int rc = 0;
if (blkid_uuid_is_empty(uuid, len))
return 0;
if ((chn->flags & BLKID_SUBLKS_UUIDRAW) &&
- blkid_probe_set_value(pr, "UUID_RAW", uuid, len) < 0)
- return -1;
+ (rc = blkid_probe_set_value(pr, "UUID_RAW", uuid, len)) < 0)
+ return rc;
+
if (!(chn->flags & BLKID_SUBLKS_UUID))
return 0;
rc = blkid_probe_vsprintf_value(pr, "UUID", fmt, ap);
va_end(ap);
- /* convert to lower case (..be paranoid) */
- if (!rc) {
- size_t i;
- struct blkid_prval *v = __blkid_probe_get_value(pr,
- blkid_probe_numof_values(pr));
- if (v) {
- for (i = 0; i < v->len; i++)
- if (v->data[i] >= 'A' && v->data[i] <= 'F')
- v->data[i] = (v->data[i] - 'A') + 'a';
- }
- }
return rc;
}
{
struct blkid_chain *chn = blkid_probe_get_chain(pr);
struct blkid_prval *v;
+ int rc = 0;
if (str == NULL || *str == '\0')
- return -1;
+ return -EINVAL;
+
if (!len)
len = strlen((char *) str);
- if (len > BLKID_PROBVAL_BUFSIZ)
- len = BLKID_PROBVAL_BUFSIZ;
if ((chn->flags & BLKID_SUBLKS_UUIDRAW) &&
- blkid_probe_set_value(pr, "UUID_RAW", str, len) < 0)
- return -1;
+ (rc = blkid_probe_set_value(pr, "UUID_RAW", str, len)) < 0)
+ return rc;
+
if (!(chn->flags & BLKID_SUBLKS_UUID))
return 0;
v = blkid_probe_assign_value(pr, "UUID");
- if (v) {
- if (len == BLKID_PROBVAL_BUFSIZ)
- len--; /* make a space for \0 */
-
- memcpy((char *) v->data, str, len);
- v->data[len] = '\0';
- v->len = len + 1;
- return 0;
+ if (!v)
+ rc= -ENOMEM;
+ if (!rc)
+ rc = blkid_probe_value_set_data(v, str, len);
+ if (!rc) {
+ v->len = blkid_rtrim_whitespace(v->data) + 1;
+ if (v->len > 1)
+ return 0;
}
- return -1;
+
+ blkid_probe_free_val(v);
+ return rc;
}
/* default _set_uuid function to set DCE UUIDs */
{
struct blkid_chain *chn = blkid_probe_get_chain(pr);
struct blkid_prval *v;
+ int rc = 0;
if (blkid_uuid_is_empty(uuid, 16))
return 0;
if (!name) {
if ((chn->flags & BLKID_SUBLKS_UUIDRAW) &&
- blkid_probe_set_value(pr, "UUID_RAW", uuid, 16) < 0)
- return -1;
+ (rc = blkid_probe_set_value(pr, "UUID_RAW", uuid, 16)) < 0)
+ return rc;
+
if (!(chn->flags & BLKID_SUBLKS_UUID))
return 0;
} else
v = blkid_probe_assign_value(pr, name);
- blkid_unparse_uuid(uuid, (char *) v->data, sizeof(v->data));
+ if (!v)
+ return -ENOMEM;
+
v->len = 37;
+ v->data = calloc(1, v->len);
+ if (!v->data)
+ rc = -ENOMEM;
- return 0;
+ if (!rc) {
+ blkid_unparse_uuid(uuid, (char *) v->data, v->len);
+ return 0;
+ }
+
+ blkid_probe_free_val(v);
+ return rc;
}
int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid)