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