|
1 | | -/* termux-api.c - helper binary for calling termux api classes |
2 | | - * Usage: termux-api ${API_METHOD} ${ADDITIONAL_FLAGS} |
3 | | - * This executes |
4 | | - * am broadcast com.termux.api/.TermuxApiReceiver \ |
5 | | - * --es socket_input ${INPUT_SOCKET} \ |
6 | | - * --es socket_output ${OUTPUT_SOCKET} \ |
7 | | - * --es api_method ${API_METHOD} \ |
8 | | - * ${ADDITIONAL_FLAGS} |
9 | | - * where ${INPUT_SOCKET} and ${OUTPUT_SOCKET} are addresses to linux |
10 | | - * abstract namespace sockets, used to pass on stdin to the java |
11 | | - * implementation and pass back output from java to stdout. |
12 | | - */ |
13 | 1 | #define _POSIX_SOURCE |
14 | 2 | #define _GNU_SOURCE |
15 | 3 | #include <fcntl.h> |
|
20 | 8 | #include <stdio.h> |
21 | 9 | #include <stdlib.h> |
22 | 10 | #include <string.h> |
| 11 | +#include <sys/endian.h> |
23 | 12 | #include <sys/socket.h> |
24 | 13 | #include <sys/stat.h> |
25 | 14 | #include <sys/types.h> |
26 | 15 | #include <sys/un.h> |
27 | 16 | #include <time.h> |
28 | 17 | #include <unistd.h> |
29 | 18 |
|
| 19 | +#include "termux-api.h" |
| 20 | + |
| 21 | +#ifndef PREFIX |
| 22 | +# define PREFIX "/data/data/com.termux/files/usr" |
| 23 | +#endif |
| 24 | + |
30 | 25 | // Function which execs "am broadcast ..". |
31 | 26 | _Noreturn void exec_am_broadcast(int argc, char** argv, |
32 | 27 | char* input_address_string, |
@@ -77,6 +72,9 @@ _Noreturn void exec_callback(int fd) |
77 | 72 | if (asprintf(&fds, "%d", fd) == -1) |
78 | 73 | perror("asprintf"); |
79 | 74 |
|
| 75 | + /* TERMUX_EXPORT_FD and TERMUX_USB_FD are (currently) specific for |
| 76 | + termux-usb, so there's some room for improvement here (this |
| 77 | + function should be generic) */ |
80 | 78 | char errmsg[256]; |
81 | 79 | char *export_to_env = getenv("TERMUX_EXPORT_FD"); |
82 | 80 | if (export_to_env && strncmp(export_to_env, "true", 4) == 0) { |
@@ -154,70 +152,82 @@ int transmit_socket_to_stdout(int input_socket_fd) { |
154 | 152 | return fd; |
155 | 153 | } |
156 | 154 |
|
157 | | -int main(int argc, char** argv) { |
| 155 | +int run_api_command(int argc, char **argv) { |
158 | 156 | // Do not transform children into zombies when they terminate: |
159 | 157 | struct sigaction sigchld_action = { |
160 | 158 | .sa_handler = SIG_DFL, |
161 | 159 | .sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_NOCLDWAIT |
162 | 160 | }; |
163 | 161 | sigaction(SIGCHLD, &sigchld_action, NULL); |
164 | 162 |
|
165 | | - char input_address_string[100]; // This program reads from it. |
166 | | - char output_address_string[100]; // This program writes to it. |
| 163 | + char input_addr_str[100]; // This program reads from it. |
| 164 | + char output_addr_str[100]; // This program writes to it. |
167 | 165 |
|
168 | | - generate_uuid(input_address_string); |
169 | | - generate_uuid(output_address_string); |
| 166 | + generate_uuid(input_addr_str); |
| 167 | + generate_uuid(output_addr_str); |
170 | 168 |
|
171 | | - struct sockaddr_un input_address = { .sun_family = AF_UNIX }; |
172 | | - struct sockaddr_un output_address = { .sun_family = AF_UNIX }; |
| 169 | + struct sockaddr_un input_addr = { .sun_family = AF_UNIX }; |
| 170 | + struct sockaddr_un output_addr = { .sun_family = AF_UNIX }; |
173 | 171 | // Leave struct sockaddr_un.sun_path[0] as 0 and use the UUID |
174 | 172 | // string as abstract linux namespace: |
175 | | - strncpy(&input_address.sun_path[1], input_address_string, |
176 | | - strlen(input_address_string)); |
177 | | - strncpy(&output_address.sun_path[1], output_address_string, |
178 | | - strlen(output_address_string)); |
| 173 | + strncpy(&input_addr.sun_path[1], input_addr_str, strlen(input_addr_str)); |
| 174 | + strncpy(&output_addr.sun_path[1], output_addr_str, strlen(output_addr_str)); |
179 | 175 |
|
180 | 176 | int input_server_socket = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); |
181 | | - if (input_server_socket == -1) { perror("socket()"); return 1; } |
| 177 | + if (input_server_socket == -1) { |
| 178 | + perror("socket()"); |
| 179 | + return -1; |
| 180 | + } |
182 | 181 | int output_server_socket = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); |
183 | | - if (output_server_socket == -1) { perror("socket()"); return 1; } |
| 182 | + if (output_server_socket == -1) { |
| 183 | + perror("socket()"); |
| 184 | + return -1; |
| 185 | + } |
184 | 186 |
|
185 | | - int ret = bind(input_server_socket, (struct sockaddr*) &input_address, |
186 | | - sizeof(sa_family_t) + strlen(input_address_string) + 1); |
| 187 | + int ret; |
| 188 | + ret = bind(input_server_socket, (struct sockaddr*) &input_addr, |
| 189 | + sizeof(sa_family_t) + strlen(input_addr_str) + 1); |
187 | 190 | if (ret == -1) { |
188 | 191 | perror("bind(input)"); |
189 | | - return 1; |
| 192 | + return ret; |
190 | 193 | } |
191 | 194 |
|
192 | | - ret = bind(output_server_socket, (struct sockaddr*) &output_address, |
193 | | - sizeof(sa_family_t) + strlen(output_address_string) + 1); |
| 195 | + ret = bind(output_server_socket, (struct sockaddr*) &output_addr, |
| 196 | + sizeof(sa_family_t) + strlen(output_addr_str) + 1); |
194 | 197 | if (ret == -1) { |
195 | 198 | perror("bind(output)"); |
196 | | - return 1; |
| 199 | + return ret; |
| 200 | + } |
| 201 | + |
| 202 | + if (listen(input_server_socket, 1) == -1) { |
| 203 | + perror("listen()"); |
| 204 | + return -1; |
197 | 205 | } |
198 | 206 |
|
199 | | - if (listen(input_server_socket, 1) == -1) { perror("listen()"); return 1; } |
200 | | - if (listen(output_server_socket, 1) == -1) { perror("listen()"); return 1; } |
| 207 | + if (listen(output_server_socket, 1) == -1) { |
| 208 | + perror("listen()"); |
| 209 | + return -1; |
| 210 | + } |
201 | 211 |
|
202 | 212 | pid_t fork_result = fork(); |
203 | | - switch (fork_result) { |
204 | | - case -1: perror("fork()"); return 1; |
205 | | - case 0: exec_am_broadcast(argc, argv, input_address_string, |
206 | | - output_address_string); |
207 | | - } |
| 213 | + if (fork_result == -1) { |
| 214 | + perror("fork()"); |
| 215 | + return -1; |
| 216 | + } else if (fork_result == 0) |
| 217 | + exec_am_broadcast(argc, argv, input_addr_str, output_addr_str); |
208 | 218 |
|
209 | 219 | struct sockaddr_un remote_addr; |
210 | 220 | socklen_t addrlen = sizeof(remote_addr); |
211 | | - int input_client_socket = accept(input_server_socket, (struct sockaddr*) |
212 | | - &remote_addr, &addrlen); |
| 221 | + int input_client_socket = accept(input_server_socket, |
| 222 | + (struct sockaddr*) &remote_addr, |
| 223 | + &addrlen); |
213 | 224 |
|
214 | 225 | pthread_t transmit_thread; |
215 | 226 | pthread_create(&transmit_thread, NULL, transmit_stdin_to_socket, |
216 | 227 | &output_server_socket); |
217 | 228 |
|
| 229 | + /* Device has been opened, time to actually get the fd */ |
218 | 230 | int fd = transmit_socket_to_stdout(input_client_socket); |
219 | 231 | close(input_client_socket); |
220 | | - if (fd != -1) { exec_callback(fd); } |
221 | | - |
222 | | - return 0; |
| 232 | + return fd; |
223 | 233 | } |
0 commit comments