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