Home | History | Annotate | Download | only in inode
      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 (at) us.ibm.com */
     21 /* 06/30/2001	Port to Linux	nsharoff (at) 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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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  */
    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  */
    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  */
    744 void blenter()
    745 {
    746 	local_flag = PASSED;
    747 	return;
    748 }
    749 
    750 /*
    751  * fail_exit()
    752  *
    753  * Exit on failure
    754  */
    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  */
    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  */
    779 void ok_exit()
    780 {
    781 	local_flag = PASSED;
    782 	return;
    783 }
    784