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