get_devname.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Support functions for mounting devices by label/uuid
  4. *
  5. * Copyright (C) 2006 by Jason Schoon <floydpink@gmail.com>
  6. * Some portions cribbed from e2fsprogs, util-linux, dosfstools
  7. *
  8. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  9. */
  10. //kbuild:lib-$(CONFIG_BLKID) += get_devname.o
  11. //kbuild:lib-$(CONFIG_FINDFS) += get_devname.o
  12. //kbuild:lib-$(CONFIG_FEATURE_MOUNT_LABEL) += get_devname.o
  13. //kbuild:lib-$(CONFIG_FEATURE_SWAPONOFF_LABEL) += get_devname.o
  14. #include <sys/mount.h> /* BLKGETSIZE64 */
  15. #if !defined(BLKGETSIZE64)
  16. # define BLKGETSIZE64 _IOR(0x12,114,size_t)
  17. #endif
  18. #include "volume_id_internal.h"
  19. static struct uuidCache_s {
  20. struct uuidCache_s *next;
  21. // int major, minor;
  22. char *device;
  23. char *label;
  24. char *uc_uuid; /* prefix makes it easier to grep for */
  25. IF_FEATURE_BLKID_TYPE(const char *type;)
  26. } *uuidCache;
  27. #if !ENABLE_FEATURE_BLKID_TYPE
  28. #define get_label_uuid(fd, label, uuid, type) \
  29. get_label_uuid(fd, label, uuid)
  30. #define uuidcache_addentry(device, label, uuid, type) \
  31. uuidcache_addentry(device, label, uuid)
  32. #endif
  33. /* Returns !0 on error.
  34. * Otherwise, returns malloc'ed strings for label and uuid
  35. * (and they can't be NULL, although they can be "").
  36. * NB: closes fd. */
  37. static int
  38. get_label_uuid(int fd, char **label, char **uuid, const char **type)
  39. {
  40. int rv = 1;
  41. uint64_t size;
  42. struct volume_id *vid;
  43. /* fd is owned by vid now */
  44. vid = volume_id_open_node(fd);
  45. if (ioctl(/*vid->*/fd, BLKGETSIZE64, &size) != 0)
  46. size = 0;
  47. if (volume_id_probe_all(vid, /*0,*/ size) != 0)
  48. goto ret;
  49. if (vid->label[0] != '\0' || vid->uuid[0] != '\0'
  50. #if ENABLE_FEATURE_BLKID_TYPE
  51. || vid->type != NULL
  52. #endif
  53. ) {
  54. *label = xstrndup(vid->label, sizeof(vid->label));
  55. *uuid = xstrndup(vid->uuid, sizeof(vid->uuid));
  56. #if ENABLE_FEATURE_BLKID_TYPE
  57. *type = vid->type;
  58. dbg("found label '%s', uuid '%s', type '%s'", *label, *uuid, *type);
  59. #else
  60. dbg("found label '%s', uuid '%s'", *label, *uuid);
  61. #endif
  62. rv = 0;
  63. }
  64. ret:
  65. free_volume_id(vid); /* also closes fd */
  66. return rv;
  67. }
  68. /* NB: we take ownership of (malloc'ed) label and uuid */
  69. static void
  70. uuidcache_addentry(char *device, /*int major, int minor,*/ char *label, char *uuid, const char *type)
  71. {
  72. struct uuidCache_s *last;
  73. if (!uuidCache) {
  74. last = uuidCache = xzalloc(sizeof(*uuidCache));
  75. } else {
  76. for (last = uuidCache; last->next; last = last->next)
  77. continue;
  78. last->next = xzalloc(sizeof(*uuidCache));
  79. last = last->next;
  80. }
  81. /*last->next = NULL; - xzalloc did it*/
  82. // last->major = major;
  83. // last->minor = minor;
  84. last->device = device;
  85. last->label = label;
  86. last->uc_uuid = uuid;
  87. IF_FEATURE_BLKID_TYPE(last->type = type;)
  88. }
  89. /* If get_label_uuid() on device_name returns success,
  90. * add a cache entry for this device.
  91. * If device node does not exist, it will be temporarily created. */
  92. static int FAST_FUNC
  93. uuidcache_check_device(struct recursive_state *state UNUSED_PARAM,
  94. const char *device,
  95. struct stat *statbuf)
  96. {
  97. /* note: this check rejects links to devices, among other nodes */
  98. if (!S_ISBLK(statbuf->st_mode)
  99. #if ENABLE_FEATURE_VOLUMEID_UBIFS
  100. && !(S_ISCHR(statbuf->st_mode) && strncmp(bb_basename(device), "ubi", 3) == 0)
  101. #endif
  102. )
  103. return TRUE;
  104. /* Users report that mucking with floppies (especially non-present
  105. * ones) is significant PITA. This is a horribly dirty hack,
  106. * but it is very useful in real world.
  107. * If this will ever need to be enabled, consider using O_NONBLOCK.
  108. */
  109. if (major(statbuf->st_rdev) == 2)
  110. return TRUE;
  111. add_to_uuid_cache(device);
  112. return TRUE;
  113. }
  114. static struct uuidCache_s*
  115. uuidcache_init(int scan_devices)
  116. {
  117. dbg("DBG: uuidCache=%x, uuidCache");
  118. if (uuidCache)
  119. return uuidCache;
  120. /* We were scanning /proc/partitions
  121. * and /proc/sys/dev/cdrom/info here.
  122. * Missed volume managers. I see that "standard" blkid uses these:
  123. * /dev/mapper/control
  124. * /proc/devices
  125. * /proc/evms/volumes
  126. * /proc/lvm/VGs
  127. * This is unacceptably complex. Let's just scan /dev.
  128. * (Maybe add scanning of /sys/block/XXX/dev for devices
  129. * somehow not having their /dev/XXX entries created?) */
  130. if (scan_devices) {
  131. recursive_action("/dev", ACTION_RECURSE,
  132. uuidcache_check_device, /* file_action */
  133. NULL, /* dir_action */
  134. NULL /* userData */
  135. );
  136. }
  137. return uuidCache;
  138. }
  139. #define UUID 1
  140. #define VOL 2
  141. #ifdef UNUSED
  142. static char *
  143. get_spec_by_x(int n, const char *t, int *majorPtr, int *minorPtr)
  144. {
  145. struct uuidCache_s *uc;
  146. uc = uuidcache_init(/*scan_devices:*/ 1);
  147. while (uc) {
  148. switch (n) {
  149. case UUID:
  150. if (strcmp(t, uc->uc_uuid) == 0) {
  151. *majorPtr = uc->major;
  152. *minorPtr = uc->minor;
  153. return uc->device;
  154. }
  155. break;
  156. case VOL:
  157. if (strcmp(t, uc->label) == 0) {
  158. *majorPtr = uc->major;
  159. *minorPtr = uc->minor;
  160. return uc->device;
  161. }
  162. break;
  163. }
  164. uc = uc->next;
  165. }
  166. return NULL;
  167. }
  168. static unsigned char
  169. fromhex(char c)
  170. {
  171. if (isdigit(c))
  172. return (c - '0');
  173. return ((c|0x20) - 'a' + 10);
  174. }
  175. static char *
  176. get_spec_by_uuid(const char *s, int *major, int *minor)
  177. {
  178. unsigned char uuid[16];
  179. int i;
  180. if (strlen(s) != 36 || s[8] != '-' || s[13] != '-'
  181. || s[18] != '-' || s[23] != '-'
  182. ) {
  183. goto bad_uuid;
  184. }
  185. for (i = 0; i < 16; i++) {
  186. if (*s == '-')
  187. s++;
  188. if (!isxdigit(s[0]) || !isxdigit(s[1]))
  189. goto bad_uuid;
  190. uuid[i] = ((fromhex(s[0]) << 4) | fromhex(s[1]));
  191. s += 2;
  192. }
  193. return get_spec_by_x(UUID, (char *)uuid, major, minor);
  194. bad_uuid:
  195. fprintf(stderr, _("mount: bad UUID"));
  196. return 0;
  197. }
  198. static char *
  199. get_spec_by_volume_label(const char *s, int *major, int *minor)
  200. {
  201. return get_spec_by_x(VOL, s, major, minor);
  202. }
  203. #endif // UNUSED
  204. /* Used by blkid */
  205. void display_uuid_cache(int scan_devices)
  206. {
  207. struct uuidCache_s *uc;
  208. uc = uuidcache_init(scan_devices);
  209. while (uc) {
  210. printf("%s:", uc->device);
  211. if (uc->label[0])
  212. printf(" LABEL=\"%s\"", uc->label);
  213. if (uc->uc_uuid[0])
  214. printf(" UUID=\"%s\"", uc->uc_uuid);
  215. #if ENABLE_FEATURE_BLKID_TYPE
  216. if (uc->type)
  217. printf(" TYPE=\"%s\"", uc->type);
  218. #endif
  219. bb_putchar('\n');
  220. uc = uc->next;
  221. }
  222. }
  223. int add_to_uuid_cache(const char *device)
  224. {
  225. char *uuid = uuid; /* for compiler */
  226. char *label = label;
  227. #if ENABLE_FEATURE_BLKID_TYPE
  228. const char *type = type;
  229. #endif
  230. int fd;
  231. fd = open(device, O_RDONLY);
  232. if (fd < 0)
  233. return 0;
  234. /* get_label_uuid() closes fd in all cases (success & failure) */
  235. if (get_label_uuid(fd, &label, &uuid, &type) == 0) {
  236. /* uuidcache_addentry() takes ownership of all four params */
  237. uuidcache_addentry(xstrdup(device), /*ma, mi,*/ label, uuid, type);
  238. return 1;
  239. }
  240. return 0;
  241. }
  242. /* Used by mount and findfs */
  243. char *get_devname_from_label(const char *spec)
  244. {
  245. struct uuidCache_s *uc;
  246. uc = uuidcache_init(/*scan_devices:*/ 1);
  247. while (uc) {
  248. if (uc->label[0] && strcmp(spec, uc->label) == 0) {
  249. return xstrdup(uc->device);
  250. }
  251. uc = uc->next;
  252. }
  253. return NULL;
  254. }
  255. char *get_devname_from_uuid(const char *spec)
  256. {
  257. struct uuidCache_s *uc;
  258. uc = uuidcache_init(/*scan_devices:*/ 1);
  259. while (uc) {
  260. /* case of hex numbers doesn't matter */
  261. if (strcasecmp(spec, uc->uc_uuid) == 0) {
  262. return xstrdup(uc->device);
  263. }
  264. uc = uc->next;
  265. }
  266. return NULL;
  267. }
  268. int resolve_mount_spec(char **fsname)
  269. {
  270. char *tmp = *fsname;
  271. if (is_prefixed_with(*fsname, "UUID="))
  272. tmp = get_devname_from_uuid(*fsname + 5);
  273. else if (is_prefixed_with(*fsname, "LABEL="))
  274. tmp = get_devname_from_label(*fsname + 6);
  275. if (tmp == *fsname)
  276. return 0; /* no UUID= or LABEL= prefix found */
  277. if (tmp)
  278. *fsname = tmp;
  279. return 1;
  280. }