params.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. #include "common/params.h"
  2. #include <dirent.h>
  3. #include <sys/file.h>
  4. #include <algorithm>
  5. #include <csignal>
  6. #include <unordered_map>
  7. #include "common/swaglog.h"
  8. #include "common/util.h"
  9. #include "system/hardware/hw.h"
  10. namespace {
  11. volatile sig_atomic_t params_do_exit = 0;
  12. void params_sig_handler(int signal) {
  13. params_do_exit = 1;
  14. }
  15. int fsync_dir(const std::string &path) {
  16. int result = -1;
  17. int fd = HANDLE_EINTR(open(path.c_str(), O_RDONLY, 0755));
  18. if (fd >= 0) {
  19. result = fsync(fd);
  20. close(fd);
  21. }
  22. return result;
  23. }
  24. bool create_params_path(const std::string &param_path, const std::string &key_path) {
  25. // Make sure params path exists
  26. if (!util::file_exists(param_path) && !util::create_directories(param_path, 0775)) {
  27. return false;
  28. }
  29. // See if the symlink exists, otherwise create it
  30. if (!util::file_exists(key_path)) {
  31. // 1) Create temp folder
  32. // 2) Symlink it to temp link
  33. // 3) Move symlink to <params>/d
  34. std::string tmp_path = param_path + "/.tmp_XXXXXX";
  35. // this should be OK since mkdtemp just replaces characters in place
  36. char *tmp_dir = mkdtemp((char *)tmp_path.c_str());
  37. if (tmp_dir == NULL) {
  38. return false;
  39. }
  40. std::string link_path = std::string(tmp_dir) + ".link";
  41. if (symlink(tmp_dir, link_path.c_str()) != 0) {
  42. return false;
  43. }
  44. // don't return false if it has been created by other
  45. if (rename(link_path.c_str(), key_path.c_str()) != 0 && errno != EEXIST) {
  46. return false;
  47. }
  48. }
  49. return true;
  50. }
  51. std::string ensure_params_path(const std::string &prefix, const std::string &path = {}) {
  52. std::string params_path = path.empty() ? Path::params() : path;
  53. if (!create_params_path(params_path, params_path + prefix)) {
  54. throw std::runtime_error(util::string_format("Failed to ensure params path, errno=%d", errno));
  55. }
  56. return params_path;
  57. }
  58. class FileLock {
  59. public:
  60. FileLock(const std::string &fn) {
  61. fd_ = HANDLE_EINTR(open(fn.c_str(), O_CREAT, 0775));
  62. if (fd_ < 0 || HANDLE_EINTR(flock(fd_, LOCK_EX)) < 0) {
  63. LOGE("Failed to lock file %s, errno=%d", fn.c_str(), errno);
  64. }
  65. }
  66. ~FileLock() { close(fd_); }
  67. private:
  68. int fd_ = -1;
  69. };
  70. std::unordered_map<std::string, uint32_t> keys = {
  71. {"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
  72. {"AssistNowToken", PERSISTENT},
  73. {"AthenadPid", PERSISTENT},
  74. {"AthenadUploadQueue", PERSISTENT},
  75. {"CalibrationParams", PERSISTENT},
  76. {"CameraDebugExpGain", CLEAR_ON_MANAGER_START},
  77. {"CameraDebugExpTime", CLEAR_ON_MANAGER_START},
  78. {"CarBatteryCapacity", PERSISTENT},
  79. {"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
  80. {"CarParamsCache", CLEAR_ON_MANAGER_START},
  81. {"CarParamsPersistent", PERSISTENT},
  82. {"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
  83. {"CompletedTrainingVersion", PERSISTENT},
  84. {"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
  85. {"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
  86. {"DashcamOverride", PERSISTENT},
  87. {"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
  88. {"DisablePowerDown", PERSISTENT},
  89. {"ExperimentalMode", PERSISTENT},
  90. {"ExperimentalModeConfirmed", PERSISTENT},
  91. {"ExperimentalLongitudinalEnabled", PERSISTENT}, // WARNING: THIS MAY DISABLE AEB
  92. {"DisableUpdates", PERSISTENT},
  93. {"DisengageOnAccelerator", PERSISTENT},
  94. {"DongleId", PERSISTENT},
  95. {"DoReboot", CLEAR_ON_MANAGER_START},
  96. {"DoShutdown", CLEAR_ON_MANAGER_START},
  97. {"DoUninstall", CLEAR_ON_MANAGER_START},
  98. {"ForcePowerDown", CLEAR_ON_MANAGER_START},
  99. {"GitBranch", PERSISTENT},
  100. {"GitCommit", PERSISTENT},
  101. {"GitDiff", PERSISTENT},
  102. {"GithubSshKeys", PERSISTENT},
  103. {"GithubUsername", PERSISTENT},
  104. {"GitRemote", PERSISTENT},
  105. {"GsmApn", PERSISTENT},
  106. {"GsmMetered", PERSISTENT},
  107. {"GsmRoaming", PERSISTENT},
  108. {"HardwareSerial", PERSISTENT},
  109. {"HasAcceptedTerms", PERSISTENT},
  110. {"IMEI", PERSISTENT},
  111. {"InstallDate", PERSISTENT},
  112. {"IsDriverViewEnabled", CLEAR_ON_MANAGER_START},
  113. {"IsEngaged", PERSISTENT},
  114. {"IsLdwEnabled", PERSISTENT},
  115. {"IsMetric", PERSISTENT},
  116. {"IsOffroad", CLEAR_ON_MANAGER_START},
  117. {"IsOnroad", PERSISTENT},
  118. {"IsRhdDetected", PERSISTENT},
  119. {"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
  120. {"IsTestedBranch", CLEAR_ON_MANAGER_START},
  121. {"IsUpdateAvailable", CLEAR_ON_MANAGER_START},
  122. {"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
  123. {"LaikadEphemeris", PERSISTENT | DONT_LOG},
  124. {"LanguageSetting", PERSISTENT},
  125. {"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
  126. {"LastGPSPosition", PERSISTENT},
  127. {"LastManagerExitReason", CLEAR_ON_MANAGER_START},
  128. {"LastPowerDropDetected", CLEAR_ON_MANAGER_START},
  129. {"LastSystemShutdown", CLEAR_ON_MANAGER_START},
  130. {"LastUpdateException", CLEAR_ON_MANAGER_START},
  131. {"LastUpdateTime", PERSISTENT},
  132. {"LiveParameters", PERSISTENT},
  133. {"LiveTorqueCarParams", PERSISTENT},
  134. {"LiveTorqueParameters", PERSISTENT | DONT_LOG},
  135. {"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
  136. {"NavSettingTime24h", PERSISTENT},
  137. {"NavSettingLeftSide", PERSISTENT},
  138. {"NavdRender", PERSISTENT},
  139. {"OpenpilotEnabledToggle", PERSISTENT},
  140. {"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
  141. {"PandaSignatures", CLEAR_ON_MANAGER_START},
  142. {"Passive", PERSISTENT},
  143. {"PrimeType", PERSISTENT},
  144. {"RecordFront", PERSISTENT},
  145. {"RecordFrontLock", PERSISTENT}, // for the internal fleet
  146. {"ReplayControlsState", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
  147. {"ShouldDoUpdate", CLEAR_ON_MANAGER_START},
  148. {"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
  149. {"SshEnabled", PERSISTENT},
  150. {"SubscriberInfo", PERSISTENT},
  151. {"TermsVersion", PERSISTENT},
  152. {"Timezone", PERSISTENT},
  153. {"TrainingVersion", PERSISTENT},
  154. {"UbloxAvailable", PERSISTENT},
  155. {"UpdateAvailable", CLEAR_ON_MANAGER_START},
  156. {"UpdateFailedCount", CLEAR_ON_MANAGER_START},
  157. {"UpdaterState", CLEAR_ON_MANAGER_START},
  158. {"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START},
  159. {"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
  160. {"UpdaterAvailableBranches", CLEAR_ON_MANAGER_START},
  161. {"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START},
  162. {"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START},
  163. {"UpdaterNewDescription", CLEAR_ON_MANAGER_START},
  164. {"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START},
  165. {"Version", PERSISTENT},
  166. {"VisionRadarToggle", PERSISTENT},
  167. {"WideCameraOnly", PERSISTENT},
  168. {"ApiCache_Device", PERSISTENT},
  169. {"ApiCache_DriveStats", PERSISTENT},
  170. {"ApiCache_NavDestinations", PERSISTENT},
  171. {"ApiCache_Owner", PERSISTENT},
  172. {"Offroad_BadNvme", CLEAR_ON_MANAGER_START},
  173. {"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
  174. {"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START},
  175. {"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START},
  176. {"Offroad_InvalidTime", CLEAR_ON_MANAGER_START},
  177. {"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START},
  178. {"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START},
  179. {"Offroad_NoFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
  180. {"Offroad_StorageMissing", CLEAR_ON_MANAGER_START},
  181. {"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START},
  182. {"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START},
  183. {"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START},
  184. };
  185. } // namespace
  186. Params::Params(const std::string &path) {
  187. prefix = "/" + util::getenv("OPENPILOT_PREFIX", "d");
  188. params_path = ensure_params_path(prefix, path);
  189. }
  190. std::vector<std::string> Params::allKeys() const {
  191. std::vector<std::string> ret;
  192. for (auto &p : keys) {
  193. ret.push_back(p.first);
  194. }
  195. return ret;
  196. }
  197. bool Params::checkKey(const std::string &key) {
  198. return keys.find(key) != keys.end();
  199. }
  200. ParamKeyType Params::getKeyType(const std::string &key) {
  201. return static_cast<ParamKeyType>(keys[key]);
  202. }
  203. int Params::put(const char* key, const char* value, size_t value_size) {
  204. // Information about safely and atomically writing a file: https://lwn.net/Articles/457667/
  205. // 1) Create temp file
  206. // 2) Write data to temp file
  207. // 3) fsync() the temp file
  208. // 4) rename the temp file to the real name
  209. // 5) fsync() the containing directory
  210. std::string tmp_path = params_path + "/.tmp_value_XXXXXX";
  211. int tmp_fd = mkstemp((char*)tmp_path.c_str());
  212. if (tmp_fd < 0) return -1;
  213. int result = -1;
  214. do {
  215. // Write value to temp.
  216. ssize_t bytes_written = HANDLE_EINTR(write(tmp_fd, value, value_size));
  217. if (bytes_written < 0 || (size_t)bytes_written != value_size) {
  218. result = -20;
  219. break;
  220. }
  221. // fsync to force persist the changes.
  222. if ((result = fsync(tmp_fd)) < 0) break;
  223. FileLock file_lock(params_path + "/.lock");
  224. // Move temp into place.
  225. if ((result = rename(tmp_path.c_str(), getParamPath(key).c_str())) < 0) break;
  226. // fsync parent directory
  227. result = fsync_dir(getParamPath());
  228. } while (false);
  229. close(tmp_fd);
  230. ::unlink(tmp_path.c_str());
  231. return result;
  232. }
  233. int Params::remove(const std::string &key) {
  234. FileLock file_lock(params_path + "/.lock");
  235. int result = unlink(getParamPath(key).c_str());
  236. if (result != 0) {
  237. return result;
  238. }
  239. return fsync_dir(getParamPath());
  240. }
  241. std::string Params::get(const std::string &key, bool block) {
  242. if (!block) {
  243. return util::read_file(getParamPath(key));
  244. } else {
  245. // blocking read until successful
  246. params_do_exit = 0;
  247. void (*prev_handler_sigint)(int) = std::signal(SIGINT, params_sig_handler);
  248. void (*prev_handler_sigterm)(int) = std::signal(SIGTERM, params_sig_handler);
  249. std::string value;
  250. while (!params_do_exit) {
  251. if (value = util::read_file(getParamPath(key)); !value.empty()) {
  252. break;
  253. }
  254. util::sleep_for(100); // 0.1 s
  255. }
  256. std::signal(SIGINT, prev_handler_sigint);
  257. std::signal(SIGTERM, prev_handler_sigterm);
  258. return value;
  259. }
  260. }
  261. std::map<std::string, std::string> Params::readAll() {
  262. FileLock file_lock(params_path + "/.lock");
  263. return util::read_files_in_dir(getParamPath());
  264. }
  265. void Params::clearAll(ParamKeyType key_type) {
  266. FileLock file_lock(params_path + "/.lock");
  267. if (key_type == ALL) {
  268. util::remove_files_in_dir(getParamPath());
  269. } else {
  270. for (auto &[key, type] : keys) {
  271. if (type & key_type) {
  272. unlink(getParamPath(key).c_str());
  273. }
  274. }
  275. }
  276. fsync_dir(getParamPath());
  277. }