1 /*
2  * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 7162400
27  * @key regression
28  * @summary Regression test for attach issue where stale pid files in /tmp lead to connection issues
29  * @modules java.base/jdk.internal.misc:open
30  * @modules java.base/java.lang:open
31  * @modules jdk.attach/sun.tools.attach
32  * @library /test/lib
33  * @run main AttachWithStalePidFile
34  */
35 
36 import jdk.test.lib.Platform;
37 import jdk.test.lib.process.ProcessTools;
38 import com.sun.tools.attach.VirtualMachine;
39 import sun.tools.attach.HotSpotVirtualMachine;
40 import java.lang.reflect.Field;
41 import java.nio.file.*;
42 import java.nio.file.attribute.*;
43 import java.io.*;
44 
45 public class AttachWithStalePidFile {
main(String... args)46   public static void main(String... args) throws Exception {
47 
48     // this test is only valid on non-Windows platforms
49     if(Platform.isWindows()) {
50       System.out.println("This test is only valid on non-Windows platforms.");
51       return;
52     }
53 
54     // Since there might be stale pid-files owned by different
55     // users on the system we may need to retry the test in case we
56     // are unable to remove the existing file.
57     int retries = 5;
58     while(!runTest() && --retries > 0);
59 
60     if(retries == 0) {
61       throw new RuntimeException("Test failed after 5 retries. " +
62         "Remove any /tmp/.java_pid* files and retry.");
63     }
64   }
65 
runTest()66   public static boolean runTest() throws Exception {
67     ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
68       "-XX:+UnlockDiagnosticVMOptions", "-XX:+PauseAtStartup", "AttachWithStalePidFileTarget");
69     Process target = pb.start();
70     Path pidFile = null;
71 
72     try {
73       int pid = getUnixProcessId(target);
74 
75       // create the stale .java_pid file. use hard-coded /tmp path as in th VM
76       pidFile = createJavaPidFile(pid);
77       if(pidFile == null) {
78         return false;
79       }
80 
81       // wait for vm.paused file to be created and delete it once we find it.
82       waitForAndResumeVM(pid);
83 
84       waitForTargetReady(target);
85 
86       HotSpotVirtualMachine vm = (HotSpotVirtualMachine)VirtualMachine.attach(((Integer)pid).toString());
87       BufferedReader remoteDataReader = new BufferedReader(new InputStreamReader(vm.remoteDataDump()));
88       String line = null;
89       while((line = remoteDataReader.readLine()) != null);
90 
91       vm.detach();
92       return true;
93     }
94     finally {
95       target.destroy();
96       target.waitFor();
97 
98       if(pidFile != null && Files.exists(pidFile)) {
99         Files.delete(pidFile);
100       }
101     }
102   }
103 
waitForTargetReady(Process target)104   private static void waitForTargetReady(Process target) throws IOException {
105     BufferedReader br = new BufferedReader(new InputStreamReader(target.getInputStream()));
106     String line = br.readLine();
107     // wait for the ready message having been printed or EOF (line == null)
108     while (line != null && !line.equals(AttachWithStalePidFileTarget.READY_MSG)) {
109         line = br.readLine();
110     }
111     // target VM ready
112   }
113 
createJavaPidFile(int pid)114   private static Path createJavaPidFile(int pid) throws Exception {
115     Path pidFile = Paths.get("/tmp/.java_pid" + pid);
116     if(Files.exists(pidFile)) {
117       try {
118         Files.delete(pidFile);
119       }
120       catch(FileSystemException e) {
121         if(e.getReason().matches("Operation not permitted|Not owner")) {
122           System.out.println("Unable to remove exisiting stale PID file" + pidFile);
123           System.out.println("===================================================");
124           e.printStackTrace(System.out);
125           return null;
126         }
127         throw e;
128       }
129     }
130     return Files.createFile(pidFile,
131       PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rw-------")));
132   }
133 
waitForAndResumeVM(int pid)134   private static void waitForAndResumeVM(int pid) throws Exception {
135     Path pauseFile = Paths.get("vm.paused." + pid);
136     int retries = 60;
137     while(!Files.exists(pauseFile) && --retries > 0) {
138       Thread.sleep(1000);
139     }
140     if(retries == 0) {
141       throw new RuntimeException("Timeout waiting for VM to start. " +
142         "vm.paused file not created within 60 seconds.");
143     }
144     Files.delete(pauseFile);
145   }
146 
getUnixProcessId(Process unixProcess)147   private static int getUnixProcessId(Process unixProcess) throws Exception {
148     Field pidField = unixProcess.getClass().getDeclaredField("pid");
149     pidField.setAccessible(true);
150     return (Integer)pidField.get(unixProcess);
151   }
152 }
153