OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 132 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 132 Rev 180
Line 12... Line 12...
12
 */
12
 */
13
 
13
 
14
 package org.openconcerto.utils;
14
 package org.openconcerto.utils;
15
 
15
 
16
import static org.openconcerto.utils.DesktopEnvironment.cmdSubstitution;
16
import static org.openconcerto.utils.DesktopEnvironment.cmdSubstitution;
-
 
17
 
17
import org.openconcerto.utils.cc.ITransformer;
18
import org.openconcerto.utils.cc.ITransformer;
18
 
19
 
19
import java.io.BufferedReader;
20
import java.io.BufferedReader;
20
import java.io.File;
21
import java.io.File;
21
import java.io.IOException;
22
import java.io.IOException;
22
import java.io.InputStreamReader;
23
import java.io.InputStreamReader;
23
import java.math.BigDecimal;
24
import java.math.BigDecimal;
24
import java.net.InetAddress;
25
import java.net.InetAddress;
25
import java.net.SocketException;
26
import java.net.SocketException;
-
 
27
import java.nio.file.Files;
-
 
28
import java.nio.file.Paths;
26
import java.util.ArrayList;
29
import java.util.ArrayList;
27
import java.util.List;
30
import java.util.List;
28
import java.util.logging.Level;
31
import java.util.logging.Level;
29
import java.util.regex.Matcher;
32
import java.util.regex.Matcher;
30
import java.util.regex.Pattern;
33
import java.util.regex.Pattern;
Line 41... Line 44...
41
 
44
 
42
    public static final Platform getInstance() {
45
    public static final Platform getInstance() {
43
        final OSFamily os = OSFamily.getInstance();
46
        final OSFamily os = OSFamily.getInstance();
44
        if (os == OSFamily.Windows) {
47
        if (os == OSFamily.Windows) {
45
            return CYGWIN;
48
            return CYGWIN;
46
        } else if (os == OSFamily.FreeBSD || os == OSFamily.Mac) {
49
        } else if (os == OSFamily.FreeBSD) {
47
            return FREEBSD;
50
            return FREEBSD;
-
 
51
        } else if (os == OSFamily.Mac) {
-
 
52
            return MACOS;
48
        } else {
53
        } else {
49
            return LINUX;
54
            return LINUX;
50
        }
55
        }
51
    }
56
    }
52
 
57
 
Line 55... Line 60...
55
    public abstract boolean isRunning(final int pid) throws IOException;
60
    public abstract boolean isRunning(final int pid) throws IOException;
56
 
61
 
57
    public abstract String getPath(final File f);
62
    public abstract String getPath(final File f);
58
 
63
 
59
    public final String getPID() throws IOException {
64
    public final String getPID() throws IOException {
60
        final Process p = this.eval("echo -n $PPID");
65
        // TODO remove reflection and getPreJava9PID() once on java 11
61
        final BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
-
 
62
        try {
66
        try {
-
 
67
            final Class<?> phClass = Class.forName("java.lang.ProcessHandle");
-
 
68
            final Object ph = phClass.getMethod("current").invoke(null);
-
 
69
            return ((Number) phClass.getMethod("pid").invoke(ph)).toString();
-
 
70
        } catch (ClassNotFoundException e) {
-
 
71
            // fall back
-
 
72
        } catch (Exception e) {
-
 
73
            throw new IOException("Couldn't get PID", e);
-
 
74
        }
-
 
75
        return getPreJava9PID();
-
 
76
    }
-
 
77
 
-
 
78
    protected String getPreJava9PID() throws IOException {
-
 
79
        final Process p = this.eval("echo -n $PPID");
-
 
80
        try (final BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
63
            return reader.readLine();
81
            return reader.readLine();
64
        } finally {
-
 
65
            reader.close();
-
 
66
        }
82
        }
67
    }
83
    }
68
 
84
 
69
    public final String tail(final File f, final int n) throws IOException {
85
    public final String tail(final File f, final int n) throws IOException {
70
        final Process p = Runtime.getRuntime().exec(new String[] { "tail", "-n" + n, this.getPath(f) });
86
        final Process p = Runtime.getRuntime().exec(new String[] { "tail", "-n" + n, this.getPath(f) });
Line 100... Line 116...
100
        return exitStatus(Runtime.getRuntime().exec(new String[] { "test", "-e", f.getAbsolutePath() })) == 0;
116
        return exitStatus(Runtime.getRuntime().exec(new String[] { "test", "-e", f.getAbsolutePath() })) == 0;
101
    }
117
    }
102
 
118
 
103
    public final void append(File f1, File f2) throws IOException {
119
    public final void append(File f1, File f2) throws IOException {
104
        final String c = "cat '" + f1.getAbsolutePath() + "' >> '" + f2.getAbsolutePath() + "'";
120
        final String c = "cat '" + f1.getAbsolutePath() + "' >> '" + f2.getAbsolutePath() + "'";
105
        try {
-
 
106
            this.eval(c).waitFor();
121
        this.waitForSuccess(this.eval(c), "append");
107
        } catch (InterruptedException e) {
-
 
108
            throw new IllegalStateException(e);
-
 
109
        }
-
 
110
    }
122
    }
111
 
123
 
112
    public Process cp_l(File src, File dest) throws IOException {
124
    public Process cp_l(File src, File dest) throws IOException {
113
        return Runtime.getRuntime().exec(new String[] { "cp", "-prl", src.getAbsolutePath(), dest.getAbsolutePath() });
125
        return Runtime.getRuntime().exec(new String[] { "cp", "-prl", src.getAbsolutePath(), dest.getAbsolutePath() });
114
    }
126
    }
Line 136... Line 148...
136
    protected abstract BigDecimal parsePingAverageRT(String statsLine);
148
    protected abstract BigDecimal parsePingAverageRT(String statsLine);
137
 
149
 
138
    protected final PingResult ping(final String command, final int totalCount, int requiredCount) throws IOException {
150
    protected final PingResult ping(final String command, final int totalCount, int requiredCount) throws IOException {
139
        if (requiredCount <= 0)
151
        if (requiredCount <= 0)
140
            requiredCount = totalCount;
152
            requiredCount = totalCount;
-
 
153
        // Keep errors out of cmdSubstitution() (e.g. "ping: sendto: Message too long" when
-
 
154
        // setDontFragment(true))
-
 
155
        final Process proc = evalPB(command).redirectErrorStream(false).start();
-
 
156
        final String output = cmdSubstitution(proc);
-
 
157
        try {
-
 
158
            this.waitForSuccess(proc, "ping");
141
        final List<String> countAndLastLine = StringUtils.splitIntoLines(cmdSubstitution(eval(command)));
159
            final List<String> countAndLastLine = StringUtils.splitIntoLines(output);
142
        if (countAndLastLine.size() != 2)
160
            if (countAndLastLine.size() != 2)
143
            throw new IllegalStateException("Not 2 lines in " + countAndLastLine);
161
                throw new IllegalStateException("Not 2 lines in " + countAndLastLine);
144
        final int replied = Integer.parseInt(countAndLastLine.get(0));
162
            final int replied = Integer.parseInt(countAndLastLine.get(0));
145
        assert replied <= totalCount;
163
            assert replied <= totalCount;
146
        final PingResult res = new PingResult(totalCount, replied, requiredCount, replied == 0 ? null : parsePingAverageRT(countAndLastLine.get(1).trim()));
164
            final BigDecimal averageRTT = replied == 0 ? null : parsePingAverageRT(countAndLastLine.get(1).trim());
-
 
165
            return new PingResult(totalCount, replied, requiredCount, averageRTT);
-
 
166
        } catch (Exception e) {
-
 
167
            throw new IllegalStateException("Couldn't use output :<<<\n" + output + "\n<<<", e);
147
        return res;
168
        }
148
    }
169
    }
149
 
170
 
150
    /**
171
    /**
151
     * Eval the passed string with bash.
172
     * Eval the passed string with bash.
152
     * 
173
     * 
153
     * @param s a bash script.
174
     * @param s a bash script.
154
     * @return the created process.
175
     * @return the created process.
155
     * @throws IOException If an I/O error occurs.
176
     * @throws IOException If an I/O error occurs.
156
     */
177
     */
157
    public final Process eval(String s) throws IOException {
178
    public final Process eval(String s) throws IOException {
-
 
179
        return evalPB(s).start();
-
 
180
    }
-
 
181
 
-
 
182
    public final ProcessBuilder evalPB(String s) throws IOException {
158
        return Runtime.getRuntime().exec(new String[] { this.getBash(), "-c", s });
183
        return new ProcessBuilder(this.getBash(), "-c", s);
159
    }
184
    }
160
 
185
 
161
    public final int exitStatus(Process p) {
186
    public final int exitStatus(Process p) {
-
 
187
        return this.exitStatus(p, null);
-
 
188
    }
-
 
189
 
-
 
190
    public final int exitStatus(Process p, final String name) {
162
        try {
191
        try {
163
            return p.waitFor();
192
            return p.waitFor();
164
        } catch (InterruptedException e) {
193
        } catch (InterruptedException e) {
165
            throw new IllegalStateException(e);
194
            throw new RTInterruptedException("Interrupted while waiting for" + (name == null ? "" : " '" + name + "'") + " process", e);
166
        }
195
        }
167
    }
196
    }
168
 
197
 
-
 
198
    public final void waitForSuccess(final Process p, final String name) {
-
 
199
        final int exitStatus = exitStatus(p, name);
-
 
200
        if (exitStatus != 0)
-
 
201
            throw new IllegalStateException(name + " unsuccessful : " + exitStatus);
-
 
202
    }
-
 
203
 
169
    public abstract boolean isAdmin() throws IOException;
204
    public abstract boolean isAdmin() throws IOException;
170
 
205
 
171
    private static abstract class UnixPlatform extends Platform {
206
    private static abstract class UnixPlatform extends Platform {
172
 
207
 
173
        @Override
208
        @Override
174
        public boolean supportsPID() {
209
        public boolean supportsPID() {
175
            return true;
210
            return true;
176
        }
211
        }
177
 
212
 
-
 
213
        @Override
-
 
214
        public final String getPreJava9PID() throws IOException {
-
 
215
            final String symlink = getSelfProcessSymlink();
-
 
216
            if (symlink == null)
-
 
217
                return super.getPreJava9PID();
-
 
218
 
-
 
219
            // readSymbolicLink() seems to faster than getCanonicalFile() or toRealPath().
-
 
220
            // Another way is using reflection for
-
 
221
            // ManagementFactory.getRuntimeMXBean().jvm.getProcessId()
-
 
222
            return Files.readSymbolicLink(Paths.get(symlink)).getFileName().toString();
-
 
223
        }
-
 
224
 
-
 
225
        protected abstract String getSelfProcessSymlink();
-
 
226
 
178
        public final boolean isRunning(final int pid) throws IOException {
227
        public final boolean isRunning(final int pid) throws IOException {
179
            // --pid only works on Linux, -p also on Nexenta
228
            // --pid only works on Linux, -p also on Nexenta
180
            final Process p = Runtime.getRuntime().exec(new String[] { "ps", "-p", String.valueOf(pid) });
229
            final Process p = Runtime.getRuntime().exec(new String[] { "ps", "-p", String.valueOf(pid) });
181
            return this.exitStatus(p) == 0;
230
            return this.exitStatus(p) == 0;
182
        }
231
        }
Line 218... Line 267...
218
 
267
 
219
        @Override
268
        @Override
220
        protected BigDecimal parsePingAverageRT(String statsLine) {
269
        protected BigDecimal parsePingAverageRT(String statsLine) {
221
            final Matcher m = PING_STATS_PATTERN.matcher(statsLine);
270
            final Matcher m = PING_STATS_PATTERN.matcher(statsLine);
222
            if (!m.matches())
271
            if (!m.matches())
223
                throw new IllegalArgumentException("Not matching " + PING_STATS_PATTERN + " : " + statsLine);
272
                throw new IllegalArgumentException("Not matching " + PING_STATS_PATTERN + " :\n" + statsLine);
224
            return new BigDecimal(m.group(2));
273
            return new BigDecimal(m.group(2));
225
        }
274
        }
226
 
275
 
227
        @Override
276
        @Override
228
        public boolean isAdmin() throws IOException {
277
        public boolean isAdmin() throws IOException {
Line 230... Line 279...
230
            return cmdSubstitution(this.eval("id -u")).trim().equals("0");
279
            return cmdSubstitution(this.eval("id -u")).trim().equals("0");
231
        }
280
        }
232
    }
281
    }
233
 
282
 
234
    private static final Platform LINUX = new UnixPlatform() {
283
    private static final Platform LINUX = new UnixPlatform() {
-
 
284
 
-
 
285
        @Override
-
 
286
        protected String getSelfProcessSymlink() {
-
 
287
            return "/proc/self";
-
 
288
        }
-
 
289
 
235
        @Override
290
        @Override
236
        public PingResult ping(final InetAddress host, final PingBuilder pingBuilder, final int routingTableIndex) throws IOException {
291
        public PingResult ping(final InetAddress host, final PingBuilder pingBuilder, final int routingTableIndex) throws IOException {
237
            if (routingTableIndex > 0)
292
            if (routingTableIndex > 0)
238
                throw new UnsupportedOperationException("On Linux, choosing a different routing table requires changing the system policy");
293
                throw new UnsupportedOperationException("On Linux, choosing a different routing table requires changing the system policy");
239
            final List<String> command = new ArrayList<String>(16);
294
            final List<String> command = new ArrayList<String>(16);
Line 269... Line 324...
269
            return ping("out=$(" + CollectionUtils.join(command, " ") + ") ; grep -c ttl= <<< \"$out\" ; tail -n1 <<< \"$out\"", totalCount, pingBuilder.getRequiredReplies());
324
            return ping("out=$(" + CollectionUtils.join(command, " ") + ") ; grep -c ttl= <<< \"$out\" ; tail -n1 <<< \"$out\"", totalCount, pingBuilder.getRequiredReplies());
270
        }
325
        }
271
    };
326
    };
272
 
327
 
273
    private static final Platform FREEBSD = new UnixPlatform() {
328
    private static final Platform FREEBSD = new UnixPlatform() {
-
 
329
 
-
 
330
        @Override
-
 
331
        protected String getSelfProcessSymlink() {
-
 
332
            return "/proc/curproc";
-
 
333
        }
-
 
334
 
274
        @Override
335
        @Override
275
        public PingResult ping(final InetAddress host, final PingBuilder pingBuilder, final int routingTableIndex) throws IOException {
336
        public PingResult ping(final InetAddress host, final PingBuilder pingBuilder, final int routingTableIndex) throws IOException {
276
            final List<String> command = new ArrayList<String>(16);
337
            final List<String> command = new ArrayList<String>(16);
277
            command.add("setfib");
338
            command.add("setfib");
278
            command.add(String.valueOf(routingTableIndex));
339
            command.add(String.valueOf(routingTableIndex));
Line 306... Line 367...
306
 
367
 
307
            return ping("out=$(" + CollectionUtils.join(command, " ") + ") ; grep -c ttl= <<< \"$out\" ; tail -n1 <<< \"$out\"", totalCount, pingBuilder.getRequiredReplies());
368
            return ping("out=$(" + CollectionUtils.join(command, " ") + ") ; grep -c ttl= <<< \"$out\" ; tail -n1 <<< \"$out\"", totalCount, pingBuilder.getRequiredReplies());
308
        }
369
        }
309
    };
370
    };
310
 
371
 
-
 
372
    private static final Platform MACOS = new UnixPlatform() {
-
 
373
        @Override
-
 
374
        protected String getSelfProcessSymlink() {
-
 
375
            return null;
-
 
376
        }
-
 
377
 
-
 
378
        @Override
-
 
379
        protected PingResult ping(InetAddress host, PingBuilder pingBuilder, int routingTableIndex) throws IOException {
-
 
380
            return FREEBSD.ping(host, pingBuilder, routingTableIndex);
-
 
381
        }
-
 
382
    };
-
 
383
 
311
    private static final class CygwinPlatform extends Platform {
384
    private static final class CygwinPlatform extends Platform {
312
 
385
 
313
        @Override
386
        @Override
314
        public boolean supportsPID() {
387
        public boolean supportsPID() {
315
            return false;
388
            return false;
Line 345... Line 418...
345
 
418
 
346
        @Override
419
        @Override
347
        public boolean ping(InetAddress host, final int timeout) throws IOException {
420
        public boolean ping(InetAddress host, final int timeout) throws IOException {
348
            // windows implem of isReachable() is buggy
421
            // windows implem of isReachable() is buggy
349
            // see http://bordet.blogspot.com/2006/07/icmp-and-inetaddressisreachable.html
422
            // see http://bordet.blogspot.com/2006/07/icmp-and-inetaddressisreachable.html
350
            try {
-
 
351
                final int exit = Runtime.getRuntime().exec("ping -n 1 -w " + timeout + " " + host.getHostAddress()).waitFor();
423
            final int exit = this.exitStatus(Runtime.getRuntime().exec("ping -n 1 -w " + timeout + " " + host.getHostAddress()), "ping");
352
                return exit == 0;
424
            return exit == 0;
353
            } catch (InterruptedException e) {
-
 
354
                throw new IllegalStateException(e);
-
 
355
            }
-
 
356
        }
425
        }
357
 
426
 
358
        @Override
427
        @Override
359
        public PingResult ping(final InetAddress host, final PingBuilder pingBuilder, final int routingTableIndex) throws IOException {
428
        public PingResult ping(final InetAddress host, final PingBuilder pingBuilder, final int routingTableIndex) throws IOException {
360
            if (routingTableIndex > 0)
429
            if (routingTableIndex > 0)