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