blob: 16ba0f2bb83c18d58c57c1faeb26435ab9a2a5be [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
James Kuszmaul011b67a2019-12-15 12:52:34 -080017#include "glog/logging.h"
18
Philipp Schrader790cb542023-07-05 21:06:52 -070019#include "aos/configuration.h"
20
Adam Snaider13d48d92023-08-03 12:20:15 -070021#if defined(__clang)
22#pragma clang diagnostic ignored "-Wformat-nonliteral"
23#elif defined(__GNUC__)
24#pragma GCC diagnostic ignored "-Wformat-nonliteral"
25#endif
26
Austin Schuh03e80a62019-12-28 15:18:54 -080027DEFINE_string(logging_folder,
28#ifdef AOS_ARCHITECTURE_arm_frc
29 "",
30#else
31 "./logs",
32#endif
33 "The folder to log to. If empty, search for the /media/sd*1/ "
34 "folder and place logs there.");
35
Stephan Pleinesf63bde82024-01-13 15:59:33 -080036namespace aos::logging {
James Kuszmaul011b67a2019-12-15 12:52:34 -080037namespace {
38void AllocateLogName(char **filename, const char *directory,
39 const char *basename) {
40 int fileindex = 0;
41 DIR *const d = opendir(directory);
42 if (d == nullptr) {
43 PLOG(FATAL) << "could not open directory" << directory;
44 }
45 int index = 0;
46 while (true) {
47 errno = 0;
48 struct dirent *const dir = readdir(d);
49 if (dir == nullptr) {
50 if (errno == 0) {
51 break;
52 } else {
53 PLOG(FATAL) << "readdir(" << d << ") failed";
54 }
55 } else {
56 const std::string format_string = std::string(basename) + "-%d";
57 if (sscanf(dir->d_name, format_string.c_str(), &index) == 1) {
58 if (index >= fileindex) {
59 fileindex = index + 1;
60 }
61 }
62 }
63 }
64 closedir(d);
65
66 char previous[512];
67 ::std::string path = ::std::string(directory) + "/" + basename + "-current";
68 ssize_t len = ::readlink(path.c_str(), previous, sizeof(previous));
69 if (len != -1) {
70 previous[len] = '\0';
71 } else {
72 previous[0] = '\0';
73 LOG(INFO) << "Could not find " << path;
74 }
75 if (asprintf(filename, "%s/%s-%03d", directory, basename, fileindex) == -1) {
76 PLOG(FATAL) << "couldn't create final name";
77 }
James Kuszmaul131aa042021-08-01 17:28:50 -070078 // Fix basename formatting.
79 LOG(INFO) << "Created log file (" << filename << "). Previous file was ("
80 << directory << "/" << previous << ").";
James Kuszmaul011b67a2019-12-15 12:52:34 -080081}
82
James Kuszmaul011b67a2019-12-15 12:52:34 -080083bool FoundThumbDrive(const char *path) {
84 FILE *mnt_fp = setmntent("/etc/mtab", "r");
85 if (mnt_fp == nullptr) {
86 LOG(FATAL) << "Could not open /etc/mtab";
87 }
88
89 bool found = false;
90 struct mntent mntbuf;
91 char buf[256];
92 while (!found) {
93 struct mntent *mount_list = getmntent_r(mnt_fp, &mntbuf, buf, sizeof(buf));
94 if (mount_list == nullptr) {
95 break;
96 }
97 if (strcmp(mount_list->mnt_dir, path) == 0) {
98 found = true;
99 }
100 }
101 endmntent(mnt_fp);
102 return found;
103}
104
105bool FindDevice(char *device, size_t device_size) {
106 char test_device[10];
107 for (char i = 'a'; i < 'z'; ++i) {
108 snprintf(test_device, sizeof(test_device), "/dev/sd%c", i);
Austin Schuh73fcab12020-02-22 14:59:23 -0800109 VLOG(1) << "Trying to access" << test_device;
James Kuszmaul011b67a2019-12-15 12:52:34 -0800110 if (access(test_device, F_OK) != -1) {
111 snprintf(device, device_size, "sd%c", i);
112 return true;
113 }
114 }
115 return false;
116}
Austin Schuh03e80a62019-12-28 15:18:54 -0800117
James Kuszmaul011b67a2019-12-15 12:52:34 -0800118} // namespace
119
Ravago Jones1a4bc762023-04-09 16:21:57 -0700120std::optional<std::string> MaybeGetLogName(const char *basename) {
Austin Schuh03e80a62019-12-28 15:18:54 -0800121 if (FLAGS_logging_folder.empty()) {
122 char folder[128];
123 {
124 char dev_name[8];
Ravago Jones1a4bc762023-04-09 16:21:57 -0700125 if (!FindDevice(dev_name, sizeof(dev_name))) {
Austin Schuh03e80a62019-12-28 15:18:54 -0800126 LOG(INFO) << "Waiting for a device";
Ravago Jones1a4bc762023-04-09 16:21:57 -0700127 return std::nullopt;
Austin Schuh03e80a62019-12-28 15:18:54 -0800128 }
129 snprintf(folder, sizeof(folder), "/media/%s1", dev_name);
Ravago Jones1a4bc762023-04-09 16:21:57 -0700130 if (!FoundThumbDrive(folder)) {
Austin Schuh03e80a62019-12-28 15:18:54 -0800131 LOG(INFO) << "Waiting for" << folder;
Ravago Jones1a4bc762023-04-09 16:21:57 -0700132 return std::nullopt;
Austin Schuh03e80a62019-12-28 15:18:54 -0800133 }
134 snprintf(folder, sizeof(folder), "/media/%s1/", dev_name);
James Kuszmaul011b67a2019-12-15 12:52:34 -0800135 }
James Kuszmaul011b67a2019-12-15 12:52:34 -0800136
Austin Schuh03e80a62019-12-28 15:18:54 -0800137 if (access(folder, F_OK) == -1) {
138 LOG(FATAL) << "folder '" << folder
139 << "' does not exist. please create it.";
140 }
141
142 FLAGS_logging_folder = folder;
143 }
144 const char *folder = FLAGS_logging_folder.c_str();
James Kuszmaul011b67a2019-12-15 12:52:34 -0800145 if (access(folder, R_OK | W_OK) == -1) {
James Kuszmaul011b67a2019-12-15 12:52:34 -0800146 LOG(FATAL) << "folder '" << folder << "' does not exist. please create it.";
147 }
148 LOG(INFO) << "logging to folder '" << folder << "'";
149
150 char *tmp;
151 AllocateLogName(&tmp, folder, basename);
Austin Schuh2d0471d2020-02-29 13:27:07 -0800152
153 std::string log_base_name = tmp;
Austin Schuhe715eae2020-10-10 15:39:30 -0700154 std::string log_roborio_name = log_base_name + "/";
Austin Schuh2d0471d2020-02-29 13:27:07 -0800155 free(tmp);
156
James Kuszmaul011b67a2019-12-15 12:52:34 -0800157 char *tmp2;
Austin Schuhe715eae2020-10-10 15:39:30 -0700158 if (asprintf(&tmp2, "%s/%s-current", folder, basename) == -1) {
James Kuszmaul011b67a2019-12-15 12:52:34 -0800159 PLOG(WARNING) << "couldn't create current symlink name";
160 } else {
161 if (unlink(tmp2) == -1 && (errno != EROFS && errno != ENOENT)) {
162 LOG(WARNING) << "unlink('" << tmp2 << "') failed";
163 }
Austin Schuh2d0471d2020-02-29 13:27:07 -0800164 if (symlink(log_roborio_name.c_str(), tmp2) == -1) {
165 PLOG(WARNING) << "symlink('" << log_roborio_name.c_str() << "', '" << tmp2
166 << "') failed";
James Kuszmaul011b67a2019-12-15 12:52:34 -0800167 }
168 free(tmp2);
169 }
Austin Schuh2d0471d2020-02-29 13:27:07 -0800170 return log_base_name;
James Kuszmaul011b67a2019-12-15 12:52:34 -0800171}
172
Ravago Jones1a4bc762023-04-09 16:21:57 -0700173std::string GetLogName(const char *basename) {
174 std::optional<std::string> log_base_name;
175
176 while (true) {
177 log_base_name = MaybeGetLogName(basename);
178
179 if (log_base_name.has_value()) {
180 break;
181 }
182
183 sleep(5);
184 }
185
186 return log_base_name.value();
187}
188
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800189} // namespace aos::logging