1 /*
2 * Copyright (C) 2019 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 <gflags/gflags.h>
18 #include <android-base/logging.h>
19
20 #include <chrono>
21 #include <fstream>
22 #include <iomanip>
23 #include <sstream>
24
25 #include "common/libs/fs/shared_fd.h"
26 #include "common/libs/utils/flag_parser.h"
27 #include "common/libs/utils/shared_fd_flag.h"
28 #include "host/libs/config/logging.h"
29
30 namespace cuttlefish {
31
32 static uint num_tombstones_in_last_second = 0;
33 static std::string last_tombstone_name = "";
34
next_tombstone_path(const std::string & tombstone_dir)35 static std::string next_tombstone_path(const std::string& tombstone_dir) {
36 auto in_time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
37 std::stringstream ss;
38 ss << tombstone_dir << "/tombstone_"
39 << std::put_time(std::gmtime(&in_time_t), "%Y-%m-%d-%H%M%S");
40 auto retval = ss.str();
41
42 // Gives tombstones unique names
43 if(retval == last_tombstone_name) {
44 num_tombstones_in_last_second++;
45 retval += "_" + std::to_string(num_tombstones_in_last_second);
46 } else {
47 last_tombstone_name = retval;
48 num_tombstones_in_last_second = 0;
49 }
50
51 LOG(DEBUG) << "Creating " << retval;
52 return retval;
53 }
54
55 static constexpr size_t CHUNK_RECV_MAX_LEN = 1024;
56
TombstoneReceiverMain(int argc,char ** argv)57 int TombstoneReceiverMain(int argc, char** argv) {
58 DefaultSubprocessLogging(argv);
59
60 std::vector<Flag> flags;
61
62 std::string tombstone_dir;
63 flags.emplace_back(GflagsCompatFlag("tombstone_dir", tombstone_dir)
64 .Help("directory to write out tombstones in"));
65
66 SharedFD server_fd;
67 flags.emplace_back(
68 SharedFDFlag("server_fd", server_fd)
69 .Help("File descriptor to an already created vsock server"));
70
71 flags.emplace_back(HelpFlag(flags));
72 flags.emplace_back(UnexpectedArgumentGuard());
73
74 std::vector<std::string> args =
75 ArgsToVec(argc - 1, argv + 1); // Skip argv[0]
76 CHECK(ParseFlags(flags, args)) << "Could not process command line flags.";
77
78 CHECK(server_fd->IsOpen()) << "Did not receive a server fd";
79
80 LOG(DEBUG) << "Host is starting server on port "
81 << server_fd->VsockServerPort();
82
83 // Server loop
84 while (true) {
85 auto conn = SharedFD::Accept(*server_fd);
86 std::ofstream file(next_tombstone_path(tombstone_dir),
87 std::ofstream::out | std::ofstream::binary);
88
89 while (file.is_open()) {
90 char buff[CHUNK_RECV_MAX_LEN];
91 auto bytes_read = conn->Read(buff, sizeof(buff));
92 if (bytes_read <= 0) {
93 // reset the other side if it's still connected
94 break;
95 } else {
96 file.write(buff, bytes_read);
97 }
98 }
99 }
100
101 return 0;
102 }
103
104 } // namespace cuttlefish
105
main(int argc,char ** argv)106 int main(int argc, char** argv) {
107 return cuttlefish::TombstoneReceiverMain(argc, argv);
108 }
109