xref: /openbsd-src/sbin/fdisk/misc.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: misc.c,v 1.29 2012/07/11 10:27:34 krw 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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <err.h>
29 #include <stdio.h>
30 #include <ctype.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <sys/disklabel.h>
35 #include <limits.h>
36 #include "misc.h"
37 
38 struct unit_type unit_types[] = {
39 	{"b", 1			, "Bytes"},
40 	{" ", DEV_BSIZE		, "Sectors"},
41 	{"K", 1024		, "Kilobytes"},
42 	{"M", 1024 * 1024	, "Megabytes"},
43 	{"G", 1024 * 1024 *1024	, "Gigabytes"},
44 	{NULL, 0		, NULL },
45 };
46 
47 int
48 unit_lookup(char *units)
49 {
50 	int i = 0;
51 	if (units == NULL)
52 		return (UNIT_TYPE_DEFAULT);
53 
54 	while (unit_types[i].abbr != NULL) {
55 		if (strncasecmp(unit_types[i].abbr, units, 1) == 0)
56 			break;
57 		i++;
58 	}
59 	/* default */
60 	if (unit_types[i].abbr == NULL)
61 		return (UNIT_TYPE_DEFAULT);
62 
63 	return (i);
64 }
65 
66 int
67 ask_cmd(cmd_t *cmd)
68 {
69 	char lbuf[100], *cp, *buf;
70 	size_t lbuflen;
71 
72 	/* Get input */
73 	if (fgets(lbuf, sizeof lbuf, stdin) == NULL)
74 		errx(1, "eof");
75 	lbuflen = strlen(lbuf);
76 	if (lbuflen > 0 && lbuf[lbuflen - 1] == '\n')
77 		lbuf[lbuflen - 1] = '\0';
78 
79 	/* Parse input */
80 	buf = lbuf;
81 	buf = &buf[strspn(buf, " \t")];
82 	cp = &buf[strcspn(buf, " \t")];
83 	*cp++ = '\0';
84 	strncpy(cmd->cmd, buf, sizeof(cmd->cmd));
85 	buf = &cp[strspn(cp, " \t")];
86 	strncpy(cmd->args, buf, sizeof(cmd->args));
87 
88 	return (0);
89 }
90 
91 int
92 ask_num(const char *str, int dflt, int low, int high)
93 {
94 	char lbuf[100], *cp;
95 	const char *errstr;
96 	size_t lbuflen;
97 	int num;
98 
99 	if (dflt < low)
100 		dflt = low;
101 	else if (dflt > high)
102 		dflt = high;
103 
104 	do {
105 		printf("%s [%d - %d]: [%d] ", str, low, high, dflt);
106 
107 		if (fgets(lbuf, sizeof lbuf, stdin) == NULL)
108 			errx(1, "eof");
109 
110 		lbuflen = strlen(lbuf);
111 		if (lbuflen > 0 && lbuf[lbuflen - 1] == '\n')
112 			lbuf[lbuflen - 1] = '\0';
113 
114 		if (lbuf[0] == '\0') {
115 			num = dflt;
116 			errstr = NULL;
117 		} else {
118 			num = (int)strtonum(lbuf, low, high, &errstr);
119 			if (errstr)
120 				printf("%s is %s: %s.\n", str, errstr, lbuf);
121 		}
122 	} while (errstr);
123 
124 	return (num);
125 }
126 
127 int
128 ask_pid(int dflt)
129 {
130 	char lbuf[100], *cp;
131 	size_t lbuflen;
132 	int num;
133 	const int low = 0, high = 0xff;
134 
135 	if (dflt < low)
136 		dflt = low;
137 	else if (dflt > high)
138 		dflt = high;
139 
140 	do {
141 again:
142 		printf("Partition id ('0' to disable) [%X - %X]: [%X] ", low,
143 		    high, dflt);
144 		printf("(? for help) ");
145 
146 		if (fgets(lbuf, sizeof lbuf, stdin) == NULL)
147 			errx(1, "eof");
148 		lbuflen = strlen(lbuf);
149 		if (lbuflen > 0 && lbuf[lbuflen - 1] == '\n')
150 			lbuf[lbuflen - 1] = '\0';
151 
152 		if (lbuf[0] == '?') {
153 			PRT_printall();
154 			goto again;
155 		}
156 
157 		/* Convert */
158 		cp = lbuf;
159 		num = strtol(lbuf, &cp, 16);
160 
161 		/* Make sure only number present */
162 		if (cp == lbuf)
163 			num = dflt;
164 		if (*cp != '\0') {
165 			printf("'%s' is not a valid number.\n", lbuf);
166 			num = low - 1;
167 		} else if (num < low || num > high) {
168 			printf("'%x' is out of range.\n", num);
169 		}
170 	} while (num < low || num > high);
171 
172 	return (num);
173 }
174 
175 int
176 ask_yn(const char *str)
177 {
178 	int ch, first;
179 	extern int y_flag;
180 
181 	if (y_flag)
182 		return (1);
183 
184 	printf("%s [n] ", str);
185 	fflush(stdout);
186 
187 	first = ch = getchar();
188 	while (ch != '\n' && ch != EOF)
189 		ch = getchar();
190 
191 	if (ch == EOF || first == EOF)
192 		errx(1, "eof");
193 
194 	return (first == 'y' || first == 'Y');
195 }
196 
197 u_int16_t
198 getshort(void *p)
199 {
200 	unsigned char *cp = p;
201 
202 	return (cp[0] | (cp[1] << 8));
203 }
204 
205 void
206 putshort(void *p, u_int16_t l)
207 {
208 	unsigned char *cp = p;
209 
210 	*cp++ = l;
211 	*cp++ = l >> 8;
212 }
213 
214 u_int32_t
215 getlong(void *p)
216 {
217 	unsigned char *cp = p;
218 
219 	return (cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24));
220 }
221 
222 void
223 putlong(void *p, u_int32_t l)
224 {
225 	unsigned char *cp = p;
226 
227 	*cp++ = l;
228 	*cp++ = l >> 8;
229 	*cp++ = l >> 16;
230 	*cp++ = l >> 24;
231 }
232 
233 /*
234  * adapted from sbin/disklabel/editor.c
235  */
236 u_int32_t
237 getuint(disk_t *disk, char *prompt, u_int32_t oval, u_int32_t maxval)
238 {
239 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
240 	size_t n;
241 	int mult = 1, secsize = unit_types[SECTORS].conversion;
242 	double d, d2;
243 	int secpercyl, saveerr;
244 	char unit;
245 
246 	if (oval > maxval)
247 		oval = maxval;
248 
249 	secpercyl = disk->real->sectors * disk->real->heads;
250 
251 	do {
252 		printf("%s: [%u] ", prompt, oval);
253 
254 		if (fgets(buf, sizeof(buf), stdin) == NULL)
255 			errx(1, "eof");
256 
257 		n = strlen(buf);
258 		if (n > 0 && buf[n-1] == '\n')
259 			buf[--n] = '\0';
260 
261 		if (buf[0] == '\0') {
262 			return (oval);
263 		} else if (buf[0] == '*' && buf[1] == '\0') {
264 			return (maxval);
265 		}
266 
267 		/* deal with units */
268 		switch (tolower(buf[n-1])) {
269 		case 'c':
270 			unit = 'c';
271 			mult = secpercyl;
272 			buf[--n] = '\0';
273 			break;
274 		case 'b':
275 			unit = 'b';
276 			mult = -secsize;
277 			buf[--n] = '\0';
278 			break;
279 		case 's':
280 			unit = 's';
281 			mult = 1;
282 			buf[--n] = '\0';
283 			break;
284 		case 'k':
285 			unit = 'k';
286 			if (secsize > 1024)
287 				mult = -secsize / 1024;
288 			else
289 				mult = 1024 / secsize;
290 			buf[--n] = '\0';
291 			break;
292 		case 'm':
293 			unit = 'm';
294 			mult = 1048576 / secsize;
295 			buf[--n] = '\0';
296 			break;
297 		case 'g':
298 			unit = 'g';
299 			mult = 1073741824 / secsize;
300 			buf[--n] = '\0';
301 			break;
302 		default:
303 			unit = ' ';
304 			mult = 1;
305 			break;
306 		}
307 
308 		/* deal with the operator */
309 		p = &buf[0];
310 		if (*p == '+' || *p == '-')
311 			operator = *p++;
312 		else
313 			operator = ' ';
314 
315 		endptr = p;
316 		errno = 0;
317 		d = strtod(p, &endptr);
318 		saveerr = errno;
319 		d2 = d;
320 		if (mult > 0)
321 			d *= mult;
322 		else {
323 			d /= (-mult);
324 			d2 = d;
325 		}
326 
327 		/* Apply the operator */
328 		if (operator == '+')
329 			d = oval + d;
330 		else if (operator == '-') {
331 			d = oval - d;
332 			d2 = d;
333 		}
334 
335 		if (saveerr == ERANGE || d > maxval || d < 0 || d < d2) {
336 			printf("%s is out of range: %c%s%c\n", prompt, operator,
337 			    p, unit);
338 		} else if (*endptr != '\0') {
339 			printf("%s is invalid: %c%s%c\n", prompt, operator,
340 			    p, unit);
341 		} else {
342 			break;
343 		}
344 	} while (1);
345 
346 	return ((u_int32_t)d);
347 }
348