lchown01.c revision 43088e16aa60d69e3ec5a69cdd8bdd45b8891127
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
21 * Test Name: lchown01
22 *
23 * Test Description:
24 *  Verify that, lchown(2) succeeds to change the owner and group of a file
25 *  specified by path to any numeric owner(uid)/group(gid) values when invoked
26 *  by super-user.
27 *
28 * Expected Result:
29 *  lchown(2) should return 0 and the ownership set on the file should match
30 *  the numeric values contained in owner and group respectively.
31 *
32 * Algorithm:
33 *  Setup:
34 *   Setup signal handling.
35 *   Create temporary directory.
36 *   Pause for SIGUSR1 if option specified.
37 *
38 *  Test:
39 *   Loop if the proper options are given.
40 *   Execute system call
41 *   Check return code, if system call failed (return=-1)
42 *	Log the errno and Issue a FAIL message.
43 *   Otherwise,
44 *	Verify the Functionality of system call
45 *      if successful,
46 *		Issue Functionality-Pass message.
47 *      Otherwise,
48 *		Issue Functionality-Fail message.
49 *  Cleanup:
50 *   Print errno log and/or timing stats if options given
51 *   Delete the temporary directory created.
52 *
53 * Usage:  <for command-line>
54 *  lchown01 [-c n] [-e] [-f] [-i n] [-I x] [-P x] [-t]
55 *     where,  -c n : Run n copies concurrently.
56 *             -e   : Turn on errno logging.
57 *             -f   : Turn off functionality Testing.
58 *	       -i n : Execute test n times.
59 *	       -I x : Execute test for x seconds.
60 *	       -P x : Pause for x seconds between iterations.
61 *	       -t   : Turn on syscall timing.
62 *
63 * HISTORY
64 *	07/2001 Ported by Wayne Boyer
65 *	11/2010 Code cleanup by Cyril Hrubis chrubis@suse.cz
66 *
67 * RESTRICTIONS:
68 *  This test should be run by 'super-user' (root) only.
69 *
70 */
71
72#include <stdio.h>
73#include <sys/types.h>
74#include <sys/stat.h>
75#include <sys/fcntl.h>
76#include <errno.h>
77#include <string.h>
78#include <signal.h>
79
80#include "test.h"
81#include "usctest.h"
82
83#define FILE_MODE	(S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
84#define TESTFILE	"testfile"
85#define SFILE		"slink_file"
86
87char *TCID = "lchown01";
88int TST_TOTAL = 5;
89extern int Tst_count;
90
91struct test_case_t {
92	char *desc;
93	uid_t user_id;
94	gid_t group_id;
95};
96
97static struct test_case_t test_cases[] = {
98	{"Change Owner/Group ids", 700, 701},
99	{"Change Owner id only",   702,  -1},
100	{"Change Owner/Group ids", 703, 701},
101	{"Change Group id only",    -1, 704},
102	{"Change Group/Group ids", 703, 705},
103	{"Change none",             -1,  -1},
104	{NULL,                       0,   0}
105};
106
107void setup(void);
108void cleanup(void);
109
110int main(int argc, char *argv[])
111{
112	struct stat stat_buf;
113	int lc;
114	char *msg;
115	int i;
116	uid_t user_id;
117	gid_t group_id;
118	char *test_desc;
119
120	if ((msg = parse_opts(ac, av, (option_t *) NULL, NULL)) != NULL)
121		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
122
123	setup();
124
125	for (lc = 0; TEST_LOOPING(lc); lc++) {
126		/* Reset Tst_count in case we are looping. */
127		Tst_count = 0;
128
129		for (i = 0; test_cases[i].desc != NULL; i++) {
130			uid_t user_id = test_cases[i].user_id;
131			gid_t group_id = test_cases[i].group_id;
132			char *test_desc = test_cases[i].desc;
133
134			/*
135			 * Call lchown(2) with different user id and
136			 * group id (numeric values) to set it on
137			 * symlink of testfile.
138			 */
139			TEST(lchown(SFILE, user_id, group_id));
140
141			if (TEST_RETURN == -1) {
142				tst_resm(TFAIL,
143					 "lchown() Fails to %s, errno %d",
144					 test_desc, TEST_ERRNO);
145				continue;
146			}
147			/*
148			 * Perform functional verification if test
149			 * executed without (-f) option.
150			 */
151			if (STD_FUNCTIONAL_TEST) {
152				/*
153				 * Get the testfile information using
154				 * lstat(2).
155				 */
156				if (lstat(SFILE, &stat_buf) < 0) {
157					tst_brkm(TFAIL, cleanup, "lstat(2) "
158					         "%s failed, errno %d",
159						 SFILE, TEST_ERRNO);
160				}
161				if (user_id == -1) {
162					if (i > 0)
163						user_id = test_cases[i-1].user_id;
164					else
165						user_id = geteuid();
166				}
167				if (group_id == -1) {
168					if (i > 0)
169						group_id = test_cases[i-1].group_id;
170					else
171						group_id = getegid();
172				}
173
174				/*
175				 * Check for expected Ownership ids
176				 * set on testfile.
177				 */
178				if ((stat_buf.st_uid != user_id) ||
179				    (stat_buf.st_gid != group_id)) {
180					tst_resm(TFAIL,
181						 "%s: incorrect ownership set, "
182						 "Expected %d %d", SFILE,
183						 user_id, group_id);
184				} else {
185					tst_resm(TPASS, "lchown() succeeds to "
186						 "%s of %s", test_desc, SFILE);
187				}
188			} else {
189				tst_resm(TPASS, "call succeeded");
190			}
191		}
192	}
193
194	cleanup();
195
196	tst_exit();
197}
198
199/*
200 * setup() - performs all ONE TIME setup for this test.
201 *	     Create a temporary directory and change directory to it.
202 *	     Create a test file under temporary directory and close it
203 *	     Create a symlink of testfile under temporary directory.
204 */
205void setup(void)
206{
207	int fd;
208
209	/* capture signals */
210	tst_sig(NOFORK, DEF_HANDLER, cleanup);
211
212	tst_require_root(NULL);
213
214	TEST_PAUSE;
215	tst_tmpdir();
216
217	if ((fd = open(TESTFILE, O_RDWR | O_CREAT, FILE_MODE)) == -1) {
218		tst_brkm(TBROK, cleanup, "open(%s, O_RDWR|O_CREAT, %o) failed",
219			 TESTFILE, FILE_MODE);
220	}
221	if (close(fd) == -1) {
222		tst_brkm(TBROK|TERRNO, cleanup, "close(%s) failed", TESTFILE);
223	}
224
225	if (close(fd) == -1)
226		tst_brkm(TBROK|TERRNO, cleanup, "close(2) %s", TESTFILE);
227
228	if (symlink(TESTFILE, SFILE) < 0) {
229		tst_brkm(TBROK|TERRNO, cleanup, "symlink(2) %s to %s failed",
230		         TESTFILE, SFILE);
231	}
232}
233
234/*
235 * cleanup() - performs all ONE TIME cleanup for this test at
236 *	       completion or premature exit.
237 *	       Remove the test directory and testfile created in the setup.
238 */
239void cleanup(void)
240{
241	TEST_CLEANUP;
242
243	tst_rmdir();
244}
245