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