generic/486: Get rid of the redundant error=%d printing
[xfstests-dev.git] / src / dirstress.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  /*
20   * This is mostly a "crash & burn" test. -v turns on verbosity
21   * and -c actually fails on errors - but expected errors aren't
22   * expected...
23   */
24  
25 #include "global.h"
26
27 int verbose;
28 int pid;
29
30 int checkflag=0;
31
32 #define MKNOD_DEV 0
33
34 static int dirstress(char *dirname, int dirnum, int nfiles, int keep, int nprocs_per_dir);
35 static int create_entries(int nfiles);
36 static int scramble_entries(int nfiles);
37 static int remove_entries(int nfiles);
38
39 int
40 main(
41         int     argc,
42         char    *argv[])
43 {
44         char    *dirname;
45         int     nprocs;
46         int     nfiles;
47         int     c;
48         int     errflg;
49         int     i;
50         long    seed;
51         int     childpid;
52         int     nprocs_per_dir;
53         int     keep;
54         int     status, istatus;
55         
56         pid=getpid();
57
58         errflg = 0;
59         dirname = NULL;
60         nprocs = 4;
61         nfiles = 100;
62         seed = time(NULL);
63         nprocs_per_dir = 1;
64         keep = 0;
65         verbose = 0;
66         while ((c = getopt(argc, argv, "d:p:f:s:n:kvc")) != EOF) {
67                 switch(c) {
68                         case 'p':
69                                 nprocs = atoi(optarg);
70                                 break;
71                         case 'f':
72                                 nfiles = atoi(optarg);
73                                 break;
74                         case 'n':
75                                 nprocs_per_dir = atoi(optarg);
76                                 break;
77                         case 'd':
78                                 dirname = optarg;
79                                 break;
80                         case 's':
81                                 seed = strtol(optarg, NULL, 0);
82                                 break;
83                         case 'k':
84                                 keep = 1;
85                                 break;
86                         case '?':
87                                 errflg++;
88                                 break;
89                         case 'v':
90                                 verbose++;
91                                 break;
92                         case 'c':
93                                 checkflag++;
94                                 break;
95                 }
96         }
97         if (errflg || (dirname == NULL)) {
98                 printf("Usage: dirstress [-d dir] [-p nprocs] [-f nfiles] [-n procs per dir]\n"
99                        "                 [-v] [-s seed] [-k] [-c]\n");
100                 exit(0); 
101         }
102
103         printf("** [%d] Using seed %ld\n", pid, seed);
104         srandom(seed);
105
106         for (i = 0; i < nprocs; i++) {
107                 if (verbose) fprintf(stderr,"** [%d] fork\n", pid);
108                 childpid = fork();
109                 if (childpid < 0) {
110                         perror("Fork failed");
111                         exit(errno);
112                 }
113                 if (childpid == 0) {
114                         int r;
115                         /* child */
116                         pid=getpid();
117                         
118                         if (verbose) fprintf(stderr,"** [%d] forked\n", pid);
119                         r=dirstress(dirname, i / nprocs_per_dir, nfiles, keep, nprocs_per_dir);
120                         if (verbose) fprintf(stderr,"** [%d] exit %d\n", pid, r);
121                         exit(r);
122                 }
123         }
124         if (verbose) fprintf(stderr,"** [%d] wait\n", pid);
125         istatus=0;
126         
127         /* wait & reap children, accumulating error results */
128         while (wait(&status) != -1)
129             istatus+=status/256;
130         
131         printf("INFO: Dirstress complete\n");
132         if (verbose) fprintf(stderr,"** [%d] parent exit %d\n", pid, istatus);
133         return istatus;
134 }
135
136
137
138 int
139 dirstress(
140         char    *dirname,
141         int     dirnum,
142         int     nfiles,
143         int     keep,
144         int     nprocs_per_dir)
145 {
146         int             error;
147         char            buf[1024];
148         int             r;
149         
150         sprintf(buf, "%s/stressdir", dirname);
151         if (verbose) fprintf(stderr,"** [%d] mkdir %s 0777\n", pid, buf);
152         error = mkdir(buf, 0777);
153         if (error && (errno != EEXIST)) {
154                 perror("Create stressdir directory failed");
155                 return 1;
156         }
157
158         if (verbose) fprintf(stderr,"** [%d] chdir %s\n", pid, buf);
159         error = chdir(buf);
160         if (error) {
161                 perror("Cannot chdir to main directory");
162                 return 1;
163         }
164
165         sprintf(buf, "stress.%d", dirnum);
166         if (verbose) fprintf(stderr,"** [%d] mkdir %s 0777\n", pid, buf);
167         error = mkdir(buf, 0777);
168         if (error && (errno != EEXIST)) {
169                 perror("Create pid directory failed");
170                 return 1;
171         }
172
173         if (verbose) fprintf(stderr,"** [%d] chdir %s\n", pid, buf);
174         error = chdir(buf);
175         if (error) {
176                 perror("Cannot chdir to dirnum directory");
177                 return 1;
178         }
179
180         r=1; /* assume failure */
181         if (verbose) fprintf(stderr,"** [%d] create entries\n", pid);
182         if (create_entries(nfiles)) {
183             printf("!! [%d] create failed\n", pid);
184         } else {
185             if (verbose) fprintf(stderr,"** [%d] scramble entries\n", pid);
186             if (scramble_entries(nfiles)) {
187                 printf("!! [%d] scramble failed\n", pid);
188             } else {
189                 if (keep) {
190                     if (verbose) fprintf(stderr,"** [%d] keep entries\n", pid);
191                     r=0; /* success */
192                 } else {
193                     if (verbose) fprintf(stderr,"** [%d] remove entries\n", pid);
194                     if (remove_entries(nfiles)) {
195                         printf("!! [%d] remove failed\n", pid);
196                     } else {
197                         r=0; /* success */
198                     }
199                 }
200             }
201         }
202
203         if (verbose) fprintf(stderr,"** [%d] chdir ..\n", pid);
204         error = chdir("..");
205         if (error) {
206                 /* If this is multithreaded, then expecting a ENOENT here is fine,
207                  * and ESTALE is normal in the NFS case. */
208                 if (nprocs_per_dir > 1 && (errno == ENOENT || errno == ESTALE)) {
209                         return 0;
210                 }
211
212                 perror("Cannot chdir out of pid directory");
213                 return 1;
214         }
215
216         if (!keep) {
217                 sprintf(buf, "stress.%d", dirnum);
218                 if (verbose) fprintf(stderr,"** [%d] rmdir %s\n", pid, buf);
219                 if (rmdir(buf)) {
220                     perror("rmdir");
221                     if (checkflag) return 1;
222                 }
223         }
224         
225         if (verbose) fprintf(stderr,"** [%d] chdir ..\n", pid);
226         error = chdir("..");
227         if (error) {
228                 /* If this is multithreaded, then expecting a ENOENT here is fine,
229                  * and ESTALE is normal in the NFS case. */
230                 if (nprocs_per_dir > 1 && (errno == ENOENT || errno == ESTALE)) {
231                         return 0;
232                 }
233
234                 perror("Cannot chdir out of working directory");
235                 return 1;
236         }
237
238         if (!keep) {
239                 if (verbose) fprintf(stderr,"** [%d] rmdir stressdir\n", pid);
240                 if (rmdir("stressdir")) {
241                     perror("rmdir");
242                     if (checkflag) return 1;
243                 }
244         }
245
246         return r;
247 }
248
249 int
250 create_entries(
251        int      nfiles)
252 {
253         int     i;
254         int     fd;
255         char    buf[1024];
256
257         for (i = 0; i < nfiles; i++) {
258                 sprintf(buf, "XXXXXXXXXXXX.%d", i);
259                 switch (i % 4) {
260                 case 0:
261                         /*
262                          * Create a file
263                          */
264                         if (verbose) fprintf(stderr,"** [%d] creat %s\n", pid, buf);
265                         fd = creat(buf, 0666);
266                         if (fd > 0) {
267                                 if (verbose) fprintf(stderr,"** [%d] close %s\n", pid, buf);
268                                 close(fd);
269                         } else {
270                                 fprintf(stderr,"!! [%d] close %s failed\n", pid, buf);
271                                 perror("close");
272                                 if (checkflag) return 1;
273                         }
274                         
275                         break;
276                 case 1:
277                         /*
278                          * Make a directory.
279                          */
280                         if (verbose) fprintf(stderr,"** [%d] mkdir %s 0777\n", pid, buf);
281                         if (mkdir(buf, 0777)) {
282                             fprintf(stderr,"!! [%d] mkdir %s 0777 failed\n", pid, buf);
283                             perror("mkdir");
284                             if (checkflag) return 1;
285                         }
286                         
287                         break;
288                 case 2:
289                         /*
290                          * Make a symlink
291                          */
292                         if (verbose) fprintf(stderr,"** [%d] symlink %s %s\n", pid, buf, buf);
293                         if (symlink(buf, buf)) {
294                             fprintf(stderr,"!! [%d] symlink %s %s failed\n", pid, buf, buf);
295                             perror("symlink");
296                             if (checkflag) return 1;
297                         }
298                         
299                         break;
300                 case 3:
301                         /*
302                          * Make a dev node
303                          */
304                         if (verbose) fprintf(stderr,"** [%d] mknod %s 0x%x\n", pid, buf, MKNOD_DEV);
305                         if (mknod(buf, S_IFCHR | 0666, MKNOD_DEV)) {
306                             fprintf(stderr,"!! [%d] mknod %s 0x%x failed\n", pid, buf, MKNOD_DEV);
307                             perror("mknod");
308                             if (checkflag) return 1;
309                         }
310                         
311                         break;
312                 default:
313                         break;
314                 }
315         }
316         return 0;
317 }
318
319
320 int
321 scramble_entries(
322         int     nfiles)
323 {
324         int             i;
325         char            buf[1024];
326         char            buf1[1024];
327         long            r;
328         int             fd;
329
330         for (i = 0; i < nfiles * 2; i++) {
331                 switch (i % 5) {
332                 case 0:
333                         /*
334                          * rename two random entries
335                          */
336                         r = random() % nfiles;
337                         sprintf(buf, "XXXXXXXXXXXX.%ld", r);
338                         r = random() % nfiles;
339                         sprintf(buf1, "XXXXXXXXXXXX.%ld", r);
340
341                         if (verbose) fprintf(stderr,"** [%d] rename %s %s\n", pid, buf, buf1);
342                         if (rename(buf, buf1)) {
343                             perror("rename");
344                             if (checkflag) return 1;
345                         }
346                         break;
347                 case 1:
348                         /*
349                          * unlink a random entry
350                          */
351                         r = random() % nfiles;
352                         sprintf(buf, "XXXXXXXXXXXX.%ld", r);
353                         if (verbose) fprintf(stderr,"** [%d] unlink %s\n", pid, buf);
354                         if (unlink(buf)) {
355                             fprintf(stderr,"!! [%d] unlink %s failed\n", pid, buf);
356                             perror("unlink");
357                             if (checkflag) return 1;
358                         }
359                         break;
360                 case 2:
361                         /*
362                          * rmdir a random entry
363                          */
364                         r = random() % nfiles;
365                         sprintf(buf, "XXXXXXXXXXXX.%ld", r);
366                         if (verbose) fprintf(stderr,"** [%d] rmdir %s\n", pid, buf);
367                         if (rmdir(buf)) {
368                             fprintf(stderr,"!! [%d] rmdir %s failed\n", pid, buf);
369                             perror("rmdir");
370                             if (checkflag) return 1;
371                         }
372                         break;
373                 case 3:
374                         /*
375                          * create a random entry
376                          */
377                         r = random() % nfiles;
378                         sprintf(buf, "XXXXXXXXXXXX.%ld", r);
379
380                         if (verbose) fprintf(stderr,"** [%d] creat %s 0666\n", pid, buf);
381                         fd = creat(buf, 0666);
382                         if (fd > 0) {
383                                 if (verbose) fprintf(stderr,"** [%d] close %s\n", pid, buf);
384                                 if (close(fd)) {
385                                     fprintf(stderr,"!! [%d] close %s failed\n", pid, buf);
386                                     perror("close");
387                                     if (checkflag) return 1;
388                                 }
389                         } else {
390                             fprintf(stderr,"!! [%d] creat %s 0666 failed\n", pid, buf);
391                             perror("creat");
392                             if (checkflag) return 1;
393                         }
394                         break;
395                 case 4:
396                         /*
397                          * mkdir a random entry
398                          */
399                         r = random() % nfiles;
400                         sprintf(buf, "XXXXXXXXXXXX.%ld", r);
401                         if (verbose) fprintf(stderr,"** [%d] mkdir %s\n", pid, buf);
402                         if (mkdir(buf, 0777)) {
403                             fprintf(stderr,"!! [%d] mkdir %s failed\n", pid, buf);
404                             perror("mkdir");
405                             if (checkflag) return 1;
406                         }
407                         break;
408                 default:
409                         break;
410                 }
411         }
412         return 0;
413 }
414                         
415 int
416 remove_entries(
417         int     nfiles)
418 {
419         int             i;
420         char            buf[1024];
421         struct stat     statb;
422         int             error;
423
424         for (i = 0; i < nfiles; i++) {
425                 sprintf(buf, "XXXXXXXXXXXX.%d", i);
426                 error = lstat(buf, &statb);
427                 if (error) {
428                         /* ignore this one */
429                         continue;
430                 }
431                 if (S_ISDIR(statb.st_mode)) {
432                         if (verbose) fprintf(stderr,"** [%d] rmdir %s\n", pid, buf);
433                         if (rmdir(buf)) {
434                             fprintf(stderr,"!! [%d] rmdir %s failed\n", pid, buf);
435                             perror("rmdir");
436                             if (checkflag) return 1;
437                         }
438                 } else {
439                         if (verbose) fprintf(stderr,"** [%d] unlink %s\n", pid, buf);
440                         if (unlink(buf)) {
441                             fprintf(stderr,"!! [%d] unlink %s failed\n", pid, buf);
442                             perror("unlink");
443                             if (checkflag) return 1;
444                         }
445                 }
446         }
447         return 0;
448 }