devno.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * devno.c - find a particular device by its device number (major/minor)
  4. *
  5. * Copyright (C) 2000, 2001, 2003 Theodore Ts'o
  6. * Copyright (C) 2001 Andreas Dilger
  7. *
  8. * %Begin-Header%
  9. * This file may be redistributed under the terms of the
  10. * GNU Lesser General Public License.
  11. * %End-Header%
  12. */
  13. #include <stdio.h>
  14. #include <string.h>
  15. #ifdef HAVE_UNISTD_H
  16. #include <unistd.h>
  17. #endif
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #ifdef HAVE_SYS_TYPES_H
  21. #include <sys/types.h>
  22. #endif
  23. #include <sys/stat.h>
  24. #include <dirent.h>
  25. #ifdef HAVE_ERRNO_H
  26. #include <errno.h>
  27. #endif
  28. #ifdef HAVE_SYS_MKDEV_H
  29. #include <sys/mkdev.h>
  30. #endif
  31. #include "blkidP.h"
  32. struct dir_list {
  33. char *name;
  34. struct dir_list *next;
  35. };
  36. char *blkid_strndup(const char *s, int length)
  37. {
  38. char *ret;
  39. if (!s)
  40. return NULL;
  41. if (!length)
  42. length = strlen(s);
  43. ret = xmalloc(length + 1);
  44. strncpy(ret, s, length);
  45. ret[length] = '\0';
  46. return ret;
  47. }
  48. char *blkid_strdup(const char *s)
  49. {
  50. return blkid_strndup(s, 0);
  51. }
  52. /*
  53. * This function adds an entry to the directory list
  54. */
  55. static void add_to_dirlist(const char *name, struct dir_list **list)
  56. {
  57. struct dir_list *dp;
  58. dp = xmalloc(sizeof(struct dir_list));
  59. dp->name = blkid_strdup(name);
  60. dp->next = *list;
  61. *list = dp;
  62. }
  63. /*
  64. * This function frees a directory list
  65. */
  66. static void free_dirlist(struct dir_list **list)
  67. {
  68. struct dir_list *dp, *next;
  69. for (dp = *list; dp; dp = next) {
  70. next = dp->next;
  71. free(dp->name);
  72. free(dp);
  73. }
  74. *list = NULL;
  75. }
  76. static void scan_dir(char *dir_name, dev_t devno, struct dir_list **list,
  77. char **devname)
  78. {
  79. DIR *dir;
  80. struct dirent *dp;
  81. char path[1024];
  82. int dirlen;
  83. struct stat st;
  84. if ((dir = opendir(dir_name)) == NULL)
  85. return;
  86. dirlen = strlen(dir_name) + 2;
  87. while ((dp = readdir(dir)) != 0) {
  88. if (dirlen + strlen(dp->d_name) >= sizeof(path))
  89. continue;
  90. if (dp->d_name[0] == '.' &&
  91. ((dp->d_name[1] == 0) ||
  92. ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
  93. continue;
  94. sprintf(path, "%s/%s", dir_name, dp->d_name);
  95. if (stat(path, &st) < 0)
  96. continue;
  97. if (S_ISDIR(st.st_mode))
  98. add_to_dirlist(path, list);
  99. else if (S_ISBLK(st.st_mode) && st.st_rdev == devno) {
  100. *devname = blkid_strdup(path);
  101. DBG(DEBUG_DEVNO,
  102. printf("found 0x%llx at %s (%p)\n", devno,
  103. path, *devname));
  104. break;
  105. }
  106. }
  107. closedir(dir);
  108. return;
  109. }
  110. /* Directories where we will try to search for device numbers */
  111. const char *blkid_devdirs[] = { "/devices", "/devfs", "/dev", NULL };
  112. /*
  113. * This function finds the pathname to a block device with a given
  114. * device number. It returns a pointer to allocated memory to the
  115. * pathname on success, and NULL on failure.
  116. */
  117. char *blkid_devno_to_devname(dev_t devno)
  118. {
  119. struct dir_list *list = NULL, *new_list = NULL;
  120. char *devname = NULL;
  121. const char **dir;
  122. /*
  123. * Add the starting directories to search in reverse order of
  124. * importance, since we are using a stack...
  125. */
  126. for (dir = blkid_devdirs; *dir; dir++)
  127. add_to_dirlist(*dir, &list);
  128. while (list) {
  129. struct dir_list *current = list;
  130. list = list->next;
  131. DBG(DEBUG_DEVNO, printf("directory %s\n", current->name));
  132. scan_dir(current->name, devno, &new_list, &devname);
  133. free(current->name);
  134. free(current);
  135. if (devname)
  136. break;
  137. /*
  138. * If we're done checking at this level, descend to
  139. * the next level of subdirectories. (breadth-first)
  140. */
  141. if (list == NULL) {
  142. list = new_list;
  143. new_list = NULL;
  144. }
  145. }
  146. free_dirlist(&list);
  147. free_dirlist(&new_list);
  148. if (!devname) {
  149. DBG(DEBUG_DEVNO,
  150. printf("blkid: cannot find devno 0x%04lx\n",
  151. (unsigned long) devno));
  152. } else {
  153. DBG(DEBUG_DEVNO,
  154. printf("found devno 0x%04llx as %s\n", devno, devname));
  155. }
  156. return devname;
  157. }
  158. #ifdef TEST_PROGRAM
  159. int main(int argc, char** argv)
  160. {
  161. char *devname, *tmp;
  162. int major, minor;
  163. dev_t devno;
  164. const char *errmsg = "Cannot parse %s: %s\n";
  165. blkid_debug_mask = DEBUG_ALL;
  166. if ((argc != 2) && (argc != 3)) {
  167. fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n"
  168. "Resolve a device number to a device name\n",
  169. argv[0], argv[0]);
  170. exit(1);
  171. }
  172. if (argc == 2) {
  173. devno = strtoul(argv[1], &tmp, 0);
  174. if (*tmp) {
  175. fprintf(stderr, errmsg, "device number", argv[1]);
  176. exit(1);
  177. }
  178. } else {
  179. major = strtoul(argv[1], &tmp, 0);
  180. if (*tmp) {
  181. fprintf(stderr, errmsg, "major number", argv[1]);
  182. exit(1);
  183. }
  184. minor = strtoul(argv[2], &tmp, 0);
  185. if (*tmp) {
  186. fprintf(stderr, errmsg, "minor number", argv[2]);
  187. exit(1);
  188. }
  189. devno = makedev(major, minor);
  190. }
  191. printf("Looking for device 0x%04Lx\n", devno);
  192. devname = blkid_devno_to_devname(devno);
  193. free(devname);
  194. return 0;
  195. }
  196. #endif