xref: /openbsd-src/sbin/fdisk/misc.c (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 /*	$OpenBSD: misc.c,v 1.63 2019/07/03 03:24:01 deraadt 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 #include <uuid.h>
29 
30 #include "disk.h"
31 #include "misc.h"
32 #include "part.h"
33 
34 struct unit_type unit_types[] = {
35 	{ "b"	, 1LL				, "Bytes"	},
36 	{ " "	, 0LL				, "Sectors"	},
37 	{ "K"	, 1024LL			, "Kilobytes"	},
38 	{ "M"	, 1024LL * 1024			, "Megabytes"	},
39 	{ "G"	, 1024LL * 1024 *1024		, "Gigabytes"	},
40 	{ "T"	, 1024LL * 1024 * 1024 * 1024	, "Terabytes"	},
41 	{ NULL	, 0				, NULL		},
42 };
43 
44 int
45 unit_lookup(char *units)
46 {
47 	int i = 0;
48 
49 	if (units == NULL)
50 		return (SECTORS);
51 
52 	while (unit_types[i].abbr != NULL) {
53 		if (strncasecmp(unit_types[i].abbr, units, 1) == 0)
54 			break;
55 		i++;
56 	}
57 	/* default */
58 	if (unit_types[i].abbr == NULL)
59 		return (SECTORS);
60 
61 	return (i);
62 }
63 
64 int
65 string_from_line(char *buf, size_t buflen)
66 {
67 	char *line;
68 	size_t sz;
69 
70 	line = fgetln(stdin, &sz);
71 	if (line == NULL)
72 		return (1);
73 
74 	if (line[sz - 1] == '\n')
75 		sz--;
76 	if (sz >= buflen)
77 		sz = buflen - 1;
78 
79 	memcpy(buf, line, sz);
80 	buf[sz] = '\0';
81 
82 	return (0);
83 }
84 
85 void
86 ask_cmd(char **cmd, char **arg)
87 {
88 	static char lbuf[100];
89 	size_t cmdstart, cmdend, argstart;
90 
91 	/* Get NUL terminated string from stdin. */
92 	if (string_from_line(lbuf, sizeof(lbuf)))
93 		errx(1, "eof");
94 
95 	cmdstart = strspn(lbuf, " \t");
96 	cmdend = cmdstart + strcspn(&lbuf[cmdstart], " \t");
97 	argstart = cmdend + strspn(&lbuf[cmdend], " \t");
98 
99 	/* *cmd and *arg may be set to point at final NUL! */
100 	*cmd = &lbuf[cmdstart];
101 	lbuf[cmdend] = '\0';
102 	*arg = &lbuf[argstart];
103 }
104 
105 int
106 ask_num(const char *str, int dflt, int low, int high)
107 {
108 	char lbuf[100];
109 	const char *errstr;
110 	int num;
111 
112 	if (dflt < low)
113 		dflt = low;
114 	else if (dflt > high)
115 		dflt = high;
116 
117 	do {
118 		printf("%s [%d - %d]: [%d] ", str, low, high, dflt);
119 
120 		if (string_from_line(lbuf, sizeof(lbuf)))
121 			errx(1, "eof");
122 
123 		if (lbuf[0] == '\0') {
124 			num = dflt;
125 			errstr = NULL;
126 		} else {
127 			num = (int)strtonum(lbuf, low, high, &errstr);
128 			if (errstr)
129 				printf("%s is %s: %s.\n", str, errstr, lbuf);
130 		}
131 	} while (errstr);
132 
133 	return (num);
134 }
135 
136 int
137 ask_pid(int dflt, struct uuid *guid)
138 {
139 	char lbuf[100], *cp;
140 	int num = -1, status;
141 
142 	do {
143 		printf("Partition id ('0' to disable) [01 - FF]: [%X] ", dflt);
144 		printf("(? for help) ");
145 
146 		if (string_from_line(lbuf, sizeof(lbuf)))
147 			errx(1, "eof");
148 
149 		if (lbuf[0] == '?') {
150 			PRT_printall();
151 			continue;
152 		}
153 
154 		if (guid && strlen(lbuf) == UUID_STR_LEN) {
155 			uuid_from_string(lbuf, guid, &status);
156 			if (status == uuid_s_ok)
157 				return (0x100);
158 		}
159 
160 		/* Convert */
161 		cp = lbuf;
162 		num = strtol(lbuf, &cp, 16);
163 
164 		/* Make sure only number present */
165 		if (cp == lbuf)
166 			num = dflt;
167 		if (*cp != '\0') {
168 			printf("'%s' is not a valid number.\n", lbuf);
169 			num = -1;
170 		} else if (num == 0) {
171 			break;
172 		} else if (num < 0 || num > 0xff) {
173 			printf("'%x' is out of range.\n", num);
174 		}
175 	} while (num < 0 || num > 0xff);
176 
177 	return (num);
178 }
179 
180 int
181 ask_yn(const char *str)
182 {
183 	int ch, first;
184 	extern int y_flag;
185 
186 	if (y_flag)
187 		return (1);
188 
189 	printf("%s [n] ", str);
190 	fflush(stdout);
191 
192 	first = ch = getchar();
193 	while (ch != '\n' && ch != EOF)
194 		ch = getchar();
195 
196 	if (ch == EOF || first == EOF)
197 		errx(1, "eof");
198 
199 	return (first == 'y' || first == 'Y');
200 }
201 
202 /*
203  * adapted from sbin/disklabel/editor.c
204  */
205 u_int64_t
206 getuint64(char *prompt, u_int64_t oval, u_int64_t minval, u_int64_t maxval)
207 {
208 	const int secsize = unit_types[SECTORS].conversion;
209 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
210 	size_t n;
211 	int64_t mult = 1;
212 	double d, d2;
213 	int rslt, secpercyl, saveerr;
214 	char unit;
215 
216 	if (oval > maxval)
217 		oval = maxval;
218 	if (oval < minval)
219 		oval = minval;
220 
221 	secpercyl = disk.sectors * disk.heads;
222 
223 	do {
224 		printf("%s [%llu - %llu]: [%llu] ", prompt, minval, maxval,
225 		    oval);
226 
227 		if (string_from_line(buf, sizeof(buf)))
228 			errx(1, "eof");
229 
230 		if (buf[0] == '\0') {
231 			rslt = snprintf(buf, sizeof(buf), "%llu", oval);
232 			if (rslt < 0 || rslt >= sizeof(buf))
233 				errx(1, "default value too long");
234 		} else if (buf[0] == '*' && buf[1] == '\0') {
235 			return (maxval);
236 		}
237 
238 		/* deal with units */
239 		n = strlen(buf);
240 		switch (tolower((unsigned char)buf[n-1])) {
241 		case 'c':
242 			unit = 'c';
243 			mult = secpercyl;
244 			buf[--n] = '\0';
245 			break;
246 		case 'b':
247 			unit = 'b';
248 			mult = -(int64_t)secsize;
249 			buf[--n] = '\0';
250 			break;
251 		case 's':
252 			unit = 's';
253 			mult = 1;
254 			buf[--n] = '\0';
255 			break;
256 		case 'k':
257 			unit = 'k';
258 			if (secsize > 1024)
259 				mult = -(int64_t)secsize / 1024LL;
260 			else
261 				mult = 1024LL / secsize;
262 			buf[--n] = '\0';
263 			break;
264 		case 'm':
265 			unit = 'm';
266 			mult = (1024LL * 1024) / secsize;
267 			buf[--n] = '\0';
268 			break;
269 		case 'g':
270 			unit = 'g';
271 			mult = (1024LL * 1024 * 1024) / secsize;
272 			buf[--n] = '\0';
273 			break;
274 		case 't':
275 			unit = 't';
276 			mult = (1024LL * 1024 * 1024 * 1024) / secsize;
277 			buf[--n] = '\0';
278 			break;
279 		default:
280 			unit = ' ';
281 			mult = 1;
282 			break;
283 		}
284 
285 		/* deal with the operator */
286 		p = &buf[0];
287 		if (*p == '+' || *p == '-')
288 			operator = *p++;
289 		else
290 			operator = ' ';
291 
292 		endptr = p;
293 		errno = 0;
294 		d = strtod(p, &endptr);
295 		saveerr = errno;
296 		d2 = d;
297 		if (mult > 0)
298 			d *= mult;
299 		else {
300 			d /= (-mult);
301 			d2 = d;
302 		}
303 
304 		/* Apply the operator */
305 		if (operator == '+')
306 			d = oval + d;
307 		else if (operator == '-') {
308 			d = oval - d;
309 			d2 = d;
310 		}
311 
312 		if (saveerr == ERANGE || d > maxval || d < minval || d < d2) {
313 			printf("%s is out of range: %c%s%c\n", prompt, operator,
314 			    p, unit);
315 		} else if (*endptr != '\0') {
316 			printf("%s is invalid: %c%s%c\n", prompt, operator,
317 			    p, unit);
318 		} else {
319 			break;
320 		}
321 	} while (1);
322 
323 	return((u_int64_t)d);
324 }
325 
326 char *
327 ask_string(const char *prompt, const char *oval)
328 {
329 	static char buf[37];
330 
331 	buf[0] = '\0';
332 	printf("%s: [%s] ", prompt, oval ? oval : "");
333 	if (string_from_line(buf, sizeof(buf)))
334 		errx(1, "eof");
335 
336 	if (buf[0] == '\0' && oval)
337 		strlcpy(buf, oval, sizeof(buf));
338 
339 	return(buf);
340 }
341 
342 /*
343  * Adapted from Hacker's Delight crc32b().
344  *
345  * To quote http://www.hackersdelight.org/permissions.htm :
346  *
347  * "You are free to use, copy, and distribute any of the code on
348  *  this web site, whether modified by you or not. You need not give
349  *  attribution. This includes the algorithms (some of which appear
350  *  in Hacker's Delight), the Hacker's Assistant, and any code submitted
351  *  by readers. Submitters implicitly agree to this."
352  */
353 u_int32_t
354 crc32(const u_char *buf, const u_int32_t size)
355 {
356 	int j;
357 	u_int32_t i, byte, crc, mask;
358 
359 	crc = 0xFFFFFFFF;
360 
361 	for (i = 0; i < size; i++) {
362 		byte = buf[i];			/* Get next byte. */
363 		crc = crc ^ byte;
364 		for (j = 7; j >= 0; j--) {	/* Do eight times. */
365 			mask = -(crc & 1);
366 			crc = (crc >> 1) ^ (0xEDB88320 & mask);
367 		}
368 	}
369 
370 	return ~crc;
371 }
372 
373 char *
374 utf16le_to_string(u_int16_t *utf)
375 {
376 	static char name[GPTPARTNAMESIZE];
377 	int i;
378 
379 	for (i = 0; i < GPTPARTNAMESIZE; i++) {
380 		name[i] = letoh16(utf[i]) & 0x7F;
381 		if (name[i] == '\0')
382 			break;
383 	}
384 	if (i == GPTPARTNAMESIZE)
385 		name[i - 1] = '\0';
386 
387 	return (name);
388 }
389 
390 u_int16_t *
391 string_to_utf16le(char *ch)
392 {
393 	static u_int16_t utf[GPTPARTNAMESIZE];
394 	int i;
395 
396 	for (i = 0; i < GPTPARTNAMESIZE; i++) {
397 		utf[i] = htole16((unsigned int)ch[i]);
398 		if (utf[i] == 0)
399 			break;
400 	}
401 	if (i == GPTPARTNAMESIZE)
402 		utf[i - 1] = 0;
403 
404 	return (utf);
405 }
406