libfstools: query drivers by priority
[project/fstools.git] / libfstools / ubi.c
1 /*
2 * Copyright (C) 2014 Daniel Golle <daniel@makrotopia.org>
3 *
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
7 *
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.
12 */
13
14 #include "common.h"
15
16 /* fit for UBI_MAX_VOLUME_NAME and sysfs path lengths */
17 #define BUFLEN 128
18
19 /* could use libubi-tiny instead, but already had the code directly reading
20 * from sysfs */
21 const char *const ubi_dir_name = "/sys/class/ubi";
22
23 struct ubi_volume {
24 struct volume v;
25 int ubi_num;
26 int ubi_volid;
27 };
28
29 static struct driver ubi_driver;
30
31 static unsigned int
32 test_open(char *filename)
33 {
34 FILE *f;
35
36 f = fopen(filename, "r");
37 if (!f)
38 return 0;
39
40 fclose(f);
41 return 1;
42 }
43
44 static int ubi_volume_init(struct volume *v)
45 {
46 struct ubi_volume *p = container_of(v, struct ubi_volume, v);
47 char voldir[BUFLEN], voldev[BUFLEN], volname[BUFLEN];
48 unsigned int volsize;
49
50 snprintf(voldir, sizeof(voldir), "%s/ubi%u_%u",
51 ubi_dir_name, p->ubi_num, p->ubi_volid);
52
53 snprintf(voldev, sizeof(voldev), "/dev/ubi%u_%u",
54 p->ubi_num, p->ubi_volid);
55
56 if (!read_string_from_file(voldir, "name", volname, sizeof(volname)))
57 return -1;
58
59 if (read_uint_from_file(voldir, "data_bytes", &volsize))
60 return -1;
61
62 v->name = volname;
63 v->type = UBIVOLUME;
64 v->size = volsize;
65 v->blk = strdup(voldev);
66
67 return 0;
68 }
69
70 static struct volume *ubi_volume_match(char *name, int ubi_num, int volid)
71 {
72 char voldir[BUFLEN], volblkdev[BUFLEN], volname[BUFLEN];
73 struct ubi_volume *p;
74
75 snprintf(voldir, sizeof(voldir), "%s/ubi%u_%u",
76 ubi_dir_name, ubi_num, volid);
77
78 snprintf(volblkdev, sizeof(volblkdev), "/dev/ubiblock%u_%u",
79 ubi_num, volid);
80
81 /* skip if ubiblock device exists */
82 if (test_open(volblkdev))
83 return NULL;
84
85 /* todo: skip existing gluebi device for legacy support */
86
87 if (!read_string_from_file(voldir, "name", volname, sizeof(volname))) {
88 ULOG_ERR("Couldn't read %s/name\n", voldir);
89 return NULL;
90 }
91
92 if (strcmp(name, volname))
93 return NULL;
94
95 p = calloc(1, sizeof(struct ubi_volume));
96 if (!p)
97 return NULL;
98
99 p->v.drv = &ubi_driver;
100 p->ubi_num = ubi_num;
101 p->ubi_volid = volid;
102
103 return &p->v;
104 }
105
106 static struct volume *ubi_part_match(char *name, unsigned int ubi_num)
107 {
108 DIR *ubi_dir;
109 struct dirent *ubi_dirent;
110 unsigned int volid;
111 char devdir[BUFLEN];
112 struct volume *ret = NULL;
113
114 snprintf(devdir, sizeof(devdir), "%s/ubi%u",
115 ubi_dir_name, ubi_num);
116
117 ubi_dir = opendir(devdir);
118 if (!ubi_dir)
119 return ret;
120
121 while ((ubi_dirent = readdir(ubi_dir)) != NULL) {
122 if (strncmp(ubi_dirent->d_name, "ubi", 3))
123 continue;
124
125 if (sscanf(ubi_dirent->d_name, "ubi%*u_%u", &volid) != 1)
126 continue;
127
128 ret = ubi_volume_match(name, ubi_num, volid);
129 if (ret)
130 break;
131 }
132 closedir(ubi_dir);
133
134 return ret;
135 }
136
137 static struct volume *ubi_volume_find(char *name)
138 {
139 struct volume *ret = NULL;
140 DIR *ubi_dir;
141 struct dirent *ubi_dirent;
142 unsigned int ubi_num;
143
144 if (find_filesystem("ubifs"))
145 return ret;
146
147 ubi_dir = opendir(ubi_dir_name);
148 /* check for os ubi support */
149 if (!ubi_dir)
150 return ret;
151
152 /* probe ubi devices and volumes */
153 while ((ubi_dirent = readdir(ubi_dir)) != NULL) {
154 if (ubi_dirent->d_name[0] == '.')
155 continue;
156
157 sscanf(ubi_dirent->d_name, "ubi%u", &ubi_num);
158 ret = ubi_part_match(name, ubi_num);
159 if (ret)
160 break;
161 }
162 closedir(ubi_dir);
163 return ret;
164 }
165
166 static int ubi_volume_identify(struct volume *v)
167 {
168 /* Todo: use libblkid-tiny on the ubi chardev */
169 return FS_UBIFS;
170 }
171
172 static struct driver ubi_driver = {
173 .name = "ubi",
174 .priority = 20,
175 .find = ubi_volume_find,
176 .init = ubi_volume_init,
177 .identify = ubi_volume_identify,
178 };
179
180 DRIVER(ubi_driver);