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 25 #include <sys/socket.h> 26 #include <sys/select.h> 27 #include <sys/time.h> 28 #include <sys/types.h> 29 #include <sys/un.h> 30 31 #include <cutils/sockets.h> 32 #include <private/android_filesystem_config.h> 33 34 static void usage(char *progname); 35 static int do_monitor(int sock, int stop_after_cmd); 36 static int do_cmd(int sock, int argc, char **argv); 37 38 int main(int argc, char **argv) { 39 int sock; 40 int cmdOffset = 0; 41 42 if (argc < 2) 43 usage(argv[0]); 44 45 // try interpreting the first arg as the socket name - if it fails go back to netd 46 47 if ((sock = socket_local_client(argv[1], 48 ANDROID_SOCKET_NAMESPACE_RESERVED, 49 SOCK_STREAM)) < 0) { 50 if ((sock = socket_local_client("netd", 51 ANDROID_SOCKET_NAMESPACE_RESERVED, 52 SOCK_STREAM)) < 0) { 53 fprintf(stderr, "Error connecting (%s)\n", strerror(errno)); 54 exit(4); 55 } 56 } else { 57 if (argc < 3) usage(argv[0]); 58 printf("Using alt socket %s\n", argv[1]); 59 cmdOffset = 1; 60 } 61 62 if (!strcmp(argv[1+cmdOffset], "monitor")) 63 exit(do_monitor(sock, 0)); 64 exit(do_cmd(sock, argc-cmdOffset, &(argv[cmdOffset]))); 65 } 66 67 static int do_cmd(int sock, int argc, char **argv) { 68 char *final_cmd; 69 char *conv_ptr; 70 int i; 71 72 /* Check if 1st arg is cmd sequence number */ 73 strtol(argv[1], &conv_ptr, 10); 74 if (conv_ptr == argv[1]) { 75 final_cmd = strdup("0 "); 76 } else { 77 final_cmd = strdup(""); 78 } 79 if (final_cmd == NULL) { 80 int res = errno; 81 perror("strdup failed"); 82 return res; 83 } 84 85 for (i = 1; i < argc; i++) { 86 if (strchr(argv[i], '"')) { 87 perror("argument with embedded quotes not allowed"); 88 free(final_cmd); 89 return 1; 90 } 91 bool needs_quoting = strchr(argv[i], ' '); 92 const char *format = needs_quoting ? "%s\"%s\"%s" : "%s%s%s"; 93 char *tmp_final_cmd; 94 95 if (asprintf(&tmp_final_cmd, format, final_cmd, argv[i], 96 (i == (argc - 1)) ? "" : " ") < 0) { 97 int res = errno; 98 perror("failed asprintf"); 99 free(final_cmd); 100 return res; 101 } 102 free(final_cmd); 103 final_cmd = tmp_final_cmd; 104 } 105 106 if (write(sock, final_cmd, strlen(final_cmd) + 1) < 0) { 107 int res = errno; 108 perror("write"); 109 free(final_cmd); 110 return res; 111 } 112 free(final_cmd); 113 114 return do_monitor(sock, 1); 115 } 116 117 static int do_monitor(int sock, int stop_after_cmd) { 118 char *buffer = (char *)malloc(4096); 119 120 if (!stop_after_cmd) 121 printf("[Connected to Netd]\n"); 122 123 while(1) { 124 fd_set read_fds; 125 struct timeval to; 126 int rc = 0; 127 128 to.tv_sec = 10; 129 to.tv_usec = 0; 130 131 FD_ZERO(&read_fds); 132 FD_SET(sock, &read_fds); 133 134 rc = TEMP_FAILURE_RETRY(select(sock +1, &read_fds, NULL, NULL, &to)); 135 if (rc < 0) { 136 int res = errno; 137 fprintf(stderr, "Error in select (%s)\n", strerror(res)); 138 free(buffer); 139 return res; 140 } 141 if (rc == 0) { 142 continue; 143 } 144 if (!FD_ISSET(sock, &read_fds)) { 145 continue; 146 } 147 148 memset(buffer, 0, 4096); 149 if ((rc = read(sock, buffer, 4096)) <= 0) { 150 int res = errno; 151 if (rc == 0) 152 fprintf(stderr, "Lost connection to Netd - did it crash?\n"); 153 else 154 fprintf(stderr, "Error reading data (%s)\n", strerror(res)); 155 free(buffer); 156 if (rc == 0) 157 return ECONNRESET; 158 return res; 159 } 160 161 int offset = 0; 162 int i = 0; 163 164 for (i = 0; i < rc; i++) { 165 if (buffer[i] == '\0') { 166 int code; 167 char tmp[4]; 168 169 strncpy(tmp, buffer + offset, 3); 170 tmp[3] = '\0'; 171 code = atoi(tmp); 172 173 printf("%s\n", buffer + offset); 174 if (stop_after_cmd) { 175 if (code >= 200 && code < 600) 176 return 0; 177 } 178 offset = i + 1; 179 } 180 } 181 } 182 free(buffer); 183 return 0; 184 } 185 186 static void usage(char *progname) { 187 fprintf(stderr, "Usage: %s [<sockname>] ([monitor] | ([<cmd_seq_num>] <cmd> [arg ...]))\n", progname); 188 exit(1); 189 } 190