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