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