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 39static void usage(char *progname); 40static int do_monitor(int sock, int stop_after_cmd); 41static int do_cmd(int sock, int argc, char **argv); 42 43static constexpr int kCommandTimeoutMs = 20 * 1000; 44 45int 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 93static 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 119static 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 179static void usage(char *progname) { 180 LOG(INFO) << "Usage: " << progname << " [--wait] <monitor>|<cmd> [arg1] [arg2...]"; 181} 182