xref: /original-bsd/lib/libc/gen/disklabel.c (revision e59fb703)
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.18 (Berkeley) 11/04/91";
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 					error(errno);
165 					close(tf);
166 					return (0);
167 				}
168 				i = 0;
169 			}
170 			c = ibuf[i++];
171 			if (c == '\n') {
172 				if (cp > bp && cp[-1] == '\\'){
173 					cp--;
174 					continue;
175 				}
176 				break;
177 			}
178 			if (cp >= bp+BUFSIZ) {
179 				error(EFTYPE);
180 				break;
181 			} else
182 				*cp++ = c;
183 		}
184 		*cp = 0;
185 
186 		/*
187 		 * The real work for the match.
188 		 */
189 		if (dnamatch(name)) {
190 			close(tf);
191 			return (1);
192 		}
193 	}
194 }
195 
196 /*
197  * Dnamatch deals with name matching.  The first field of the disktab
198  * entry is a sequence of names separated by |'s, so we compare
199  * against each such name.  The normal : terminator after the last
200  * name (before the first field) stops us.
201  */
202 static
203 dnamatch(np)
204 	char *np;
205 {
206 	register char *Np, *Bp;
207 
208 	Bp = tbuf;
209 	if (*Bp == '#')
210 		return (0);
211 	for (;;) {
212 		for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
213 			continue;
214 		if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
215 			return (1);
216 		while (*Bp && *Bp != ':' && *Bp != '|')
217 			Bp++;
218 		if (*Bp == 0 || *Bp == ':')
219 			return (0);
220 		Bp++;
221 	}
222 }
223 
224 /*
225  * Skip to the next field.  Notice that this is very dumb, not
226  * knowing about \: escapes or any such.  If necessary, :'s can be put
227  * into the diskcap file in octal.
228  */
229 static char *
230 dskip(bp)
231 	register char *bp;
232 {
233 
234 	while (*bp && *bp != ':')
235 		bp++;
236 	if (*bp == ':')
237 		bp++;
238 	return (bp);
239 }
240 
241 /*
242  * Return the (numeric) option id.
243  * Numeric options look like
244  *	li#80
245  * i.e. the option string is separated from the numeric value by
246  * a # character.  If the option is not found we return -1.
247  * Note that we handle octal numbers beginning with 0.
248  */
249 static
250 dgetnum(id)
251 	char *id;
252 {
253 	register int i, base;
254 	register char *bp = tbuf;
255 
256 	for (;;) {
257 		bp = dskip(bp);
258 		if (*bp == 0)
259 			return (-1);
260 		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
261 			continue;
262 		if (*bp == '@')
263 			return (-1);
264 		if (*bp != '#')
265 			continue;
266 		bp++;
267 		base = 10;
268 		if (*bp == '0')
269 			base = 8;
270 		i = 0;
271 		while (isdigit(*bp))
272 			i *= base, i += *bp++ - '0';
273 		return (i);
274 	}
275 }
276 
277 /*
278  * Handle a flag option.
279  * Flag options are given "naked", i.e. followed by a : or the end
280  * of the buffer.  Return 1 if we find the option, or 0 if it is
281  * not given.
282  */
283 static
284 dgetflag(id)
285 	char *id;
286 {
287 	register char *bp = tbuf;
288 
289 	for (;;) {
290 		bp = dskip(bp);
291 		if (!*bp)
292 			return (0);
293 		if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
294 			if (!*bp || *bp == ':')
295 				return (1);
296 			else if (*bp == '@')
297 				return (0);
298 		}
299 	}
300 }
301 
302 /*
303  * Get a string valued option.
304  * These are given as
305  *	cl=^Z
306  * Much decoding is done on the strings, and the strings are
307  * placed in area, which is a ref parameter which is updated.
308  * No checking on area overflow.
309  */
310 static char *
311 dgetstr(id, area)
312 	char *id, **area;
313 {
314 	register char *bp = tbuf;
315 
316 	for (;;) {
317 		bp = dskip(bp);
318 		if (!*bp)
319 			return (0);
320 		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
321 			continue;
322 		if (*bp == '@')
323 			return (0);
324 		if (*bp != '=')
325 			continue;
326 		bp++;
327 		return (ddecode(bp, area));
328 	}
329 }
330 
331 /*
332  * Tdecode does the grung work to decode the
333  * string capability escapes.
334  */
335 static char *
336 ddecode(str, area)
337 	register char *str;
338 	char **area;
339 {
340 	register char *cp;
341 	register int c;
342 	register char *dp;
343 	int i;
344 
345 	cp = *area;
346 	while ((c = *str++) && c != ':') {
347 		switch (c) {
348 
349 		case '^':
350 			c = *str++ & 037;
351 			break;
352 
353 		case '\\':
354 			dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
355 			c = *str++;
356 nextc:
357 			if (*dp++ == c) {
358 				c = *dp++;
359 				break;
360 			}
361 			dp++;
362 			if (*dp)
363 				goto nextc;
364 			if (isdigit(c)) {
365 				c -= '0', i = 2;
366 				do
367 					c <<= 3, c |= *str++ - '0';
368 				while (--i && isdigit(*str));
369 			}
370 			break;
371 		}
372 		*cp++ = c;
373 	}
374 	*cp++ = 0;
375 	str = *area;
376 	*area = cp;
377 	return (str);
378 }
379 
380 static
381 gettype(t, names)
382 	char *t;
383 	char **names;
384 {
385 	register char **nm;
386 
387 	for (nm = names; *nm; nm++)
388 		if (strcasecmp(t, *nm) == 0)
389 			return (nm - names);
390 	if (isdigit(*t))
391 		return (atoi(t));
392 	return (0);
393 }
394 
395 static
396 error(err)
397 	int err;
398 {
399 	char *p;
400 
401 	(void)write(STDERR_FILENO, "disktab: ", 9);
402 	(void)write(STDERR_FILENO, _PATH_DISKTAB, sizeof(_PATH_DISKTAB) - 1);
403 	p = strerror(err);
404 	(void)write(STDERR_FILENO, p, strlen(p));
405 	(void)write(STDERR_FILENO, "\n", 1);
406 }
407