1/*
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20/*
21 * NAME
22 *	getcwd02
23 *
24 * DESCRIPTION
25 *	Testcase to check the basic functionality of the getcwd(2) system call.
26 *
27 * ALGORITHM
28 *	Get the path name of the current working directory from the current
29 *	shell through a pipe, and compare it with what is returned by
30 *	getcwd(2) system call.
31 *
32 *  Blocks 1-4 are with char[], #4 is special case where address is -1
33 *
34 *	Block 1: Call getcwd(2) with valid cwd[]:
35 *              Should work fine
36 *	Block 2: Call getcwd(2) with valid cwd[], size = 0:
37 *              Should return NULL, errno = EINVAL
38 *	Block 3: Call getcwd(2) with valid cwd[], size <= strlen(path):
39 *              i.e. size = 1, Should return NULL, errno = ERANGE
40 *      Block 4: Call getcwd(2) with cwd address = -1, size > strlen(path):
41 *              Should return NULL, errno = EFAULT
42 *
43 *  Blocks 5-7 are with char*
44 *
45 *	Block 5: Call getcwd(2) with *buffer = NULL, size = 0:
46 * 		Should allocate buffer, and work fine
47 *	Block 6: Call getcwd(2) with *buffer = NULL, size <= strlen(path):
48 * 		i.e. size = 1, Should return NULL, errno = ERANGE
49 *      Block 7: Call getcwd(2) with *buffer = NULL, size > strlen(path):
50 *              Should work fine and allocate buffer
51 *
52 * HISTORY
53 *	07/2001 Ported by Wayne Boyer
54 *      02/2002 Added more testcases, cleaned up by wjh
55 *
56 * RESTRICTIONS
57 *	NONE
58 */
59#include <stdio.h>
60#include <string.h>
61#include <errno.h>
62#include "test.h"
63#define FAILED 1
64
65#ifdef ANDROID
66char *pwd = "/system/bin/pwd";
67#else
68char *pwd = "/bin/pwd";
69#endif
70int flag;
71char *TCID = "getcwd02";
72int TST_TOTAL = 7;
73
74void cleanup(void);
75void setup(void);
76void do_block1(void);
77void do_block2(void);
78void do_block3(void);
79void do_block4(void);
80void do_block5(void);
81void do_block6(void);
82void do_block7(void);
83
84char pwd_buf[BUFSIZ];		//holds results of pwd pipe
85char cwd[BUFSIZ];		//used as our valid buffer
86char *buffer = NULL;		//catches the return value from getcwd when passing NULL
87char *cwd_ptr = NULL;		//catches the return value from getcwd() when passing cwd[]
88
89int main(int ac, char **av)
90{
91	FILE *fin;
92	char *cp;
93	int lc;
94
95	tst_parse_opts(ac, av, NULL, NULL);
96	setup();
97
98	/*
99	 * The following loop checks looping state if -i option given
100	 */
101	for (lc = 0; TEST_LOOPING(lc); lc++) {
102		tst_count = 0;
103
104		if ((fin = popen(pwd, "r")) == NULL) {
105			tst_resm(TINFO, "%s: can't run %s", TCID, pwd);
106			tst_brkm(TBROK, cleanup, "%s FAILED", TCID);
107		}
108		while (fgets(pwd_buf, sizeof(pwd_buf), fin) != NULL) {
109			if ((cp = strchr(pwd_buf, '\n')) == NULL) {
110				tst_brkm(TBROK, cleanup, "pwd output too long");
111			}
112			*cp = 0;
113		}
114		pclose(fin);
115
116		do_block1();
117		do_block2();
118		do_block3();
119		do_block4();
120		do_block5();
121		do_block6();
122		do_block7();
123	}
124	cleanup();
125	tst_exit();
126}
127
128void do_block1(void)		//valid cwd[]: -> Should work fine
129{
130	int flag = 0;
131	tst_resm(TINFO, "Enter Block 1");
132
133	if ((cwd_ptr = getcwd(cwd, sizeof(cwd))) == NULL) {
134		tst_resm(TFAIL|TERRNO, "getcwd() failed unexpectedly");
135		flag = FAILED;
136	}
137	if ((flag != FAILED) && (strcmp(pwd_buf, cwd) != 0)) {
138		tst_resm(TFAIL, "getcwd() returned unexpected working "
139			 "directory: expected: %s, got: %s\n", pwd_buf, cwd);
140		flag = FAILED;
141	}
142	tst_resm(TINFO, "Exit Block 1");
143	if (flag == FAILED) {
144		tst_resm(TFAIL, "Block 1 FAILED");
145	} else {
146		tst_resm(TPASS, "Block 1 PASSED");
147	}
148}
149
150void do_block2(void)		//valid cwd[], size = 0: -> Should return NULL, errno = EINVAL
151{
152	int flag = 0;
153	tst_resm(TINFO, "Enter Block 2");
154
155	if (((cwd_ptr = getcwd(cwd, 0)) == NULL)
156	    && (errno != EINVAL)) {
157		tst_resm(TFAIL|TERRNO, "getcwd() failed unexpectedly (wanted EINVAL)");
158		flag = FAILED;
159	}
160	tst_resm(TINFO, "Exit Block 2");
161	if (flag == FAILED) {
162		tst_resm(TFAIL, "Block 2 FAILED");
163	} else {
164		tst_resm(TPASS, "Block 2 PASSED");
165	}
166}
167
168void do_block3(void)		//valid cwd[], size = 1 -> Should return NULL, errno = ERANGE
169{
170	int flag = 0;
171	tst_resm(TINFO, "Enter Block 3");
172
173	if (((cwd_ptr = getcwd(cwd, 1)) != NULL)
174	    || (errno != ERANGE)) {
175		tst_resm(TFAIL|TERRNO, "getcwd() failed unexpectedly (wanted ERANGE)");
176		flag = FAILED;
177	}
178	tst_resm(TINFO, "Exit Block 3");
179	if (flag == FAILED) {
180		tst_resm(TFAIL, "Block 3 FAILED");
181	} else {
182		tst_resm(TPASS, "Block 3 PASSED");
183	}
184}
185
186void do_block4(void)		//invalid cwd[] = -1, size = BUFSIZ: -> return NULL, errno = FAULT
187{
188/* Skip since uClinux does not implement memory protection */
189#ifndef UCLINUX
190	int flag = 0;
191	tst_resm(TINFO, "Enter Block 4");
192
193	if (((cwd_ptr = getcwd((char *)-1, sizeof(cwd))) != NULL)
194	    || (errno != EFAULT)) {
195		tst_resm(TFAIL|TERRNO, "getcwd() failed unexpectedly (wanted EFAULT)");
196		flag = FAILED;
197	}
198	tst_resm(TINFO, "Exit Block 4");
199	if (flag == FAILED) {
200		tst_resm(TFAIL, "Block 4 FAILED");
201	} else {
202		tst_resm(TPASS, "Block 4 PASSED");
203	}
204#else
205	tst_resm(TINFO, "Skipping Block 4 on uClinux");
206#endif
207}
208
209void do_block5(void)		//buffer = NULL, and size = 0, should succeed
210{
211	int flag = 0;
212	tst_resm(TINFO, "Enter Block 5");
213
214	if ((buffer = getcwd(NULL, 0)) == NULL) {
215		tst_resm(TFAIL|TERRNO, "getcwd() failed unexpectedly");
216		flag = FAILED;
217	}
218	if ((flag != FAILED) && (strcmp(pwd_buf, buffer) != 0)) {
219		tst_resm(TFAIL, "getcwd() returned unexpected working "
220			 "directory: expected: %s, got: %s\n", pwd_buf, buffer);
221		flag = FAILED;
222	}
223	tst_resm(TINFO, "Exit Block 5");
224	if (flag == FAILED) {
225		tst_resm(TFAIL, "Block 5 FAILED");
226	} else {
227		tst_resm(TPASS, "Block 5 PASSED");
228	}
229	free(buffer);
230	buffer = NULL;
231}
232
233void do_block6(void)		//buffer = NULL, size = 1: -> return NULL, errno = ERANGE
234{
235	int flag = 0;
236	tst_resm(TINFO, "Enter Block 6");
237
238	if (((buffer = getcwd(NULL, 1)) != NULL)
239	    || (errno != ERANGE)) {
240		tst_resm(TFAIL|TERRNO, "getcwd() failed unexpectedly (wanted ERANGE)");
241		flag = FAILED;
242	}
243	tst_resm(TINFO, "Exit Block 6");
244	if (flag == FAILED) {
245		tst_resm(TFAIL, "Block 6 FAILED");
246	} else {
247		tst_resm(TPASS, "Block 6 PASSED");
248	}
249}
250
251void do_block7(void)		//buffer = NULL, size = BUFSIZ: -> work fine, allocate buffer
252{
253	int flag = 0;
254	tst_resm(TINFO, "Enter Block 7");
255
256	if ((buffer = getcwd(NULL, sizeof(cwd))) == NULL) {
257		tst_resm(TFAIL|TERRNO, "getcwd() failed unexpectedly");
258		flag = FAILED;
259	}
260	if ((flag != FAILED) && (strcmp(pwd_buf, buffer) != 0)) {
261		tst_resm(TFAIL, "getcwd() returned unexpected working "
262			 "directory: expected: %s, got: %s\n", pwd_buf, buffer);
263		flag = FAILED;
264	}
265	tst_resm(TINFO, "Exit Block 7");
266	if (flag == FAILED) {
267		tst_resm(TFAIL, "Block 7 FAILED");
268	} else {
269		tst_resm(TPASS, "Block 7 PASSED");
270	}
271	free(buffer);
272	buffer = NULL;
273}
274
275void setup(void)
276{
277	/* FORK is set here because of the popen() call above */
278	tst_sig(FORK, DEF_HANDLER, cleanup);
279
280	TEST_PAUSE;
281
282	/* create a test directory and cd into it */
283	tst_tmpdir();
284}
285
286void cleanup(void)
287{
288	/* remove the test directory */
289	tst_rmdir();
290}
291