blob: 2979280f7b7c6214cffa5e981eeac4df1bfa02b6 [file] [log] [blame]
Mike Frysinger38a33f92005-05-09 22:13:22 +00001/*
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
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <stdlib.h>
19#include <string.h>
20#if HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23#if HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#include <dirent.h>
27#if HAVE_ERRNO_H
28#include <errno.h>
29#endif
30#if HAVE_SYS_MKDEV_H
31#include <sys/mkdev.h>
32#endif
33
34#include "blkidP.h"
35
36struct dir_list {
37 char *name;
38 struct dir_list *next;
39};
40
41char *blkid_strndup(const char *s, int length)
42{
43 char *ret;
44
45 if (!s)
46 return NULL;
47
48 if (!length)
49 length = strlen(s);
50
Mike Frysinger7fde8de2005-06-11 22:37:25 +000051 ret = xmalloc(length + 1);
52 strncpy(ret, s, length);
53 ret[length] = '\0';
Mike Frysinger38a33f92005-05-09 22:13:22 +000054 return ret;
55}
56
57char *blkid_strdup(const char *s)
58{
59 return blkid_strndup(s, 0);
60}
61
62/*
63 * This function adds an entry to the directory list
64 */
65static void add_to_dirlist(const char *name, struct dir_list **list)
66{
67 struct dir_list *dp;
68
Mike Frysinger7fde8de2005-06-11 22:37:25 +000069 dp = xmalloc(sizeof(struct dir_list));
Mike Frysinger38a33f92005-05-09 22:13:22 +000070 dp->name = blkid_strdup(name);
Mike Frysinger38a33f92005-05-09 22:13:22 +000071 dp->next = *list;
72 *list = dp;
73}
74
75/*
76 * This function frees a directory list
77 */
78static void free_dirlist(struct dir_list **list)
79{
80 struct dir_list *dp, *next;
81
82 for (dp = *list; dp; dp = next) {
83 next = dp->next;
84 free(dp->name);
85 free(dp);
86 }
87 *list = NULL;
88}
89
90static void scan_dir(char *dir_name, dev_t devno, struct dir_list **list,
91 char **devname)
92{
93 DIR *dir;
94 struct dirent *dp;
95 char path[1024];
96 int dirlen;
97 struct stat st;
98
99 if ((dir = opendir(dir_name)) == NULL)
100 return;
101 dirlen = strlen(dir_name) + 2;
102 while ((dp = readdir(dir)) != 0) {
103 if (dirlen + strlen(dp->d_name) >= sizeof(path))
104 continue;
105
106 if (dp->d_name[0] == '.' &&
107 ((dp->d_name[1] == 0) ||
108 ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
109 continue;
110
111 sprintf(path, "%s/%s", dir_name, dp->d_name);
112 if (stat(path, &st) < 0)
113 continue;
114
115 if (S_ISDIR(st.st_mode))
116 add_to_dirlist(path, list);
117 else if (S_ISBLK(st.st_mode) && st.st_rdev == devno) {
118 *devname = blkid_strdup(path);
119 DBG(DEBUG_DEVNO,
120 printf("found 0x%Lx at %s (%p)\n", devno,
121 path, *devname));
122 break;
123 }
124 }
125 closedir(dir);
126 return;
127}
128
129/* Directories where we will try to search for device numbers */
130const char *blkid_devdirs[] = { "/devices", "/devfs", "/dev", NULL };
131
132/*
133 * This function finds the pathname to a block device with a given
134 * device number. It returns a pointer to allocated memory to the
135 * pathname on success, and NULL on failure.
136 */
137char *blkid_devno_to_devname(dev_t devno)
138{
139 struct dir_list *list = NULL, *new_list = NULL;
140 char *devname = NULL;
141 const char **dir;
142
143 /*
144 * Add the starting directories to search in reverse order of
145 * importance, since we are using a stack...
146 */
147 for (dir = blkid_devdirs; *dir; dir++)
148 add_to_dirlist(*dir, &list);
149
150 while (list) {
151 struct dir_list *current = list;
152
153 list = list->next;
154 DBG(DEBUG_DEVNO, printf("directory %s\n", current->name));
155 scan_dir(current->name, devno, &new_list, &devname);
156 free(current->name);
157 free(current);
158 if (devname)
159 break;
160 /*
161 * If we're done checking at this level, descend to
162 * the next level of subdirectories. (breadth-first)
163 */
164 if (list == NULL) {
165 list = new_list;
166 new_list = NULL;
167 }
168 }
169 free_dirlist(&list);
170 free_dirlist(&new_list);
171
172 if (!devname) {
173 DBG(DEBUG_DEVNO,
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000174 printf("blkid: couldn't find devno 0x%04lx\n",
Mike Frysinger38a33f92005-05-09 22:13:22 +0000175 (unsigned long) devno));
176 } else {
177 DBG(DEBUG_DEVNO,
178 printf("found devno 0x%04Lx as %s\n", devno, devname));
179 }
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000180
Mike Frysinger38a33f92005-05-09 22:13:22 +0000181
182 return devname;
183}
184
185#ifdef TEST_PROGRAM
186int main(int argc, char** argv)
187{
188 char *devname, *tmp;
189 int major, minor;
190 dev_t devno;
191 const char *errmsg = "Couldn't parse %s: %s\n";
192
193 blkid_debug_mask = DEBUG_ALL;
194 if ((argc != 2) && (argc != 3)) {
195 fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n"
196 "Resolve a device number to a device name\n",
197 argv[0], argv[0]);
198 exit(1);
199 }
200 if (argc == 2) {
201 devno = strtoul(argv[1], &tmp, 0);
202 if (*tmp) {
203 fprintf(stderr, errmsg, "device number", argv[1]);
204 exit(1);
205 }
206 } else {
207 major = strtoul(argv[1], &tmp, 0);
208 if (*tmp) {
209 fprintf(stderr, errmsg, "major number", argv[1]);
210 exit(1);
211 }
212 minor = strtoul(argv[2], &tmp, 0);
213 if (*tmp) {
214 fprintf(stderr, errmsg, "minor number", argv[2]);
215 exit(1);
216 }
217 devno = makedev(major, minor);
218 }
219 printf("Looking for device 0x%04Lx\n", devno);
220 devname = blkid_devno_to_devname(devno);
Rob Landleye7c43b62006-03-01 16:39:45 +0000221 free(devname);
Mike Frysinger38a33f92005-05-09 22:13:22 +0000222 return 0;
223}
224#endif