get_devname.c 6.1 KB

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