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