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