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