blob: 77312fe2a6fbf44f0e6430e232447d05da37a5a7 [file] [log] [blame]
James Kuszmaul011b67a2019-12-15 12:52:34 -08001#include "aos/logging/log_namer.h"
2
3#include <dirent.h>
4#include <errno.h>
5#include <fcntl.h>
6#include <mntent.h>
7#include <pwd.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <sys/types.h>
12#include <time.h>
13#include <unistd.h>
14#include <string>
15
16#include "aos/configuration.h"
17#include "glog/logging.h"
18
Austin Schuh03e80a62019-12-28 15:18:54 -080019DEFINE_string(logging_folder,
20#ifdef AOS_ARCHITECTURE_arm_frc
21 "",
22#else
23 "./logs",
24#endif
25 "The folder to log to. If empty, search for the /media/sd*1/ "
26 "folder and place logs there.");
27
James Kuszmaul011b67a2019-12-15 12:52:34 -080028namespace aos {
29namespace logging {
30namespace {
31void AllocateLogName(char **filename, const char *directory,
32 const char *basename) {
33 int fileindex = 0;
34 DIR *const d = opendir(directory);
35 if (d == nullptr) {
36 PLOG(FATAL) << "could not open directory" << directory;
37 }
38 int index = 0;
39 while (true) {
40 errno = 0;
41 struct dirent *const dir = readdir(d);
42 if (dir == nullptr) {
43 if (errno == 0) {
44 break;
45 } else {
46 PLOG(FATAL) << "readdir(" << d << ") failed";
47 }
48 } else {
49 const std::string format_string = std::string(basename) + "-%d";
50 if (sscanf(dir->d_name, format_string.c_str(), &index) == 1) {
51 if (index >= fileindex) {
52 fileindex = index + 1;
53 }
54 }
55 }
56 }
57 closedir(d);
58
59 char previous[512];
60 ::std::string path = ::std::string(directory) + "/" + basename + "-current";
61 ssize_t len = ::readlink(path.c_str(), previous, sizeof(previous));
62 if (len != -1) {
63 previous[len] = '\0';
64 } else {
65 previous[0] = '\0';
66 LOG(INFO) << "Could not find " << path;
67 }
68 if (asprintf(filename, "%s/%s-%03d", directory, basename, fileindex) == -1) {
69 PLOG(FATAL) << "couldn't create final name";
70 }
James Kuszmaul131aa042021-08-01 17:28:50 -070071 // Fix basename formatting.
72 LOG(INFO) << "Created log file (" << filename << "). Previous file was ("
73 << directory << "/" << previous << ").";
James Kuszmaul011b67a2019-12-15 12:52:34 -080074}
75
James Kuszmaul011b67a2019-12-15 12:52:34 -080076bool FoundThumbDrive(const char *path) {
77 FILE *mnt_fp = setmntent("/etc/mtab", "r");
78 if (mnt_fp == nullptr) {
79 LOG(FATAL) << "Could not open /etc/mtab";
80 }
81
82 bool found = false;
83 struct mntent mntbuf;
84 char buf[256];
85 while (!found) {
86 struct mntent *mount_list = getmntent_r(mnt_fp, &mntbuf, buf, sizeof(buf));
87 if (mount_list == nullptr) {
88 break;
89 }
90 if (strcmp(mount_list->mnt_dir, path) == 0) {
91 found = true;
92 }
93 }
94 endmntent(mnt_fp);
95 return found;
96}
97
98bool FindDevice(char *device, size_t device_size) {
99 char test_device[10];
100 for (char i = 'a'; i < 'z'; ++i) {
101 snprintf(test_device, sizeof(test_device), "/dev/sd%c", i);
Austin Schuh73fcab12020-02-22 14:59:23 -0800102 VLOG(1) << "Trying to access" << test_device;
James Kuszmaul011b67a2019-12-15 12:52:34 -0800103 if (access(test_device, F_OK) != -1) {
104 snprintf(device, device_size, "sd%c", i);
105 return true;
106 }
107 }
108 return false;
109}
Austin Schuh03e80a62019-12-28 15:18:54 -0800110
James Kuszmaul011b67a2019-12-15 12:52:34 -0800111} // namespace
112
113std::string GetLogName(const char *basename) {
Austin Schuh03e80a62019-12-28 15:18:54 -0800114 if (FLAGS_logging_folder.empty()) {
115 char folder[128];
116 {
117 char dev_name[8];
118 while (!FindDevice(dev_name, sizeof(dev_name))) {
119 LOG(INFO) << "Waiting for a device";
120 sleep(5);
121 }
122 snprintf(folder, sizeof(folder), "/media/%s1", dev_name);
123 while (!FoundThumbDrive(folder)) {
124 LOG(INFO) << "Waiting for" << folder;
125 sleep(1);
126 }
127 snprintf(folder, sizeof(folder), "/media/%s1/", dev_name);
James Kuszmaul011b67a2019-12-15 12:52:34 -0800128 }
James Kuszmaul011b67a2019-12-15 12:52:34 -0800129
Austin Schuh03e80a62019-12-28 15:18:54 -0800130 if (access(folder, F_OK) == -1) {
131 LOG(FATAL) << "folder '" << folder
132 << "' does not exist. please create it.";
133 }
134
135 FLAGS_logging_folder = folder;
136 }
137 const char *folder = FLAGS_logging_folder.c_str();
James Kuszmaul011b67a2019-12-15 12:52:34 -0800138 if (access(folder, R_OK | W_OK) == -1) {
James Kuszmaul011b67a2019-12-15 12:52:34 -0800139 LOG(FATAL) << "folder '" << folder << "' does not exist. please create it.";
140 }
141 LOG(INFO) << "logging to folder '" << folder << "'";
142
143 char *tmp;
144 AllocateLogName(&tmp, folder, basename);
Austin Schuh2d0471d2020-02-29 13:27:07 -0800145
146 std::string log_base_name = tmp;
Austin Schuhe715eae2020-10-10 15:39:30 -0700147 std::string log_roborio_name = log_base_name + "/";
Austin Schuh2d0471d2020-02-29 13:27:07 -0800148 free(tmp);
149
James Kuszmaul011b67a2019-12-15 12:52:34 -0800150 char *tmp2;
Austin Schuhe715eae2020-10-10 15:39:30 -0700151 if (asprintf(&tmp2, "%s/%s-current", folder, basename) == -1) {
James Kuszmaul011b67a2019-12-15 12:52:34 -0800152 PLOG(WARNING) << "couldn't create current symlink name";
153 } else {
154 if (unlink(tmp2) == -1 && (errno != EROFS && errno != ENOENT)) {
155 LOG(WARNING) << "unlink('" << tmp2 << "') failed";
156 }
Austin Schuh2d0471d2020-02-29 13:27:07 -0800157 if (symlink(log_roborio_name.c_str(), tmp2) == -1) {
158 PLOG(WARNING) << "symlink('" << log_roborio_name.c_str() << "', '" << tmp2
159 << "') failed";
James Kuszmaul011b67a2019-12-15 12:52:34 -0800160 }
161 free(tmp2);
162 }
Austin Schuh2d0471d2020-02-29 13:27:07 -0800163 return log_base_name;
James Kuszmaul011b67a2019-12-15 12:52:34 -0800164}
165
166} // namespace logging
167} // namespace aos