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