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