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