这是indexloc提供的服务,不要输入任何密码
Skip to content

Commit f047302

Browse files
Fixed: Fix argument parsing and convert termux-am binary to termux-am-socket and introduce termux-am wrapper script
Arguments were being passed to server by surrounding them with double quotes, which obviously wouldn't work if arguments themselves contained double quotes and would result in broken commands and wrong data. bash printf built-in provides `%q` format specification which can be used to convert argument arrays to a single string that can be reused as shell input. The `ArgumentTokenizer` should be able to handle this string to convert it back to arguments. The c printf does not support `%q` and porting bash functionality would require importing a lot of code. So the new termux-am script will convert arguments to a string and pass it to the termux-am-socket binary to be sent to the server. The termux-am also provides a help screen to help user understand how it works and provides `--am-help` flag to show am command help instead which is returned by termux-am-library.
1 parent bd8e9f5 commit f047302

File tree

3 files changed

+169
-12
lines changed

3 files changed

+169
-12
lines changed

CMakeLists.txt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ configure_file(
1313
termux-am.h @ONLY
1414
)
1515

16-
add_executable(termux-am termux-am.cpp)
17-
target_include_directories(termux-am PUBLIC ${CMAKE_BINARY_DIR})
16+
configure_file(
17+
${CMAKE_CURRENT_SOURCE_DIR}/termux-am.sh.in
18+
termux-am @ONLY
19+
)
20+
21+
add_executable(termux-am-socket termux-am.cpp)
22+
target_include_directories(termux-am-socket PUBLIC ${CMAKE_BINARY_DIR})
23+
1824

19-
install(TARGETS termux-am DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
25+
install(FILES ${CMAKE_BINARY_DIR}/termux-am TYPE BIN PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
26+
install(TARGETS termux-am-socket DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)

termux-am.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@
2626
#include <sys/types.h>
2727
#include <sys/un.h>
2828

29-
#define QUOTE "\""
30-
#define SPACE " "
31-
3229
#include <iostream>
3330
#include <memory>
3431
#include <stdexcept>
@@ -71,7 +68,13 @@ bool is_number(const std::string& s) {
7168
return !s.empty() && it == s.end();
7269
}
7370

71+
7472
int main(int argc, char* argv[]) {
73+
if (argc > 2) {
74+
std::cerr << "termux-am-socket only expects 1 argument and received " << argc - 1 << std::endl;
75+
return 1;
76+
}
77+
7578
struct sockaddr_un adr = {.sun_family = AF_UNIX};
7679
if (strlen(SOCKET_PATH) >= sizeof(adr.sun_path)) {
7780
std::cerr << "Socket path \"" << SOCKET_PATH << "\" too long" << std::endl;
@@ -91,12 +94,10 @@ int main(int argc, char* argv[]) {
9194
return 1;
9295
}
9396

94-
for (int i = 1; i<argc; i++) {
95-
send_blocking(fd, QUOTE, sizeof(QUOTE)-1);
96-
send_blocking(fd, argv[i], strlen(argv[i]));
97-
send_blocking(fd, QUOTE, sizeof(QUOTE)-1);
98-
send_blocking(fd, SPACE, sizeof(SPACE)-1);
99-
}
97+
if (argc == 2) {
98+
send_blocking(fd, argv[1], strlen(argv[1]));
99+
}
100+
100101
shutdown(fd, SHUT_WR);
101102

102103
int exit_code;

termux-am.sh.in

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
#!@TERMUX_PREFIX@/bin/bash
2+
# shellcheck disable=SC2039,SC2059
3+
version=1.02
4+
5+
6+
COMMAND_TYPE="am_command_run" # Default to "am_command_run"
7+
NOOP_COMMAND=0 # Default to 0
8+
9+
10+
##
11+
# main `[argument...]`
12+
##
13+
main() {
14+
15+
# Process the command arguments passed to termux-am if arguments received
16+
if [ $# -ne 0 ]; then
17+
process_arguments "$@" || return $?
18+
19+
[ "$NOOP_COMMAND" = "1" ] && return 0
20+
else
21+
show_help || return $?
22+
return 0
23+
fi
24+
25+
# TERMUX_APP_AM_SOCKET_SERVER_ENABLED=false is exported by termux-app
26+
# if server is disabled, so don't try to connect to server if its
27+
# disabled and save a few milliseconds and also warn user.
28+
if [[ "$TERMUX_APP_AM_SOCKET_SERVER_ENABLED" == "false" ]]; then
29+
echo "TermuxAm server is not enabled. Make sure \"run-termux-am-socket-server=false\" is not added to the \"~/.termux/termux.properties\" file" 1>&2
30+
return 1;
31+
fi
32+
33+
local am_command_string
34+
35+
if [[ "$COMMAND_TYPE" == "am_command_run" ]]; then
36+
if [ $# -ne 0 ]; then
37+
# Converts arguments array to a single string that can be reused as shell input
38+
# https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html#printf
39+
# https://github.com/bminor/bash/blob/bash-5.1/builtins/printf.def#L575
40+
# https://github.com/bminor/bash/blob/bash-5.1/lib/sh/strtrans.c
41+
# https://github.com/bminor/bash/blob/bash-5.1/lib/sh/shquote.c
42+
printf -v "am_command_string" "%q " "$@" || return $?
43+
fi
44+
elif [[ "$COMMAND_TYPE" == "am_command_help" ]]; then
45+
: # Do not pass any arguments so that 'am --help' is returned by server
46+
else
47+
echo "Invalid COMMAND_TYPE \"$COMMAND_TYPE\" set" 1>&2
48+
return 1
49+
fi
50+
51+
termux-am-socket "$am_command_string"
52+
53+
}
54+
55+
##
56+
# process_arguments `[argument...]`
57+
##
58+
process_arguments() {
59+
60+
local opt; local arg; local OPTARG; local OPTIND
61+
62+
# Parse options to termux-am command
63+
while getopts ":h-:" opt; do
64+
case "${opt}" in
65+
-)
66+
arg="${OPTARG#*=}"
67+
case "${OPTARG}" in
68+
am-help)
69+
COMMAND_TYPE="am_command_help"
70+
;;
71+
help)
72+
show_help
73+
NOOP_COMMAND=1; return 0
74+
;;
75+
version)
76+
echo "$version"
77+
NOOP_COMMAND=1; return 0
78+
;;
79+
*)
80+
:;;
81+
esac
82+
;;
83+
h)
84+
show_help
85+
NOOP_COMMAND=1; return 0
86+
;;
87+
\?)
88+
:;;
89+
esac
90+
done
91+
shift $((OPTIND - 1)) # Remove already processed arguments from argument list
92+
93+
return 0;
94+
95+
}
96+
97+
##
98+
# show_help
99+
##
100+
show_help() {
101+
102+
cat <<'HELP_EOF'
103+
104+
termux-am is a wrapper script that converts the arguments array
105+
passed to a single string that can be reused as shell input with the
106+
bash 'printf "%q"' built-in and passes the string to termux-am-socket.
107+
108+
109+
Usage:
110+
termux-am [command_options]
111+
112+
113+
Available command_options:
114+
[ -h | --help ] Display termux-am help screen.
115+
[ --am-help ] Display am command help screen.
116+
[ --version ] Display version.
117+
118+
119+
termux-am-socket sends the converted string to
120+
"@TERMUX_PREFIX@/../apps/termux-app/termux-am/am.sock"
121+
local unix socket server that is run by termux-app if enabled, which
122+
executes it as an android activity manager (am) command from within
123+
termux-app java process via termux/termux-am-library.
124+
125+
The termux-am provides similar functionality to "$PREFIX/bin/am"
126+
(and "/system/bin/am"), but should be faster since it does not
127+
require starting a dalvik vm for every command as done by "am" via
128+
termux/TermuxAm.
129+
130+
The server normally only allows termux-app user and root user to
131+
connect to it. If you run termux-am with root, then the am commands
132+
executed will be run as the termux user and its permissions,
133+
capabilities and selinux context instead of root.
134+
135+
The server is enabled by default and can be disabled by adding
136+
"run-termux-am-socket-server=false" to the
137+
"~/.termux/termux.properties"
138+
file. Changes require termux-app to be force stopped and restarted.
139+
140+
The current state of the server can be checked with the
141+
TERMUX_APP_AM_SOCKET_SERVER_ENABLED env variable.
142+
143+
HELP_EOF
144+
145+
echo "TERMUX_APP_AM_SOCKET_SERVER_ENABLED=$TERMUX_APP_AM_SOCKET_SERVER_ENABLED"
146+
147+
}
148+
149+
main "$@"

0 commit comments

Comments
 (0)