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