backup: Don't cast returns from malloc()
[openafs.git] / src / bucoord / expire.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 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #include <ctype.h>
17
18 #include <afs/ktime.h>
19 #include <afs/cmd.h>
20
21 #include "bc.h"
22
23 #define MAX_YEAR_VALUE  0
24 #define MAX_MONTH_VALUE 11
25 #define MAX_DAY_VALUE   30
26
27 /* for parsing relative expiration dates */
28 static struct parseseqS {
29     afs_int32 ps_field;
30     char ps_keychar;
31     afs_int32 ps_maxValue;
32 } parseseq[] = {
33     KTIMEDATE_YEAR, 'y', MAX_YEAR_VALUE,        /* no max. value */
34         KTIMEDATE_MONTH, 'm', MAX_MONTH_VALUE,  /* months max. 12 */
35         KTIMEDATE_DAY, 'd', MAX_DAY_VALUE,      /* days max. 31 */
36 0, 0, 0,};
37
38 /* Encodings to and from relative dates. The caller is responsible for
39  * enforcing appropriate use of these routines
40  */
41 afs_int32
42 ktimeRelDate_ToLong(kdptr)
43      struct ktime_date *kdptr;
44 {
45     afs_int32 retval;
46
47     retval =
48         (((kdptr->year * (MAX_MONTH_VALUE + 1)) +
49           kdptr->month) * (MAX_DAY_VALUE + 1)) + kdptr->day;
50     return (retval);
51 }
52
53 /* LongTo_ktimeRelDate
54  *      Convert a relative date encoded in a long - back into a ktime_date
55  *      structure
56  */
57
58 LongTo_ktimeRelDate(longDate, kdptr)
59      afs_int32 longDate;
60      struct ktime_date *kdptr;
61 {
62     memset(kdptr, 0, sizeof(*kdptr));
63
64     kdptr->day = longDate % (MAX_DAY_VALUE + 1);
65     if (kdptr->day != 0)
66         kdptr->mask |= KTIMEDATE_DAY;
67
68     longDate = longDate / (MAX_DAY_VALUE + 1);
69
70     kdptr->month = longDate % (MAX_MONTH_VALUE + 1);
71     if (kdptr->month != 0)
72         kdptr->mask |= KTIMEDATE_MONTH;
73
74     longDate = longDate / (MAX_MONTH_VALUE + 1);
75
76     kdptr->year = longDate;
77     if (kdptr->year != 0)
78         kdptr->mask |= KTIMEDATE_YEAR;
79
80     return (0);
81 }
82
83
84 #ifdef notdef
85 /* First some date storage and retrieval routines.
86  * These routines are for convert ktime date structures into text, and back.
87  * the format is compact and suitable for relative dates. These are used
88  * to store dates into the backup database.
89  */
90
91 /* ktimeDate_ToCompactString
92  *      convert the ktime into a compact text form.
93  * exit:
94  *      pointer to a static string containing the text form of the ktime.
95  * notes:
96  *      it assumes that non-valid portions of the date are set to 0 and that
97  *      all date fields are non-negative.
98  */
99
100 char *
101 ktimeDate_ToCompactString(kdptr)
102      struct ktime_date *kdptr;
103 {
104     char buffer[1024];
105
106     sprintf(buffer, "%-d:%-d:%-d:%-d:%-d:%-d", kdptr->year, kdptr->month,
107             kdptr->day, kdptr->hour, kdptr->min, kdptr->sec);
108
109     return (&buffer[0]);
110 }
111
112 /* CompactStringTo_ktimeDate
113  *      parses the string and places it in the ktime structure
114  * exit:
115  *      0 - success
116  *      -1 - failed, string format error
117  */
118 afs_int32
119 CompactStringTo_ktimeDate(stptr, kdptr)
120      char *stptr;
121      struct ktime_date *kdptr;
122 {
123     afs_int32 code;
124
125     code =
126         sscanf(stptr, "%d:%d:%d:%d:%d:%d", &kdptr->year, &kdptr->month,
127                &kdptr->day, &kdptr->hour, &kdptr->min, &kdptr->sec);
128
129     if (code != 6)
130         return (-1);
131
132     kdptr->mask = 0;
133
134     if (kdptr->year)
135         kdptr->mask |= KTIMEDATE_YEAR;
136
137     if (kdptr->month)
138         kdptr->mask |= KTIMEDATE_MONTH;
139
140     if (kdptr->day)
141         kdptr->mask |= KTIMEDATE_DAY;
142
143     if (kdptr->hour)
144         kdptr->mask |= KTIMEDATE_HOUR;
145
146     if (kdptr->min)
147         kdptr->mask |= KTIMEDATE_MIN;
148
149     if (kdptr->sec)
150         kdptr->mask |= KTIMEDATE_SEC;
151
152     return (0);
153 }
154
155 /* ktimeDate_FromLong
156  *      Converts a time in seconds, to a time (in ktime_date format). Result is
157  *      placed in the supplied structure
158  * entry:
159  *      timeSecs - time in seconds
160  *      ktimePtr - ptr to struct for the return value
161  */
162
163 ktimeDate_FromLong(timeSecs, ktimePtr)
164      afs_int32 timeSecs;
165      struct ktime_date *ktimePtr;
166 {
167     struct tm timePtr;
168
169     timePtr = localtime(&timeSecs);
170
171     /* copy the relevant fields */
172     ktimePtr->sec = timePtr->sec;
173     ktimePtr->min = timePtr->min;
174     ktimePtr->hour = timePtr->hour;
175     ktimePtr->day = timePtr->mday;
176     ktimePtr->month = timePtr->mon;
177     ktimePtr->year = timePtr->year;
178
179     ktimePtr->mask =
180         KTIMEDATE_YEAR | KTIMEDATE_MONTH | KTIMEDATE_DAY | KTIMEDATE_HOUR |
181         KTIMEDATE_MIN | KTIMEDATE_SEC;
182
183     return (0);
184 }
185
186
187 /* AddKtimeToNow
188  *      Returns current time with a relative time added. Note that the
189  *      computation adds in most significant fields first, i.e. year, month
190  *      day etc. Addition of least significant fields would produce different
191  *      results (depending on the data).
192  * entry:
193  *      relDatePtr - a ktime_date containing a relative time specification
194  * exit:
195  *      returns current time with relative time added.
196  */
197
198 afs_int32
199 AddKtimeToNow(relDatePtr)
200      struct ktime_date *relDatePtr;
201 {
202     struct parseseqS typePtr;
203     afs_int32 curTime;
204     afs_int32 moreYears;
205     static struct ktime_date absDate;
206
207     curTime = time(0);          /* get current time */
208     ktimeDate_FromLong(curTime, &absDate);      /* convert to ktime */
209
210     /* add in years */
211     absDate.year += relDatePtr->year;
212
213     /* add in months */
214     absDate.month += relDatePtr->month;
215     if (absDate.month > 12) {
216         moreYears = absDate.month / 12;
217         absDate.month = absDate.month % 12;
218         absDate.year += moreYears;
219     }
220
221     /* day computations depend upon month size, so do these in seconds */
222     curTime = ktime_InterpretDate(&absDate);
223
224     curTime =
225         curTime + relDatePtr->sec + relDatePtr->min * 60 +
226         relDatePtr->hour * 60 * 60 + relDatePtr->day * 24 * 60 * 60;
227
228     return (curTime);
229 }
230 #endif /* notdef */
231
232 #define RD_DIGIT_LIMIT  4       /* max. no. digits permitted */
233
234
235 /* ParseRelDate
236  *      Parses a relative date of the form  <n>y<n>m<n>d representing years
237  *      months and days. <n> is limited to RD_DIGIT_LIMIT digits in length.
238  * entry:
239  *      dateStr - ptr to string to parse. Leading white space ingnored.
240  * exit:
241  *      returns a ptr to a static ktime_date structure containing
242  *              appropriately set fields. The mask field is unused.
243  *      0 - error in date specification
244  */
245
246 afs_int32
247 ParseRelDate(dateStr, relDatePtr)
248      char *dateStr;
249      struct ktime_date *relDatePtr;
250 {
251     struct parseseqS *psPtr;
252     afs_int32 value, digit_limit;
253     afs_int32 type_index;
254
255     memset(relDatePtr, 0, sizeof(*relDatePtr));
256     type_index = 0;
257
258     while (1) {                 /*w */
259
260         while (isspace(*dateStr))       /* skip leading whitespace */
261             dateStr++;
262
263         if (isdigit(*dateStr) == 0)
264             goto error;
265
266         digit_limit = RD_DIGIT_LIMIT;
267         value = 0;
268         while (isdigit(*dateStr)) {
269             value = value * 10 + *dateStr - '0';
270             dateStr++;
271             if (digit_limit-- == 0)
272                 goto error;
273         }
274
275         psPtr = &parseseq[type_index];
276         /* determine the units. Search for a matching type character */
277         while ((psPtr->ps_keychar != *dateStr)
278                && (psPtr->ps_keychar != 0)
279             ) {
280             type_index++;
281             psPtr = &parseseq[type_index];
282         }
283
284         /* no matching type found */
285         if (psPtr->ps_keychar == 0)
286             goto error;
287
288         /* check the bounds on the maximum value. Can't be negative
289          * and if a maximum value is specified, check against it
290          */
291         if ((value < 0)
292             || ((psPtr->ps_maxValue > 0) && (value > psPtr->ps_maxValue))
293             )
294             goto error;
295
296         /* save computed value in the relevant type field */
297         switch (psPtr->ps_field) {
298         case KTIMEDATE_YEAR:
299             relDatePtr->year = value;
300             relDatePtr->mask |= KTIMEDATE_YEAR;
301             break;
302
303         case KTIMEDATE_MONTH:
304             relDatePtr->month = value;
305             relDatePtr->mask |= KTIMEDATE_MONTH;
306             break;
307
308         case KTIMEDATE_DAY:
309             relDatePtr->mask |= KTIMEDATE_DAY;
310             relDatePtr->day = value;
311             break;
312
313         default:
314             goto error;
315         }
316         dateStr++;              /* next digit */
317
318         if (*dateStr == 0) {
319             /* no more chars to process, return the result */
320             return (0);
321         }
322     }                           /*w */
323
324   error:
325     return (1);
326 }
327
328 /* RelDatetoString
329  *      returns a static string representing the relative date. This is in
330  *      a format acceptable to the relative date parser.
331  * entry:
332  *      datePtr - relative date to be converted.
333  * exit:
334  *      ptr to static string
335  */
336
337 char *
338 RelDatetoString(datePtr)
339      struct ktime_date *datePtr;
340 {
341     static char dateString[64];
342     char tempstring[64], *sptr;
343
344     dateString[0] = 0;
345     sptr = &dateString[0];
346
347     if (datePtr->mask & KTIMEDATE_YEAR) {
348         sprintf(tempstring, "%-dy", datePtr->year);
349         strcat(sptr, tempstring);
350     }
351
352     if (datePtr->mask & KTIMEDATE_MONTH) {
353         strcat(sptr, " ");
354         sprintf(tempstring, "%-dm", datePtr->month);
355         strcat(sptr, tempstring);
356     }
357
358     if (datePtr->mask & KTIMEDATE_DAY) {
359         strcat(sptr, " ");
360         sprintf(tempstring, "%-dd", datePtr->day);
361         strcat(sptr, tempstring);
362     }
363     return (sptr);
364 }
365
366 #define FAIL(n)                                         \
367 {                                                       \
368      code = n;                                          \
369      goto error;                                        \
370 }
371
372 /* bc_ParseExpiration
373  *
374  * Notes:
375  *      dates are specified as absolute or relative, the syntax is:
376  *      absolute:       at %d/%d/%d [%d:%d]     where [..] is optional
377  *      relative:       in [%dy][%dm][%dd]      where at least one component
378  *                                              must be specified
379  */
380
381 afs_int32
382 bc_ParseExpiration(struct cmd_parmdesc *paramPtr, afs_int32 *expType,
383                    afs_int32 *expDate)
384 {
385     struct cmd_item *itemPtr, *tempPtr;
386     struct ktime_date kt;
387     char *dateString;
388     afs_int32 length = 0;
389     afs_int32 code = 0;
390
391     if (paramPtr->items == 0) {
392         /* no expiration specified */
393         *expType = BC_NO_EXPDATE;
394         *expDate = 0;
395         return (0);
396     }
397
398     /* some form of expiration date specified. First validate the prefix */
399     itemPtr = paramPtr->items;
400
401     if (strcmp(itemPtr->data, "at") == 0) {
402         *expType = BC_ABS_EXPDATE;
403     } else if (strcmp(itemPtr->data, "in") == 0) {
404         *expType = BC_REL_EXPDATE;
405     } else
406         FAIL(1);
407
408     /* before parsing the date string - concatenate all the pieces */
409     itemPtr = itemPtr->next;
410     tempPtr = itemPtr;
411
412     /* compute the length of string required */
413     while (tempPtr != 0) {
414         length += strlen(tempPtr->data);
415         tempPtr = tempPtr->next;
416         length++;               /* space or null terminator */
417     }
418     if (length == 0)            /* no actual date string */
419         FAIL(1);
420
421     dateString = malloc(length);
422     if (dateString == 0)
423         FAIL(2);
424
425     /* now assemble the date string */
426     dateString[0] = 0;
427     while (itemPtr != 0) {
428         strcat(dateString, itemPtr->data);
429         itemPtr = itemPtr->next;
430         if (itemPtr != 0)
431             strcat(dateString, " ");
432     }
433
434     switch (*expType) {
435     case BC_ABS_EXPDATE:
436         code = ktime_DateToLong(dateString, expDate);
437         if (code)
438             FAIL(1);
439         break;
440
441     case BC_REL_EXPDATE:
442         code = ParseRelDate(dateString, &kt);
443         if (code)
444             FAIL(1);
445         *expDate = ktimeRelDate_ToLong(&kt);
446         break;
447
448     default:
449         FAIL(1);
450     }
451
452     /* code will be 0 */
453   exit:
454     /* normal exit */
455     if (dateString)
456         free(dateString);
457     return (code);
458
459   error:
460     /* assign default values */
461     *expType = BC_NO_EXPDATE;
462     *expDate = 0;
463     goto exit;
464 }