tzdatacheck.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /*
  2. * Copyright (C) 2015 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <ctype.h>
  17. #include <errno.h>
  18. #include <ftw.h>
  19. #include <libgen.h>
  20. #include <stdarg.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <unistd.h>
  25. #include <iostream>
  26. #include <memory>
  27. #include <string>
  28. #include <vector>
  29. #include "android-base/logging.h"
  30. // The name of the directory that holds a staged time zone update distro. If this exists it should
  31. // replace the one in CURRENT_DIR_NAME.
  32. // See also com.android.timezone.distro.installer.TimeZoneDistroInstaller.
  33. static const char* STAGED_DIR_NAME = "/staged";
  34. // The name of the directory that holds the (optional) installed time zone update distro.
  35. // See also com.android.timezone.distro.installer.TimeZoneDistroInstaller.
  36. static const char* CURRENT_DIR_NAME = "/current";
  37. // The name of a file in the staged dir that indicates the staged operation is an "uninstall".
  38. // See also com.android.timezone.distro.installer.TimeZoneDistroInstaller.
  39. static const char* UNINSTALL_TOMBSTONE_FILE_NAME = "/STAGED_UNINSTALL_TOMBSTONE";
  40. // The name of the file containing the distro version information.
  41. // See also com.android.timezone.distro.TimeZoneDistro / com.android.timezone.distro.DistroVersion.
  42. static const char* DISTRO_VERSION_FILENAME = "/distro_version";
  43. // The name of the file containing the base tz data set version information.
  44. // See also libcore.timezone.TzDataSetVersion.
  45. static const char* BASE_VERSION_FILENAME = "/tz_version";
  46. // distro_version / tz_version are ASCII files consisting of at least 17 bytes in the
  47. // form: AAA.BBB|CCCCC|DDD
  48. // AAA.BBB is the major/minor version of the format (e.g. 004.001),
  49. // CCCCC is the rules version (e.g. 2016g),
  50. // DDD is the android revision for this rules version to allow for data corrections (e.g. 001),
  51. // We only use the first 13 to determine suitability of format / data.
  52. static const int READ_DATA_LENGTH = 13;
  53. // Version bytes are: AAA.BBB|CCCCC - the format version is AAA.BBB
  54. // The length of the format version, e.g. "004.001" == 7 bytes
  55. static const size_t FORMAT_VERSION_LEN = 7;
  56. // Version bytes are: AAA.BBB|CCCCC - the format major version is AAA
  57. static const size_t FORMAT_MAJOR_VERSION_LEN = 3;
  58. // Version bytes are: AAA.BBB|CCCCC - the format major version is AAA
  59. static const size_t FORMAT_MAJOR_VERSION_IDX = 0;
  60. // Version bytes are: AAA.BBB|CCCCC - the format major version is AAA
  61. static const size_t FORMAT_MINOR_VERSION_LEN = 3;
  62. // Version bytes are: AAA.BBB|CCCCC - the format minor version is BBB
  63. static const size_t FORMAT_MINOR_VERSION_IDX = 4;
  64. // Version bytes are: AAA.BBB|CCCCC - the IANA rules version is CCCCC
  65. // The length of the IANA rules version bytes, e.g. 2016a
  66. static const size_t RULES_VERSION_LEN = 5;
  67. // Version bytes are: AAA.BBB|CCCCC - the rules version is CCCCC
  68. static const size_t VERSION_RULES_IDX = 8;
  69. static void usage() {
  70. std::cerr << "Usage: tzdatacheck BASE_TZ_DIR DATA_TZ_DIR\n"
  71. "\n"
  72. "Checks whether any timezone update distro in DATA_TZ_DIR is compatible with the\n"
  73. "current Android release and better than or the same as base timezone rules in\n"
  74. "BASE_TZ_DIR. If the timezone rules in BASE_TZ_DIR are a higher version than the\n"
  75. "one in DATA_TZ_DIR the DATA_TZ_DIR is renamed and then deleted.\n";
  76. exit(1);
  77. }
  78. /*
  79. * Opens a file and fills buffer with the first byteCount bytes from the file.
  80. * If the file does not exist or cannot be opened or is too short then false is returned.
  81. * If the bytes were read successfully then true is returned.
  82. */
  83. static bool readBytes(const std::string& fileName, char* buffer, size_t byteCount) {
  84. FILE* file = fopen(fileName.c_str(), "r");
  85. if (file == nullptr) {
  86. if (errno != ENOENT) {
  87. PLOG(WARNING) << "Error opening file " << fileName;
  88. }
  89. return false;
  90. }
  91. size_t bytesRead = fread(buffer, 1, byteCount, file);
  92. fclose(file);
  93. if (bytesRead != byteCount) {
  94. LOG(WARNING) << fileName << " is too small. " << byteCount << " bytes required";
  95. return false;
  96. }
  97. return true;
  98. }
  99. static bool checkDigits(const char* buffer, const size_t count, size_t* i) {
  100. for (size_t j = 0; j < count; j++) {
  101. char toCheck = buffer[(*i)++];
  102. if (!isdigit(toCheck)) {
  103. return false;
  104. }
  105. }
  106. return true;
  107. }
  108. static bool checkValidVersionBytes(const char* buffer) {
  109. // See READ_DATA_LENGTH comments above for a description of the format.
  110. size_t i = 0;
  111. if (!checkDigits(buffer, 3, &i)) {
  112. return false;
  113. }
  114. if (buffer[i++] != '.') {
  115. return false;
  116. }
  117. if (!checkDigits(buffer, 3, &i)) {
  118. return false;
  119. }
  120. if (buffer[i++] != '|') {
  121. return false;
  122. }
  123. if (!checkDigits(buffer, 4, &i)) {
  124. return false;
  125. }
  126. // Ignore the last character. It is assumed to be a letter but we don't check because it's not
  127. // obvious what would happen at 'z'.
  128. return true;
  129. }
  130. /* Return the parent directory of dirName. */
  131. static std::string getParentDir(const std::string& dirName) {
  132. char *cMutableDirName = strdup(dirName.c_str());
  133. std::string parentDir = dirname(cMutableDirName);
  134. free(cMutableDirName);
  135. return parentDir;
  136. }
  137. /* Deletes a single file, symlink or directory. Called from nftw(). */
  138. static int deleteFn(const char* fpath, const struct stat*, int typeflag, struct FTW*) {
  139. LOG(DEBUG) << "Inspecting " << fpath;
  140. switch (typeflag) {
  141. case FTW_F:
  142. case FTW_SL:
  143. LOG(DEBUG) << "Unlinking " << fpath;
  144. if (unlink(fpath)) {
  145. PLOG(WARNING) << "Failed to unlink file/symlink " << fpath;
  146. }
  147. break;
  148. case FTW_D:
  149. case FTW_DP:
  150. LOG(DEBUG) << "Removing dir " << fpath;
  151. if (rmdir(fpath)) {
  152. PLOG(WARNING) << "Failed to remove dir " << fpath;
  153. }
  154. break;
  155. default:
  156. LOG(WARNING) << "Unsupported file type " << fpath << ": " << typeflag;
  157. break;
  158. }
  159. return 0;
  160. }
  161. enum PathStatus { ERR, NONE, IS_DIR, IS_REG, UNKNOWN };
  162. static PathStatus checkPath(const std::string& path) {
  163. struct stat buf;
  164. if (stat(path.c_str(), &buf) != 0) {
  165. if (errno != ENOENT) {
  166. PLOG(WARNING) << "Unable to stat " << path;
  167. return ERR;
  168. }
  169. return NONE;
  170. }
  171. return S_ISDIR(buf.st_mode) ? IS_DIR : S_ISREG(buf.st_mode) ? IS_REG : UNKNOWN;
  172. }
  173. /*
  174. * Deletes fileToDelete and returns true if it is successful. If fileToDelete is not a file or
  175. * cannot be accessed this method returns false.
  176. */
  177. static bool deleteFile(const std::string& fileToDelete) {
  178. // Check whether the file exists.
  179. PathStatus pathStatus = checkPath(fileToDelete);
  180. if (pathStatus == NONE) {
  181. LOG(INFO) << "Path " << fileToDelete << " does not exist";
  182. return true;
  183. }
  184. if (pathStatus != IS_REG) {
  185. LOG(WARNING) << "Path " << fileToDelete << " failed to stat() or is not a file.";
  186. return false;
  187. }
  188. // Attempt the deletion.
  189. int rc = unlink(fileToDelete.c_str());
  190. if (rc != 0) {
  191. PLOG(WARNING) << "unlink() failed for " << fileToDelete;
  192. }
  193. return rc == 0;
  194. }
  195. /*
  196. * Deletes dirToDelete and returns true if it is successful in removing or moving the directory out
  197. * of the way. If dirToDelete does not exist this function does nothing and returns true. If
  198. * dirToDelete is not a directory or cannot be accessed this method returns false.
  199. *
  200. * During deletion, this function first renames the directory to a temporary name. If the temporary
  201. * directory cannot be created, or the directory cannot be renamed, false is returned. After the
  202. * rename, deletion of files and subdirs beneath the directory is performed on a "best effort"
  203. * basis. Symlinks beneath the directory are not followed.
  204. */
  205. static bool deleteDir(const std::string& dirToDelete) {
  206. // Check whether the dir exists.
  207. int pathStatus = checkPath(dirToDelete);
  208. if (pathStatus == NONE) {
  209. LOG(INFO) << "Path " << dirToDelete << " does not exist";
  210. return true;
  211. }
  212. if (pathStatus != IS_DIR) {
  213. LOG(WARNING) << "Path " << dirToDelete << " failed to stat() or is not a directory.";
  214. return false;
  215. }
  216. // First, rename dirToDelete.
  217. std::string tempDirNameTemplate = getParentDir(dirToDelete);
  218. tempDirNameTemplate += "/tempXXXXXX";
  219. // Create an empty directory with the temporary name. For this we need a non-const char*.
  220. std::vector<char> tempDirName(tempDirNameTemplate.length() + 1);
  221. strcpy(&tempDirName[0], tempDirNameTemplate.c_str());
  222. if (mkdtemp(&tempDirName[0]) == nullptr) {
  223. PLOG(WARNING) << "Unable to create a temporary directory: " << tempDirNameTemplate;
  224. return false;
  225. }
  226. // Rename dirToDelete to tempDirName (replacing the empty tempDirName directory created above).
  227. int rc = rename(dirToDelete.c_str(), &tempDirName[0]);
  228. if (rc == -1) {
  229. PLOG(WARNING) << "Unable to rename directory from " << dirToDelete << " to "
  230. << &tempDirName[0];
  231. return false;
  232. }
  233. // Recursively delete contents of tempDirName.
  234. rc = nftw(&tempDirName[0], deleteFn, 10 /* openFiles */,
  235. FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
  236. if (rc == -1) {
  237. LOG(INFO) << "Could not delete directory: " << &tempDirName[0];
  238. }
  239. return true;
  240. }
  241. /*
  242. * Deletes the timezone update distro directory.
  243. */
  244. static void deleteUpdateDistroDir(const std::string& distroDirName) {
  245. LOG(INFO) << "Removing: " << distroDirName;
  246. if (!deleteDir(distroDirName)) {
  247. LOG(WARNING) << "Deletion of distro dir " << distroDirName << " was not successful";
  248. }
  249. }
  250. static void handleStagedUninstall(const std::string& dataStagedDirName,
  251. const std::string& dataCurrentDirName,
  252. const PathStatus dataCurrentDirStatus) {
  253. LOG(INFO) << "Staged operation is an uninstall.";
  254. // Delete the current install directory.
  255. switch (dataCurrentDirStatus) {
  256. case NONE:
  257. // This is unexpected: No uninstall should be staged if there is nothing to
  258. // uninstall. Carry on anyway.
  259. LOG(WARNING) << "No current install to delete.";
  260. break;
  261. case IS_DIR:
  262. // This is normal. Delete the current install dir.
  263. if (!deleteDir(dataCurrentDirName)) {
  264. LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
  265. << " was not successful";
  266. // If this happens we don't know whether we were able to delete or not. We don't
  267. // delete the staged operation so it will be retried next boot unless overridden.
  268. return;
  269. }
  270. break;
  271. case IS_REG:
  272. default:
  273. // This is unexpected: We can try to delete the unexpected file and carry on.
  274. LOG(WARNING) << "Current distro dir " << dataCurrentDirName
  275. << " is not actually a directory. Attempting deletion.";
  276. if (!deleteFile(dataCurrentDirName)) {
  277. LOG(WARNING) << "Could not delete " << dataCurrentDirName;
  278. return;
  279. }
  280. break;
  281. }
  282. // Delete the staged uninstall dir.
  283. if (!deleteDir(dataStagedDirName)) {
  284. LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
  285. << " was not successful";
  286. // If this happens we don't know whether we were able to delete the staged operation
  287. // or not.
  288. return;
  289. }
  290. LOG(INFO) << "Staged uninstall complete.";
  291. }
  292. static void handleStagedInstall(const std::string& dataStagedDirName,
  293. const std::string& dataCurrentDirName,
  294. const PathStatus dataCurrentDirStatus) {
  295. LOG(INFO) << "Staged operation is an install.";
  296. switch (dataCurrentDirStatus) {
  297. case NONE:
  298. // This is expected: This is the first install.
  299. LOG(INFO) << "No current install to replace.";
  300. break;
  301. case IS_DIR:
  302. // This is expected: We are replacing an existing install.
  303. // Delete the current dir so we can replace it.
  304. if (!deleteDir(dataCurrentDirName)) {
  305. LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
  306. << " was not successful";
  307. // If this happens, we cannot proceed.
  308. return;
  309. }
  310. break;
  311. case IS_REG:
  312. default:
  313. // This is unexpected: We can try to delete the unexpected file and carry on.
  314. LOG(WARNING) << "Current distro dir " << dataCurrentDirName
  315. << " is not actually a directory. Attempting deletion.";
  316. if (!deleteFile(dataCurrentDirName)) {
  317. LOG(WARNING) << "Could not delete " << dataCurrentDirName;
  318. return;
  319. }
  320. break;
  321. }
  322. // Move the staged dir so it is the new current dir, completing the install.
  323. LOG(INFO) << "Moving " << dataStagedDirName << " to " << dataCurrentDirName;
  324. int rc = rename(dataStagedDirName.c_str(), dataCurrentDirName.c_str());
  325. if (rc == -1) {
  326. PLOG(WARNING) << "Unable to rename directory from " << dataStagedDirName << " to "
  327. << &dataCurrentDirName[0];
  328. return;
  329. }
  330. LOG(INFO) << "Staged install complete.";
  331. }
  332. /*
  333. * Process a staged operation if there is one.
  334. */
  335. static void processStagedOperation(const std::string& dataStagedDirName,
  336. const std::string& dataCurrentDirName) {
  337. PathStatus dataStagedDirStatus = checkPath(dataStagedDirName);
  338. // Exit early for the common case.
  339. if (dataStagedDirStatus == NONE) {
  340. LOG(DEBUG) << "No staged time zone operation.";
  341. return;
  342. }
  343. // Check known directory names are in a good starting state.
  344. if (dataStagedDirStatus != IS_DIR) {
  345. LOG(WARNING) << "Staged distro dir " << dataStagedDirName
  346. << " could not be accessed or is not a directory."
  347. << " stagedDirStatus=" << dataStagedDirStatus;
  348. return;
  349. }
  350. // dataStagedDirStatus == IS_DIR.
  351. // Work out whether there is anything currently installed.
  352. PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
  353. if (dataCurrentDirStatus == ERR) {
  354. LOG(WARNING) << "Current install dir " << dataCurrentDirName << " could not be accessed"
  355. << " dataCurrentDirStatus=" << dataCurrentDirStatus;
  356. return;
  357. }
  358. // We must perform the staged operation.
  359. // Check to see if the staged directory contains an uninstall or an install operation.
  360. std::string uninstallTombStoneFile(dataStagedDirName);
  361. uninstallTombStoneFile += UNINSTALL_TOMBSTONE_FILE_NAME;
  362. int uninstallTombStoneFileStatus = checkPath(uninstallTombStoneFile);
  363. if (uninstallTombStoneFileStatus != IS_REG && uninstallTombStoneFileStatus != NONE) {
  364. // Error case.
  365. LOG(WARNING) << "Unable to determine if the staged operation is an uninstall.";
  366. return;
  367. }
  368. if (uninstallTombStoneFileStatus == IS_REG) {
  369. handleStagedUninstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
  370. } else {
  371. // uninstallTombStoneFileStatus == NONE meaning this is a staged install.
  372. handleStagedInstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
  373. }
  374. }
  375. /*
  376. * After a platform update it is likely that the "base" timezone data found on the device will be
  377. * newer than the version found in the data partition. This tool detects this case and removes the
  378. * version in /data.
  379. *
  380. * Note: This code is related to code in com.android.server.updates.TzDataInstallReceiver. The
  381. * paths for the metadata and current timezone data must match.
  382. *
  383. * Typically on device the two args will be:
  384. * /apex/com.google.runtime/etc/tz /data/misc/zoneinfo
  385. *
  386. * See usage() for usage notes.
  387. */
  388. int main(int argc, char* argv[]) {
  389. if (argc != 3) {
  390. usage();
  391. return 1;
  392. }
  393. const char* baseZoneInfoDir = argv[1];
  394. const char* dataZoneInfoDir = argv[2];
  395. std::string dataStagedDirName(dataZoneInfoDir);
  396. dataStagedDirName += STAGED_DIR_NAME;
  397. std::string dataCurrentDirName(dataZoneInfoDir);
  398. dataCurrentDirName += CURRENT_DIR_NAME;
  399. // Check for an process any staged operation.
  400. // If the staged operation could not be handled we still have to validate the current installed
  401. // directory so we do not check for errors and do not quit early.
  402. processStagedOperation(dataStagedDirName, dataCurrentDirName);
  403. // Check the distro directory exists. If it does not, exit quickly: nothing to do.
  404. PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
  405. if (dataCurrentDirStatus == NONE) {
  406. LOG(INFO) << "timezone distro dir " << dataCurrentDirName
  407. << " does not exist. No action required.";
  408. return 0;
  409. }
  410. // If the distro directory path is not a directory or we can't stat() the path, exit with a
  411. // warning: either there's a problem accessing storage or the world is not as it should be;
  412. // nothing to do.
  413. if (dataCurrentDirStatus != IS_DIR) {
  414. LOG(WARNING) << "Current distro dir " << dataCurrentDirName
  415. << " could not be accessed or is not a directory. result=" << dataCurrentDirStatus;
  416. return 2;
  417. }
  418. // Check the installed distro version.
  419. std::string distroVersionFileName(dataCurrentDirName);
  420. distroVersionFileName += DISTRO_VERSION_FILENAME;
  421. std::vector<char> distroVersion;
  422. distroVersion.reserve(READ_DATA_LENGTH);
  423. bool distroVersionReadOk =
  424. readBytes(distroVersionFileName, distroVersion.data(), READ_DATA_LENGTH);
  425. if (!distroVersionReadOk) {
  426. LOG(WARNING) << "distro version file " << distroVersionFileName
  427. << " does not exist or is too short. Deleting distro dir.";
  428. // Implies the contents of the data partition is corrupt in some way. Try to clean up.
  429. deleteUpdateDistroDir(dataCurrentDirName);
  430. return 3;
  431. }
  432. if (!checkValidVersionBytes(distroVersion.data())) {
  433. LOG(WARNING) << "distro version file " << distroVersionFileName
  434. << " is not valid. Deleting distro dir.";
  435. // Implies the contents of the data partition is corrupt in some way. Try to clean up.
  436. deleteUpdateDistroDir(dataCurrentDirName);
  437. return 4;
  438. }
  439. // Check the base tz data set version.
  440. std::string baseVersionFileName(baseZoneInfoDir);
  441. baseVersionFileName += BASE_VERSION_FILENAME;
  442. std::vector<char> baseVersion;
  443. baseVersion.reserve(READ_DATA_LENGTH);
  444. bool baseVersionReadOk =
  445. readBytes(baseVersionFileName, baseVersion.data(), READ_DATA_LENGTH);
  446. if (!baseVersionReadOk) {
  447. // Implies the contents of the system partition is corrupt in some way. Nothing we can do.
  448. LOG(WARNING) << baseVersionFileName << " does not exist or could not be opened";
  449. return 6;
  450. }
  451. if (!checkValidVersionBytes(baseVersion.data())) {
  452. // Implies the contents of the system partition is corrupt in some way. Nothing we can do.
  453. LOG(WARNING) << baseVersionFileName << " is not valid.";
  454. return 7;
  455. }
  456. std::string actualDistroVersion = std::string(distroVersion.data(), FORMAT_VERSION_LEN);
  457. std::string baseTzVersion = std::string(baseVersion.data(), FORMAT_VERSION_LEN);
  458. // Check the first 3 bytes of the format version: these are the major version (e.g. 001).
  459. // It must match the one we support exactly to be ok.
  460. if (strncmp(
  461. &distroVersion[FORMAT_MAJOR_VERSION_IDX],
  462. &baseTzVersion[FORMAT_MAJOR_VERSION_IDX],
  463. FORMAT_MAJOR_VERSION_LEN) != 0) {
  464. LOG(INFO) << "distro version file " << distroVersionFileName
  465. << " major version is not the required version " << baseTzVersion
  466. << ", was \"" << actualDistroVersion << "\". Deleting distro dir.";
  467. // This implies there has been an OTA and the installed distro is not compatible with a
  468. // new version of Android. Remove the installed distro.
  469. deleteUpdateDistroDir(dataCurrentDirName);
  470. return 5;
  471. }
  472. // Check the last 3 bytes of the format version: these are the minor version (e.g. 001).
  473. // If the version in the distro is < the minor version required by this device it cannot be
  474. // used.
  475. if (strncmp(
  476. &distroVersion[FORMAT_MINOR_VERSION_IDX],
  477. &baseTzVersion[FORMAT_MINOR_VERSION_IDX],
  478. FORMAT_MINOR_VERSION_LEN) < 0) {
  479. LOG(INFO) << "distro version file " << distroVersionFileName
  480. << " minor version is not the required version " << baseTzVersion
  481. << ", was \"" << actualDistroVersion << "\". Deleting distro dir.";
  482. // This implies there has been an OTA and the installed distro is not compatible with a
  483. // new version of Android. Remove the installed distro.
  484. deleteUpdateDistroDir(dataCurrentDirName);
  485. return 5;
  486. }
  487. // Compare the distro rules version against the system rules version.
  488. if (strncmp(
  489. &baseVersion[VERSION_RULES_IDX],
  490. &distroVersion[VERSION_RULES_IDX],
  491. RULES_VERSION_LEN) <= 0) {
  492. LOG(INFO) << "Found an installed distro but it is valid. No action taken.";
  493. // Implies there is an installed update, but it is good.
  494. return 0;
  495. }
  496. // Implies there has been an OTA and the system version of the timezone rules is now newer
  497. // than the version installed in /data. Remove the installed distro.
  498. LOG(INFO) << "timezone distro in " << dataCurrentDirName << " is older than data in "
  499. << baseVersionFileName << "; fixing...";
  500. deleteUpdateDistroDir(dataCurrentDirName);
  501. return 0;
  502. }