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