xref: /openbsd-src/sbin/fdisk/misc.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: misc.c,v 1.14 2003/07/29 18:38:35 deraadt 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 int
39 unit_lookup(char *units)
40 {
41 	int i = 0;
42 	if (units == NULL)
43 		return (UNIT_TYPE_DEFAULT);
44 
45 	while (unit_types[i].abbr != NULL) {
46 		if (strncasecmp(unit_types[i].abbr, units, 1) == 0)
47 			break;
48 		i++;
49 	}
50 	/* default */
51 	if (unit_types[i].abbr == NULL)
52 		return (UNIT_TYPE_DEFAULT);
53 
54 	return (i);
55 }
56 
57 int
58 ask_cmd(cmd_t *cmd)
59 {
60 	char lbuf[100], *cp, *buf;
61 
62 	/* Get input */
63 	if (fgets(lbuf, sizeof lbuf, stdin) == NULL)
64 		errx(1, "eof");
65 	lbuf[strlen(lbuf)-1] = '\0';
66 
67 	/* Parse input */
68 	buf = lbuf;
69 	buf = &buf[strspn(buf, " \t")];
70 	cp = &buf[strcspn(buf, " \t")];
71 	*cp++ = '\0';
72 	strncpy(cmd->cmd, buf, sizeof(cmd->cmd));
73 	buf = &cp[strspn(cp, " \t")];
74 	strncpy(cmd->args, buf, sizeof(cmd->args));
75 
76 	return (0);
77 }
78 
79 int
80 ask_num(const char *str, int flags, int dflt, int low, int high,
81     void (*help)(void))
82 {
83 	char lbuf[100], *cp;
84 	int num;
85 
86 	do {
87 again:
88 		num = dflt;
89 		if (flags == ASK_HEX)
90 			printf("%s [%X - %X]: [%X] ", str, low, high, num);
91 		else
92 			printf("%s [%d - %d]: [%d] ", str, low, high, num);
93 		if (help)
94 			printf("(? for help) ");
95 
96 		if (fgets(lbuf, sizeof lbuf, stdin) == NULL)
97 			errx(1, "eof");
98 		lbuf[strlen(lbuf)-1] = '\0';
99 
100 		if (help && lbuf[0] == '?') {
101 			(*help)();
102 			goto again;
103 		}
104 
105 		/* Convert */
106 		cp = lbuf;
107 		num = strtol(lbuf, &cp, ((flags==ASK_HEX)?16:10));
108 
109 		/* Make sure only number present */
110 		if (cp == lbuf)
111 			num = dflt;
112 		if (*cp != '\0') {
113 			printf("'%s' is not a valid number.\n", lbuf);
114 			num = low - 1;
115 		} else if (num < low || num > high) {
116 			printf("'%d' is out of range.\n", num);
117 		}
118 	} while (num < low || num > high);
119 
120 	return (num);
121 }
122 
123 int
124 ask_yn(const char *str)
125 {
126 	int ch, first;
127 
128 	printf("%s [n] ", str);
129 	fflush(stdout);
130 
131 	first = ch = getchar();
132 	while (ch != '\n' && ch != EOF)
133 		ch = getchar();
134 
135 	if (ch == EOF || first == EOF)
136 		errx(1, "eof");
137 
138 	return (first == 'y' || first == 'Y');
139 }
140 
141 u_int16_t
142 getshort(void *p)
143 {
144 	unsigned char *cp = p;
145 
146 	return (cp[0] | (cp[1] << 8));
147 }
148 
149 void
150 putshort(void *p, u_int16_t l)
151 {
152 	unsigned char *cp = p;
153 
154 	*cp++ = l;
155 	*cp++ = l >> 8;
156 }
157 
158 u_int32_t
159 getlong(void *p)
160 {
161 	unsigned char *cp = p;
162 
163 	return (cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24));
164 }
165 
166 void
167 putlong(void *p, u_int32_t l)
168 {
169 	unsigned char *cp = p;
170 
171 	*cp++ = l;
172 	*cp++ = l >> 8;
173 	*cp++ = l >> 16;
174 	*cp++ = l >> 24;
175 }
176 
177 /*
178  * adapted from sbin/disklabel/editor.c
179  * Returns UINT_MAX on error
180  */
181 u_int32_t
182 getuint(disk_t *disk, char *prompt, char *helpstring, u_int32_t oval,
183     u_int32_t maxval, u_int32_t offset,	int flags)
184 {
185 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
186 	u_int32_t rval = oval;
187 	size_t n;
188 	int mult = 1;
189 	double d;
190 	int secpercyl;
191 
192 	secpercyl = disk->real->sectors * disk->real->heads;
193 
194 	/* We only care about the remainder */
195 	offset = offset % secpercyl;
196 
197 	buf[0] = '\0';
198 	do {
199 		printf("%s: [%u] ", prompt, oval);
200 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
201 			buf[0] = '\0';
202 			if (feof(stdin)) {
203 				clearerr(stdin);
204 				putchar('\n');
205 				return(UINT_MAX - 1);
206 			}
207 		}
208 		n = strlen(buf);
209 		if (n > 0 && buf[n-1] == '\n')
210 			buf[--n] = '\0';
211 		if (buf[0] == '?')
212 			puts(helpstring);
213 	} while (buf[0] == '?');
214 
215 	if (buf[0] == '*' && buf[1] == '\0') {
216 		rval = maxval;
217 	} else {
218 		/* deal with units */
219 		if (buf[0] != '\0' && n > 0) {
220 			if ((flags & DO_CONVERSIONS)) {
221 				switch (tolower(buf[n-1])) {
222 
223 				case 'c':
224 					mult = secpercyl;
225 					buf[--n] = '\0';
226 					break;
227 				case 'b':
228 					mult = -DEV_BSIZE;
229 					buf[--n] = '\0';
230 					break;
231 				case 's':
232 					buf[--n] = '\0';
233 					break;
234 				case 'k':
235 					mult = 1024 / DEV_BSIZE;
236 					buf[--n] = '\0';
237 					break;
238 				case 'm':
239 					mult = 1048576 / DEV_BSIZE;
240 					buf[--n] = '\0';
241 					break;
242 				case 'g':
243 					mult = 1073741824 / DEV_BSIZE;
244 					buf[--n] = '\0';
245 					break;
246 				}
247 			}
248 
249 			/* Did they give us an operator? */
250 			p = &buf[0];
251 			if (*p == '+' || *p == '-')
252 				operator = *p++;
253 
254 			endptr = p;
255 			errno = 0;
256 			d = strtod(p, &endptr);
257 			if (errno == ERANGE)
258 				rval = UINT_MAX;	/* too big/small */
259 			else if (*endptr != '\0') {
260 				errno = EINVAL;		/* non-numbers in str */
261 				rval = UINT_MAX;
262 			} else {
263 				/* XXX - should check for overflow */
264 				if (mult > 0)
265 					rval = d * mult;
266 				else
267 					/* Negative mult means divide (fancy) */
268 					rval = d / (-mult);
269 
270 				/* Apply the operator */
271 				if (operator == '+')
272 					rval += oval;
273 				else if (operator == '-')
274 					rval = oval - rval;
275 			}
276 		}
277 	}
278 	if ((flags & DO_ROUNDING) && rval < UINT_MAX) {
279 #ifndef CYLCHECK
280 		/* Round to nearest cylinder unless given in sectors */
281 		if (mult != 1)
282 #endif
283 		{
284 			u_int32_t cyls;
285 
286 			/* If we round up past the end, round down instead */
287 			cyls = (u_int32_t)((rval / (double)secpercyl)
288 			    + 0.5);
289 			if (cyls != 0 && secpercyl != 0) {
290 				if ((cyls * secpercyl) - offset > maxval)
291 					cyls--;
292 
293 				if (rval != (cyls * secpercyl) - offset) {
294 					rval = (cyls * secpercyl) - offset;
295 					printf("Rounding to nearest cylinder: %u\n",
296 					    rval);
297 				}
298 			}
299 		}
300 	}
301 
302 	return(rval);
303 }
304