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
units_size(const char * units,const uint64_t sectors,const struct unit_type ** ut)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
string_from_line(char * buf,const size_t buflen,const int trim)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
ask_yn(const char * str)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
getuint64(const char * prompt,uint64_t oval,const uint64_t minval,const uint64_t maxval)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
hex_octet(char * buf)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