devno.c 4.6 KB

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