blob: 56949b5e8069f33178d722b0d057031fddf075b9 [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#include <stdio.h>
2#include <stdlib.h>
3#include <errno.h>
4#include <time.h>
5#include <string.h>
6#include <string>
7#include <unistd.h>
8#include <sys/types.h>
9#include <pwd.h>
10#include <fcntl.h>
Ben Fredricksona04c1752014-03-02 22:54:07 +000011#include <dirent.h>
Austin Schuhc5982cb2014-10-25 18:04:36 -070012#include <mntent.h>
brians343bc112013-02-10 01:53:46 +000013
14#include <map>
Brian Silverman88471dc2014-02-15 22:35:42 -080015#include <unordered_set>
brians343bc112013-02-10 01:53:46 +000016
Brian Silvermancb5da1f2015-12-05 22:19:58 -050017#include "aos/common/logging/implementations.h"
Brian Silvermanf44f1242015-12-05 20:19:48 -050018#include "aos/common/logging/binary_log_file.h"
Brian Silverman14fd0fb2014-01-14 21:42:01 -080019#include "aos/linux_code/init.h"
20#include "aos/linux_code/configuration.h"
Brian Silvermancb5da1f2015-12-05 22:19:58 -050021#include "aos/linux_code/ipc_lib/queue.h"
Brian Silverman88471dc2014-02-15 22:35:42 -080022#include "aos/common/queue_types.h"
Ben Fredricksona04c1752014-03-02 22:54:07 +000023#include "aos/common/die.h"
brians343bc112013-02-10 01:53:46 +000024
Brian Silvermanf665d692013-02-17 22:11:39 -080025namespace aos {
26namespace logging {
Brian Silverman14fd0fb2014-01-14 21:42:01 -080027namespace linux_code {
Brian Silvermanf665d692013-02-17 22:11:39 -080028namespace {
brians343bc112013-02-10 01:53:46 +000029
Brian Silvermanf5ca4d02015-03-01 16:52:24 -050030void CheckTypeWritten(uint32_t type_id, LogFileWriter *writer,
31 ::std::unordered_set<uint32_t> *written_type_ids) {
32 if (written_type_ids->count(type_id) > 0) return;
Brian Silverman88471dc2014-02-15 22:35:42 -080033 if (MessageType::IsPrimitive(type_id)) return;
34
35 const MessageType &type = type_cache::Get(type_id);
36 for (int i = 0; i < type.number_fields; ++i) {
Brian Silvermanf5ca4d02015-03-01 16:52:24 -050037 CheckTypeWritten(type.fields[i]->type, writer, written_type_ids);
Brian Silverman88471dc2014-02-15 22:35:42 -080038 }
39
40 char buffer[1024];
41 ssize_t size = type.Serialize(buffer, sizeof(buffer));
42 if (size == -1) {
43 LOG(WARNING, "%zu-byte buffer is too small to serialize type %s\n",
44 sizeof(buffer), type.name.c_str());
45 return;
46 }
47 LogFileMessageHeader *const output =
Brian Silvermanf5ca4d02015-03-01 16:52:24 -050048 writer->GetWritePosition(sizeof(LogFileMessageHeader) + size);
Brian Silverman88471dc2014-02-15 22:35:42 -080049
50 output->time_sec = output->time_nsec = 0;
51 output->source = getpid();
52 output->name_size = 0;
53 output->sequence = 0;
54 output->level = FATAL;
55
56 memcpy(output + 1, buffer, size);
57 output->message_size = size;
58
59 output->type = LogFileMessageHeader::MessageType::kStructType;
60 futex_set(&output->marker);
Brian Silvermanf7780312014-02-16 17:26:15 -080061
Brian Silvermanf5ca4d02015-03-01 16:52:24 -050062 written_type_ids->insert(type_id);
Brian Silverman88471dc2014-02-15 22:35:42 -080063}
64
Ben Fredricksona04c1752014-03-02 22:54:07 +000065void AllocateLogName(char **filename, const char *directory) {
66 int fileindex = 0;
Brian Silverman2adb1452014-05-13 08:43:38 -070067 DIR *const d = opendir(directory);
68 if (d == nullptr) {
69 PDie("could not open directory %s", directory);
70 }
71 int index = 0;
72 while (true) {
73 errno = 0;
74 struct dirent *const dir = readdir(d);
75 if (dir == nullptr) {
76 if (errno == 0) {
77 break;
78 } else {
79 PLOG(FATAL, "readdir(%p) failed", d);
80 }
81 } else {
Ben Fredricksona04c1752014-03-02 22:54:07 +000082 if (sscanf(dir->d_name, "aos_log-%d", &index) == 1) {
83 if (index >= fileindex) {
84 fileindex = index + 1;
85 }
86 }
87 }
Ben Fredricksona04c1752014-03-02 22:54:07 +000088 }
Brian Silverman2adb1452014-05-13 08:43:38 -070089 closedir(d);
Ben Fredricksona04c1752014-03-02 22:54:07 +000090
91 char previous[512];
Brian Silvermanf574e732014-03-02 17:35:04 -080092 ::std::string path = ::std::string(directory) + "/aos_log-current";
93 ssize_t len = ::readlink(path.c_str(), previous, sizeof(previous));
Ben Fredricksona04c1752014-03-02 22:54:07 +000094 if (len != -1) {
95 previous[len] = '\0';
96 } else {
Brian Silvermanf574e732014-03-02 17:35:04 -080097 previous[0] = '\0';
98 LOG(INFO, "Could not find aos_log-current\n");
99 printf("Could not find aos_log-current\n");
Ben Fredricksona04c1752014-03-02 22:54:07 +0000100 }
Brian Silverman09e85ed2014-03-15 08:26:29 -0700101 if (asprintf(filename, "%s/aos_log-%03d", directory, fileindex) == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700102 PDie("couldn't create final name");
Ben Fredricksona04c1752014-03-02 22:54:07 +0000103 }
Brian Silvermanf574e732014-03-02 17:35:04 -0800104 LOG(INFO, "Created log file (aos_log-%d) in directory (%s). Previous file "
105 "was (%s).\n",
106 fileindex, directory, previous);
107 printf("Created log file (aos_log-%d) in directory (%s). Previous file was "
108 "(%s).\n",
109 fileindex, directory, previous);
Ben Fredricksona04c1752014-03-02 22:54:07 +0000110}
111
Brian Silverman9f330492015-03-01 17:37:02 -0500112#ifdef AOS_ARCHITECTURE_arm_frc
Austin Schuhc5982cb2014-10-25 18:04:36 -0700113bool FoundThumbDrive(const char *path) {
114 FILE *mnt_fp = setmntent("/etc/mtab", "r");
115 if (mnt_fp == nullptr) {
116 Die("Could not open /etc/mtab");
117 }
118
119 bool found = false;
120 struct mntent mntbuf;
121 char buf[256];
122 while (!found) {
123 struct mntent *mount_list = getmntent_r(mnt_fp, &mntbuf, buf, sizeof(buf));
124 if (mount_list == nullptr) {
125 break;
126 }
127 if (strcmp(mount_list->mnt_dir, path) == 0) {
128 found = true;
129 }
130 }
131 endmntent(mnt_fp);
132 return found;
133}
134
135bool FindDevice(char *device, size_t device_size) {
136 char test_device[10];
137 for (char i = 'a'; i < 'z'; ++i) {
138 snprintf(test_device, sizeof(test_device), "/dev/sd%c", i);
139 LOG(INFO, "Trying to access %s\n", test_device);
140 if (access(test_device, F_OK) != -1) {
141 snprintf(device, device_size, "sd%c", i);
142 return true;
143 }
144 }
145 return false;
146}
147#endif
148
Brian Silvermanab6615c2013-03-05 20:29:29 -0800149int BinaryLogReaderMain() {
Brian Silvermanf665d692013-02-17 22:11:39 -0800150 InitNRT();
brians343bc112013-02-10 01:53:46 +0000151
Brian Silverman9f330492015-03-01 17:37:02 -0500152#ifdef AOS_ARCHITECTURE_arm_frc
Austin Schuhc5982cb2014-10-25 18:04:36 -0700153 char folder[128];
154
155 {
156 char dev_name[8];
157 while (!FindDevice(dev_name, sizeof(dev_name))) {
158 LOG(INFO, "Waiting for a device\n");
159 printf("Waiting for a device\n");
160 sleep(5);
161 }
162 snprintf(folder, sizeof(folder), "/media/%s1", dev_name);
163 while (!FoundThumbDrive(folder)) {
164 LOG(INFO, "Waiting for %s\n", folder);
165 printf("Waiting for %s\n", folder);
166 sleep(1);
167 }
168 snprintf(folder, sizeof(folder), "/media/%s1/", dev_name);
169 }
170
171 if (access(folder, F_OK) == -1) {
172#else
Brian Silvermanf665d692013-02-17 22:11:39 -0800173 const char *folder = configuration::GetLoggingDirectory();
brians343bc112013-02-10 01:53:46 +0000174 if (access(folder, R_OK | W_OK) == -1) {
Austin Schuhc5982cb2014-10-25 18:04:36 -0700175#endif
brians2fdfc072013-02-26 05:35:15 +0000176 LOG(FATAL, "folder '%s' does not exist. please create it\n", folder);
brians343bc112013-02-10 01:53:46 +0000177 }
178 LOG(INFO, "logging to folder '%s'\n", folder);
179
brians343bc112013-02-10 01:53:46 +0000180 char *tmp;
Ben Fredricksona04c1752014-03-02 22:54:07 +0000181 AllocateLogName(&tmp, folder);
brians343bc112013-02-10 01:53:46 +0000182 char *tmp2;
183 if (asprintf(&tmp2, "%s/aos_log-current", folder) == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700184 PLOG(WARNING, "couldn't create current symlink name");
brians343bc112013-02-10 01:53:46 +0000185 } else {
186 if (unlink(tmp2) == -1 && (errno != EROFS && errno != ENOENT)) {
Brian Silverman01be0002014-05-10 15:44:38 -0700187 LOG(WARNING, "unlink('%s') failed", tmp2);
brians343bc112013-02-10 01:53:46 +0000188 }
189 if (symlink(tmp, tmp2) == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700190 PLOG(WARNING, "symlink('%s', '%s') failed", tmp, tmp2);
brians343bc112013-02-10 01:53:46 +0000191 }
192 free(tmp2);
193 }
194 int fd = open(tmp, O_SYNC | O_APPEND | O_RDWR | O_CREAT,
195 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
196 free(tmp);
197 if (fd == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700198 PLOG(FATAL, "opening file '%s' failed", tmp);
brians343bc112013-02-10 01:53:46 +0000199 }
Brian Silvermanab5ba472014-04-18 15:26:14 -0700200 LogFileWriter writer(fd);
brians343bc112013-02-10 01:53:46 +0000201
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500202 RawQueue *queue = GetLoggingQueue();
203
Brian Silvermanf5ca4d02015-03-01 16:52:24 -0500204 ::std::unordered_set<uint32_t> written_type_ids;
205 off_t clear_type_ids_cookie = 0;
206
brians343bc112013-02-10 01:53:46 +0000207 while (true) {
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500208 const LogMessage *const msg =
209 static_cast<const LogMessage *>(queue->ReadMessage(RawQueue::kBlock));
brians343bc112013-02-10 01:53:46 +0000210 if (msg == NULL) continue;
brians343bc112013-02-10 01:53:46 +0000211
Brian Silverman664db1a2014-03-20 17:06:29 -0700212 const size_t raw_output_length =
Brian Silverman88471dc2014-02-15 22:35:42 -0800213 sizeof(LogFileMessageHeader) + msg->name_length + msg->message_length;
Brian Silverman664db1a2014-03-20 17:06:29 -0700214 size_t output_length = raw_output_length;
Brian Silverman88471dc2014-02-15 22:35:42 -0800215 if (msg->type == LogMessage::Type::kStruct) {
216 output_length += sizeof(msg->structure.type_id) + sizeof(uint32_t) +
217 msg->structure.string_length;
Brian Silvermanf5ca4d02015-03-01 16:52:24 -0500218 if (writer.ShouldClearSeekableData(&clear_type_ids_cookie,
219 output_length)) {
220 writer.ForceNewPage();
221 written_type_ids.clear();
222 }
223 CheckTypeWritten(msg->structure.type_id, &writer, &written_type_ids);
Brian Silverman664db1a2014-03-20 17:06:29 -0700224 } else if (msg->type == LogMessage::Type::kMatrix) {
225 output_length +=
226 sizeof(msg->matrix.type) + sizeof(uint32_t) + sizeof(uint16_t) +
227 sizeof(uint16_t) + msg->matrix.string_length;
Brian Silvermanab5ba472014-04-18 15:26:14 -0700228 CHECK(MessageType::IsPrimitive(msg->matrix.type));
Brian Silverman88471dc2014-02-15 22:35:42 -0800229 }
Brian Silverman91660632014-03-21 20:52:03 -0700230 LogFileMessageHeader *const output = writer.GetWritePosition(output_length);
brians343bc112013-02-10 01:53:46 +0000231 char *output_strings = reinterpret_cast<char *>(output) + sizeof(*output);
Brian Silverman88471dc2014-02-15 22:35:42 -0800232 output->name_size = msg->name_length;
233 output->message_size = msg->message_length;
brians343bc112013-02-10 01:53:46 +0000234 output->source = msg->source;
Brian Silvermanf665d692013-02-17 22:11:39 -0800235 output->level = msg->level;
236 output->time_sec = msg->seconds;
237 output->time_nsec = msg->nseconds;
238 output->sequence = msg->sequence;
Brian Silverman88471dc2014-02-15 22:35:42 -0800239 memcpy(output_strings, msg->name, msg->name_length);
240
241 switch (msg->type) {
242 case LogMessage::Type::kString:
243 memcpy(output_strings + msg->name_length, msg->message,
244 msg->message_length);
245 output->type = LogFileMessageHeader::MessageType::kString;
246 break;
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700247 case LogMessage::Type::kStruct: {
Brian Silverman88471dc2014-02-15 22:35:42 -0800248 char *position = output_strings + msg->name_length;
249
Brian Silverman4dd06242014-04-08 19:10:17 -0700250 memcpy(position, &msg->structure.type_id,
251 sizeof(msg->structure.type_id));
Brian Silverman88471dc2014-02-15 22:35:42 -0800252 position += sizeof(msg->structure.type_id);
253 output->message_size += sizeof(msg->structure.type_id);
254
Brian Silvermana7234c62014-03-24 20:23:25 -0700255 const uint32_t length = msg->structure.string_length;
Brian Silverman88471dc2014-02-15 22:35:42 -0800256 memcpy(position, &length, sizeof(length));
257 position += sizeof(length);
Brian Silverman4dd06242014-04-08 19:10:17 -0700258 memcpy(position, msg->structure.serialized,
259 length + msg->message_length);
Brian Silvermana7234c62014-03-24 20:23:25 -0700260 position += length + msg->message_length;
Brian Silverman88471dc2014-02-15 22:35:42 -0800261 output->message_size += sizeof(length) + length;
262
Brian Silverman88471dc2014-02-15 22:35:42 -0800263 output->type = LogFileMessageHeader::MessageType::kStruct;
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700264 } break;
265 case LogMessage::Type::kMatrix: {
266 char *position = output_strings + msg->name_length;
267
268 memcpy(position, &msg->matrix.type, sizeof(msg->matrix.type));
269 position += sizeof(msg->matrix.type);
270 output->message_size += sizeof(msg->matrix.type);
271
272 uint32_t length = msg->matrix.string_length;
273 memcpy(position, &length, sizeof(length));
274 position += sizeof(length);
Brian Silverman664db1a2014-03-20 17:06:29 -0700275 output->message_size += sizeof(length);
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700276
277 uint16_t rows = msg->matrix.rows, cols = msg->matrix.cols;
278 memcpy(position, &rows, sizeof(rows));
279 position += sizeof(rows);
280 memcpy(position, &cols, sizeof(cols));
281 position += sizeof(cols);
282 output->message_size += sizeof(rows) + sizeof(cols);
283 CHECK_EQ(msg->message_length,
284 MessageType::Sizeof(msg->matrix.type) * rows * cols);
285
Brian Silverman664db1a2014-03-20 17:06:29 -0700286 memcpy(position, msg->matrix.data, msg->message_length + length);
287 output->message_size += length;
288
289 output->type = LogFileMessageHeader::MessageType::kMatrix;
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700290 } break;
Brian Silverman88471dc2014-02-15 22:35:42 -0800291 }
292
Brian Silverman664db1a2014-03-20 17:06:29 -0700293 if (output->message_size - msg->message_length !=
294 output_length - raw_output_length) {
295 LOG(FATAL, "%zu != %zu\n", output->message_size - msg->message_length,
296 output_length - raw_output_length);
297 }
298
Brian Silvermanaf221b82013-09-01 13:57:50 -0700299 futex_set(&output->marker);
brians343bc112013-02-10 01:53:46 +0000300
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500301 queue->FreeMessage(msg);
brians343bc112013-02-10 01:53:46 +0000302 }
303
Brian Silvermanf665d692013-02-17 22:11:39 -0800304 Cleanup();
305 return 0;
306}
307
308} // namespace
Brian Silverman14fd0fb2014-01-14 21:42:01 -0800309} // namespace linux_code
Brian Silvermanf665d692013-02-17 22:11:39 -0800310} // namespace logging
311} // namespace aos
312
313int main() {
Brian Silverman14fd0fb2014-01-14 21:42:01 -0800314 return ::aos::logging::linux_code::BinaryLogReaderMain();
brians343bc112013-02-10 01:53:46 +0000315}