blob: ed57caa85fe191a49c0dd763ac8272001d6072e0 [file] [log] [blame]
James Kuszmaul011b67a2019-12-15 12:52:34 -08001#include "aos/logging/log_namer.h"
2
3#include <dirent.h>
James Kuszmaul011b67a2019-12-15 12:52:34 -08004#include <fcntl.h>
5#include <mntent.h>
6#include <pwd.h>
James Kuszmaul011b67a2019-12-15 12:52:34 -08007#include <sys/types.h>
James Kuszmaul011b67a2019-12-15 12:52:34 -08008#include <unistd.h>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07009
10#include <cerrno>
11#include <cstdio>
12#include <cstdlib>
13#include <cstring>
14#include <ctime>
James Kuszmaul011b67a2019-12-15 12:52:34 -080015#include <string>
16
17#include "aos/configuration.h"
18#include "glog/logging.h"
19
Austin Schuh03e80a62019-12-28 15:18:54 -080020DEFINE_string(logging_folder,
21#ifdef AOS_ARCHITECTURE_arm_frc
22 "",
23#else
24 "./logs",
25#endif
26 "The folder to log to. If empty, search for the /media/sd*1/ "
27 "folder and place logs there.");
28
James Kuszmaul011b67a2019-12-15 12:52:34 -080029namespace aos {
30namespace logging {
31namespace {
32void AllocateLogName(char **filename, const char *directory,
33 const char *basename) {
34 int fileindex = 0;
35 DIR *const d = opendir(directory);
36 if (d == nullptr) {
37 PLOG(FATAL) << "could not open directory" << directory;
38 }
39 int index = 0;
40 while (true) {
41 errno = 0;
42 struct dirent *const dir = readdir(d);
43 if (dir == nullptr) {
44 if (errno == 0) {
45 break;
46 } else {
47 PLOG(FATAL) << "readdir(" << d << ") failed";
48 }
49 } else {
50 const std::string format_string = std::string(basename) + "-%d";
51 if (sscanf(dir->d_name, format_string.c_str(), &index) == 1) {
52 if (index >= fileindex) {
53 fileindex = index + 1;
54 }
55 }
56 }
57 }
58 closedir(d);
59
60 char previous[512];
61 ::std::string path = ::std::string(directory) + "/" + basename + "-current";
62 ssize_t len = ::readlink(path.c_str(), previous, sizeof(previous));
63 if (len != -1) {
64 previous[len] = '\0';
65 } else {
66 previous[0] = '\0';
67 LOG(INFO) << "Could not find " << path;
68 }
69 if (asprintf(filename, "%s/%s-%03d", directory, basename, fileindex) == -1) {
70 PLOG(FATAL) << "couldn't create final name";
71 }
James Kuszmaul131aa042021-08-01 17:28:50 -070072 // Fix basename formatting.
73 LOG(INFO) << "Created log file (" << filename << "). Previous file was ("
74 << directory << "/" << previous << ").";
James Kuszmaul011b67a2019-12-15 12:52:34 -080075}
76
James Kuszmaul011b67a2019-12-15 12:52:34 -080077bool FoundThumbDrive(const char *path) {
78 FILE *mnt_fp = setmntent("/etc/mtab", "r");
79 if (mnt_fp == nullptr) {
80 LOG(FATAL) << "Could not open /etc/mtab";
81 }
82
83 bool found = false;
84 struct mntent mntbuf;
85 char buf[256];
86 while (!found) {
87 struct mntent *mount_list = getmntent_r(mnt_fp, &mntbuf, buf, sizeof(buf));
88 if (mount_list == nullptr) {
89 break;
90 }
91 if (strcmp(mount_list->mnt_dir, path) == 0) {
92 found = true;
93 }
94 }
95 endmntent(mnt_fp);
96 return found;
97}
98
99bool FindDevice(char *device, size_t device_size) {
100 char test_device[10];
101 for (char i = 'a'; i < 'z'; ++i) {
102 snprintf(test_device, sizeof(test_device), "/dev/sd%c", i);
Austin Schuh73fcab12020-02-22 14:59:23 -0800103 VLOG(1) << "Trying to access" << test_device;
James Kuszmaul011b67a2019-12-15 12:52:34 -0800104 if (access(test_device, F_OK) != -1) {
105 snprintf(device, device_size, "sd%c", i);
106 return true;
107 }
108 }
109 return false;
110}
Austin Schuh03e80a62019-12-28 15:18:54 -0800111
James Kuszmaul011b67a2019-12-15 12:52:34 -0800112} // namespace
113
Ravago Jones1a4bc762023-04-09 16:21:57 -0700114std::optional<std::string> MaybeGetLogName(const char *basename) {
Austin Schuh03e80a62019-12-28 15:18:54 -0800115 if (FLAGS_logging_folder.empty()) {
116 char folder[128];
117 {
118 char dev_name[8];
Ravago Jones1a4bc762023-04-09 16:21:57 -0700119 if (!FindDevice(dev_name, sizeof(dev_name))) {
Austin Schuh03e80a62019-12-28 15:18:54 -0800120 LOG(INFO) << "Waiting for a device";
Ravago Jones1a4bc762023-04-09 16:21:57 -0700121 return std::nullopt;
Austin Schuh03e80a62019-12-28 15:18:54 -0800122 }
123 snprintf(folder, sizeof(folder), "/media/%s1", dev_name);
Ravago Jones1a4bc762023-04-09 16:21:57 -0700124 if (!FoundThumbDrive(folder)) {
Austin Schuh03e80a62019-12-28 15:18:54 -0800125 LOG(INFO) << "Waiting for" << folder;
Ravago Jones1a4bc762023-04-09 16:21:57 -0700126 return std::nullopt;
Austin Schuh03e80a62019-12-28 15:18:54 -0800127 }
128 snprintf(folder, sizeof(folder), "/media/%s1/", dev_name);
James Kuszmaul011b67a2019-12-15 12:52:34 -0800129 }
James Kuszmaul011b67a2019-12-15 12:52:34 -0800130
Austin Schuh03e80a62019-12-28 15:18:54 -0800131 if (access(folder, F_OK) == -1) {
132 LOG(FATAL) << "folder '" << folder
133 << "' does not exist. please create it.";
134 }
135
136 FLAGS_logging_folder = folder;
137 }
138 const char *folder = FLAGS_logging_folder.c_str();
James Kuszmaul011b67a2019-12-15 12:52:34 -0800139 if (access(folder, R_OK | W_OK) == -1) {
James Kuszmaul011b67a2019-12-15 12:52:34 -0800140 LOG(FATAL) << "folder '" << folder << "' does not exist. please create it.";
141 }
142 LOG(INFO) << "logging to folder '" << folder << "'";
143
144 char *tmp;
145 AllocateLogName(&tmp, folder, basename);
Austin Schuh2d0471d2020-02-29 13:27:07 -0800146
147 std::string log_base_name = tmp;
Austin Schuhe715eae2020-10-10 15:39:30 -0700148 std::string log_roborio_name = log_base_name + "/";
Austin Schuh2d0471d2020-02-29 13:27:07 -0800149 free(tmp);
150
James Kuszmaul011b67a2019-12-15 12:52:34 -0800151 char *tmp2;
Austin Schuhe715eae2020-10-10 15:39:30 -0700152 if (asprintf(&tmp2, "%s/%s-current", folder, basename) == -1) {
James Kuszmaul011b67a2019-12-15 12:52:34 -0800153 PLOG(WARNING) << "couldn't create current symlink name";
154 } else {
155 if (unlink(tmp2) == -1 && (errno != EROFS && errno != ENOENT)) {
156 LOG(WARNING) << "unlink('" << tmp2 << "') failed";
157 }
Austin Schuh2d0471d2020-02-29 13:27:07 -0800158 if (symlink(log_roborio_name.c_str(), tmp2) == -1) {
159 PLOG(WARNING) << "symlink('" << log_roborio_name.c_str() << "', '" << tmp2
160 << "') failed";
James Kuszmaul011b67a2019-12-15 12:52:34 -0800161 }
162 free(tmp2);
163 }
Austin Schuh2d0471d2020-02-29 13:27:07 -0800164 return log_base_name;
James Kuszmaul011b67a2019-12-15 12:52:34 -0800165}
166
Ravago Jones1a4bc762023-04-09 16:21:57 -0700167std::string GetLogName(const char *basename) {
168 std::optional<std::string> log_base_name;
169
170 while (true) {
171 log_base_name = MaybeGetLogName(basename);
172
173 if (log_base_name.has_value()) {
174 break;
175 }
176
177 sleep(5);
178 }
179
180 return log_base_name.value();
181}
182
James Kuszmaul011b67a2019-12-15 12:52:34 -0800183} // namespace logging
184} // namespace aos