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