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/logging.h> 34 #include <android-base/stringprintf.h> 35 36 #include <cutils/sockets.h> 37 #include <private/android_filesystem_config.h> 38 39 static void usage(char *progname); 40 static int do_monitor(int sock, int stop_after_cmd); 41 static int do_cmd(int sock, int argc, char **argv); 42 43 static constexpr int kCommandTimeoutMs = 20 * 1000; 44 45 int main(int argc, char **argv) { 46 int sock; 47 int wait_for_socket; 48 char *progname; 49 50 progname = argv[0]; 51 52 if (getppid() == 1) { 53 // If init is calling us then it's during boot and we should log to kmsg 54 android::base::InitLogging(argv, &android::base::KernelLogger); 55 } else { 56 android::base::InitLogging(argv, &android::base::StderrLogger); 57 } 58 59 wait_for_socket = argc > 1 && strcmp(argv[1], "--wait") == 0; 60 if (wait_for_socket) { 61 argv++; 62 argc--; 63 } 64 65 if (argc < 2) { 66 usage(progname); 67 exit(5); 68 } 69 70 const char* sockname = "vold"; 71 if (!strcmp(argv[1], "cryptfs")) { 72 sockname = "cryptd"; 73 } 74 75 while ((sock = socket_local_client(sockname, 76 ANDROID_SOCKET_NAMESPACE_RESERVED, 77 SOCK_STREAM)) < 0) { 78 if (!wait_for_socket) { 79 PLOG(ERROR) << "Error connecting to " << sockname; 80 exit(4); 81 } else { 82 usleep(10000); 83 } 84 } 85 86 if (!strcmp(argv[1], "monitor")) { 87 exit(do_monitor(sock, 0)); 88 } else { 89 exit(do_cmd(sock, argc, argv)); 90 } 91 } 92 93 static int do_cmd(int sock, int argc, char **argv) { 94 int seq = getpid(); 95 96 std::string cmd(android::base::StringPrintf("%d ", seq)); 97 for (int i = 1; i < argc; i++) { 98 if (!strchr(argv[i], ' ')) { 99 cmd.append(argv[i]); 100 } else { 101 cmd.push_back('\"'); 102 cmd.append(argv[i]); 103 cmd.push_back('\"'); 104 } 105 106 if (i < argc - 1) { 107 cmd.push_back(' '); 108 } 109 } 110 111 if (TEMP_FAILURE_RETRY(write(sock, cmd.c_str(), cmd.length() + 1)) < 0) { 112 PLOG(ERROR) << "Failed to write command"; 113 return errno; 114 } 115 116 return do_monitor(sock, seq); 117 } 118 119 static int do_monitor(int sock, int stop_after_seq) { 120 char buffer[4096]; 121 int timeout = kCommandTimeoutMs; 122 123 if (stop_after_seq == 0) { 124 LOG(INFO) << "Connected to vold"; 125 timeout = -1; 126 } 127 128 while (1) { 129 struct pollfd poll_sock = { sock, POLLIN, 0 }; 130 int rc = TEMP_FAILURE_RETRY(poll(&poll_sock, 1, timeout)); 131 if (rc == 0) { 132 LOG(ERROR) << "Timeout waiting for " << stop_after_seq; 133 return ETIMEDOUT; 134 } else if (rc < 0) { 135 PLOG(ERROR) << "Failed during poll"; 136 return errno; 137 } 138 139 if (!(poll_sock.revents & POLLIN)) { 140 LOG(INFO) << "No data; trying again"; 141 continue; 142 } 143 144 memset(buffer, 0, sizeof(buffer)); 145 rc = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer))); 146 if (rc == 0) { 147 LOG(ERROR) << "Lost connection, did vold crash?"; 148 return ECONNRESET; 149 } else if (rc < 0) { 150 PLOG(ERROR) << "Error reading data"; 151 return errno; 152 } 153 154 int offset = 0; 155 for (int i = 0; i < rc; i++) { 156 if (buffer[i] == '\0') { 157 char* res = buffer + offset; 158 fprintf(stdout, "%s\n", res); 159 160 int code = atoi(strtok(res, " ")); 161 if (code >= 200 && code < 600) { 162 int seq = atoi(strtok(nullptr, " ")); 163 if (seq == stop_after_seq) { 164 if (code == 200) { 165 return 0; 166 } else { 167 return code; 168 } 169 } 170 } 171 172 offset = i + 1; 173 } 174 } 175 } 176 return EIO; 177 } 178 179 static void usage(char *progname) { 180 LOG(INFO) << "Usage: " << progname << " [--wait] <monitor>|<cmd> [arg1] [arg2...]"; 181 } 182