backport to buster
[hcoop/debian/openafs.git] / src / util / volparse.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14
15 #include "afsutil.h"
16
17 /* maximum number of partitions - must match vol/voldefs.h */
18 #define VOLMAXPARTS 255
19
20 /**
21 * map a partition id from any partition-style name.
22 *
23 * @param[in] aname partition name string
24 *
25 * @return partition index number
26 * @retval -1 invalid partition name
27 *
28 * @see volutil_PartitionName2_r
29 * @see volutil_PartitionName_r
30 * @see volutil_PartitionName
31 */
32 afs_int32
33 volutil_GetPartitionID(char *aname)
34 {
35 char tc;
36 afs_int32 temp;
37 char ascii[3];
38
39 tc = *aname;
40 if (tc == 0)
41 return -1; /* unknown */
42 /* numbers go straight through */
43 if (tc >= '0' && tc <= '9') {
44 temp = atoi(aname);
45 /* this next check is to make the syntax less ambiguous when discriminating
46 * between volume numbers and partition IDs. This lets things like
47 * bos salvage do some reasonability checks on its input w/o checking
48 * to see if the partition is really on the server.
49 */
50 if (temp < 0 || temp >= VOLMAXPARTS)
51 return -1;
52 else
53 return temp;
54 }
55 /* otherwise check for vicepa or /vicepa, or just plain "a" */
56 ascii[2] = 0;
57 if (strlen(aname) <= 2) {
58 strcpy(ascii, aname);
59 } else if (!strncmp(aname, "/vicep", 6)) {
60 if(strlcpy(ascii, aname + 6, sizeof(ascii)) >= sizeof(ascii))
61 return -1; /* bad partition name: trailing characters */
62 } else if (!strncmp(aname, "vicep", 5)) {
63 if(strlcpy(ascii, aname + 5, sizeof(ascii)) >= sizeof(ascii))
64 return -1; /* bad partition name: trailing characters */
65 } else
66 return -1; /* bad partition name */
67 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz,
68 * and are numbered from 0. Do the appropriate conversion */
69 if (ascii[1] == 0) {
70 /* one char name, 0..25 */
71 if (ascii[0] < 'a' || ascii[0] > 'z')
72 return -1; /* wrongo */
73 return ascii[0] - 'a';
74 } else {
75 /* two char name, 26 .. <whatever> */
76 if (ascii[0] < 'a' || ascii[0] > 'z')
77 return -1; /* wrongo */
78 if (ascii[1] < 'a' || ascii[1] > 'z')
79 return -1; /* just as bad */
80 temp = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
81 return (temp >= VOLMAXPARTS ? -1 : temp);
82 }
83 }
84
85 /**
86 * convert a partition index number into a partition name string (/vicepXX).
87 *
88 * @param[in] part partition index number
89 * @param[out] tbuffer buffer in which to store name
90 * @param[in] buflen length of tbuffer
91 *
92 * @return operation status
93 * @retval 0 success
94 * @retval -1 buffer too short
95 * @retval -2 invalid partition id
96 *
97 * @see volutil_PartitionName_r
98 * @see volutil_PartitionName
99 * @see volutil_GetPartitionID
100 */
101 afs_int32
102 volutil_PartitionName2_r(afs_int32 part, char *tbuffer, size_t buflen)
103 {
104 char tempString[3];
105 int i;
106
107 if (part < 0 || part >= VOLMAXPARTS) {
108 return -2;
109 }
110
111 tempString[1] = tempString[2] = 0;
112 strncpy(tbuffer, "/vicep", buflen);
113 if (part <= 25) {
114 tempString[0] = 'a' + part;
115 } else {
116 part -= 26;
117 i = (part / 26);
118 tempString[0] = i + 'a';
119 tempString[1] = (part % 26) + 'a';
120 }
121 if (strlcat(tbuffer, tempString, buflen) >= buflen) {
122 return -1;
123 }
124 return 0;
125 }
126
127 #define BAD_VID "BAD VOLUME ID"
128 #define BAD_VID_LEN (sizeof(BAD_VID))
129 /**
130 * convert a partition index number into a partition name string (/vicepXX).
131 *
132 * @param[in] part partition index number
133 * @param[out] tbuffer buffer in which to store name
134 * @param[in] buflen length of tbuffer
135 *
136 * @return partition name string
137 * @retval "" buffer too short
138 * @retval "SPC" buffer too short
139 * @retval "BAD VOLUME ID" avalue contains an invalid partition index
140 *
141 * @note you may wish to consider using volutil_PartitionName2_r, as its
142 * error handling is more standard
143 *
144 * @see volutil_PartitionName2_r
145 * @see volutil_PartitionName
146 * @see volutil_GetPartitionID
147 */
148 char *
149 volutil_PartitionName_r(int part, char *tbuffer, int buflen)
150 {
151 afs_int32 code;
152
153 if (buflen < BAD_VID_LEN) {
154 strlcpy(tbuffer, "SPC", buflen);
155 return tbuffer;
156 }
157
158 code = volutil_PartitionName2_r(part, tbuffer, buflen);
159
160 if (code == -2) {
161 strlcpy(tbuffer, BAD_VID, buflen);
162 }
163
164 return tbuffer;
165 }
166
167 /**
168 * convert a partition index number into a partition name string (/vicepXX).
169 *
170 * @param[in] avalue partition index number
171 *
172 * @return partition name string
173 * @retval "BAD VOLUME ID" avalue contains an invalid partition index
174 *
175 * @warning this interface is not re-entrant
176 *
177 * @see volutil_PartitionName2_r
178 * @see volutil_PartitionName_r
179 * @see volutil_GetPartitionID
180 */
181 char *
182 volutil_PartitionName(int avalue)
183 {
184 #define VPN_TBUFLEN 64
185 static char tbuffer[VPN_TBUFLEN];
186 return volutil_PartitionName_r(avalue, tbuffer, VPN_TBUFLEN - 1);
187 }
188
189 /* is this a digit or a digit-like thing? */
190 static int
191 ismeta(int ac, int abase)
192 {
193 /* if (ac == '-' || ac == 'x' || ac == 'X') return 1; */
194 if (ac >= '0' && ac <= '7')
195 return 1;
196 if (abase <= 8)
197 return 0;
198 if (ac >= '8' && ac <= '9')
199 return 1;
200 if (abase <= 10)
201 return 0;
202 if (ac >= 'a' && ac <= 'f')
203 return 1;
204 if (ac >= 'A' && ac <= 'F')
205 return 1;
206 return 0;
207 }
208
209 /* given that this is a digit or a digit-like thing, compute its value */
210 static int
211 getmeta(int ac)
212 {
213 if (ac >= '0' && ac <= '9')
214 return ac - '0';
215 if (ac >= 'a' && ac <= 'f')
216 return ac - 'a' + 10;
217 if (ac >= 'A' && ac <= 'F')
218 return ac - 'A' + 10;
219 return 0;
220 }
221
222 afs_int32
223 util_GetInt32(char *as, afs_int32 * aval)
224 {
225 afs_int32 total;
226 int tc;
227 int base;
228 int negative;
229
230 total = 0; /* initialize things */
231 negative = 0;
232
233 /* skip over leading spaces */
234 for (tc = *as; tc !='\0'; as++, tc = *as) {
235 if (tc != ' ' && tc != '\t')
236 break;
237 }
238
239 /* compute sign */
240 if (*as == '-') {
241 negative = 1;
242 as++; /* skip over character */
243 }
244
245 /* compute the base */
246 if (*as == '0') {
247 as++;
248 if (*as == 'x' || *as == 'X') {
249 base = 16;
250 as++;
251 } else
252 base = 8;
253 } else
254 base = 10;
255
256 /* compute the # itself */
257 for (tc = *as; tc !='\0'; as++, tc = *as) {
258 if (!ismeta(tc, base))
259 return -1;
260 total *= base;
261 total += getmeta(tc);
262 }
263
264 if (negative)
265 *aval = -total;
266 else
267 *aval = total;
268 return 0;
269 }
270
271 afs_uint32
272 util_GetUInt32(char *as, afs_uint32 * aval)
273 {
274 afs_uint32 total;
275 int tc;
276 int base;
277
278 total = 0; /* initialize things */
279
280 /* skip over leading spaces */
281 for (tc = *as; tc !='\0'; as++, tc = *as) {
282 if (tc != ' ' && tc != '\t')
283 break;
284 }
285
286 /* compute the base */
287 if (*as == '0') {
288 as++;
289 if (*as == 'x' || *as == 'X') {
290 base = 16;
291 as++;
292 } else
293 base = 8;
294 } else
295 base = 10;
296
297 /* compute the # itself */
298 for (tc = *as; tc !='\0'; as++, tc = *as) {
299 if (!ismeta(tc, base))
300 return -1;
301 total *= base;
302 total += getmeta(tc);
303 }
304
305 *aval = total;
306 return 0;
307 }
308
309 static const char power_letter[] = {
310 'K', /* kibi */
311 'M', /* mebi */
312 'G', /* gibi */
313 'T', /* tebi */
314 };
315
316 afs_int32
317 util_GetHumanInt32(char *as, afs_int32 * aval)
318 {
319 long value;
320 char * unit;
321 long mult = 1;
322 int exponent = 0;
323
324 errno = 0;
325 value = strtol(as, &unit, 0);
326 if (errno)
327 return -1;
328 if (unit[0] != 0) {
329 for (exponent = 0; exponent < sizeof(power_letter) && power_letter[exponent] != unit[0]; exponent++) {
330 mult *= 1024;
331 }
332 if (exponent == sizeof(power_letter))
333 return -1;
334 }
335 if (value > MAX_AFS_INT32 / mult || value < MIN_AFS_INT32 / mult)
336 return -1;
337
338 *aval = value * mult;
339
340 return 0;
341 }
342
343 afs_int32
344 util_GetInt64(char *as, afs_int64 * aval)
345 {
346 afs_int64 total;
347 int tc;
348 int base;
349 int negative;
350
351 total = 0; /* initialize things */
352 negative = 0;
353
354 /* skip over leading spaces */
355 while ((tc = *as)) {
356 if (tc != ' ' && tc != '\t')
357 break;
358 }
359
360 /* compute sign */
361 if (*as == '-') {
362 negative = 1;
363 as++; /* skip over character */
364 }
365
366 /* compute the base */
367 if (*as == '0') {
368 as++;
369 if (*as == 'x' || *as == 'X') {
370 base = 16;
371 as++;
372 } else
373 base = 8;
374 } else
375 base = 10;
376
377 /* compute the # itself */
378 while ((tc = *as)) {
379 if (!ismeta(tc, base))
380 return -1;
381 total *= base;
382 total += getmeta(tc);
383 as++;
384 }
385
386 if (negative)
387 *aval = -total;
388 else
389 *aval = total;
390 return 0;
391 }
392
393 afs_uint32
394 util_GetUInt64(char *as, afs_uint64 * aval)
395 {
396 afs_uint64 total;
397 int tc;
398 int base;
399
400 total = 0; /* initialize things */
401
402 /* skip over leading spaces */
403 while ((tc = *as)) {
404 if (tc != ' ' && tc != '\t')
405 break;
406 }
407
408 /* compute the base */
409 if (*as == '0') {
410 as++;
411 if (*as == 'x' || *as == 'X') {
412 base = 16;
413 as++;
414 } else
415 base = 8;
416 } else
417 base = 10;
418
419 /* compute the # itself */
420 while ((tc = *as)) {
421 if (!ismeta(tc, base))
422 return -1;
423 total *= base;
424 total += getmeta(tc);
425 as++;
426 }
427
428 *aval = total;
429 return 0;
430 }