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