bugreportz.cpp revision ceeb64281d012cfac99827adbcdb5800b2ce0542
1/* 2 * Copyright (C) 2016 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 <errno.h> 18#include <getopt.h> 19#include <stdio.h> 20#include <sys/socket.h> 21#include <sys/types.h> 22#include <unistd.h> 23 24#include <cutils/properties.h> 25#include <cutils/sockets.h> 26 27static constexpr char VERSION[] = "1.0"; 28 29static void show_usage() { 30 fprintf(stderr, 31 "usage: bugreportz [-h | -v]\n" 32 " -h: to display this help message\n" 33 " -v: to display the version\n" 34 " or no arguments to generate a zipped bugreport\n"); 35} 36 37static void show_version() { 38 fprintf(stderr, "%s\n", VERSION); 39} 40 41int main(int argc, char *argv[]) { 42 43 if (argc > 1) { 44 /* parse arguments */ 45 int c; 46 while ((c = getopt(argc, argv, "vh")) != -1) { 47 switch (c) { 48 case 'h': 49 show_usage(); 50 return EXIT_SUCCESS; 51 case 'v': 52 show_version(); 53 return EXIT_SUCCESS; 54 default: 55 show_usage(); 56 return EXIT_FAILURE; 57 } 58 } 59 // passed an argument not starting with - 60 if (optind > 1 || argv[optind] != nullptr) { 61 show_usage(); 62 return EXIT_FAILURE; 63 } 64 } 65 66 // TODO: code below was copy-and-pasted from bugreport.cpp (except by the timeout value); 67 // should be reused instead. 68 69 // Start the dumpstatez service. 70 property_set("ctl.start", "dumpstatez"); 71 72 // Socket will not be available until service starts. 73 int s; 74 for (int i = 0; i < 20; i++) { 75 s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); 76 if (s >= 0) 77 break; 78 // Try again in 1 second. 79 sleep(1); 80 } 81 82 if (s == -1) { 83 printf("Failed to connect to dumpstatez service: %s\n", strerror(errno)); 84 return EXIT_FAILURE; 85 } 86 87 // Set a timeout so that if nothing is read in 10 minutes, we'll stop 88 // reading and quit. No timeout in dumpstate is longer than 60 seconds, 89 // so this gives lots of leeway in case of unforeseen time outs. 90 struct timeval tv; 91 tv.tv_sec = 10 * 60; 92 tv.tv_usec = 0; 93 if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { 94 printf("WARNING: Cannot set socket timeout: %s\n", strerror(errno)); 95 } 96 97 while (1) { 98 char buffer[65536]; 99 ssize_t bytes_read = TEMP_FAILURE_RETRY( 100 read(s, buffer, sizeof(buffer))); 101 if (bytes_read == 0) { 102 break; 103 } else if (bytes_read == -1) { 104 // EAGAIN really means time out, so change the errno. 105 if (errno == EAGAIN) { 106 errno = ETIMEDOUT; 107 } 108 printf("\nBugreport read terminated abnormally (%s).\n", 109 strerror(errno)); 110 break; 111 } 112 113 ssize_t bytes_to_send = bytes_read; 114 ssize_t bytes_written; 115 do { 116 bytes_written = TEMP_FAILURE_RETRY( 117 write(STDOUT_FILENO, buffer + bytes_read - bytes_to_send, 118 bytes_to_send)); 119 if (bytes_written == -1) { 120 printf( 121 "Failed to write data to stdout: read %zd, trying to send %zd (%s)\n", 122 bytes_read, bytes_to_send, strerror(errno)); 123 return EXIT_FAILURE; 124 } 125 bytes_to_send -= bytes_written; 126 } while (bytes_written != 0 && bytes_to_send > 0); 127 } 128 129 close(s); 130 return EXIT_SUCCESS; 131} 132