blob: 2c61fc0cd5092ff153902139139c7db1317094ea [file] [log] [blame]
plars865695b2001-08-27 22:15:12 +00001/*
2 *
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
21 * Test Name : readlink03
22 *
23 * Test Description :
24 * Verify that,
25 * 1) readlink(2) returns -1 and sets errno to EACCES if search/write
26 * permission is denied in the directory where the symbolic link
27 * resides.
28 * 2) readlink(2) returns -1 and sets errno to EINVAL if the buffer size
29 * is not positive.
30 * 3) readlink(2) returns -1 and sets errno to EINVAL if the specified
31 * file is not a symbolic link file.
32 * 4) readlink(2) returns -1 and sets errno to ENAMETOOLONG if the
33 * pathname component of symbolic link is too long (ie, > PATH_MAX).
34 * 5) readlink(2) returns -1 and sets errno to ENOENT if the component of
35 * symbolic link points to an empty string.
36 *
37 * Expected Result:
38 * readlink() should fail with return value -1 and set expected errno.
39 *
40 * Algorithm:
41 * Setup:
42 * Setup signal handling.
43 * Create temporary directory.
44 * Pause for SIGUSR1 if option specified.
45 *
46 * Test:
47 * Loop if the proper options are given.
48 * Execute system call
49 * Check return code, if system call failed (return=-1)
50 * if errno set == expected errno
51 * Issue sys call fails with expected return value and errno.
52 * Otherwise,
53 * Issue sys call fails with unexpected errno.
54 * Otherwise,
55 * Issue sys call returns unexpected value.
56 *
57 * Cleanup:
58 * Print errno log and/or timing stats if options given
59 * Delete the temporary directory(s)/file(s) created.
60 *
61 * Usage: <for command-line>
62 * readlink03 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
63 * where, -c n : Run n copies concurrently.
64 * -e : Turn on errno logging.
65 * -i n : Execute test n times.
66 * -I x : Execute test for x seconds.
67 * -P x : Pause for x seconds between iterations.
68 * -t : Turn on syscall timing.
69 *
70 * HISTORY
71 * 07/2001 Ported by Wayne Boyer
72 *
73 * RESTRICTIONS:
74 * This test should be executed by 'non-super-user' only.
75 */
76
77#include <stdio.h>
78#include <sys/types.h>
79#include <sys/fcntl.h>
80#include <errno.h>
81#include <string.h>
82#include <signal.h>
83#include <sys/stat.h>
84
85#include "test.h"
86#include "usctest.h"
87
88#define MODE_RWX S_IRWXU | S_IRWXG | S_IRWXO
89#define FILE_MODE S_IRUSR | S_IRGRP | S_IROTH
90#define DIR_TEMP "testdir_1"
91#define TESTFILE "testfile"
92#define TEST_FILE1 "testdir_1/tfile_1"
93#define SYM_FILE1 "testdir_1/sfile_1"
94#define TEST_FILE2 "tfile_2"
95#define SYM_FILE2 "sfile_2"
96#define MAX_SIZE 256
97
98char *TCID="readlink03"; /* Test program identifier. */
99int TST_TOTAL=5; /* Total number of test cases. */
100extern int Tst_count; /* Test Case counter for tst_* routines */
101int exp_enos[]={EACCES, EINVAL, ENAMETOOLONG, ENOENT, 0};
102
103int no_setup();
104int setup1(); /* setup function to test symlink for EACCES */
105int setup2(); /* setup function to test symlink for EEXIST */
106int lpath_setup(); /* setup function to test chmod for ENAMETOOLONG */
107
108char Longpathname[PATH_MAX+2];
109
110struct test_case_t { /* test case struct. to hold ref. test cond's*/
111 char *link;
112 char *desc;
113 int exp_errno;
114 size_t buf_siz;
115 int (*setupfunc)();
116} Test_cases[] = {
117 { SYM_FILE1, "No Search permissions to process", EACCES, 1, setup1 },
118 { SYM_FILE2, "Buffer size is not positive", EINVAL, -1, setup2 },
119 { TEST_FILE2, "File is not symbolic link", EINVAL, 1, no_setup },
120 { Longpathname, "Symlink path too long", ENAMETOOLONG, 1, lpath_setup },
121 { "", "Symlink Pathname is empty", ENOENT, 1, no_setup },
122 { NULL, NULL, 0, 0, no_setup }
123};
124
125extern void setup(); /* Setup function for the test */
126extern void cleanup(); /* Cleanup function for the test */
127
128int
129main(int ac, char **av)
130{
131 char buffer[MAX_SIZE]; /* temporary buffer to hold symlink contents*/
132 int lc; /* loop counter */
133 char *msg; /* message returned from parse_opts */
134 char *sym_file; /* symbolic link file name */
135 char *test_desc; /* test specific error message */
136 int i; /* counter to test different test conditions */
137 size_t buf_size; /* size of buffer for readlink */
138
139 /* Parse standard options given to run the test. */
140 msg = parse_opts(ac, av, (option_t *)NULL, NULL);
141 if (msg != (char *)NULL) {
142 tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg);
143 }
144
145 /*
146 * Invoke setup function to call individual test setup functions
147 * to simulate test conditions.
148 */
149 setup();
150
151 /* set the expected errnos... */
152 TEST_EXP_ENOS(exp_enos);
153
154 /* Check looping state if -i option given */
155 for (lc = 0; TEST_LOOPING(lc); lc++) {
156 /* Reset Tst_count in case we are looping. */
157 Tst_count=0;
158
159 for (i = 0; Test_cases[i].desc != NULL; i++) {
160 sym_file = Test_cases[i].link;
161 test_desc = Test_cases[i].desc;
162 buf_size = Test_cases[i].buf_siz;
163
164 if (buf_size == 1) {
165 buf_size = sizeof(buffer);
166 }
167
168 /*
169 * Call readlink(2) to test different test conditions.
170 * verify that it fails with -1 return value and sets
171 * appropriate errno.
172 */
173 TEST(readlink(sym_file, buffer, buf_size));
174
175 /* Check return code of readlink(2) */
176 if (TEST_RETURN != -1) {
177 tst_resm(TFAIL, "readlink() returned %d, "
178 "expected -1, errno:%d", TEST_RETURN,
179 Test_cases[i].exp_errno);
180 continue;
181 }
182
183 TEST_ERROR_LOG(TEST_ERRNO);
184
185 if (TEST_ERRNO == Test_cases[i].exp_errno) {
186 tst_resm(TPASS, "readlink(), %s, returned "
187 "errno %d", test_desc, TEST_ERRNO);
188 tst_resm(TPASS, "readlink(), %s, returned "
189 "errno %d", test_desc, TEST_ERRNO);
190 } else {
191 tst_resm(TFAIL, "readlink() failed, %s, "
192 "errno=%d, expected errno=%d",
193 test_desc, TEST_ERRNO,
194 Test_cases[i].exp_errno);
195 }
196 } /* End of TEST CASE LOOPING. */
197 } /* End for TEST_LOOPING */
198 /* Call cleanup() to undo setup done for the test. */
199 cleanup();
200
201 /*NOTREACHED*/
202} /* End main */
203
204/*
205 * setup() - performs all ONE TIME setup for this test.
206 *
207 * Create a temporary directory and change directory to it.
208 * Call test specific setup functions.
209 */
210void
211setup()
212{
213 int i;
214
215 /* make sure test is not being run as root */
216 if (0 == geteuid()) {
217 tst_brkm(TBROK, tst_exit, "Must not run test as root");
218 }
219
220 /* capture signals */
221 tst_sig(NOFORK, DEF_HANDLER, cleanup);
222
223 /* Pause if that option was specified */
224 TEST_PAUSE;
225
226 /* make a temp directory and cd to it */
227 tst_tmpdir();
228
229 /* call individual setup functions */
230 for (i = 0; Test_cases[i].desc != NULL; i++) {
231 Test_cases[i].setupfunc();
232 }
233}
234
235/*
236 * no_setup() - Some test conditions for readlink(2) do not any setup.
237 */
238int
239no_setup()
240{
241 return 0;
242}
243
244/*
245 * setup1() - setup function for a test condition for which readlink(2)
246 * returns -1 and sets errno to EACCES.
247 *
248 * Create a test directory under temporary directory and create a test file
249 * under this directory with mode "0666" permissions.
250 * Create a symlink of testfile under test directory.
251 * Modify the mode permissions on test directory such that process will not
252 * have search permissions on test directory.
253 */
254int
255setup1()
256{
257 int fd; /* file handle for testfile */
258
259 if (mkdir(DIR_TEMP, MODE_RWX) < 0) {
260 tst_brkm(TBROK, cleanup, "mkdir(2) of %s failed", DIR_TEMP);
261 }
262
263 if ((fd = open(TEST_FILE1, O_RDWR|O_CREAT, 0666)) == -1) {
264 tst_brkm(TBROK, cleanup,
265 "open(%s, O_RDWR|O_CREAT, 0666) failed, errno=%d : %s",
266 TEST_FILE1, errno, strerror(errno));
267 }
268 if (close(fd) == -1) {
269 tst_brkm(TBROK, cleanup, "close(%s) failed, errno=%d : %s",
270 TEST_FILE1, errno, strerror(errno));
271 }
272
273 /* Creat a symbolic link of testfile under test directory */
274 if (symlink(TEST_FILE1, SYM_FILE1) < 0) {
275 tst_brkm(TBROK, cleanup, "symlink of %s failed", TEST_FILE1);
276 }
277
278 /* Modify mode permissions on test directory */
279 if (chmod(DIR_TEMP, FILE_MODE) < 0) {
280 tst_brkm(TBROK, cleanup, "chmod(2) of %s failed", DIR_TEMP);
281 }
282 return 0;
283}
284
285/*
286 * setup2() - setup function for a test condition for which readlink(2)
287 * returns -1 and sets errno to EINVAL.
288 *
289 * Create a testfile under temporary directory and create a symlink
290 * file of it.
291 */
292int
293setup2()
294{
295 int fd; /* file handle for testfile */
296
297 /* Creat a testfile and close it */
298 if ((fd = open(TEST_FILE2, O_RDWR|O_CREAT, 0666)) == -1) {
299 tst_brkm(TBROK, cleanup,
300 "open(%s, O_RDWR|O_CREAT, 0666) failed, errno=%d : %s",
301 TEST_FILE2, errno, strerror(errno));
302 }
303 if (close(fd) == -1) {
304 tst_brkm(TBROK, cleanup, "close(%s) failed, errno=%d : %s",
305 TEST_FILE2, errno, strerror(errno));
306 }
307
308 /* Creat a symlink of testfile created above */
309 if (symlink(TEST_FILE2, SYM_FILE2) < 0) {
310 tst_brkm(TBROK, cleanup, "symlink() failed to create %s in "
311 "setup2, error=%d", SYM_FILE2, errno);
312 }
313 return 0;
314}
315
316/*
317 * lpath_setup() - setup to create a node with a name length exceeding
318 * the MAX. length of PATH_MAX.
319 */
320int
321lpath_setup()
322{
323 int i; /* counter variable */
324
325 for (i = 0; i <= (PATH_MAX + 1); i++) {
326 Longpathname[i] = 'a';
327 }
328 return 0;
329}
330
331/*
332 * cleanup() - performs all ONE TIME cleanup for this test at
333 * completion or premature exit.
334 *
335 * Restore the mode permissions on test directory.
336 * Remove the temporary directory created in the setup.
337 */
338void
339cleanup()
340{
341 /*
342 * print timing stats if that option was specified.
343 * print errno log if that option was specified.
344 */
345 TEST_CLEANUP;
346
347 /* Restore mode permissions on test directory created in setup2() */
348 if (chmod(DIR_TEMP, MODE_RWX) < 0) {
349 tst_brkm(TBROK, NULL, "chmod(2) of %s failed", DIR_TEMP);
350 }
351
352 /* Remove tmp dir and all files in it */
353 tst_rmdir();
354
355 /* exit with return code appropriate for results */
356 tst_exit();
357}