1 /* $OpenBSD: misc.c,v 1.64 2021/01/31 14:24:47 naddy 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 static char *line; 68 static size_t sz; 69 ssize_t len; 70 71 len = getline(&line, &sz, stdin); 72 if (len == -1) 73 return (1); 74 75 if (line[len - 1] == '\n') 76 line[len - 1] = '\0'; 77 78 strlcpy(buf, line, buflen); 79 80 return (0); 81 } 82 83 void 84 ask_cmd(char **cmd, char **arg) 85 { 86 static char lbuf[100]; 87 size_t cmdstart, cmdend, argstart; 88 89 /* Get NUL terminated string from stdin. */ 90 if (string_from_line(lbuf, sizeof(lbuf))) 91 errx(1, "eof"); 92 93 cmdstart = strspn(lbuf, " \t"); 94 cmdend = cmdstart + strcspn(&lbuf[cmdstart], " \t"); 95 argstart = cmdend + strspn(&lbuf[cmdend], " \t"); 96 97 /* *cmd and *arg may be set to point at final NUL! */ 98 *cmd = &lbuf[cmdstart]; 99 lbuf[cmdend] = '\0'; 100 *arg = &lbuf[argstart]; 101 } 102 103 int 104 ask_num(const char *str, int dflt, int low, int high) 105 { 106 char lbuf[100]; 107 const char *errstr; 108 int num; 109 110 if (dflt < low) 111 dflt = low; 112 else if (dflt > high) 113 dflt = high; 114 115 do { 116 printf("%s [%d - %d]: [%d] ", str, low, high, dflt); 117 118 if (string_from_line(lbuf, sizeof(lbuf))) 119 errx(1, "eof"); 120 121 if (lbuf[0] == '\0') { 122 num = dflt; 123 errstr = NULL; 124 } else { 125 num = (int)strtonum(lbuf, low, high, &errstr); 126 if (errstr) 127 printf("%s is %s: %s.\n", str, errstr, lbuf); 128 } 129 } while (errstr); 130 131 return (num); 132 } 133 134 int 135 ask_pid(int dflt, struct uuid *guid) 136 { 137 char lbuf[100], *cp; 138 int num = -1, status; 139 140 do { 141 printf("Partition id ('0' to disable) [01 - FF]: [%X] ", dflt); 142 printf("(? for help) "); 143 144 if (string_from_line(lbuf, sizeof(lbuf))) 145 errx(1, "eof"); 146 147 if (lbuf[0] == '?') { 148 PRT_printall(); 149 continue; 150 } 151 152 if (guid && strlen(lbuf) == UUID_STR_LEN) { 153 uuid_from_string(lbuf, guid, &status); 154 if (status == uuid_s_ok) 155 return (0x100); 156 } 157 158 /* Convert */ 159 cp = lbuf; 160 num = strtol(lbuf, &cp, 16); 161 162 /* Make sure only number present */ 163 if (cp == lbuf) 164 num = dflt; 165 if (*cp != '\0') { 166 printf("'%s' is not a valid number.\n", lbuf); 167 num = -1; 168 } else if (num == 0) { 169 break; 170 } else if (num < 0 || num > 0xff) { 171 printf("'%x' is out of range.\n", num); 172 } 173 } while (num < 0 || num > 0xff); 174 175 return (num); 176 } 177 178 int 179 ask_yn(const char *str) 180 { 181 int ch, first; 182 extern int y_flag; 183 184 if (y_flag) 185 return (1); 186 187 printf("%s [n] ", str); 188 fflush(stdout); 189 190 first = ch = getchar(); 191 while (ch != '\n' && ch != EOF) 192 ch = getchar(); 193 194 if (ch == EOF || first == EOF) 195 errx(1, "eof"); 196 197 return (first == 'y' || first == 'Y'); 198 } 199 200 /* 201 * adapted from sbin/disklabel/editor.c 202 */ 203 u_int64_t 204 getuint64(char *prompt, u_int64_t oval, u_int64_t minval, u_int64_t maxval) 205 { 206 const int secsize = unit_types[SECTORS].conversion; 207 char buf[BUFSIZ], *endptr, *p, operator = '\0'; 208 size_t n; 209 int64_t mult = 1; 210 double d, d2; 211 int rslt, secpercyl, saveerr; 212 char unit; 213 214 if (oval > maxval) 215 oval = maxval; 216 if (oval < minval) 217 oval = minval; 218 219 secpercyl = disk.sectors * disk.heads; 220 221 do { 222 printf("%s [%llu - %llu]: [%llu] ", prompt, minval, maxval, 223 oval); 224 225 if (string_from_line(buf, sizeof(buf))) 226 errx(1, "eof"); 227 228 if (buf[0] == '\0') { 229 rslt = snprintf(buf, sizeof(buf), "%llu", oval); 230 if (rslt < 0 || rslt >= sizeof(buf)) 231 errx(1, "default value too long"); 232 } else if (buf[0] == '*' && buf[1] == '\0') { 233 return (maxval); 234 } 235 236 /* deal with units */ 237 n = strlen(buf); 238 switch (tolower((unsigned char)buf[n-1])) { 239 case 'c': 240 unit = 'c'; 241 mult = secpercyl; 242 buf[--n] = '\0'; 243 break; 244 case 'b': 245 unit = 'b'; 246 mult = -(int64_t)secsize; 247 buf[--n] = '\0'; 248 break; 249 case 's': 250 unit = 's'; 251 mult = 1; 252 buf[--n] = '\0'; 253 break; 254 case 'k': 255 unit = 'k'; 256 if (secsize > 1024) 257 mult = -(int64_t)secsize / 1024LL; 258 else 259 mult = 1024LL / secsize; 260 buf[--n] = '\0'; 261 break; 262 case 'm': 263 unit = 'm'; 264 mult = (1024LL * 1024) / secsize; 265 buf[--n] = '\0'; 266 break; 267 case 'g': 268 unit = 'g'; 269 mult = (1024LL * 1024 * 1024) / secsize; 270 buf[--n] = '\0'; 271 break; 272 case 't': 273 unit = 't'; 274 mult = (1024LL * 1024 * 1024 * 1024) / secsize; 275 buf[--n] = '\0'; 276 break; 277 default: 278 unit = ' '; 279 mult = 1; 280 break; 281 } 282 283 /* deal with the operator */ 284 p = &buf[0]; 285 if (*p == '+' || *p == '-') 286 operator = *p++; 287 else 288 operator = ' '; 289 290 endptr = p; 291 errno = 0; 292 d = strtod(p, &endptr); 293 saveerr = errno; 294 d2 = d; 295 if (mult > 0) 296 d *= mult; 297 else { 298 d /= (-mult); 299 d2 = d; 300 } 301 302 /* Apply the operator */ 303 if (operator == '+') 304 d = oval + d; 305 else if (operator == '-') { 306 d = oval - d; 307 d2 = d; 308 } 309 310 if (saveerr == ERANGE || d > maxval || d < minval || d < d2) { 311 printf("%s is out of range: %c%s%c\n", prompt, operator, 312 p, unit); 313 } else if (*endptr != '\0') { 314 printf("%s is invalid: %c%s%c\n", prompt, operator, 315 p, unit); 316 } else { 317 break; 318 } 319 } while (1); 320 321 return((u_int64_t)d); 322 } 323 324 char * 325 ask_string(const char *prompt, const char *oval) 326 { 327 static char buf[37]; 328 329 buf[0] = '\0'; 330 printf("%s: [%s] ", prompt, oval ? oval : ""); 331 if (string_from_line(buf, sizeof(buf))) 332 errx(1, "eof"); 333 334 if (buf[0] == '\0' && oval) 335 strlcpy(buf, oval, sizeof(buf)); 336 337 return(buf); 338 } 339 340 /* 341 * Adapted from Hacker's Delight crc32b(). 342 * 343 * To quote http://www.hackersdelight.org/permissions.htm : 344 * 345 * "You are free to use, copy, and distribute any of the code on 346 * this web site, whether modified by you or not. You need not give 347 * attribution. This includes the algorithms (some of which appear 348 * in Hacker's Delight), the Hacker's Assistant, and any code submitted 349 * by readers. Submitters implicitly agree to this." 350 */ 351 u_int32_t 352 crc32(const u_char *buf, const u_int32_t size) 353 { 354 int j; 355 u_int32_t i, byte, crc, mask; 356 357 crc = 0xFFFFFFFF; 358 359 for (i = 0; i < size; i++) { 360 byte = buf[i]; /* Get next byte. */ 361 crc = crc ^ byte; 362 for (j = 7; j >= 0; j--) { /* Do eight times. */ 363 mask = -(crc & 1); 364 crc = (crc >> 1) ^ (0xEDB88320 & mask); 365 } 366 } 367 368 return ~crc; 369 } 370 371 char * 372 utf16le_to_string(u_int16_t *utf) 373 { 374 static char name[GPTPARTNAMESIZE]; 375 int i; 376 377 for (i = 0; i < GPTPARTNAMESIZE; i++) { 378 name[i] = letoh16(utf[i]) & 0x7F; 379 if (name[i] == '\0') 380 break; 381 } 382 if (i == GPTPARTNAMESIZE) 383 name[i - 1] = '\0'; 384 385 return (name); 386 } 387 388 u_int16_t * 389 string_to_utf16le(char *ch) 390 { 391 static u_int16_t utf[GPTPARTNAMESIZE]; 392 int i; 393 394 for (i = 0; i < GPTPARTNAMESIZE; i++) { 395 utf[i] = htole16((unsigned int)ch[i]); 396 if (utf[i] == 0) 397 break; 398 } 399 if (i == GPTPARTNAMESIZE) 400 utf[i - 1] = 0; 401 402 return (utf); 403 } 404