Home | History | Annotate | Download | only in rawbu
      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