1
1
package com .termux .shared .shell ;
2
2
3
- import android .content .Context ;
4
-
5
- import androidx .annotation .NonNull ;
6
-
7
- import com .termux .shared .models .errors .Error ;
8
- import com .termux .shared .termux .TermuxConstants ;
9
- import com .termux .shared .file .FileUtils ;
10
- import com .termux .shared .logger .Logger ;
11
- import com .termux .shared .packages .PackageUtils ;
12
- import com .termux .shared .termux .TermuxUtils ;
13
3
import com .termux .terminal .TerminalBuffer ;
14
4
import com .termux .terminal .TerminalEmulator ;
15
5
import com .termux .terminal .TerminalSession ;
16
6
17
- import java .io .File ;
18
- import java .io .FileInputStream ;
19
- import java .io .IOException ;
20
7
import java .lang .reflect .Field ;
21
- import java .util .ArrayList ;
22
- import java .util .Collections ;
23
- import java .util .List ;
24
8
25
9
public class ShellUtils {
26
10
27
- public static String [] buildEnvironment (Context currentPackageContext , boolean isFailSafe , String workingDirectory ) {
28
- TermuxConstants .TERMUX_HOME_DIR .mkdirs ();
29
-
30
- if (workingDirectory == null || workingDirectory .isEmpty ()) workingDirectory = TermuxConstants .TERMUX_HOME_DIR_PATH ;
31
-
32
- List <String > environment = new ArrayList <>();
33
-
34
- // This function may be called by a different package like a plugin, so we get version for Termux package via its context
35
- Context termuxPackageContext = TermuxUtils .getTermuxPackageContext (currentPackageContext );
36
- if (termuxPackageContext != null ) {
37
- String termuxVersionName = PackageUtils .getVersionNameForPackage (termuxPackageContext );
38
- if (termuxVersionName != null )
39
- environment .add ("TERMUX_VERSION=" + termuxVersionName );
40
- }
41
-
42
- environment .add ("TERM=xterm-256color" );
43
- environment .add ("COLORTERM=truecolor" );
44
- environment .add ("HOME=" + TermuxConstants .TERMUX_HOME_DIR_PATH );
45
- environment .add ("PREFIX=" + TermuxConstants .TERMUX_PREFIX_DIR_PATH );
46
- environment .add ("BOOTCLASSPATH=" + System .getenv ("BOOTCLASSPATH" ));
47
- environment .add ("ANDROID_ROOT=" + System .getenv ("ANDROID_ROOT" ));
48
- environment .add ("ANDROID_DATA=" + System .getenv ("ANDROID_DATA" ));
49
- // EXTERNAL_STORAGE is needed for /system/bin/am to work on at least
50
- // Samsung S7 - see https://plus.google.com/110070148244138185604/posts/gp8Lk3aCGp3.
51
- environment .add ("EXTERNAL_STORAGE=" + System .getenv ("EXTERNAL_STORAGE" ));
52
-
53
- // These variables are needed if running on Android 10 and higher.
54
- addToEnvIfPresent (environment , "ANDROID_ART_ROOT" );
55
- addToEnvIfPresent (environment , "DEX2OATBOOTCLASSPATH" );
56
- addToEnvIfPresent (environment , "ANDROID_I18N_ROOT" );
57
- addToEnvIfPresent (environment , "ANDROID_RUNTIME_ROOT" );
58
- addToEnvIfPresent (environment , "ANDROID_TZDATA_ROOT" );
59
-
60
- if (isFailSafe ) {
61
- // Keep the default path so that system binaries can be used in the failsafe session.
62
- environment .add ("PATH= " + System .getenv ("PATH" ));
63
- } else {
64
- environment .add ("LANG=en_US.UTF-8" );
65
- environment .add ("PATH=" + TermuxConstants .TERMUX_BIN_PREFIX_DIR_PATH );
66
- environment .add ("PWD=" + workingDirectory );
67
- environment .add ("TMPDIR=" + TermuxConstants .TERMUX_TMP_PREFIX_DIR_PATH );
68
- }
69
-
70
- return environment .toArray (new String [0 ]);
71
- }
72
-
73
- public static void addToEnvIfPresent (List <String > environment , String name ) {
74
- String value = System .getenv (name );
75
- if (value != null ) {
76
- environment .add (name + "=" + value );
77
- }
78
- }
79
-
80
11
public static int getPid (Process p ) {
81
12
try {
82
13
Field f = p .getClass ().getDeclaredField ("pid" );
@@ -91,77 +22,12 @@ public static int getPid(Process p) {
91
22
}
92
23
}
93
24
94
- public static String [] setupProcessArgs (@ NonNull String fileToExecute , String [] arguments ) {
95
- // The file to execute may either be:
96
- // - An elf file, in which we execute it directly.
97
- // - A script file without shebang, which we execute with our standard shell $PREFIX/bin/sh instead of the
98
- // system /system/bin/sh. The system shell may vary and may not work at all due to LD_LIBRARY_PATH.
99
- // - A file with shebang, which we try to handle with e.g. /bin/foo -> $PREFIX/bin/foo.
100
- String interpreter = null ;
101
- try {
102
- File file = new File (fileToExecute );
103
- try (FileInputStream in = new FileInputStream (file )) {
104
- byte [] buffer = new byte [256 ];
105
- int bytesRead = in .read (buffer );
106
- if (bytesRead > 4 ) {
107
- if (buffer [0 ] == 0x7F && buffer [1 ] == 'E' && buffer [2 ] == 'L' && buffer [3 ] == 'F' ) {
108
- // Elf file, do nothing.
109
- } else if (buffer [0 ] == '#' && buffer [1 ] == '!' ) {
110
- // Try to parse shebang.
111
- StringBuilder builder = new StringBuilder ();
112
- for (int i = 2 ; i < bytesRead ; i ++) {
113
- char c = (char ) buffer [i ];
114
- if (c == ' ' || c == '\n' ) {
115
- if (builder .length () == 0 ) {
116
- // Skip whitespace after shebang.
117
- } else {
118
- // End of shebang.
119
- String executable = builder .toString ();
120
- if (executable .startsWith ("/usr" ) || executable .startsWith ("/bin" )) {
121
- String [] parts = executable .split ("/" );
122
- String binary = parts [parts .length - 1 ];
123
- interpreter = TermuxConstants .TERMUX_BIN_PREFIX_DIR_PATH + "/" + binary ;
124
- }
125
- break ;
126
- }
127
- } else {
128
- builder .append (c );
129
- }
130
- }
131
- } else {
132
- // No shebang and no ELF, use standard shell.
133
- interpreter = TermuxConstants .TERMUX_BIN_PREFIX_DIR_PATH + "/sh" ;
134
- }
135
- }
136
- }
137
- } catch (IOException e ) {
138
- // Ignore.
139
- }
140
-
141
- List <String > result = new ArrayList <>();
142
- if (interpreter != null ) result .add (interpreter );
143
- result .add (fileToExecute );
144
- if (arguments != null ) Collections .addAll (result , arguments );
145
- return result .toArray (new String [0 ]);
146
- }
147
-
148
25
public static String getExecutableBasename (String executable ) {
149
26
if (executable == null ) return null ;
150
27
int lastSlash = executable .lastIndexOf ('/' );
151
28
return (lastSlash == -1 ) ? executable : executable .substring (lastSlash + 1 );
152
29
}
153
30
154
- public static void clearTermuxTMPDIR (boolean onlyIfExists ) {
155
- if (onlyIfExists && !FileUtils .directoryFileExists (TermuxConstants .TERMUX_TMP_PREFIX_DIR_PATH , false ))
156
- return ;
157
-
158
- Error error ;
159
- error = FileUtils .clearDirectory ("$TMPDIR" , FileUtils .getCanonicalPath (TermuxConstants .TERMUX_TMP_PREFIX_DIR_PATH , null ));
160
- if (error != null ) {
161
- Logger .logErrorExtended (error .toString ());
162
- }
163
- }
164
-
165
31
public static String getTerminalSessionTranscriptText (TerminalSession terminalSession , boolean linesJoined , boolean trim ) {
166
32
if (terminalSession == null ) return null ;
167
33
0 commit comments