base_device.c revision efc6f628e15de95bcd13e4f0ee223cb42115d520
1/*
2 * base_device.c
3 *
4 * Return the "base device" given a particular device; this is used to
5 * assure that we only fsck one partition on a particular drive at any
6 * one time.  Otherwise, the disk heads will be seeking all over the
7 * place.  If the base device can not be determined, return NULL.
8 *
9 * The base_device() function returns an allocated string which must
10 * be freed.
11 *
12 * Written by Theodore Ts'o, <tytso@mit.edu>
13 *
14 * Copyright (C) 2000 Theodore Ts'o.
15 *
16 * %Begin-Header%
17 * This file may be redistributed under the terms of the GNU Public
18 * License.
19 * %End-Header%
20 */
21#include <stdio.h>
22#if HAVE_UNISTD_H
23#include <unistd.h>
24#endif
25#if HAVE_STDLIB_H
26#include <stdlib.h>
27#endif
28#include <ctype.h>
29#include <string.h>
30
31#include "fsck.h"
32
33/*
34 * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
35 * pathames.
36 */
37static const char *devfs_hier[] = {
38	"host", "bus", "target", "lun", 0
39};
40
41char *base_device(const char *device)
42{
43	char *str, *cp;
44	const char **hier, *disk;
45	int len;
46
47	str = malloc(strlen(device)+1);
48	if (!str)
49		return NULL;
50	strcpy(str, device);
51	cp = str;
52
53	/* Skip over /dev/; if it's not present, give up. */
54	if (strncmp(cp, "/dev/", 5) != 0)
55		goto errout;
56	cp += 5;
57
58	/* Skip over /dev/dsk/... */
59	if (strncmp(cp, "dsk/", 4) == 0)
60		cp += 4;
61
62	/*
63	 * For md devices, we treat them all as if they were all
64	 * on one disk, since we don't know how to parallelize them.
65	 */
66	if (cp[0] == 'm' && cp[1] == 'd') {
67		*(cp+2) = 0;
68		return str;
69	}
70
71	/* Handle DAC 960 devices */
72	if (strncmp(cp, "rd/", 3) == 0) {
73		cp += 3;
74		if (cp[0] != 'c' || cp[2] != 'd' ||
75		    !isdigit(cp[1]) || !isdigit(cp[3]))
76			goto errout;
77		*(cp+4) = 0;
78		return str;
79	}
80
81	/* Now let's handle /dev/hd* and /dev/sd* devices.... */
82	if ((cp[0] == 'h' || cp[0] == 's') && (cp[1] == 'd')) {
83		cp += 2;
84		/* If there's a single number after /dev/hd, skip it */
85		if (isdigit(*cp))
86			cp++;
87		/* What follows must be an alpha char, or give up */
88		if (!isalpha(*cp))
89			goto errout;
90		*(cp + 1) = 0;
91		return str;
92	}
93
94	/* Now let's handle devfs (ugh) names */
95	len = 0;
96	if (strncmp(cp, "ide/", 4) == 0)
97		len = 4;
98	if (strncmp(cp, "scsi/", 5) == 0)
99		len = 5;
100	if (len) {
101		cp += len;
102		/*
103		 * Now we proceed down the expected devfs hierarchy.
104		 * i.e., .../host1/bus2/target3/lun4/...
105		 * If we don't find the expected token, followed by
106		 * some number of digits at each level, abort.
107		 */
108		for (hier = devfs_hier; *hier; hier++) {
109			len = strlen(*hier);
110			if (strncmp(cp, *hier, len) != 0)
111				goto errout;
112			cp += len;
113			while (*cp != '/' && *cp != 0) {
114				if (!isdigit(*cp))
115					goto errout;
116				cp++;
117			}
118			cp++;
119		}
120		*(cp - 1) = 0;
121		return str;
122	}
123
124	/* Now handle devfs /dev/disc or /dev/disk names */
125	disk = 0;
126	if (strncmp(cp, "discs/", 6) == 0)
127		disk = "disc";
128	else if (strncmp(cp, "disks/", 6) == 0)
129		disk = "disk";
130	if (disk) {
131		cp += 6;
132		if (strncmp(cp, disk, 4) != 0)
133			goto errout;
134		cp += 4;
135		while (*cp != '/' && *cp != 0) {
136			if (!isdigit(*cp))
137				goto errout;
138			cp++;
139		}
140		*cp = 0;
141		return str;
142	}
143
144errout:
145	free(str);
146	return NULL;
147}
148
149#ifdef DEBUG
150int main(int argc, char** argv)
151{
152	const char *base;
153	char  buf[256], *cp;
154
155	while (1) {
156		if (fgets(buf, sizeof(buf), stdin) == NULL)
157			break;
158		cp = strchr(buf, '\n');
159		if (cp)
160			*cp = 0;
161		cp = strchr(buf, '\t');
162		if (cp)
163			*cp = 0;
164		base = base_device(buf);
165		printf("%s\t%s\n", buf, base ? base : "NONE");
166	}
167	exit(0);
168}
169#endif
170