You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
780 lines
19 KiB
780 lines
19 KiB
/*
|
|
*
|
|
* 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"
|
|
|
|
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(void)
|
|
{
|
|
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(char *string, int 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 */
|
|
/* */
|
|
/****************************************/
|
|
/***************************/
|
|
/* string[] */
|
|
/* the directory path */
|
|
/* string below which a */
|
|
/* tree is generated */
|
|
/* */
|
|
/***************************/
|
|
|
|
/***************************/
|
|
/* 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(void)
|
|
|
|
/****************************************/
|
|
/* */
|
|
/* 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(void)
|
|
|
|
/****************************************/
|
|
/* */
|
|
/* 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(int position)
|
|
|
|
/****************************************/
|
|
/* */
|
|
/* recursively revise the letters in */
|
|
/* a name to get the lexiographically */
|
|
/* next name */
|
|
/* */
|
|
/****************************************/
|
|
{
|
|
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(char *path_string)
|
|
|
|
/****************************************/
|
|
/* */
|
|
/* determine and return the mode of */
|
|
/* the file named by 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(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(void)
|
|
{
|
|
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(void)
|
|
{
|
|
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(void)
|
|
{
|
|
(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(void)
|
|
{
|
|
local_flag = PASSED;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* fail_exit()
|
|
*
|
|
* Exit on failure
|
|
*/
|
|
void fail_exit(void)
|
|
{
|
|
tst_brkm(TFAIL, tst_rmdir, "Test failed");
|
|
}
|
|
|
|
/*
|
|
*
|
|
* Function: anyfail()
|
|
*
|
|
* Description: Exit a test.
|
|
*/
|
|
void anyfail(void)
|
|
{
|
|
(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(void)
|
|
{
|
|
local_flag = PASSED;
|
|
return;
|
|
}
|