xref: /openbsd-src/sbin/fdisk/misc.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: misc.c,v 1.21 2009/04/07 16:06:37 weingart 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 flags, int dflt, int low, int high,
93     void (*help)(void))
94 {
95 	char lbuf[100], *cp;
96 	size_t lbuflen;
97 	int num;
98 
99 	do {
100 again:
101 		if (dflt < low)
102 			num = low;
103 		else if (dflt > high)
104 			num = high;
105 		else
106 			num = dflt;
107 		if (flags == ASK_HEX)
108 			printf("%s [%X - %X]: [%X] ", str, low, high, num);
109 		else
110 			printf("%s [%d - %d]: [%d] ", str, low, high, num);
111 		if (help)
112 			printf("(? for help) ");
113 
114 		if (fgets(lbuf, sizeof lbuf, stdin) == NULL)
115 			errx(1, "eof");
116 		lbuflen = strlen(lbuf);
117 		if (lbuflen > 0 && lbuf[lbuflen - 1] == '\n')
118 			lbuf[lbuflen - 1] = '\0';
119 
120 		if (help && lbuf[0] == '?') {
121 			(*help)();
122 			goto again;
123 		}
124 
125 		/* Convert */
126 		cp = lbuf;
127 		num = strtol(lbuf, &cp, ((flags==ASK_HEX)?16:10));
128 
129 		/* Make sure only number present */
130 		if (cp == lbuf)
131 			num = dflt;
132 		if (*cp != '\0') {
133 			printf("'%s' is not a valid number.\n", lbuf);
134 			num = low - 1;
135 		} else if (num < low || num > high) {
136 			printf("'%d' is out of range.\n", num);
137 		}
138 	} while (num < low || num > high);
139 
140 	return (num);
141 }
142 
143 int
144 ask_yn(const char *str)
145 {
146 	int ch, first;
147 	extern int y_flag;
148 
149 	if (y_flag)
150 		return (1);
151 
152 	printf("%s [n] ", str);
153 	fflush(stdout);
154 
155 	first = ch = getchar();
156 	while (ch != '\n' && ch != EOF)
157 		ch = getchar();
158 
159 	if (ch == EOF || first == EOF)
160 		errx(1, "eof");
161 
162 	return (first == 'y' || first == 'Y');
163 }
164 
165 u_int16_t
166 getshort(void *p)
167 {
168 	unsigned char *cp = p;
169 
170 	return (cp[0] | (cp[1] << 8));
171 }
172 
173 void
174 putshort(void *p, u_int16_t l)
175 {
176 	unsigned char *cp = p;
177 
178 	*cp++ = l;
179 	*cp++ = l >> 8;
180 }
181 
182 u_int32_t
183 getlong(void *p)
184 {
185 	unsigned char *cp = p;
186 
187 	return (cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24));
188 }
189 
190 void
191 putlong(void *p, u_int32_t l)
192 {
193 	unsigned char *cp = p;
194 
195 	*cp++ = l;
196 	*cp++ = l >> 8;
197 	*cp++ = l >> 16;
198 	*cp++ = l >> 24;
199 }
200 
201 /*
202  * adapted from sbin/disklabel/editor.c
203  * Returns UINT_MAX on error
204  */
205 u_int32_t
206 getuint(disk_t *disk, char *prompt, char *helpstring, u_int32_t oval,
207     u_int32_t maxval, u_int32_t offset,	int flags)
208 {
209 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
210 	u_int32_t rval = oval;
211 	size_t n;
212 	int mult = 1, secsize = unit_types[SECTORS].conversion;
213 	double d;
214 	int secpercyl;
215 
216 	secpercyl = disk->real->sectors * disk->real->heads;
217 
218 	/* We only care about the remainder */
219 	offset = offset % secpercyl;
220 
221 	buf[0] = '\0';
222 	do {
223 		printf("%s: [%u] ", prompt, oval);
224 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
225 			buf[0] = '\0';
226 			if (feof(stdin)) {
227 				clearerr(stdin);
228 				putchar('\n');
229 				return(UINT_MAX - 1);
230 			}
231 		}
232 		n = strlen(buf);
233 		if (n > 0 && buf[n-1] == '\n')
234 			buf[--n] = '\0';
235 		if (buf[0] == '?')
236 			puts(helpstring);
237 	} while (buf[0] == '?');
238 
239 	if (buf[0] == '*' && buf[1] == '\0') {
240 		rval = maxval;
241 	} else {
242 		/* deal with units */
243 		if (buf[0] != '\0' && n > 0) {
244 			if ((flags & DO_CONVERSIONS)) {
245 				switch (tolower(buf[n-1])) {
246 
247 				case 'c':
248 					mult = secpercyl;
249 					buf[--n] = '\0';
250 					break;
251 				case 'b':
252 					mult = -secsize;
253 					buf[--n] = '\0';
254 					break;
255 				case 's':
256 					buf[--n] = '\0';
257 					break;
258 				case 'k':
259 					if (secsize > 1024)
260 						mult = -secsize / 1024;
261 					else
262 						mult = 1024 / secsize;
263 					buf[--n] = '\0';
264 					break;
265 				case 'm':
266 					mult = 1048576 / secsize;
267 					buf[--n] = '\0';
268 					break;
269 				case 'g':
270 					mult = 1073741824 / secsize;
271 					buf[--n] = '\0';
272 					break;
273 				}
274 			}
275 
276 			/* Did they give us an operator? */
277 			p = &buf[0];
278 			if (*p == '+' || *p == '-')
279 				operator = *p++;
280 
281 			endptr = p;
282 			errno = 0;
283 			d = strtod(p, &endptr);
284 			if (errno == ERANGE)
285 				rval = UINT_MAX;	/* too big/small */
286 			else if (*endptr != '\0') {
287 				errno = EINVAL;		/* non-numbers in str */
288 				rval = UINT_MAX;
289 			} else {
290 				/* XXX - should check for overflow */
291 				if (mult > 0)
292 					rval = d * mult;
293 				else
294 					/* Negative mult means divide (fancy) */
295 					rval = d / (-mult);
296 
297 				/* Apply the operator */
298 				if (operator == '+')
299 					rval += oval;
300 				else if (operator == '-')
301 					rval = oval - rval;
302 			}
303 		}
304 	}
305 	if ((flags & DO_ROUNDING) && rval < UINT_MAX) {
306 #ifndef CYLCHECK
307 		/* Round to nearest cylinder unless given in sectors */
308 		if (mult != 1)
309 #endif
310 		{
311 			u_int32_t cyls;
312 
313 			/* If we round up past the end, round down instead */
314 			cyls = (u_int32_t)((rval / (double)secpercyl)
315 			    + 0.5);
316 			if (cyls != 0 && secpercyl != 0) {
317 				if ((cyls * secpercyl) - offset > maxval)
318 					cyls--;
319 
320 				if (rval != (cyls * secpercyl) - offset) {
321 					rval = (cyls * secpercyl) - offset;
322 					printf("Rounding to nearest cylinder: %u\n",
323 					    rval);
324 				}
325 			}
326 		}
327 	}
328 
329 	return(rval);
330 }
331