1 /* $OpenBSD: misc.c,v 1.82 2021/08/28 11:55:17 krw 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 29 #include "part.h" 30 #include "disk.h" 31 #include "misc.h" 32 33 struct unit_type unit_types[] = { 34 { "b" , 1LL , "Bytes" }, 35 { " " , 0LL , "Sectors" }, 36 { "K" , 1024LL , "Kilobytes" }, 37 { "M" , 1024LL * 1024 , "Megabytes" }, 38 { "G" , 1024LL * 1024 *1024 , "Gigabytes" }, 39 { "T" , 1024LL * 1024 * 1024 * 1024 , "Terabytes" }, 40 { NULL , 0 , NULL }, 41 }; 42 43 int 44 unit_lookup(const char *units) 45 { 46 int i = 0; 47 48 if (units == NULL) 49 return SECTORS; 50 51 while (unit_types[i].ut_abbr != NULL) { 52 if (strncasecmp(unit_types[i].ut_abbr, units, 1) == 0) 53 break; 54 i++; 55 } 56 if (unit_types[i].ut_abbr == NULL) 57 return SECTORS; 58 59 return i; 60 } 61 62 void 63 string_from_line(char *buf, const size_t buflen, const int trim) 64 { 65 static char *line; 66 static size_t sz; 67 ssize_t len; 68 unsigned int i; 69 70 len = getline(&line, &sz, stdin); 71 if (len == -1) 72 errx(1, "eof"); 73 74 switch (trim) { 75 case UNTRIMMED: 76 line[strcspn(line, "\n")] = '\0'; 77 strlcpy(buf, line, buflen); 78 break; 79 case TRIMMED: 80 for (i = strlen(line); i > 0; i--) { 81 if (isspace((unsigned char)line[i - 1]) == 0) 82 break; 83 line[i - 1] = '\0'; 84 } 85 strlcpy(buf, line + strspn(line, WHITESPACE), buflen); 86 break; 87 } 88 } 89 90 int 91 ask_yn(const char *str) 92 { 93 int ch, first; 94 extern int y_flag; 95 96 if (y_flag) 97 return 1; 98 99 printf("%s [n] ", str); 100 fflush(stdout); 101 102 first = ch = getchar(); 103 while (ch != '\n' && ch != EOF) 104 ch = getchar(); 105 106 if (ch == EOF || first == EOF) 107 errx(1, "eof"); 108 109 return first == 'y' || first == 'Y'; 110 } 111 112 /* 113 * adapted from sbin/disklabel/editor.c 114 */ 115 uint64_t 116 getuint64(const char *prompt, uint64_t oval, const uint64_t minval, 117 const uint64_t maxval) 118 { 119 char buf[BUFSIZ], *endptr, *p, operator = '\0'; 120 const int secsize = unit_types[SECTORS].ut_conversion; 121 size_t n; 122 int64_t mult = 1; 123 double d, d2; 124 int rslt, secpercyl, saveerr; 125 char unit; 126 127 if (oval > maxval) 128 oval = maxval; 129 if (oval < minval) 130 oval = minval; 131 132 secpercyl = disk.dk_sectors * disk.dk_heads; 133 134 do { 135 printf("%s [%llu - %llu]: [%llu] ", prompt, minval, maxval, 136 oval); 137 string_from_line(buf, sizeof(buf), TRIMMED); 138 139 if (buf[0] == '\0') { 140 rslt = snprintf(buf, sizeof(buf), "%llu", oval); 141 if (rslt < 0 || rslt >= sizeof(buf)) 142 errx(1, "default value too long"); 143 } else if (buf[0] == '*' && buf[1] == '\0') { 144 return maxval; 145 } 146 147 /* deal with units */ 148 n = strlen(buf); 149 switch (tolower((unsigned char)buf[n-1])) { 150 case 'c': 151 unit = 'c'; 152 mult = secpercyl; 153 buf[--n] = '\0'; 154 break; 155 case 'b': 156 unit = 'b'; 157 mult = -(int64_t)secsize; 158 buf[--n] = '\0'; 159 break; 160 case 's': 161 unit = 's'; 162 mult = 1; 163 buf[--n] = '\0'; 164 break; 165 case 'k': 166 unit = 'k'; 167 if (secsize > 1024) 168 mult = -(int64_t)secsize / 1024LL; 169 else 170 mult = 1024LL / secsize; 171 buf[--n] = '\0'; 172 break; 173 case 'm': 174 unit = 'm'; 175 mult = (1024LL * 1024) / secsize; 176 buf[--n] = '\0'; 177 break; 178 case 'g': 179 unit = 'g'; 180 mult = (1024LL * 1024 * 1024) / secsize; 181 buf[--n] = '\0'; 182 break; 183 case 't': 184 unit = 't'; 185 mult = (1024LL * 1024 * 1024 * 1024) / secsize; 186 buf[--n] = '\0'; 187 break; 188 default: 189 unit = ' '; 190 mult = 1; 191 break; 192 } 193 194 /* deal with the operator */ 195 p = &buf[0]; 196 if (*p == '+' || *p == '-') 197 operator = *p++; 198 else 199 operator = ' '; 200 201 endptr = p; 202 errno = 0; 203 d = strtod(p, &endptr); 204 saveerr = errno; 205 d2 = d; 206 if (mult > 0) 207 d *= mult; 208 else { 209 d /= (-mult); 210 d2 = d; 211 } 212 213 /* Apply the operator */ 214 if (operator == '+') 215 d = oval + d; 216 else if (operator == '-') { 217 d = oval - d; 218 d2 = d; 219 } 220 221 if (saveerr == ERANGE || d > maxval || d < minval || d < d2) { 222 printf("%s is out of range: %c%s%c\n", prompt, operator, 223 p, unit); 224 } else if (*endptr != '\0') { 225 printf("%s is invalid: %c%s%c\n", prompt, operator, 226 p, unit); 227 } else { 228 break; 229 } 230 } while (1); 231 232 return (uint64_t)d; 233 } 234 235 char * 236 utf16le_to_string(const uint16_t *utf) 237 { 238 static char name[GPTPARTNAMESIZE]; 239 int i; 240 241 for (i = 0; i < GPTPARTNAMESIZE; i++) { 242 name[i] = letoh16(utf[i]) & 0x7F; 243 if (name[i] == '\0') 244 break; 245 } 246 if (i == GPTPARTNAMESIZE) 247 name[i - 1] = '\0'; 248 249 return name; 250 } 251 252 uint16_t * 253 string_to_utf16le(const char *ch) 254 { 255 static uint16_t utf[GPTPARTNAMESIZE]; 256 int i; 257 258 for (i = 0; i < GPTPARTNAMESIZE; i++) { 259 utf[i] = htole16((unsigned int)ch[i]); 260 if (utf[i] == 0) 261 break; 262 } 263 if (i == GPTPARTNAMESIZE) 264 utf[i - 1] = 0; 265 266 return utf; 267 } 268 269 int 270 hex_octet(char *buf) 271 { 272 char *cp; 273 long num; 274 275 cp = buf; 276 num = strtol(buf, &cp, 16); 277 278 if (cp == buf || *cp != '\0') 279 return -1; 280 281 if (num < 0 || num > 0xff) 282 return -1; 283 284 return num; 285 } 286