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