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