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