Home | History | Annotate | Download | only in adjtimex
      1 /*
      2  * Copyright (c) Wipro Technologies Ltd, 2002.  All Rights Reserved.
      3  *
      4  * This program is free software; you can redistribute it and/or modify it
      5  * under the terms of version 2 of the GNU General Public License as
      6  * published by the Free Software Foundation.
      7  *
      8  * This program is distributed in the hope that it would be useful, but
      9  * WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     11  *
     12  * You should have received a copy of the GNU General Public License along
     13  * with this program; if not, write the Free Software Foundation, Inc.,
     14  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     15  *
     16  */
     17 /**********************************************************
     18  *
     19  *    TEST IDENTIFIER	: adjtimex02
     20  *
     21  *    EXECUTED BY	: root / superuser
     22  *
     23  *    TEST TITLE	: Tests for error conditions
     24  *
     25  *    TEST CASE TOTAL	: 6
     26  *
     27  *    AUTHOR		: Saji Kumar.V.R <saji.kumar (at) wipro.com>
     28  *
     29  *    SIGNALS
     30  * 	Uses SIGUSR1 to pause before test if option set.
     31  * 	(See the parse_opts(3) man page).
     32  *
     33  *    DESCRIPTION
     34  *	Verify that
     35  *	1) adjtimex(2) fails with errno set to EFAULT if buf does
     36  *	   not point to writable memory
     37  *	2) adjtimex(2) fails with errno set to EINVAL if an attempt
     38  *	   is  made  to set buf.tick to a value < 900000/HZ
     39  *	3) adjtimex(2) fails with errno set to EINVAL if an attempt
     40  *	   is  made  to set buf.tick to a value > 1100000/HZ
     41  *	4) adjtimex(2) fails with errno set to EINVAL if an attempt
     42  *	   is  made  to set buf.offset to a value > 512000L
     43  *	   (This test case will be executed only if the kernel version
     44  *	    is 2.6.25 or below)
     45  *	5) adjtimex(2) fails with errno set to EINVAL if an attempt
     46  *	   is  made  to set buf.offset to a value < 512000L
     47  *	   (This test case will be executed only if the kernel version
     48  *	    is 2.6.25 or below)
     49  *	6) adjtimex(2) fails with errno set to EPERM if buf.mode is
     50  *	   non-zero and the user is not super-user.
     51  *
     52  * 	Setup:
     53  * 	  Setup signal handling.
     54  *	  Pause for SIGUSR1 if option specified.
     55  *	  Save current parameters in tim_save
     56  *
     57  * 	Test:
     58  *	 Loop if the proper options are given.
     59  *	  Call test case specific setup if needed
     60  * 	  call adjtimex with saved timex structure
     61  *	  Check return value is between 0 & 5
     62  *		Test passed
     63  *	  Otherwise
     64  *		Test failed
     65  *	  Call test case specific cleanup if needed
     66  *
     67  * 	Cleanup:
     68  * 	  Print errno log and/or timing stats if options given
     69  *
     70  * USAGE:  <for command-line>
     71  * adjtimex02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] [-h] [-f] [-p]
     72  *			where,  -c n : Run n copies concurrently.
     73  *				-e   : Turn on errno logging.
     74  *				-h   : Show help screen
     75  *				-f   : Turn off functional testing
     76  *				-i n : Execute test n times.
     77  *				-I x : Execute test for x seconds.
     78  *				-p   : Pause for SIGUSR1 before starting
     79  *				-P x : Pause for x seconds between iterations.
     80  *				-t   : Turn on syscall timing.
     81  *
     82  ****************************************************************/
     83 
     84 #if defined UCLINUX && !__THROW
     85 /* workaround for libc bug causing failure in sys/timex.h */
     86 #define __THROW
     87 #endif
     88 
     89 #include <errno.h>
     90 #include <sys/timex.h>
     91 #include <unistd.h>
     92 #include <pwd.h>
     93 #include "test.h"
     94 
     95 #define SET_MODE ( ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \
     96 	ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK )
     97 
     98 static void setup(void);
     99 static int setup2(void);
    100 static int setup3(void);
    101 static int setup4(void);
    102 static int setup5(void);
    103 static int setup6(void);
    104 static void cleanup(void);
    105 static void cleanup6(void);
    106 
    107 char *TCID = "adjtimex02";
    108 
    109 static int hz;			/* HZ from sysconf */
    110 
    111 static struct timex tim_save;
    112 static struct timex buff;
    113 
    114 static char nobody_uid[] = "nobody";
    115 struct passwd *ltpuser;
    116 
    117 struct test_cases_t {
    118 	struct timex *buffp;
    119 	int (*setup) ();
    120 	void (*cleanup) ();
    121 	int exp_errno;
    122 } test_cases[] = {
    123 #ifndef UCLINUX
    124 	/* Skip since uClinux does not implement memory protection */
    125 	{
    126 	(struct timex *)-1, NULL, NULL, EFAULT},
    127 #endif
    128 	{
    129 	&buff, setup2, NULL, EINVAL}, {
    130 	&buff, setup3, NULL, EINVAL}, {
    131 	&buff, setup4, NULL, EINVAL}, {
    132 	&buff, setup5, NULL, EINVAL}, {
    133 	&buff, setup6, cleanup6, EPERM}
    134 };
    135 
    136 int TST_TOTAL = sizeof(test_cases) / sizeof(test_cases[0]);
    137 
    138 int main(int ac, char **av)
    139 {
    140 
    141 	int lc, i;
    142 
    143 	tst_parse_opts(ac, av, NULL, NULL);
    144 
    145 	setup();
    146 
    147 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    148 
    149 		tst_count = 0;
    150 
    151 		for (i = 0; i < TST_TOTAL; ++i) {
    152 			/*
    153 			 * since Linux 2.6.26, if buf.offset value is outside
    154 			 * the acceptable range, it is simply normalized instead
    155 			 * of letting the syscall fail. so just skip this test
    156 			 * case.
    157 			 */
    158 			if ((i == 3 || i == 4) && tst_kvercmp(2, 6, 25) > 0) {
    159 				tst_resm(TCONF, "this kernel normalizes buf."
    160 					 "offset value if it is outside"
    161 					 " the acceptable range.");
    162 				continue;
    163 			}
    164 
    165 			buff = tim_save;
    166 			buff.modes = SET_MODE;
    167 			if ((test_cases[i].setup) && (test_cases[i].setup())) {
    168 				tst_resm(TWARN, "setup() failed, skipping"
    169 					 " this test case");
    170 				continue;
    171 			}
    172 
    173 			/* Call adjtimex(2) */
    174 			TEST(adjtimex(test_cases[i].buffp));
    175 
    176 			if ((TEST_RETURN == -1) && (TEST_ERRNO ==
    177 						    test_cases[i].exp_errno)) {
    178 				tst_resm(TPASS | TTERRNO,
    179 					 "Test Passed, adjtimex() returned -1");
    180 			} else {
    181 				tst_resm(TFAIL | TTERRNO,
    182 					 "Test Failed, adjtimex() returned %ld",
    183 					 TEST_RETURN);
    184 			}
    185 			if (test_cases[i].cleanup) {
    186 				test_cases[i].cleanup();
    187 			}
    188 		}
    189 	}
    190 
    191 	/* cleanup and exit */
    192 	cleanup();
    193 
    194 	tst_exit();
    195 
    196 }
    197 
    198 /* setup() - performs all ONE TIME setup for this test */
    199 void setup(void)
    200 {
    201 	tst_require_root();
    202 
    203 	tim_save.modes = 0;
    204 
    205 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
    206 
    207 	/* set the HZ from sysconf */
    208 	hz = sysconf(_SC_CLK_TCK);
    209 	if (hz == -1) {
    210 		tst_brkm(TBROK, NULL, "Failed to read the HZ from sysconf\n");
    211 	}
    212 
    213 	TEST_PAUSE;
    214 
    215 	/* Save current parameters in tim_save */
    216 	if ((adjtimex(&tim_save)) == -1) {
    217 		tst_brkm(TBROK, NULL, "Failed to save current parameters");
    218 	}
    219 }
    220 
    221 /*
    222  *cleanup() -  performs all ONE TIME cleanup for this test at
    223  *		completion or premature exit.
    224  */
    225 void cleanup(void)
    226 {
    227 
    228 	tim_save.modes = SET_MODE;
    229 	/* Restore saved parameters */
    230 	if ((adjtimex(&tim_save)) == -1) {
    231 		tst_resm(TWARN, "Failed to restore saved parameters");
    232 	}
    233 }
    234 
    235 int setup2(void)
    236 {
    237 	buff.tick = 900000 / hz - 1;
    238 	return 0;
    239 }
    240 
    241 int setup3(void)
    242 {
    243 	buff.tick = 1100000 / hz + 1;
    244 	return 0;
    245 }
    246 
    247 int setup4(void)
    248 {
    249 	buff.offset = 512000L + 1;
    250 	return 0;
    251 }
    252 
    253 int setup5(void)
    254 {
    255 	buff.offset = (-1) * (512000L) - 1;
    256 	return 0;
    257 }
    258 
    259 int setup6(void)
    260 {
    261 	/* Switch to nobody user for correct error code collection */
    262 	if ((ltpuser = getpwnam(nobody_uid)) == NULL) {
    263 		tst_brkm(TBROK, NULL, "\"nobody\" user not present");
    264 	}
    265 	if (seteuid(ltpuser->pw_uid) == -1) {
    266 		tst_resm(TWARN | TERRNO, "seteuid(%d) failed", ltpuser->pw_uid);
    267 		return 1;
    268 	}
    269 	return 0;
    270 }
    271 
    272 void cleanup6(void)
    273 {
    274 	/* Set effective user id back to root */
    275 	if (seteuid(0) == -1) {
    276 		tst_brkm(TBROK | TERRNO, cleanup, "seteuid failed to set the"
    277 			 " effective uid to root");
    278 	}
    279 }
    280