xref: /openbsd/sbin/fdisk/misc.c (revision d89ec533)
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