xref: /csrg-svn/lib/libc/gen/disklabel.c (revision 33399)
1 /*
2  * Copyright (c) 1983,1987 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 #if defined(LIBC_SCCS) && !defined(lint)
8 static char sccsid[] = "@(#)disklabel.c	5.9 (Berkeley) 01/27/88";
9 #endif LIBC_SCCS and not lint
10 
11 #include <sys/param.h>
12 #include <sys/fs.h>
13 #include <sys/file.h>
14 #define DKTYPENAMES
15 #include <sys/disklabel.h>
16 #include <stdio.h>
17 #include <strings.h>
18 
19 static	char *dgetstr();
20 
21 struct disklabel *
22 getdiskbyname(name)
23 	char *name;
24 {
25 	static struct	disklabel disk;
26 	static char 	boot[BUFSIZ];
27 	char	localbuf[BUFSIZ];
28 	char	buf[BUFSIZ];
29 	char	*cp, *cq;	/* can't be register */
30 	register struct	disklabel *dp = &disk;
31 	register struct partition *pp;
32 	char	p, max, psize[3], pbsize[3],
33 		pfsize[3], poffset[3], ptype[3];
34 	u_long	*dx;
35 
36 	if (dgetent(buf, name) <= 0)
37 		return ((struct disklabel *)0);
38 	bzero((char *)&disk, sizeof(disk));
39 	/*
40 	 * typename
41 	 */
42 	cq = dp->d_typename;
43 	cp = buf;
44 	while (cq < dp->d_typename + sizeof(dp->d_typename) - 1 &&
45 	    (*cq = *cp) && *cq != '|' && *cq != ':')
46 		cq++, cp++;
47 	*cq = '\0';
48 	/*
49 	 * boot name (optional)  xxboot, bootxx
50 	 */
51 	cp = boot;
52 	dp->d_boot0 = dgetstr("b0", &cp);
53 	dp->d_boot1 = dgetstr("b1", &cp);
54 	cp = localbuf;
55 	cq = dgetstr("ty", &cp);
56 	if (cq && strcmp(cq, "removable") == 0)
57 		dp->d_flags |= D_REMOVABLE;
58 	else  if (cq && strcmp(cq, "simulated") == 0)
59 		dp->d_flags |= D_RAMDISK;
60 	if (dgetflag("sf"))
61 		dp->d_flags |= D_BADSECT;
62 
63 #define getnumdflt(field, dname, dflt) \
64 	{ int f = dgetnum(dname); \
65 	(field) = f == -1 ? (dflt) : f; }
66 
67 	getnumdflt(dp->d_secsize, "se", DEV_BSIZE);
68 	dp->d_ntracks = dgetnum("nt");
69 	dp->d_nsectors = dgetnum("ns");
70 	dp->d_ncylinders = dgetnum("nc");
71 	cq = dgetstr("dt", &cp);
72 	if (cq)
73 		dp->d_type = gettype(cq, dktypenames);
74 	else
75 		getnumdflt(dp->d_type, "dt", 0);
76 	getnumdflt(dp->d_secpercyl, "sc", dp->d_nsectors * dp->d_ntracks);
77 	getnumdflt(dp->d_secperunit, "su", dp->d_secpercyl * dp->d_ncylinders);
78 	getnumdflt(dp->d_rpm, "rm", 3600);
79 	getnumdflt(dp->d_interleave, "il", 1);
80 	getnumdflt(dp->d_trackskew, "sk", 0);
81 	getnumdflt(dp->d_cylskew, "cs", 0);
82 	getnumdflt(dp->d_headswitch, "hs", 0);
83 	getnumdflt(dp->d_trkseek, "ts", 0);
84 	getnumdflt(dp->d_bbsize, "bs", BBSIZE);
85 	getnumdflt(dp->d_sbsize, "sb", SBSIZE);
86 	strcpy(psize, "px");
87 	strcpy(pbsize, "bx");
88 	strcpy(pfsize, "fx");
89 	strcpy(poffset, "ox");
90 	strcpy(ptype, "tx");
91 	max = 'a' - 1;
92 	pp = &dp->d_partitions[0];
93 	for (p = 'a'; p < 'a' + MAXPARTITIONS; p++, pp++) {
94 		psize[1] = pbsize[1] = pfsize[1] = poffset[1] = ptype[1] = p;
95 		pp->p_size = dgetnum(psize);
96 		if (pp->p_size == -1)
97 			pp->p_size = 0;
98 		else {
99 			pp->p_offset = dgetnum(poffset);
100 			getnumdflt(pp->p_fsize, pfsize, 0);
101 			if (pp->p_fsize)
102 				pp->p_frag = dgetnum(pbsize) / pp->p_fsize;
103 			getnumdflt(pp->p_fstype, ptype, 0);
104 			if (pp->p_fstype == 0 && (cq = dgetstr(ptype, &cp)))
105 				pp->p_fstype = gettype(cq, fstypenames);
106 			max = p;
107 		}
108 	}
109 	dp->d_npartitions = max + 1 - 'a';
110 	(void)strcpy(psize, "dx");
111 	dx = dp->d_drivedata;
112 	for (p = '0'; p < '0' + NDDATA; p++, dx++) {
113 		psize[1] = p;
114 		getnumdflt(*dx, psize, 0);
115 	}
116 	dp->d_magic = DISKMAGIC;
117 	dp->d_magic2 = DISKMAGIC;
118 	return (dp);
119 }
120 
121 #include <ctype.h>
122 
123 static	char *tbuf;
124 static	char *dskip();
125 static	char *ddecode();
126 
127 /*
128  * Get an entry for disk name in buffer bp,
129  * from the diskcap file.  Parse is very rudimentary;
130  * we just notice escaped newlines.
131  */
132 static
133 dgetent(bp, name)
134 	char *bp, *name;
135 {
136 	register char *cp;
137 	register int c;
138 	register int i = 0, cnt = 0;
139 	char ibuf[BUFSIZ];
140 	int tf;
141 
142 	tbuf = bp;
143 	tf = open(DISKTAB, 0);
144 	if (tf < 0)
145 		return (-1);
146 	for (;;) {
147 		cp = bp;
148 		for (;;) {
149 			if (i == cnt) {
150 				cnt = read(tf, ibuf, BUFSIZ);
151 				if (cnt <= 0) {
152 					close(tf);
153 					return (0);
154 				}
155 				i = 0;
156 			}
157 			c = ibuf[i++];
158 			if (c == '\n') {
159 				if (cp > bp && cp[-1] == '\\'){
160 					cp--;
161 					continue;
162 				}
163 				break;
164 			}
165 			if (cp >= bp+BUFSIZ) {
166 				write(2,"Disktab entry too long\n", 23);
167 				break;
168 			} else
169 				*cp++ = c;
170 		}
171 		*cp = 0;
172 
173 		/*
174 		 * The real work for the match.
175 		 */
176 		if (dnamatch(name)) {
177 			close(tf);
178 			return (1);
179 		}
180 	}
181 }
182 
183 /*
184  * Dnamatch deals with name matching.  The first field of the disktab
185  * entry is a sequence of names separated by |'s, so we compare
186  * against each such name.  The normal : terminator after the last
187  * name (before the first field) stops us.
188  */
189 static
190 dnamatch(np)
191 	char *np;
192 {
193 	register char *Np, *Bp;
194 
195 	Bp = tbuf;
196 	if (*Bp == '#')
197 		return (0);
198 	for (;;) {
199 		for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
200 			continue;
201 		if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
202 			return (1);
203 		while (*Bp && *Bp != ':' && *Bp != '|')
204 			Bp++;
205 		if (*Bp == 0 || *Bp == ':')
206 			return (0);
207 		Bp++;
208 	}
209 }
210 
211 /*
212  * Skip to the next field.  Notice that this is very dumb, not
213  * knowing about \: escapes or any such.  If necessary, :'s can be put
214  * into the diskcap file in octal.
215  */
216 static char *
217 dskip(bp)
218 	register char *bp;
219 {
220 
221 	while (*bp && *bp != ':')
222 		bp++;
223 	if (*bp == ':')
224 		bp++;
225 	return (bp);
226 }
227 
228 /*
229  * Return the (numeric) option id.
230  * Numeric options look like
231  *	li#80
232  * i.e. the option string is separated from the numeric value by
233  * a # character.  If the option is not found we return -1.
234  * Note that we handle octal numbers beginning with 0.
235  */
236 static
237 dgetnum(id)
238 	char *id;
239 {
240 	register int i, base;
241 	register char *bp = tbuf;
242 
243 	for (;;) {
244 		bp = dskip(bp);
245 		if (*bp == 0)
246 			return (-1);
247 		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
248 			continue;
249 		if (*bp == '@')
250 			return (-1);
251 		if (*bp != '#')
252 			continue;
253 		bp++;
254 		base = 10;
255 		if (*bp == '0')
256 			base = 8;
257 		i = 0;
258 		while (isdigit(*bp))
259 			i *= base, i += *bp++ - '0';
260 		return (i);
261 	}
262 }
263 
264 /*
265  * Handle a flag option.
266  * Flag options are given "naked", i.e. followed by a : or the end
267  * of the buffer.  Return 1 if we find the option, or 0 if it is
268  * not given.
269  */
270 static
271 dgetflag(id)
272 	char *id;
273 {
274 	register char *bp = tbuf;
275 
276 	for (;;) {
277 		bp = dskip(bp);
278 		if (!*bp)
279 			return (0);
280 		if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
281 			if (!*bp || *bp == ':')
282 				return (1);
283 			else if (*bp == '@')
284 				return (0);
285 		}
286 	}
287 }
288 
289 /*
290  * Get a string valued option.
291  * These are given as
292  *	cl=^Z
293  * Much decoding is done on the strings, and the strings are
294  * placed in area, which is a ref parameter which is updated.
295  * No checking on area overflow.
296  */
297 static char *
298 dgetstr(id, area)
299 	char *id, **area;
300 {
301 	register char *bp = tbuf;
302 
303 	for (;;) {
304 		bp = dskip(bp);
305 		if (!*bp)
306 			return (0);
307 		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
308 			continue;
309 		if (*bp == '@')
310 			return (0);
311 		if (*bp != '=')
312 			continue;
313 		bp++;
314 		return (ddecode(bp, area));
315 	}
316 }
317 
318 /*
319  * Tdecode does the grung work to decode the
320  * string capability escapes.
321  */
322 static char *
323 ddecode(str, area)
324 	register char *str;
325 	char **area;
326 {
327 	register char *cp;
328 	register int c;
329 	register char *dp;
330 	int i;
331 
332 	cp = *area;
333 	while ((c = *str++) && c != ':') {
334 		switch (c) {
335 
336 		case '^':
337 			c = *str++ & 037;
338 			break;
339 
340 		case '\\':
341 			dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
342 			c = *str++;
343 nextc:
344 			if (*dp++ == c) {
345 				c = *dp++;
346 				break;
347 			}
348 			dp++;
349 			if (*dp)
350 				goto nextc;
351 			if (isdigit(c)) {
352 				c -= '0', i = 2;
353 				do
354 					c <<= 3, c |= *str++ - '0';
355 				while (--i && isdigit(*str));
356 			}
357 			break;
358 		}
359 		*cp++ = c;
360 	}
361 	*cp++ = 0;
362 	str = *area;
363 	*area = cp;
364 	return (str);
365 }
366 
367 static
368 gettype(t, names)
369 	char *t;
370 	char **names;
371 {
372 	register char **nm;
373 
374 	for (nm = names; *nm; nm++)
375 		if (strcasecmp(t, *nm) == 0)
376 			return (nm - names);
377 	if (isdigit(*t))
378 		return (atoi(t));
379 	return (0);
380 }
381 
382 dkcksum(lp)
383 	register struct disklabel *lp;
384 {
385 	register u_short *start, *end;
386 	register u_short sum = 0;
387 
388 	start = (u_short *)lp;
389 	end = (u_short *)&lp->d_partitions[lp->d_npartitions];
390 	while (start < end)
391 		sum ^= *start++;
392 	return (sum);
393 }
394