1/*
2 * Copyright (c) Wipro Technologies Ltd, 2003.  All Rights Reserved.
3 * Copyright (c) 2011 Cyril Hrubis <chrubis@suse.cz>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17 */
18
19#include <errno.h>
20#include <time.h>
21#include <pwd.h>
22#include <unistd.h>
23
24#include "test.h"
25#include "common_timers.h"
26
27static void setup(void);
28static void cleanup(void);
29static int setup_test(int option);
30
31clockid_t clocks[] = {
32	CLOCK_REALTIME,
33	CLOCK_MONOTONIC,
34	MAX_CLOCKS,
35	MAX_CLOCKS + 1,
36	CLOCK_REALTIME,
37	CLOCK_REALTIME,
38	CLOCK_REALTIME,
39	CLOCK_PROCESS_CPUTIME_ID,
40	CLOCK_THREAD_CPUTIME_ID
41};
42
43int testcases[] = {
44	EFAULT,			/* tp bad               */
45	EINVAL,			/* CLOCK_MONOTONIC      */
46	EINVAL,			/* MAX_CLOCKS           */
47	EINVAL,			/* MAX_CLOCKS + 1       */
48	EINVAL,			/* Invalid timespec     */
49	EINVAL,			/* NSEC_PER_SEC + 1     */
50	EPERM,			/* non-root user        */
51	EINVAL,			/* PROCESS_CPUTIME_ID	*/
52	EINVAL,			/* THREAD_CPUTIME_ID	*/
53};
54
55char *TCID = "clock_settime03";
56int TST_TOTAL = ARRAY_SIZE(testcases);
57
58char nobody_uid[] = "nobody";
59struct passwd *ltpuser;
60static struct timespec spec, *temp, saved;
61
62int main(int ac, char **av)
63{
64	int lc, i;
65
66	tst_parse_opts(ac, av, NULL, NULL);
67
68	setup();
69
70	for (lc = 0; TEST_LOOPING(lc); lc++) {
71
72		tst_count = 0;
73
74		for (i = 0; i < TST_TOTAL; i++) {
75
76			if (setup_test(i) < 0)
77				continue;
78
79			TEST(ltp_syscall(__NR_clock_settime, clocks[i], temp));
80
81			/* Change the UID back to root */
82			if (i == TST_TOTAL - 1) {
83				if (seteuid(0) == -1) {
84					tst_brkm(TBROK | TERRNO, cleanup,
85						 "Failed to set the effective "
86						 "uid to root");
87				}
88			}
89
90			/* check return code */
91			if (TEST_RETURN == -1 && TEST_ERRNO == testcases[i]) {
92				tst_resm(TPASS | TTERRNO,
93					 "clock_settime(2) got expected "
94					 "failure.");
95			} else {
96				tst_resm(TFAIL | TTERRNO,
97					 "clock_settime(2) failed to produce "
98					 "expected error (return code = %ld)",
99					 TEST_RETURN);
100				/* Restore the clock to its previous state. */
101				if (TEST_RETURN == 0) {
102					if (ltp_syscall(__NR_clock_settime,
103						    CLOCK_REALTIME,
104						    &saved) < 0) {
105						tst_resm(TWARN | TERRNO,
106							 "FATAL: could not set "
107							 "the clock!");
108					}
109				}
110			}
111
112		}
113
114	}
115
116	cleanup();
117	tst_exit();
118}
119
120static int setup_test(int option)
121{
122	/* valid timespec */
123	spec = saved;
124	temp = &spec;
125
126	/* error sceanrios */
127	switch (option) {
128	case 0:
129		/* Make tp argument bad pointer */
130		temp = (struct timespec *)-1;
131		break;
132	case 4:
133		/* Make the parameter of timespec invalid */
134		spec.tv_nsec = -1;
135		break;
136	case 5:
137		/* Make the parameter of timespec invalid */
138		spec.tv_nsec = NSEC_PER_SEC + 1;
139		break;
140	case 6:
141		/* change the User to non-root */
142		spec.tv_nsec = 0;
143		if ((ltpuser = getpwnam(nobody_uid)) == NULL) {
144			tst_resm(TWARN, "user \"nobody\" not present; "
145				 "skipping test");
146			return -1;
147		}
148		if (seteuid(ltpuser->pw_uid) == -1) {
149			tst_resm(TWARN | TERRNO,
150				 "seteuid failed to set the effective "
151				 "uid to %d (nobody)", ltpuser->pw_uid);
152			return -1;
153		}
154		break;
155	}
156	return 0;
157}
158
159static void setup(void)
160{
161	tst_sig(NOFORK, DEF_HANDLER, cleanup);
162
163	tst_require_root();
164
165	if (ltp_syscall(__NR_clock_gettime, CLOCK_REALTIME, &saved) < 0)
166		tst_brkm(TBROK, NULL, "Clock gettime failed");
167
168	spec.tv_sec = 1;
169	spec.tv_nsec = 0;
170
171	TEST_PAUSE;
172}
173
174static void cleanup(void)
175{
176}
177