| /* |
| * |
| * Copyright (c) International Business Machines Corp., 2002 |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| * the GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| /* 10/31/2002 Port to LTP robbiew@us.ibm.com */ |
| /* 06/30/2001 Port to Linux nsharoff@us.ibm.com */ |
| |
| /* inode1.c */ |
| /*====================================================================== |
| =================== TESTPLAN SEGMENT =================== |
| CALLS: mkdir, stat, open |
| |
| run using TERM mode |
| |
| >KEYS: < file system management I/O |
| >WHAT: < Do the system's file system management and I/O functions work |
| < correctly? |
| >HOW: < Construct a directory tree, create files in it, and verify |
| < that this was done as expected. |
| >BUGS: < |
| ======================================================================*/ |
| /* modified by dale 25-Jul-84 */ |
| |
| /************************************************/ |
| #define PATH_STRING_LENGTH 100 |
| #define NAME_LENGTH 8 |
| #define MAX_PATH_STRING_LENGTH (PATH_STRING_LENGTH - NAME_LENGTH) |
| #define MAX_DEPTH 3 |
| #define MAX_BREADTH 3 |
| #define FILE_LENGTH 100 |
| #define DIRECTORY_MODE 00777 |
| #define FILE_MODE 00777 |
| |
| /* #define PRINT define to get list while running */ |
| |
| #define TRUE 1 |
| #define FALSE 0 |
| #define READ 0 |
| #define WRITE 1 |
| |
| #include <stdio.h> |
| #include <errno.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <signal.h> |
| #include <errno.h> |
| |
| /** LTP Port **/ |
| #include "test.h" |
| #include "usctest.h" |
| |
| void blexit(void); |
| void blenter(void); |
| void setup(void); |
| void fail_exit(void); |
| void anyfail(void); |
| void ok_exit(void); |
| |
| #define FAILED 0 |
| #define PASSED 1 |
| |
| int local_flag = PASSED; |
| int block_number; |
| FILE *temp; |
| |
| char *TCID = "inode01"; /* Test program identifier. */ |
| int TST_TOTAL = 2; /* Total number of test cases. */ |
| /**************/ |
| |
| #ifdef LINUX |
| #include <string.h> |
| #endif |
| |
| char name[NAME_LENGTH + 1]; |
| char path_string[PATH_STRING_LENGTH + 1]; |
| char read_string[PATH_STRING_LENGTH + 1]; |
| char write_string[PATH_STRING_LENGTH + 1]; |
| char rm_string[200]; |
| |
| FILE *list_stream = NULL; |
| int file_id; |
| int list_id; |
| |
| int increment_name(), get_next_name(), mode(), escrivez(); |
| |
| int main() |
| { |
| char root[16]; //as pids can get much longer |
| int gen_ret_val, ch_ret_val, level; |
| int ret_val; |
| int generate(), check(); |
| char path_list_string[PATH_STRING_LENGTH + 1]; |
| int status; |
| int len; |
| int term(); |
| int snp_ret; |
| |
| strcpy(path_string, "inode"); |
| sprintf(root, "A%d", getpid()); |
| strcat(path_string, root); |
| |
| strcpy(rm_string, "rm -rf "); |
| strcat(rm_string, path_string); |
| |
| setup(); |
| |
| if (signal(SIGTERM, (void (*)())term) == SIG_ERR) { |
| fprintf(temp, "\tSIGTERM signal set failed!, errno=%d\n", |
| errno); |
| fail_exit(); |
| } |
| |
| blenter(); |
| |
| /********************************/ |
| /* */ |
| /* make the root directory for */ |
| /* the tree */ |
| /* */ |
| /********************************/ |
| |
| ret_val = mkdir(path_string, DIRECTORY_MODE); |
| |
| if (ret_val == -1) { |
| perror("mkdir error"); |
| fprintf(temp, "\tcreating directory '%s'\n", path_string); |
| fprintf(temp, "\t\n%s Impossible to create directory %s\n", |
| root, path_string); |
| fail_exit(); |
| } |
| #ifdef PRINT |
| printf("\n%s\n", path_string); |
| #endif |
| |
| /****************************************/ |
| /* */ |
| /* create the "path_list" file, in */ |
| /* which the list of generated paths */ |
| /* will be stored so that they later */ |
| /* may be checked */ |
| /* */ |
| /****************************************/ |
| |
| snp_ret = snprintf(path_list_string, sizeof(path_list_string), |
| "%s/path_list", path_string); |
| if (snp_ret < 0 || snp_ret >= sizeof(path_list_string)) { |
| tst_resm(TBROK, "snprintf(path_list_string,..) returned %d", |
| snp_ret); |
| fail_exit(); |
| } |
| list_id = creat(path_list_string, FILE_MODE); |
| if (list_id == -1) { |
| fprintf(temp, |
| "\t\n%s The path_list file cannot be created, errno=%d \n", |
| root, errno); |
| fail_exit(); |
| } |
| |
| /****************************************/ |
| /* */ |
| /* and store its name in path_list */ |
| /* */ |
| /****************************************/ |
| |
| strcpy(write_string, path_string); |
| len = strlen(write_string); |
| write_string[len++] = 'D'; |
| write_string[len] = '\0'; |
| escrivez(write_string); |
| |
| /****************************************/ |
| /* */ |
| /* generate the directory-file tree */ |
| /* */ |
| /****************************************/ |
| |
| level = 0; |
| |
| #ifdef PRINT |
| printf("\n\t%s\n\n", "GENERATING:"); |
| #endif |
| |
| gen_ret_val = generate(path_string, level); |
| |
| if (gen_ret_val) { |
| fprintf(temp, |
| "Failure occured in generate routine, return value %d\n", |
| gen_ret_val); |
| local_flag = FAILED; |
| } |
| |
| blexit(); |
| blenter(); |
| |
| close(list_id); |
| list_id = open(path_list_string, READ); |
| if (list_id == -1) { |
| fprintf(temp, |
| "\t\n%s The path_list file cannot be opened for reading, errno=%d\n", |
| root, errno); |
| fail_exit(); |
| } |
| list_stream = fdopen(list_id, "r"); |
| |
| /****************************************/ |
| /* */ |
| /* check the directory-file tree */ |
| /* for correctness */ |
| /* */ |
| /****************************************/ |
| |
| #ifdef PRINT |
| printf("\n\t%s\n\n", "CHECKING:"); |
| #endif |
| |
| ch_ret_val = check(); |
| |
| if (ch_ret_val) { |
| fprintf(temp, |
| "Failure occured in check routine, return value %d\n", |
| ch_ret_val); |
| local_flag = FAILED; |
| } |
| |
| status = fclose(list_stream); |
| if (status != 0) { |
| fprintf(temp, |
| "Failed to close list_stream: ret=%d errno=%d (%s)\n", |
| status, errno, strerror(errno)); |
| local_flag = FAILED; |
| } |
| |
| blexit(); |
| |
| /* |
| * Now fork and exec a system call to remove the directory. |
| */ |
| |
| #ifdef DEBUG |
| fprintf(temp, "\nClean up:\trm string = %s\n", rm_string); |
| #endif |
| fflush(stdout); |
| fflush(temp); |
| |
| status = system(rm_string); |
| |
| if (status) { |
| fprintf(temp, "Caution-``%s'' may have failed\n", rm_string); |
| fprintf(temp, "rm command exit status = %d\n", status); |
| } |
| |
| /****************************************/ |
| /* */ |
| /* .....and exit main */ |
| /* */ |
| /****************************************/ |
| |
| anyfail(); |
| /***** NOT REACHED ******/ |
| tst_exit(); |
| } |
| |
| int generate(string, level) |
| |
| /****************************************/ |
| /* */ |
| /* generate recursively a tree of */ |
| /* directories and files: within */ |
| /* created directory, an alternating */ |
| /* series of files and directories */ |
| /* are constructed---until tree */ |
| /* breadth and depth limits are */ |
| /* reached or an error occurs */ |
| /* */ |
| /****************************************/ |
| /***************************/ |
| /* */ |
| char string[]; /* the directory path */ |
| /* string below which a */ |
| /* tree is generated */ |
| /* */ |
| /***************************/ |
| |
| /***************************/ |
| /* */ |
| int level; /* the tree depth variable */ |
| /* */ |
| /***************************/ |
| { |
| int switch_flag; |
| int ret_val = 0; |
| int new_ret_val, len, ret_len; |
| char new_string[PATH_STRING_LENGTH + 1]; |
| int new_level; |
| int i, j; /* iteration counters */ |
| int snp_ret; |
| |
| switch_flag = level & TRUE; |
| if (strlen(string) >= MAX_PATH_STRING_LENGTH) { |
| |
| /********************************/ |
| /* */ |
| /* Maximum path name length */ |
| /* reached */ |
| /* */ |
| /********************************/ |
| |
| fprintf(temp, "\tMaximum path_name length reached.\n"); |
| return (-1); |
| } else if (level < MAX_DEPTH) { |
| for (i = 0; i <= MAX_BREADTH; i++) { |
| get_next_name(); |
| snp_ret = snprintf(new_string, sizeof(new_string), |
| "%s/%s", string, name); |
| if (snp_ret < 0 || snp_ret >= sizeof(new_string)) { |
| tst_resm(TBROK, "snprintf(new_string,..) " |
| "returned %d", snp_ret); |
| fail_exit(); |
| } |
| |
| /****************************************/ |
| /* */ |
| /* switch between creating files */ |
| /* and making directories */ |
| /* */ |
| /****************************************/ |
| |
| if (switch_flag) { |
| switch_flag = FALSE; |
| |
| /****************************************/ |
| /* */ |
| /* create a new file */ |
| /* */ |
| /****************************************/ |
| |
| file_id = creat(new_string, FILE_MODE); |
| if (file_id == -1) { |
| fprintf(temp, |
| "\tImpossible to create file %s, errno=%d\n", |
| new_string, errno); |
| return (-2); |
| } |
| #ifdef PRINT |
| printf("%d %s F\n", level, new_string); |
| #endif |
| |
| /****************************************/ |
| /* */ |
| /* write to it */ |
| /* */ |
| /****************************************/ |
| |
| len = strlen(new_string); |
| for (j = 1; j <= FILE_LENGTH; j++) { |
| ret_len = |
| write(file_id, new_string, len); |
| if (ret_len != len) { |
| fprintf(temp, |
| "\tUnsuccessful write to file %s, expected return of %d, got %d, errno=%d\n", |
| new_string, len, |
| ret_len, errno); |
| return (-3); |
| } |
| } |
| close(file_id); |
| |
| /****************************************/ |
| /* */ |
| /* and store its name in path_list */ |
| /* */ |
| /****************************************/ |
| |
| strcpy(write_string, new_string); |
| len = strlen(write_string); |
| write_string[len++] = 'F'; |
| write_string[len] = '\0'; |
| escrivez(write_string); |
| } else { |
| switch_flag = TRUE; |
| |
| /****************************************/ |
| /* */ |
| /* or make a directory */ |
| /* */ |
| /****************************************/ |
| |
| ret_val = mkdir(new_string, DIRECTORY_MODE); |
| |
| if (ret_val != 0) { |
| fprintf(temp, |
| "\tImpossible to create directory %s, errno=%d\n", |
| new_string, errno); |
| return (-5); |
| } |
| #ifdef PRINT |
| printf("%d %s D\n", level, new_string); |
| #endif |
| |
| /****************************************/ |
| /* */ |
| /* store its name in path_list */ |
| /* */ |
| /****************************************/ |
| |
| strcpy(write_string, new_string); |
| len = strlen(write_string); |
| write_string[len++] = 'D'; |
| write_string[len] = '\0'; |
| escrivez(write_string); |
| |
| /****************************************/ |
| /* */ |
| /* and generate a new level */ |
| /* */ |
| /****************************************/ |
| |
| new_level = level + 1; |
| new_ret_val = generate(new_string, new_level); |
| if (new_ret_val < ret_val) |
| ret_val = new_ret_val; |
| } |
| } |
| |
| /********************************/ |
| /* */ |
| /* Maximum breadth reached */ |
| /* */ |
| /********************************/ |
| |
| return (ret_val); |
| } else |
| /********************************/ |
| /* */ |
| /* Maximum depth reached */ |
| /* */ |
| /********************************/ |
| return 0; |
| } |
| |
| int check() |
| |
| /****************************************/ |
| /* */ |
| /* check for file and directory */ |
| /* correctness by reading records */ |
| /* from the path_list and attempting */ |
| /* to determine if the corresponding */ |
| /* files or directories are as */ |
| /* created */ |
| /* */ |
| /****************************************/ |
| { |
| int len, path_mode, val, ret_len, j; |
| |
| for (;;) { |
| |
| /****************************************/ |
| /* */ |
| /* read a path string from path_list */ |
| /* */ |
| /****************************************/ |
| |
| if (fscanf(list_stream, "%s", path_string) == EOF) { |
| |
| #ifdef PRINT |
| printf("\nEnd of path_list file reached \n"); |
| #endif |
| |
| return 0; |
| } |
| #ifdef PRINT |
| printf("%s\n", path_string); |
| #endif |
| |
| len = strlen(path_string); |
| len--; |
| if (path_string[len] == 'F') { |
| |
| /********************************/ |
| /* */ |
| /* this should be a file */ |
| /* */ |
| /********************************/ |
| |
| path_string[len] = '\0'; |
| file_id = open(path_string, READ); |
| if (file_id <= 0) { |
| fprintf(temp, |
| "\tImpossible to open file %s, errno=%d\n", |
| path_string, errno); |
| return (-1); |
| } |
| |
| else { |
| /********************************/ |
| /* */ |
| /* check its contents */ |
| /* */ |
| /********************************/ |
| |
| len = strlen(path_string); |
| for (j = 1; j <= FILE_LENGTH; j++) { |
| ret_len = |
| read(file_id, read_string, len); |
| if (len != ret_len) { |
| fprintf(temp, |
| "\tFile read error for file %s, expected return of %d, got %d, errno=%d\n", |
| path_string, len, |
| ret_len, errno); |
| return (-3); |
| } |
| read_string[len] = '\0'; |
| val = strcmp(read_string, path_string); |
| if (val != 0) { |
| fprintf(temp, |
| "\tContents of file %s are different than expected: %s\n", |
| path_string, |
| read_string); |
| return (-4); |
| } |
| } |
| close(file_id); |
| } /* else for */ |
| if (ret_len <= 0) { |
| fprintf(temp, "\tImpossible to read file %s\n", |
| path_string); |
| return (-2); |
| } |
| } else { |
| |
| /********************************/ |
| /* */ |
| /* otherwise.......... */ |
| /* it should be a directory */ |
| /* */ |
| /********************************/ |
| |
| path_string[len] = '\0'; |
| path_mode = mode(path_string); |
| if (path_mode == -1) { |
| fprintf(temp, |
| "\tPreviously created directory path %s was not open\n", |
| path_string); |
| return (-4); |
| } |
| if ((040000 & path_mode) != 040000) { |
| fprintf(temp, |
| "\tPath %s was not recognized to be a directory\n", |
| path_string); |
| fprintf(temp, "\tIts mode is %o\n", path_mode); |
| return (-5); |
| } |
| } |
| } /* while */ |
| } |
| |
| int get_next_name() |
| |
| /****************************************/ |
| /* */ |
| /* get the next---in a dictionary */ |
| /* sense---file or directory name */ |
| /* */ |
| /****************************************/ |
| { |
| static int k; |
| int i; |
| int last_position; |
| |
| last_position = NAME_LENGTH - 1; |
| if (k == 0) { |
| |
| /************************/ |
| /* */ |
| /* initialize name */ |
| /* */ |
| /************************/ |
| |
| for (i = 0; i < NAME_LENGTH; i++) |
| name[i] = 'a'; |
| name[NAME_LENGTH] = '\0'; |
| k++; |
| } |
| /********************************/ |
| /* */ |
| else |
| increment_name(last_position); /* i.e., beginning at the last */ |
| /* position */ |
| /* */ |
| /********************************/ |
| return 0; |
| } |
| |
| int increment_name(position) |
| |
| /****************************************/ |
| /* */ |
| /* recursively revise the letters in */ |
| /* a name to get the lexiographically */ |
| /* next name */ |
| /* */ |
| /****************************************/ |
| int position; |
| { |
| int next_position; |
| |
| if (name[position] == 'z') |
| if (position == 0) { |
| fprintf(temp, |
| "\tERROR: There are no more available names\n"); |
| fail_exit(); |
| } else { |
| name[position] = 'a'; /**********************/ |
| next_position = --position; /* */ |
| increment_name(next_position); /* increment the */ |
| /* previous letter */ |
| /* */ |
| /**********************/ |
| } |
| /*********************************/ |
| /* */ |
| else |
| name[position]++; /* otherwise, increment this one */ |
| return 0; /* */ |
| /*********************************/ |
| } |
| |
| int mode(path_string) |
| |
| /****************************************/ |
| /* */ |
| /* determine and return the mode of */ |
| /* the file named by path_string */ |
| /* */ |
| /****************************************/ |
| char path_string[]; |
| { |
| struct stat buf; |
| int ret_val, mod; |
| |
| ret_val = stat(path_string, &buf); |
| if (ret_val == -1) |
| return (-1); |
| else { |
| mod = buf.st_mode; |
| return (mod); |
| } |
| } |
| |
| int escrivez(string) |
| |
| char string[]; |
| { |
| char write_string[PATH_STRING_LENGTH + 1]; |
| int len, ret_len; |
| |
| strcpy(write_string, string); |
| len = strlen(write_string); |
| write_string[len] = '\n'; |
| len++; |
| ret_len = write(list_id, write_string, len); |
| if (len != ret_len) { |
| fprintf(temp, |
| "\tA string of deviant length %d written to path_list, errno=%d\n", |
| ret_len, errno); |
| fail_exit(); |
| } |
| return 0; |
| } |
| |
| int term() |
| { |
| int status; |
| |
| fprintf(temp, "\tterm - got SIGTERM, cleaning up.\n"); |
| |
| if (list_stream != NULL) |
| fclose(list_stream); |
| close(list_id); |
| close(file_id); |
| |
| status = system(rm_string); |
| if (status) { |
| fprintf(temp, "Caution - ``%s'' may have failed.\n", rm_string); |
| fprintf(temp, "rm command exit status = %d\n", status); |
| } |
| |
| ok_exit(); |
| /***NOT REACHED***/ |
| return 0; |
| |
| } |
| |
| /** LTP Port **/ |
| /* |
| * setup |
| * |
| * Do set up - here its a dummy function |
| */ |
| void setup() |
| { |
| tst_tmpdir(); |
| temp = stderr; |
| } |
| |
| /* |
| * Function: blexit() |
| * |
| * Description: This function will exit a block, a block may be a lo |
| gical unit |
| * of a test. It will report the status if the test ie |
| fail or |
| * pass. |
| */ |
| void blexit() |
| { |
| (local_flag == PASSED) ? tst_resm(TPASS, "Test block %d", block_number) |
| : tst_resm(TFAIL, "Test block %d", block_number); |
| block_number++; |
| return; |
| } |
| |
| /* |
| * Function: blenter() |
| * |
| * Description: Print message on entering a new block |
| */ |
| void blenter() |
| { |
| local_flag = PASSED; |
| return; |
| } |
| |
| /* |
| * fail_exit() |
| * |
| * Exit on failure |
| */ |
| void fail_exit() |
| { |
| tst_resm(TFAIL, "Test failed"); |
| tst_rmdir(); |
| tst_exit(); |
| } |
| |
| /* |
| * |
| * Function: anyfail() |
| * |
| * Description: Exit a test. |
| */ |
| void anyfail() |
| { |
| (local_flag == FAILED) ? tst_resm(TFAIL, "Test failed") |
| : tst_resm(TPASS, "Test passed"); |
| tst_rmdir(); |
| tst_exit(); |
| } |
| |
| /* |
| * ok_exit |
| * |
| * Calling block passed the test |
| */ |
| void ok_exit() |
| { |
| local_flag = PASSED; |
| return; |
| } |