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