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