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 "safe_macros.h"
     96 #include "config.h"
     97 
     98 char *TCID = "unshare01";
     99 int testno;
    100 int TST_TOTAL = 1;
    101 
    102 #ifdef HAVE_UNSHARE
    103 
    104 /* Extern Global Functions */
    105 /******************************************************************************/
    106 /*									    */
    107 /* Function:    cleanup						       */
    108 /*									    */
    109 /* Description: Performs all one time clean up for this test on successful    */
    110 /*	      completion,  premature exit or  failure. Closes all temporary */
    111 /*	      files, removes all temporary directories exits the test with  */
    112 /*	      appropriate return code by calling tst_exit() function.       */
    113 /*									    */
    114 /* Input:       None.							 */
    115 /*									    */
    116 /* Output:      None.							 */
    117 /*									    */
    118 /* Return:      On failure - Exits calling tst_exit(). Non '0' return code.   */
    119 /*	      On success - Exits calling tst_exit(). With '0' return code.  */
    120 /*									    */
    121 /******************************************************************************/
    122 void cleanup(void)
    123 {
    124 
    125 	tst_rmdir();
    126 }
    127 
    128 /* Local  Functions */
    129 /******************************************************************************/
    130 /*									    */
    131 /* Function:    setup							 */
    132 /*									    */
    133 /* Description: Performs all one time setup for this test. This function is   */
    134 /*	      typically used to capture signals, create temporary dirs      */
    135 /*	      and temporary files that may be used in the course of this    */
    136 /*	      test.							 */
    137 /*									    */
    138 /* Input:       None.							 */
    139 /*									    */
    140 /* Output:      None.							 */
    141 /*									    */
    142 /* Return:      On failure - Exits by calling cleanup().		      */
    143 /*	      On success - returns 0.				       */
    144 /*									    */
    145 /******************************************************************************/
    146 void setup(void)
    147 {
    148 	tst_require_root();
    149 
    150 	/* Capture signals if any */
    151 	/* Create temporary directories */
    152 	TEST_PAUSE;
    153 	tst_tmpdir();
    154 }
    155 
    156 int main(int ac, char **av)
    157 {
    158 	pid_t pid1;
    159 	int lc;
    160 	int rval;
    161 
    162 	tst_parse_opts(ac, av, NULL, NULL);
    163 
    164 	setup();
    165 
    166 	for (lc = 0; TEST_LOOPING(lc); ++lc) {
    167 		tst_count = 0;
    168 		for (testno = 0; testno < TST_TOTAL; ++testno) {
    169 
    170 			pid1 = fork();	//call to fork()
    171 			if (pid1 == -1) {
    172 				tst_brkm(TFAIL | TERRNO, cleanup,
    173 					 "fork failed");
    174 			} else if (pid1 == 0) {
    175 				switch (unshare(CLONE_FILES)) {
    176 				case 0:
    177 					printf("unshare with CLONE_FILES call "
    178 					       "succeeded\n");
    179 					rval = 0;
    180 					break;
    181 				case -1:
    182 					if (errno == ENOSYS)
    183 						rval = 1;
    184 					else {
    185 						perror("unshare failed");
    186 						rval = 2;
    187 					}
    188 				}
    189 				exit(rval);
    190 			} else {
    191 				SAFE_WAIT(cleanup, &rval);
    192 				if (rval != 0 && WIFEXITED(rval)) {
    193 					switch (WEXITSTATUS(rval)) {
    194 					case 1:
    195 						tst_brkm(TCONF, cleanup,
    196 							 "unshare not supported in "
    197 							 "kernel");
    198 						break;
    199 					default:
    200 						tst_brkm(TFAIL, cleanup,
    201 							 "unshare failed");
    202 					}
    203 				}
    204 			}
    205 
    206 			pid1 = fork();
    207 			if (pid1 == -1) {
    208 				tst_brkm(TFAIL | TERRNO, cleanup,
    209 					 "fork failed");
    210 			} else if (pid1 == 0) {
    211 				switch (unshare(CLONE_FS)) {
    212 				case 0:
    213 					printf("unshare with CLONE_FS call "
    214 					       "succeeded\n");
    215 					rval = 0;
    216 					break;
    217 				case -1:
    218 					if (errno == ENOSYS)
    219 						rval = 1;
    220 					else {
    221 						perror("unshare failed");
    222 						rval = 2;
    223 					}
    224 				}
    225 				exit(rval);
    226 			} else {
    227 				SAFE_WAIT(cleanup, &rval);
    228 				if (rval != 0 && WIFEXITED(rval)) {
    229 					switch (WEXITSTATUS(rval)) {
    230 					case 1:
    231 						tst_brkm(TCONF, cleanup,
    232 							 "unshare not supported in "
    233 							 "kernel");
    234 						break;
    235 					default:
    236 						tst_brkm(TFAIL, cleanup,
    237 							 "unshare failed");
    238 					}
    239 				}
    240 			}
    241 
    242 			pid1 = fork();
    243 			if (pid1 == -1) {
    244 				tst_brkm(TFAIL | TERRNO, cleanup,
    245 					 "fork() failed.");
    246 			} else if (pid1 == 0) {
    247 				switch (unshare(CLONE_NEWNS)) {
    248 				case 0:
    249 					printf("unshare call with CLONE_NEWNS "
    250 					       "succeeded\n");
    251 					rval = 0;
    252 					break;
    253 				case -1:
    254 					if (errno == ENOSYS)
    255 						rval = 1;
    256 					else {
    257 						perror("unshare failed");
    258 						rval = 2;
    259 					}
    260 				}
    261 				exit(rval);
    262 			} else {
    263 				SAFE_WAIT(cleanup, &rval);
    264 				if (rval != 0 && WIFEXITED(rval)) {
    265 					switch (WEXITSTATUS(rval)) {
    266 					case 1:
    267 						tst_brkm(TCONF, cleanup,
    268 							 "unshare not supported in "
    269 							 "kernel");
    270 						break;
    271 					default:
    272 						tst_brkm(TFAIL, cleanup,
    273 							 "unshare failed");
    274 					}
    275 
    276 				}
    277 
    278 			}
    279 
    280 		}
    281 
    282 	}
    283 	cleanup();
    284 	tst_exit();
    285 }
    286 #else
    287 int main(void)
    288 {
    289 	tst_brkm(TCONF, NULL, "unshare is undefined.");
    290 }
    291 #endif
    292