merge irix dmapi test changes
[xfstests-dev.git] / dmapi / src / suite1 / cmd / set_fileattr.c
1 /*
2  * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
3  * 
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  * 
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  * 
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  * 
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc., 59
21  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22  * 
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  * 
26  * http://www.sgi.com 
27  * 
28  * For further information regarding this notice, see: 
29  * 
30  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31  */
32
33 #include <ctype.h>
34 #include <time.h>
35
36 #include <lib/hsm.h>
37
38 #include <getopt.h>
39 #include <string.h>
40
41
42
43 extern  int     optind;
44 extern  int     opterr;
45 extern  char    *optarg;
46
47 static  char            *Progname;
48
49 #define MIN_HD_DATE     19800101
50 #define MIN_HD_TMSTAMP  315554400       /* timestamp of 19800101 */
51
52 static  int     dayno, day_of_week;
53 static  int     leap_year;
54
55 /*
56  * The following table is used for USA daylight savings time and
57  * gives the day number of the first day after the Sunday of the
58  * change.
59  */
60 static struct {
61         int     yrbgn;
62         int     daylb;
63         int     dayle;
64 } daytab[] = {
65         {1987,  96,     303},   /* new legislation - 1st Sun in April */
66         {1976,  119,    303},   /* normal Last Sun in Apr - last Sun in Oct */
67         {1975,  58,     303},   /* 1975: Last Sun in Feb - last Sun in Oct */
68         {1974,  5,      333},   /* 1974: Jan 6 - last Sun. in Nov */
69         {1970,  119,    303},   /* start GMT */
70 };
71 #define DAYTABSIZE (sizeof(daytab)/sizeof(daytab[0]))
72
73
74 /******************************************************************************
75 * NAME
76 *       dysize
77 *
78 * DESCRIPTION
79 *       Return number of days in year y.
80 *
81 ******************************************************************************/
82
83 int
84 dysize(int y)
85 {
86         int     temp;
87         temp = (y%4)==0;
88         if (temp) {
89                 if ( (y%100)==0) 
90                         temp = ( (y%400) != 0);
91         }
92         return(365+temp);
93 }
94
95 /******************************************************************************
96 * NAME
97 *       sunday
98 *
99 * DESCRIPTION
100 *       sunday - return sunday daynumber.  Argument d is the day number of the
101 *       first Sunday on or before the special day.  Variables leap_year, dayno,
102 *       and day_of_week must have been set before sunday is called.
103 *
104 * RETURN VALUE
105 *       The sunday daynumber.
106 *
107 ******************************************************************************/
108
109 static int
110 sunday(int d)
111 {
112         if(d >= 58)
113                 d += leap_year;
114         return(d - (d - dayno + day_of_week + 700) % 7);
115 }
116
117
118 extern  long 
119 cnvdate(int mon, int mday, int year, int hour, int min, int sec)
120 {
121         int     t, i;
122         int     daylbegin, daylend;
123         int     ly_correction;  /* Leap Year Correction */
124         int     dl_correction;  /* Daylight Savings Time Correction */
125         long    s;
126         static int days[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
127
128         days[2] = 28;
129
130         /* Verify Input Parameters. */
131  
132         /*      Set  year. */
133
134         if( year < 0) {
135                 return(-1);
136         }
137         if( year < 100) {
138                 if (year < 70) year += 2000;
139                 else year += 1900;
140         }
141         if (year < 1970) {
142                 return(-1);
143         }
144         if( year>2099 ) {
145                 return(-1);
146         }
147
148         if (dysize(year) == 366) {
149                 leap_year = 1;
150                 days[2]++;
151         } else  
152                 leap_year = 0;
153         /*
154          * Set ly_correction = number of leap year days from 1/1/1970 to
155          * 1/1/year.
156          */
157         ly_correction =  ((year-1969) / 4);
158
159         /* Check Month */
160
161         if( (mon < 1) || (mon > 12)) {
162                 return(-1);
163         }
164
165         /* Check Day */
166
167         if ( (mday < 1) || (mday > days[mon]) ) {
168                 return(-1);
169         }
170
171         /* Check Time */
172
173         if( (hour<0) || (hour>23)) {
174                 return(-1);
175         }
176         if( (min<0) || (min>59)) {
177                 return(-1);
178         }
179         if( (sec<0) || (sec>59)) {
180                 return(-1);
181         }
182
183         /* Calculate Correction for Daylight Savings Time (U.S.) */
184
185         dayno = mday-1;
186         for (t=0; t<mon;)
187                 dayno += days[t++];
188         s = (year-1970)*365L + ly_correction + dayno;
189         day_of_week = (s + 4) % 7;
190
191         i = 0;
192         while (year < daytab[i].yrbgn) { 
193                 /* fall through when in correct interval */ 
194                 i++;
195                 if (i>DAYTABSIZE)
196                         return(-1);
197         }
198         daylbegin = daytab[i].daylb; 
199         daylend = daytab[i].dayle;
200
201         daylbegin = sunday(daylbegin);
202         daylend = sunday(daylend);
203         if(daylight &&
204             (dayno>daylbegin || (dayno==daylbegin && hour>=2)) &&
205             (dayno<daylend || (dayno==daylend && hour<1)))
206                 dl_correction = -1*60*60;
207         else
208                 dl_correction = 0;
209
210         /* Calculate seconds since 00:00:00 1/1/1970. */
211
212         s = ( ( s*24 +hour)*60 +min)*60 + sec + dl_correction;
213         return(s+timezone);
214 }
215
216
217 /* Cracks dates in the form YYYYMMDD and YYYYMMDDHHMMSS.  */
218
219 static int
220 get_absolute_date(
221         char    *ptr,
222         time_t  *timestamp)
223 {
224         int     l;
225         int     yr;
226         int     mon;
227         int     day;
228         int     hr;
229         int     mn;
230         int     sec;
231         char    date[9];
232         char    *last_char;
233
234         if (strlen(ptr) != 8 && strlen(ptr) != 14)
235                 return(0);
236         strncpy(date, ptr, 8);
237         date[8] = '\0';
238         l = atol(date);
239         if (l < MIN_HD_DATE)
240                 return(0);
241         yr = l / 10000;
242         l = l % 10000;
243         mon = l / 100;
244         if (mon < 0 || mon > 12)
245                 return(0);
246         day = l % 100;
247
248         /* Note: invalid day numbers are caught in cnvdate */
249
250         ptr+=8;
251
252         l = strtol(ptr, &last_char, 10);
253         if (l < 0 || l>235959 || *last_char != '\0')
254                 return(0);
255         hr = l / 10000;
256         if (hr > 23)
257                 return(0);
258         l = l % 10000;
259         mn = l / 100;
260         if (mn > 59)
261                 return(0);
262         sec = l % 100;
263         if (sec > 59)
264                 return(0);
265
266         /* Get timestamp. */
267
268         (void)tzset();
269         if ((*timestamp = cnvdate(mon, day, yr, hr, mn, sec)) < 0) {
270                 return(0);
271         }
272
273         return(1);
274 }
275
276
277 /* Cracks dates in the form:   NNs, NNm, NNh, or NNd which are interpreted
278    as NN seconds, minutes, hours, or days prior to the current time, 
279    respectively.
280 */
281
282 static int
283 get_relative_date(
284         char    *ptr,
285         time_t  *timestamp)
286 {
287         int     l;
288         char    *last_char;
289
290         if (!isdigit(*ptr))
291                 return(0);
292         l = strtol (ptr, &last_char, 10);
293         (void) time(timestamp);
294         if (strcmp(last_char, "s") == 0)
295                 /* do nothing */;
296         else if (strcmp(last_char, "m") == 0)
297                 l = l * 60;
298         else if (strcmp(last_char, "h") == 0)
299                 l = l * 60 * 60;
300         else if (strcmp(last_char, "d") == 0)
301                 l = l * 60 * 60 * 24;
302         else
303                 return(0);
304         *timestamp -= l;
305         if (*timestamp < MIN_HD_TMSTAMP)
306                 return(0);
307         return(1);
308 }
309
310
311 static void
312 usage(void)
313 {
314         fprintf(stderr, "Usage: %s [-M mode] [-u uid] [-g gid] [-a atime] \\\n"
315                 "\t[-m mtime] [-c ctime] [-d dtime] [-S size] [-s sid] pathname\n",
316                 Progname);
317         fprintf(stderr, "\nDates can either be absolute:\n");
318         fprintf(stderr, "\t\tYYYYMMDD or YYYYMMDDHHMMSS\n");
319         fprintf(stderr, "or relative (prior to) the current time:\n");
320         fprintf(stderr, "\tNNs (seconds), NNm (minutes), NNh (hours), "
321                 " or NNd (days)\n");
322         exit(1);
323 }
324
325
326 int
327 main(
328         int     argc,
329         char    **argv)
330 {
331         dm_sessid_t     sid = DM_NO_SESSION;
332         void            *hanp;
333         size_t          hlen;
334         dm_fileattr_t   fileattr;
335         u_int           mask = 0;
336         char            *pathname;
337         char            *name;
338         int             opt;
339
340         if (Progname = strrchr(argv[0], '/')) {
341                 Progname++;
342         } else {
343                 Progname = argv[0];
344         }
345
346         opterr = 0;
347         while ((opt = getopt(argc, argv, "M:u:g:a:m:c:d:S:s:")) != EOF) {
348                 switch (opt) {
349                 case 'M':
350                         mask |= DM_AT_MODE;
351                         fileattr.fa_mode = strtol (optarg, NULL, 8);
352                         break;
353                 case 'u':
354                         mask |= DM_AT_UID;
355                         fileattr.fa_uid = atol(optarg);
356                         break;
357                 case 'g':
358                         mask |= DM_AT_GID;
359                         fileattr.fa_gid = atol(optarg);
360                         break;
361                 case 'a':
362                         mask |= DM_AT_ATIME;
363                         if (get_absolute_date(optarg, &fileattr.FA_ATIME))
364                                 break;
365                         if (get_relative_date(optarg, &fileattr.FA_ATIME))
366                                 break;
367                         usage();
368                 case 'm':
369                         mask |= DM_AT_MTIME;
370                         if (get_absolute_date(optarg, &fileattr.FA_MTIME))
371                                 break;
372                         if (get_relative_date(optarg, &fileattr.FA_MTIME))
373                                 break;
374                         usage();
375                 case 'c':
376                         mask |= DM_AT_CTIME;
377                         if (get_absolute_date(optarg, &fileattr.FA_CTIME))
378                                 break;
379                         if (get_relative_date(optarg, &fileattr.FA_CTIME))
380                                 break;
381                         usage();
382                 case 'd':
383                         mask |= DM_AT_DTIME;
384                         if (get_absolute_date(optarg, &fileattr.FA_DTIME))
385                                 break;
386                         if (get_relative_date(optarg, &fileattr.FA_DTIME))
387                                 break;
388                         usage();
389                 case 'S':
390                         mask |= DM_AT_SIZE;
391                         fileattr.fa_size = atol(optarg);
392                         break;
393                 case 's':
394                         sid = atol(optarg);
395                         break;
396                 case '?':
397                         usage();
398                 }
399         }
400         if (optind + 1 != argc) {
401                 usage();
402         }
403         pathname = argv[optind];
404
405         if (dm_init_service(&name) == -1)  {
406                 fprintf(stderr, "Can't inititalize the DMAPI\n");
407                 exit(1);
408         }
409         if (sid == DM_NO_SESSION)
410                 find_test_session(&sid);
411
412         if (dm_path_to_handle(pathname, &hanp, &hlen)) {
413                 fprintf(stderr, "dm_path_to_handle failed, %s\n",
414                         strerror(errno));
415                 exit(1);
416         }
417
418         if (dm_set_fileattr(sid, hanp, hlen, DM_NO_TOKEN, mask, &fileattr)) {
419                 fprintf(stderr, "dm_set_fileattr failed, %s\n",
420                         strerror(errno));
421                 exit(1);
422         }
423         exit(0);
424 }