xref: /original-bsd/lib/libc/gen/disklabel.c (revision 0fc6f013)
1 /*
2  * Copyright (c) 1983 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.3 (Berkeley) 03/09/86";
9 #endif LIBC_SCCS and not lint
10 
11 #include <disktab.h>
12 #include <stdio.h>
13 
14 static	char *dgetstr();
15 
16 struct disktab *
17 getdiskbyname(name)
18 	char *name;
19 {
20 	static struct disktab disk;
21 	static char localbuf[100], *cp = localbuf;
22 	register struct	disktab *dp = &disk;
23 	register struct partition *pp;
24 	char p, psize[3], pbsize[3], pfsize[3];
25 	char buf[BUFSIZ];
26 
27 	if (dgetent(buf, name) <= 0)
28 		return ((struct disktab *)0);
29 	dp->d_name = cp;
30 	strcpy(cp, name);
31 	cp += strlen(name) + 1;
32 	dp->d_type = dgetstr("ty", &cp);
33 	dp->d_secsize = dgetnum("se");
34 	if (dp->d_secsize < 0)
35 		dp->d_secsize = 512;
36 	dp->d_ntracks = dgetnum("nt");
37 	dp->d_nsectors = dgetnum("ns");
38 	dp->d_ncylinders = dgetnum("nc");
39 	dp->d_rpm = dgetnum("rm");
40 	if (dp->d_rpm < 0)
41 		dp->d_rpm = 3600;
42 	dp->d_badsectforw = dgetflag("sf");
43 	dp->d_sectoffset = dgetflag("so");
44 	strcpy(psize, "px");
45 	strcpy(pbsize, "bx");
46 	strcpy(pfsize, "fx");
47 	for (p = 'a'; p < 'i'; p++) {
48 		psize[1] = pbsize[1] = pfsize[1] = p;
49 		pp = &dp->d_partitions[p - 'a'];
50 		pp->p_size = dgetnum(psize);
51 		pp->p_bsize = dgetnum(pbsize);
52 		pp->p_fsize = dgetnum(pfsize);
53 	}
54 	return (dp);
55 }
56 
57 #include <ctype.h>
58 
59 static	char *tbuf;
60 static	char *dskip();
61 static	char *ddecode();
62 
63 /*
64  * Get an entry for disk name in buffer bp,
65  * from the diskcap file.  Parse is very rudimentary;
66  * we just notice escaped newlines.
67  */
68 static
69 dgetent(bp, name)
70 	char *bp, *name;
71 {
72 	register char *cp;
73 	register int c;
74 	register int i = 0, cnt = 0;
75 	char ibuf[BUFSIZ];
76 	int tf;
77 
78 	tbuf = bp;
79 	tf = open(DISKTAB, 0);
80 	if (tf < 0)
81 		return (-1);
82 	for (;;) {
83 		cp = bp;
84 		for (;;) {
85 			if (i == cnt) {
86 				cnt = read(tf, ibuf, BUFSIZ);
87 				if (cnt <= 0) {
88 					close(tf);
89 					return (0);
90 				}
91 				i = 0;
92 			}
93 			c = ibuf[i++];
94 			if (c == '\n') {
95 				if (cp > bp && cp[-1] == '\\'){
96 					cp--;
97 					continue;
98 				}
99 				break;
100 			}
101 			if (cp >= bp+BUFSIZ) {
102 				write(2,"Disktab entry too long\n", 23);
103 				break;
104 			} else
105 				*cp++ = c;
106 		}
107 		*cp = 0;
108 
109 		/*
110 		 * The real work for the match.
111 		 */
112 		if (dnamatch(name)) {
113 			close(tf);
114 			return (1);
115 		}
116 	}
117 }
118 
119 /*
120  * Dnamatch deals with name matching.  The first field of the disktab
121  * entry is a sequence of names separated by |'s, so we compare
122  * against each such name.  The normal : terminator after the last
123  * name (before the first field) stops us.
124  */
125 static
126 dnamatch(np)
127 	char *np;
128 {
129 	register char *Np, *Bp;
130 
131 	Bp = tbuf;
132 	if (*Bp == '#')
133 		return (0);
134 	for (;;) {
135 		for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
136 			continue;
137 		if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
138 			return (1);
139 		while (*Bp && *Bp != ':' && *Bp != '|')
140 			Bp++;
141 		if (*Bp == 0 || *Bp == ':')
142 			return (0);
143 		Bp++;
144 	}
145 }
146 
147 /*
148  * Skip to the next field.  Notice that this is very dumb, not
149  * knowing about \: escapes or any such.  If necessary, :'s can be put
150  * into the diskcap file in octal.
151  */
152 static char *
153 dskip(bp)
154 	register char *bp;
155 {
156 
157 	while (*bp && *bp != ':')
158 		bp++;
159 	if (*bp == ':')
160 		bp++;
161 	return (bp);
162 }
163 
164 /*
165  * Return the (numeric) option id.
166  * Numeric options look like
167  *	li#80
168  * i.e. the option string is separated from the numeric value by
169  * a # character.  If the option is not found we return -1.
170  * Note that we handle octal numbers beginning with 0.
171  */
172 static
173 dgetnum(id)
174 	char *id;
175 {
176 	register int i, base;
177 	register char *bp = tbuf;
178 
179 	for (;;) {
180 		bp = dskip(bp);
181 		if (*bp == 0)
182 			return (-1);
183 		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
184 			continue;
185 		if (*bp == '@')
186 			return (-1);
187 		if (*bp != '#')
188 			continue;
189 		bp++;
190 		base = 10;
191 		if (*bp == '0')
192 			base = 8;
193 		i = 0;
194 		while (isdigit(*bp))
195 			i *= base, i += *bp++ - '0';
196 		return (i);
197 	}
198 }
199 
200 /*
201  * Handle a flag option.
202  * Flag options are given "naked", i.e. followed by a : or the end
203  * of the buffer.  Return 1 if we find the option, or 0 if it is
204  * not given.
205  */
206 static
207 dgetflag(id)
208 	char *id;
209 {
210 	register char *bp = tbuf;
211 
212 	for (;;) {
213 		bp = dskip(bp);
214 		if (!*bp)
215 			return (0);
216 		if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
217 			if (!*bp || *bp == ':')
218 				return (1);
219 			else if (*bp == '@')
220 				return (0);
221 		}
222 	}
223 }
224 
225 /*
226  * Get a string valued option.
227  * These are given as
228  *	cl=^Z
229  * Much decoding is done on the strings, and the strings are
230  * placed in area, which is a ref parameter which is updated.
231  * No checking on area overflow.
232  */
233 static char *
234 dgetstr(id, area)
235 	char *id, **area;
236 {
237 	register char *bp = tbuf;
238 
239 	for (;;) {
240 		bp = dskip(bp);
241 		if (!*bp)
242 			return (0);
243 		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
244 			continue;
245 		if (*bp == '@')
246 			return (0);
247 		if (*bp != '=')
248 			continue;
249 		bp++;
250 		return (ddecode(bp, area));
251 	}
252 }
253 
254 /*
255  * Tdecode does the grung work to decode the
256  * string capability escapes.
257  */
258 static char *
259 ddecode(str, area)
260 	register char *str;
261 	char **area;
262 {
263 	register char *cp;
264 	register int c;
265 	register char *dp;
266 	int i;
267 
268 	cp = *area;
269 	while ((c = *str++) && c != ':') {
270 		switch (c) {
271 
272 		case '^':
273 			c = *str++ & 037;
274 			break;
275 
276 		case '\\':
277 			dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
278 			c = *str++;
279 nextc:
280 			if (*dp++ == c) {
281 				c = *dp++;
282 				break;
283 			}
284 			dp++;
285 			if (*dp)
286 				goto nextc;
287 			if (isdigit(c)) {
288 				c -= '0', i = 2;
289 				do
290 					c <<= 3, c |= *str++ - '0';
291 				while (--i && isdigit(*str));
292 			}
293 			break;
294 		}
295 		*cp++ = c;
296 	}
297 	*cp++ = 0;
298 	str = *area;
299 	*area = cp;
300 	return (str);
301 }
302