Home | History | Annotate | Download | only in updater
      1 /*
      2  * Copyright (C) 2009 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 <stdarg.h>
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <sys/mount.h>
     24 #include <sys/stat.h>
     25 #include <sys/types.h>
     26 #include <sys/wait.h>
     27 #include <unistd.h>
     28 #include <fcntl.h>
     29 #include <time.h>
     30 #include <selinux/selinux.h>
     31 #include <ftw.h>
     32 #include <sys/capability.h>
     33 #include <sys/xattr.h>
     34 #include <linux/xattr.h>
     35 #include <inttypes.h>
     36 
     37 #include "bootloader.h"
     38 #include "applypatch/applypatch.h"
     39 #include "cutils/android_reboot.h"
     40 #include "cutils/misc.h"
     41 #include "cutils/properties.h"
     42 #include "edify/expr.h"
     43 #include "mincrypt/sha.h"
     44 #include "minzip/DirUtil.h"
     45 #include "mtdutils/mounts.h"
     46 #include "mtdutils/mtdutils.h"
     47 #include "updater.h"
     48 
     49 #ifdef USE_EXT4
     50 #include "make_ext4fs.h"
     51 #endif
     52 
     53 // mount(fs_type, partition_type, location, mount_point)
     54 //
     55 //    fs_type="yaffs2" partition_type="MTD"     location=partition
     56 //    fs_type="ext4"   partition_type="EMMC"    location=device
     57 Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
     58     char* result = NULL;
     59     if (argc != 4) {
     60         return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc);
     61     }
     62     char* fs_type;
     63     char* partition_type;
     64     char* location;
     65     char* mount_point;
     66     if (ReadArgs(state, argv, 4, &fs_type, &partition_type,
     67                  &location, &mount_point) < 0) {
     68         return NULL;
     69     }
     70 
     71     if (strlen(fs_type) == 0) {
     72         ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
     73         goto done;
     74     }
     75     if (strlen(partition_type) == 0) {
     76         ErrorAbort(state, "partition_type argument to %s() can't be empty",
     77                    name);
     78         goto done;
     79     }
     80     if (strlen(location) == 0) {
     81         ErrorAbort(state, "location argument to %s() can't be empty", name);
     82         goto done;
     83     }
     84     if (strlen(mount_point) == 0) {
     85         ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
     86         goto done;
     87     }
     88 
     89     char *secontext = NULL;
     90 
     91     if (sehandle) {
     92         selabel_lookup(sehandle, &secontext, mount_point, 0755);
     93         setfscreatecon(secontext);
     94     }
     95 
     96     mkdir(mount_point, 0755);
     97 
     98     if (secontext) {
     99         freecon(secontext);
    100         setfscreatecon(NULL);
    101     }
    102 
    103     if (strcmp(partition_type, "MTD") == 0) {
    104         mtd_scan_partitions();
    105         const MtdPartition* mtd;
    106         mtd = mtd_find_partition_by_name(location);
    107         if (mtd == NULL) {
    108             printf("%s: no mtd partition named \"%s\"",
    109                     name, location);
    110             result = strdup("");
    111             goto done;
    112         }
    113         if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
    114             printf("mtd mount of %s failed: %s\n",
    115                     location, strerror(errno));
    116             result = strdup("");
    117             goto done;
    118         }
    119         result = mount_point;
    120     } else {
    121         if (mount(location, mount_point, fs_type,
    122                   MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
    123             printf("%s: failed to mount %s at %s: %s\n",
    124                     name, location, mount_point, strerror(errno));
    125             result = strdup("");
    126         } else {
    127             result = mount_point;
    128         }
    129     }
    130 
    131 done:
    132     free(fs_type);
    133     free(partition_type);
    134     free(location);
    135     if (result != mount_point) free(mount_point);
    136     return StringValue(result);
    137 }
    138 
    139 
    140 // is_mounted(mount_point)
    141 Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
    142     char* result = NULL;
    143     if (argc != 1) {
    144         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    145     }
    146     char* mount_point;
    147     if (ReadArgs(state, argv, 1, &mount_point) < 0) {
    148         return NULL;
    149     }
    150     if (strlen(mount_point) == 0) {
    151         ErrorAbort(state, "mount_point argument to unmount() can't be empty");
    152         goto done;
    153     }
    154 
    155     scan_mounted_volumes();
    156     const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
    157     if (vol == NULL) {
    158         result = strdup("");
    159     } else {
    160         result = mount_point;
    161     }
    162 
    163 done:
    164     if (result != mount_point) free(mount_point);
    165     return StringValue(result);
    166 }
    167 
    168 
    169 Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
    170     char* result = NULL;
    171     if (argc != 1) {
    172         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    173     }
    174     char* mount_point;
    175     if (ReadArgs(state, argv, 1, &mount_point) < 0) {
    176         return NULL;
    177     }
    178     if (strlen(mount_point) == 0) {
    179         ErrorAbort(state, "mount_point argument to unmount() can't be empty");
    180         goto done;
    181     }
    182 
    183     scan_mounted_volumes();
    184     const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
    185     if (vol == NULL) {
    186         printf("unmount of %s failed; no such volume\n", mount_point);
    187         result = strdup("");
    188     } else {
    189         unmount_mounted_volume(vol);
    190         result = mount_point;
    191     }
    192 
    193 done:
    194     if (result != mount_point) free(mount_point);
    195     return StringValue(result);
    196 }
    197 
    198 
    199 // format(fs_type, partition_type, location, fs_size, mount_point)
    200 //
    201 //    fs_type="yaffs2" partition_type="MTD"     location=partition fs_size=<bytes> mount_point=<location>
    202 //    fs_type="ext4"   partition_type="EMMC"    location=device    fs_size=<bytes> mount_point=<location>
    203 //    if fs_size == 0, then make_ext4fs uses the entire partition.
    204 //    if fs_size > 0, that is the size to use
    205 //    if fs_size < 0, then reserve that many bytes at the end of the partition
    206 Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
    207     char* result = NULL;
    208     if (argc != 5) {
    209         return ErrorAbort(state, "%s() expects 5 args, got %d", name, argc);
    210     }
    211     char* fs_type;
    212     char* partition_type;
    213     char* location;
    214     char* fs_size;
    215     char* mount_point;
    216 
    217     if (ReadArgs(state, argv, 5, &fs_type, &partition_type, &location, &fs_size, &mount_point) < 0) {
    218         return NULL;
    219     }
    220 
    221     if (strlen(fs_type) == 0) {
    222         ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
    223         goto done;
    224     }
    225     if (strlen(partition_type) == 0) {
    226         ErrorAbort(state, "partition_type argument to %s() can't be empty",
    227                    name);
    228         goto done;
    229     }
    230     if (strlen(location) == 0) {
    231         ErrorAbort(state, "location argument to %s() can't be empty", name);
    232         goto done;
    233     }
    234 
    235     if (strlen(mount_point) == 0) {
    236         ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
    237         goto done;
    238     }
    239 
    240     if (strcmp(partition_type, "MTD") == 0) {
    241         mtd_scan_partitions();
    242         const MtdPartition* mtd = mtd_find_partition_by_name(location);
    243         if (mtd == NULL) {
    244             printf("%s: no mtd partition named \"%s\"",
    245                     name, location);
    246             result = strdup("");
    247             goto done;
    248         }
    249         MtdWriteContext* ctx = mtd_write_partition(mtd);
    250         if (ctx == NULL) {
    251             printf("%s: can't write \"%s\"", name, location);
    252             result = strdup("");
    253             goto done;
    254         }
    255         if (mtd_erase_blocks(ctx, -1) == -1) {
    256             mtd_write_close(ctx);
    257             printf("%s: failed to erase \"%s\"", name, location);
    258             result = strdup("");
    259             goto done;
    260         }
    261         if (mtd_write_close(ctx) != 0) {
    262             printf("%s: failed to close \"%s\"", name, location);
    263             result = strdup("");
    264             goto done;
    265         }
    266         result = location;
    267 #ifdef USE_EXT4
    268     } else if (strcmp(fs_type, "ext4") == 0) {
    269         int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle);
    270         if (status != 0) {
    271             printf("%s: make_ext4fs failed (%d) on %s",
    272                     name, status, location);
    273             result = strdup("");
    274             goto done;
    275         }
    276         result = location;
    277 #endif
    278     } else {
    279         printf("%s: unsupported fs_type \"%s\" partition_type \"%s\"",
    280                 name, fs_type, partition_type);
    281     }
    282 
    283 done:
    284     free(fs_type);
    285     free(partition_type);
    286     if (result != location) free(location);
    287     return StringValue(result);
    288 }
    289 
    290 Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) {
    291     char* result = NULL;
    292     if (argc != 2) {
    293         return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
    294     }
    295 
    296     char* src_name;
    297     char* dst_name;
    298 
    299     if (ReadArgs(state, argv, 2, &src_name, &dst_name) < 0) {
    300         return NULL;
    301     }
    302     if (strlen(src_name) == 0) {
    303         ErrorAbort(state, "src_name argument to %s() can't be empty", name);
    304         goto done;
    305     }
    306     if (strlen(dst_name) == 0) {
    307         ErrorAbort(state, "dst_name argument to %s() can't be empty",
    308                    name);
    309         goto done;
    310     }
    311 
    312     if (rename(src_name, dst_name) != 0) {
    313         ErrorAbort(state, "Rename of %s() to %s() failed, error %s()",
    314           src_name, dst_name, strerror(errno));
    315     } else {
    316         result = dst_name;
    317     }
    318 
    319 done:
    320     free(src_name);
    321     if (result != dst_name) free(dst_name);
    322     return StringValue(result);
    323 }
    324 
    325 Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
    326     char** paths = malloc(argc * sizeof(char*));
    327     int i;
    328     for (i = 0; i < argc; ++i) {
    329         paths[i] = Evaluate(state, argv[i]);
    330         if (paths[i] == NULL) {
    331             int j;
    332             for (j = 0; j < i; ++i) {
    333                 free(paths[j]);
    334             }
    335             free(paths);
    336             return NULL;
    337         }
    338     }
    339 
    340     bool recursive = (strcmp(name, "delete_recursive") == 0);
    341 
    342     int success = 0;
    343     for (i = 0; i < argc; ++i) {
    344         if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
    345             ++success;
    346         free(paths[i]);
    347     }
    348     free(paths);
    349 
    350     char buffer[10];
    351     sprintf(buffer, "%d", success);
    352     return StringValue(strdup(buffer));
    353 }
    354 
    355 
    356 Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
    357     if (argc != 2) {
    358         return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
    359     }
    360     char* frac_str;
    361     char* sec_str;
    362     if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
    363         return NULL;
    364     }
    365 
    366     double frac = strtod(frac_str, NULL);
    367     int sec = strtol(sec_str, NULL, 10);
    368 
    369     UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
    370     fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
    371 
    372     free(sec_str);
    373     return StringValue(frac_str);
    374 }
    375 
    376 Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
    377     if (argc != 1) {
    378         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    379     }
    380     char* frac_str;
    381     if (ReadArgs(state, argv, 1, &frac_str) < 0) {
    382         return NULL;
    383     }
    384 
    385     double frac = strtod(frac_str, NULL);
    386 
    387     UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
    388     fprintf(ui->cmd_pipe, "set_progress %f\n", frac);
    389 
    390     return StringValue(frac_str);
    391 }
    392 
    393 // package_extract_dir(package_path, destination_path)
    394 Value* PackageExtractDirFn(const char* name, State* state,
    395                           int argc, Expr* argv[]) {
    396     if (argc != 2) {
    397         return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
    398     }
    399     char* zip_path;
    400     char* dest_path;
    401     if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
    402 
    403     ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
    404 
    405     // To create a consistent system image, never use the clock for timestamps.
    406     struct utimbuf timestamp = { 1217592000, 1217592000 };  // 8/1/2008 default
    407 
    408     bool success = mzExtractRecursive(za, zip_path, dest_path,
    409                                       MZ_EXTRACT_FILES_ONLY, &timestamp,
    410                                       NULL, NULL, sehandle);
    411     free(zip_path);
    412     free(dest_path);
    413     return StringValue(strdup(success ? "t" : ""));
    414 }
    415 
    416 
    417 // package_extract_file(package_path, destination_path)
    418 //   or
    419 // package_extract_file(package_path)
    420 //   to return the entire contents of the file as the result of this
    421 //   function (the char* returned is actually a FileContents*).
    422 Value* PackageExtractFileFn(const char* name, State* state,
    423                            int argc, Expr* argv[]) {
    424     if (argc != 1 && argc != 2) {
    425         return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
    426                           name, argc);
    427     }
    428     bool success = false;
    429     if (argc == 2) {
    430         // The two-argument version extracts to a file.
    431 
    432         char* zip_path;
    433         char* dest_path;
    434         if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
    435 
    436         ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
    437         const ZipEntry* entry = mzFindZipEntry(za, zip_path);
    438         if (entry == NULL) {
    439             printf("%s: no %s in package\n", name, zip_path);
    440             goto done2;
    441         }
    442 
    443         FILE* f = fopen(dest_path, "wb");
    444         if (f == NULL) {
    445             printf("%s: can't open %s for write: %s\n",
    446                     name, dest_path, strerror(errno));
    447             goto done2;
    448         }
    449         success = mzExtractZipEntryToFile(za, entry, fileno(f));
    450         fclose(f);
    451 
    452       done2:
    453         free(zip_path);
    454         free(dest_path);
    455         return StringValue(strdup(success ? "t" : ""));
    456     } else {
    457         // The one-argument version returns the contents of the file
    458         // as the result.
    459 
    460         char* zip_path;
    461         Value* v = malloc(sizeof(Value));
    462         v->type = VAL_BLOB;
    463         v->size = -1;
    464         v->data = NULL;
    465 
    466         if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
    467 
    468         ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
    469         const ZipEntry* entry = mzFindZipEntry(za, zip_path);
    470         if (entry == NULL) {
    471             printf("%s: no %s in package\n", name, zip_path);
    472             goto done1;
    473         }
    474 
    475         v->size = mzGetZipEntryUncompLen(entry);
    476         v->data = malloc(v->size);
    477         if (v->data == NULL) {
    478             printf("%s: failed to allocate %ld bytes for %s\n",
    479                     name, (long)v->size, zip_path);
    480             goto done1;
    481         }
    482 
    483         success = mzExtractZipEntryToBuffer(za, entry,
    484                                             (unsigned char *)v->data);
    485 
    486       done1:
    487         free(zip_path);
    488         if (!success) {
    489             free(v->data);
    490             v->data = NULL;
    491             v->size = -1;
    492         }
    493         return v;
    494     }
    495 }
    496 
    497 // Create all parent directories of name, if necessary.
    498 static int make_parents(char* name) {
    499     char* p;
    500     for (p = name + (strlen(name)-1); p > name; --p) {
    501         if (*p != '/') continue;
    502         *p = '\0';
    503         if (make_parents(name) < 0) return -1;
    504         int result = mkdir(name, 0700);
    505         if (result == 0) printf("symlink(): created [%s]\n", name);
    506         *p = '/';
    507         if (result == 0 || errno == EEXIST) {
    508             // successfully created or already existed; we're done
    509             return 0;
    510         } else {
    511             printf("failed to mkdir %s: %s\n", name, strerror(errno));
    512             return -1;
    513         }
    514     }
    515     return 0;
    516 }
    517 
    518 // symlink target src1 src2 ...
    519 //    unlinks any previously existing src1, src2, etc before creating symlinks.
    520 Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
    521     if (argc == 0) {
    522         return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
    523     }
    524     char* target;
    525     target = Evaluate(state, argv[0]);
    526     if (target == NULL) return NULL;
    527 
    528     char** srcs = ReadVarArgs(state, argc-1, argv+1);
    529     if (srcs == NULL) {
    530         free(target);
    531         return NULL;
    532     }
    533 
    534     int bad = 0;
    535     int i;
    536     for (i = 0; i < argc-1; ++i) {
    537         if (unlink(srcs[i]) < 0) {
    538             if (errno != ENOENT) {
    539                 printf("%s: failed to remove %s: %s\n",
    540                         name, srcs[i], strerror(errno));
    541                 ++bad;
    542             }
    543         }
    544         if (make_parents(srcs[i])) {
    545             printf("%s: failed to symlink %s to %s: making parents failed\n",
    546                     name, srcs[i], target);
    547             ++bad;
    548         }
    549         if (symlink(target, srcs[i]) < 0) {
    550             printf("%s: failed to symlink %s to %s: %s\n",
    551                     name, srcs[i], target, strerror(errno));
    552             ++bad;
    553         }
    554         free(srcs[i]);
    555     }
    556     free(srcs);
    557     if (bad) {
    558         return ErrorAbort(state, "%s: some symlinks failed", name);
    559     }
    560     return StringValue(strdup(""));
    561 }
    562 
    563 
    564 Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
    565     char* result = NULL;
    566     bool recursive = (strcmp(name, "set_perm_recursive") == 0);
    567 
    568     int min_args = 4 + (recursive ? 1 : 0);
    569     if (argc < min_args) {
    570         return ErrorAbort(state, "%s() expects %d+ args, got %d",
    571                           name, min_args, argc);
    572     }
    573 
    574     char** args = ReadVarArgs(state, argc, argv);
    575     if (args == NULL) return NULL;
    576 
    577     char* end;
    578     int i;
    579     int bad = 0;
    580 
    581     int uid = strtoul(args[0], &end, 0);
    582     if (*end != '\0' || args[0][0] == 0) {
    583         ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
    584         goto done;
    585     }
    586 
    587     int gid = strtoul(args[1], &end, 0);
    588     if (*end != '\0' || args[1][0] == 0) {
    589         ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
    590         goto done;
    591     }
    592 
    593     if (recursive) {
    594         int dir_mode = strtoul(args[2], &end, 0);
    595         if (*end != '\0' || args[2][0] == 0) {
    596             ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
    597             goto done;
    598         }
    599 
    600         int file_mode = strtoul(args[3], &end, 0);
    601         if (*end != '\0' || args[3][0] == 0) {
    602             ErrorAbort(state, "%s: \"%s\" not a valid filemode",
    603                        name, args[3]);
    604             goto done;
    605         }
    606 
    607         for (i = 4; i < argc; ++i) {
    608             dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
    609         }
    610     } else {
    611         int mode = strtoul(args[2], &end, 0);
    612         if (*end != '\0' || args[2][0] == 0) {
    613             ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
    614             goto done;
    615         }
    616 
    617         for (i = 3; i < argc; ++i) {
    618             if (chown(args[i], uid, gid) < 0) {
    619                 printf("%s: chown of %s to %d %d failed: %s\n",
    620                         name, args[i], uid, gid, strerror(errno));
    621                 ++bad;
    622             }
    623             if (chmod(args[i], mode) < 0) {
    624                 printf("%s: chmod of %s to %o failed: %s\n",
    625                         name, args[i], mode, strerror(errno));
    626                 ++bad;
    627             }
    628         }
    629     }
    630     result = strdup("");
    631 
    632 done:
    633     for (i = 0; i < argc; ++i) {
    634         free(args[i]);
    635     }
    636     free(args);
    637 
    638     if (bad) {
    639         free(result);
    640         return ErrorAbort(state, "%s: some changes failed", name);
    641     }
    642     return StringValue(result);
    643 }
    644 
    645 struct perm_parsed_args {
    646     bool has_uid;
    647     uid_t uid;
    648     bool has_gid;
    649     gid_t gid;
    650     bool has_mode;
    651     mode_t mode;
    652     bool has_fmode;
    653     mode_t fmode;
    654     bool has_dmode;
    655     mode_t dmode;
    656     bool has_selabel;
    657     char* selabel;
    658     bool has_capabilities;
    659     uint64_t capabilities;
    660 };
    661 
    662 static struct perm_parsed_args ParsePermArgs(int argc, char** args) {
    663     int i;
    664     struct perm_parsed_args parsed;
    665     int bad = 0;
    666     static int max_warnings = 20;
    667 
    668     memset(&parsed, 0, sizeof(parsed));
    669 
    670     for (i = 1; i < argc; i += 2) {
    671         if (strcmp("uid", args[i]) == 0) {
    672             int64_t uid;
    673             if (sscanf(args[i+1], "%" SCNd64, &uid) == 1) {
    674                 parsed.uid = uid;
    675                 parsed.has_uid = true;
    676             } else {
    677                 printf("ParsePermArgs: invalid UID \"%s\"\n", args[i + 1]);
    678                 bad++;
    679             }
    680             continue;
    681         }
    682         if (strcmp("gid", args[i]) == 0) {
    683             int64_t gid;
    684             if (sscanf(args[i+1], "%" SCNd64, &gid) == 1) {
    685                 parsed.gid = gid;
    686                 parsed.has_gid = true;
    687             } else {
    688                 printf("ParsePermArgs: invalid GID \"%s\"\n", args[i + 1]);
    689                 bad++;
    690             }
    691             continue;
    692         }
    693         if (strcmp("mode", args[i]) == 0) {
    694             int32_t mode;
    695             if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) {
    696                 parsed.mode = mode;
    697                 parsed.has_mode = true;
    698             } else {
    699                 printf("ParsePermArgs: invalid mode \"%s\"\n", args[i + 1]);
    700                 bad++;
    701             }
    702             continue;
    703         }
    704         if (strcmp("dmode", args[i]) == 0) {
    705             int32_t mode;
    706             if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) {
    707                 parsed.dmode = mode;
    708                 parsed.has_dmode = true;
    709             } else {
    710                 printf("ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1]);
    711                 bad++;
    712             }
    713             continue;
    714         }
    715         if (strcmp("fmode", args[i]) == 0) {
    716             int32_t mode;
    717             if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) {
    718                 parsed.fmode = mode;
    719                 parsed.has_fmode = true;
    720             } else {
    721                 printf("ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1]);
    722                 bad++;
    723             }
    724             continue;
    725         }
    726         if (strcmp("capabilities", args[i]) == 0) {
    727             int64_t capabilities;
    728             if (sscanf(args[i+1], "%" SCNi64, &capabilities) == 1) {
    729                 parsed.capabilities = capabilities;
    730                 parsed.has_capabilities = true;
    731             } else {
    732                 printf("ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1]);
    733                 bad++;
    734             }
    735             continue;
    736         }
    737         if (strcmp("selabel", args[i]) == 0) {
    738             if (args[i+1][0] != '\0') {
    739                 parsed.selabel = args[i+1];
    740                 parsed.has_selabel = true;
    741             } else {
    742                 printf("ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1]);
    743                 bad++;
    744             }
    745             continue;
    746         }
    747         if (max_warnings != 0) {
    748             printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i]);
    749             max_warnings--;
    750             if (max_warnings == 0) {
    751                 printf("ParsedPermArgs: suppressing further warnings\n");
    752             }
    753         }
    754     }
    755     return parsed;
    756 }
    757 
    758 static int ApplyParsedPerms(
    759         const char* filename,
    760         const struct stat *statptr,
    761         struct perm_parsed_args parsed)
    762 {
    763     int bad = 0;
    764 
    765     /* ignore symlinks */
    766     if (S_ISLNK(statptr->st_mode)) {
    767         return 0;
    768     }
    769 
    770     if (parsed.has_uid) {
    771         if (chown(filename, parsed.uid, -1) < 0) {
    772             printf("ApplyParsedPerms: chown of %s to %d failed: %s\n",
    773                    filename, parsed.uid, strerror(errno));
    774             bad++;
    775         }
    776     }
    777 
    778     if (parsed.has_gid) {
    779         if (chown(filename, -1, parsed.gid) < 0) {
    780             printf("ApplyParsedPerms: chgrp of %s to %d failed: %s\n",
    781                    filename, parsed.gid, strerror(errno));
    782             bad++;
    783         }
    784     }
    785 
    786     if (parsed.has_mode) {
    787         if (chmod(filename, parsed.mode) < 0) {
    788             printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n",
    789                    filename, parsed.mode, strerror(errno));
    790             bad++;
    791         }
    792     }
    793 
    794     if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) {
    795         if (chmod(filename, parsed.dmode) < 0) {
    796             printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n",
    797                    filename, parsed.dmode, strerror(errno));
    798             bad++;
    799         }
    800     }
    801 
    802     if (parsed.has_fmode && S_ISREG(statptr->st_mode)) {
    803         if (chmod(filename, parsed.fmode) < 0) {
    804             printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n",
    805                    filename, parsed.fmode, strerror(errno));
    806             bad++;
    807         }
    808     }
    809 
    810     if (parsed.has_selabel) {
    811         // TODO: Don't silently ignore ENOTSUP
    812         if (lsetfilecon(filename, parsed.selabel) && (errno != ENOTSUP)) {
    813             printf("ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n",
    814                    filename, parsed.selabel, strerror(errno));
    815             bad++;
    816         }
    817     }
    818 
    819     if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) {
    820         if (parsed.capabilities == 0) {
    821             if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) {
    822                 // Report failure unless it's ENODATA (attribute not set)
    823                 printf("ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n",
    824                        filename, parsed.capabilities, strerror(errno));
    825                 bad++;
    826             }
    827         } else {
    828             struct vfs_cap_data cap_data;
    829             memset(&cap_data, 0, sizeof(cap_data));
    830             cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
    831             cap_data.data[0].permitted = (uint32_t) (parsed.capabilities & 0xffffffff);
    832             cap_data.data[0].inheritable = 0;
    833             cap_data.data[1].permitted = (uint32_t) (parsed.capabilities >> 32);
    834             cap_data.data[1].inheritable = 0;
    835             if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) {
    836                 printf("ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n",
    837                        filename, parsed.capabilities, strerror(errno));
    838                 bad++;
    839             }
    840         }
    841     }
    842 
    843     return bad;
    844 }
    845 
    846 // nftw doesn't allow us to pass along context, so we need to use
    847 // global variables.  *sigh*
    848 static struct perm_parsed_args recursive_parsed_args;
    849 
    850 static int do_SetMetadataRecursive(const char* filename, const struct stat *statptr,
    851         int fileflags, struct FTW *pfwt) {
    852     return ApplyParsedPerms(filename, statptr, recursive_parsed_args);
    853 }
    854 
    855 static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) {
    856     int i;
    857     int bad = 0;
    858     static int nwarnings = 0;
    859     struct stat sb;
    860     Value* result = NULL;
    861 
    862     bool recursive = (strcmp(name, "set_metadata_recursive") == 0);
    863 
    864     if ((argc % 2) != 1) {
    865         return ErrorAbort(state, "%s() expects an odd number of arguments, got %d",
    866                           name, argc);
    867     }
    868 
    869     char** args = ReadVarArgs(state, argc, argv);
    870     if (args == NULL) return NULL;
    871 
    872     if (lstat(args[0], &sb) == -1) {
    873         result = ErrorAbort(state, "%s: Error on lstat of \"%s\": %s", name, args[0], strerror(errno));
    874         goto done;
    875     }
    876 
    877     struct perm_parsed_args parsed = ParsePermArgs(argc, args);
    878 
    879     if (recursive) {
    880         recursive_parsed_args = parsed;
    881         bad += nftw(args[0], do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS);
    882         memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args));
    883     } else {
    884         bad += ApplyParsedPerms(args[0], &sb, parsed);
    885     }
    886 
    887 done:
    888     for (i = 0; i < argc; ++i) {
    889         free(args[i]);
    890     }
    891     free(args);
    892 
    893     if (result != NULL) {
    894         return result;
    895     }
    896 
    897     if (bad > 0) {
    898         return ErrorAbort(state, "%s: some changes failed", name);
    899     }
    900 
    901     return StringValue(strdup(""));
    902 }
    903 
    904 Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
    905     if (argc != 1) {
    906         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    907     }
    908     char* key;
    909     key = Evaluate(state, argv[0]);
    910     if (key == NULL) return NULL;
    911 
    912     char value[PROPERTY_VALUE_MAX];
    913     property_get(key, value, "");
    914     free(key);
    915 
    916     return StringValue(strdup(value));
    917 }
    918 
    919 
    920 // file_getprop(file, key)
    921 //
    922 //   interprets 'file' as a getprop-style file (key=value pairs, one
    923 //   per line, # comment lines and blank lines okay), and returns the value
    924 //   for 'key' (or "" if it isn't defined).
    925 Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
    926     char* result = NULL;
    927     char* buffer = NULL;
    928     char* filename;
    929     char* key;
    930     if (ReadArgs(state, argv, 2, &filename, &key) < 0) {
    931         return NULL;
    932     }
    933 
    934     struct stat st;
    935     if (stat(filename, &st) < 0) {
    936         ErrorAbort(state, "%s: failed to stat \"%s\": %s",
    937                    name, filename, strerror(errno));
    938         goto done;
    939     }
    940 
    941 #define MAX_FILE_GETPROP_SIZE    65536
    942 
    943     if (st.st_size > MAX_FILE_GETPROP_SIZE) {
    944         ErrorAbort(state, "%s too large for %s (max %d)",
    945                    filename, name, MAX_FILE_GETPROP_SIZE);
    946         goto done;
    947     }
    948 
    949     buffer = malloc(st.st_size+1);
    950     if (buffer == NULL) {
    951         ErrorAbort(state, "%s: failed to alloc %lld bytes", name, st.st_size+1);
    952         goto done;
    953     }
    954 
    955     FILE* f = fopen(filename, "rb");
    956     if (f == NULL) {
    957         ErrorAbort(state, "%s: failed to open %s: %s",
    958                    name, filename, strerror(errno));
    959         goto done;
    960     }
    961 
    962     if (fread(buffer, 1, st.st_size, f) != st.st_size) {
    963         ErrorAbort(state, "%s: failed to read %lld bytes from %s",
    964                    name, st.st_size+1, filename);
    965         fclose(f);
    966         goto done;
    967     }
    968     buffer[st.st_size] = '\0';
    969 
    970     fclose(f);
    971 
    972     char* line = strtok(buffer, "\n");
    973     do {
    974         // skip whitespace at start of line
    975         while (*line && isspace(*line)) ++line;
    976 
    977         // comment or blank line: skip to next line
    978         if (*line == '\0' || *line == '#') continue;
    979 
    980         char* equal = strchr(line, '=');
    981         if (equal == NULL) {
    982             ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
    983                        name, line, filename);
    984             goto done;
    985         }
    986 
    987         // trim whitespace between key and '='
    988         char* key_end = equal-1;
    989         while (key_end > line && isspace(*key_end)) --key_end;
    990         key_end[1] = '\0';
    991 
    992         // not the key we're looking for
    993         if (strcmp(key, line) != 0) continue;
    994 
    995         // skip whitespace after the '=' to the start of the value
    996         char* val_start = equal+1;
    997         while(*val_start && isspace(*val_start)) ++val_start;
    998 
    999         // trim trailing whitespace
   1000         char* val_end = val_start + strlen(val_start)-1;
   1001         while (val_end > val_start && isspace(*val_end)) --val_end;
   1002         val_end[1] = '\0';
   1003 
   1004         result = strdup(val_start);
   1005         break;
   1006 
   1007     } while ((line = strtok(NULL, "\n")));
   1008 
   1009     if (result == NULL) result = strdup("");
   1010 
   1011   done:
   1012     free(filename);
   1013     free(key);
   1014     free(buffer);
   1015     return StringValue(result);
   1016 }
   1017 
   1018 
   1019 static bool write_raw_image_cb(const unsigned char* data,
   1020                                int data_len, void* ctx) {
   1021     int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
   1022     if (r == data_len) return true;
   1023     printf("%s\n", strerror(errno));
   1024     return false;
   1025 }
   1026 
   1027 // write_raw_image(filename_or_blob, partition)
   1028 Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
   1029     char* result = NULL;
   1030 
   1031     Value* partition_value;
   1032     Value* contents;
   1033     if (ReadValueArgs(state, argv, 2, &contents, &partition_value) < 0) {
   1034         return NULL;
   1035     }
   1036 
   1037     char* partition = NULL;
   1038     if (partition_value->type != VAL_STRING) {
   1039         ErrorAbort(state, "partition argument to %s must be string", name);
   1040         goto done;
   1041     }
   1042     partition = partition_value->data;
   1043     if (strlen(partition) == 0) {
   1044         ErrorAbort(state, "partition argument to %s can't be empty", name);
   1045         goto done;
   1046     }
   1047     if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) {
   1048         ErrorAbort(state, "file argument to %s can't be empty", name);
   1049         goto done;
   1050     }
   1051 
   1052     mtd_scan_partitions();
   1053     const MtdPartition* mtd = mtd_find_partition_by_name(partition);
   1054     if (mtd == NULL) {
   1055         printf("%s: no mtd partition named \"%s\"\n", name, partition);
   1056         result = strdup("");
   1057         goto done;
   1058     }
   1059 
   1060     MtdWriteContext* ctx = mtd_write_partition(mtd);
   1061     if (ctx == NULL) {
   1062         printf("%s: can't write mtd partition \"%s\"\n",
   1063                 name, partition);
   1064         result = strdup("");
   1065         goto done;
   1066     }
   1067 
   1068     bool success;
   1069 
   1070     if (contents->type == VAL_STRING) {
   1071         // we're given a filename as the contents
   1072         char* filename = contents->data;
   1073         FILE* f = fopen(filename, "rb");
   1074         if (f == NULL) {
   1075             printf("%s: can't open %s: %s\n",
   1076                     name, filename, strerror(errno));
   1077             result = strdup("");
   1078             goto done;
   1079         }
   1080 
   1081         success = true;
   1082         char* buffer = malloc(BUFSIZ);
   1083         int read;
   1084         while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
   1085             int wrote = mtd_write_data(ctx, buffer, read);
   1086             success = success && (wrote == read);
   1087         }
   1088         free(buffer);
   1089         fclose(f);
   1090     } else {
   1091         // we're given a blob as the contents
   1092         ssize_t wrote = mtd_write_data(ctx, contents->data, contents->size);
   1093         success = (wrote == contents->size);
   1094     }
   1095     if (!success) {
   1096         printf("mtd_write_data to %s failed: %s\n",
   1097                 partition, strerror(errno));
   1098     }
   1099 
   1100     if (mtd_erase_blocks(ctx, -1) == -1) {
   1101         printf("%s: error erasing blocks of %s\n", name, partition);
   1102     }
   1103     if (mtd_write_close(ctx) != 0) {
   1104         printf("%s: error closing write of %s\n", name, partition);
   1105     }
   1106 
   1107     printf("%s %s partition\n",
   1108            success ? "wrote" : "failed to write", partition);
   1109 
   1110     result = success ? partition : strdup("");
   1111 
   1112 done:
   1113     if (result != partition) FreeValue(partition_value);
   1114     FreeValue(contents);
   1115     return StringValue(result);
   1116 }
   1117 
   1118 // apply_patch_space(bytes)
   1119 Value* ApplyPatchSpaceFn(const char* name, State* state,
   1120                          int argc, Expr* argv[]) {
   1121     char* bytes_str;
   1122     if (ReadArgs(state, argv, 1, &bytes_str) < 0) {
   1123         return NULL;
   1124     }
   1125 
   1126     char* endptr;
   1127     size_t bytes = strtol(bytes_str, &endptr, 10);
   1128     if (bytes == 0 && endptr == bytes_str) {
   1129         ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
   1130                    name, bytes_str);
   1131         free(bytes_str);
   1132         return NULL;
   1133     }
   1134 
   1135     return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
   1136 }
   1137 
   1138 
   1139 // apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
   1140 Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
   1141     if (argc < 6 || (argc % 2) == 1) {
   1142         return ErrorAbort(state, "%s(): expected at least 6 args and an "
   1143                                  "even number, got %d",
   1144                           name, argc);
   1145     }
   1146 
   1147     char* source_filename;
   1148     char* target_filename;
   1149     char* target_sha1;
   1150     char* target_size_str;
   1151     if (ReadArgs(state, argv, 4, &source_filename, &target_filename,
   1152                  &target_sha1, &target_size_str) < 0) {
   1153         return NULL;
   1154     }
   1155 
   1156     char* endptr;
   1157     size_t target_size = strtol(target_size_str, &endptr, 10);
   1158     if (target_size == 0 && endptr == target_size_str) {
   1159         ErrorAbort(state, "%s(): can't parse \"%s\" as byte count",
   1160                    name, target_size_str);
   1161         free(source_filename);
   1162         free(target_filename);
   1163         free(target_sha1);
   1164         free(target_size_str);
   1165         return NULL;
   1166     }
   1167 
   1168     int patchcount = (argc-4) / 2;
   1169     Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
   1170 
   1171     int i;
   1172     for (i = 0; i < patchcount; ++i) {
   1173         if (patches[i*2]->type != VAL_STRING) {
   1174             ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
   1175             break;
   1176         }
   1177         if (patches[i*2+1]->type != VAL_BLOB) {
   1178             ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
   1179             break;
   1180         }
   1181     }
   1182     if (i != patchcount) {
   1183         for (i = 0; i < patchcount*2; ++i) {
   1184             FreeValue(patches[i]);
   1185         }
   1186         free(patches);
   1187         return NULL;
   1188     }
   1189 
   1190     char** patch_sha_str = malloc(patchcount * sizeof(char*));
   1191     for (i = 0; i < patchcount; ++i) {
   1192         patch_sha_str[i] = patches[i*2]->data;
   1193         patches[i*2]->data = NULL;
   1194         FreeValue(patches[i*2]);
   1195         patches[i] = patches[i*2+1];
   1196     }
   1197 
   1198     int result = applypatch(source_filename, target_filename,
   1199                             target_sha1, target_size,
   1200                             patchcount, patch_sha_str, patches, NULL);
   1201 
   1202     for (i = 0; i < patchcount; ++i) {
   1203         FreeValue(patches[i]);
   1204     }
   1205     free(patch_sha_str);
   1206     free(patches);
   1207 
   1208     return StringValue(strdup(result == 0 ? "t" : ""));
   1209 }
   1210 
   1211 // apply_patch_check(file, [sha1_1, ...])
   1212 Value* ApplyPatchCheckFn(const char* name, State* state,
   1213                          int argc, Expr* argv[]) {
   1214     if (argc < 1) {
   1215         return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
   1216                           name, argc);
   1217     }
   1218 
   1219     char* filename;
   1220     if (ReadArgs(state, argv, 1, &filename) < 0) {
   1221         return NULL;
   1222     }
   1223 
   1224     int patchcount = argc-1;
   1225     char** sha1s = ReadVarArgs(state, argc-1, argv+1);
   1226 
   1227     int result = applypatch_check(filename, patchcount, sha1s);
   1228 
   1229     int i;
   1230     for (i = 0; i < patchcount; ++i) {
   1231         free(sha1s[i]);
   1232     }
   1233     free(sha1s);
   1234 
   1235     return StringValue(strdup(result == 0 ? "t" : ""));
   1236 }
   1237 
   1238 Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
   1239     char** args = ReadVarArgs(state, argc, argv);
   1240     if (args == NULL) {
   1241         return NULL;
   1242     }
   1243 
   1244     int size = 0;
   1245     int i;
   1246     for (i = 0; i < argc; ++i) {
   1247         size += strlen(args[i]);
   1248     }
   1249     char* buffer = malloc(size+1);
   1250     size = 0;
   1251     for (i = 0; i < argc; ++i) {
   1252         strcpy(buffer+size, args[i]);
   1253         size += strlen(args[i]);
   1254         free(args[i]);
   1255     }
   1256     free(args);
   1257     buffer[size] = '\0';
   1258 
   1259     char* line = strtok(buffer, "\n");
   1260     while (line) {
   1261         fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
   1262                 "ui_print %s\n", line);
   1263         line = strtok(NULL, "\n");
   1264     }
   1265     fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
   1266 
   1267     return StringValue(buffer);
   1268 }
   1269 
   1270 Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) {
   1271     if (argc != 0) {
   1272         return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
   1273     }
   1274     fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "wipe_cache\n");
   1275     return StringValue(strdup("t"));
   1276 }
   1277 
   1278 Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
   1279     if (argc < 1) {
   1280         return ErrorAbort(state, "%s() expects at least 1 arg", name);
   1281     }
   1282     char** args = ReadVarArgs(state, argc, argv);
   1283     if (args == NULL) {
   1284         return NULL;
   1285     }
   1286 
   1287     char** args2 = malloc(sizeof(char*) * (argc+1));
   1288     memcpy(args2, args, sizeof(char*) * argc);
   1289     args2[argc] = NULL;
   1290 
   1291     printf("about to run program [%s] with %d args\n", args2[0], argc);
   1292 
   1293     pid_t child = fork();
   1294     if (child == 0) {
   1295         execv(args2[0], args2);
   1296         printf("run_program: execv failed: %s\n", strerror(errno));
   1297         _exit(1);
   1298     }
   1299     int status;
   1300     waitpid(child, &status, 0);
   1301     if (WIFEXITED(status)) {
   1302         if (WEXITSTATUS(status) != 0) {
   1303             printf("run_program: child exited with status %d\n",
   1304                     WEXITSTATUS(status));
   1305         }
   1306     } else if (WIFSIGNALED(status)) {
   1307         printf("run_program: child terminated by signal %d\n",
   1308                 WTERMSIG(status));
   1309     }
   1310 
   1311     int i;
   1312     for (i = 0; i < argc; ++i) {
   1313         free(args[i]);
   1314     }
   1315     free(args);
   1316     free(args2);
   1317 
   1318     char buffer[20];
   1319     sprintf(buffer, "%d", status);
   1320 
   1321     return StringValue(strdup(buffer));
   1322 }
   1323 
   1324 // Take a sha-1 digest and return it as a newly-allocated hex string.
   1325 static char* PrintSha1(uint8_t* digest) {
   1326     char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
   1327     int i;
   1328     const char* alphabet = "0123456789abcdef";
   1329     for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
   1330         buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
   1331         buffer[i*2+1] = alphabet[digest[i] & 0xf];
   1332     }
   1333     buffer[i*2] = '\0';
   1334     return buffer;
   1335 }
   1336 
   1337 // sha1_check(data)
   1338 //    to return the sha1 of the data (given in the format returned by
   1339 //    read_file).
   1340 //
   1341 // sha1_check(data, sha1_hex, [sha1_hex, ...])
   1342 //    returns the sha1 of the file if it matches any of the hex
   1343 //    strings passed, or "" if it does not equal any of them.
   1344 //
   1345 Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
   1346     if (argc < 1) {
   1347         return ErrorAbort(state, "%s() expects at least 1 arg", name);
   1348     }
   1349 
   1350     Value** args = ReadValueVarArgs(state, argc, argv);
   1351     if (args == NULL) {
   1352         return NULL;
   1353     }
   1354 
   1355     if (args[0]->size < 0) {
   1356         return StringValue(strdup(""));
   1357     }
   1358     uint8_t digest[SHA_DIGEST_SIZE];
   1359     SHA_hash(args[0]->data, args[0]->size, digest);
   1360     FreeValue(args[0]);
   1361 
   1362     if (argc == 1) {
   1363         return StringValue(PrintSha1(digest));
   1364     }
   1365 
   1366     int i;
   1367     uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE);
   1368     for (i = 1; i < argc; ++i) {
   1369         if (args[i]->type != VAL_STRING) {
   1370             printf("%s(): arg %d is not a string; skipping",
   1371                     name, i);
   1372         } else if (ParseSha1(args[i]->data, arg_digest) != 0) {
   1373             // Warn about bad args and skip them.
   1374             printf("%s(): error parsing \"%s\" as sha-1; skipping",
   1375                    name, args[i]->data);
   1376         } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
   1377             break;
   1378         }
   1379         FreeValue(args[i]);
   1380     }
   1381     if (i >= argc) {
   1382         // Didn't match any of the hex strings; return false.
   1383         return StringValue(strdup(""));
   1384     }
   1385     // Found a match; free all the remaining arguments and return the
   1386     // matched one.
   1387     int j;
   1388     for (j = i+1; j < argc; ++j) {
   1389         FreeValue(args[j]);
   1390     }
   1391     return args[i];
   1392 }
   1393 
   1394 // Read a local file and return its contents (the Value* returned
   1395 // is actually a FileContents*).
   1396 Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
   1397     if (argc != 1) {
   1398         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
   1399     }
   1400     char* filename;
   1401     if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
   1402 
   1403     Value* v = malloc(sizeof(Value));
   1404     v->type = VAL_BLOB;
   1405 
   1406     FileContents fc;
   1407     if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) {
   1408         free(filename);
   1409         v->size = -1;
   1410         v->data = NULL;
   1411         free(fc.data);
   1412         return v;
   1413     }
   1414 
   1415     v->size = fc.size;
   1416     v->data = (char*)fc.data;
   1417 
   1418     free(filename);
   1419     return v;
   1420 }
   1421 
   1422 // Immediately reboot the device.  Recovery is not finished normally,
   1423 // so if you reboot into recovery it will re-start applying the
   1424 // current package (because nothing has cleared the copy of the
   1425 // arguments stored in the BCB).
   1426 //
   1427 // The argument is the partition name passed to the android reboot
   1428 // property.  It can be "recovery" to boot from the recovery
   1429 // partition, or "" (empty string) to boot from the regular boot
   1430 // partition.
   1431 Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) {
   1432     if (argc != 2) {
   1433         return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
   1434     }
   1435 
   1436     char* filename;
   1437     char* property;
   1438     if (ReadArgs(state, argv, 2, &filename, &property) < 0) return NULL;
   1439 
   1440     char buffer[80];
   1441 
   1442     // zero out the 'command' field of the bootloader message.
   1443     memset(buffer, 0, sizeof(((struct bootloader_message*)0)->command));
   1444     FILE* f = fopen(filename, "r+b");
   1445     fseek(f, offsetof(struct bootloader_message, command), SEEK_SET);
   1446     fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f);
   1447     fclose(f);
   1448     free(filename);
   1449 
   1450     strcpy(buffer, "reboot,");
   1451     if (property != NULL) {
   1452         strncat(buffer, property, sizeof(buffer)-10);
   1453     }
   1454 
   1455     property_set(ANDROID_RB_PROPERTY, buffer);
   1456 
   1457     sleep(5);
   1458     free(property);
   1459     ErrorAbort(state, "%s() failed to reboot", name);
   1460     return NULL;
   1461 }
   1462 
   1463 // Store a string value somewhere that future invocations of recovery
   1464 // can access it.  This value is called the "stage" and can be used to
   1465 // drive packages that need to do reboots in the middle of
   1466 // installation and keep track of where they are in the multi-stage
   1467 // install.
   1468 //
   1469 // The first argument is the block device for the misc partition
   1470 // ("/misc" in the fstab), which is where this value is stored.  The
   1471 // second argument is the string to store; it should not exceed 31
   1472 // bytes.
   1473 Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
   1474     if (argc != 2) {
   1475         return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
   1476     }
   1477 
   1478     char* filename;
   1479     char* stagestr;
   1480     if (ReadArgs(state, argv, 2, &filename, &stagestr) < 0) return NULL;
   1481 
   1482     // Store this value in the misc partition, immediately after the
   1483     // bootloader message that the main recovery uses to save its
   1484     // arguments in case of the device restarting midway through
   1485     // package installation.
   1486     FILE* f = fopen(filename, "r+b");
   1487     fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET);
   1488     int to_write = strlen(stagestr)+1;
   1489     int max_size = sizeof(((struct bootloader_message*)0)->stage);
   1490     if (to_write > max_size) {
   1491         to_write = max_size;
   1492         stagestr[max_size-1] = 0;
   1493     }
   1494     fwrite(stagestr, to_write, 1, f);
   1495     fclose(f);
   1496 
   1497     free(stagestr);
   1498     return StringValue(filename);
   1499 }
   1500 
   1501 // Return the value most recently saved with SetStageFn.  The argument
   1502 // is the block device for the misc partition.
   1503 Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
   1504     if (argc != 2) {
   1505         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
   1506     }
   1507 
   1508     char* filename;
   1509     if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
   1510 
   1511     char buffer[sizeof(((struct bootloader_message*)0)->stage)];
   1512     FILE* f = fopen(filename, "rb");
   1513     fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET);
   1514     fread(buffer, sizeof(buffer), 1, f);
   1515     fclose(f);
   1516     buffer[sizeof(buffer)-1] = '\0';
   1517 
   1518     return StringValue(strdup(buffer));
   1519 }
   1520 
   1521 void RegisterInstallFunctions() {
   1522     RegisterFunction("mount", MountFn);
   1523     RegisterFunction("is_mounted", IsMountedFn);
   1524     RegisterFunction("unmount", UnmountFn);
   1525     RegisterFunction("format", FormatFn);
   1526     RegisterFunction("show_progress", ShowProgressFn);
   1527     RegisterFunction("set_progress", SetProgressFn);
   1528     RegisterFunction("delete", DeleteFn);
   1529     RegisterFunction("delete_recursive", DeleteFn);
   1530     RegisterFunction("package_extract_dir", PackageExtractDirFn);
   1531     RegisterFunction("package_extract_file", PackageExtractFileFn);
   1532     RegisterFunction("symlink", SymlinkFn);
   1533 
   1534     // Maybe, at some future point, we can delete these functions? They have been
   1535     // replaced by perm_set and perm_set_recursive.
   1536     RegisterFunction("set_perm", SetPermFn);
   1537     RegisterFunction("set_perm_recursive", SetPermFn);
   1538 
   1539     // Usage:
   1540     //   set_metadata("filename", "key1", "value1", "key2", "value2", ...)
   1541     // Example:
   1542     //   set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0);
   1543     RegisterFunction("set_metadata", SetMetadataFn);
   1544 
   1545     // Usage:
   1546     //   set_metadata_recursive("dirname", "key1", "value1", "key2", "value2", ...)
   1547     // Example:
   1548     //   set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0);
   1549     RegisterFunction("set_metadata_recursive", SetMetadataFn);
   1550 
   1551     RegisterFunction("getprop", GetPropFn);
   1552     RegisterFunction("file_getprop", FileGetPropFn);
   1553     RegisterFunction("write_raw_image", WriteRawImageFn);
   1554 
   1555     RegisterFunction("apply_patch", ApplyPatchFn);
   1556     RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
   1557     RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
   1558 
   1559     RegisterFunction("read_file", ReadFileFn);
   1560     RegisterFunction("sha1_check", Sha1CheckFn);
   1561     RegisterFunction("rename", RenameFn);
   1562 
   1563     RegisterFunction("wipe_cache", WipeCacheFn);
   1564 
   1565     RegisterFunction("ui_print", UIPrintFn);
   1566 
   1567     RegisterFunction("run_program", RunProgramFn);
   1568 
   1569     RegisterFunction("reboot_now", RebootNowFn);
   1570     RegisterFunction("get_stage", GetStageFn);
   1571     RegisterFunction("set_stage", SetStageFn);
   1572 }
   1573