1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2002
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /* 10/31/2002 Port to LTP robbiew@us.ibm.com */
21 /* 06/30/2001 Port to Linux nsharoff@us.ibm.com */
22
23 /* inode1.c */
24 /*======================================================================
25 =================== TESTPLAN SEGMENT ===================
26 CALLS: mkdir, stat, open
27
28 run using TERM mode
29
30 >KEYS: < file system management I/O
31 >WHAT: < Do the system's file system management and I/O functions work
32 < correctly?
33 >HOW: < Construct a directory tree, create files in it, and verify
34 < that this was done as expected.
35 >BUGS: <
36 ======================================================================*/
37 /* modified by dale 25-Jul-84 */
38
39 /************************************************/
40 #define PATH_STRING_LENGTH 100
41 #define NAME_LENGTH 8
42 #define MAX_PATH_STRING_LENGTH (PATH_STRING_LENGTH - NAME_LENGTH)
43 #define MAX_DEPTH 3
44 #define MAX_BREADTH 3
45 #define FILE_LENGTH 100
46 #define DIRECTORY_MODE 00777
47 #define FILE_MODE 00777
48
49 /* #define PRINT define to get list while running */
50
51 #define TRUE 1
52 #define FALSE 0
53 #define READ 0
54 #define WRITE 1
55
56 #include <stdio.h>
57 #include <errno.h>
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #include <fcntl.h>
61 #include <signal.h>
62 #include <errno.h>
63
64 /** LTP Port **/
65 #include "test.h"
66
67 void blexit(void);
68 void blenter(void);
69 void setup(void);
70 void fail_exit(void);
71 void anyfail(void);
72 void ok_exit(void);
73
74 #define FAILED 0
75 #define PASSED 1
76
77 int local_flag = PASSED;
78 int block_number;
79 FILE *temp;
80
81 char *TCID = "inode01"; /* Test program identifier. */
82 int TST_TOTAL = 2; /* Total number of test cases. */
83 /**************/
84
85 #ifdef LINUX
86 #include <string.h>
87 #endif
88
89 char name[NAME_LENGTH + 1];
90 char path_string[PATH_STRING_LENGTH + 1];
91 char read_string[PATH_STRING_LENGTH + 1];
92 char write_string[PATH_STRING_LENGTH + 1];
93 char rm_string[200];
94
95 FILE *list_stream = NULL;
96 int file_id;
97 int list_id;
98
99 int increment_name(), get_next_name(), mode(), escrivez();
100
main(void)101 int main(void)
102 {
103 char root[16]; //as pids can get much longer
104 int gen_ret_val, ch_ret_val, level;
105 int ret_val;
106 int generate(), check();
107 char path_list_string[PATH_STRING_LENGTH + 1];
108 int status;
109 int len;
110 int term();
111 int snp_ret;
112
113 strcpy(path_string, "inode");
114 sprintf(root, "A%d", getpid());
115 strcat(path_string, root);
116
117 strcpy(rm_string, "rm -rf ");
118 strcat(rm_string, path_string);
119
120 setup();
121
122 if (signal(SIGTERM, (void (*)())term) == SIG_ERR) {
123 fprintf(temp, "\tSIGTERM signal set failed!, errno=%d\n",
124 errno);
125 fail_exit();
126 }
127
128 blenter();
129
130 /********************************/
131 /* */
132 /* make the root directory for */
133 /* the tree */
134 /* */
135 /********************************/
136
137 ret_val = mkdir(path_string, DIRECTORY_MODE);
138
139 if (ret_val == -1) {
140 perror("mkdir error");
141 fprintf(temp, "\tcreating directory '%s'\n", path_string);
142 fprintf(temp, "\t\n%s Impossible to create directory %s\n",
143 root, path_string);
144 fail_exit();
145 }
146 #ifdef PRINT
147 printf("\n%s\n", path_string);
148 #endif
149
150 /****************************************/
151 /* */
152 /* create the "path_list" file, in */
153 /* which the list of generated paths */
154 /* will be stored so that they later */
155 /* may be checked */
156 /* */
157 /****************************************/
158
159 snp_ret = snprintf(path_list_string, sizeof(path_list_string),
160 "%s/path_list", path_string);
161 if (snp_ret < 0 || snp_ret >= sizeof(path_list_string)) {
162 tst_resm(TBROK, "snprintf(path_list_string,..) returned %d",
163 snp_ret);
164 fail_exit();
165 }
166 list_id = creat(path_list_string, FILE_MODE);
167 if (list_id == -1) {
168 fprintf(temp,
169 "\t\n%s The path_list file cannot be created, errno=%d \n",
170 root, errno);
171 fail_exit();
172 }
173
174 /****************************************/
175 /* */
176 /* and store its name in path_list */
177 /* */
178 /****************************************/
179
180 strcpy(write_string, path_string);
181 len = strlen(write_string);
182 write_string[len++] = 'D';
183 write_string[len] = '\0';
184 escrivez(write_string);
185
186 /****************************************/
187 /* */
188 /* generate the directory-file tree */
189 /* */
190 /****************************************/
191
192 level = 0;
193
194 #ifdef PRINT
195 printf("\n\t%s\n\n", "GENERATING:");
196 #endif
197
198 gen_ret_val = generate(path_string, level);
199
200 if (gen_ret_val) {
201 fprintf(temp,
202 "Failure occured in generate routine, return value %d\n",
203 gen_ret_val);
204 local_flag = FAILED;
205 }
206
207 blexit();
208 blenter();
209
210 close(list_id);
211 list_id = open(path_list_string, READ);
212 if (list_id == -1) {
213 fprintf(temp,
214 "\t\n%s The path_list file cannot be opened for reading, errno=%d\n",
215 root, errno);
216 fail_exit();
217 }
218 list_stream = fdopen(list_id, "r");
219
220 /****************************************/
221 /* */
222 /* check the directory-file tree */
223 /* for correctness */
224 /* */
225 /****************************************/
226
227 #ifdef PRINT
228 printf("\n\t%s\n\n", "CHECKING:");
229 #endif
230
231 ch_ret_val = check();
232
233 if (ch_ret_val) {
234 fprintf(temp,
235 "Failure occured in check routine, return value %d\n",
236 ch_ret_val);
237 local_flag = FAILED;
238 }
239
240 status = fclose(list_stream);
241 if (status != 0) {
242 fprintf(temp,
243 "Failed to close list_stream: ret=%d errno=%d (%s)\n",
244 status, errno, strerror(errno));
245 local_flag = FAILED;
246 }
247
248 blexit();
249
250 /*
251 * Now fork and exec a system call to remove the directory.
252 */
253
254 #ifdef DEBUG
255 fprintf(temp, "\nClean up:\trm string = %s\n", rm_string);
256 #endif
257 fflush(stdout);
258 fflush(temp);
259
260 status = system(rm_string);
261
262 if (status) {
263 fprintf(temp, "Caution-``%s'' may have failed\n", rm_string);
264 fprintf(temp, "rm command exit status = %d\n", status);
265 }
266
267 /****************************************/
268 /* */
269 /* .....and exit main */
270 /* */
271 /****************************************/
272
273 anyfail();
274 /***** NOT REACHED ******/
275 tst_exit();
276 }
277
generate(char * string,int level)278 int generate(char *string, int level)
279
280 /****************************************/
281 /* */
282 /* generate recursively a tree of */
283 /* directories and files: within */
284 /* created directory, an alternating */
285 /* series of files and directories */
286 /* are constructed---until tree */
287 /* breadth and depth limits are */
288 /* reached or an error occurs */
289 /* */
290 /****************************************/
291 /***************************/
292 /* string[] */
293 /* the directory path */
294 /* string below which a */
295 /* tree is generated */
296 /* */
297 /***************************/
298
299 /***************************/
300 /* level */
301 /* the tree depth variable */
302 /* */
303 /***************************/
304 {
305 int switch_flag;
306 int ret_val = 0;
307 int new_ret_val, len, ret_len;
308 char new_string[PATH_STRING_LENGTH + 1];
309 int new_level;
310 int i, j; /* iteration counters */
311 int snp_ret;
312
313 switch_flag = level & TRUE;
314 if (strlen(string) >= MAX_PATH_STRING_LENGTH) {
315
316 /********************************/
317 /* */
318 /* Maximum path name length */
319 /* reached */
320 /* */
321 /********************************/
322
323 fprintf(temp, "\tMaximum path_name length reached.\n");
324 return (-1);
325 } else if (level < MAX_DEPTH) {
326 for (i = 0; i <= MAX_BREADTH; i++) {
327 get_next_name();
328 snp_ret = snprintf(new_string, sizeof(new_string),
329 "%s/%s", string, name);
330 if (snp_ret < 0 || snp_ret >= sizeof(new_string)) {
331 tst_resm(TBROK, "snprintf(new_string,..) "
332 "returned %d", snp_ret);
333 fail_exit();
334 }
335
336 /****************************************/
337 /* */
338 /* switch between creating files */
339 /* and making directories */
340 /* */
341 /****************************************/
342
343 if (switch_flag) {
344 switch_flag = FALSE;
345
346 /****************************************/
347 /* */
348 /* create a new file */
349 /* */
350 /****************************************/
351
352 file_id = creat(new_string, FILE_MODE);
353 if (file_id == -1) {
354 fprintf(temp,
355 "\tImpossible to create file %s, errno=%d\n",
356 new_string, errno);
357 return (-2);
358 }
359 #ifdef PRINT
360 printf("%d %s F\n", level, new_string);
361 #endif
362
363 /****************************************/
364 /* */
365 /* write to it */
366 /* */
367 /****************************************/
368
369 len = strlen(new_string);
370 for (j = 1; j <= FILE_LENGTH; j++) {
371 ret_len =
372 write(file_id, new_string, len);
373 if (ret_len != len) {
374 fprintf(temp,
375 "\tUnsuccessful write to file %s, expected return of %d, got %d, errno=%d\n",
376 new_string, len,
377 ret_len, errno);
378 return (-3);
379 }
380 }
381 close(file_id);
382
383 /****************************************/
384 /* */
385 /* and store its name in path_list */
386 /* */
387 /****************************************/
388
389 strcpy(write_string, new_string);
390 len = strlen(write_string);
391 write_string[len++] = 'F';
392 write_string[len] = '\0';
393 escrivez(write_string);
394 } else {
395 switch_flag = TRUE;
396
397 /****************************************/
398 /* */
399 /* or make a directory */
400 /* */
401 /****************************************/
402
403 ret_val = mkdir(new_string, DIRECTORY_MODE);
404
405 if (ret_val != 0) {
406 fprintf(temp,
407 "\tImpossible to create directory %s, errno=%d\n",
408 new_string, errno);
409 return (-5);
410 }
411 #ifdef PRINT
412 printf("%d %s D\n", level, new_string);
413 #endif
414
415 /****************************************/
416 /* */
417 /* store its name in path_list */
418 /* */
419 /****************************************/
420
421 strcpy(write_string, new_string);
422 len = strlen(write_string);
423 write_string[len++] = 'D';
424 write_string[len] = '\0';
425 escrivez(write_string);
426
427 /****************************************/
428 /* */
429 /* and generate a new level */
430 /* */
431 /****************************************/
432
433 new_level = level + 1;
434 new_ret_val = generate(new_string, new_level);
435 if (new_ret_val < ret_val)
436 ret_val = new_ret_val;
437 }
438 }
439
440 /********************************/
441 /* */
442 /* Maximum breadth reached */
443 /* */
444 /********************************/
445
446 return (ret_val);
447 } else
448 /********************************/
449 /* */
450 /* Maximum depth reached */
451 /* */
452 /********************************/
453 return 0;
454 }
455
check(void)456 int check(void)
457
458 /****************************************/
459 /* */
460 /* check for file and directory */
461 /* correctness by reading records */
462 /* from the path_list and attempting */
463 /* to determine if the corresponding */
464 /* files or directories are as */
465 /* created */
466 /* */
467 /****************************************/
468 {
469 int len, path_mode, val, ret_len, j;
470
471 for (;;) {
472
473 /****************************************/
474 /* */
475 /* read a path string from path_list */
476 /* */
477 /****************************************/
478
479 if (fscanf(list_stream, "%s", path_string) == EOF) {
480
481 #ifdef PRINT
482 printf("\nEnd of path_list file reached \n");
483 #endif
484
485 return 0;
486 }
487 #ifdef PRINT
488 printf("%s\n", path_string);
489 #endif
490
491 len = strlen(path_string);
492 len--;
493 if (path_string[len] == 'F') {
494
495 /********************************/
496 /* */
497 /* this should be a file */
498 /* */
499 /********************************/
500
501 path_string[len] = '\0';
502 file_id = open(path_string, READ);
503 if (file_id <= 0) {
504 fprintf(temp,
505 "\tImpossible to open file %s, errno=%d\n",
506 path_string, errno);
507 return (-1);
508 }
509
510 else {
511 /********************************/
512 /* */
513 /* check its contents */
514 /* */
515 /********************************/
516
517 len = strlen(path_string);
518 for (j = 1; j <= FILE_LENGTH; j++) {
519 ret_len =
520 read(file_id, read_string, len);
521 if (len != ret_len) {
522 fprintf(temp,
523 "\tFile read error for file %s, expected return of %d, got %d, errno=%d\n",
524 path_string, len,
525 ret_len, errno);
526 return (-3);
527 }
528 read_string[len] = '\0';
529 val = strcmp(read_string, path_string);
530 if (val != 0) {
531 fprintf(temp,
532 "\tContents of file %s are different than expected: %s\n",
533 path_string,
534 read_string);
535 return (-4);
536 }
537 }
538 close(file_id);
539 } /* else for */
540 if (ret_len <= 0) {
541 fprintf(temp, "\tImpossible to read file %s\n",
542 path_string);
543 return (-2);
544 }
545 } else {
546
547 /********************************/
548 /* */
549 /* otherwise.......... */
550 /* it should be a directory */
551 /* */
552 /********************************/
553
554 path_string[len] = '\0';
555 path_mode = mode(path_string);
556 if (path_mode == -1) {
557 fprintf(temp,
558 "\tPreviously created directory path %s was not open\n",
559 path_string);
560 return (-4);
561 }
562 if ((040000 & path_mode) != 040000) {
563 fprintf(temp,
564 "\tPath %s was not recognized to be a directory\n",
565 path_string);
566 fprintf(temp, "\tIts mode is %o\n", path_mode);
567 return (-5);
568 }
569 }
570 } /* while */
571 }
572
get_next_name(void)573 int get_next_name(void)
574
575 /****************************************/
576 /* */
577 /* get the next---in a dictionary */
578 /* sense---file or directory name */
579 /* */
580 /****************************************/
581 {
582 static int k;
583 int i;
584 int last_position;
585
586 last_position = NAME_LENGTH - 1;
587 if (k == 0) {
588
589 /************************/
590 /* */
591 /* initialize name */
592 /* */
593 /************************/
594
595 for (i = 0; i < NAME_LENGTH; i++)
596 name[i] = 'a';
597 name[NAME_LENGTH] = '\0';
598 k++;
599 }
600 /********************************/
601 /* */
602 else
603 increment_name(last_position); /* i.e., beginning at the last */
604 /* position */
605 /* */
606 /********************************/
607 return 0;
608 }
609
increment_name(int position)610 int increment_name(int position)
611
612 /****************************************/
613 /* */
614 /* recursively revise the letters in */
615 /* a name to get the lexiographically */
616 /* next name */
617 /* */
618 /****************************************/
619 {
620 int next_position;
621
622 if (name[position] == 'z')
623 if (position == 0) {
624 fprintf(temp,
625 "\tERROR: There are no more available names\n");
626 fail_exit();
627 } else {
628 name[position] = 'a'; /**********************/
629 next_position = --position; /* */
630 increment_name(next_position); /* increment the */
631 /* previous letter */
632 /* */
633 /**********************/
634 }
635 /*********************************/
636 /* */
637 else
638 name[position]++; /* otherwise, increment this one */
639 return 0; /* */
640 /*********************************/
641 }
642
mode(char * path_string)643 int mode(char *path_string)
644
645 /****************************************/
646 /* */
647 /* determine and return the mode of */
648 /* the file named by path_string */
649 /* */
650 /****************************************/
651 {
652 struct stat buf;
653 int ret_val, mod;
654
655 ret_val = stat(path_string, &buf);
656 if (ret_val == -1)
657 return (-1);
658 else {
659 mod = buf.st_mode;
660 return (mod);
661 }
662 }
663
escrivez(char * string)664 int escrivez(char *string)
665 {
666 char write_string[PATH_STRING_LENGTH + 1];
667 int len, ret_len;
668
669 strcpy(write_string, string);
670 len = strlen(write_string);
671 write_string[len] = '\n';
672 len++;
673 ret_len = write(list_id, write_string, len);
674 if (len != ret_len) {
675 fprintf(temp,
676 "\tA string of deviant length %d written to path_list, errno=%d\n",
677 ret_len, errno);
678 fail_exit();
679 }
680 return 0;
681 }
682
term(void)683 int term(void)
684 {
685 int status;
686
687 fprintf(temp, "\tterm - got SIGTERM, cleaning up.\n");
688
689 if (list_stream != NULL)
690 fclose(list_stream);
691 close(list_id);
692 close(file_id);
693
694 status = system(rm_string);
695 if (status) {
696 fprintf(temp, "Caution - ``%s'' may have failed.\n", rm_string);
697 fprintf(temp, "rm command exit status = %d\n", status);
698 }
699
700 ok_exit();
701 /***NOT REACHED***/
702 return 0;
703
704 }
705
706 /** LTP Port **/
707 /*
708 * setup
709 *
710 * Do set up - here its a dummy function
711 */
setup(void)712 void setup(void)
713 {
714 tst_tmpdir();
715 temp = stderr;
716 }
717
718 /*
719 * Function: blexit()
720 *
721 * Description: This function will exit a block, a block may be a lo
722 gical unit
723 * of a test. It will report the status if the test ie
724 fail or
725 * pass.
726 */
blexit(void)727 void blexit(void)
728 {
729 (local_flag == PASSED) ? tst_resm(TPASS, "Test block %d", block_number)
730 : tst_resm(TFAIL, "Test block %d", block_number);
731 block_number++;
732 return;
733 }
734
735 /*
736 * Function: blenter()
737 *
738 * Description: Print message on entering a new block
739 */
blenter(void)740 void blenter(void)
741 {
742 local_flag = PASSED;
743 return;
744 }
745
746 /*
747 * fail_exit()
748 *
749 * Exit on failure
750 */
fail_exit(void)751 void fail_exit(void)
752 {
753 tst_brkm(TFAIL, tst_rmdir, "Test failed");
754 }
755
756 /*
757 *
758 * Function: anyfail()
759 *
760 * Description: Exit a test.
761 */
anyfail(void)762 void anyfail(void)
763 {
764 (local_flag == FAILED) ? tst_resm(TFAIL, "Test failed")
765 : tst_resm(TPASS, "Test passed");
766 tst_rmdir();
767 tst_exit();
768 }
769
770 /*
771 * ok_exit
772 *
773 * Calling block passed the test
774 */
ok_exit(void)775 void ok_exit(void)
776 {
777 local_flag = PASSED;
778 return;
779 }
780