aboutsummaryrefslogtreecommitdiff
path: root/ubi-utils/src/libubi
diff options
context:
space:
mode:
Diffstat (limited to 'ubi-utils/src/libubi')
-rw-r--r--ubi-utils/src/libubi/libubi.c773
-rw-r--r--ubi-utils/src/libubi/libubi_int.h119
-rw-r--r--ubi-utils/src/libubi/libubi_sysfs.c231
-rw-r--r--ubi-utils/src/libubi/libubi_sysfs.h109
4 files changed, 1232 insertions, 0 deletions
diff --git a/ubi-utils/src/libubi/libubi.c b/ubi-utils/src/libubi/libubi.c
new file mode 100644
index 0000000..9b9a793
--- /dev/null
+++ b/ubi-utils/src/libubi/libubi.c
@@ -0,0 +1,773 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * UBI (Unsorted Block Images) library.
+ *
+ * Author: Artem B. Bityutskiy
+ * Oliver Lohmann
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <stdint.h>
+#include <mtd/ubi-user.h>
+
+#include "libubi.h"
+#include "libubi_int.h"
+#include "libubi_sysfs.h"
+
+/**
+ * struct ubi_lib - UBI library descriptor.
+ *
+ * @ubi general UBI information
+ *
+ * @sysfs_root sysfs root directory
+ * @ubi_root UBI root directory in sysfs
+ *
+ * @nlen_max full path to the "maximum volume name length" sysfs file
+ * @version full path to the "UBI version" sysfs file
+ *
+ * @cdev_path path pattern to UBI character devices
+ * @cdev_path_len maximum length of the @cdev_path string after substitution
+ * @udev_path path to sysfs directories corresponding to UBI devices
+ * @wear_path path to sysfs file containing UBI wear information
+ * @vol_count_path path to sysfs file containing the number of volumes in an
+ * UBI device
+ * @tot_ebs_path path to sysfs file containing the total number of
+ * eraseblock on an UBI device
+ * @avail_ebs_path path to sysfs file containing the number of unused
+ * eraseblocks on an UBI device, available for new volumes
+ * @eb_size_path path to sysfs file containing size of UBI eraseblocks
+ * @nums_path path to sysfs file containing major and minor number of an
+ * UBI device
+ * @vol_cdev_path path to UBI volume character devices
+ * @vdev_path path to sysfs directories corresponding to UBI volume
+ * devices
+ * @vol_nums_path path to sysfs file containing major and minor number of an
+ * UBI volume device
+ * @vol_bytes_path path to sysfs file containing size of an UBI volume device
+ * in bytes
+ * @vol_ebs_path path to sysfs file containing the number of eraseblocks in
+ * an UBI volume device
+ * @vol_type_path path to sysfs file containing type of an UBI volume
+ * @vol_name_path @FIXME: Describe me.
+ *
+ * This structure is created and initialized by 'ubi_init()' and is passed to
+ * all UBI library calls.
+ */
+struct ubi_lib
+{
+ struct ubi_info ubi;
+
+ char *sysfs_root;
+ char *ubi_root;
+
+ char *nlen_max;
+ char *version;
+ char *cdev_path;
+ int cdev_path_len;
+ char *udev_path;
+ char *wear_path;
+ char *vol_count_path;
+ char *tot_ebs_path;
+ char *avail_ebs_path;
+ char *eb_size_path;
+ char *nums_path;
+ int vol_cdev_path_len;
+ char *vol_cdev_path;
+ char *vdev_path;
+ char *vol_nums_path;
+ char *vol_bytes_path;
+ char *vol_ebs_path;
+ char *vol_type_path;
+ char *vol_name_path;
+};
+
+
+/**
+ * mkpath - compose full path from 2 given components.
+ *
+ * @path first component @name second component
+ *
+ * Returns the resulting path in case of success and %NULL in case of failure.
+ * Callers have to take care the resulting path is freed.
+ */
+static char*
+mkpath(const char *path, const char *name)
+{
+ char *n;
+ int len1 = strlen(path);
+ int len2 = strlen(name);
+
+ n = malloc(len1 + len2 + 2);
+ if (!n)
+ return NULL;
+
+ memcpy(n, path, len1);
+ if (n[len1 - 1] != '/')
+ n[len1++] = '/';
+
+ memcpy(n + len1, name, len2 + 1);
+ return n;
+}
+
+
+static int
+get_ubi_info(ubi_lib_t desc, struct ubi_info *ubi)
+{
+ int err;
+ int n = 1;
+ char *path;
+ struct stat stat;
+
+ err = sysfs_read_int(desc->version, (int*) &ubi->version);
+ if (err)
+ return -1;
+
+ err = sysfs_read_int(desc->nlen_max, (int*) &ubi->nlen_max);
+ if (err)
+ return -1;
+
+ /* Calculate number of UBI devices */
+ do {
+ char dir[20];
+
+ sprintf(&dir[0], "ubi%d", n);
+ path = mkpath(desc->sysfs_root, dir);
+ if (!path)
+ return ENOMEM;
+
+ err = lstat(path, &stat);
+ if (err == 0)
+ n += 1;
+ free(path);
+ } while (err == 0);
+
+ if (errno != ENOENT)
+ return -1;
+
+ if (n == 0) {
+ ubi_err("no UBI devices found");
+ errno = EINVAL;
+ return -1;
+ }
+
+ errno = 0;
+ ubi->dev_count = n;
+ return 0;
+}
+
+void
+ubi_dump_handler(ubi_lib_t desc)
+{
+ ubi_lib_t d = desc;
+ printf( "UBI Library Descriptor:\n"
+ "ubi_root: %s\n"
+ "nlen_max: %s\n"
+ "version: %s\n"
+ "cdev_path: %s\n"
+ "udev_path: %s\n"
+ "wear_path: %s\n"
+ "vol_count_path: %s\n"
+ "tot_ebs_path: %s\n"
+ "avail_ebs_path: %s\n"
+ "eb_size_path: %s\n"
+ "nums_path: %s\n"
+ "vol_cdev_path: %s\n"
+ "vdev_path: %s\n"
+ "vol_nums_path: %s\n"
+ "vol_bytes_path: %s\n"
+ "vol_ebs_path: %s\n"
+ "vol_type_path: %s\n"
+ "vol_name_path: %s\n"
+ "cdev_path_len: %d\n\n",
+ d->ubi_root, d->nlen_max, d->version, d->cdev_path,
+ d->udev_path, d->wear_path, d->vol_count_path,
+ d->tot_ebs_path, d->avail_ebs_path, d->eb_size_path,
+ d->nums_path, d->vol_cdev_path, d->vdev_path,
+ d->vol_nums_path, d->vol_bytes_path, d->vol_ebs_path,
+ d->vol_type_path, d->vol_name_path, d->cdev_path_len);
+}
+
+int
+ubi_set_cdev_pattern(ubi_lib_t desc, const char *pattern)
+{
+ char *patt;
+
+ patt = strdup(pattern);
+ if (!patt) {
+ ubi_err("cannot allocate memory");
+ return -1;
+ }
+
+ if (desc->cdev_path)
+ free(desc->cdev_path);
+
+ desc->cdev_path = patt;
+ desc->cdev_path_len = strlen(patt) + 1 + UBI_MAX_ID_SIZE;
+
+ ubi_dbg("ubi dev pattern is now \"%s\"", patt);
+
+ return 0;
+}
+
+int
+ubi_set_vol_cdev_pattern(ubi_lib_t desc, const char *pattern)
+{
+ char *patt;
+
+ patt = strdup(pattern);
+ if (!patt) {
+ ubi_err("cannot allocate memory");
+ return -1;
+ }
+
+ free(desc->vol_cdev_path);
+ desc->vol_cdev_path = patt;
+ desc->vol_cdev_path_len = strlen(patt) + 1 + 2 * UBI_MAX_ID_SIZE;
+
+ ubi_dbg("ubi volume dev pattern is now \"%s\"", patt);
+
+ return 0;
+}
+
+int
+ubi_open(ubi_lib_t *desc)
+{
+ int err = -1;
+ ubi_lib_t res;
+ struct stat stat;
+
+ res = calloc(1, sizeof(struct ubi_lib));
+ if (!res) {
+ ubi_err("cannot allocate memory");
+ return -1;
+ }
+
+ res->cdev_path = NULL;
+ err = ubi_set_cdev_pattern(res, UBI_CDEV_PATH);
+ if (err)
+ goto error;
+
+ /* TODO: this actually has to be discovered */
+ res->sysfs_root = strdup(UBI_SYSFS_ROOT);
+ if (!res->sysfs_root)
+ goto error;
+
+ res->ubi_root = mkpath(res->sysfs_root, UBI_ROOT);
+ if (!res->ubi_root)
+ goto error;
+
+ res->nlen_max = mkpath(res->ubi_root, UBI_NLEN_MAX);
+ if (!res->nlen_max)
+ goto error;
+
+ res->version = mkpath(res->ubi_root, UBI_VERSION);
+ if (!res->version)
+ goto error;
+
+ res->udev_path = mkpath(res->ubi_root, "ubi%d/");
+ if (!res->udev_path)
+ goto error;
+
+ res->wear_path = mkpath(res->udev_path, UBI_WEAR);
+ if (!res->wear_path)
+ goto error;
+
+ res->vol_count_path = mkpath(res->udev_path, UBI_VOL_COUNT);
+ if (!res->vol_count_path)
+ goto error;
+
+ res->tot_ebs_path = mkpath(res->udev_path, UBI_AVAIL_EBS);
+ if (!res->tot_ebs_path)
+ goto error;
+
+ res->avail_ebs_path = mkpath(res->udev_path, UBI_TOT_EBS);
+ if (!res->avail_ebs_path)
+ goto error;
+
+ res->eb_size_path = mkpath(res->udev_path, UBI_EB_SIZE);
+ if (!res->eb_size_path)
+ goto error;
+
+ res->nums_path = mkpath(res->udev_path, UBI_NUMS);
+ if (!res->nums_path)
+ goto error;
+
+ err = ubi_set_vol_cdev_pattern(res, UBI_VOL_CDEV_PATH);
+ if (err)
+ goto error;
+
+ res->vdev_path = mkpath(res->udev_path, "%d/");
+ if (!res->vdev_path)
+ goto error;
+
+ res->vol_nums_path = mkpath(res->vdev_path, UBI_NUMS);
+ if (!res->vol_nums_path)
+ goto error;
+
+ res->vol_bytes_path = mkpath(res->vdev_path, UBI_VBYTES);
+ if (!res->vol_bytes_path)
+ goto error;
+
+ res->vol_ebs_path = mkpath(res->vdev_path, UBI_VEBS);
+ if (!res->vol_ebs_path)
+ goto error;
+
+ res->vol_type_path = mkpath(res->vdev_path, UBI_VTYPE);
+ if (!res->vol_type_path)
+ goto error;
+
+ res->vol_name_path = mkpath(res->vdev_path, UBI_VNAME);
+ if (!res->vol_name_path)
+ goto error;
+
+ /* Check if UBI exists in the system */
+ err = lstat(res->ubi_root, &stat);
+ if (err) {
+ perror("lstat");
+ fprintf(stderr, "%s\n", res->ubi_root);
+ err = UBI_ENOTFOUND;
+ goto error;
+ }
+
+ err = get_ubi_info(res, &res->ubi);
+ if (err)
+ goto error;
+
+ *desc = res;
+
+ ubi_dbg("opened library successfully.");
+
+ return 0;
+
+error:
+ ubi_close(&res);
+
+ if (err == -1 && errno == ENOMEM)
+ ubi_err("Cannot allocate memory");
+
+ return err;
+}
+
+int
+ubi_close(ubi_lib_t *desc)
+{
+ ubi_lib_t tmp = *desc;
+
+ free(tmp->vol_name_path);
+ free(tmp->vol_type_path);
+ free(tmp->vol_ebs_path);
+ free(tmp->vol_bytes_path);
+ free(tmp->vol_nums_path);
+ free(tmp->vdev_path);
+ free(tmp->vol_cdev_path);
+ free(tmp->nums_path);
+ free(tmp->eb_size_path);
+ free(tmp->avail_ebs_path);
+ free(tmp->tot_ebs_path);
+ free(tmp->vol_count_path);
+ free(tmp->wear_path);
+ free(tmp->udev_path);
+ free(tmp->cdev_path);
+ free(tmp->version);
+ free(tmp->nlen_max);
+ free(tmp->ubi_root);
+ free(tmp->sysfs_root);
+ free(tmp);
+
+ *desc = NULL;
+
+ return 0;
+}
+
+void
+ubi_perror(const char *prefix, int code)
+{
+ if (code == 0)
+ return;
+
+ fprintf(stderr, "%s: ", prefix);
+
+ switch (code) {
+ case UBI_ENOTFOUND:
+ fprintf(stderr, "UBI was not found in system\n");
+ break;
+ case UBI_EBUG:
+ fprintf(stderr, "an UBI or UBI library bug\n");
+ break;
+ case UBI_EINVAL:
+ fprintf(stderr, "invalid parameter\n");
+ break;
+ case -1:
+ perror(prefix);
+ break;
+ default:
+ ubi_err("unknown error code %d", code);
+ break;
+ }
+}
+
+int
+ubi_get_dev_info(ubi_lib_t desc, unsigned int devn, struct ubi_dev_info *di)
+{
+ int err;
+
+ if (devn >= desc->ubi.dev_count) {
+ ubi_err("bad device number, max is %d\n",
+ desc->ubi.dev_count - 1);
+ return UBI_EINVAL;
+ }
+
+ err = sysfs_read_dev_subst(desc->nums_path, &di->major,
+ &di->minor, 1, devn);
+ if (err)
+ return -1;
+
+ err = sysfs_read_ull_subst(desc->wear_path, &di->wear, 1, devn);
+ if (err)
+ return -1;
+
+ err = sysfs_read_uint_subst(desc->vol_count_path,
+ &di->vol_count, 1, devn);
+ if (err)
+ return -1;
+
+ err = sysfs_read_uint_subst(desc->eb_size_path, &di->eb_size, 1, devn);
+ if (err)
+ return -1;
+
+ err = sysfs_read_uint_subst(desc->tot_ebs_path, &di->total_ebs, 1, devn);
+ if (err)
+ return -1;
+
+ err = sysfs_read_uint_subst(desc->avail_ebs_path,
+ &di->avail_ebs, 1, devn);
+ if (err)
+ return -1;
+
+#if 0
+ ubi_dbg("major:minor %d:%d, wear %llu, EB size %d, "
+ "vol. count %d, tot. EBs %d, avail. EBs %d",
+ di->major, di->minor, di->wear, di->eb_size,
+ di->vol_count, di->total_ebs, di->avail_ebs);
+#endif
+
+ return err;
+}
+
+int
+ubi_get_vol_info(ubi_lib_t desc, unsigned int devn, unsigned int vol_id,
+ struct ubi_vol_info *req)
+{
+ int err;
+ int len;
+ char buf1[10];
+ char buf2[desc->ubi.nlen_max];
+
+ err = sysfs_read_dev_subst(desc->vol_nums_path, &req->major,
+ &req->minor, 2, devn, vol_id);
+ if (err)
+ return -1;
+
+ err = sysfs_read_ull_subst(desc->vol_bytes_path,
+ &req->bytes, 2, devn, vol_id);
+ if (err)
+ return -1;
+
+ err = sysfs_read_uint_subst(desc->vol_ebs_path,
+ &req->eraseblocks, 2, devn, vol_id);
+ if (err)
+ return -1;
+
+ len = sysfs_read_data_subst(desc->vol_type_path, &buf1[0],
+ 10, 2, devn, vol_id);
+ if (len == -1)
+ return -1;
+
+ if (buf1[len - 1] != '\n') {
+ ubi_err("bad volume type");
+ return UBI_EBUG;
+ }
+
+ if (!strncmp(&buf1[0], "static", sizeof("static") - 1)) {
+ req->type = UBI_STATIC_VOLUME;
+ } else if (!strncmp(&buf1[0], "dynamic", sizeof("dynamic") - 1)) {
+ req->type = UBI_DYNAMIC_VOLUME;
+ } else {
+ ubi_err("bad type %s", &buf1[0]);
+ return -1;
+ }
+
+ len = sysfs_read_data_subst(desc->vol_name_path, &buf2[0],
+ desc->ubi.nlen_max, 2, devn, vol_id);
+ if (len == -1)
+ return -1;
+
+ if (buf2[len - 1] != '\n') {
+ ubi_err("bad volume name");
+ return UBI_EBUG;
+ }
+
+ req->name = malloc(len);
+ if (!req->name) {
+ ubi_err("cannot allocate memory");
+ return -1;
+ }
+
+ memcpy(req->name, &buf2[0], len - 1);
+ req->name[len - 1] = '\0';
+
+ return 0;
+}
+
+/**
+ * ubi_cdev_open - open a UBI device
+ *
+ * @desc UBI library descriptor
+ * @devn Number of UBI device to open
+ * @flags Flags to pass to open()
+ *
+ * This function opens a UBI device by number and returns a file
+ * descriptor. In case of an error %-1 is returned and errno is set
+ * appropriately.
+ */
+static int
+ubi_cdev_open(ubi_lib_t desc, int devn, int flags)
+{
+ char *buf;
+ int fd;
+
+ ubi_dbg("desc=%p, devn=%d, flags=%08x\n", desc, devn, flags);
+
+ if (desc == NULL) {
+ ubi_err("desc is NULL\n");
+ return -1;
+ }
+ if (desc->vol_cdev_path_len == 0) {
+ ubi_err("path_len == 0\n");
+ return -1;
+ }
+ buf = malloc(desc->cdev_path_len);
+
+ sprintf(buf, desc->cdev_path, devn);
+
+ fd = open(buf, flags);
+ if (fd == -1)
+ ubi_dbg("cannot open %s", buf);
+
+ free(buf);
+ return fd;
+}
+
+/**
+ * ubi_cdev_close - close a UBI device
+ *
+ * @dev_fd file descriptor of UBI device to close
+ *
+ * This function closes the given UBI device.
+ */
+static int
+ubi_cdev_close(int dev_fd)
+{
+ return close(dev_fd);
+}
+
+/**
+ * @size is now in bytes.
+ */
+int
+ubi_mkvol(ubi_lib_t desc, int devn, int vol_id, int vol_type,
+ long long bytes, int alignment, const char *name)
+{
+ int fd;
+ int err;
+ struct ubi_mkvol_req req;
+
+ if ((fd = ubi_cdev_open(desc, devn, O_RDWR)) == -1)
+ return -1;
+
+ req.vol_id = vol_id;
+ req.bytes = bytes;
+ req.vol_type = vol_type;
+ req.alignment = alignment;
+ req.name_len = strlen(name);
+ req.name = name;
+
+ /* printf("DBG: %s(vol_id=%d, bytes=%lld, type=%d, alig=%d, nlen=%d, "
+ "name=%s)\n", __func__, vol_id, bytes, vol_type, alignment,
+ strlen(name), name);*/
+
+ err = ioctl(fd, UBI_IOCMKVOL, &req);
+ if (err < 0) {
+ ubi_err("ioctl returned %d errno=%d\n", err, errno);
+ goto out_close;
+ }
+
+ ubi_dbg("created volume %d, size %lld, name \"%s\" "
+ "at UBI dev %d\n", vol_id, bytes, name, devn);
+
+ close(fd);
+ return err;
+ out_close:
+ ubi_cdev_close(fd);
+ return err;
+}
+
+int
+ubi_rmvol(ubi_lib_t desc, int devn, int vol_id)
+{
+ int fd;
+ int err;
+
+ if ((fd = ubi_cdev_open(desc, devn, O_RDWR)) == -1)
+ return -1;
+
+ err = ioctl(fd, UBI_IOCRMVOL, &vol_id);
+ if (err < 0)
+ goto out_close;
+
+ ubi_dbg("removed volume %d", vol_id);
+
+ out_close:
+ ubi_cdev_close(fd);
+ return err;
+}
+
+int
+ubi_get_info(ubi_lib_t desc, struct ubi_info *ubi)
+{
+ memcpy(ubi, &desc->ubi, sizeof(struct ubi_info));
+ return 0;
+}
+
+
+int
+ubi_vol_open(ubi_lib_t desc, int devn, int vol_id, int flags)
+{
+ char *buf;
+ int fd;
+
+ ubi_dbg("desc=%p, devn=%d, vol_id=%d, flags=%08x\n",
+ desc, devn, vol_id, flags);
+
+ if (desc == NULL) {
+ ubi_err("desc is NULL\n");
+ return -1;
+ }
+ if (desc->vol_cdev_path_len == 0) {
+ ubi_err("path_len == 0\n");
+ return -1;
+ }
+ buf = malloc(desc->cdev_path_len);
+
+ sprintf(buf, desc->vol_cdev_path, devn, vol_id);
+
+ fd = open(buf, flags);
+ if (fd == -1)
+ ubi_dbg("cannot open %s", buf);
+
+ free(buf);
+ return fd;
+}
+
+int
+ubi_vol_close(int vol_fd)
+{
+ return close(vol_fd);
+}
+
+
+int
+ubi_vol_update(int vol_fd, unsigned long long bytes)
+{
+ int err;
+
+ err = ioctl(vol_fd, UBI_IOCVOLUP, &bytes);
+ if (err) {
+ ubi_err("%s failure calling update ioctl\n"
+ " IOCTL(%08x) err=%d errno=%d\n",
+ __func__, UBI_IOCVOLUP, err, errno);
+ }
+ return err;
+}
+
+FILE *
+ubi_vol_fopen_read(ubi_lib_t desc, int devn, uint32_t vol_id)
+{
+ FILE *fp;
+ int fd;
+
+ fd = ubi_vol_open(desc, devn, vol_id, O_RDONLY);
+ if (fd == -1)
+ return NULL;
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL)
+ ubi_vol_close(fd);
+
+ return fp;
+}
+
+FILE *
+ubi_vol_fopen_update(ubi_lib_t desc, int devn, uint32_t vol_id,
+ unsigned long long bytes)
+{
+ FILE *fp;
+ int fd;
+ int err;
+
+ fd = ubi_vol_open(desc, devn, vol_id, O_RDWR);
+ if (fd == -1)
+ return NULL;
+
+ fp = fdopen(fd, "r+");
+ if (fp == NULL) {
+ printf("DBG: %s(errno=%d)\n", __func__, errno);
+ ubi_vol_close(fd);
+ return NULL;
+ }
+ err = ubi_vol_update(fd, bytes);
+ if (err < 0) {
+ printf("DBG: %s() fd=%d err=%d\n", __func__, fd, err);
+ fclose(fp);
+ return NULL;
+ }
+ return fp;
+}
+
+int
+ubi_vol_get_used_bytes(int vol_fd, unsigned long long *bytes)
+{
+ off_t res;
+
+ res = lseek(vol_fd, 0, SEEK_END);
+ if (res == (off_t)-1)
+ return -1;
+ *bytes = (unsigned long long) res;
+ res = lseek(vol_fd, 0, SEEK_SET);
+ return res == (off_t)-1 ? -1 : 0;
+}
diff --git a/ubi-utils/src/libubi/libubi_int.h b/ubi-utils/src/libubi/libubi_int.h
new file mode 100644
index 0000000..1640010
--- /dev/null
+++ b/ubi-utils/src/libubi/libubi_int.h
@@ -0,0 +1,119 @@
+#ifndef __UBI_INT_H__
+#define __UBI_INT_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * UBI (Unsorted Block Images) library.
+ *
+ * Author: Artem B. Bityutskiy
+ */
+
+/*
+ * Enable/disable UBI library debugging messages.
+ */
+#undef UBILIB_DEBUG
+
+/*
+ * UBI library error message.
+ */
+#define ubi_err(fmt, ...) do { \
+ fprintf(stderr, "UBI Library Error at %s: ", __func__); \
+ fprintf(stderr, fmt, ##__VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ } while(0)
+
+#ifdef UBILIB_DEBUG
+#define ubi_dbg(fmt, ...) do { \
+ fprintf(stderr, "UBI Debug: %s: ", __func__); \
+ fprintf(stderr, fmt, ##__VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ } while(0)
+
+#else
+#define ubi_dbg(fmt, ...)
+#endif
+
+/**
+ * SYSFS Entries.
+ *
+ * @def UBI_ROOT
+ * @brief Name of the root UBI directory in sysfs.
+ *
+ * @def UBI_NLEN_MAX
+ * @brief Name of syfs file containing the maximum UBI volume name length.
+ *
+ * @def UBI_VERSION
+ * @brief Name of sysfs file containing UBI version.
+ *
+ * @def UBI_WEAR
+ * @brief Name of sysfs file containing wear level of an UBI device.
+ *
+ * @def UBI_VOL_COUNT
+ * @brief Name of sysfs file contaning the of volume on an UBI device
+ *
+ * @def UBI_TOT_EBS
+ * @brief Name of sysfs file contaning the total number of
+ * eraseblocks on an UBI device.
+ *
+ * @def UBI_AVAIL_EBS
+ * @brief Name of sysfs file contaning the number of unused eraseblocks on
+ * an UBI device.
+ *
+ * @def UBI_EB_SIZE
+ * @brief Name of sysfs file containing size of UBI eraseblocks.
+ *
+ * @def UBI_NUMS
+ * @brief Name of sysfs file containing major and minor numbers
+ * of an UBI device or an UBI volume device.
+ *
+ * @def UBI_VBYTES
+ * @brief Name of sysfs file containing size of an UBI volume device in
+ * bytes.
+ *
+ * @def UBI_VEBS
+ * @brief Name of sysfs file containing size of an UBI volume device in
+ * eraseblocks.
+ *
+ * @def UBI_VTYPE
+ * @brief Name of sysfs file containing type of an UBI volume device.
+ *
+ * @def UBI_VNAME
+ * @brief Name of sysfs file containing name of an UBI volume device.
+ **/
+#define UBI_ROOT "ubi"
+#define UBI_NLEN_MAX "volume_name_max"
+#define UBI_VERSION "version"
+#define UBI_WEAR "wear"
+#define UBI_VOL_COUNT "volumes_count"
+#define UBI_TOT_EBS "total_eraseblocks"
+#define UBI_AVAIL_EBS "avail_eraseblocks"
+#define UBI_EB_SIZE "eraseblock_size"
+#define UBI_NUMS "dev"
+#define UBI_VBYTES "bytes"
+#define UBI_VEBS "eraseblocks"
+#define UBI_VTYPE "type"
+#define UBI_VNAME "name"
+
+#define UBI_CDEV_PATH "/dev/ubi%d"
+#define UBI_VOL_CDEV_PATH "/dev/ubi%d_%d"
+#define UBI_SYSFS_ROOT "/sys/class"
+
+#define UBI_MAX_ID_SIZE 9
+
+#endif /* !__UBI_INT_H__ */
diff --git a/ubi-utils/src/libubi/libubi_sysfs.c b/ubi-utils/src/libubi/libubi_sysfs.c
new file mode 100644
index 0000000..f7ecebc
--- /dev/null
+++ b/ubi-utils/src/libubi/libubi_sysfs.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * UBI (Unsorted Block Images) library.
+ *
+ * Author: Artem B. Bityutskiy
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "libubi_int.h"
+
+int
+sysfs_read_data(const char *file, void *buf, int len)
+{
+ int fd;
+ ssize_t rd;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ ubi_err("cannot open file %s", file);
+ return -1;
+ }
+
+ rd = read(fd, buf, len);
+ if (rd == -1)
+ ubi_err("cannot read file %s", file);
+
+ close(fd);
+
+ return rd;
+}
+
+int
+sysfs_read_data_subst(const char *patt, void *buf, int len, int n, ...)
+{
+ va_list args;
+ char buf1[strlen(patt) + 20 * n];
+
+ va_start(args, n);
+ vsprintf(&buf1[0], patt, args);
+ va_end(args);
+
+ return sysfs_read_data(&buf1[0], buf, len);
+}
+
+int
+sysfs_read_dev(const char *file, unsigned int *major, unsigned int *minor)
+{
+ int fd;
+ int ret;
+ ssize_t rd;
+ int err = -1;
+ char buf[40];
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ ubi_err("cannot open file %s", file);
+ return -1;
+ }
+
+ rd = read(fd, &buf[0], 20);
+ if (rd == -1) {
+ ubi_err("cannot read file %s", file);
+ goto error;
+ }
+ if (rd < 4) {
+ ubi_err("bad contents of file %s:", file);
+ goto error;
+ }
+
+ err = -1;
+ if (buf[rd -1] != '\n') {
+ ubi_err("bad contents of file %s", file);
+ goto error;
+ }
+
+ ret = sscanf(&buf[0], "%d:%d\n", major, minor);
+ if (ret != 2) {
+ ubi_err("bad contents of file %s", file);
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ close(fd);
+
+ return err;
+}
+
+int
+sysfs_read_dev_subst(const char *patt, unsigned int *major,
+ unsigned int *minor, int n, ...)
+{
+ va_list args;
+ char buf[strlen(patt) + 20 * n];
+
+ va_start(args, n);
+ vsprintf(&buf[0], patt, args);
+ va_end(args);
+
+ return sysfs_read_dev(&buf[0], major, minor);
+}
+
+static int
+sysfs_read_ull(const char *file, unsigned long long *num)
+{
+ return 0;
+}
+
+int
+sysfs_read_ull_subst(const char *patt, unsigned long long *num, int n, ...)
+{
+ va_list args;
+ char buf[strlen(patt) + 20 * n];
+
+ va_start(args, n);
+ vsprintf(&buf[0], patt, args);
+ va_end(args);
+
+ return sysfs_read_ull(&buf[0], num);
+}
+
+static int
+sysfs_read_uint(const char *file, unsigned int *num)
+{
+ return 0;
+}
+
+int
+sysfs_read_uint_subst(const char *patt, unsigned int *num, int n, ...)
+{
+ va_list args;
+ char buf[strlen(patt) + 20 * n];
+
+ va_start(args, n);
+ vsprintf(&buf[0], patt, args);
+ va_end(args);
+
+ return sysfs_read_uint(&buf[0], num);
+}
+
+int
+sysfs_read_ll(const char *file, long long *num)
+{
+ int fd;
+ ssize_t rd;
+ int err = -1;
+ char buf[20];
+ char *endptr;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, &buf[0], 20);
+ if (rd == -1)
+ goto out;
+
+ if (rd < 2) {
+ ubi_err("bad contents in file %s: \"%c%c...\"",
+ file, buf[0], buf[1]);
+ goto out_errno;
+ }
+
+ *num = strtoll(&buf[0], &endptr, 10);
+ if (endptr == &buf[0] || *endptr != '\n') {
+ ubi_err("bad contents in file %s: \"%c%c...\"",
+ file, buf[0], buf[1]);
+ goto out_errno;
+ }
+
+ if (*num < 0) {
+ ubi_err("bad number in file %s: %lld", file, *num);
+ goto out_errno;
+ }
+
+ err = 0;
+
+out_errno:
+ errno = EINVAL;
+
+out:
+ close(fd);
+ return err;
+}
+
+int
+sysfs_read_int(const char *file, int *num)
+{
+ int err;
+ long long res = 0;
+
+ err = sysfs_read_ll(file, &res);
+ if (err)
+ return err;
+
+ if (res < 0 || res > INT_MAX) {
+ ubi_err("bad number in file %s: %lld", file, res);
+ errno = EINVAL;
+ return -1;
+ }
+
+ *num = res;
+ return 0;
+}
diff --git a/ubi-utils/src/libubi/libubi_sysfs.h b/ubi-utils/src/libubi/libubi_sysfs.h
new file mode 100644
index 0000000..2fb6072
--- /dev/null
+++ b/ubi-utils/src/libubi/libubi_sysfs.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * UBI (Unsorted Block Images) library.
+ *
+ * Author: Artem B. Bityutskiy
+ */
+
+/**
+ * sysfs_read_data - read data from a sysfs file.
+ *
+ * @file path to the file to read from
+ * @buf furrer where to store read data
+ * @len length of provided buffer @buf
+ *
+ * This function returns the number of read bytes or -1 in case of error.
+ */
+int sysfs_read_data(const char *file, void *buf, int len);
+
+/**
+ * sysfs_read_data_subst - form path to a sysfs file and read data from it.
+ *
+ * @patt path to the file to read from
+ * @buf furrer where to store read data
+ * @len length of provided buffer @buf
+ * @n number of parameters to substitute to @patt
+ *
+ * This function forms path to a sysfs file by means of substituting parameters
+ * to @patt and then reads @len bytes from this file and stores the read data
+ * to @buf. This function returns the number of read bytes or -1 in case of
+ * error.
+ */
+int sysfs_read_data_subst(const char *patt, void *buf, int len, int n, ...);
+
+/**
+ * sysfs_read_dev - read major and minor number from a sysfs file.
+ *
+ * @file path to the file to read from
+ * @major major number is returned here
+ * @minor minor number is returned here
+ */
+int sysfs_read_dev(const char *file, unsigned int *major,
+ unsigned int *minor);
+/**
+ * sysfs_read_dev_subst - for path to a file and read major and minor number
+ * from it.
+ *
+ * @patt pattern of the path to the file to read from
+ * @major major number is returned here
+ * @minor minor number is returned here
+ * @n number of arguments to substitute
+ *
+ * This function substitures arguments to the @patt file path pattern and reads
+ * major and minor numbers from the resulting file.
+ */
+int sysfs_read_dev_subst(const char *patt, unsigned int *major,
+ unsigned int *minor, int n, ...);
+
+/**
+ * sysfs_read_ull_subst - form path to a sysfs file and read an unsigned long
+ * long value from there.
+ *
+ * @patt pattern of file path
+ * @num the read value is returned here
+ * @n number of parameters to substitute
+ *
+ *
+ * This function first forms the path to a sysfs file by means of substituting
+ * passed parameters to the @patt string, and then read an 'unsigned long long'
+ * value from this file.
+ */
+int sysfs_read_ull_subst(const char *patt, unsigned long long *num,
+ int n, ...);
+
+/**
+ * sysfs_read_uint_subst - the same as 'sysfs_read_uint_subst()' but reads an
+ * unsigned int value.
+ */
+int sysfs_read_uint_subst(const char *patt, unsigned int *num,
+ int n, ...);
+
+/**
+ * sysfs_read_ll - read a long long integer from an UBI sysfs file.
+ *
+ * @file file name from where to read
+ * @num the result is returned here
+ */
+int sysfs_read_ll(const char *file, long long *num);
+
+/**
+ * sysfs_read_int - the same as 'sysfs_read_ll()' but reads an 'int' value.
+ */
+int sysfs_read_int(const char *file, int *num);