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