ubi.c 4.8 KB

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