1 // Copyright 2009 The Android Open Source Project 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <stdarg.h> 6 #include <string.h> 7 #include <unistd.h> 8 #include <fcntl.h> 9 #include <time.h> 10 #include <dirent.h> 11 #include <errno.h> 12 #include <assert.h> 13 #include <ctype.h> 14 #include <utime.h> 15 #include <sys/stat.h> 16 #include <sys/types.h> 17 #include <stdint.h> 18 19 #include <cutils/properties.h> 20 21 #include <private/android_filesystem_config.h> 22 23 #ifndef PATH_MAX 24 #define PATH_MAX 4096 25 #endif 26 27 // First version. 28 #define FILE_VERSION_1 0xffff0001 29 30 // Introduces backup all option to header. 31 #define FILE_VERSION_2 0xffff0002 32 33 #define FILE_VERSION FILE_VERSION_2 34 35 namespace android { 36 37 static char nameBuffer[PATH_MAX]; 38 static struct stat statBuffer; 39 40 static char copyBuffer[8192]; 41 static char *backupFilePath = NULL; 42 43 static uint32_t inputFileVersion; 44 45 static int opt_backupAll; 46 47 #define SPECIAL_NO_TOUCH 0 48 #define SPECIAL_NO_BACKUP 1 49 50 struct special_dir { 51 const char* path; 52 int type; 53 }; 54 55 /* Directory paths that we will not backup/restore */ 56 static const struct special_dir SKIP_PATHS[] = { 57 { "/data/misc", SPECIAL_NO_TOUCH }, 58 { "/data/system/batterystats.bin", SPECIAL_NO_TOUCH }, 59 { "/data/system/location", SPECIAL_NO_TOUCH }, 60 { "/data/dalvik-cache", SPECIAL_NO_BACKUP }, 61 { NULL, 0 }, 62 }; 63 64 /* This is just copied from the shell's built-in wipe command. */ 65 static int wipe (const char *path) 66 { 67 DIR *dir; 68 struct dirent *de; 69 int ret; 70 int i; 71 72 dir = opendir(path); 73 74 if (dir == NULL) { 75 fprintf (stderr, "Error opendir'ing %s: %s\n", 76 path, strerror(errno)); 77 return 0; 78 } 79 80 char *filenameOffset; 81 82 strcpy(nameBuffer, path); 83 strcat(nameBuffer, "/"); 84 85 filenameOffset = nameBuffer + strlen(nameBuffer); 86 87 for (;;) { 88 de = readdir(dir); 89 90 if (de == NULL) { 91 break; 92 } 93 94 if (0 == strcmp(de->d_name, ".") 95 || 0 == strcmp(de->d_name, "..") 96 || 0 == strcmp(de->d_name, "lost+found") 97 ) { 98 continue; 99 } 100 101 strcpy(filenameOffset, de->d_name); 102 bool noBackup = false; 103 104 /* See if this is a path we should skip. */ 105 for (i = 0; SKIP_PATHS[i].path; i++) { 106 if (strcmp(SKIP_PATHS[i].path, nameBuffer) == 0) { 107 if (opt_backupAll || SKIP_PATHS[i].type == SPECIAL_NO_BACKUP) { 108 // In this case we didn't back up the directory -- 109 // we do want to wipe its contents, but not the 110 // directory itself, since the restore file won't 111 // contain the directory. 112 noBackup = true; 113 } 114 break; 115 } 116 } 117 118 if (!noBackup && SKIP_PATHS[i].path != NULL) { 119 // This is a SPECIAL_NO_TOUCH directory. 120 continue; 121 } 122 123 ret = lstat (nameBuffer, &statBuffer); 124 125 if (ret != 0) { 126 fprintf(stderr, "warning -- stat() error on '%s': %s\n", 127 nameBuffer, strerror(errno)); 128 continue; 129 } 130 131 if(S_ISDIR(statBuffer.st_mode)) { 132 int i; 133 char *newpath; 134 135 newpath = strdup(nameBuffer); 136 if (wipe(newpath) == 0) { 137 free(newpath); 138 closedir(dir); 139 return 0; 140 } 141 142 if (!noBackup) { 143 ret = rmdir(newpath); 144 if (ret != 0) { 145 fprintf(stderr, "warning -- rmdir() error on '%s': %s\n", 146 newpath, strerror(errno)); 147 } 148 } 149 150 free(newpath); 151 152 strcpy(nameBuffer, path); 153 strcat(nameBuffer, "/"); 154 155 } else { 156 // Don't delete the backup file 157 if (backupFilePath && strcmp(backupFilePath, nameBuffer) == 0) { 158 continue; 159 } 160 ret = unlink(nameBuffer); 161 162 if (ret != 0) { 163 fprintf(stderr, "warning -- unlink() error on '%s': %s\n", 164 nameBuffer, strerror(errno)); 165 } 166 } 167 } 168 169 closedir(dir); 170 171 return 1; 172 } 173 174 static int write_int32(FILE* fh, int32_t val) 175 { 176 int res = fwrite(&val, 1, sizeof(val), fh); 177 if (res != sizeof(val)) { 178 fprintf(stderr, "unable to write int32 (%d bytes): %s\n", res, strerror(errno)); 179 return 0; 180 } 181 182 return 1; 183 } 184 185 static int write_int64(FILE* fh, int64_t val) 186 { 187 int res = fwrite(&val, 1, sizeof(val), fh); 188 if (res != sizeof(val)) { 189 fprintf(stderr, "unable to write int64 (%d bytes): %s\n", res, strerror(errno)); 190 return 0; 191 } 192 193 return 1; 194 } 195 196 static int copy_file(FILE* dest, FILE* src, off_t size, const char* destName, 197 const char* srcName) 198 { 199 errno = 0; 200 201 off_t origSize = size; 202 203 while (size > 0) { 204 int amt = size > (off_t)sizeof(copyBuffer) ? sizeof(copyBuffer) : (int)size; 205 int readLen = fread(copyBuffer, 1, amt, src); 206 if (readLen <= 0) { 207 if (srcName != NULL) { 208 fprintf(stderr, "unable to read source (%d of %ld bytes) file '%s': %s\n", 209 amt, origSize, srcName, errno != 0 ? strerror(errno) : "unexpected EOF"); 210 } else { 211 fprintf(stderr, "unable to read buffer (%d of %ld bytes): %s\n", 212 amt, origSize, errno != 0 ? strerror(errno) : "unexpected EOF"); 213 } 214 return 0; 215 } 216 int writeLen = fwrite(copyBuffer, 1, readLen, dest); 217 if (writeLen != readLen) { 218 if (destName != NULL) { 219 fprintf(stderr, "unable to write file (%d of %d bytes) '%s': '%s'\n", 220 writeLen, readLen, destName, strerror(errno)); 221 } else { 222 fprintf(stderr, "unable to write buffer (%d of %d bytes): '%s'\n", 223 writeLen, readLen, strerror(errno)); 224 } 225 return 0; 226 } 227 size -= readLen; 228 } 229 return 1; 230 } 231 232 #define TYPE_END 0 233 #define TYPE_DIR 1 234 #define TYPE_FILE 2 235 236 static int write_header(FILE* fh, int type, const char* path, const struct stat* st) 237 { 238 int pathLen = strlen(path); 239 if (!write_int32(fh, type)) return 0; 240 if (!write_int32(fh, pathLen)) return 0; 241 if (fwrite(path, 1, pathLen, fh) != (size_t)pathLen) { 242 fprintf(stderr, "unable to write: %s\n", strerror(errno)); 243 return 0; 244 } 245 246 if (!write_int32(fh, st->st_uid)) return 0; 247 if (!write_int32(fh, st->st_gid)) return 0; 248 if (!write_int32(fh, st->st_mode)) return 0; 249 if (!write_int64(fh, ((int64_t)st->st_atime)*1000*1000*1000)) return 0; 250 if (!write_int64(fh, ((int64_t)st->st_mtime)*1000*1000*1000)) return 0; 251 if (!write_int64(fh, ((int64_t)st->st_ctime)*1000*1000*1000)) return 0; 252 253 return 1; 254 } 255 256 static int backup_dir(FILE* fh, const char* srcPath) 257 { 258 DIR *dir; 259 struct dirent *de; 260 char* fullPath = NULL; 261 int srcLen = strlen(srcPath); 262 int result = 1; 263 int i; 264 265 dir = opendir(srcPath); 266 267 if (dir == NULL) { 268 fprintf (stderr, "error opendir'ing '%s': %s\n", 269 srcPath, strerror(errno)); 270 return 0; 271 } 272 273 for (;;) { 274 de = readdir(dir); 275 276 if (de == NULL) { 277 break; 278 } 279 280 if (0 == strcmp(de->d_name, ".") 281 || 0 == strcmp(de->d_name, "..") 282 || 0 == strcmp(de->d_name, "lost+found") 283 ) { 284 continue; 285 } 286 287 if (fullPath != NULL) { 288 free(fullPath); 289 } 290 fullPath = (char*)malloc(srcLen + strlen(de->d_name) + 2); 291 strcpy(fullPath, srcPath); 292 fullPath[srcLen] = '/'; 293 strcpy(fullPath+srcLen+1, de->d_name); 294 295 /* See if this is a path we should skip. */ 296 if (!opt_backupAll) { 297 for (i = 0; SKIP_PATHS[i].path; i++) { 298 if (strcmp(SKIP_PATHS[i].path, fullPath) == 0) { 299 break; 300 } 301 } 302 if (SKIP_PATHS[i].path != NULL) { 303 continue; 304 } 305 } 306 307 int ret = lstat(fullPath, &statBuffer); 308 309 if (ret != 0) { 310 fprintf(stderr, "stat() error on '%s': %s\n", 311 fullPath, strerror(errno)); 312 result = 0; 313 goto done; 314 } 315 316 if(S_ISDIR(statBuffer.st_mode)) { 317 printf("Saving dir %s...\n", fullPath); 318 319 if (write_header(fh, TYPE_DIR, fullPath, &statBuffer) == 0) { 320 result = 0; 321 goto done; 322 } 323 if (backup_dir(fh, fullPath) == 0) { 324 result = 0; 325 goto done; 326 } 327 } else if (S_ISREG(statBuffer.st_mode)) { 328 // Skip the backup file 329 if (backupFilePath && strcmp(fullPath, backupFilePath) == 0) { 330 printf("Skipping backup file %s...\n", backupFilePath); 331 continue; 332 } else { 333 printf("Saving file %s...\n", fullPath); 334 } 335 if (write_header(fh, TYPE_FILE, fullPath, &statBuffer) == 0) { 336 result = 0; 337 goto done; 338 } 339 340 off_t size = statBuffer.st_size; 341 if (!write_int64(fh, size)) { 342 result = 0; 343 goto done; 344 } 345 346 FILE* src = fopen(fullPath, "r"); 347 if (src == NULL) { 348 fprintf(stderr, "unable to open source file '%s': %s\n", 349 fullPath, strerror(errno)); 350 result = 0; 351 goto done; 352 } 353 354 int copyres = copy_file(fh, src, size, NULL, fullPath); 355 fclose(src); 356 if (!copyres) { 357 result = 0; 358 goto done; 359 } 360 } 361 } 362 363 done: 364 if (fullPath != NULL) { 365 free(fullPath); 366 } 367 368 closedir(dir); 369 370 return result; 371 } 372 373 static int backup_data(const char* destPath) 374 { 375 int res = -1; 376 377 FILE* fh = fopen(destPath, "w"); 378 if (fh == NULL) { 379 fprintf(stderr, "unable to open destination '%s': %s\n", 380 destPath, strerror(errno)); 381 return -1; 382 } 383 384 printf("Backing up /data to %s...\n", destPath); 385 386 // The path that shouldn't be backed up 387 backupFilePath = strdup(destPath); 388 389 if (!write_int32(fh, FILE_VERSION)) goto done; 390 if (!write_int32(fh, opt_backupAll)) goto done; 391 if (!backup_dir(fh, "/data")) goto done; 392 if (!write_int32(fh, 0)) goto done; 393 394 res = 0; 395 396 done: 397 if (fflush(fh) != 0) { 398 fprintf(stderr, "error flushing destination '%s': %s\n", 399 destPath, strerror(errno)); 400 res = -1; 401 goto donedone; 402 } 403 if (fsync(fileno(fh)) != 0) { 404 fprintf(stderr, "error syncing destination '%s': %s\n", 405 destPath, strerror(errno)); 406 res = -1; 407 goto donedone; 408 } 409 fclose(fh); 410 sync(); 411 412 donedone: 413 return res; 414 } 415 416 static int32_t read_int32(FILE* fh, int32_t defVal) 417 { 418 int32_t val; 419 if (fread(&val, 1, sizeof(val), fh) != sizeof(val)) { 420 fprintf(stderr, "unable to read: %s\n", strerror(errno)); 421 return defVal; 422 } 423 424 return val; 425 } 426 427 static int64_t read_int64(FILE* fh, int64_t defVal) 428 { 429 int64_t val; 430 if (fread(&val, 1, sizeof(val), fh) != sizeof(val)) { 431 fprintf(stderr, "unable to read: %s\n", strerror(errno)); 432 return defVal; 433 } 434 435 return val; 436 } 437 438 static int read_header(FILE* fh, int* type, char** path, struct stat* st) 439 { 440 *type = read_int32(fh, -1); 441 if (*type == TYPE_END) { 442 return 1; 443 } 444 445 if (*type < 0) { 446 fprintf(stderr, "bad token %d in restore file\n", *type); 447 return 0; 448 } 449 450 int32_t pathLen = read_int32(fh, -1); 451 if (pathLen <= 0) { 452 fprintf(stderr, "bad path length %d in restore file\n", pathLen); 453 return 0; 454 } 455 char* readPath = (char*)malloc(pathLen+1); 456 if (fread(readPath, 1, pathLen, fh) != (size_t)pathLen) { 457 fprintf(stderr, "truncated path in restore file\n"); 458 free(readPath); 459 return 0; 460 } 461 readPath[pathLen] = 0; 462 *path = readPath; 463 464 st->st_uid = read_int32(fh, -1); 465 if (st->st_uid == (uid_t)-1) { 466 fprintf(stderr, "bad uid in restore file at '%s'\n", readPath); 467 return 0; 468 } 469 st->st_gid = read_int32(fh, -1); 470 if (st->st_gid == (gid_t)-1) { 471 fprintf(stderr, "bad gid in restore file at '%s'\n", readPath); 472 return 0; 473 } 474 st->st_mode = read_int32(fh, -1); 475 if (st->st_mode == (mode_t)-1) { 476 fprintf(stderr, "bad mode in restore file at '%s'\n", readPath); 477 return 0; 478 } 479 int64_t ltime = read_int64(fh, -1); 480 if (ltime < 0) { 481 fprintf(stderr, "bad atime in restore file at '%s'\n", readPath); 482 return 0; 483 } 484 st->st_atime = (time_t)(ltime/1000/1000/1000); 485 ltime = read_int64(fh, -1); 486 if (ltime < 0) { 487 fprintf(stderr, "bad mtime in restore file at '%s'\n", readPath); 488 return 0; 489 } 490 st->st_mtime = (time_t)(ltime/1000/1000/1000); 491 ltime = read_int64(fh, -1); 492 if (ltime < 0) { 493 fprintf(stderr, "bad ctime in restore file at '%s'\n", readPath); 494 return 0; 495 } 496 st->st_ctime = (time_t)(ltime/1000/1000/1000); 497 498 st->st_mode &= (S_IRWXU|S_IRWXG|S_IRWXO); 499 500 return 1; 501 } 502 503 static int restore_data(const char* srcPath) 504 { 505 int res = -1; 506 507 FILE* fh = fopen(srcPath, "r"); 508 if (fh == NULL) { 509 fprintf(stderr, "Unable to open source '%s': %s\n", 510 srcPath, strerror(errno)); 511 return -1; 512 } 513 514 inputFileVersion = read_int32(fh, 0); 515 if (inputFileVersion < FILE_VERSION_1 || inputFileVersion > FILE_VERSION) { 516 fprintf(stderr, "Restore file has bad version: 0x%x\n", inputFileVersion); 517 goto done; 518 } 519 520 if (inputFileVersion >= FILE_VERSION_2) { 521 opt_backupAll = read_int32(fh, 0); 522 } else { 523 opt_backupAll = 0; 524 } 525 526 // The path that shouldn't be deleted 527 backupFilePath = strdup(srcPath); 528 529 printf("Wiping contents of /data...\n"); 530 if (!wipe("/data")) { 531 goto done; 532 } 533 534 printf("Restoring from %s to /data...\n", srcPath); 535 536 while (1) { 537 int type; 538 char* path = NULL; 539 if (read_header(fh, &type, &path, &statBuffer) == 0) { 540 goto done; 541 } 542 if (type == 0) { 543 break; 544 } 545 546 const char* typeName = "?"; 547 548 if (type == TYPE_DIR) { 549 typeName = "dir"; 550 551 printf("Restoring dir %s...\n", path); 552 553 if (mkdir(path, statBuffer.st_mode) != 0) { 554 if (errno != EEXIST) { 555 fprintf(stderr, "unable to create directory '%s': %s\n", 556 path, strerror(errno)); 557 free(path); 558 goto done; 559 } 560 } 561 562 } else if (type == TYPE_FILE) { 563 typeName = "file"; 564 off_t size = read_int64(fh, -1); 565 if (size < 0) { 566 fprintf(stderr, "bad file size %ld in restore file\n", size); 567 free(path); 568 goto done; 569 } 570 571 printf("Restoring file %s...\n", path); 572 573 FILE* dest = fopen(path, "w"); 574 if (dest == NULL) { 575 fprintf(stderr, "unable to open destination file '%s': %s\n", 576 path, strerror(errno)); 577 free(path); 578 goto done; 579 } 580 581 int copyres = copy_file(dest, fh, size, path, NULL); 582 fclose(dest); 583 if (!copyres) { 584 free(path); 585 goto done; 586 } 587 588 } else { 589 fprintf(stderr, "unknown node type %d\n", type); 590 goto done; 591 } 592 593 // Do this even for directories, since the dir may have already existed 594 // so we need to make sure it gets the correct mode. 595 if (chmod(path, statBuffer.st_mode&(S_IRWXU|S_IRWXG|S_IRWXO)) != 0) { 596 fprintf(stderr, "unable to chmod destination %s '%s' to 0x%x: %s\n", 597 typeName, path, statBuffer.st_mode, strerror(errno)); 598 free(path); 599 goto done; 600 } 601 602 if (chown(path, statBuffer.st_uid, statBuffer.st_gid) != 0) { 603 fprintf(stderr, "unable to chown destination %s '%s' to uid %d / gid %d: %s\n", 604 typeName, path, (int)statBuffer.st_uid, (int)statBuffer.st_gid, strerror(errno)); 605 free(path); 606 goto done; 607 } 608 609 struct utimbuf timbuf; 610 timbuf.actime = statBuffer.st_atime; 611 timbuf.modtime = statBuffer.st_mtime; 612 if (utime(path, &timbuf) != 0) { 613 fprintf(stderr, "unable to utime destination %s '%s': %s\n", 614 typeName, path, strerror(errno)); 615 free(path); 616 goto done; 617 } 618 619 620 free(path); 621 } 622 623 res = 0; 624 625 done: 626 fclose(fh); 627 628 return res; 629 } 630 631 static void show_help(const char *cmd) 632 { 633 fprintf(stderr,"Usage: %s COMMAND [options] [backup-file-path]\n", cmd); 634 635 fprintf(stderr, "commands are:\n" 636 " help Show this help text.\n" 637 " backup Perform a backup of /data.\n" 638 " restore Perform a restore of /data.\n"); 639 fprintf(stderr, "options include:\n" 640 " -h Show this help text.\n" 641 " -a Backup all files.\n"); 642 fprintf(stderr, "\n backup-file-path Defaults to /sdcard/backup.dat .\n" 643 " On devices that emulate the sdcard, you will need to\n" 644 " explicitly specify the directory it is mapped to,\n" 645 " to avoid recursive backup or deletion of the backup file\n" 646 " during restore.\n\n" 647 " Eg. /data/media/0/backup.dat\n"); 648 fprintf(stderr, "\nThe %s command allows you to perform low-level\n" 649 "backup and restore of the /data partition. This is\n" 650 "where all user data is kept, allowing for a fairly\n" 651 "complete restore of a device's state. Note that\n" 652 "because this is low-level, it will only work across\n" 653 "builds of the same (or very similar) device software.\n", 654 cmd); 655 } 656 657 } /* namespace android */ 658 659 int main (int argc, char **argv) 660 { 661 int restore = 0; 662 663 if (getuid() != AID_ROOT) { 664 fprintf(stderr, "error -- %s must run as root\n", argv[0]); 665 exit(-1); 666 } 667 668 if (argc < 2) { 669 fprintf(stderr, "No command specified.\n"); 670 android::show_help(argv[0]); 671 exit(-1); 672 } 673 674 if (0 == strcmp(argv[1], "restore")) { 675 restore = 1; 676 } else if (0 == strcmp(argv[1], "help")) { 677 android::show_help(argv[0]); 678 exit(0); 679 } else if (0 != strcmp(argv[1], "backup")) { 680 fprintf(stderr, "Unknown command: %s\n", argv[1]); 681 android::show_help(argv[0]); 682 exit(-1); 683 } 684 685 android::opt_backupAll = 0; 686 687 optind = 2; 688 689 for (;;) { 690 int ret; 691 692 ret = getopt(argc, argv, "ah"); 693 694 if (ret < 0) { 695 break; 696 } 697 698 switch(ret) { 699 case 'a': 700 android::opt_backupAll = 1; 701 if (restore) fprintf(stderr, "Warning: -a option ignored on restore\n"); 702 break; 703 case 'h': 704 android::show_help(argv[0]); 705 exit(0); 706 break; 707 708 default: 709 fprintf(stderr,"Unrecognized Option\n"); 710 android::show_help(argv[0]); 711 exit(-1); 712 break; 713 } 714 } 715 716 const char* backupFile = "/sdcard/backup.dat"; 717 718 if (argc > optind) { 719 backupFile = argv[optind]; 720 optind++; 721 if (argc != optind) { 722 fprintf(stderr, "Too many arguments\n"); 723 android::show_help(argv[0]); 724 exit(-1); 725 } 726 } 727 728 printf("Stopping system...\n"); 729 property_set("ctl.stop", "runtime"); 730 property_set("ctl.stop", "zygote"); 731 sleep(1); 732 733 int res; 734 if (restore) { 735 res = android::restore_data(backupFile); 736 if (res != 0) { 737 // Don't restart system, since the data partition is hosed. 738 return res; 739 } 740 printf("Restore complete! Restarting system, cross your fingers...\n"); 741 } else { 742 res = android::backup_data(backupFile); 743 if (res == 0) { 744 printf("Backup complete! Restarting system...\n"); 745 } else { 746 printf("Restarting system...\n"); 747 } 748 } 749 750 property_set("ctl.start", "zygote"); 751 property_set("ctl.start", "runtime"); 752 } 753