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