1 /* $OpenBSD: misc.c,v 1.63 2019/07/03 03:24:01 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Tobias Weingartner 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/disklabel.h> 21 22 #include <ctype.h> 23 #include <err.h> 24 #include <errno.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <uuid.h> 29 30 #include "disk.h" 31 #include "misc.h" 32 #include "part.h" 33 34 struct unit_type unit_types[] = { 35 { "b" , 1LL , "Bytes" }, 36 { " " , 0LL , "Sectors" }, 37 { "K" , 1024LL , "Kilobytes" }, 38 { "M" , 1024LL * 1024 , "Megabytes" }, 39 { "G" , 1024LL * 1024 *1024 , "Gigabytes" }, 40 { "T" , 1024LL * 1024 * 1024 * 1024 , "Terabytes" }, 41 { NULL , 0 , NULL }, 42 }; 43 44 int 45 unit_lookup(char *units) 46 { 47 int i = 0; 48 49 if (units == NULL) 50 return (SECTORS); 51 52 while (unit_types[i].abbr != NULL) { 53 if (strncasecmp(unit_types[i].abbr, units, 1) == 0) 54 break; 55 i++; 56 } 57 /* default */ 58 if (unit_types[i].abbr == NULL) 59 return (SECTORS); 60 61 return (i); 62 } 63 64 int 65 string_from_line(char *buf, size_t buflen) 66 { 67 char *line; 68 size_t sz; 69 70 line = fgetln(stdin, &sz); 71 if (line == NULL) 72 return (1); 73 74 if (line[sz - 1] == '\n') 75 sz--; 76 if (sz >= buflen) 77 sz = buflen - 1; 78 79 memcpy(buf, line, sz); 80 buf[sz] = '\0'; 81 82 return (0); 83 } 84 85 void 86 ask_cmd(char **cmd, char **arg) 87 { 88 static char lbuf[100]; 89 size_t cmdstart, cmdend, argstart; 90 91 /* Get NUL terminated string from stdin. */ 92 if (string_from_line(lbuf, sizeof(lbuf))) 93 errx(1, "eof"); 94 95 cmdstart = strspn(lbuf, " \t"); 96 cmdend = cmdstart + strcspn(&lbuf[cmdstart], " \t"); 97 argstart = cmdend + strspn(&lbuf[cmdend], " \t"); 98 99 /* *cmd and *arg may be set to point at final NUL! */ 100 *cmd = &lbuf[cmdstart]; 101 lbuf[cmdend] = '\0'; 102 *arg = &lbuf[argstart]; 103 } 104 105 int 106 ask_num(const char *str, int dflt, int low, int high) 107 { 108 char lbuf[100]; 109 const char *errstr; 110 int num; 111 112 if (dflt < low) 113 dflt = low; 114 else if (dflt > high) 115 dflt = high; 116 117 do { 118 printf("%s [%d - %d]: [%d] ", str, low, high, dflt); 119 120 if (string_from_line(lbuf, sizeof(lbuf))) 121 errx(1, "eof"); 122 123 if (lbuf[0] == '\0') { 124 num = dflt; 125 errstr = NULL; 126 } else { 127 num = (int)strtonum(lbuf, low, high, &errstr); 128 if (errstr) 129 printf("%s is %s: %s.\n", str, errstr, lbuf); 130 } 131 } while (errstr); 132 133 return (num); 134 } 135 136 int 137 ask_pid(int dflt, struct uuid *guid) 138 { 139 char lbuf[100], *cp; 140 int num = -1, status; 141 142 do { 143 printf("Partition id ('0' to disable) [01 - FF]: [%X] ", dflt); 144 printf("(? for help) "); 145 146 if (string_from_line(lbuf, sizeof(lbuf))) 147 errx(1, "eof"); 148 149 if (lbuf[0] == '?') { 150 PRT_printall(); 151 continue; 152 } 153 154 if (guid && strlen(lbuf) == UUID_STR_LEN) { 155 uuid_from_string(lbuf, guid, &status); 156 if (status == uuid_s_ok) 157 return (0x100); 158 } 159 160 /* Convert */ 161 cp = lbuf; 162 num = strtol(lbuf, &cp, 16); 163 164 /* Make sure only number present */ 165 if (cp == lbuf) 166 num = dflt; 167 if (*cp != '\0') { 168 printf("'%s' is not a valid number.\n", lbuf); 169 num = -1; 170 } else if (num == 0) { 171 break; 172 } else if (num < 0 || num > 0xff) { 173 printf("'%x' is out of range.\n", num); 174 } 175 } while (num < 0 || num > 0xff); 176 177 return (num); 178 } 179 180 int 181 ask_yn(const char *str) 182 { 183 int ch, first; 184 extern int y_flag; 185 186 if (y_flag) 187 return (1); 188 189 printf("%s [n] ", str); 190 fflush(stdout); 191 192 first = ch = getchar(); 193 while (ch != '\n' && ch != EOF) 194 ch = getchar(); 195 196 if (ch == EOF || first == EOF) 197 errx(1, "eof"); 198 199 return (first == 'y' || first == 'Y'); 200 } 201 202 /* 203 * adapted from sbin/disklabel/editor.c 204 */ 205 u_int64_t 206 getuint64(char *prompt, u_int64_t oval, u_int64_t minval, u_int64_t maxval) 207 { 208 const int secsize = unit_types[SECTORS].conversion; 209 char buf[BUFSIZ], *endptr, *p, operator = '\0'; 210 size_t n; 211 int64_t mult = 1; 212 double d, d2; 213 int rslt, secpercyl, saveerr; 214 char unit; 215 216 if (oval > maxval) 217 oval = maxval; 218 if (oval < minval) 219 oval = minval; 220 221 secpercyl = disk.sectors * disk.heads; 222 223 do { 224 printf("%s [%llu - %llu]: [%llu] ", prompt, minval, maxval, 225 oval); 226 227 if (string_from_line(buf, sizeof(buf))) 228 errx(1, "eof"); 229 230 if (buf[0] == '\0') { 231 rslt = snprintf(buf, sizeof(buf), "%llu", oval); 232 if (rslt < 0 || rslt >= sizeof(buf)) 233 errx(1, "default value too long"); 234 } else if (buf[0] == '*' && buf[1] == '\0') { 235 return (maxval); 236 } 237 238 /* deal with units */ 239 n = strlen(buf); 240 switch (tolower((unsigned char)buf[n-1])) { 241 case 'c': 242 unit = 'c'; 243 mult = secpercyl; 244 buf[--n] = '\0'; 245 break; 246 case 'b': 247 unit = 'b'; 248 mult = -(int64_t)secsize; 249 buf[--n] = '\0'; 250 break; 251 case 's': 252 unit = 's'; 253 mult = 1; 254 buf[--n] = '\0'; 255 break; 256 case 'k': 257 unit = 'k'; 258 if (secsize > 1024) 259 mult = -(int64_t)secsize / 1024LL; 260 else 261 mult = 1024LL / secsize; 262 buf[--n] = '\0'; 263 break; 264 case 'm': 265 unit = 'm'; 266 mult = (1024LL * 1024) / secsize; 267 buf[--n] = '\0'; 268 break; 269 case 'g': 270 unit = 'g'; 271 mult = (1024LL * 1024 * 1024) / secsize; 272 buf[--n] = '\0'; 273 break; 274 case 't': 275 unit = 't'; 276 mult = (1024LL * 1024 * 1024 * 1024) / secsize; 277 buf[--n] = '\0'; 278 break; 279 default: 280 unit = ' '; 281 mult = 1; 282 break; 283 } 284 285 /* deal with the operator */ 286 p = &buf[0]; 287 if (*p == '+' || *p == '-') 288 operator = *p++; 289 else 290 operator = ' '; 291 292 endptr = p; 293 errno = 0; 294 d = strtod(p, &endptr); 295 saveerr = errno; 296 d2 = d; 297 if (mult > 0) 298 d *= mult; 299 else { 300 d /= (-mult); 301 d2 = d; 302 } 303 304 /* Apply the operator */ 305 if (operator == '+') 306 d = oval + d; 307 else if (operator == '-') { 308 d = oval - d; 309 d2 = d; 310 } 311 312 if (saveerr == ERANGE || d > maxval || d < minval || d < d2) { 313 printf("%s is out of range: %c%s%c\n", prompt, operator, 314 p, unit); 315 } else if (*endptr != '\0') { 316 printf("%s is invalid: %c%s%c\n", prompt, operator, 317 p, unit); 318 } else { 319 break; 320 } 321 } while (1); 322 323 return((u_int64_t)d); 324 } 325 326 char * 327 ask_string(const char *prompt, const char *oval) 328 { 329 static char buf[37]; 330 331 buf[0] = '\0'; 332 printf("%s: [%s] ", prompt, oval ? oval : ""); 333 if (string_from_line(buf, sizeof(buf))) 334 errx(1, "eof"); 335 336 if (buf[0] == '\0' && oval) 337 strlcpy(buf, oval, sizeof(buf)); 338 339 return(buf); 340 } 341 342 /* 343 * Adapted from Hacker's Delight crc32b(). 344 * 345 * To quote http://www.hackersdelight.org/permissions.htm : 346 * 347 * "You are free to use, copy, and distribute any of the code on 348 * this web site, whether modified by you or not. You need not give 349 * attribution. This includes the algorithms (some of which appear 350 * in Hacker's Delight), the Hacker's Assistant, and any code submitted 351 * by readers. Submitters implicitly agree to this." 352 */ 353 u_int32_t 354 crc32(const u_char *buf, const u_int32_t size) 355 { 356 int j; 357 u_int32_t i, byte, crc, mask; 358 359 crc = 0xFFFFFFFF; 360 361 for (i = 0; i < size; i++) { 362 byte = buf[i]; /* Get next byte. */ 363 crc = crc ^ byte; 364 for (j = 7; j >= 0; j--) { /* Do eight times. */ 365 mask = -(crc & 1); 366 crc = (crc >> 1) ^ (0xEDB88320 & mask); 367 } 368 } 369 370 return ~crc; 371 } 372 373 char * 374 utf16le_to_string(u_int16_t *utf) 375 { 376 static char name[GPTPARTNAMESIZE]; 377 int i; 378 379 for (i = 0; i < GPTPARTNAMESIZE; i++) { 380 name[i] = letoh16(utf[i]) & 0x7F; 381 if (name[i] == '\0') 382 break; 383 } 384 if (i == GPTPARTNAMESIZE) 385 name[i - 1] = '\0'; 386 387 return (name); 388 } 389 390 u_int16_t * 391 string_to_utf16le(char *ch) 392 { 393 static u_int16_t utf[GPTPARTNAMESIZE]; 394 int i; 395 396 for (i = 0; i < GPTPARTNAMESIZE; i++) { 397 utf[i] = htole16((unsigned int)ch[i]); 398 if (utf[i] == 0) 399 break; 400 } 401 if (i == GPTPARTNAMESIZE) 402 utf[i - 1] = 0; 403 404 return (utf); 405 } 406