xref: /csrg-svn/lib/libc/gen/disklabel.c (revision 10748)
1 /*	@(#)disklabel.c	4.1 (Berkeley) 02/06/83	*/
2 
3 #include <disktab.h>
4 #include <stdio.h>
5 
6 static	char *dgetstr();
7 
8 struct disktab *
9 getdiskbyname(name)
10 	char *name;
11 {
12 	static struct disktab disk;
13 	static char localbuf[100], *cp = localbuf;
14 	register struct	disktab *dp = &disk;
15 	char p, part[3], buf[BUFSIZ];
16 
17 	if (dgetent(buf, name) <= 0)
18 		return ((struct disktab *)0);
19 	dp->d_name = cp;
20 	strcpy(cp, name);
21 	cp += strlen(name) + 1;
22 	dp->d_type = dgetstr("ty", &cp);
23 	dp->d_secsize = dgetnum("se");
24 	if (dp->d_secsize < 0)
25 		dp->d_secsize = 512;
26 	dp->d_ntracks = dgetnum("nt");
27 	dp->d_nsectors = dgetnum("ns");
28 	dp->d_ncylinders = dgetnum("nc");
29 	dp->d_rpm = dgetnum("rm");
30 	if (dp->d_rpm < 0)
31 		dp->d_rpm = 3600;
32 	strcpy(part, "px");
33 	for (p = 'a'; p < 'i'; p++) {
34 		part[1] = p;
35 		dp->d_partitions[p - 'a'] = dgetnum(part);
36 	}
37 	return (dp);
38 }
39 
40 #include <ctype.h>
41 
42 static	char *tbuf;
43 static	char *dskip();
44 static	char *ddecode();
45 
46 /*
47  * Get an entry for disk name in buffer bp,
48  * from the diskcap file.  Parse is very rudimentary;
49  * we just notice escaped newlines.
50  */
51 static
52 dgetent(bp, name)
53 	char *bp, *name;
54 {
55 	register char *cp;
56 	register int c;
57 	register int i = 0, cnt = 0;
58 	char ibuf[BUFSIZ];
59 	int tf;
60 
61 	tbuf = bp;
62 	tf = open(DISKTAB, 0);
63 	if (tf < 0)
64 		return (-1);
65 	for (;;) {
66 		cp = bp;
67 		for (;;) {
68 			if (i == cnt) {
69 				cnt = read(tf, ibuf, BUFSIZ);
70 				if (cnt <= 0) {
71 					close(tf);
72 					return (0);
73 				}
74 				i = 0;
75 			}
76 			c = ibuf[i++];
77 			if (c == '\n') {
78 				if (cp > bp && cp[-1] == '\\'){
79 					cp--;
80 					continue;
81 				}
82 				break;
83 			}
84 			if (cp >= bp+BUFSIZ) {
85 				write(2,"Disktab entry too long\n", 23);
86 				break;
87 			} else
88 				*cp++ = c;
89 		}
90 		*cp = 0;
91 
92 		/*
93 		 * The real work for the match.
94 		 */
95 		if (dnamatch(name)) {
96 			close(tf);
97 			return (1);
98 		}
99 	}
100 }
101 
102 /*
103  * Dnamatch deals with name matching.  The first field of the disktab
104  * entry is a sequence of names separated by |'s, so we compare
105  * against each such name.  The normal : terminator after the last
106  * name (before the first field) stops us.
107  */
108 static
109 dnamatch(np)
110 	char *np;
111 {
112 	register char *Np, *Bp;
113 
114 	Bp = tbuf;
115 	if (*Bp == '#')
116 		return (0);
117 	for (;;) {
118 		for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
119 			continue;
120 		if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
121 			return (1);
122 		while (*Bp && *Bp != ':' && *Bp != '|')
123 			Bp++;
124 		if (*Bp == 0 || *Bp == ':')
125 			return (0);
126 		Bp++;
127 	}
128 }
129 
130 /*
131  * Skip to the next field.  Notice that this is very dumb, not
132  * knowing about \: escapes or any such.  If necessary, :'s can be put
133  * into the diskcap file in octal.
134  */
135 static char *
136 dskip(bp)
137 	register char *bp;
138 {
139 
140 	while (*bp && *bp != ':')
141 		bp++;
142 	if (*bp == ':')
143 		bp++;
144 	return (bp);
145 }
146 
147 /*
148  * Return the (numeric) option id.
149  * Numeric options look like
150  *	li#80
151  * i.e. the option string is separated from the numeric value by
152  * a # character.  If the option is not found we return -1.
153  * Note that we handle octal numbers beginning with 0.
154  */
155 static
156 dgetnum(id)
157 	char *id;
158 {
159 	register int i, base;
160 	register char *bp = tbuf;
161 
162 	for (;;) {
163 		bp = dskip(bp);
164 		if (*bp == 0)
165 			return (-1);
166 		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
167 			continue;
168 		if (*bp == '@')
169 			return (-1);
170 		if (*bp != '#')
171 			continue;
172 		bp++;
173 		base = 10;
174 		if (*bp == '0')
175 			base = 8;
176 		i = 0;
177 		while (isdigit(*bp))
178 			i *= base, i += *bp++ - '0';
179 		return (i);
180 	}
181 }
182 
183 /*
184  * Handle a flag option.
185  * Flag options are given "naked", i.e. followed by a : or the end
186  * of the buffer.  Return 1 if we find the option, or 0 if it is
187  * not given.
188  */
189 static
190 dgetflag(id)
191 	char *id;
192 {
193 	register char *bp = tbuf;
194 
195 	for (;;) {
196 		bp = dskip(bp);
197 		if (!*bp)
198 			return (0);
199 		if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
200 			if (!*bp || *bp == ':')
201 				return (1);
202 			else if (*bp == '@')
203 				return (0);
204 		}
205 	}
206 }
207 
208 /*
209  * Get a string valued option.
210  * These are given as
211  *	cl=^Z
212  * Much decoding is done on the strings, and the strings are
213  * placed in area, which is a ref parameter which is updated.
214  * No checking on area overflow.
215  */
216 static char *
217 dgetstr(id, area)
218 	char *id, **area;
219 {
220 	register char *bp = tbuf;
221 
222 	for (;;) {
223 		bp = dskip(bp);
224 		if (!*bp)
225 			return (0);
226 		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
227 			continue;
228 		if (*bp == '@')
229 			return (0);
230 		if (*bp != '=')
231 			continue;
232 		bp++;
233 		return (ddecode(bp, area));
234 	}
235 }
236 
237 /*
238  * Tdecode does the grung work to decode the
239  * string capability escapes.
240  */
241 static char *
242 ddecode(str, area)
243 	register char *str;
244 	char **area;
245 {
246 	register char *cp;
247 	register int c;
248 	register char *dp;
249 	int i;
250 
251 	cp = *area;
252 	while ((c = *str++) && c != ':') {
253 		switch (c) {
254 
255 		case '^':
256 			c = *str++ & 037;
257 			break;
258 
259 		case '\\':
260 			dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
261 			c = *str++;
262 nextc:
263 			if (*dp++ == c) {
264 				c = *dp++;
265 				break;
266 			}
267 			dp++;
268 			if (*dp)
269 				goto nextc;
270 			if (isdigit(c)) {
271 				c -= '0', i = 2;
272 				do
273 					c <<= 3, c |= *str++ - '0';
274 				while (--i && isdigit(*str));
275 			}
276 			break;
277 		}
278 		*cp++ = c;
279 	}
280 	*cp++ = 0;
281 	str = *area;
282 	*area = cp;
283 	return (str);
284 }
285