1de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o/*
2de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o * finddev.c -- this routine attempts to find a particular device in
3de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o * 	/dev
4efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
5de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o * Copyright (C) 2000 Theodore Ts'o.
6de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o *
7de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o * %Begin-Header%
8543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * This file may be redistributed under the terms of the GNU Library
9543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * General Public License, version 2.
10de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o * %End-Header%
11de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o */
12de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o
13de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#include <stdio.h>
14de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#include <string.h>
15de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#if HAVE_UNISTD_H
16de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#include <unistd.h>
17de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#endif
18de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#include <stdlib.h>
19de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#include <string.h>
20de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#if HAVE_SYS_TYPES_H
21de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#include <sys/types.h>
22de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#endif
23de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#if HAVE_SYS_STAT_H
24de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#include <sys/stat.h>
25de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#endif
26de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#include <dirent.h>
27de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#if HAVE_ERRNO_H
28de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#include <errno.h>
29de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#endif
30de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#if HAVE_SYS_MKDEV_H
31de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#include <sys/mkdev.h>
32de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#endif
33de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o
3431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o#include "ext2_fs.h"
3531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o#include "ext2fs.h"
36e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include "ext2fsP.h"
3731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o
38de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'ostruct dir_list {
39de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	char	*name;
40de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	struct dir_list *next;
41de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o};
42de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o
43de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o/*
44de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o * This function adds an entry to the directory list
45de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o */
4631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'ostatic void add_to_dirlist(const char *name, struct dir_list **list)
47de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o{
48de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	struct dir_list *dp;
49de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o
50de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	dp = malloc(sizeof(struct dir_list));
51de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	if (!dp)
52de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		return;
53de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	dp->name = malloc(strlen(name)+1);
54de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	if (!dp->name) {
55de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		free(dp);
56de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		return;
57de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	}
58de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	strcpy(dp->name, name);
59de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	dp->next = *list;
60de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	*list = dp;
61de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o}
62de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o
63de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o/*
64de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o * This function frees a directory list
65de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o */
66de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'ostatic void free_dirlist(struct dir_list **list)
67de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o{
68de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	struct dir_list *dp, *next;
69de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o
70de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	for (dp = *list; dp; dp = next) {
71de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		next = dp->next;
72de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		free(dp->name);
73de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		free(dp);
74de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	}
75de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	*list = 0;
76de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o}
77de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o
78de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'ostatic int scan_dir(char *dirname, dev_t device, struct dir_list **list,
79de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		    char **ret_path)
80de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o{
81de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	DIR	*dir;
82de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	struct dirent *dp;
83de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	char	path[1024], *cp;
84de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	int	dirlen;
85de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	struct stat st;
86de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o
87de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	dirlen = strlen(dirname);
88de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	if ((dir = opendir(dirname)) == NULL)
89de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		return errno;
90de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	dp = readdir(dir);
91de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	while (dp) {
92de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		if (dirlen + strlen(dp->d_name) + 2 >= sizeof(path))
93de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			goto skip_to_next;
94de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		if (dp->d_name[0] == '.' &&
95de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		    ((dp->d_name[1] == 0) ||
9631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		     ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
97de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			goto skip_to_next;
98de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		sprintf(path, "%s/%s", dirname, dp->d_name);
99de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		if (stat(path, &st) < 0)
100f86fa6c7483f6fee33fb128fced4644ec876a1bcTheodore Ts'o			goto skip_to_next;
101de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		if (S_ISDIR(st.st_mode))
102de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			add_to_dirlist(path, list);
103de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		if (S_ISBLK(st.st_mode) && st.st_rdev == device) {
104de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			cp = malloc(strlen(path)+1);
1053751721fbb2b72cf99dff3755249357ef5372205Theodore Ts'o			if (!cp) {
1063751721fbb2b72cf99dff3755249357ef5372205Theodore Ts'o				closedir(dir);
107de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o				return ENOMEM;
1083751721fbb2b72cf99dff3755249357ef5372205Theodore Ts'o			}
109de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			strcpy(cp, path);
110de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			*ret_path = cp;
1113751721fbb2b72cf99dff3755249357ef5372205Theodore Ts'o			goto success;
112de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		}
113de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	skip_to_next:
114de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		dp = readdir(dir);
115de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	}
1163751721fbb2b72cf99dff3755249357ef5372205Theodore Ts'osuccess:
117de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	closedir(dir);
118de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	return 0;
119de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o}
120de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o
121de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o/*
122de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o * This function finds the pathname to a block device with a given
123de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o * device number.  It returns a pointer to allocated memory to the
124de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o * pathname on success, and NULL on failure.
125de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o */
126de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'ochar *ext2fs_find_block_device(dev_t device)
127de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o{
128de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	struct dir_list *list = 0, *new_list = 0;
129de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	struct dir_list *current;
130de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	char	*ret_path = 0;
131e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int    level = 0;
132de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o
133de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	/*
134de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	 * Add the starting directories to search...
135de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	 */
136de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	add_to_dirlist("/devices", &list);
137de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	add_to_dirlist("/devfs", &list);
138de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	add_to_dirlist("/dev", &list);
139efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
140de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	while (list) {
141de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		current = list;
142de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		list = list->next;
143de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#ifdef DEBUG
144de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		printf("Scanning directory %s\n", current->name);
145de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#endif
146de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		scan_dir(current->name, device, &new_list, &ret_path);
147de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		free(current->name);
148de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		free(current);
149de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		if (ret_path)
150de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			break;
151de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		/*
152de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		 * If we're done checking at this level, descend to
153de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		 * the next level of subdirectories. (breadth-first)
154de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		 */
155de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		if (list == 0) {
156de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			list = new_list;
157de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			new_list = 0;
158e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			/* Avoid infinite loop */
159e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if (++level >= EXT2FS_MAX_NESTED_LINKS)
160e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				break;
161de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		}
162de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	}
163de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	free_dirlist(&list);
164de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	free_dirlist(&new_list);
165de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	return ret_path;
166de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o}
167de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o
168efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
169de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#ifdef DEBUG
170de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'oint main(int argc, char** argv)
171de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o{
172de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	char	*devname, *tmp;
173de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	int	major, minor;
174de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	dev_t	device;
175de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	const char *errmsg = "Couldn't parse %s: %s\n";
176de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o
177de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	if ((argc != 2) && (argc != 3)) {
178de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		fprintf(stderr, "Usage: %s device_number\n", argv[0]);
179de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		fprintf(stderr, "\t: %s major minor\n", argv[0]);
180de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		exit(1);
181de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	}
182de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	if (argc == 2) {
183de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		device = strtoul(argv[1], &tmp, 0);
184de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		if (*tmp) {
185de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			fprintf(stderr, errmsg, "device number", argv[1]);
186de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			exit(1);
187de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		}
188de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	} else {
189de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		major = strtoul(argv[1], &tmp, 0);
190de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		if (*tmp) {
191de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			fprintf(stderr, errmsg, "major number", argv[1]);
192de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			exit(1);
193de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		}
194de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		minor = strtoul(argv[2], &tmp, 0);
195de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		if (*tmp) {
196de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			fprintf(stderr, errmsg, "minor number", argv[2]);
197de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o			exit(1);
198de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		}
199de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		device = makedev(major, minor);
200de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		printf("Looking for device 0x%04x (%d:%d)\n", device,
201de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		       major, minor);
202de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	}
203de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	devname = ext2fs_find_block_device(device);
204de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	if (devname) {
205de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		printf("Found device!  %s\n", devname);
206de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		free(devname);
207de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	} else {
208de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o		printf("Couldn't find device.\n");
209de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	}
210de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o	return 0;
211de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o}
212efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
213de23aa1d177a67283f5f5a1f172b00527fe3b63aTheodore Ts'o#endif
214