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