xref: /openbsd-src/sbin/fdisk/misc.c (revision 18270f79f17989f9cfedd96c0d9a34fd91cdb415)
1 /*	$OpenBSD: misc.c,v 1.78 2021/07/17 14:16:34 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 <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <uuid.h>
30 
31 #include "part.h"
32 #include "disk.h"
33 #include "misc.h"
34 
35 struct unit_type	unit_types[] = {
36 	{ "b"	, 1LL				, "Bytes"	},
37 	{ " "	, 0LL				, "Sectors"	},
38 	{ "K"	, 1024LL			, "Kilobytes"	},
39 	{ "M"	, 1024LL * 1024			, "Megabytes"	},
40 	{ "G"	, 1024LL * 1024 *1024		, "Gigabytes"	},
41 	{ "T"	, 1024LL * 1024 * 1024 * 1024	, "Terabytes"	},
42 	{ NULL	, 0				, NULL		},
43 };
44 
45 int
46 unit_lookup(const char *units)
47 {
48 	int			i = 0;
49 
50 	if (units == NULL)
51 		return SECTORS;
52 
53 	while (unit_types[i].ut_abbr != NULL) {
54 		if (strncasecmp(unit_types[i].ut_abbr, units, 1) == 0)
55 			break;
56 		i++;
57 	}
58 	if (unit_types[i].ut_abbr == NULL)
59 		return SECTORS;
60 
61 	return i;
62 }
63 
64 int
65 string_from_line(char *buf, const size_t buflen)
66 {
67 	static char		*line;
68 	static size_t		 sz;
69 	ssize_t			 len;
70 
71 	len = getline(&line, &sz, stdin);
72 	if (len == -1)
73 		return -1;
74 
75 	if (line[len - 1] == '\n')
76 		line[len - 1] = '\0';
77 
78 	strlcpy(buf, line, buflen);
79 
80 	return 0;
81 }
82 
83 int
84 ask_yn(const char *str)
85 {
86 	int			ch, first;
87 	extern int		y_flag;
88 
89 	if (y_flag)
90 		return 1;
91 
92 	printf("%s [n] ", str);
93 	fflush(stdout);
94 
95 	first = ch = getchar();
96 	while (ch != '\n' && ch != EOF)
97 		ch = getchar();
98 
99 	if (ch == EOF || first == EOF)
100 		errx(1, "eof");
101 
102 	return first == 'y' || first == 'Y';
103 }
104 
105 /*
106  * adapted from sbin/disklabel/editor.c
107  */
108 uint64_t
109 getuint64(const char *prompt, uint64_t oval, const uint64_t minval,
110     const uint64_t maxval)
111 {
112 	char			buf[BUFSIZ], *endptr, *p, operator = '\0';
113 	const int		secsize = unit_types[SECTORS].ut_conversion;
114 	size_t			n;
115 	int64_t			mult = 1;
116 	double			d, d2;
117 	int			rslt, secpercyl, saveerr;
118 	char			unit;
119 
120 	if (oval > maxval)
121 		oval = maxval;
122 	if (oval < minval)
123 		oval = minval;
124 
125 	secpercyl = disk.dk_sectors * disk.dk_heads;
126 
127 	do {
128 		printf("%s [%llu - %llu]: [%llu] ", prompt, minval, maxval,
129 		    oval);
130 
131 		if (string_from_line(buf, sizeof(buf)))
132 			errx(1, "eof");
133 
134 		if (buf[0] == '\0') {
135 			rslt = snprintf(buf, sizeof(buf), "%llu", oval);
136 			if (rslt < 0 || rslt >= sizeof(buf))
137 				errx(1, "default value too long");
138 		} else if (buf[0] == '*' && buf[1] == '\0') {
139 			return maxval;
140 		}
141 
142 		/* deal with units */
143 		n = strlen(buf);
144 		switch (tolower((unsigned char)buf[n-1])) {
145 		case 'c':
146 			unit = 'c';
147 			mult = secpercyl;
148 			buf[--n] = '\0';
149 			break;
150 		case 'b':
151 			unit = 'b';
152 			mult = -(int64_t)secsize;
153 			buf[--n] = '\0';
154 			break;
155 		case 's':
156 			unit = 's';
157 			mult = 1;
158 			buf[--n] = '\0';
159 			break;
160 		case 'k':
161 			unit = 'k';
162 			if (secsize > 1024)
163 				mult = -(int64_t)secsize / 1024LL;
164 			else
165 				mult = 1024LL / secsize;
166 			buf[--n] = '\0';
167 			break;
168 		case 'm':
169 			unit = 'm';
170 			mult = (1024LL * 1024) / secsize;
171 			buf[--n] = '\0';
172 			break;
173 		case 'g':
174 			unit = 'g';
175 			mult = (1024LL * 1024 * 1024) / secsize;
176 			buf[--n] = '\0';
177 			break;
178 		case 't':
179 			unit = 't';
180 			mult = (1024LL * 1024 * 1024 * 1024) / secsize;
181 			buf[--n] = '\0';
182 			break;
183 		default:
184 			unit = ' ';
185 			mult = 1;
186 			break;
187 		}
188 
189 		/* deal with the operator */
190 		p = &buf[0];
191 		if (*p == '+' || *p == '-')
192 			operator = *p++;
193 		else
194 			operator = ' ';
195 
196 		endptr = p;
197 		errno = 0;
198 		d = strtod(p, &endptr);
199 		saveerr = errno;
200 		d2 = d;
201 		if (mult > 0)
202 			d *= mult;
203 		else {
204 			d /= (-mult);
205 			d2 = d;
206 		}
207 
208 		/* Apply the operator */
209 		if (operator == '+')
210 			d = oval + d;
211 		else if (operator == '-') {
212 			d = oval - d;
213 			d2 = d;
214 		}
215 
216 		if (saveerr == ERANGE || d > maxval || d < minval || d < d2) {
217 			printf("%s is out of range: %c%s%c\n", prompt, operator,
218 			    p, unit);
219 		} else if (*endptr != '\0') {
220 			printf("%s is invalid: %c%s%c\n", prompt, operator,
221 			    p, unit);
222 		} else {
223 			break;
224 		}
225 	} while (1);
226 
227 	return (uint64_t)d;
228 }
229 
230 char *
231 utf16le_to_string(const uint16_t *utf)
232 {
233 	static char		name[GPTPARTNAMESIZE];
234 	int			i;
235 
236 	for (i = 0; i < GPTPARTNAMESIZE; i++) {
237 		name[i] = letoh16(utf[i]) & 0x7F;
238 		if (name[i] == '\0')
239 			break;
240 	}
241 	if (i == GPTPARTNAMESIZE)
242 		name[i - 1] = '\0';
243 
244 	return name;
245 }
246 
247 uint16_t *
248 string_to_utf16le(const char *ch)
249 {
250 	static uint16_t		utf[GPTPARTNAMESIZE];
251 	int			i;
252 
253 	for (i = 0; i < GPTPARTNAMESIZE; i++) {
254 		utf[i] = htole16((unsigned int)ch[i]);
255 		if (utf[i] == 0)
256 			break;
257 	}
258 	if (i == GPTPARTNAMESIZE)
259 		utf[i - 1] = 0;
260 
261 	return utf;
262 }
263