Home | History | Annotate | Download | only in getcwd
      1 /*
      2  *   Copyright (c) 2014 Fujitsu Ltd.
      3  *   Author: Xiaoguang Wang <wangxg.fnst (at) cn.fujitsu.com>
      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 
     16 /*
     17  * Note: this test has already been in xfstests generic/028 test case,
     18  * I just port it to LTP.
     19  *
     20  * Kernel commit '232d2d60aa5469bb097f55728f65146bd49c1d25' introduced a race
     21  * condition that causes getcwd(2) to return "/" instead of correct path.
     22  *     232d2d6 dcache: Translating dentry into pathname without
     23  *             taking rename_lock
     24  *
     25  * And these two kernel commits fixed the bug:
     26  *   ede4cebce16f5643c61aedd6d88d9070a1d23a68
     27  *	prepend_path() needs to reinitialize dentry/vfsmount/mnt on restarts
     28  *   f6500801522c61782d4990fa1ad96154cb397cd4
     29  *	f650080 __dentry_path() fixes
     30  *
     31  * This test is to check whether this bug exists in the running kernel,
     32  * or whether this bug has been fixed.
     33  *
     34  */
     35 
     36 #include <stdio.h>
     37 #include <errno.h>
     38 #include <fcntl.h>
     39 #include <sys/types.h>
     40 #include <unistd.h>
     41 #include "test.h"
     42 #include "safe_macros.h"
     43 
     44 #define TIMEOUT	5
     45 
     46 static void setup(void);
     47 static void cleanup(void);
     48 static void do_child(void);
     49 static void sigproc(int sig);
     50 static volatile sig_atomic_t end;
     51 static char init_cwd[PATH_MAX];
     52 
     53 char *TCID = "getcwd04";
     54 int TST_TOTAL = 1;
     55 
     56 int main(int ac, char **av)
     57 {
     58 	int status;
     59 	char cur_cwd[PATH_MAX];
     60 	pid_t child;
     61 
     62 	tst_parse_opts(ac, av, NULL, NULL);
     63 
     64 	setup();
     65 
     66 	child = tst_fork();
     67 	if (child < 0)
     68 		tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
     69 
     70 	if (child == 0)
     71 		do_child();
     72 
     73 	 while (1) {
     74 		SAFE_GETCWD(cleanup, cur_cwd, PATH_MAX);
     75 		if (strncmp(init_cwd, cur_cwd, PATH_MAX)) {
     76 			tst_resm(TFAIL, "initial current work directory is "
     77 				 "%s, now is %s. Bug is reproduced!",
     78 				 init_cwd, cur_cwd);
     79 			break;
     80 		}
     81 
     82 		if (end) {
     83 			tst_resm(TPASS, "Bug is not reproduced!");
     84 			break;
     85 		}
     86 	}
     87 
     88 	SAFE_KILL(cleanup, child, SIGKILL);
     89 	SAFE_WAITPID(cleanup, child, &status, 0);
     90 
     91 	cleanup();
     92 	tst_exit();
     93 }
     94 
     95 static void setup(void)
     96 {
     97 	tst_sig(FORK, DEF_HANDLER, cleanup);
     98 
     99 	TEST_PAUSE;
    100 
    101 	if (tst_ncpus() == 1)
    102 		tst_brkm(TCONF, NULL, "This test needs two cpus at least");
    103 
    104 	tst_tmpdir();
    105 
    106 	if (signal(SIGALRM, sigproc) == SIG_ERR)
    107 		tst_brkm(TBROK | TERRNO, cleanup, "signal(SIGALRM) failed");
    108 
    109 	alarm(TIMEOUT);
    110 
    111 	SAFE_GETCWD(cleanup, init_cwd, PATH_MAX);
    112 }
    113 
    114 static void sigproc(int sig)
    115 {
    116 	end = sig;
    117 }
    118 
    119 static void do_child(void)
    120 {
    121 	unsigned int i = 0;
    122 	char c_name[PATH_MAX] = "testfile", n_name[PATH_MAX];
    123 
    124 	SAFE_TOUCH(NULL, c_name, 0644, NULL);
    125 
    126 	while (1) {
    127 		snprintf(n_name, PATH_MAX, "testfile%u", i++);
    128 		SAFE_RENAME(NULL, c_name, n_name);
    129 		strncpy(c_name, n_name, PATH_MAX);
    130 	}
    131 }
    132 
    133 static void cleanup(void)
    134 {
    135 	tst_rmdir();
    136 }
    137