1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <unistd.h> 20 #include <string.h> 21 #include <signal.h> 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <stdlib.h> 25 #include <poll.h> 26 27 #include <sys/socket.h> 28 #include <sys/select.h> 29 #include <sys/time.h> 30 #include <sys/types.h> 31 #include <sys/un.h> 32 33 #include <android-base/stringprintf.h> 34 35 #include <cutils/sockets.h> 36 #include <private/android_filesystem_config.h> 37 38 static void usage(char *progname); 39 static int do_monitor(int sock, int stop_after_cmd); 40 static int do_cmd(int sock, int argc, char **argv); 41 42 static constexpr int kCommandTimeoutMs = 20 * 1000; 43 44 int main(int argc, char **argv) { 45 int sock; 46 int wait_for_socket; 47 char *progname; 48 49 progname = argv[0]; 50 51 wait_for_socket = argc > 1 && strcmp(argv[1], "--wait") == 0; 52 if (wait_for_socket) { 53 argv++; 54 argc--; 55 } 56 57 if (argc < 2) { 58 usage(progname); 59 exit(5); 60 } 61 62 const char* sockname = "vold"; 63 if (!strcmp(argv[1], "cryptfs")) { 64 sockname = "cryptd"; 65 } 66 67 while ((sock = socket_local_client(sockname, 68 ANDROID_SOCKET_NAMESPACE_RESERVED, 69 SOCK_STREAM)) < 0) { 70 if (!wait_for_socket) { 71 fprintf(stdout, "Error connecting to %s: %s\n", sockname, strerror(errno)); 72 exit(4); 73 } else { 74 usleep(10000); 75 } 76 } 77 78 if (!strcmp(argv[1], "monitor")) { 79 exit(do_monitor(sock, 0)); 80 } else { 81 exit(do_cmd(sock, argc, argv)); 82 } 83 } 84 85 static int do_cmd(int sock, int argc, char **argv) { 86 int seq = getpid(); 87 88 std::string cmd(android::base::StringPrintf("%d ", seq)); 89 for (int i = 1; i < argc; i++) { 90 if (!strchr(argv[i], ' ')) { 91 cmd.append(argv[i]); 92 } else { 93 cmd.push_back('\"'); 94 cmd.append(argv[i]); 95 cmd.push_back('\"'); 96 } 97 98 if (i < argc - 1) { 99 cmd.push_back(' '); 100 } 101 } 102 103 if (TEMP_FAILURE_RETRY(write(sock, cmd.c_str(), cmd.length() + 1)) < 0) { 104 fprintf(stderr, "Failed to write command: %s\n", strerror(errno)); 105 return errno; 106 } 107 108 return do_monitor(sock, seq); 109 } 110 111 static int do_monitor(int sock, int stop_after_seq) { 112 char buffer[4096]; 113 int timeout = kCommandTimeoutMs; 114 115 if (stop_after_seq == 0) { 116 fprintf(stderr, "Connected to vold\n"); 117 timeout = -1; 118 } 119 120 while (1) { 121 struct pollfd poll_sock = { sock, POLLIN, 0 }; 122 int rc = TEMP_FAILURE_RETRY(poll(&poll_sock, 1, timeout)); 123 if (rc == 0) { 124 fprintf(stderr, "Timeout waiting for %d\n", stop_after_seq); 125 return ETIMEDOUT; 126 } else if (rc < 0) { 127 fprintf(stderr, "Failed during poll: %s\n", strerror(errno)); 128 return errno; 129 } 130 131 if (!(poll_sock.revents & POLLIN)) { 132 fprintf(stderr, "No data; trying again\n"); 133 continue; 134 } 135 136 memset(buffer, 0, sizeof(buffer)); 137 rc = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer))); 138 if (rc == 0) { 139 fprintf(stderr, "Lost connection, did vold crash?\n"); 140 return ECONNRESET; 141 } else if (rc < 0) { 142 fprintf(stderr, "Error reading data: %s\n", strerror(errno)); 143 return errno; 144 } 145 146 int offset = 0; 147 for (int i = 0; i < rc; i++) { 148 if (buffer[i] == '\0') { 149 char* res = buffer + offset; 150 fprintf(stdout, "%s\n", res); 151 152 int code = atoi(strtok(res, " ")); 153 if (code >= 200 && code < 600) { 154 int seq = atoi(strtok(nullptr, " ")); 155 if (seq == stop_after_seq) { 156 if (code == 200) { 157 return 0; 158 } else { 159 return code; 160 } 161 } 162 } 163 164 offset = i + 1; 165 } 166 } 167 } 168 return EIO; 169 } 170 171 static void usage(char *progname) { 172 fprintf(stderr, 173 "Usage: %s [--wait] <monitor>|<cmd> [arg1] [arg2...]\n", progname); 174 } 175