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()101 int main()
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(string,level)278 int generate(string, 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 		/*                         */
293 char string[];			/*  the directory path     */
294 		/*  string below which a   */
295 		/*  tree is generated      */
296 		/*                         */
297 		/***************************/
298 
299 		/***************************/
300 		/*                         */
301 int level;			/* 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()456 int check()
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()573 int get_next_name()
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(position)610 int increment_name(position)
611 
612 /****************************************/
613 /*					*/
614 /*  recursively revise the letters in 	*/
615 /*  a name to get the lexiographically	*/
616 /*  next name				*/
617 /*					*/
618 /****************************************/
619  int position;
620 {
621 	int next_position;
622 
623 	if (name[position] == 'z')
624 		if (position == 0) {
625 			fprintf(temp,
626 				"\tERROR: There are no more available names\n");
627 			fail_exit();
628 		} else {
629 			name[position] = 'a';	       /**********************/
630 			next_position = --position;	/*                    */
631 			increment_name(next_position);	/*  increment the     */
632 			/*  previous letter   */
633 			/*                    */
634 						       /**********************/
635 		}
636 				  /*********************************/
637 	/*                               */
638 	else
639 		name[position]++;	/* otherwise, increment this one */
640 	return 0;		/*                               */
641 				  /*********************************/
642 }
643 
mode(path_string)644 int mode(path_string)
645 
646 /****************************************/
647 /*					*/
648 /*   determine and return the mode of	*/
649 /*   the file named by path_string 	*/
650 /*					*/
651 /****************************************/
652  char path_string[];
653 {
654 	struct stat buf;
655 	int ret_val, mod;
656 
657 	ret_val = stat(path_string, &buf);
658 	if (ret_val == -1)
659 		return (-1);
660 	else {
661 		mod = buf.st_mode;
662 		return (mod);
663 	}
664 }
665 
escrivez(string)666 int escrivez(string)
667 
668 char string[];
669 {
670 	char write_string[PATH_STRING_LENGTH + 1];
671 	int len, ret_len;
672 
673 	strcpy(write_string, string);
674 	len = strlen(write_string);
675 	write_string[len] = '\n';
676 	len++;
677 	ret_len = write(list_id, write_string, len);
678 	if (len != ret_len) {
679 		fprintf(temp,
680 			"\tA string of deviant length %d written to path_list, errno=%d\n",
681 			ret_len, errno);
682 		fail_exit();
683 	}
684 	return 0;
685 }
686 
term()687 int term()
688 {
689 	int status;
690 
691 	fprintf(temp, "\tterm - got SIGTERM, cleaning up.\n");
692 
693 	if (list_stream != NULL)
694 		fclose(list_stream);
695 	close(list_id);
696 	close(file_id);
697 
698 	status = system(rm_string);
699 	if (status) {
700 		fprintf(temp, "Caution - ``%s'' may have failed.\n", rm_string);
701 		fprintf(temp, "rm command exit status = %d\n", status);
702 	}
703 
704 	ok_exit();
705 	/***NOT REACHED***/
706 	return 0;
707 
708 }
709 
710 /** LTP Port **/
711 /*
712  * setup
713  *
714  * Do set up - here its a dummy function
715  */
setup()716 void setup()
717 {
718 	tst_tmpdir();
719 	temp = stderr;
720 }
721 
722 /*
723  * Function: blexit()
724  *
725  * Description: This function will exit a block, a block may be a lo
726 gical unit
727  *              of a test. It will report the status if the test ie
728 fail or
729  *              pass.
730  */
blexit()731 void blexit()
732 {
733 	(local_flag == PASSED) ? tst_resm(TPASS, "Test block %d", block_number)
734 	    : tst_resm(TFAIL, "Test block %d", block_number);
735 	block_number++;
736 	return;
737 }
738 
739 /*
740  * Function: blenter()
741  *
742  * Description: Print message on entering a new block
743  */
blenter()744 void blenter()
745 {
746 	local_flag = PASSED;
747 	return;
748 }
749 
750 /*
751  * fail_exit()
752  *
753  * Exit on failure
754  */
fail_exit()755 void fail_exit()
756 {
757 	tst_brkm(TFAIL, tst_rmdir, "Test failed");
758 }
759 
760 /*
761  *
762  * Function: anyfail()
763  *
764  * Description: Exit a test.
765  */
anyfail()766 void anyfail()
767 {
768 	(local_flag == FAILED) ? tst_resm(TFAIL, "Test failed")
769 	    : tst_resm(TPASS, "Test passed");
770 	tst_rmdir();
771 	tst_exit();
772 }
773 
774 /*
775  * ok_exit
776  *
777  * Calling block passed the test
778  */
ok_exit()779 void ok_exit()
780 {
781 	local_flag = PASSED;
782 	return;
783 }
784