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(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 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 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 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 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 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 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 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 */ 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 */ 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 */ 740 void blenter(void) 741 { 742 local_flag = PASSED; 743 return; 744 } 745 746 /* 747 * fail_exit() 748 * 749 * Exit on failure 750 */ 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 */ 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 */ 775 void ok_exit(void) 776 { 777 local_flag = PASSED; 778 return; 779 } 780