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