xref: /openbsd-src/sbin/fdisk/misc.c (revision e5157e49389faebcb42b7237d55fbf096d9c2523)
1 /*	$OpenBSD: misc.c,v 1.42 2014/03/31 19:50:52 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 <sys/types.h>
29 #include <sys/disklabel.h>
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <err.h>
35 #include <errno.h>
36 
37 #include "disk.h"
38 #include "misc.h"
39 #include "part.h"
40 
41 struct unit_type unit_types[] = {
42 	{"b", 1			, "Bytes"},
43 	{" ", 0			, "Sectors"},	/* Filled in from disklabel. */
44 	{"K", 1024		, "Kilobytes"},
45 	{"M", 1024 * 1024	, "Megabytes"},
46 	{"G", 1024 * 1024 *1024	, "Gigabytes"},
47 	{NULL, 0		, NULL },
48 };
49 
50 int
51 unit_lookup(char *units)
52 {
53 	int i = 0;
54 	if (units == NULL)
55 		return (SECTORS);
56 
57 	while (unit_types[i].abbr != NULL) {
58 		if (strncasecmp(unit_types[i].abbr, units, 1) == 0)
59 			break;
60 		i++;
61 	}
62 	/* default */
63 	if (unit_types[i].abbr == NULL)
64 		return (SECTORS);
65 
66 	return (i);
67 }
68 
69 int
70 ask_cmd(char **cmd, char **args)
71 {
72 	static char lbuf[100];
73 	char *cp, *buf;
74 	size_t lbuflen;
75 
76 	/* Get input */
77 	if (fgets(lbuf, sizeof lbuf, stdin) == NULL)
78 		errx(1, "eof");
79 	lbuflen = strlen(lbuf);
80 	if (lbuflen > 0 && lbuf[lbuflen - 1] == '\n')
81 		lbuf[lbuflen - 1] = '\0';
82 
83 	/* Parse input */
84 	buf = lbuf;
85 	buf = &buf[strspn(buf, " \t")];
86 	cp = &buf[strcspn(buf, " \t")];
87 	*cp++ = '\0';
88 	*cmd = buf;
89 	*args = &cp[strspn(cp, " \t")];
90 
91 	return (0);
92 }
93 
94 int
95 ask_num(const char *str, int dflt, int low, int high)
96 {
97 	char lbuf[100];
98 	const char *errstr;
99 	size_t lbuflen;
100 	int num;
101 
102 	if (dflt < low)
103 		dflt = low;
104 	else if (dflt > high)
105 		dflt = high;
106 
107 	do {
108 		printf("%s [%d - %d]: [%d] ", str, low, high, dflt);
109 
110 		if (fgets(lbuf, sizeof lbuf, stdin) == NULL)
111 			errx(1, "eof");
112 
113 		lbuflen = strlen(lbuf);
114 		if (lbuflen > 0 && lbuf[lbuflen - 1] == '\n')
115 			lbuf[lbuflen - 1] = '\0';
116 
117 		if (lbuf[0] == '\0') {
118 			num = dflt;
119 			errstr = NULL;
120 		} else {
121 			num = (int)strtonum(lbuf, low, high, &errstr);
122 			if (errstr)
123 				printf("%s is %s: %s.\n", str, errstr, lbuf);
124 		}
125 	} while (errstr);
126 
127 	return (num);
128 }
129 
130 int
131 ask_pid(int dflt)
132 {
133 	char lbuf[100], *cp;
134 	size_t lbuflen;
135 	int num = -1;
136 	const int low = 0, high = 0xff;
137 
138 	if (dflt < low)
139 		dflt = low;
140 	else if (dflt > high)
141 		dflt = high;
142 
143 	do {
144 		printf("Partition id ('0' to disable) [%X - %X]: [%X] ", low,
145 		    high, dflt);
146 		printf("(? for help) ");
147 
148 		if (fgets(lbuf, sizeof lbuf, stdin) == NULL)
149 			errx(1, "eof");
150 		lbuflen = strlen(lbuf);
151 		if (lbuflen > 0 && lbuf[lbuflen - 1] == '\n')
152 			lbuf[lbuflen - 1] = '\0';
153 
154 		if (lbuf[0] == '?') {
155 			PRT_printall();
156 			continue;
157 		}
158 
159 		/* Convert */
160 		cp = lbuf;
161 		num = strtol(lbuf, &cp, 16);
162 
163 		/* Make sure only number present */
164 		if (cp == lbuf)
165 			num = dflt;
166 		if (*cp != '\0') {
167 			printf("'%s' is not a valid number.\n", lbuf);
168 			num = low - 1;
169 		} else if (num < low || num > high) {
170 			printf("'%x' is out of range.\n", num);
171 		}
172 	} while (num < low || num > high);
173 
174 	return (num);
175 }
176 
177 int
178 ask_yn(const char *str)
179 {
180 	int ch, first;
181 	extern int y_flag;
182 
183 	if (y_flag)
184 		return (1);
185 
186 	printf("%s [n] ", str);
187 	fflush(stdout);
188 
189 	first = ch = getchar();
190 	while (ch != '\n' && ch != EOF)
191 		ch = getchar();
192 
193 	if (ch == EOF || first == EOF)
194 		errx(1, "eof");
195 
196 	return (first == 'y' || first == 'Y');
197 }
198 
199 /*
200  * adapted from sbin/disklabel/editor.c
201  */
202 u_int32_t
203 getuint(struct disk *disk, char *prompt, u_int32_t oval, u_int32_t maxval)
204 {
205 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
206 	size_t n;
207 	int mult = 1, secsize = unit_types[SECTORS].conversion;
208 	double d, d2;
209 	int secpercyl, saveerr;
210 	char unit;
211 
212 	if (oval > maxval)
213 		oval = maxval;
214 
215 	secpercyl = disk->sectors * disk->heads;
216 
217 	do {
218 		printf("%s: [%u] ", prompt, oval);
219 
220 		if (fgets(buf, sizeof(buf), stdin) == NULL)
221 			errx(1, "eof");
222 
223 		n = strlen(buf);
224 		if (n > 0 && buf[n-1] == '\n')
225 			buf[--n] = '\0';
226 
227 		if (buf[0] == '\0') {
228 			return (oval);
229 		} else if (buf[0] == '*' && buf[1] == '\0') {
230 			return (maxval);
231 		}
232 
233 		/* deal with units */
234 		switch (tolower((unsigned char)buf[n-1])) {
235 		case 'c':
236 			unit = 'c';
237 			mult = secpercyl;
238 			buf[--n] = '\0';
239 			break;
240 		case 'b':
241 			unit = 'b';
242 			mult = -secsize;
243 			buf[--n] = '\0';
244 			break;
245 		case 's':
246 			unit = 's';
247 			mult = 1;
248 			buf[--n] = '\0';
249 			break;
250 		case 'k':
251 			unit = 'k';
252 			if (secsize > 1024)
253 				mult = -secsize / 1024;
254 			else
255 				mult = 1024 / secsize;
256 			buf[--n] = '\0';
257 			break;
258 		case 'm':
259 			unit = 'm';
260 			mult = 1048576 / secsize;
261 			buf[--n] = '\0';
262 			break;
263 		case 'g':
264 			unit = 'g';
265 			mult = 1073741824 / secsize;
266 			buf[--n] = '\0';
267 			break;
268 		default:
269 			unit = ' ';
270 			mult = 1;
271 			break;
272 		}
273 
274 		/* deal with the operator */
275 		p = &buf[0];
276 		if (*p == '+' || *p == '-')
277 			operator = *p++;
278 		else
279 			operator = ' ';
280 
281 		endptr = p;
282 		errno = 0;
283 		d = strtod(p, &endptr);
284 		saveerr = errno;
285 		d2 = d;
286 		if (mult > 0)
287 			d *= mult;
288 		else {
289 			d /= (-mult);
290 			d2 = d;
291 		}
292 
293 		/* Apply the operator */
294 		if (operator == '+')
295 			d = oval + d;
296 		else if (operator == '-') {
297 			d = oval - d;
298 			d2 = d;
299 		}
300 
301 		if (saveerr == ERANGE || d > maxval || d < 0 || d < d2) {
302 			printf("%s is out of range: %c%s%c\n", prompt, operator,
303 			    p, unit);
304 		} else if (*endptr != '\0') {
305 			printf("%s is invalid: %c%s%c\n", prompt, operator,
306 			    p, unit);
307 		} else {
308 			break;
309 		}
310 	} while (1);
311 
312 	return ((u_int32_t)d);
313 }
314