Home | History | Annotate | Download | only in unshare
      1 /*************************************************************************/
      2 /* Copyright (c) Crackerjack Project., 2007				 */
      3 /*									 */
      4 /* This program is free software;  you can redistribute it and/or modify */
      5 /* it under the terms of the GNU General Public License as published by  */
      6 /* the Free Software Foundation; either version 2 of the License, or	 */
      7 /* (at your option) any later version.					 */
      8 /*									 */
      9 /* This program is distributed in the hope that it will be useful,	 */
     10 /* but WITHOUT ANY WARRANTY;  without even the implied warranty of	 */
     11 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See		 */
     12 /* the GNU General Public License for more details.			 */
     13 /*									 */
     14 /* You should have received a copy of the GNU General Public License	 */
     15 /* along with this program;  if not, write to the Free Software	       	 */
     16 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*/
     17 /*									 */
     18 /*************************************************************************/
     19 /*************************************************************************/
     20 /*									 */
     21 /* File:	unshare01.c					   	 */
     22 /*									 */
     23 /* Description: This tests the unshare() syscall.		      	 */
     24 /*	     unshare() allows a process to disassociate parts of its	 */
     25 /*		execution context that are currently being shared with other 	*/
     26 /*		processes. Part of the execution context, such as the namespace	*/
     27 /*		,is shared implicitly when a new process is created using 	*/
     28 /*		fork(2) or vfork(2), while other parts, such as virtual memory	*/
     29 /*		, may be shared by explicit request when creating a process 	*/
     30 /*		using clone(2).							*/
     31 /*										*/
     32 /*		The main use of unshare() is to allow a process to control its	*/
     33 /*		shared execution context without creating a new process.	*/
     34 /*		 								*/
     35 /*										*/
     36 /*		The flags argument is a bit mask that specifies which parts of	*/
     37 /*		the execution context should be unshared. This argument is 	*/
     38 /*		specified by ORing together zero or more of the following cons-	*/
     39 /*		tants:								*/
     40 /*										*/
     41 /*		CLONE_FILES:							*/
     42 /*		    	Reverse the effect of the clone(2) CLONE_FILES flag. 	*/
     43 /*			Unshare	the file descriptor table, so that the calling 	*/
     44 /*			process no longer shares its file descriptors with any 	*/
     45 /*			other process.						*/
     46 /*		CLONE_FS:							*/
     47 /*			Reverse the effect of the clone(2) CLONE_FS flag.Unshare*/
     48 /*			file system attributes, so that the calling process no 	*/
     49 /*			longer shares its root directory, current directory, or	*/
     50 /*			umask attributes with any other process.		*/
     51 /*		CLONE_NEWNS:							*/
     52 /*		       This flag has the same effect as the clone(2) CLONE_NEWNS*/
     53 /*			flag. Unshare the namespace, so that the calling process*/
     54 /*			has a private copy of its namespacei which is not shared*/
     55 /*			with any other process. Specifying this flag automat-	*/
     56 /*			ically implies CLONE_FS as well. 			*/
     57 /*										*/
     58 /*		If flags is specified as zero, then unshare() is a no-op; no 	*/
     59 /*		changes are made to the calling process's execution context. 	*/
     60 /*									       	*/
     61 /* Usage:  <for command-line>						 	*/
     62 /* unshare01 [-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 /* Total Tests: 1							     	*/
     71 /*									    	*/
     72 /* Test Name:   unshare01					     		*/
     73 /* History:     Porting from Crackerjack to LTP is done by		    	*/
     74 /*	      Manas Kumar Nayak maknayak (at) in.ibm.com>				*/
     75 /********************************************************************************/
     76 
     77 #define _GNU_SOURCE
     78 
     79 #include <stdio.h>
     80 #include <sys/wait.h>
     81 #include <sys/types.h>
     82 #include <sched.h>
     83 #include <limits.h>
     84 #include <unistd.h>
     85 #include <sys/types.h>
     86 #include <sys/syscall.h>
     87 #include <errno.h>
     88 #include <pwd.h>
     89 #include <grp.h>
     90 #include <string.h>
     91 #include <sys/param.h>
     92 #include <stdio.h>
     93 
     94 #include "test.h"
     95 #include "config.h"
     96 
     97 char *TCID = "unshare01";
     98 int testno;
     99 int TST_TOTAL = 1;
    100 
    101 #ifdef HAVE_UNSHARE
    102 
    103 /* Extern Global Functions */
    104 /******************************************************************************/
    105 /*									    */
    106 /* Function:    cleanup						       */
    107 /*									    */
    108 /* Description: Performs all one time clean up for this test on successful    */
    109 /*	      completion,  premature exit or  failure. Closes all temporary */
    110 /*	      files, removes all temporary directories exits the test with  */
    111 /*	      appropriate return code by calling tst_exit() function.       */
    112 /*									    */
    113 /* Input:       None.							 */
    114 /*									    */
    115 /* Output:      None.							 */
    116 /*									    */
    117 /* Return:      On failure - Exits calling tst_exit(). Non '0' return code.   */
    118 /*	      On success - Exits calling tst_exit(). With '0' return code.  */
    119 /*									    */
    120 /******************************************************************************/
    121 void cleanup(void)
    122 {
    123 
    124 	tst_rmdir();
    125 }
    126 
    127 /* Local  Functions */
    128 /******************************************************************************/
    129 /*									    */
    130 /* Function:    setup							 */
    131 /*									    */
    132 /* Description: Performs all one time setup for this test. This function is   */
    133 /*	      typically used to capture signals, create temporary dirs      */
    134 /*	      and temporary files that may be used in the course of this    */
    135 /*	      test.							 */
    136 /*									    */
    137 /* Input:       None.							 */
    138 /*									    */
    139 /* Output:      None.							 */
    140 /*									    */
    141 /* Return:      On failure - Exits by calling cleanup().		      */
    142 /*	      On success - returns 0.				       */
    143 /*									    */
    144 /******************************************************************************/
    145 void setup(void)
    146 {
    147 	tst_require_root();
    148 
    149 	/* Capture signals if any */
    150 	/* Create temporary directories */
    151 	TEST_PAUSE;
    152 	tst_tmpdir();
    153 }
    154 
    155 int main(int ac, char **av)
    156 {
    157 	pid_t pid1;
    158 	int lc;
    159 	int rval;
    160 
    161 	tst_parse_opts(ac, av, NULL, NULL);
    162 
    163 	setup();
    164 
    165 	for (lc = 0; TEST_LOOPING(lc); ++lc) {
    166 		tst_count = 0;
    167 		for (testno = 0; testno < TST_TOTAL; ++testno) {
    168 
    169 			pid1 = fork();	//call to fork()
    170 			if (pid1 == -1) {
    171 				tst_brkm(TFAIL | TERRNO, cleanup,
    172 					 "fork failed");
    173 			} else if (pid1 == 0) {
    174 				switch (unshare(CLONE_FILES)) {
    175 				case 0:
    176 					printf("unshare with CLONE_FILES call "
    177 					       "succeeded\n");
    178 					rval = 0;
    179 					break;
    180 				case -1:
    181 					if (errno == ENOSYS)
    182 						rval = 1;
    183 					else {
    184 						perror("unshare failed");
    185 						rval = 2;
    186 					}
    187 				}
    188 				exit(rval);
    189 			} else {
    190 				if (wait(&rval) == -1)
    191 					tst_brkm(TBROK | TERRNO, cleanup,
    192 						 "wait failed");
    193 				if (rval != 0 && WIFEXITED(rval)) {
    194 					switch (WEXITSTATUS(rval)) {
    195 					case 1:
    196 						tst_brkm(TCONF, cleanup,
    197 							 "unshare not supported in "
    198 							 "kernel");
    199 						break;
    200 					default:
    201 						tst_brkm(TFAIL, cleanup,
    202 							 "unshare failed");
    203 					}
    204 				}
    205 			}
    206 
    207 			pid1 = fork();
    208 			if (pid1 == -1) {
    209 				tst_brkm(TFAIL | TERRNO, cleanup,
    210 					 "fork failed");
    211 			} else if (pid1 == 0) {
    212 				switch (unshare(CLONE_FS)) {
    213 				case 0:
    214 					printf("unshare with CLONE_FS call "
    215 					       "succeeded\n");
    216 					rval = 0;
    217 					break;
    218 				case -1:
    219 					if (errno == ENOSYS)
    220 						rval = 1;
    221 					else {
    222 						perror("unshare failed");
    223 						rval = 2;
    224 					}
    225 				}
    226 				exit(rval);
    227 			} else {
    228 				if (wait(&rval) == -1)
    229 					tst_brkm(TBROK | TERRNO, cleanup,
    230 						 "wait failed");
    231 				if (rval != 0 && WIFEXITED(rval)) {
    232 					switch (WEXITSTATUS(rval)) {
    233 					case 1:
    234 						tst_brkm(TCONF, cleanup,
    235 							 "unshare not supported in "
    236 							 "kernel");
    237 						break;
    238 					default:
    239 						tst_brkm(TFAIL, cleanup,
    240 							 "unshare failed");
    241 					}
    242 				}
    243 			}
    244 
    245 			pid1 = fork();
    246 			if (pid1 == -1) {
    247 				tst_brkm(TFAIL | TERRNO, cleanup,
    248 					 "fork() failed.");
    249 			} else if (pid1 == 0) {
    250 				switch (unshare(CLONE_NEWNS)) {
    251 				case 0:
    252 					printf("unshare call with CLONE_NEWNS "
    253 					       "succeeded\n");
    254 					rval = 0;
    255 					break;
    256 				case -1:
    257 					if (errno == ENOSYS)
    258 						rval = 1;
    259 					else {
    260 						perror("unshare failed");
    261 						rval = 2;
    262 					}
    263 				}
    264 				exit(rval);
    265 			} else {
    266 				if (wait(&rval) == -1)
    267 					tst_brkm(TBROK | TERRNO, cleanup,
    268 						 "wait failed");
    269 				if (rval != 0 && WIFEXITED(rval)) {
    270 					switch (WEXITSTATUS(rval)) {
    271 					case 1:
    272 						tst_brkm(TCONF, cleanup,
    273 							 "unshare not supported in "
    274 							 "kernel");
    275 						break;
    276 					default:
    277 						tst_brkm(TFAIL, cleanup,
    278 							 "unshare failed");
    279 					}
    280 
    281 				}
    282 
    283 			}
    284 
    285 		}
    286 
    287 	}
    288 	cleanup();
    289 	tst_exit();
    290 }
    291 #else
    292 int main(void)
    293 {
    294 	tst_brkm(TCONF, NULL, "unshare is undefined.");
    295 }
    296 #endif
    297