diff options
Diffstat (limited to 'app/src/main/java/org/pacien/tincapp/commands')
5 files changed, 233 insertions, 0 deletions
diff --git a/app/src/main/java/org/pacien/tincapp/commands/Command.java b/app/src/main/java/org/pacien/tincapp/commands/Command.java new file mode 100644 index 0000000..28ff226 --- /dev/null +++ b/app/src/main/java/org/pacien/tincapp/commands/Command.java | |||
@@ -0,0 +1,67 @@ | |||
1 | package org.pacien.tincapp.commands; | ||
2 | |||
3 | import com.annimon.stream.Collectors; | ||
4 | import com.annimon.stream.Optional; | ||
5 | import com.annimon.stream.Stream; | ||
6 | |||
7 | import java.util.Arrays; | ||
8 | import java.util.Collections; | ||
9 | import java.util.LinkedList; | ||
10 | import java.util.List; | ||
11 | |||
12 | /** | ||
13 | * @author pacien | ||
14 | */ | ||
15 | class Command { | ||
16 | |||
17 | static private class Option { | ||
18 | final String key; | ||
19 | final Optional<java.lang.String> val; | ||
20 | |||
21 | Option(String key, String val) { | ||
22 | this.key = key; | ||
23 | this.val = Optional.ofNullable(val); | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public String toString() { | ||
28 | return val.isPresent() ? "--" + key + "=" + val.get() : "--" + key; | ||
29 | } | ||
30 | } | ||
31 | |||
32 | final private String cmd; | ||
33 | final private List<Option> opts; | ||
34 | final private List<String> args; | ||
35 | |||
36 | public Command(String cmd) { | ||
37 | this.cmd = cmd; | ||
38 | this.opts = new LinkedList<>(); | ||
39 | this.args = new LinkedList<>(); | ||
40 | } | ||
41 | |||
42 | public Command withOption(String key, String val) { | ||
43 | this.opts.add(new Option(key, val)); | ||
44 | return this; | ||
45 | } | ||
46 | |||
47 | public Command withOption(String key) { | ||
48 | return this.withOption(key, null); | ||
49 | } | ||
50 | |||
51 | public Command withArguments(String... args) { | ||
52 | this.args.addAll(Arrays.asList(args)); | ||
53 | return this; | ||
54 | } | ||
55 | |||
56 | public List<String> asList() { | ||
57 | return Collections.unmodifiableList( | ||
58 | Stream.concat(Stream.of(Collections.singleton(this.cmd)), | ||
59 | Stream.concat(Stream.of(this.opts).map(Option::toString), Stream.of(this.args))) | ||
60 | .collect(Collectors.toList())); | ||
61 | } | ||
62 | |||
63 | public String[] asArray() { | ||
64 | return this.asList().toArray(new String[0]); | ||
65 | } | ||
66 | |||
67 | } | ||
diff --git a/app/src/main/java/org/pacien/tincapp/commands/Executor.java b/app/src/main/java/org/pacien/tincapp/commands/Executor.java new file mode 100644 index 0000000..edf229c --- /dev/null +++ b/app/src/main/java/org/pacien/tincapp/commands/Executor.java | |||
@@ -0,0 +1,44 @@ | |||
1 | package org.pacien.tincapp.commands; | ||
2 | |||
3 | import java.io.BufferedReader; | ||
4 | import java.io.IOException; | ||
5 | import java.io.InputStreamReader; | ||
6 | import java.util.Collections; | ||
7 | import java.util.LinkedList; | ||
8 | import java.util.List; | ||
9 | |||
10 | /** | ||
11 | * @author pacien | ||
12 | */ | ||
13 | final class Executor { | ||
14 | |||
15 | private Executor() { | ||
16 | // static class | ||
17 | } | ||
18 | |||
19 | static { | ||
20 | System.loadLibrary("exec"); | ||
21 | } | ||
22 | |||
23 | /** | ||
24 | * @return -1 on error, forked child PID otherwise | ||
25 | */ | ||
26 | static private native int forkExec(String[] argcv); | ||
27 | |||
28 | static public void forkExec(Command cmd) throws IOException { | ||
29 | if (forkExec(cmd.asArray()) == -1) | ||
30 | throw new IOException(); | ||
31 | } | ||
32 | |||
33 | static public List<String> call(Command cmd) throws IOException { | ||
34 | Process proc = new ProcessBuilder(cmd.asList()).start(); | ||
35 | BufferedReader outputReader = new BufferedReader(new InputStreamReader(proc.getInputStream())); | ||
36 | |||
37 | String line; | ||
38 | List<String> list = new LinkedList<>(); | ||
39 | while ((line = outputReader.readLine()) != null) list.add(line); | ||
40 | |||
41 | return Collections.unmodifiableList(list); | ||
42 | } | ||
43 | |||
44 | } | ||
diff --git a/app/src/main/java/org/pacien/tincapp/commands/PermissionFixer.java b/app/src/main/java/org/pacien/tincapp/commands/PermissionFixer.java new file mode 100644 index 0000000..b00d0d6 --- /dev/null +++ b/app/src/main/java/org/pacien/tincapp/commands/PermissionFixer.java | |||
@@ -0,0 +1,34 @@ | |||
1 | package org.pacien.tincapp.commands; | ||
2 | |||
3 | import android.annotation.SuppressLint; | ||
4 | import android.content.Context; | ||
5 | |||
6 | import com.annimon.stream.Stream; | ||
7 | |||
8 | import org.pacien.tincapp.context.AppPaths; | ||
9 | |||
10 | import java.io.File; | ||
11 | |||
12 | /** | ||
13 | * @author pacien | ||
14 | */ | ||
15 | final public class PermissionFixer { | ||
16 | |||
17 | private PermissionFixer() { | ||
18 | // static class | ||
19 | } | ||
20 | |||
21 | @SuppressLint({"SetWorldReadable", "SetWorldWritable"}) | ||
22 | static private Boolean setAllRWXPermissions(File f) { | ||
23 | return f.setReadable(true, false) | ||
24 | && f.setWritable(true, false) | ||
25 | && f.setExecutable(true, false); | ||
26 | } | ||
27 | |||
28 | static public Boolean makePrivateDirsPublic(Context ctx) { | ||
29 | return Stream.of(AppPaths.confDir(ctx), AppPaths.logDir(ctx), AppPaths.pidDir(ctx)) | ||
30 | .map(PermissionFixer::setAllRWXPermissions) | ||
31 | .reduce((x, y) -> x && y).get(); | ||
32 | } | ||
33 | |||
34 | } | ||
diff --git a/app/src/main/java/org/pacien/tincapp/commands/Tinc.java b/app/src/main/java/org/pacien/tincapp/commands/Tinc.java new file mode 100644 index 0000000..ca11698 --- /dev/null +++ b/app/src/main/java/org/pacien/tincapp/commands/Tinc.java | |||
@@ -0,0 +1,60 @@ | |||
1 | package org.pacien.tincapp.commands; | ||
2 | |||
3 | import android.content.Context; | ||
4 | |||
5 | import com.annimon.stream.Stream; | ||
6 | |||
7 | import org.pacien.tincapp.context.AppPaths; | ||
8 | |||
9 | import java.io.IOException; | ||
10 | import java.util.List; | ||
11 | |||
12 | /** | ||
13 | * @author pacien | ||
14 | */ | ||
15 | final public class Tinc { | ||
16 | |||
17 | private Tinc() { | ||
18 | // static class | ||
19 | } | ||
20 | |||
21 | static private Command newCommand(Context ctx, String netName) { | ||
22 | return new Command(AppPaths.tinc(ctx).getAbsolutePath()) | ||
23 | .withOption("config", AppPaths.confDir(ctx, netName).getAbsolutePath()) | ||
24 | .withOption("pidfile", AppPaths.pidFile(ctx, netName).getAbsolutePath()); | ||
25 | } | ||
26 | |||
27 | // independently runnable commands | ||
28 | |||
29 | static public List<String> network(Context ctx) throws IOException { | ||
30 | return Executor.call(new Command(AppPaths.tinc(ctx).getAbsolutePath()) | ||
31 | .withOption("config", AppPaths.confDir(ctx).getAbsolutePath()) | ||
32 | .withArguments("network")); | ||
33 | } | ||
34 | |||
35 | static public List<String> fsck(Context ctx, String netName, Boolean fix) throws IOException { | ||
36 | Command cmd = newCommand(ctx, netName).withArguments("fsck"); | ||
37 | if (fix) cmd = cmd.withOption("force"); | ||
38 | return Executor.call(cmd); | ||
39 | } | ||
40 | |||
41 | // commands requiring a running tinc daemon | ||
42 | |||
43 | static public void stop(Context ctx, String netName) throws IOException { | ||
44 | Executor.call(newCommand(ctx, netName).withArguments("stop")); | ||
45 | } | ||
46 | |||
47 | static public List<String> dumpNodes(Context ctx, String netName, Boolean reachable) throws IOException { | ||
48 | Command cmd = reachable | ||
49 | ? newCommand(ctx, netName).withArguments("dump", "reachable", "nodes") | ||
50 | : newCommand(ctx, netName).withArguments("dump", "nodes"); | ||
51 | |||
52 | return Executor.call(cmd); | ||