* GNU General Public License for more details.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-
-#include "libfstools.h"
-#include "volume.h"
+#include "common.h"
/* fit for UBI_MAX_VOLUME_NAME and sysfs path lengths */
#define BUFLEN 128
/* could use libubi-tiny instead, but already had the code directly reading
* from sysfs */
-const char *const ubi_dir_name = "/sys/devices/virtual/ubi";
+const char *const ubi_dir_name = "/sys/class/ubi";
-struct ubi_priv {
+struct ubi_volume {
+ struct volume v;
int ubi_num;
int ubi_volid;
};
static struct driver ubi_driver;
-static int
-read_uint_from_file(char *dirname, char *filename, unsigned int *i)
-{
- FILE *f;
- char fname[BUFLEN];
- int ret = -1;
-
- snprintf(fname, sizeof(fname), "%s/%s", dirname, filename);
-
- f = fopen(fname, "r");
- if (!f)
- return ret;
-
- if (fscanf(f, "%u", i) == 1)
- ret = 0;
-
- fclose(f);
- return ret;
-}
-
-static char
-*read_string_from_file(char *dirname, char *filename)
-{
- FILE *f;
- char fname[BUFLEN];
- char buf[BUFLEN];
- int i;
-
- snprintf(fname, sizeof(fname), "%s/%s", dirname, filename);
-
- f = fopen(fname, "r");
- if (!f)
- return NULL;
-
- if (fgets(buf, sizeof(buf), f) == NULL)
- return NULL;
-
- fclose(f);
-
- /* make sure the string is \0 terminated */
- buf[sizeof(buf) - 1] = '\0';
-
- /* remove trailing whitespace */
- i = strlen(buf) - 1;
- while (i > 0 && buf[i] <= ' ')
- buf[i--] = '\0';
-
- return strdup(buf);
-}
-
static unsigned int
test_open(char *filename)
{
static int ubi_volume_init(struct volume *v)
{
- char voldir[BUFLEN], voldev[BUFLEN], *volname;
- struct ubi_priv *p;
+ struct ubi_volume *p = container_of(v, struct ubi_volume, v);
+ char voldir[BUFLEN], voldev[BUFLEN], volname[BUFLEN];
unsigned int volsize;
- p = (struct ubi_priv*)v->priv;
-
- snprintf(voldir, sizeof(voldir), "%s/ubi%u/ubi%u_%u",
- ubi_dir_name, p->ubi_num, p->ubi_num, p->ubi_volid);
+ snprintf(voldir, sizeof(voldir), "%s/ubi%u_%u",
+ ubi_dir_name, p->ubi_num, p->ubi_volid);
snprintf(voldev, sizeof(voldev), "/dev/ubi%u_%u",
p->ubi_num, p->ubi_volid);
- volname = read_string_from_file(voldir, "name");
- if (!volname)
+ if (!read_string_from_file(voldir, "name", volname, sizeof(volname)))
return -1;
if (read_uint_from_file(voldir, "data_bytes", &volsize))
return 0;
}
-static int ubi_volume_match(struct volume *v, char *name, int ubi_num, int volid)
+static struct volume *ubi_volume_match(char *name, int ubi_num, int volid)
{
- char voldir[BUFLEN], volblkdev[BUFLEN], *volname;
- struct ubi_priv *p;
+ char voldir[BUFLEN], volblkdev[BUFLEN], volname[BUFLEN];
+ struct ubi_volume *p;
- snprintf(voldir, sizeof(voldir), "%s/ubi%u/ubi%u_%u",
- ubi_dir_name, ubi_num, ubi_num, volid);
+ snprintf(voldir, sizeof(voldir), "%s/ubi%u_%u",
+ ubi_dir_name, ubi_num, volid);
snprintf(volblkdev, sizeof(volblkdev), "/dev/ubiblock%u_%u",
ubi_num, volid);
/* skip if ubiblock device exists */
if (test_open(volblkdev))
- return -1;
+ return NULL;
/* todo: skip existing gluebi device for legacy support */
- volname = read_string_from_file(voldir, "name");
+ if (!read_string_from_file(voldir, "name", volname, sizeof(volname))) {
+ ULOG_ERR("Couldn't read %s/name\n", voldir);
+ return NULL;
+ }
- if (strncmp(name, volname, strlen(volname) + 1))
- return -1;
+ if (strcmp(name, volname))
+ return NULL;
- p = calloc(1, sizeof(struct ubi_priv));
+ p = calloc(1, sizeof(struct ubi_volume));
if (!p)
- return -1;
+ return NULL;
- v->priv = p;
- v->drv = &ubi_driver;
+ p->v.drv = &ubi_driver;
p->ubi_num = ubi_num;
p->ubi_volid = volid;
- return ubi_volume_init(v);
+ return &p->v;
}
-static int ubi_part_match(struct volume *v, char *name, unsigned int ubi_num)
+static struct volume *ubi_part_match(char *name, unsigned int ubi_num)
{
- unsigned int i, volumes_count;
+ DIR *ubi_dir;
+ struct dirent *ubi_dirent;
+ unsigned int volid;
char devdir[BUFLEN];
+ struct volume *ret = NULL;
snprintf(devdir, sizeof(devdir), "%s/ubi%u",
ubi_dir_name, ubi_num);
- if (read_uint_from_file(devdir, "volumes_count", &volumes_count))
- return -1;
+ ubi_dir = opendir(devdir);
+ if (!ubi_dir)
+ return ret;
+
+ while ((ubi_dirent = readdir(ubi_dir)) != NULL) {
+ if (strncmp(ubi_dirent->d_name, "ubi", 3))
+ continue;
+
+ if (sscanf(ubi_dirent->d_name, "ubi%*u_%u", &volid) != 1)
+ continue;
- for (i=0;i<volumes_count;i++) {
- if (!ubi_volume_match(v, name, ubi_num, i)) {
- return 0;
- }
+ ret = ubi_volume_match(name, ubi_num, volid);
+ if (ret)
+ break;
}
+ closedir(ubi_dir);
- return -1;
+ return ret;
}
-static int ubi_volume_find(struct volume *v, char *name)
+static struct volume *ubi_volume_find(char *name)
{
+ struct volume *ret = NULL;
DIR *ubi_dir;
struct dirent *ubi_dirent;
unsigned int ubi_num;
- int ret = -1;
if (find_filesystem("ubifs"))
return ret;
continue;
sscanf(ubi_dirent->d_name, "ubi%u", &ubi_num);
- if (!ubi_part_match(v, name, ubi_num)) {
- ret = 0;
+ ret = ubi_part_match(name, ubi_num);
+ if (ret)
break;
- };
}
closedir(ubi_dir);
return ret;
static struct driver ubi_driver = {
.name = "ubi",
+ .priority = 20,
.find = ubi_volume_find,
.init = ubi_volume_init,
.identify = ubi_volume_identify,