1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package com.sun.akuma;
25
26 import com.sun.jna.Memory;
27 import com.sun.jna.Native;
28 import com.sun.jna.NativeLong;
29 import com.sun.jna.StringArray;
30 import static com.sun.akuma.CLibrary.LIBC;
31
32 import java.io.FileWriter;
33 import java.io.IOException;
34 import java.io.File;
35 import java.lang.reflect.Method;
36 import java.util.logging.Level;
37 import java.util.logging.Logger;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 public class Daemon {
76
77
78
79
80
81
82
83 public void all(boolean daemonize) throws Exception {
84 if(isDaemonized())
85 init();
86 else {
87 if(daemonize) {
88 daemonize();
89 System.exit(0);
90 }
91 }
92 }
93
94
95
96
97
98 public boolean isDaemonized() {
99 return System.getProperty(Daemon.class.getName())!=null;
100 }
101
102
103
104
105 public void daemonize() throws IOException {
106 daemonize(JavaVMArguments.current());
107 }
108
109
110
111
112 public void daemonize(JavaVMArguments args) {
113 if(isDaemonized())
114 throw new IllegalStateException("Already running as a daemon");
115
116 if (System.getProperty("com.sun.management.jmxremote.port") != null) {
117 try {
118 Method m = Class.forName("sun.management.Agent").getDeclaredMethod("stopRemoteManagementAgent");
119 m.setAccessible(true);
120 m.invoke(null);
121 } catch (Exception x) {
122 LOGGER.log(Level.SEVERE, "could not simulate jcmd $$ ManagementAgent.stop (JENKINS-14529)", x);
123 }
124 }
125
126
127 args.setSystemProperty(Daemon.class.getName(),"daemonized");
128
129
130 String exe = getCurrentExecutable();
131 StringArray sa = args.toStringArray();
132
133 int i = LIBC.fork();
134 if(i<0) {
135 LIBC.perror("initial fork failed");
136 System.exit(-1);
137 }
138 if(i==0) {
139
140 LIBC.execv(exe,sa);
141 System.err.println("exec failed");
142 LIBC.perror("initial exec failed");
143 System.exit(-1);
144 }
145
146
147 }
148
149
150
151
152 public static void selfExec(JavaVMArguments args) {
153 LIBC.execv(getCurrentExecutable(), args.toStringArray());
154 }
155
156
157
158
159
160 public void init() throws Exception {
161 init("/var/run/daemon.pid");
162 }
163
164
165
166
167
168
169 @SuppressWarnings({"OctalInteger"})
170 public void init(String pidFile) throws Exception {
171
172 LIBC.setsid();
173
174 closeDescriptors();
175
176 chdirToRoot();
177 if (pidFile != null) writePidFile(pidFile);
178 }
179
180
181
182
183
184
185
186
187 protected void closeDescriptors() throws IOException {
188 if(!Boolean.getBoolean(Daemon.class.getName()+".keepDescriptors")) {
189 System.out.close();
190 System.err.close();
191 System.in.close();
192 }
193
194
195
196 }
197
198
199
200
201 protected void chdirToRoot() {
202 LIBC.chdir("/");
203 System.setProperty("user.dir","/");
204 }
205
206
207
208
209
210 protected void writePidFile(String pidFile) throws IOException {
211 try {
212 FileWriter fw = new FileWriter(pidFile);
213 fw.write(String.valueOf(LIBC.getpid()));
214 fw.close();
215 } catch (IOException e) {
216
217 }
218 }
219
220
221
222
223 public static String getCurrentExecutable() {
224 int pid = LIBC.getpid();
225 String name = "/proc/" + pid + "/exe";
226 File exe = new File(name);
227 if(exe.exists()) {
228 try {
229 String path = resolveSymlink(exe);
230 if (path!=null) return path;
231 } catch (IOException e) {
232 LOGGER.log(Level.FINE,"Failed to resolve symlink "+exe,e);
233 }
234 return name;
235 }
236
237
238 return System.getProperty("java.home")+"/bin/java";
239 }
240
241 private static String resolveSymlink(File link) throws IOException {
242 String filename = link.getAbsolutePath();
243
244 for (int sz=512; sz < 65536; sz*=2) {
245 Memory m = new Memory(sz);
246 int r = LIBC.readlink(filename,m,new NativeLong(sz));
247 if (r<0) {
248 int err = Native.getLastError();
249 if (err==22)
250 return null;
251 throw new IOException("Failed to readlink "+link+" error="+ err+" "+ LIBC.strerror(err));
252 }
253
254 if (r==sz)
255 continue;
256
257 byte[] buf = new byte[r];
258 m.read(0,buf,0,r);
259 return new String(buf);
260 }
261
262 throw new IOException("Failed to readlink "+link);
263 }
264
265
266
267
268
269
270
271
272 public static class WithoutChdir extends Daemon {
273 @Override
274 protected void chdirToRoot() {
275
276 }
277 }
278
279 private static final Logger LOGGER = Logger.getLogger(Daemon.class.getName());
280 }