1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
package com.wireguard.android.util;
import android.content.Context;
import android.system.ErrnoException;
import android.system.OsConstants;
import com.wireguard.android.Application.ApplicationContext;
import com.wireguard.android.Application.ApplicationScope;
import com.wireguard.android.util.RootShell.NoRootException;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
/**
* Helper to install WireGuard tools to the system partition.
*/
@ApplicationScope
public final class ToolsInstaller {
private static final String[][] EXECUTABLES = {
{"libwg.so", "wg"},
{"libwg-quick.so", "wg-quick"},
};
private static final File[] INSTALL_DIRS = {
new File("/system/xbin"),
new File("/system/bin"),
};
private static final File INSTALL_DIR = getInstallDir();
private final File localBinaryDir;
private final File nativeLibraryDir;
private final RootShell rootShell;
@Inject
public ToolsInstaller(@ApplicationContext final Context context, final RootShell rootShell) {
localBinaryDir = new File(context.getCacheDir(), "bin");
nativeLibraryDir = new File(context.getApplicationInfo().nativeLibraryDir);
this.rootShell = rootShell;
}
private static File getInstallDir() {
final String path = System.getenv("PATH");
if (path == null)
return INSTALL_DIRS[0];
final List<String> paths = Arrays.asList(path.split(":"));
for (final File dir : INSTALL_DIRS)
if (paths.contains(dir.getPath()) && dir.isDirectory())
return dir;
return null;
}
public boolean areInstalled() {
if (INSTALL_DIR == null)
return false;
final StringBuilder script = new StringBuilder();
for (final String[] names : EXECUTABLES) {
script.append(String.format("cmp -s '%s' '%s' && ",
new File(nativeLibraryDir, names[0]),
new File(INSTALL_DIR, names[1])));
}
script.append("exit ").append(OsConstants.EALREADY);
try {
return rootShell.run(null, script.toString()) == OsConstants.EALREADY;
} catch (final ErrnoException | IOException | NoRootException ignored) {
return false;
}
}
public boolean areSymlinked() {
final StringBuilder script = new StringBuilder();
for (final String[] names : EXECUTABLES) {
script.append(String.format("test '%s' -ef '%s' && ",
new File(nativeLibraryDir, names[0]),
new File(localBinaryDir, names[1])));
}
script.append("exit ").append(OsConstants.EALREADY);
try {
return rootShell.run(null, script.toString()) == OsConstants.EALREADY;
} catch (final ErrnoException | IOException | NoRootException ignored) {
return false;
}
}
public int install() {
if (INSTALL_DIR == null)
return OsConstants.ENOENT;
final StringBuilder script = new StringBuilder("set -ex"
+ "; trap 'mount -o ro,remount /system' EXIT; mount -o rw,remount /system");
for (final String[] names : EXECUTABLES) {
final File destination = new File(INSTALL_DIR, names[1]);
script.append(String.format("; cp '%s' '%s'; chmod 755 '%s'; restorecon '%s' ",
new File(nativeLibraryDir, names[0]), destination, destination, destination));
}
try {
return rootShell.run(null, script.toString());
} catch (final ErrnoException e) {
return e.errno;
} catch (final IOException ignored) {
return OsConstants.EXIT_FAILURE;
} catch (final NoRootException ignored) {
return OsConstants.EACCES;
}
}
public int symlink() {
final StringBuilder script = new StringBuilder("set -ex");
for (final String[] names : EXECUTABLES) {
script.append(String.format("; ln -fns '%s' '%s'",
new File(nativeLibraryDir, names[0]),
new File(localBinaryDir, names[1])));
}
try {
return rootShell.run(null, script.toString());
} catch (final ErrnoException e) {
return e.errno;
} catch (final IOException ignored) {
return OsConstants.EXIT_FAILURE;
} catch (final NoRootException ignored) {
return OsConstants.EACCES;
}
}
}
|