7266713e27faf8e60c3d7863cd0a53a682a95902
[xfstests-dev.git] / dmapi / src / suite2 / src / test_invis.c
1 /*
2  * Copyright (c) 2000-2001 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21
22 #include <limits.h>
23
24 #include <lib/hsm.h>
25 #include <lib/errtest.h>
26
27 #include <getopt.h>
28 #include <string.h>
29 #include <time.h>
30
31 /*---------------------------------------------------------------------------
32
33 Automated test of the DMAPI functions dm_write_invis() and dm_read_invis()
34
35 The command line is:
36
37         test_invis [-s sid] [-v] ls_path pathname
38
39 where:
40    sid
41       is the session ID whose events you you are interested in.
42    ls_path
43       is the path to a specific copy of ls, important only for its size
44    pathname
45       is the filesystem to use for the test.
46
47 DM_WRITE_SYNC is is not supported.
48 ----------------------------------------------------------------------------*/
49
50 #define OFF_MAX  50
51 #define OFF_STEP 5
52 #define LEN_MAX  50
53 #define LEN_STEP 5
54
55 #ifndef linux
56 extern  char    *sys_errlist[];
57 #endif
58 extern  int     optind;
59 extern  char    *optarg;
60
61
62 char    *Progname;
63
64
65 static void
66 usage(void)
67 {
68         fprintf(stderr, "usage:\t%s [-v] [-s sid] ls_path pathname\n", 
69                 Progname);
70         exit(1);
71 }
72
73
74 int
75 main(
76         int     argc, 
77         char    **argv)
78 {
79         dm_sessid_t     sid = DM_NO_SESSION;
80         char            *dir_name = NULL;
81         char            *ls_path = NULL;
82         dm_off_t        offset = 0;
83         dm_size_t       length = 1;
84         dm_size_t       curlength = 0;
85         u_char          ch;
86         void            *bufp = NULL;
87         void            *hanp;
88         size_t          hlen;
89         dm_ssize_t      rc;
90         char            *name;
91         char            test_file[128];
92         char            command[128];
93         int             opt;
94         int             i;
95         int             j;
96         int             k;
97         int             Vflag=0;
98         struct stat     statbuf;
99         struct stat     checkbuf;
100         dm_token_t      test_token;
101         void*           test_vp;
102         int             cont;
103         int             error_reported;
104
105         Progname = strrchr(argv[0], '/');
106         if (Progname) {
107                 Progname++;
108         } else {
109                 Progname = argv[0];
110         }
111
112         /* Crack and validate the command line options. */
113
114         while ((opt = getopt(argc, argv, "vs:")) != EOF) {
115                 switch (opt) {
116                 case 'v':
117                         Vflag++;
118                         break;
119                 case 's':
120                         sid = atol(optarg);
121                         break;
122                 case '?':
123                         usage();
124                 }
125         }
126         if (optind + 2 != argc)
127                 usage();
128         ls_path = argv[optind];
129         dir_name = argv[optind+1];
130
131         if (dm_init_service(&name) == -1)  {
132                 fprintf(stderr, "Can't initialize the DMAPI\n");
133                 exit(1);
134         }
135         if (sid == DM_NO_SESSION)
136                 find_test_session(&sid);
137         
138         /* Get a random character for read/write tests */
139         srand((unsigned int)time(NULL));
140         ch = (u_char)rand(); 
141
142         printf("Invisible read/write tests beginning...\n");
143         
144         /* File creation loop*/
145         for(i=0; i<LEN_MAX; i+=LEN_STEP) {
146           for (j=0; j<OFF_MAX; j+=OFF_STEP) {
147             sprintf(test_file, "%s/DMAPI_invis_test_file.%02d%02d", 
148                     dir_name, i, j);
149             sprintf(command, "cp %s %s\n", ls_path, test_file); 
150             system(command);
151           }
152         }
153         
154         /* Write to files, then read them to check for correct results. 
155            Do timestamp checking along the way. */
156
157         for(i=0; i<LEN_MAX; i+=LEN_STEP) {
158           for (j=0; j<OFF_MAX; j+=OFF_STEP) {
159
160 #define max(a,b) ((a) > (b) ? (a) : (b))
161             length = max((dm_size_t)(i), length);
162             offset = (dm_off_t)(j);
163
164             sprintf(test_file, "%s/DMAPI_invis_test_file.%02d%02d", 
165                     dir_name, i, j);
166             
167             if (stat(test_file, &statbuf)){
168               fprintf(stdout, 
169                       "Error: unable to stat test file; %s (before test)\n", 
170                       test_file);
171               continue;
172             }
173             
174             if (dm_path_to_handle(test_file, &hanp, &hlen)) {
175               fprintf(stderr, "can't get handle for %s; bypassing test\n",
176                       test_file);
177               continue;
178             }
179             
180             if (length > curlength) {
181               if(curlength>0)
182                 free(bufp);
183               if ((bufp = malloc(length)) == NULL) {
184                 fprintf(stderr, "malloc of %llu bytes failed\n",
185                         (unsigned long long) length);
186                 continue;
187               }
188               curlength = length;
189               memset(bufp, ch, length);
190             }
191
192             rc = dm_write_invis(sid, hanp, hlen, DM_NO_TOKEN,
193                                 0, offset, length, bufp);
194             cont = 0;
195             if (rc < 0) {
196               fprintf(stderr, "dm_write_invis failed, %s\n", ERR_NAME);
197               cont=1;
198             } else if (rc != length) {
199               fprintf(stderr, "expected to write %lld bytes, actually "
200                       "wrote %lld\n", (long long) length, (long long) rc);
201               cont=1;
202             }
203             if(cont)
204                 continue;
205             
206             /* Timestamp checking, part 1 */
207             if (stat(test_file, &checkbuf)){
208               fprintf(stdout, 
209                       "Error: unable to stat the test file; %s (after write)\n", 
210                       test_file);
211             }
212             else {
213               if ((statbuf.st_atime == checkbuf.st_atime) &&
214               (statbuf.st_mtime == checkbuf.st_mtime) &&
215               (statbuf.st_ctime == checkbuf.st_ctime))
216                 {
217                 if (Vflag) {
218                   printf("Report: time stamp unchanged by write\n");
219                 }
220               }
221               else {
222                 printf("Error: time stamp changed by write\n");
223               }
224             }
225             
226             rc = dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN,
227                                 offset, length, bufp);
228             if (rc < 0) {
229               fprintf(stderr, "dm_read_invis failed, %s\n", ERR_NAME);
230               continue;
231             } 
232             else if (rc != length) {
233               fprintf(stderr, "expected to read %lld bytes, actually "
234                       "wrote %lld\n", (long long) length, (long long) rc);
235               continue;
236             }
237             else {
238               /* Be sure the buffer is filled with the test char */
239               error_reported = 0;
240               for (k=0; k<i; k++){
241                 if (((u_char *)bufp)[k] == ch) {
242                   if (Vflag) printf(".");
243                 }
244                 else {
245                   if(!error_reported){
246                         printf("Error!(line=%d)\n", __LINE__);
247                         error_reported++;
248                   }
249                 }
250               }
251               if (Vflag) printf("\n");
252             }
253
254             /* Timestamp checking, part 2 */
255             if (stat(test_file, &statbuf)){
256               fprintf(stdout, 
257                       "Error: unable to stat the test file; %s (after write)\n", 
258                       test_file);
259             }
260             else {
261               if ((statbuf.st_atime == checkbuf.st_atime) &&
262               (statbuf.st_mtime == checkbuf.st_mtime) &&
263               (statbuf.st_ctime == checkbuf.st_ctime))
264                 {
265                 if (Vflag) {
266                   printf("Report: time stamp unchanged by read\n");
267                 }
268               }
269               else {
270                 printf("Error: time stamp changed by read\n");
271               }
272             }
273           } /* for (j=0; j<OFF_MAX; j+=OFF_STEP) */
274         } /* for(i=0; i<LEN_MAX; i+=LEN_STEP) */
275         
276         /* File deletion loop*/
277         for(i=0; i<LEN_MAX; i+=LEN_STEP) {
278           for(j=0; j<OFF_MAX; j+=OFF_STEP) {
279             sprintf(test_file, "%s/DMAPI_invis_test_file.%02d%02d", 
280                     dir_name, i, j);
281             sprintf(command, "rm %s\n", test_file); 
282             system(command);
283           }
284         }
285         
286         /*************************************\
287         |* Correct-input testing complete.   *|
288         |* Beginning improper-input testing. *|
289         \*************************************/
290         sprintf(test_file, "%s/DMAPI_invis_test_file.ERRNO", 
291                 dir_name);
292         sprintf(command, "cp %s %s\n", ls_path, test_file); 
293         system(command);
294
295         if (dm_path_to_handle(test_file, &hanp, &hlen)) {
296           fprintf(stderr, "can't get handle for %s; bypassing errno tests\n",
297                   test_file);
298         }
299         else {
300           dm_off_t offset;
301
302           /* Try writing a character waaaaaay up in the millions range */
303           sprintf(bufp, "%c", ch);
304           if (stat(test_file, &statbuf)){
305            fprintf(stdout, 
306                     "Error: unable to stat the test file; %s \n", 
307                     test_file);
308           }
309           offset = ((1000000*(dm_off_t)(ch)) > statbuf.st_size) ? 
310                             statbuf.st_size : (1000000*(dm_off_t)(ch));
311           if (dm_write_invis(sid, hanp, hlen, DM_NO_TOKEN, 0, 
312                              offset, 1, bufp)==-1){
313             printf("Error invis-writing 0x%x at byte 0x%x million: %s\n", 
314                    *(u_char *)bufp, (unsigned int)ch, ERR_NAME);
315           }
316           else if (dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN,
317                                  offset, 1, bufp)==-1){
318             printf("Error invis-reading at byte %u million: %s\n",
319                    (unsigned int)ch, ERR_NAME);
320           }
321           else if (((u_char *)bufp)[0]!=ch) {
322             printf("Error: wanted to read %c and instead got %s.\n",
323                    ch, (u_char *)bufp);
324           }
325           else if (Vflag) {
326             printf("Report: \"0x%x\" was written and \"0x%x\" was read "
327                    "at byte %d million.\n", ch, *(u_char *)bufp, ch);
328           }
329           printf("\t(errno subtests beginning...)\n");
330           /**** WRITE tests ****/
331           /*---------------------------------------------------------*/
332           EXCLTEST("write", hanp, hlen, test_token, 
333                    dm_write_invis(sid, hanp, hlen, test_token,
334                                   0, 0, 13, "write test 1"))
335           /*---------------------------------------------------------*/
336             if ((test_vp = handle_clone(hanp, hlen)) == NULL) {
337             fprintf(stderr, 
338                     "Cannot create a test handle (%s); skipping EBADF test\n",
339                     ERR_NAME);
340           }
341           else {
342             ((char *) test_vp)[hlen/2]++;
343             ERRTEST(EBADF,
344                     "write",
345                     dm_write_invis(sid, test_vp, hlen, DM_NO_TOKEN,
346                                    0, 0, 0, bufp))
347             ERRTEST(EBADF,
348                     "read",
349                     dm_read_invis(sid, test_vp, hlen, DM_NO_TOKEN,
350                                   0, 0, bufp))
351             dm_handle_free(test_vp, hlen);
352           }
353
354           /*---------------------------------------------------------*/
355           ERRTEST(EBADF,
356                   "write",
357                   dm_write_invis(sid, hanp, hlen-1, DM_NO_TOKEN,
358                                  0, 0, 0, NULL))
359           /*---------------------------------------------------------*/
360           ERRTEST(EFAULT,
361                   "write",
362                   dm_write_invis(sid, NULL, hlen, DM_NO_TOKEN,
363                                  0, 0, 0, NULL))
364           /*---------------------------------------------------------*/
365 #if 0
366           PROBLEM: write_invis refuses to produce EINVAL for 
367           lengths that will not fit in a dm_size_t.
368
369           ERRTEST(EINVAL,
370                   "(bad length) write",
371                   dm_write_invis(sid, hanp, hlen, DM_NO_TOKEN,
372                                  0, 4096, (long long)0xFFFFFFFFFFFFFFFFLL,
373                                  "write invalid length test"))
374 #endif
375           /*---------------------------------------------------------*/
376 #if 0
377           PROBLEM (somewhat fixed): A signal is sent, rather than EFBIG.
378           Presumably, this signal is needed to comply with...something.
379           If this is uncommented, the program will abort here, with the 
380           error message "exceeded file size limit". 
381
382           ERRTEST(EFBIG,
383                   "write",
384                   dm_write_invis(sid, hanp, hlen, DM_NO_TOKEN,
385                                  0, (long long)0xFFFFFFFFFFLL, 
386                                  (long long)0xFFFFFFFFFFLL,
387                                  "foo foo foo"))
388 #endif
389           /*---------------------------------------------------------*/
390 #ifdef VERITAS_21
391           ERRTEST(EINVAL,
392                   "(bad offset) write",
393                   dm_write_invis(sid, hanp, hlen, DM_NO_TOKEN,
394                                  0, (dm_size_t) ULONG_MAX, 5,
395                                  "write invalid offset test"))
396 #else
397 #ifndef linux
398           ERRTEST(EINVAL,
399                   "(bad offset) write",
400                   dm_write_invis(sid, hanp, hlen, DM_NO_TOKEN,
401                                  0, (dm_size_t) ULONGLONG_MAX, 5,
402                                  "write invalid offset test"))
403 #endif
404 #endif
405
406           /*---------------------------------------------------------*/
407           ERRTEST(EINVAL,
408                   "(bad sid) write",
409                   dm_write_invis(-100, hanp, hlen, DM_NO_TOKEN,
410                                  0, 0, 26, "write invalid offset test"))
411
412
413           /**** READ tests ****/
414           /*---------------------------------------------------------*/
415           SHAREDTEST("read", hanp, hlen, test_token,
416                      dm_read_invis(sid, hanp, hlen, test_token, 
417                                    0, 13, bufp))
418           /*---------------------------------------------------------*/
419           ERRTEST(EBADF,
420                   "read",
421                   dm_read_invis(sid, hanp, hlen-1, DM_NO_TOKEN,
422                                  0, 0, bufp))
423           /*---------------------------------------------------------*/
424           ERRTEST(EFAULT,
425                   "read",
426                   dm_read_invis(sid, NULL, hlen, DM_NO_TOKEN,
427                                  0, 0, bufp))
428           /*---------------------------------------------------------*/
429 #ifdef  VERITAS_21
430           ERRTEST(EINVAL,
431                   "(bad offset) read",
432                   dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN,
433                                 ULONG_MAX, 5, bufp));
434 #else
435 #ifndef linux
436           ERRTEST(EINVAL,
437                   "(bad offset) read",
438                   dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN,
439                                 ULONGLONG_MAX, 5, bufp));
440 #endif
441 #endif
442
443           /*---------------------------------------------------------*/
444           ERRTEST(EINVAL,
445                   "(bad sid) read",
446                   dm_read_invis(-100, hanp, hlen, DM_NO_TOKEN,
447                                 0, 5, bufp))
448           /*---------------------------------------------------------*/
449           printf("\t(errno subtests complete!)\n");
450         }
451         sprintf(test_file, "%s/DMAPI_invis_test_file.ERRNO", 
452                 dir_name);
453         sprintf(command, "rm %s \n", test_file); 
454         system(command);
455
456         printf("Invisible read/write tests complete.\n");
457
458         dm_handle_free(hanp, hlen);
459         exit(0);
460 }