get_devname.c 7.2 KB

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