xref: /openbsd-src/sbin/fdisk/misc.c (revision 33b792a3c1c87b47219fdf9a73548c4003214de3)
1 /*	$OpenBSD: misc.c,v 1.10 2002/02/16 21:27:34 millert Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 Tobias Weingartner
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *    This product includes software developed by Tobias Weingartner.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <err.h>
34 #include <stdio.h>
35 #include <ctype.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <sys/disklabel.h>
40 #include <machine/limits.h>
41 #include "misc.h"
42 
43 int
44 unit_lookup(units)
45 	char *units;
46 {
47 	int i = 0;
48 	if (units == NULL)
49 		return (UNIT_TYPE_DEFAULT);
50 
51 	while (unit_types[i].abbr != NULL) {
52 		if (strncasecmp(unit_types[i].abbr, units, 1) == 0)
53 			break;
54 		i++;
55 	}
56 	/* default */
57 	if (unit_types[i].abbr == NULL)
58 		return (UNIT_TYPE_DEFAULT);
59 
60 	return (i);
61 }
62 
63 int
64 ask_cmd(cmd)
65 	cmd_t *cmd;
66 {
67 	char lbuf[100], *cp, *buf;
68 
69 	/* Get input */
70 	if (fgets(lbuf, sizeof lbuf, stdin) == NULL)
71 		errx(1, "eof");
72 	lbuf[strlen(lbuf)-1] = '\0';
73 
74 	/* Parse input */
75 	buf = lbuf;
76 	buf = &buf[strspn(buf, " \t")];
77 	cp = &buf[strcspn(buf, " \t")];
78 	*cp++ = '\0';
79 	strncpy(cmd->cmd, buf, sizeof(cmd->cmd));
80 	buf = &cp[strspn(cp, " \t")];
81 	strncpy(cmd->args, buf, sizeof(cmd->args));
82 
83 	return (0);
84 }
85 
86 int
87 ask_num(str, flags, dflt, low, high, help)
88 	const char *str;
89 	int flags;
90 	int dflt;
91 	int low;
92 	int high;
93 	void (*help)(void);
94 {
95 	char lbuf[100], *cp;
96 	int num;
97 
98 	do {
99 again:
100 		num = dflt;
101 		if (flags == ASK_HEX)
102 			printf("%s [%X - %X]: [%X] ", str, low, high, num);
103 		else
104 			printf("%s [%d - %d]: [%d] ", str, low, high, num);
105 		if (help)
106 			printf("(? for help) ");
107 
108 		if (fgets(lbuf, sizeof lbuf, stdin) == NULL)
109 			errx(1, "eof");
110 		lbuf[strlen(lbuf)-1] = '\0';
111 
112 		if (help && lbuf[0] == '?') {
113 			(*help)();
114 			goto again;
115 		}
116 
117 		/* Convert */
118 		cp = lbuf;
119 		num = strtol(lbuf, &cp, ((flags==ASK_HEX)?16:10));
120 
121 		/* Make sure only number present */
122 		if (cp == lbuf)
123 			num = dflt;
124 		if (*cp != '\0') {
125 			printf("'%s' is not a valid number.\n", lbuf);
126 			num = low - 1;
127 		} else if (num < low || num > high) {
128 			printf("'%d' is out of range.\n", num);
129 		}
130 	} while (num < low || num > high);
131 
132 	return (num);
133 }
134 
135 int
136 ask_yn(str)
137 	const char *str;
138 {
139 	int ch, first;
140 
141 	printf("%s [n] ", str);
142 	fflush(stdout);
143 
144 	first = ch = getchar();
145 	while (ch != '\n' && ch != EOF)
146 		ch = getchar();
147 
148 	if (ch == EOF || first == EOF)
149 		errx(1, "eof");
150 
151 	return (first == 'y' || first == 'Y');
152 }
153 
154 u_int16_t
155 getshort(p)
156 	void *p;
157 {
158 	unsigned char *cp = p;
159 
160 	return (cp[0] | (cp[1] << 8));
161 }
162 
163 void
164 putshort(p, l)
165 	void *p;
166 	u_int16_t l;
167 {
168 	unsigned char *cp = p;
169 
170 	*cp++ = l;
171 	*cp++ = l >> 8;
172 }
173 
174 u_int32_t
175 getlong(p)
176 	void *p;
177 {
178 	unsigned char *cp = p;
179 
180 	return (cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24));
181 }
182 
183 void
184 putlong(p, l)
185 	void *p;
186 	u_int32_t l;
187 {
188 	unsigned char *cp = p;
189 
190 	*cp++ = l;
191 	*cp++ = l >> 8;
192 	*cp++ = l >> 16;
193 	*cp++ = l >> 24;
194 }
195 
196 /*
197  * adapted from sbin/disklabel/editor.c
198  * Returns UINT_MAX on error
199  */
200 u_int32_t
201 getuint(disk, prompt, helpstring, oval, maxval, offset, flags)
202 	disk_t *disk;
203 	char *prompt;
204 	char *helpstring;
205 	u_int32_t oval;
206 	u_int32_t maxval;
207 	u_int32_t offset;
208 	int flags;
209 {
210 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
211 	u_int32_t rval = oval;
212 	size_t n;
213 	int mult = 1;
214 	double d;
215 	int secpercyl;
216 
217 	secpercyl = disk->real->sectors * disk->real->heads;
218 
219 	/* We only care about the remainder */
220 	offset = offset % secpercyl;
221 
222 	buf[0] = '\0';
223 	do {
224 		printf("%s: [%u] ", prompt, oval);
225 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
226 			buf[0] = '\0';
227 			if (feof(stdin)) {
228 				clearerr(stdin);
229 				putchar('\n');
230 				return(UINT_MAX - 1);
231 			}
232 		}
233 		n = strlen(buf);
234 		if (n > 0 && buf[n-1] == '\n')
235 			buf[--n] = '\0';
236 		if (buf[0] == '?')
237 			puts(helpstring);
238 	} while (buf[0] == '?');
239 
240 	if (buf[0] == '*' && buf[1] == '\0') {
241 		rval = maxval;
242 	} else {
243 		/* deal with units */
244 		if (buf[0] != '\0' && n > 0) {
245 			if ((flags & DO_CONVERSIONS)) {
246 				switch (tolower(buf[n-1])) {
247 
248 				case 'c':
249 					mult = secpercyl;
250 					buf[--n] = '\0';
251 					break;
252 				case 'b':
253 					mult = -DEV_BSIZE;
254 					buf[--n] = '\0';
255 					break;
256 				case 's':
257 					buf[--n] = '\0';
258 					break;
259 				case 'k':
260 					mult = 1024 / DEV_BSIZE;
261 					buf[--n] = '\0';
262 					break;
263 				case 'm':
264 					mult = 1048576 / DEV_BSIZE;
265 					buf[--n] = '\0';
266 					break;
267 				case 'g':
268 					mult = 1073741824 / DEV_BSIZE;
269 					buf[--n] = '\0';
270 					break;
271 				}
272 			}
273 
274 			/* Did they give us an operator? */
275 			p = &buf[0];
276 			if (*p == '+' || *p == '-')
277 				operator = *p++;
278 
279 			endptr = p;
280 			errno = 0;
281 			d = strtod(p, &endptr);
282 			if (errno == ERANGE)
283 				rval = UINT_MAX;	/* too big/small */
284 			else if (*endptr != '\0') {
285 				errno = EINVAL;		/* non-numbers in str */
286 				rval = UINT_MAX;
287 			} else {
288 				/* XXX - should check for overflow */
289 				if (mult > 0)
290 					rval = d * mult;
291 				else
292 					/* Negative mult means divide (fancy) */
293 					rval = d / (-mult);
294 
295 				/* Apply the operator */
296 				if (operator == '+')
297 					rval += oval;
298 				else if (operator == '-')
299 					rval = oval - rval;
300 			}
301 		}
302 	}
303 	if ((flags & DO_ROUNDING) && rval < UINT_MAX) {
304 #ifndef CYLCHECK
305 		/* Round to nearest cylinder unless given in sectors */
306 		if (mult != 1)
307 #endif
308 		{
309 			u_int32_t cyls;
310 
311 			/* If we round up past the end, round down instead */
312 			cyls = (u_int32_t)((rval / (double)secpercyl)
313 			    + 0.5);
314 			if (cyls != 0 && secpercyl != 0) {
315 				if ((cyls * secpercyl) - offset > maxval)
316 					cyls--;
317 
318 				if (rval != (cyls * secpercyl) - offset) {
319 					rval = (cyls * secpercyl) - offset;
320 					printf("Rounding to nearest cylinder: %u\n",
321 					    rval);
322 				}
323 			}
324 		}
325 	}
326 
327 	return(rval);
328 }
329