blob: be19d45d9a656f8d55d8579098781148d241950b [file] [log] [blame]
Austin Schuhf2a50ba2016-12-24 16:16:26 -08001#include <dirent.h>
2#include <errno.h>
3#include <fcntl.h>
4#include <mntent.h>
5#include <pwd.h>
brians343bc112013-02-10 01:53:46 +00006#include <stdio.h>
7#include <stdlib.h>
brians343bc112013-02-10 01:53:46 +00008#include <string.h>
brians343bc112013-02-10 01:53:46 +00009#include <sys/types.h>
Austin Schuhf2a50ba2016-12-24 16:16:26 -080010#include <time.h>
11#include <unistd.h>
12#include <string>
brians343bc112013-02-10 01:53:46 +000013
Austin Schuhf2a50ba2016-12-24 16:16:26 -080014#include <chrono>
brians343bc112013-02-10 01:53:46 +000015#include <map>
Brian Silverman88471dc2014-02-15 22:35:42 -080016#include <unordered_set>
brians343bc112013-02-10 01:53:46 +000017
John Park33858a32018-09-28 23:05:48 -070018#include "aos/die.h"
19#include "aos/logging/binary_log_file.h"
20#include "aos/logging/implementations.h"
21#include "aos/queue_types.h"
22#include "aos/time/time.h"
John Park398c74a2018-10-20 21:17:39 -070023#include "aos/configuration.h"
24#include "aos/init.h"
25#include "aos/ipc_lib/queue.h"
brians343bc112013-02-10 01:53:46 +000026
Brian Silvermanf665d692013-02-17 22:11:39 -080027namespace aos {
28namespace logging {
Brian Silverman14fd0fb2014-01-14 21:42:01 -080029namespace linux_code {
Brian Silvermanf665d692013-02-17 22:11:39 -080030namespace {
brians343bc112013-02-10 01:53:46 +000031
Brian Silvermanf5ca4d02015-03-01 16:52:24 -050032void CheckTypeWritten(uint32_t type_id, LogFileWriter *writer,
33 ::std::unordered_set<uint32_t> *written_type_ids) {
34 if (written_type_ids->count(type_id) > 0) return;
Brian Silverman88471dc2014-02-15 22:35:42 -080035 if (MessageType::IsPrimitive(type_id)) return;
36
37 const MessageType &type = type_cache::Get(type_id);
38 for (int i = 0; i < type.number_fields; ++i) {
Brian Silvermanf5ca4d02015-03-01 16:52:24 -050039 CheckTypeWritten(type.fields[i]->type, writer, written_type_ids);
Brian Silverman88471dc2014-02-15 22:35:42 -080040 }
41
42 char buffer[1024];
43 ssize_t size = type.Serialize(buffer, sizeof(buffer));
44 if (size == -1) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070045 AOS_LOG(WARNING, "%zu-byte buffer is too small to serialize type %s\n",
46 sizeof(buffer), type.name.c_str());
Brian Silverman88471dc2014-02-15 22:35:42 -080047 return;
48 }
49 LogFileMessageHeader *const output =
Brian Silvermanf5ca4d02015-03-01 16:52:24 -050050 writer->GetWritePosition(sizeof(LogFileMessageHeader) + size);
Brian Silverman88471dc2014-02-15 22:35:42 -080051
52 output->time_sec = output->time_nsec = 0;
53 output->source = getpid();
54 output->name_size = 0;
55 output->sequence = 0;
56 output->level = FATAL;
57
58 memcpy(output + 1, buffer, size);
59 output->message_size = size;
60
61 output->type = LogFileMessageHeader::MessageType::kStructType;
62 futex_set(&output->marker);
Brian Silvermanf7780312014-02-16 17:26:15 -080063
Brian Silvermanf5ca4d02015-03-01 16:52:24 -050064 written_type_ids->insert(type_id);
Brian Silverman88471dc2014-02-15 22:35:42 -080065}
66
Ben Fredricksona04c1752014-03-02 22:54:07 +000067void AllocateLogName(char **filename, const char *directory) {
68 int fileindex = 0;
Brian Silverman2adb1452014-05-13 08:43:38 -070069 DIR *const d = opendir(directory);
70 if (d == nullptr) {
71 PDie("could not open directory %s", directory);
72 }
73 int index = 0;
74 while (true) {
75 errno = 0;
76 struct dirent *const dir = readdir(d);
77 if (dir == nullptr) {
78 if (errno == 0) {
79 break;
80 } else {
Austin Schuhf257f3c2019-10-27 21:00:43 -070081 AOS_PLOG(FATAL, "readdir(%p) failed", d);
Brian Silverman2adb1452014-05-13 08:43:38 -070082 }
83 } else {
Ben Fredricksona04c1752014-03-02 22:54:07 +000084 if (sscanf(dir->d_name, "aos_log-%d", &index) == 1) {
85 if (index >= fileindex) {
86 fileindex = index + 1;
87 }
88 }
89 }
Ben Fredricksona04c1752014-03-02 22:54:07 +000090 }
Brian Silverman2adb1452014-05-13 08:43:38 -070091 closedir(d);
Ben Fredricksona04c1752014-03-02 22:54:07 +000092
93 char previous[512];
Brian Silvermanf574e732014-03-02 17:35:04 -080094 ::std::string path = ::std::string(directory) + "/aos_log-current";
95 ssize_t len = ::readlink(path.c_str(), previous, sizeof(previous));
Ben Fredricksona04c1752014-03-02 22:54:07 +000096 if (len != -1) {
97 previous[len] = '\0';
98 } else {
Brian Silvermanf574e732014-03-02 17:35:04 -080099 previous[0] = '\0';
Austin Schuhf257f3c2019-10-27 21:00:43 -0700100 AOS_LOG(INFO, "Could not find aos_log-current\n");
Brian Silvermanf574e732014-03-02 17:35:04 -0800101 printf("Could not find aos_log-current\n");
Ben Fredricksona04c1752014-03-02 22:54:07 +0000102 }
Brian Silverman09e85ed2014-03-15 08:26:29 -0700103 if (asprintf(filename, "%s/aos_log-%03d", directory, fileindex) == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700104 PDie("couldn't create final name");
Ben Fredricksona04c1752014-03-02 22:54:07 +0000105 }
Austin Schuhf257f3c2019-10-27 21:00:43 -0700106 AOS_LOG(INFO,
107 "Created log file (aos_log-%d) in directory (%s). Previous file "
108 "was (%s).\n",
109 fileindex, directory, previous);
Brian Silvermanf574e732014-03-02 17:35:04 -0800110 printf("Created log file (aos_log-%d) in directory (%s). Previous file was "
111 "(%s).\n",
112 fileindex, directory, previous);
Ben Fredricksona04c1752014-03-02 22:54:07 +0000113}
114
Brian Silverman9f330492015-03-01 17:37:02 -0500115#ifdef AOS_ARCHITECTURE_arm_frc
Austin Schuhc5982cb2014-10-25 18:04:36 -0700116bool FoundThumbDrive(const char *path) {
117 FILE *mnt_fp = setmntent("/etc/mtab", "r");
118 if (mnt_fp == nullptr) {
119 Die("Could not open /etc/mtab");
120 }
121
122 bool found = false;
123 struct mntent mntbuf;
124 char buf[256];
125 while (!found) {
126 struct mntent *mount_list = getmntent_r(mnt_fp, &mntbuf, buf, sizeof(buf));
127 if (mount_list == nullptr) {
128 break;
129 }
130 if (strcmp(mount_list->mnt_dir, path) == 0) {
131 found = true;
132 }
133 }
134 endmntent(mnt_fp);
135 return found;
136}
137
138bool FindDevice(char *device, size_t device_size) {
139 char test_device[10];
140 for (char i = 'a'; i < 'z'; ++i) {
141 snprintf(test_device, sizeof(test_device), "/dev/sd%c", i);
Austin Schuhf257f3c2019-10-27 21:00:43 -0700142 AOS_LOG(INFO, "Trying to access %s\n", test_device);
Austin Schuhc5982cb2014-10-25 18:04:36 -0700143 if (access(test_device, F_OK) != -1) {
144 snprintf(device, device_size, "sd%c", i);
145 return true;
146 }
147 }
148 return false;
149}
150#endif
151
Brian Silvermanab6615c2013-03-05 20:29:29 -0800152int BinaryLogReaderMain() {
Brian Silvermanf665d692013-02-17 22:11:39 -0800153 InitNRT();
brians343bc112013-02-10 01:53:46 +0000154
Brian Silverman9f330492015-03-01 17:37:02 -0500155#ifdef AOS_ARCHITECTURE_arm_frc
Austin Schuhc5982cb2014-10-25 18:04:36 -0700156 char folder[128];
157
158 {
159 char dev_name[8];
160 while (!FindDevice(dev_name, sizeof(dev_name))) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700161 AOS_LOG(INFO, "Waiting for a device\n");
Austin Schuhc5982cb2014-10-25 18:04:36 -0700162 printf("Waiting for a device\n");
163 sleep(5);
164 }
165 snprintf(folder, sizeof(folder), "/media/%s1", dev_name);
166 while (!FoundThumbDrive(folder)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700167 AOS_LOG(INFO, "Waiting for %s\n", folder);
Austin Schuhc5982cb2014-10-25 18:04:36 -0700168 printf("Waiting for %s\n", folder);
169 sleep(1);
170 }
171 snprintf(folder, sizeof(folder), "/media/%s1/", dev_name);
172 }
173
174 if (access(folder, F_OK) == -1) {
175#else
Brian Silvermanf665d692013-02-17 22:11:39 -0800176 const char *folder = configuration::GetLoggingDirectory();
brians343bc112013-02-10 01:53:46 +0000177 if (access(folder, R_OK | W_OK) == -1) {
Austin Schuhc5982cb2014-10-25 18:04:36 -0700178#endif
Austin Schuhf257f3c2019-10-27 21:00:43 -0700179 AOS_LOG(FATAL, "folder '%s' does not exist. please create it\n", folder);
brians343bc112013-02-10 01:53:46 +0000180 }
Austin Schuhf257f3c2019-10-27 21:00:43 -0700181 AOS_LOG(INFO, "logging to folder '%s'\n", folder);
brians343bc112013-02-10 01:53:46 +0000182
brians343bc112013-02-10 01:53:46 +0000183 char *tmp;
Ben Fredricksona04c1752014-03-02 22:54:07 +0000184 AllocateLogName(&tmp, folder);
brians343bc112013-02-10 01:53:46 +0000185 char *tmp2;
186 if (asprintf(&tmp2, "%s/aos_log-current", folder) == -1) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700187 AOS_PLOG(WARNING, "couldn't create current symlink name");
brians343bc112013-02-10 01:53:46 +0000188 } else {
189 if (unlink(tmp2) == -1 && (errno != EROFS && errno != ENOENT)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700190 AOS_LOG(WARNING, "unlink('%s') failed", tmp2);
brians343bc112013-02-10 01:53:46 +0000191 }
192 if (symlink(tmp, tmp2) == -1) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700193 AOS_PLOG(WARNING, "symlink('%s', '%s') failed", tmp, tmp2);
brians343bc112013-02-10 01:53:46 +0000194 }
195 free(tmp2);
196 }
197 int fd = open(tmp, O_SYNC | O_APPEND | O_RDWR | O_CREAT,
198 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
199 free(tmp);
200 if (fd == -1) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700201 AOS_PLOG(FATAL, "opening file '%s' failed", tmp);
brians343bc112013-02-10 01:53:46 +0000202 }
Brian Silvermanab5ba472014-04-18 15:26:14 -0700203 LogFileWriter writer(fd);
brians343bc112013-02-10 01:53:46 +0000204
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500205 RawQueue *queue = GetLoggingQueue();
206
Brian Silvermanf5ca4d02015-03-01 16:52:24 -0500207 ::std::unordered_set<uint32_t> written_type_ids;
208 off_t clear_type_ids_cookie = 0;
209
brians343bc112013-02-10 01:53:46 +0000210 while (true) {
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500211 const LogMessage *const msg =
Brian Silverman18c2c362016-01-02 14:18:32 -0800212 static_cast<const LogMessage *>(queue->ReadMessage(RawQueue::kNonBlock));
213 if (msg == NULL) {
214 // If we've emptied the queue, then wait for a bit before starting to read
215 // again so the queue can buffer up some logs. This avoids lots of context
216 // switches and mutex contention which happens if we're constantly reading
217 // new messages as they come in.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800218 ::std::this_thread::sleep_for(::std::chrono::milliseconds(100));
Brian Silverman18c2c362016-01-02 14:18:32 -0800219 continue;
220 }
brians343bc112013-02-10 01:53:46 +0000221
Brian Silverman664db1a2014-03-20 17:06:29 -0700222 const size_t raw_output_length =
Brian Silverman88471dc2014-02-15 22:35:42 -0800223 sizeof(LogFileMessageHeader) + msg->name_length + msg->message_length;
Brian Silverman664db1a2014-03-20 17:06:29 -0700224 size_t output_length = raw_output_length;
Brian Silverman88471dc2014-02-15 22:35:42 -0800225 if (msg->type == LogMessage::Type::kStruct) {
226 output_length += sizeof(msg->structure.type_id) + sizeof(uint32_t) +
227 msg->structure.string_length;
Brian Silvermanf5ca4d02015-03-01 16:52:24 -0500228 if (writer.ShouldClearSeekableData(&clear_type_ids_cookie,
229 output_length)) {
230 writer.ForceNewPage();
231 written_type_ids.clear();
232 }
233 CheckTypeWritten(msg->structure.type_id, &writer, &written_type_ids);
Brian Silverman664db1a2014-03-20 17:06:29 -0700234 } else if (msg->type == LogMessage::Type::kMatrix) {
235 output_length +=
236 sizeof(msg->matrix.type) + sizeof(uint32_t) + sizeof(uint16_t) +
237 sizeof(uint16_t) + msg->matrix.string_length;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700238 AOS_CHECK(MessageType::IsPrimitive(msg->matrix.type));
Brian Silverman88471dc2014-02-15 22:35:42 -0800239 }
Brian Silverman91660632014-03-21 20:52:03 -0700240 LogFileMessageHeader *const output = writer.GetWritePosition(output_length);
brians343bc112013-02-10 01:53:46 +0000241 char *output_strings = reinterpret_cast<char *>(output) + sizeof(*output);
Brian Silverman88471dc2014-02-15 22:35:42 -0800242 output->name_size = msg->name_length;
243 output->message_size = msg->message_length;
brians343bc112013-02-10 01:53:46 +0000244 output->source = msg->source;
Brian Silvermanf665d692013-02-17 22:11:39 -0800245 output->level = msg->level;
246 output->time_sec = msg->seconds;
247 output->time_nsec = msg->nseconds;
248 output->sequence = msg->sequence;
Brian Silverman88471dc2014-02-15 22:35:42 -0800249 memcpy(output_strings, msg->name, msg->name_length);
250
251 switch (msg->type) {
252 case LogMessage::Type::kString:
253 memcpy(output_strings + msg->name_length, msg->message,
254 msg->message_length);
255 output->type = LogFileMessageHeader::MessageType::kString;
256 break;
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700257 case LogMessage::Type::kStruct: {
Brian Silverman88471dc2014-02-15 22:35:42 -0800258 char *position = output_strings + msg->name_length;
259
Brian Silverman4dd06242014-04-08 19:10:17 -0700260 memcpy(position, &msg->structure.type_id,
261 sizeof(msg->structure.type_id));
Brian Silverman88471dc2014-02-15 22:35:42 -0800262 position += sizeof(msg->structure.type_id);
263 output->message_size += sizeof(msg->structure.type_id);
264
Brian Silvermana7234c62014-03-24 20:23:25 -0700265 const uint32_t length = msg->structure.string_length;
Brian Silverman88471dc2014-02-15 22:35:42 -0800266 memcpy(position, &length, sizeof(length));
267 position += sizeof(length);
Brian Silverman4dd06242014-04-08 19:10:17 -0700268 memcpy(position, msg->structure.serialized,
269 length + msg->message_length);
Brian Silvermana7234c62014-03-24 20:23:25 -0700270 position += length + msg->message_length;
Brian Silverman88471dc2014-02-15 22:35:42 -0800271 output->message_size += sizeof(length) + length;
272
Brian Silverman88471dc2014-02-15 22:35:42 -0800273 output->type = LogFileMessageHeader::MessageType::kStruct;
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700274 } break;
275 case LogMessage::Type::kMatrix: {
276 char *position = output_strings + msg->name_length;
277
278 memcpy(position, &msg->matrix.type, sizeof(msg->matrix.type));
279 position += sizeof(msg->matrix.type);
280 output->message_size += sizeof(msg->matrix.type);
281
282 uint32_t length = msg->matrix.string_length;
283 memcpy(position, &length, sizeof(length));
284 position += sizeof(length);
Brian Silverman664db1a2014-03-20 17:06:29 -0700285 output->message_size += sizeof(length);
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700286
287 uint16_t rows = msg->matrix.rows, cols = msg->matrix.cols;
288 memcpy(position, &rows, sizeof(rows));
289 position += sizeof(rows);
290 memcpy(position, &cols, sizeof(cols));
291 position += sizeof(cols);
292 output->message_size += sizeof(rows) + sizeof(cols);
Austin Schuhf257f3c2019-10-27 21:00:43 -0700293 AOS_CHECK_EQ(msg->message_length,
294 MessageType::Sizeof(msg->matrix.type) * rows * cols);
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700295
Brian Silverman664db1a2014-03-20 17:06:29 -0700296 memcpy(position, msg->matrix.data, msg->message_length + length);
297 output->message_size += length;
298
299 output->type = LogFileMessageHeader::MessageType::kMatrix;
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700300 } break;
Brian Silverman88471dc2014-02-15 22:35:42 -0800301 }
302
Brian Silverman664db1a2014-03-20 17:06:29 -0700303 if (output->message_size - msg->message_length !=
304 output_length - raw_output_length) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700305 AOS_LOG(FATAL, "%zu != %zu\n", output->message_size - msg->message_length,
306 output_length - raw_output_length);
Brian Silverman664db1a2014-03-20 17:06:29 -0700307 }
308
Brian Silvermanaf221b82013-09-01 13:57:50 -0700309 futex_set(&output->marker);
brians343bc112013-02-10 01:53:46 +0000310
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500311 queue->FreeMessage(msg);
brians343bc112013-02-10 01:53:46 +0000312 }
313
Brian Silvermanf665d692013-02-17 22:11:39 -0800314 Cleanup();
315 return 0;
316}
317
318} // namespace
Brian Silverman14fd0fb2014-01-14 21:42:01 -0800319} // namespace linux_code
Brian Silvermanf665d692013-02-17 22:11:39 -0800320} // namespace logging
321} // namespace aos
322
323int main() {
Brian Silverman14fd0fb2014-01-14 21:42:01 -0800324 return ::aos::logging::linux_code::BinaryLogReaderMain();
brians343bc112013-02-10 01:53:46 +0000325}