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