2 * Copyright (C) 2014 Daniel Golle <daniel@makrotopia.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2.1
6 * as published by the Free Software Foundation
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
19 #include "libfstools.h"
22 /* fit for UBI_MAX_VOLUME_NAME and sysfs path lengths */
25 /* could use libubi-tiny instead, but already had the code directly reading
27 const char *const ubi_dir_name = "/sys/devices/virtual/ubi";
35 static struct driver ubi_driver;
38 read_uint_from_file(char *dirname, char *filename, unsigned int *i)
44 snprintf(fname, sizeof(fname), "%s/%s", dirname, filename);
46 f = fopen(fname, "r");
50 if (fscanf(f, "%u", i) == 1)
58 *read_string_from_file(char *dirname, char *filename)
65 snprintf(fname, sizeof(fname), "%s/%s", dirname, filename);
67 f = fopen(fname, "r");
71 if (fgets(buf, sizeof(buf), f) == NULL)
76 /* make sure the string is \0 terminated */
77 buf[sizeof(buf) - 1] = '\0';
79 /* remove trailing whitespace */
81 while (i > 0 && buf[i] <= ' ')
88 test_open(char *filename)
92 f = fopen(filename, "r");
100 static int ubi_volume_init(struct volume *v)
102 struct ubi_volume *p = container_of(v, struct ubi_volume, v);
103 char voldir[BUFLEN], voldev[BUFLEN], *volname;
104 unsigned int volsize;
106 snprintf(voldir, sizeof(voldir), "%s/ubi%u/ubi%u_%u",
107 ubi_dir_name, p->ubi_num, p->ubi_num, p->ubi_volid);
109 snprintf(voldev, sizeof(voldev), "/dev/ubi%u_%u",
110 p->ubi_num, p->ubi_volid);
112 volname = read_string_from_file(voldir, "name");
116 if (read_uint_from_file(voldir, "data_bytes", &volsize))
122 v->blk = strdup(voldev);
127 static struct volume *ubi_volume_match(char *name, int ubi_num, int volid)
129 char voldir[BUFLEN], volblkdev[BUFLEN], *volname;
130 struct ubi_volume *p;
132 snprintf(voldir, sizeof(voldir), "%s/ubi%u/ubi%u_%u",
133 ubi_dir_name, ubi_num, ubi_num, volid);
135 snprintf(volblkdev, sizeof(volblkdev), "/dev/ubiblock%u_%u",
138 /* skip if ubiblock device exists */
139 if (test_open(volblkdev))
142 /* todo: skip existing gluebi device for legacy support */
144 volname = read_string_from_file(voldir, "name");
146 ULOG_ERR("Couldn't read %s/name\n", voldir);
150 if (strcmp(name, volname))
153 p = calloc(1, sizeof(struct ubi_volume));
157 p->v.drv = &ubi_driver;
158 p->ubi_num = ubi_num;
159 p->ubi_volid = volid;
164 static struct volume *ubi_part_match(char *name, unsigned int ubi_num)
167 struct dirent *ubi_dirent;
170 struct volume *ret = NULL;
172 snprintf(devdir, sizeof(devdir), "%s/ubi%u",
173 ubi_dir_name, ubi_num);
175 ubi_dir = opendir(devdir);
179 while ((ubi_dirent = readdir(ubi_dir)) != NULL) {
180 if (strncmp(ubi_dirent->d_name, "ubi", 3))
183 if (sscanf(ubi_dirent->d_name, "ubi%*u_%u", &volid) != 1)
186 ret = ubi_volume_match(name, ubi_num, volid);
195 static struct volume *ubi_volume_find(char *name)
197 struct volume *ret = NULL;
199 struct dirent *ubi_dirent;
200 unsigned int ubi_num;
202 if (find_filesystem("ubifs"))
205 ubi_dir = opendir(ubi_dir_name);
206 /* check for os ubi support */
210 /* probe ubi devices and volumes */
211 while ((ubi_dirent = readdir(ubi_dir)) != NULL) {
212 if (ubi_dirent->d_name[0] == '.')
215 sscanf(ubi_dirent->d_name, "ubi%u", &ubi_num);
216 ret = ubi_part_match(name, ubi_num);
224 static int ubi_volume_identify(struct volume *v)
226 /* Todo: use libblkid-tiny on the ubi chardev */
230 static struct driver ubi_driver = {
232 .find = ubi_volume_find,
233 .init = ubi_volume_init,
234 .identify = ubi_volume_identify,