diff options
Diffstat (limited to 'winsup/testsuite/winsup.api/ltp/symlink01.c')
-rw-r--r-- | winsup/testsuite/winsup.api/ltp/symlink01.c | 2024 |
1 files changed, 2024 insertions, 0 deletions
diff --git a/winsup/testsuite/winsup.api/ltp/symlink01.c b/winsup/testsuite/winsup.api/ltp/symlink01.c new file mode 100644 index 000000000..f202ee2bc --- /dev/null +++ b/winsup/testsuite/winsup.api/ltp/symlink01.c @@ -0,0 +1,2024 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ +/* $Id$ */ +/********************************************************** +* +* OS Test - Silicon Graphics, Inc. +* +* TEST IDENTIFIER : symlink01 (symlink) +* +* TEST TITLE : Make a Symbolic Link to a File +* +* PARENT DOCUMENT : symtds01 +* +* TEST CASE TOTAL : 5 +* +* WALL CLOCK TIME : 3 +* +* TEST IDENTIFIER : readlink01 (readlink) +* +* TEST TITLE : Reads Value of a Symbolic Link +* +* PARENT DOCUMENT : symtds01 +* +* TEST CASE TOTAL : 4 +* +* WALL CLOCK TIME : 3 +* +* TEST IDENTIFIER : stat04 (stat) +* +* TEST TITLE : Gets File Status Indirectly From a Symbolic Link +* File +* +* PARENT DOCUMENT : symtds01 +* +* TEST CASE TOTAL : 3 +* +* WALL CLOCK TIME : 3 +* +* TEST IDENTIFIER : lstat01 (lstat) +* +* TEST TITLE : Get file Status About a Symbolic Link File +* +* PARENT DOCUMENT : symtds01 +* +* TEST CASE TOTAL : 3 +* +* WALL CLOCK TIME : 3 +* +* TEST IDENTIFIER : mkdir05 (mkdir) +* +* TEST TITLE : Fail When Making a Directory File Indirectly From +* a Symbolic Link File +* +* PARENT DOCUMENT : symtds01 +* +* TEST CASE TOTAL : 1 +* +* WALL CLOCK TIME : 3 +* +* TEST IDENTIFIER : rmdir03 (rmdir) +* +* TEST TITLE : Fail When Removing a Directory File Indirectly +* From a Symbolic Link File +* +* PARENT DOCUMENT : symtds01 +* +* TEST CASE TOTAL : 1 +* +* WALL CLOCK TIME : 3 +* +* TEST IDENTIFIER : chdir01 (chdir) +* +* TEST TITLE : Changes Current Working DIrectory Location +* Indirectly From a Symbolic Link File +* +* PARENT DOCUMENT : symtds01 +* +* TEST CASE TOTAL : 3 +* +* WALL CLOCK TIME : 3 +* +* TEST IDENTIFIER : link01 (link) +* +* TEST TITLE : Creates a Link To a File Indirectly From a +* Symbolic Link File +* +* PARENT DOCUMENT : symtds01 +* +* TEST CASE TOTAL : 3 +* +* WALL CLOCK TIME : 3 +* +* TEST IDENTIFIER : unlink01 (unlink) +* +* TEST TITLE : Removes a Link To a File And Not Any Object File +* Which Maybe Pointed At +* +* PARENT DOCUMENT : symtds01 +* +* TEST CASE TOTAL : 1 +* +* WALL CLOCK TIME : 3 +* +* TEST IDENTIFIER : chmod01 (chmod) +* +* TEST TITLE : Change Object File Permissions Indirectly From a +* Symbolic Link File +* +* PARENT DOCUMENT : symtds01 +* +* TEST CASE TOTAL : 3 +* +* WALL CLOCK TIME : 3 +* +* TEST IDENTIFIER : utime01 (utime) +* +* TEST TITLE : Set File Access And Modify Object File Times +* Indirectly From a Symbolic Link File +* +* PARENT DOCUMENT : symtds01 +* +* TEST CASE TOTAL : 3 +* +* WALL CLOCK TIME : 3 +* +* TEST IDENTIFIER : rename01 (rename) +* +* TEST TITLE : Rename a Symbolic Link File And Not Any Object +* File +* +* PARENT DOCUMENT : symtds01 +* +* TEST CASE TOTAL : 3 +* +* WALL CLOCK TIME : 3 +* +* TEST IDENTIFIER : open01 (open) +* +* TEST TITLE : Create/Open a File For Reading Or Writing +* Indirectly From a Symbolic Link File +* +* PARENT DOCUMENT : symtds01 +* +* TEST CASE TOTAL : 5 +* +* WALL CLOCK TIME : 3 +* +* EXECUTED BY : whom ever +* +* CPU TYPES : ALL +* +* AUTHOR : David Fenner +* +* CO-PILOT : Jon Hendrickson +* +* DATE STARTED : 07/25/90 +* +* INITIAL RELEASE : UNICOS 6.0 +* +* TEST CASES +* +* For symlink +* +* 1. Create symbolic link with abnormal object name path +* 2. Create symbolic link with normal object name path +* 3. Create symbolic link with path to an existing object file +* 4. Receive EEXIST error when creating an already existing symbolic link file. +* 5. Receive ENAMETOOLONG error when creating symbolic link which exceeds PATH_MAX in length +* +* For readlink +* +* 1. Read a symbolic link file which points at no object file +* 2. Read a symbolic link file which points at an object file +* 3. Receive ENAMETOOLONG error when reading symbolic link which exceeds PATH_MAX in length +* 4. Receive an EINVAL error when reading a file which is not a symbolic +* link file. +* +* For stat +* +* 1. Get object file status through symbolic link file +* 2. Receive ENOENT error when accessing non-existent object file through symbolic link file +* 3. Receive ELOOP error when nesting of symbolic links exceed maximum +* +* For lstat +* +* 1. Get symbolic link file status when pointing at no object file +* 2. Get symbolic link file status when pointing at an object file +* 3. Get object file status when argument is not a symbolic link +* file. +* +* For mkdir +* +* 1. Receive EEXIST error when creating a directory through a symbolic link file +* +* For rmdir +* +* 1. Receive ENOTDIR error when removing an existing directory through a symbolic link file +* +* For chdir +* +* 1. Change current working directory through a symbolic link file +* 2. Receive ENOENT error when accessing non-existent directory through symbolic link file +* 3. Receive ELOOP error when nesting of symbolic links exceed maximum +* +* For link +* +* 1. Link an object file to a new file through symbolic link file +* 2. Receive ENOENT error when accessing non-existent object file through symbolic link file +* 3. Receive ELOOP error when nesting of symbolic links exceed maximum +* +* For unlink +* +* 1. Delete a symbolic link file and not the object file which it points at +* +* For chmod +* +* 1. Change file permissions of object file through a symbolic link file +* 2. Receive ENOENT error when accessing non-existent directory through symbolic link file +* 3. Receive ELOOP error when nesting of symbolic links exceed maximum +* +* For utime +* +* 1. Change inode times of object file through a symbolic link file +* 2. Receive ENOENT error when accessing non-existent directory through symbolic link file +* 3. Receive ELOOP error when nesting of symbolic links exceed maximum +* +* For rename +* +* 1. Rename a symbolic link file which points at no object file +* 2. Rename a symbolic link file which points at an object file without any object file alterations. +* 3. Receive EXDEV when trying to rename a symbolic link file to an address outside of current file system +* +* For open +* +* 1. Create an object file through a symbolic link file +* 2. Open an object file through a symbolic link file +* 3. Receive EEXIST error when exclusively creating an object file through a symbolic link file +* 4. Receive ENOENT error when accessing non-existent object file through symbolic link file +* 5. Receive ELOOP error when nesting of symbolic links exceed maximum +* +* ENVIRONMENTAL NEEDS +* None +* +* DETAILED DESCRIPTION +* +* Self-documenting code so see below +* +*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ + +#include <stdio.h> +#include <signal.h> +#include <string.h> +#include <fcntl.h> /* open(2) system call */ +#include <errno.h> +#include <sys/types.h> +#include <utime.h> /* utime(2) system call */ +#include <sys/param.h> +#include <sys/stat.h> /* stat(2) and lstat(2) system calls */ + +#include "test.h" +#include "usctest.h" + +void setup(); +void cleanup(); +void help(); +void delete_files(); +void do_EEXIST(); +void do_ENOENT(); +void do_ELOOP(); +void do_ENOTDIR(); +void do_EXDEV(); +void do_ENAMETOOLONG(); +void do_EINVAL(); +void do_readlink(); +void do_stat(); +void do_chdir(); +void do_link(); +void do_unlink(); +void do_chmod(); +void do_utime(); +void do_rename(); +void do_open(); + +#define S_FILE "symbolic" /* Name of symbolic link file */ +#define O_FILE "object" /* Name of object file */ +#define A_S_FILE "asymbolic" /* Another name for a symbolic link file */ +#define Y_A_S_FILE "/NiCkEr" /* Yet another symbolic link file */ +#define BIG_STRING "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" + +#define DEFAULT_TCID "symlink01" + +#define SYMLINK "symlink01" +#define READLINK "readlink01" +#define STAT "stat04" +#define LSTAT "lstat01" +#define MKDIR "mkdir05" +#define RMDIR "rmdir03" +#define CHDIR "chdir01" +#define LINK "link01" +#define UNLINK "unlink01" +#define CHMOD "chmod01" +#define UTIME "utime01" +#define RENAME "rename01" +#define OPEN "open01" + +#define cktcsid(s1,s2) (!strcmp(s1,s2)) +#define BUFMAX 512 +#define MODE 0700 +#define MASK 0100777 /* A regular file with r,w,x for all mask */ + +/* + * Lets be optimistic and only define messages for passing test cases + */ +char *msgs[] = { + "Creation of symbolic link file to no object file is ok", + "Creation of symbolic link file and object file via symbolic link is ok", + "Creating an existing symbolic link file error is caught", + "Creating a symbolic link which exceeds maximum pathname error is caught", + "Reading of symbolic link file contents checks out ok", + "Reading a symbolic link which exceeds maximum pathname error is caught", + "Getting stat info about object file through symbolic link file is ok", + "Stat(2) error when accessing non-existent object through symbolic link is caught", + "lstat(2) of symbolic link file which points to no object file is ok", + "lstat(2) of symbolic link file which points at an object file is ok", + "mkdir(2) of object file through symbolic link file failed as expected", + "rmdir(2) of object file through symbolic link file failed as expected", + "chdir(2) to object file location through symbolic link file is ok", + "chdir(2) to non-existent object file location through symbolic link file failed as expected", + "link(2) to a symbolic link, which is pointing to an existing object file worked - file created and link count adjusted", + "link(2) to a symbolic link, which is pointing to a non-existing object file worked ok - file created and link count adjusted.", + "unlink(2) of symbolic link file with no object file removal is ok", + "chmod(2) of object file permissions through symbolic link file is ok", + "chmod(2) error when accessing non-existent object through symbolic link is caught", + "utime(2) change of object file access and modify times through symbolic link file is ok", + "utime(2) error when accessing non-existent object through symbolic link is caught", + "rename(3) of symbolic link file name which points at no object file is ok", + "rename(3) of symbolic link file name which points at object file is ok", + "rename(3) error of symbolic link file name across file systems is caught", + "open(2) with (O_CREAT | O_RDWR) to create object file through symbolic link file and all writes, reads, and lseeks are ok", + "open(2) with O_RDWR of existing object file through symbolic link file and all writes, reads, and lseeks are ok", + "open(2) with (O_CREAT | O_EXCL) error is caught when creating object file through symbolic link file", + "open(2) error with O_RDWR is caught when processing symbolic link file which points at no object file", + "Nested symbolic link access condition caught. ELOOP is returned", + "Reading a nonsymbolic link file error condition is caught. EINVAL is returned", + "lstat(2) of object file returns object file inode information", + "NULL" +}; + +/* + * Define test object setup and validation functions + */ +int creat_both(), creat_symlink(), creat_path_max(), ck_symlink(), + creat_object(), ck_object(), ck_both(), ck_path_max(); + + +/* + * Define test cases + */ +struct all_test_cases +{ + char *tcid; + int test_fail; + int errno_val; + int pass_msg; + int (*test_setup)(); + int (*ck_test)(); + char *fn_arg[3]; + +} test_objects[] = { + {SYMLINK, 0, 0, 0, creat_symlink, ck_symlink, {"%bc+eFhi!k", S_FILE, NULL}}, + {SYMLINK, 0, 0, 0, creat_symlink, ck_symlink, {O_FILE, S_FILE, NULL}}, + {SYMLINK, 0, 0, 1, creat_both, ck_both, {O_FILE, S_FILE, O_FILE}}, + {SYMLINK, 1, EEXIST, 2, creat_symlink, ck_symlink, {O_FILE, S_FILE, NULL}}, + {SYMLINK, 1, ENAMETOOLONG, 3, creat_path_max, ck_path_max, {O_FILE, S_FILE, NULL}}, + {READLINK, 0, 0, 4, creat_symlink, ck_symlink, {O_FILE, S_FILE, NULL}}, + {READLINK, 0, 0, 4, creat_both, ck_both, {O_FILE, S_FILE, O_FILE}}, + {READLINK, 1, ENAMETOOLONG, 5, creat_path_max, ck_path_max, {O_FILE, S_FILE, NULL}}, + {READLINK, 1, EINVAL, 29, creat_object, ck_object, {O_FILE, NULL, NULL}}, + {STAT, 0, 0, 6, creat_both, ck_both, {O_FILE, S_FILE, O_FILE}}, + {STAT, 1, ENOENT, 7, creat_symlink, ck_symlink, {O_FILE, S_FILE, NULL}}, + {STAT, 1, ELOOP, 28, creat_symlink, ck_symlink, {S_FILE, S_FILE, NULL}}, + {LSTAT, 0, 0, 8, creat_symlink, ck_symlink, {O_FILE, S_FILE, NULL}}, + {LSTAT, 0, 0, 9, creat_both, ck_both, {O_FILE, S_FILE, O_FILE}}, + {LSTAT, 0, 0, 30, creat_object, ck_object, {O_FILE, NULL, NULL}}, + {MKDIR, 1, EEXIST, 10, creat_symlink, ck_symlink, {O_FILE, S_FILE, NULL}}, + {RMDIR, 1, ENOTDIR, 11, creat_symlink, ck_symlink, {O_FILE, S_FILE, NULL}}, + {CHDIR, 0, 0, 12, creat_symlink, ck_symlink, {O_FILE, S_FILE, O_FILE}}, + {CHDIR, 1, ENOENT, 13, creat_symlink, ck_symlink, {"%bc+eFhi!k", S_FILE, NULL}}, + {CHDIR, 1, ELOOP, 28, creat_symlink, ck_symlink, {S_FILE, S_FILE, NULL}}, + {LINK, 0, 0, 14, creat_both, ck_both, {O_FILE, S_FILE, O_FILE}}, + {LINK, 0, 0, 15, creat_symlink, ck_symlink, {O_FILE, S_FILE, NULL}}, + /* The following link test case is invalid - leaving it defined so */ + /* I don't have to change all the entries in the all_tcses array after link */ + {LINK, 1, -1, -1, creat_symlink, ck_symlink, {NULL, NULL, NULL}}, + {UNLINK, 0, 0, 16, creat_both, ck_both, {O_FILE, S_FILE, O_FILE}}, + {CHMOD, 0, 0, 17, creat_both, ck_both, {O_FILE, S_FILE, O_FILE}}, + {CHMOD, 1, ENOENT, 18, creat_symlink, ck_symlink, {O_FILE, S_FILE, NULL}}, + {CHMOD, 1, ELOOP, 28, creat_symlink, ck_symlink, {S_FILE, S_FILE, NULL}}, + {UTIME, 0, 0, 19, creat_both, ck_both, {O_FILE, S_FILE, O_FILE}}, + {UTIME, 1, ENOENT, 20, creat_symlink, ck_symlink, {O_FILE, S_FILE, NULL}}, + {UTIME, 1, ELOOP, 28, creat_symlink, ck_symlink, {S_FILE, S_FILE, NULL}}, + {RENAME, 0, 0, 21, creat_symlink, ck_symlink, {O_FILE, S_FILE, NULL}}, + {RENAME, 0, 0, 22, creat_both, ck_both, {O_FILE, S_FILE, O_FILE}}, + {RENAME, 1, EXDEV, 23, creat_both, ck_both, {O_FILE, S_FILE, O_FILE}}, + {OPEN, 0, 0, 24, creat_symlink, ck_symlink, {O_FILE, S_FILE, NULL}}, + {OPEN, 0, 0, 25, creat_both, ck_both, {O_FILE, S_FILE, O_FILE}}, + {OPEN, 1, EEXIST, 26, creat_symlink, ck_symlink, {O_FILE, S_FILE, O_FILE}}, + {OPEN, 1, ENOENT, 27, creat_symlink, ck_symlink, {O_FILE, S_FILE, NULL}}, + {OPEN, 1, ELOOP, 28, creat_symlink, ck_symlink, {S_FILE, S_FILE, NULL}} +}; + +/* + * Define tcses + */ +struct tcses +{ + char *tcid; + char *syscall; + int test_cases; /* number of entries in test_objects array */ + struct all_test_cases *tc_ptr; + char *desc; +} all_tcses[] = { + + { SYMLINK, "symlink", 5, &test_objects[0], + "Make a Symbolic Link to a File" }, + { READLINK, "readlink", 4, &test_objects[5], + "Reads Value of a Symbolic Link" }, + { STAT, "stat", 3, &test_objects[9], + "Gets File Status Indirectly From a Symbolic Link file" }, + { LSTAT, "lstat", 3, &test_objects[12], + "Get file Status About a Symbolic Link File" }, + { MKDIR, "mkdir", 1, &test_objects[15], + "Fail When Making a Directory File Indirectly from a symlink" }, + { RMDIR, "rmdir", 1, &test_objects[16], + "Fail When Removing a Directory File Indirectly from a symlink" }, + { CHDIR, "chdir", 3, &test_objects[17], + "Changes CWD Location Indirectly from a symlink" }, + { LINK, "link", 2, &test_objects[20], + "Creates a Link To a File Indirectly From a Symbolic" }, + { UNLINK, "unlink", 1, &test_objects[23], + "Removes a Link To a File but not the Object File" }, + { CHMOD, "chmod", 3, &test_objects[24], + "Change Object File Permissions Indirectly From a Symbolic" }, + { UTIME, "utime", 3, &test_objects[27], + "Set File Access And Modify Object File Times via symlink" }, + { RENAME, "rename", 3, &test_objects[30], + "Rename a Symbolic Link File And Not Any Object file" }, + { OPEN, "open", 5, &test_objects[33], + "Create/Open a File For Reading Or Writing via symlink" }, +}; + +/* + * Define GLOBAL variables + */ + +int TST_TOTAL; +int TEST_RESULT; +time_t a_time_value = 100; +char *TCID; +char *Selectedtests = NULL; /* Name (tcid) of selected test cases */ +char test_msg[BUFMAX]; +char full_path[PATH_MAX+1]; +extern int Tst_count; +extern char *TESTDIR; +extern char *strrchr(); +extern int errno; + +struct stat asymlink, statter; +char Buffer[1024]; +char Buf[1024]; + +char *Tcid = NULL; + +option_t Options[] = { + { "T:", NULL, &Tcid }, /* -T tcid option */ + { NULL, NULL, NULL } +}; + +/*********************************************************************** + * MAIN + ***********************************************************************/ +int +main(int argc, char *argv[]) +{ + struct tcses *tcs_ptr, *get_tcs_info(); + int do_syscalltests(); + void cleanup(); + int lc; /* loop counter */ + char *msg; /* message returned from parse_opts */ + + + /*************************************************************** + * parse standard options, and exit if there is an error + ***************************************************************/ + if ( (msg=parse_opts(argc, argv, Options, &help)) != (char *) NULL ) { + tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); + tst_exit(); + } + + /* + * If the -T option was used, use that TCID or use the default + */ + if ( Tcid != NULL ) { + TCID = Tcid; + Selectedtests=Tcid; + + } +#ifndef ALL + else { + TCID = DEFAULT_TCID; + Selectedtests = DEFAULT_TCID; + } +#endif + + /* + * Get test case specification information and assign TST_TOTAL + */ + if ((tcs_ptr=get_tcs_info(Selectedtests)) == NULL) { + TST_TOTAL=1; + tst_brkm(TBROK, cleanup, + "Unknown symbolic link test case specification executed"); + } + + /*************************************************************** + * perform global setup for test + ***************************************************************/ + + setup(); + + /*************************************************************** + * check looping state if -c option given + ***************************************************************/ + for (lc=0; TEST_LOOPING(lc); lc++) { + + /* reset Tst_count in case we are looping. */ + Tst_count=0; + + /* + * Execute tcs testing function and all defined test cases + */ + do_syscalltests(tcs_ptr); + + } /* End for TEST_LOOPING */ + + /* + * End appropriately + */ + cleanup(); + + return 0; +} + +/*********************************************************************** + * This function maps the name of the process to a test case specification + * defined in the all_tcses array of tcses structures. Either a pointer + * to the mapped test case specification information is returned or a + * null pointer. + * + * Argument is path to program name. + ***********************************************************************/ +struct tcses *get_tcs_info(ptr) +char *ptr; +{ + int ctr; + struct tcses *tcs_ptr; + +#if ALL + if ( ptr == NULL ) { + + TST_TOTAL=0; + for (ctr=1; ctr < sizeof(all_tcses)/sizeof(struct tcses); ctr++) + TST_TOTAL += all_tcses[ctr].test_cases; + return all_tcses; + } +#endif + + + for(ctr=0; ctr < (sizeof(all_tcses)/sizeof(struct tcses)); ctr++) { + if ( strcmp(ptr, all_tcses[ctr].tcid) == 0 || + strcmp(ptr, all_tcses[ctr].syscall) == 0 ) { + tcs_ptr = &all_tcses[ctr]; + TCID = all_tcses[ctr].tcid; + TST_TOTAL=tcs_ptr->test_cases; + return(tcs_ptr); + } + + } + return(NULL); +} + +/*********************************************************************** + * Determines if what path points at is a symbolic link file + * + * Argument is path to symbolic link file. + * + * Return status is one if a symbolic link file. Zero if not a symbolic + * link file and a minus one if the path doesn't point at a file. + ***********************************************************************/ +int +see_if_a_symlink(path) +char *path; +{ + if (lstat(path, &asymlink) < 0) + return(-1); + + if ((asymlink.st_mode & S_IFMT) == S_IFLNK) + return(1); + else + return(0); +} + +/*********************************************************************** + * This function performs without any hesitation, file(s) deletions + ***********************************************************************/ +void +delete_files(path1, path2) +char *path1, *path2; +{ + unlink(path1); + unlink(path2); +} + +/*********************************************************************** + * + * This routine creates a symbolic link file. + * + * Argument one is symbolic link pathname to point at. + * Argument two is name of symbolic link file. + * + ***********************************************************************/ +int +creat_symlink(path1, path2) +char *path1, *path2; +{ + TEST( symlink(path1, path2) ); + errno=TEST_ERRNO; + if (TEST_RETURN == -1) { + TEST_RESULT=TBROK; + sprintf(test_msg, + "symlink(2) Failure when creating setup %s object file: errno:%d %s", + path1, errno, strerror(errno)); + return(0); + } + else { + sprintf(Buf, "symlink(%s, %s) was succesful.\n", path1, path2); + strcat(Buffer, Buf); +#if DEBUG + tst_resm(TPASS, "symlink(%s, %s) was succesful.", path1, path2); +#endif + } + return(1); +} + +/*********************************************************************** + * + * This routine creates a regular file. + * + * Argument one is a pathname + * + ***********************************************************************/ +int +creat_object(path1) +char *path1; +{ + int fd; + if ((fd=creat(path1, MODE)) == -1) { + TEST_RESULT=TBROK; + sprintf(test_msg, + "creat(2) Failure when creating setup %s object file: errno:%d %s", + path1, errno, strerror(errno)); + return(0); + } + else { + sprintf(Buf, "creat(%s, %#o) was succesful.\n", path1, MODE); + strcat(Buffer, Buf); +#if DEBUG + tst_resm(TPASS, "creat(%s, %#o) was succesful.", path1, MODE); +#endif + } + if (close(fd) == -1) { + TEST_RESULT=TBROK; + sprintf(test_msg, + "close(2) Failure when closing setup %s object file: errno:%d %s", + path1, errno, strerror(errno)); + return(0); + } + return(1); +} + +/*********************************************************************** + * + * This routine creates a symbolic link file and a regular file. + * + * Argument one is a pathname of object file + * Argument two is symbolic link file name + * Argument three is regular file name + * + ***********************************************************************/ +int +creat_both(path1, path2, path3) +char *path1, *path2, *path3; +{ + if (creat_symlink(path1, path2) == -1) + return(0); + else if (creat_object(path3) == -1) + return(0); + return(1); +} + +/*********************************************************************** + * + * This routine checks if symbolic link file is a symbolic link file. + * + * Argument one is a pathname of object file + * Argument two is symbolic link file name + * Argument three is regular file name + * + ***********************************************************************/ +int +ck_symlink(path1, path2, path3) +char *path1, *path2, *path3; +{ + int ret; + + if ((ret=see_if_a_symlink(path2)) == -1) { + TEST_RESULT=TBROK; + sprintf(test_msg, + "lstat(2) Failure when accessing %s symbolic link file which should contain %s path to %s file ", + path2, path1, path3); + return(0); + } + else if (ret == 0) { + TEST_RESULT=TBROK; + sprintf(test_msg, + "%s is not a symbolic link file which contains %s path to %s file", + path2, path1, path3); + return(0); + } + return(1); +} + +/*********************************************************************** + * + * This routine checks if symbolic link file points at object file. + * + * Argument one is a pathname of object file + * Argument two is symbolic link file name + * Argument three is regular file name + * + ***********************************************************************/ +int +ck_both(path1, path2, path3) +char *path1, *path2, *path3; +{ + if (ck_symlink(path1, path2, path3) == 0) + return(0); + else if ((stat(path3, &statter) == -1) && (errno == ENOENT)) { + TEST_RESULT=TBROK; + sprintf(test_msg, "stat(2) Failure when accessing %s object file ", path3); + return(0); + } + else if ((stat(path2, &asymlink) == -1) && (errno == ENOENT)) { + TEST_RESULT=TBROK; + sprintf(test_msg, "stat(2) Failure when accessing %s symbolic link file ", + path2); + return(0); + } + else if (statter.st_ino != asymlink.st_ino) { + TEST_RESULT=TBROK; + sprintf(test_msg, + "stat(2) Failure when accessing %s object file through %s symbolic link file ", + path3, path2); + return(0); + } + return(1); + +} + +/*********************************************************************** + * This routine populates full_path with a pathname whose length exceeds + * the PATH_MAX define value in param.h + * + * Argument one is a pathname of object file + * Argument two is symbolic link file name + * Argument three is regular file name + ***********************************************************************/ +int +creat_path_max(path1, path2, path3) +char *path1, *path2, *path3; +{ + int ctr, to_go, size, whole_chunks; + char *cwd, *getcwd(); + + if ((cwd = getcwd((char *)NULL, 64)) == NULL) + { + TEST_RESULT=TBROK; + sprintf(test_msg, + "getcwd(3) Failure in setup of %s %s %s test case object elements", + path1, path2, path3); + return(0); + } + cwd = getcwd((char *)NULL, 64); + size = strlen(cwd); + + to_go = PATH_MAX - size; + size = strlen(path1); + whole_chunks = to_go / size; + strcpy(full_path, cwd); + for (ctr=0; ctr < whole_chunks; ctr++) { + strcat(full_path, path1); + } + size= strlen(full_path); + to_go = PATH_MAX - size; + strcat(full_path, "/"); + for (ctr=0; ctr < to_go; ctr++) + strcat(full_path, "Z"); + + return(1); +} + +/*********************************************************************** + * This routine checks that full_path's length exceeds the PATH_MAX + * define value in param.h + * + * Argument one is a pathname of object file + * Argument two is symbolic link file name + * Argument three is regular file name + ***********************************************************************/ +int +ck_path_max(path1, path2, path3) +char *path1, *path2, *path3; +{ + if (strlen(full_path) == (PATH_MAX+1)) + return(1); + else + { + TEST_RESULT=TBROK; + sprintf(test_msg, "%s %d %s %s %s %s", + "full_path character array length was not", (PATH_MAX+1), + "characters long for test case object elements", + path1, path2, path3); + return(0); + } +} + +/*********************************************************************** + * This routine checks if the stat(2) and lstat(2) calls return the same + * information when the path is not a symbolic link file + * + * Argument one is a pathname of object file + * Argument two is symbolic link file name + * Argument three is regular file name + * + ***********************************************************************/ +int +ck_object(path1, path2, path3) +char *path1, *path2, *path3; +{ + int ret; + + if ((ret=see_if_a_symlink(path1)) < 0) { + TEST_RESULT=TFAIL; + sprintf(test_msg, + "lstat(2) failed to return inode information for a regular object file"); + return(0); + } + else if (ret == 1) { + TEST_RESULT=TFAIL; + sprintf(test_msg, + "lstat(2) detected a regular object file as a symbolic link file"); + return(0); + } + else if (stat(path1, &statter) == -1) { + TEST_RESULT=TBROK; + sprintf(test_msg, + "stat(2) failed to return inode information for a regular object file"); + return(0); + } + else if (bcmp((char *)&statter, (char *)&asymlink, sizeof(statter)) != 0) { + TEST_RESULT=TFAIL; + sprintf(test_msg, + "lstat(2) and stat(2) do not return same inode information for an object file"); + return(0); + + } + return(1); +} + +/*********************************************************************** + * Main test case processing function + * + * Argument is a ptr into the all_tcses array of structures of type tcses + ***********************************************************************/ +int +do_syscalltests(tcs) +struct tcses *tcs; +{ + int ctr, ret; + struct all_test_cases *tc_ptr; + + /* + * loop through desired number of test cases + */ + for (ctr=0, tc_ptr=tcs->tc_ptr; ctr < TST_TOTAL; ctr++, tc_ptr++) { + + Buffer[0]='\0'; + + /* + * If running all test cases for all tcid, set the TCID if needed. + */ + if ( Selectedtests == NULL ) { + if ( strcmp(tcs->tcid, tc_ptr->tcid) != 0 ) { + TCID = tc_ptr->tcid; + Tst_count=0; + } + } + /* + * Insure that we are executing the correct tcs test case + */ + if (strcmp(tcs->tcid, tc_ptr->tcid) != 0) { + tst_resm(TBROK, "%s TCID attempted to execute %s %d %d test case", + tcs->tcid, tc_ptr->tcid, tc_ptr->test_fail, tc_ptr->errno_val); + continue; + } + TEST_RESULT=TPASS; + delete_files(S_FILE, O_FILE); + /* + * Perform test case setup + */ + ret = (tc_ptr->test_setup)(tc_ptr->fn_arg[0], tc_ptr->fn_arg[1], + tc_ptr->fn_arg[2], tc_ptr->errno_val); + + /* If an expected error, try it out */ + + if (tc_ptr->test_fail) { + /* + * Try to perform test verification function + */ + if (! (tc_ptr->ck_test)(tc_ptr->fn_arg[0], tc_ptr->fn_arg[1], + tc_ptr->fn_arg[2], tc_ptr->errno_val)) + tst_resm(TEST_RESULT, test_msg); + else if (tc_ptr->errno_val == EEXIST) + do_EEXIST(tc_ptr); + else if (tc_ptr->errno_val == ENOENT) + do_ENOENT(tc_ptr); + else if (tc_ptr->errno_val == ELOOP) + do_ELOOP(tc_ptr); + else if (tc_ptr->errno_val == ENOTDIR) + do_ENOTDIR(tc_ptr); + else if (tc_ptr->errno_val == EXDEV) + do_EXDEV(tc_ptr); + else if (tc_ptr->errno_val == ENAMETOOLONG) + do_ENAMETOOLONG(tc_ptr); + else if (tc_ptr->errno_val == EINVAL) + do_EINVAL(tc_ptr); + else + tst_resm(TBROK, "Test Case Declaration Error"); + } + else if (ret == 1) { /* No setup function error */ + + if (tc_ptr->errno_val != 0) + tst_resm(TBROK, "Test Case Declaration Error"); + else { + /* + * Perform test verification function + */ + ret=(tc_ptr->ck_test)(tc_ptr->fn_arg[0], tc_ptr->fn_arg[1], + tc_ptr->fn_arg[2], tc_ptr->errno_val); + + /* Perform requested symbolic link system call test */ + + if ((cktcsid(tc_ptr->tcid, SYMLINK)) || + (cktcsid(tc_ptr->tcid, LSTAT))) { + if (ret == 1) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + tst_resm(TEST_RESULT, test_msg); + } + else if (ret == 0) + tst_resm(TEST_RESULT, test_msg); + else if (cktcsid(tc_ptr->tcid, READLINK)) + do_readlink(tc_ptr); + else if (cktcsid(tc_ptr->tcid, STAT)) + do_stat(tc_ptr); + else if (cktcsid(tc_ptr->tcid, CHDIR)) + do_chdir(tc_ptr); + else if (cktcsid(tc_ptr->tcid, LINK)) + do_link(tc_ptr); + else if (cktcsid(tc_ptr->tcid, UNLINK)) + do_unlink(tc_ptr); + else if (cktcsid(tc_ptr->tcid, CHMOD)) + do_chmod(tc_ptr); + else if (cktcsid(tc_ptr->tcid, UTIME)) + do_utime(tc_ptr); + else if (cktcsid(tc_ptr->tcid, RENAME)) + do_rename(tc_ptr); + else if (cktcsid(tc_ptr->tcid, OPEN)) + do_open(tc_ptr); + else + tst_resm(TBROK, "Unknown test case processing actions declared"); + } + } + else + tst_resm(TBROK, "Test Case Declaration Error"); + } + return(0); +} + +/*********************************************************************** + * This routine checks for the return of EEXIST errno from requested + * system call + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_EEXIST(tc_ptr) +struct all_test_cases *tc_ptr; +{ + if (cktcsid(tc_ptr->tcid, SYMLINK)) { + + TEST( symlink(tc_ptr->fn_arg[0], tc_ptr->fn_arg[1]) ); + errno=TEST_ERRNO; + if ((TEST_RETURN == -1) && (errno == EEXIST)) + if ( STD_FUNCTIONAL_TEST ) + tst_resm(TPASS, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s %s", + "Expected EEXIST error when creating a symbolic link file", + "which already existed"); + } + else if (cktcsid(tc_ptr->tcid, MKDIR)) { + + TEST ( mkdir(tc_ptr->fn_arg[1],MODE) ); + errno=TEST_ERRNO; + if ((TEST_RETURN == -1) && (errno == EEXIST)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else { + + tst_resm(TFAIL, "%s %s", + "Expected EEXIST error when creating a directory by a symbolic", + "link file which pointed at no object file"); + rmdir(tc_ptr->fn_arg[1]); + } + } + else if (cktcsid(tc_ptr->tcid, OPEN)) { + + TEST( open(tc_ptr->fn_arg[1], (O_EXCL | O_CREAT)) ) + errno=TEST_ERRNO; + if ((TEST_RETURN == -1) && (errno == EEXIST)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s %s errno:%d %s", + "Expected EEXIST error for exclusively opening an object file", + "through a symbolic link file was not received:", + errno, strerror(errno)); + } + else + tst_resm(TBROK, "Unknown test case processing actions declared"); +} + +/*********************************************************************** + * This routine checks for the return of ENOENT errno from requested + * system call + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_ENOENT(tc_ptr) +struct all_test_cases *tc_ptr; +{ + if (cktcsid(tc_ptr->tcid, STAT)) { + + if ((stat(tc_ptr->fn_arg[1], &asymlink) == -1) && (errno == ENOENT)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s %s errno:%d %s", + "Expected ENOENT error for stating a non-existent directory", + "through a symbolic link file was not received:", + errno, strerror(errno)); + } + else if (cktcsid(tc_ptr->tcid, CHDIR)) { + if ((chdir(tc_ptr->fn_arg[1]) == -1) && (errno == ENOENT)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else { + tst_resm(TFAIL, "%s %s errno:%d %s", + "Expected ENOENT error for changing to a non-existent", + "directory through a symbolic link file was not received:", + errno, strerror(errno)); + chdir(TESTDIR); + } + } + else if (cktcsid(tc_ptr->tcid, LINK)) { + + if ((link(tc_ptr->fn_arg[1], "nick") == -1) && (errno == ENOENT)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + { + tst_resm(TFAIL, "%s %s errno:%d %s", + "Expected ENOENT error condition when link(2) a symbolic", + "link which pointed at no object:", errno, strerror(errno)); + delete_files("nick", NULL); + } + } + else if (cktcsid(tc_ptr->tcid, CHMOD)) { + + if ((chmod(tc_ptr->fn_arg[1], MODE) == -1) && (errno == ENOENT)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s %s errno:%d %s", + "Expected ENOENT error condition when chmod(2) a symbolic", + "link which pointed at no object,", errno, strerror(errno)); + } + else if (cktcsid(tc_ptr->tcid, UTIME)) { + + if ((utime(tc_ptr->fn_arg[1], NULL) == -1) && (errno == ENOENT)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s %s errno:%d %s", + "Expected ENOENT error condition when utime(2) a symbolic", + "link which pointed at no object:", errno, strerror(errno)); + } + else if (cktcsid(tc_ptr->tcid, OPEN)) { + + if ((open(tc_ptr->fn_arg[1], O_RDWR) == -1) && (errno == ENOENT)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s %s errno:%d %s", + "Expected ENOENT error for opening a non-existent object", + " file through a symbolic link file was not received,", + errno, strerror(errno)); + } + else + tst_resm(TBROK, "Unknown test case processing actions declared"); +} + +/*********************************************************************** + * This routine checks for the return of ELOOP errno from requested + * system call + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_ELOOP(tc_ptr) +struct all_test_cases *tc_ptr; +{ + if (cktcsid(tc_ptr->tcid, STAT)) { + + TEST( stat(tc_ptr->fn_arg[1], &asymlink) ); + errno=TEST_ERRNO; + if ((TEST_RETURN == -1) && (errno == ELOOP)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, "%s errno:%d %s", + "Expected ELOOP errno from stat(2) (nested symb link),", + errno, strerror(errno)); + else + Tst_count++; + } + else if (cktcsid(tc_ptr->tcid, CHDIR)) { + + TEST( chdir(tc_ptr->fn_arg[1]) ); + errno=TEST_ERRNO; + if ((TEST_RETURN == -1) && (errno == ELOOP)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else { + + tst_resm(TFAIL, "%s errno:%d %s", + "Expected ELOOP error condition when chdir(2) a nested symbolic link:", + errno, strerror(errno)); + chdir(TESTDIR); + } + } + else if (cktcsid(tc_ptr->tcid, LINK)) { + + TEST ( link(tc_ptr->fn_arg[1], O_FILE) ); + errno=TEST_ERRNO; + if ((TEST_RETURN == -1) && (errno == ELOOP)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s errno:%d %s", + "Expected ELOOP error condition when link(2) a nested symbolic link:", + errno, strerror(errno)); + } + else if (cktcsid(tc_ptr->tcid, CHMOD)) { + + TEST ( chmod(tc_ptr->fn_arg[1], MODE) ); + errno=TEST_ERRNO; + if ((TEST_RETURN == -1) && (errno == ELOOP)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s errno:%d %s", + "Expected ELOOP error condition when chmod(2) a nested symbolic link:", + errno, strerror(errno)); + return; + } + else if (cktcsid(tc_ptr->tcid, UTIME)) { + + TEST( utime(tc_ptr->fn_arg[1], NULL) ); + errno=TEST_ERRNO; + + if ((TEST_RETURN == -1) && (errno == ELOOP)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s errno:%d %s", + "Expected ELOOP error condition when utime(2) a nested symbolic link:", + errno, strerror(errno)); + } + else if (cktcsid(tc_ptr->tcid, OPEN)) { + + int fd; + TEST( open(tc_ptr->fn_arg[1], O_CREAT) ); + fd=TEST_RETURN; + errno=TEST_ERRNO; + if ((fd == -1) && (errno == ELOOP)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s errno:%d %s", + "Expected ELOOP error condition when open(2) a nested symbolic link:", + errno, strerror(errno)); + } + else + tst_resm(TBROK, "Unknown test case processing actions declared"); +} + +/*********************************************************************** + * This routine checks for the return of ENOTDIR errno from requested + * system call + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_ENOTDIR(tc_ptr) +struct all_test_cases *tc_ptr; +{ + if (cktcsid(tc_ptr->tcid, RMDIR)) { + + TEST( mkdir(tc_ptr->fn_arg[0], MODE) ); + errno=TEST_ERRNO; + if (TEST_RETURN == -1) + tst_resm(TBROK, "mkdir(2) Failure when creating %s", + tc_ptr->fn_arg[0]); + else if ((rmdir(tc_ptr->fn_arg[1]) == -1) && (errno == ENOTDIR)) { + + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + rmdir(tc_ptr->fn_arg[0]); + } + else + tst_resm(TFAIL, "%s %s errno:%d %s", + "Expected ENOTDIR error for removing a non-existent", + "directory through a symbolic link file was not received,", + errno, strerror(errno)); + } + else + tst_resm(TBROK, "Unknown test case processing actions declared"); +} + +/*********************************************************************** + * This routine checks for the return of EXDEV errno from requested + * system call + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_EXDEV(tc_ptr) +struct all_test_cases *tc_ptr; +{ + if (cktcsid(tc_ptr->tcid, RENAME)) { + + TEST( rename(tc_ptr->fn_arg[1], Y_A_S_FILE) ); + errno=TEST_ERRNO; + if ((TEST_RETURN == -1) && (errno == EXDEV)) { + if (see_if_a_symlink(Y_A_S_FILE) == -1) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s %s %s file outside of current file system", + "rename(3) returned -1 when trying to move symbolic link file", + "outside of current file system, but created", Y_A_S_FILE); + } + else { + tst_resm(TFAIL, "%s %s errno:%d %s", + "Expected EXDEV error for renaming an existing symbolic", + "link file to a location outside of existing file system,", + errno, strerror(errno)); + delete_files("/NiCkEr", NULL); + } + } + else + tst_resm(TBROK, "Unknown test case processing actions declared"); +} + +/*********************************************************************** + * This routine checks for the return of ENAMETOOLONG errno from requested + * system call + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_ENAMETOOLONG(tc_ptr) +struct all_test_cases *tc_ptr; +{ + int ret; + + if (cktcsid(tc_ptr->tcid, SYMLINK)) { + + TEST( symlink(tc_ptr->fn_arg[0], full_path) ); + errno=TEST_ERRNO; + if ((TEST_RETURN == -1) && (errno == ENAMETOOLONG)) + if (see_if_a_symlink(full_path) == -1) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s %s %d %s", + "symlink(2) returned -1 when trying to create a symbolic", + "link file whose name exceeded", (PATH_MAX+1), + "characters, but it created the symbolic link file"); + else + tst_resm(TFAIL, + "Expected ENAMETOOLONG error when creating %s symbolic link file with a path exceeding %d characters: errno:%d %s", + tc_ptr->fn_arg[1], (PATH_MAX+1), errno, strerror(errno)); + } + else if (cktcsid(tc_ptr->tcid, READLINK)) { + + char scratch[PATH_MAX+1]; + + ret=readlink(full_path, scratch, strlen(full_path)); + if (( ret == -1) && (errno == ENAMETOOLONG)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, + "Expected ENAMETOOLONG error when reading %s symbolic link file with a path exceeding %d characters: errno:%d %s", + tc_ptr->fn_arg[1], (PATH_MAX+1), errno, strerror(errno)); + } + else + tst_resm(TBROK, "Unknown test case processing actions declared"); +} + +/*********************************************************************** + * This routine checks for the return of EINVAL errno from requested + * system call + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_EINVAL(tc_ptr) +struct all_test_cases *tc_ptr; +{ + if (cktcsid(tc_ptr->tcid, READLINK)) { + TEST( readlink(tc_ptr->fn_arg[0], test_msg, BUFMAX) ); + errno=TEST_ERRNO; + if (TEST_RETURN == -1) { + if (errno == EINVAL) { + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + } else + tst_resm(TFAIL, "readlink(2) ret:-1, errno:%d, : Exp errno:%d", + errno, EINVAL); + } + else { + tst_resm(TFAIL, "readlink(2) did not returned -1 when reading %s", + "a file which is not a symbolic link file"); + } + } + else + tst_resm(TBROK, "Unknown test case processing actions declared"); +} + +/*********************************************************************** + * This routine checks out the readlink(2) system call for a successful + * invocation + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_readlink(tc_ptr) +struct all_test_cases *tc_ptr; +{ + char scratch[PATH_MAX]; + int ret; + + ret=readlink(tc_ptr->fn_arg[1], scratch, strlen(tc_ptr->fn_arg[0])); + + /*** the TEST macro cannot be used here for some reason ****/ + + if (ret == -1) { + tst_resm(TFAIL, + "readlink(2) failure on %s symbolic link file, errno=%d", + tc_ptr->fn_arg[1], errno); + + } + else if (strncmp(tc_ptr->fn_arg[0], scratch, + strlen(tc_ptr->fn_arg[0])) != 0) { + + /* Must null terminate scratch because readlink(2) doesn't */ + + scratch[strlen(tc_ptr->fn_arg[0])] = '\0'; + + tst_resm(TFAIL, + "readlink(2) Error : Expected %s symbolic link file contents but %s actual contents were returned", + tc_ptr->fn_arg[0], scratch); + } + else if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; +} + +/*********************************************************************** + * This routine checks out the stat(2) system call for a successful + * invocation + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_stat(tc_ptr) +struct all_test_cases *tc_ptr; +{ + if (statter.st_dev != asymlink.st_dev) + tst_resm(TFAIL, + "stat of symbolic link reference to object device info %ld != stat of object file device info %ld", + statter.st_dev, asymlink.st_dev); + + else if (statter.st_mode != asymlink.st_mode) + tst_resm(TFAIL, + "stat of symbolic link reference to object file permissions %ld != stat of object file permissions %ld", + statter.st_mode, asymlink.st_mode); + + else if (statter.st_nlink != asymlink.st_nlink) + tst_resm(TFAIL, + "stat of symbolic link reference to object file link count %ld != stat of object file link count %ld", + statter.st_nlink, asymlink.st_nlink); + + else if (statter.st_uid != asymlink.st_uid) + tst_resm(TFAIL, + "stat of symbolic link reference to object file uid %ld != stat of object file uid %ld", + statter.st_uid, asymlink.st_uid); + + else if (statter.st_gid != asymlink.st_gid) + tst_resm(TFAIL, + "stat of symbolic link reference to object file gid %ld != stat of object file gid %ld", + statter.st_gid, asymlink.st_gid); + + else if (statter.st_size != asymlink.st_size) + tst_resm(TFAIL, + "stat of symbolic link reference to object file size %ld != stat of object file size %ld", + statter.st_size, asymlink.st_size); + + else if (statter.st_atime != asymlink.st_atime) + tst_resm(TFAIL, + "stat of symbolic link reference to object access time %ld != stat of object file access time %ld", + statter.st_atime, asymlink.st_atime); + + else if (statter.st_mtime != asymlink.st_mtime) + tst_resm(TFAIL, + "stat of symbolic link reference to object modify time %ld != stat of object file modify time %ld", + statter.st_atime, asymlink.st_atime); + + else if (statter.st_ctime != asymlink.st_ctime) + tst_resm(TFAIL, + "stat of symbolic link reference to object change time %ld != stat of object file change time %ld", + statter.st_atime, asymlink.st_atime); + else if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; +} + +/*********************************************************************** + * This routine checks out the chdir(2) system call for a successful + * invocation + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_chdir(tc_ptr) +struct all_test_cases *tc_ptr; +{ + if (mkdir(tc_ptr->fn_arg[2],MODE) == -1) + tst_resm(TFAIL, "Could not create a setup directory file"); + else { + + sprintf(Buf, "mkdir(%s, %#o) was successful\n", tc_ptr->fn_arg[2],MODE); + strcat(Buffer, Buf); + + if (chdir(tc_ptr->fn_arg[1]) == -1) + tst_resm(TFAIL, "%sCould not change a directory file through a %s", + Buffer, "symbolic link which which pointed at object"); + else { + + char *cwd, *getcwd(); + char expected_location[PATH_MAX]; + /* + * Build expected current directory position + */ + strcpy(expected_location, TESTDIR); + strcat(expected_location, "/"); + strcat(expected_location, tc_ptr->fn_arg[2]); + + if ((cwd = getcwd((char *)NULL, 64)) == NULL) + tst_resm(TFAIL, "getcwd(3) FAILURE"); + else if (strcmp(cwd, expected_location) == 0) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else { + tst_resm(TFAIL, "%s%s %s %s not equal to expected %s", Buffer, + "chdir(2) returned successfully, but getcwd(3) indicated", + "new current working directory location", cwd, expected_location); + } + chdir(TESTDIR); + } + rmdir(tc_ptr->fn_arg[2]); + } +} + +/*********************************************************************** + * This routine checks out the link(2) system call for a successful + * invocation + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_link(tc_ptr) +struct all_test_cases *tc_ptr; +{ + struct stat stbuf; + + if (link(tc_ptr->fn_arg[1], "nick") == -1) { + tst_resm(TFAIL, "%slink(%s, \"nick\") failed, errno: %d\n%s %s", + Buffer, tc_ptr->fn_arg[1], errno, + "link of new file to object file via symbolic link file failed", + "when expected not to"); + } + else { + sprintf(Buf, "link(%s, \"nick\") was successful\n", tc_ptr->fn_arg[1]); + strcat(Buffer, Buf); + + if ( STD_FUNCTIONAL_TEST ) { + /* + * Check that links counts were properly set + */ + if (lstat(tc_ptr->fn_arg[1], &asymlink) == -1) { + tst_resm(TBROK, "lstat(%s) failed. errno: %d", + tc_ptr->fn_arg[1], errno); + + } else if (lstat("nick", &statter) == -1) { + tst_resm(TBROK, "lstat(nick) failed, errno:%d", errno); + } else { + if (statter.st_ino == asymlink.st_ino) { + if ((statter.st_nlink ==2) && (asymlink.st_nlink == 2)) { + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + } else { + lstat(tc_ptr->fn_arg[2], &stbuf); + + tst_resm(TFAIL, + "%slink(%s, %s) failed to adjust link count.\n\ + count for nick is %d, count for %s is %d, count for %s is %d.", + Buffer, tc_ptr->fn_arg[1], "nick", + statter.st_nlink, tc_ptr->fn_arg[1], asymlink.st_nlink, + tc_ptr->fn_arg[2], stbuf.st_nlink); + } + } else { + tst_resm(TFAIL, + "%sA lstat of %s (ino:%d) and of\n\t\t\ +%s (ino:%d), does not show them being the same ino.", Buffer, + tc_ptr->fn_arg[1], asymlink.st_ino, "nick", statter.st_ino); + } + } + } + delete_files("nick", NULL); + } +} + +/*********************************************************************** + * This routine checks out the unlink(2) system call for a successful + * invocation + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_unlink(tc_ptr) +struct all_test_cases *tc_ptr; +{ + if (stat(tc_ptr->fn_arg[2], &asymlink) == -1) + tst_resm(TBROK, + "stat(2) Failure when accessing %s object file", tc_ptr->fn_arg[2]); + else if (unlink(tc_ptr->fn_arg[1]) == -1) + tst_resm(TFAIL, "unlink(2) failed when removing symbolic link file"); + else { + sprintf(Buf, "unlink(%s) was successful\n", tc_ptr->fn_arg[1]); + strcat(Buffer, Buf); + if (stat(tc_ptr->fn_arg[2], &statter) == -1) + tst_resm(TFAIL,"%s %s", + "unlink(2) failed because it not only removed symbolic link", + "file which pointed at object file, but object file as well"); + + else + if ((statter.st_ino == asymlink.st_ino) && + (statter.st_dev == asymlink.st_dev) && + (statter.st_size == asymlink.st_size)) + + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s%s %s %s", Buffer, + "unlink(2) failed because it not only removed symbolic link", + "file which pointed at object file, but it changed object", + "file inode information"); + } + +} + +/*********************************************************************** + * This routine checks out the chmod(2) system call for a successful + * invocation + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_chmod(tc_ptr) +struct all_test_cases *tc_ptr; +{ + if (stat(tc_ptr->fn_arg[2], &asymlink) == -1) + tst_resm(TBROK, + "stat(2) Failure when accessing %s object file", tc_ptr->fn_arg[2]); + else if (chmod(tc_ptr->fn_arg[1], (MODE | MASK)) == -1) + tst_resm(TFAIL, "%s%s %s", Buffer, + "chmod(2) failed when changing file permission", + "through symbolic link file"); + else { + sprintf(Buf, "chmod(%s, %#o) was successful\n", tc_ptr->fn_arg[1], + (MODE | MASK)); + strcat(Buffer, Buf); + + if (stat(tc_ptr->fn_arg[2], &statter) == -1) + tst_resm(TBROK, + "stat(2) Failure when accessing %s object file", tc_ptr->fn_arg[2]); + else + if ((statter.st_mode == (MODE | MASK)) && + (statter.st_mode != asymlink.st_mode)) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s%s %o to %o %s", Buffer, + "chmod(2) failed to change object file permissions from", + asymlink.st_mode, (MODE | MASK), + "through symbolic link file"); + } + +} + +/*********************************************************************** + * This routine checks out the utime(2) system call for a successful + * invocation + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_utime(tc_ptr) +struct all_test_cases *tc_ptr; +{ + struct utimbuf utimes; + + if (stat(tc_ptr->fn_arg[2], &asymlink) == -1) + tst_resm(TBROK, "stat(2) Failure when accessing %s object file", + tc_ptr->fn_arg[2]); + else { + /* Now add a few values to access and modify times */ + + utimes.actime = asymlink.st_atime + a_time_value; + utimes.modtime = asymlink.st_mtime + a_time_value; + + /* Now hand off to utime(2) via symbolic link file*/ + + if (utime(tc_ptr->fn_arg[1], &utimes) == -1) + tst_resm(TFAIL, "%s %s", + "utime(2) failed to process object file access and modify", + "time updates through symbolic link"); + else { + /* Now verify changes were made */ + + if (stat(tc_ptr->fn_arg[2], &statter) == -1) + tst_resm(TBROK, + "stat(2) Failure when accessing %s object file", + tc_ptr->fn_arg[2]); + else { + time_t temp, diff; + + temp = statter.st_atime - asymlink.st_atime; + diff = (statter.st_mtime - asymlink.st_mtime) - temp; + + if (! diff) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, "%s %s %d greater than original times", + "utime(2) failed to change object file access and", + "modify times through symbolic link to a value", + a_time_value); + } + } + } +} + +/*********************************************************************** + * This routine checks out the rename(2) system call for a successful + * invocation + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_rename(tc_ptr) +struct all_test_cases *tc_ptr; +{ + int pts_at_object = 0; + + + if (stat(tc_ptr->fn_arg[2], &statter) != -1) + pts_at_object=1; + + TEST (rename(tc_ptr->fn_arg[1], A_S_FILE) ); + errno=TEST_ERRNO; + if (TEST_RETURN == -1) + tst_resm(TFAIL, "rename(3) failed to rename %s symbolic link file to %s", + tc_ptr->fn_arg[2], A_S_FILE); + else if (pts_at_object) + if (ck_both(tc_ptr->fn_arg[0], A_S_FILE, tc_ptr->fn_arg[2])) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, test_msg); + else if ( ! ck_symlink(tc_ptr->fn_arg[0], A_S_FILE, NULL)) + tst_resm(TFAIL, test_msg); + else if (stat(tc_ptr->fn_arg[1], &asymlink) != -1) + tst_resm(TFAIL, + "rename(3) did not remove %s when renaming to %s", + tc_ptr->fn_arg[1], A_S_FILE); + else if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; +} + +/*********************************************************************** + * This routine checks out the open(2) system call for a successful + * invocation + * + * Argument is pointer to test_objects array of structures of type + * all_test_cases + ***********************************************************************/ +void +do_open(tc_ptr) +struct all_test_cases *tc_ptr; +{ + int fd = -1; + int ret, pts_at_object = 0; + char scratch[PATH_MAX]; + + + if (stat(tc_ptr->fn_arg[2], &statter) != -1) + pts_at_object=1; + + if (pts_at_object) { + TEST( open(tc_ptr->fn_arg[1], O_RDWR) ); + errno=TEST_ERRNO; + if ((fd=TEST_RETURN) == -1) { + tst_resm(TFAIL, + "open(2) Failure when opening object file through symbolic link file"); + return; + } + } + else { + TEST(open(tc_ptr->fn_arg[1], (O_CREAT | O_RDWR), MODE) ); + errno=TEST_ERRNO; + if ((fd=TEST_RETURN) == -1) { + tst_resm(TFAIL, + "open(2) Failure when creating object file through symbolic link file"); + return; + } + } + if ((ret=write(fd, BIG_STRING, strlen(BIG_STRING))) == -1) { + tst_resm(TFAIL, + "write(2) Failure to object file opened through a symbolic link file: errno:%d", + errno); + } + else if (ret != strlen(BIG_STRING)) { + tst_resm(TFAIL, + "write(2) Failed to write %d bytes to object file opened through a symbolic link file", + strlen(BIG_STRING)); + } + else if (lseek(fd, 0L, 0) == -1) { + tst_resm(TFAIL, + "lseek(2) Failed to position to beginning of object file opened through a symbolic link file: errno = %d", + errno); + } + else if ((ret=read(fd, scratch, strlen(BIG_STRING))) == -1) { + tst_resm(TFAIL, + "read(2) Failure of object file opened through a symbolic link file: errno = %d", + errno); + } + else if (ret != strlen(BIG_STRING)) { + tst_resm(TFAIL, + "read(2) Failed to read %d bytes to object file opened through a symbolic link file", + strlen(BIG_STRING)); + } + else if (strncmp(BIG_STRING, scratch, strlen(BIG_STRING)) != 0) { + tst_resm(TFAIL, + "Content of write(2) and read(2) Failed to object file through symbolic link file was not as expected. Expected %s and read returned %s", + BIG_STRING, scratch); + } + else { + /* + * Close off symbolic link file to object file access + */ + if (close(fd) == -1) { + tst_resm(TFAIL, + "close(2) Failure when closing object file accessed symbolic link file"); + } + /* + * Now, lets open up and read object file and compare contents + */ + else if ((fd=open(tc_ptr->fn_arg[0], O_RDONLY)) == -1) { + tst_resm(TFAIL, "open(2) Failure when opening %s file: errno:%d %s", + tc_ptr->fn_arg[0], errno, strerror(errno)); + } + else if ((ret=read(fd, scratch, strlen(BIG_STRING))) == -1) { + tst_resm(TFAIL, + "read(2) Failure of object file opened through a symbolic link file: errno:%d", errno); + } + else if (ret != strlen(BIG_STRING)) { + tst_resm(TFAIL, + "read(2) Failed to read %d bytes to object file opened through a symbolic link file", + strlen(BIG_STRING)); + } + else if (strncmp(BIG_STRING, scratch, strlen(BIG_STRING)) != 0) { + tst_resm(TFAIL, + "Content of write(2) and read(2) Failed to object file through symbolic link file was not as expected. Expected %s and read returned %s", + BIG_STRING, scratch); + } + else if (pts_at_object) { + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + } + else { /* Insure newly created object file is pointed at */ + if (ck_both(tc_ptr->fn_arg[0], tc_ptr->fn_arg[1], tc_ptr->fn_arg[0])) + if ( TEST_RESULT != TPASS || STD_FUNCTIONAL_TEST ) + tst_resm(TEST_RESULT, msgs[tc_ptr->pass_msg]); + else + Tst_count++; + else + tst_resm(TFAIL, test_msg); + } + close(fd); + } +} + +/*************************************************************** + * setup() - performs all ONE TIME setup for this test. + ***************************************************************/ +void +setup() +{ + /* capture signals */ + tst_sig(FORK, DEF_HANDLER, cleanup); + + /* create a temporary directory and go to it */ + tst_tmpdir(); + + /* Pause if that option was specified */ + TEST_PAUSE; + +} /* End setup() */ + + +/*************************************************************** + * cleanup() - performs all ONE TIME cleanup for this test at + * completion or premature exit. + ***************************************************************/ +void +cleanup() +{ + /* + * print timing stats if that option was specified. + */ + TEST_CLEANUP; + + /* remove temporary directory and all files in it. */ + tst_rmdir(); + + /* exit with return code appropriate for results */ + tst_exit(); + +} /* End cleanup() */ + + +/* + * + */ +void help() +{ + int ind; + + printf(" -T id Determines which tests cases to execute:\n"); + + for (ind=0; ind<sizeof(all_tcses)/sizeof(struct tcses ); ind++) { + printf(" %s/%s - %s\n", all_tcses[ind].tcid, all_tcses[ind].syscall, + all_tcses[ind].desc); + } +} |