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 
     31 #include "cutils/misc.h"
     32 #include "cutils/properties.h"
     33 #include "edify/expr.h"
     34 #include "mincrypt/sha.h"
     35 #include "minzip/DirUtil.h"
     36 #include "mtdutils/mounts.h"
     37 #include "mtdutils/mtdutils.h"
     38 #include "updater.h"
     39 #include "applypatch/applypatch.h"
     40 
     41 #ifdef USE_EXT4
     42 #include "make_ext4fs.h"
     43 #endif
     44 
     45 // mount(fs_type, partition_type, location, mount_point)
     46 //
     47 //    fs_type="yaffs2" partition_type="MTD"     location=partition
     48 //    fs_type="ext4"   partition_type="EMMC"    location=device
     49 Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
     50     char* result = NULL;
     51     if (argc != 4) {
     52         return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc);
     53     }
     54     char* fs_type;
     55     char* partition_type;
     56     char* location;
     57     char* mount_point;
     58     if (ReadArgs(state, argv, 4, &fs_type, &partition_type,
     59                  &location, &mount_point) < 0) {
     60         return NULL;
     61     }
     62 
     63     if (strlen(fs_type) == 0) {
     64         ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
     65         goto done;
     66     }
     67     if (strlen(partition_type) == 0) {
     68         ErrorAbort(state, "partition_type argument to %s() can't be empty",
     69                    name);
     70         goto done;
     71     }
     72     if (strlen(location) == 0) {
     73         ErrorAbort(state, "location argument to %s() can't be empty", name);
     74         goto done;
     75     }
     76     if (strlen(mount_point) == 0) {
     77         ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
     78         goto done;
     79     }
     80 
     81     char *secontext = NULL;
     82 
     83     if (sehandle) {
     84         selabel_lookup(sehandle, &secontext, mount_point, 0755);
     85         setfscreatecon(secontext);
     86     }
     87 
     88     mkdir(mount_point, 0755);
     89 
     90     if (secontext) {
     91         freecon(secontext);
     92         setfscreatecon(NULL);
     93     }
     94 
     95     if (strcmp(partition_type, "MTD") == 0) {
     96         mtd_scan_partitions();
     97         const MtdPartition* mtd;
     98         mtd = mtd_find_partition_by_name(location);
     99         if (mtd == NULL) {
    100             fprintf(stderr, "%s: no mtd partition named \"%s\"",
    101                     name, location);
    102             result = strdup("");
    103             goto done;
    104         }
    105         if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
    106             fprintf(stderr, "mtd mount of %s failed: %s\n",
    107                     location, strerror(errno));
    108             result = strdup("");
    109             goto done;
    110         }
    111         result = mount_point;
    112     } else {
    113         if (mount(location, mount_point, fs_type,
    114                   MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
    115             fprintf(stderr, "%s: failed to mount %s at %s: %s\n",
    116                     name, location, mount_point, strerror(errno));
    117             result = strdup("");
    118         } else {
    119             result = mount_point;
    120         }
    121     }
    122 
    123 done:
    124     free(fs_type);
    125     free(partition_type);
    126     free(location);
    127     if (result != mount_point) free(mount_point);
    128     return StringValue(result);
    129 }
    130 
    131 
    132 // is_mounted(mount_point)
    133 Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
    134     char* result = NULL;
    135     if (argc != 1) {
    136         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    137     }
    138     char* mount_point;
    139     if (ReadArgs(state, argv, 1, &mount_point) < 0) {
    140         return NULL;
    141     }
    142     if (strlen(mount_point) == 0) {
    143         ErrorAbort(state, "mount_point argument to unmount() can't be empty");
    144         goto done;
    145     }
    146 
    147     scan_mounted_volumes();
    148     const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
    149     if (vol == NULL) {
    150         result = strdup("");
    151     } else {
    152         result = mount_point;
    153     }
    154 
    155 done:
    156     if (result != mount_point) free(mount_point);
    157     return StringValue(result);
    158 }
    159 
    160 
    161 Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
    162     char* result = NULL;
    163     if (argc != 1) {
    164         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    165     }
    166     char* mount_point;
    167     if (ReadArgs(state, argv, 1, &mount_point) < 0) {
    168         return NULL;
    169     }
    170     if (strlen(mount_point) == 0) {
    171         ErrorAbort(state, "mount_point argument to unmount() can't be empty");
    172         goto done;
    173     }
    174 
    175     scan_mounted_volumes();
    176     const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
    177     if (vol == NULL) {
    178         fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
    179         result = strdup("");
    180     } else {
    181         unmount_mounted_volume(vol);
    182         result = mount_point;
    183     }
    184 
    185 done:
    186     if (result != mount_point) free(mount_point);
    187     return StringValue(result);
    188 }
    189 
    190 
    191 // format(fs_type, partition_type, location, fs_size, mount_point)
    192 //
    193 //    fs_type="yaffs2" partition_type="MTD"     location=partition fs_size=<bytes> mount_point=<location>
    194 //    fs_type="ext4"   partition_type="EMMC"    location=device    fs_size=<bytes> mount_point=<location>
    195 //    if fs_size == 0, then make_ext4fs uses the entire partition.
    196 //    if fs_size > 0, that is the size to use
    197 //    if fs_size < 0, then reserve that many bytes at the end of the partition
    198 Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
    199     char* result = NULL;
    200     if (argc != 5) {
    201         return ErrorAbort(state, "%s() expects 5 args, got %d", name, argc);
    202     }
    203     char* fs_type;
    204     char* partition_type;
    205     char* location;
    206     char* fs_size;
    207     char* mount_point;
    208 
    209     if (ReadArgs(state, argv, 5, &fs_type, &partition_type, &location, &fs_size, &mount_point) < 0) {
    210         return NULL;
    211     }
    212 
    213     if (strlen(fs_type) == 0) {
    214         ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
    215         goto done;
    216     }
    217     if (strlen(partition_type) == 0) {
    218         ErrorAbort(state, "partition_type argument to %s() can't be empty",
    219                    name);
    220         goto done;
    221     }
    222     if (strlen(location) == 0) {
    223         ErrorAbort(state, "location argument to %s() can't be empty", name);
    224         goto done;
    225     }
    226 
    227     if (strlen(mount_point) == 0) {
    228         ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
    229         goto done;
    230     }
    231 
    232     if (strcmp(partition_type, "MTD") == 0) {
    233         mtd_scan_partitions();
    234         const MtdPartition* mtd = mtd_find_partition_by_name(location);
    235         if (mtd == NULL) {
    236             fprintf(stderr, "%s: no mtd partition named \"%s\"",
    237                     name, location);
    238             result = strdup("");
    239             goto done;
    240         }
    241         MtdWriteContext* ctx = mtd_write_partition(mtd);
    242         if (ctx == NULL) {
    243             fprintf(stderr, "%s: can't write \"%s\"", name, location);
    244             result = strdup("");
    245             goto done;
    246         }
    247         if (mtd_erase_blocks(ctx, -1) == -1) {
    248             mtd_write_close(ctx);
    249             fprintf(stderr, "%s: failed to erase \"%s\"", name, location);
    250             result = strdup("");
    251             goto done;
    252         }
    253         if (mtd_write_close(ctx) != 0) {
    254             fprintf(stderr, "%s: failed to close \"%s\"", name, location);
    255             result = strdup("");
    256             goto done;
    257         }
    258         result = location;
    259 #ifdef USE_EXT4
    260     } else if (strcmp(fs_type, "ext4") == 0) {
    261         int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle);
    262         if (status != 0) {
    263             fprintf(stderr, "%s: make_ext4fs failed (%d) on %s",
    264                     name, status, location);
    265             result = strdup("");
    266             goto done;
    267         }
    268         result = location;
    269 #endif
    270     } else {
    271         fprintf(stderr, "%s: unsupported fs_type \"%s\" partition_type \"%s\"",
    272                 name, fs_type, partition_type);
    273     }
    274 
    275 done:
    276     free(fs_type);
    277     free(partition_type);
    278     if (result != location) free(location);
    279     return StringValue(result);
    280 }
    281 
    282 
    283 Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
    284     char** paths = malloc(argc * sizeof(char*));
    285     int i;
    286     for (i = 0; i < argc; ++i) {
    287         paths[i] = Evaluate(state, argv[i]);
    288         if (paths[i] == NULL) {
    289             int j;
    290             for (j = 0; j < i; ++i) {
    291                 free(paths[j]);
    292             }
    293             free(paths);
    294             return NULL;
    295         }
    296     }
    297 
    298     bool recursive = (strcmp(name, "delete_recursive") == 0);
    299 
    300     int success = 0;
    301     for (i = 0; i < argc; ++i) {
    302         if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
    303             ++success;
    304         free(paths[i]);
    305     }
    306     free(paths);
    307 
    308     char buffer[10];
    309     sprintf(buffer, "%d", success);
    310     return StringValue(strdup(buffer));
    311 }
    312 
    313 
    314 Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
    315     if (argc != 2) {
    316         return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
    317     }
    318     char* frac_str;
    319     char* sec_str;
    320     if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
    321         return NULL;
    322     }
    323 
    324     double frac = strtod(frac_str, NULL);
    325     int sec = strtol(sec_str, NULL, 10);
    326 
    327     UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
    328     fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
    329 
    330     free(sec_str);
    331     return StringValue(frac_str);
    332 }
    333 
    334 Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
    335     if (argc != 1) {
    336         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    337     }
    338     char* frac_str;
    339     if (ReadArgs(state, argv, 1, &frac_str) < 0) {
    340         return NULL;
    341     }
    342 
    343     double frac = strtod(frac_str, NULL);
    344 
    345     UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
    346     fprintf(ui->cmd_pipe, "set_progress %f\n", frac);
    347 
    348     return StringValue(frac_str);
    349 }
    350 
    351 // package_extract_dir(package_path, destination_path)
    352 Value* PackageExtractDirFn(const char* name, State* state,
    353                           int argc, Expr* argv[]) {
    354     if (argc != 2) {
    355         return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
    356     }
    357     char* zip_path;
    358     char* dest_path;
    359     if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
    360 
    361     ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
    362 
    363     // To create a consistent system image, never use the clock for timestamps.
    364     struct utimbuf timestamp = { 1217592000, 1217592000 };  // 8/1/2008 default
    365 
    366     bool success = mzExtractRecursive(za, zip_path, dest_path,
    367                                       MZ_EXTRACT_FILES_ONLY, &timestamp,
    368                                       NULL, NULL, sehandle);
    369     free(zip_path);
    370     free(dest_path);
    371     return StringValue(strdup(success ? "t" : ""));
    372 }
    373 
    374 
    375 // package_extract_file(package_path, destination_path)
    376 //   or
    377 // package_extract_file(package_path)
    378 //   to return the entire contents of the file as the result of this
    379 //   function (the char* returned is actually a FileContents*).
    380 Value* PackageExtractFileFn(const char* name, State* state,
    381                            int argc, Expr* argv[]) {
    382     if (argc != 1 && argc != 2) {
    383         return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
    384                           name, argc);
    385     }
    386     bool success = false;
    387     if (argc == 2) {
    388         // The two-argument version extracts to a file.
    389 
    390         char* zip_path;
    391         char* dest_path;
    392         if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
    393 
    394         ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
    395         const ZipEntry* entry = mzFindZipEntry(za, zip_path);
    396         if (entry == NULL) {
    397             fprintf(stderr, "%s: no %s in package\n", name, zip_path);
    398             goto done2;
    399         }
    400 
    401         FILE* f = fopen(dest_path, "wb");
    402         if (f == NULL) {
    403             fprintf(stderr, "%s: can't open %s for write: %s\n",
    404                     name, dest_path, strerror(errno));
    405             goto done2;
    406         }
    407         success = mzExtractZipEntryToFile(za, entry, fileno(f));
    408         fclose(f);
    409 
    410       done2:
    411         free(zip_path);
    412         free(dest_path);
    413         return StringValue(strdup(success ? "t" : ""));
    414     } else {
    415         // The one-argument version returns the contents of the file
    416         // as the result.
    417 
    418         char* zip_path;
    419         Value* v = malloc(sizeof(Value));
    420         v->type = VAL_BLOB;
    421         v->size = -1;
    422         v->data = NULL;
    423 
    424         if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
    425 
    426         ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
    427         const ZipEntry* entry = mzFindZipEntry(za, zip_path);
    428         if (entry == NULL) {
    429             fprintf(stderr, "%s: no %s in package\n", name, zip_path);
    430             goto done1;
    431         }
    432 
    433         v->size = mzGetZipEntryUncompLen(entry);
    434         v->data = malloc(v->size);
    435         if (v->data == NULL) {
    436             fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n",
    437                     name, (long)v->size, zip_path);
    438             goto done1;
    439         }
    440 
    441         success = mzExtractZipEntryToBuffer(za, entry,
    442                                             (unsigned char *)v->data);
    443 
    444       done1:
    445         free(zip_path);
    446         if (!success) {
    447             free(v->data);
    448             v->data = NULL;
    449             v->size = -1;
    450         }
    451         return v;
    452     }
    453 }
    454 
    455 // Create all parent directories of name, if necessary.
    456 static int make_parents(char* name) {
    457     char* p;
    458     for (p = name + (strlen(name)-1); p > name; --p) {
    459         if (*p != '/') continue;
    460         *p = '\0';
    461         if (make_parents(name) < 0) return -1;
    462         int result = mkdir(name, 0700);
    463         if (result == 0) fprintf(stderr, "symlink(): created [%s]\n", name);
    464         *p = '/';
    465         if (result == 0 || errno == EEXIST) {
    466             // successfully created or already existed; we're done
    467             return 0;
    468         } else {
    469             fprintf(stderr, "failed to mkdir %s: %s\n", name, strerror(errno));
    470             return -1;
    471         }
    472     }
    473     return 0;
    474 }
    475 
    476 // symlink target src1 src2 ...
    477 //    unlinks any previously existing src1, src2, etc before creating symlinks.
    478 Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
    479     if (argc == 0) {
    480         return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
    481     }
    482     char* target;
    483     target = Evaluate(state, argv[0]);
    484     if (target == NULL) return NULL;
    485 
    486     char** srcs = ReadVarArgs(state, argc-1, argv+1);
    487     if (srcs == NULL) {
    488         free(target);
    489         return NULL;
    490     }
    491 
    492     int bad = 0;
    493     int i;
    494     for (i = 0; i < argc-1; ++i) {
    495         if (unlink(srcs[i]) < 0) {
    496             if (errno != ENOENT) {
    497                 fprintf(stderr, "%s: failed to remove %s: %s\n",
    498                         name, srcs[i], strerror(errno));
    499                 ++bad;
    500             }
    501         }
    502         if (make_parents(srcs[i])) {
    503             fprintf(stderr, "%s: failed to symlink %s to %s: making parents failed\n",
    504                     name, srcs[i], target);
    505             ++bad;
    506         }
    507         if (symlink(target, srcs[i]) < 0) {
    508             fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
    509                     name, srcs[i], target, strerror(errno));
    510             ++bad;
    511         }
    512         free(srcs[i]);
    513     }
    514     free(srcs);
    515     if (bad) {
    516         return ErrorAbort(state, "%s: some symlinks failed", name);
    517     }
    518     return StringValue(strdup(""));
    519 }
    520 
    521 
    522 Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
    523     char* result = NULL;
    524     bool recursive = (strcmp(name, "set_perm_recursive") == 0);
    525 
    526     int min_args = 4 + (recursive ? 1 : 0);
    527     if (argc < min_args) {
    528         return ErrorAbort(state, "%s() expects %d+ args, got %d",
    529                           name, min_args, argc);
    530     }
    531 
    532     char** args = ReadVarArgs(state, argc, argv);
    533     if (args == NULL) return NULL;
    534 
    535     char* end;
    536     int i;
    537     int bad = 0;
    538 
    539     int uid = strtoul(args[0], &end, 0);
    540     if (*end != '\0' || args[0][0] == 0) {
    541         ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
    542         goto done;
    543     }
    544 
    545     int gid = strtoul(args[1], &end, 0);
    546     if (*end != '\0' || args[1][0] == 0) {
    547         ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
    548         goto done;
    549     }
    550 
    551     if (recursive) {
    552         int dir_mode = strtoul(args[2], &end, 0);
    553         if (*end != '\0' || args[2][0] == 0) {
    554             ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
    555             goto done;
    556         }
    557 
    558         int file_mode = strtoul(args[3], &end, 0);
    559         if (*end != '\0' || args[3][0] == 0) {
    560             ErrorAbort(state, "%s: \"%s\" not a valid filemode",
    561                        name, args[3]);
    562             goto done;
    563         }
    564 
    565         for (i = 4; i < argc; ++i) {
    566             dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
    567         }
    568     } else {
    569         int mode = strtoul(args[2], &end, 0);
    570         if (*end != '\0' || args[2][0] == 0) {
    571             ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
    572             goto done;
    573         }
    574 
    575         for (i = 3; i < argc; ++i) {
    576             if (chown(args[i], uid, gid) < 0) {
    577                 fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n",
    578                         name, args[i], uid, gid, strerror(errno));
    579                 ++bad;
    580             }
    581             if (chmod(args[i], mode) < 0) {
    582                 fprintf(stderr, "%s: chmod of %s to %o failed: %s\n",
    583                         name, args[i], mode, strerror(errno));
    584                 ++bad;
    585             }
    586         }
    587     }
    588     result = strdup("");
    589 
    590 done:
    591     for (i = 0; i < argc; ++i) {
    592         free(args[i]);
    593     }
    594     free(args);
    595 
    596     if (bad) {
    597         free(result);
    598         return ErrorAbort(state, "%s: some changes failed", name);
    599     }
    600     return StringValue(result);
    601 }
    602 
    603 
    604 Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
    605     if (argc != 1) {
    606         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    607     }
    608     char* key;
    609     key = Evaluate(state, argv[0]);
    610     if (key == NULL) return NULL;
    611 
    612     char value[PROPERTY_VALUE_MAX];
    613     property_get(key, value, "");
    614     free(key);
    615 
    616     return StringValue(strdup(value));
    617 }
    618 
    619 
    620 // file_getprop(file, key)
    621 //
    622 //   interprets 'file' as a getprop-style file (key=value pairs, one
    623 //   per line, # comment lines and blank lines okay), and returns the value
    624 //   for 'key' (or "" if it isn't defined).
    625 Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
    626     char* result = NULL;
    627     char* buffer = NULL;
    628     char* filename;
    629     char* key;
    630     if (ReadArgs(state, argv, 2, &filename, &key) < 0) {
    631         return NULL;
    632     }
    633 
    634     struct stat st;
    635     if (stat(filename, &st) < 0) {
    636         ErrorAbort(state, "%s: failed to stat \"%s\": %s",
    637                    name, filename, strerror(errno));
    638         goto done;
    639     }
    640 
    641 #define MAX_FILE_GETPROP_SIZE    65536
    642 
    643     if (st.st_size > MAX_FILE_GETPROP_SIZE) {
    644         ErrorAbort(state, "%s too large for %s (max %d)",
    645                    filename, name, MAX_FILE_GETPROP_SIZE);
    646         goto done;
    647     }
    648 
    649     buffer = malloc(st.st_size+1);
    650     if (buffer == NULL) {
    651         ErrorAbort(state, "%s: failed to alloc %lld bytes", name, st.st_size+1);
    652         goto done;
    653     }
    654 
    655     FILE* f = fopen(filename, "rb");
    656     if (f == NULL) {
    657         ErrorAbort(state, "%s: failed to open %s: %s",
    658                    name, filename, strerror(errno));
    659         goto done;
    660     }
    661 
    662     if (fread(buffer, 1, st.st_size, f) != st.st_size) {
    663         ErrorAbort(state, "%s: failed to read %lld bytes from %s",
    664                    name, st.st_size+1, filename);
    665         fclose(f);
    666         goto done;
    667     }
    668     buffer[st.st_size] = '\0';
    669 
    670     fclose(f);
    671 
    672     char* line = strtok(buffer, "\n");
    673     do {
    674         // skip whitespace at start of line
    675         while (*line && isspace(*line)) ++line;
    676 
    677         // comment or blank line: skip to next line
    678         if (*line == '\0' || *line == '#') continue;
    679 
    680         char* equal = strchr(line, '=');
    681         if (equal == NULL) {
    682             ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
    683                        name, line, filename);
    684             goto done;
    685         }
    686 
    687         // trim whitespace between key and '='
    688         char* key_end = equal-1;
    689         while (key_end > line && isspace(*key_end)) --key_end;
    690         key_end[1] = '\0';
    691 
    692         // not the key we're looking for
    693         if (strcmp(key, line) != 0) continue;
    694 
    695         // skip whitespace after the '=' to the start of the value
    696         char* val_start = equal+1;
    697         while(*val_start && isspace(*val_start)) ++val_start;
    698 
    699         // trim trailing whitespace
    700         char* val_end = val_start + strlen(val_start)-1;
    701         while (val_end > val_start && isspace(*val_end)) --val_end;
    702         val_end[1] = '\0';
    703 
    704         result = strdup(val_start);
    705         break;
    706 
    707     } while ((line = strtok(NULL, "\n")));
    708 
    709     if (result == NULL) result = strdup("");
    710 
    711   done:
    712     free(filename);
    713     free(key);
    714     free(buffer);
    715     return StringValue(result);
    716 }
    717 
    718 
    719 static bool write_raw_image_cb(const unsigned char* data,
    720                                int data_len, void* ctx) {
    721     int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
    722     if (r == data_len) return true;
    723     fprintf(stderr, "%s\n", strerror(errno));
    724     return false;
    725 }
    726 
    727 // write_raw_image(filename_or_blob, partition)
    728 Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
    729     char* result = NULL;
    730 
    731     Value* partition_value;
    732     Value* contents;
    733     if (ReadValueArgs(state, argv, 2, &contents, &partition_value) < 0) {
    734         return NULL;
    735     }
    736 
    737     char* partition = NULL;
    738     if (partition_value->type != VAL_STRING) {
    739         ErrorAbort(state, "partition argument to %s must be string", name);
    740         goto done;
    741     }
    742     partition = partition_value->data;
    743     if (strlen(partition) == 0) {
    744         ErrorAbort(state, "partition argument to %s can't be empty", name);
    745         goto done;
    746     }
    747     if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) {
    748         ErrorAbort(state, "file argument to %s can't be empty", name);
    749         goto done;
    750     }
    751 
    752     mtd_scan_partitions();
    753     const MtdPartition* mtd = mtd_find_partition_by_name(partition);
    754     if (mtd == NULL) {
    755         fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition);
    756         result = strdup("");
    757         goto done;
    758     }
    759 
    760     MtdWriteContext* ctx = mtd_write_partition(mtd);
    761     if (ctx == NULL) {
    762         fprintf(stderr, "%s: can't write mtd partition \"%s\"\n",
    763                 name, partition);
    764         result = strdup("");
    765         goto done;
    766     }
    767 
    768     bool success;
    769 
    770     if (contents->type == VAL_STRING) {
    771         // we're given a filename as the contents
    772         char* filename = contents->data;
    773         FILE* f = fopen(filename, "rb");
    774         if (f == NULL) {
    775             fprintf(stderr, "%s: can't open %s: %s\n",
    776                     name, filename, strerror(errno));
    777             result = strdup("");
    778             goto done;
    779         }
    780 
    781         success = true;
    782         char* buffer = malloc(BUFSIZ);
    783         int read;
    784         while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
    785             int wrote = mtd_write_data(ctx, buffer, read);
    786             success = success && (wrote == read);
    787         }
    788         free(buffer);
    789         fclose(f);
    790     } else {
    791         // we're given a blob as the contents
    792         ssize_t wrote = mtd_write_data(ctx, contents->data, contents->size);
    793         success = (wrote == contents->size);
    794     }
    795     if (!success) {
    796         fprintf(stderr, "mtd_write_data to %s failed: %s\n",
    797                 partition, strerror(errno));
    798     }
    799 
    800     if (mtd_erase_blocks(ctx, -1) == -1) {
    801         fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition);
    802     }
    803     if (mtd_write_close(ctx) != 0) {
    804         fprintf(stderr, "%s: error closing write of %s\n", name, partition);
    805     }
    806 
    807     printf("%s %s partition\n",
    808            success ? "wrote" : "failed to write", partition);
    809 
    810     result = success ? partition : strdup("");
    811 
    812 done:
    813     if (result != partition) FreeValue(partition_value);
    814     FreeValue(contents);
    815     return StringValue(result);
    816 }
    817 
    818 // apply_patch_space(bytes)
    819 Value* ApplyPatchSpaceFn(const char* name, State* state,
    820                          int argc, Expr* argv[]) {
    821     char* bytes_str;
    822     if (ReadArgs(state, argv, 1, &bytes_str) < 0) {
    823         return NULL;
    824     }
    825 
    826     char* endptr;
    827     size_t bytes = strtol(bytes_str, &endptr, 10);
    828     if (bytes == 0 && endptr == bytes_str) {
    829         ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
    830                    name, bytes_str);
    831         free(bytes_str);
    832         return NULL;
    833     }
    834 
    835     return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
    836 }
    837 
    838 
    839 // apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
    840 Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
    841     if (argc < 6 || (argc % 2) == 1) {
    842         return ErrorAbort(state, "%s(): expected at least 6 args and an "
    843                                  "even number, got %d",
    844                           name, argc);
    845     }
    846 
    847     char* source_filename;
    848     char* target_filename;
    849     char* target_sha1;
    850     char* target_size_str;
    851     if (ReadArgs(state, argv, 4, &source_filename, &target_filename,
    852                  &target_sha1, &target_size_str) < 0) {
    853         return NULL;
    854     }
    855 
    856     char* endptr;
    857     size_t target_size = strtol(target_size_str, &endptr, 10);
    858     if (target_size == 0 && endptr == target_size_str) {
    859         ErrorAbort(state, "%s(): can't parse \"%s\" as byte count",
    860                    name, target_size_str);
    861         free(source_filename);
    862         free(target_filename);
    863         free(target_sha1);
    864         free(target_size_str);
    865         return NULL;
    866     }
    867 
    868     int patchcount = (argc-4) / 2;
    869     Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
    870 
    871     int i;
    872     for (i = 0; i < patchcount; ++i) {
    873         if (patches[i*2]->type != VAL_STRING) {
    874             ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
    875             break;
    876         }
    877         if (patches[i*2+1]->type != VAL_BLOB) {
    878             ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
    879             break;
    880         }
    881     }
    882     if (i != patchcount) {
    883         for (i = 0; i < patchcount*2; ++i) {
    884             FreeValue(patches[i]);
    885         }
    886         free(patches);
    887         return NULL;
    888     }
    889 
    890     char** patch_sha_str = malloc(patchcount * sizeof(char*));
    891     for (i = 0; i < patchcount; ++i) {
    892         patch_sha_str[i] = patches[i*2]->data;
    893         patches[i*2]->data = NULL;
    894         FreeValue(patches[i*2]);
    895         patches[i] = patches[i*2+1];
    896     }
    897 
    898     int result = applypatch(source_filename, target_filename,
    899                             target_sha1, target_size,
    900                             patchcount, patch_sha_str, patches, NULL);
    901 
    902     for (i = 0; i < patchcount; ++i) {
    903         FreeValue(patches[i]);
    904     }
    905     free(patch_sha_str);
    906     free(patches);
    907 
    908     return StringValue(strdup(result == 0 ? "t" : ""));
    909 }
    910 
    911 // apply_patch_check(file, [sha1_1, ...])
    912 Value* ApplyPatchCheckFn(const char* name, State* state,
    913                          int argc, Expr* argv[]) {
    914     if (argc < 1) {
    915         return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
    916                           name, argc);
    917     }
    918 
    919     char* filename;
    920     if (ReadArgs(state, argv, 1, &filename) < 0) {
    921         return NULL;
    922     }
    923 
    924     int patchcount = argc-1;
    925     char** sha1s = ReadVarArgs(state, argc-1, argv+1);
    926 
    927     int result = applypatch_check(filename, patchcount, sha1s);
    928 
    929     int i;
    930     for (i = 0; i < patchcount; ++i) {
    931         free(sha1s[i]);
    932     }
    933     free(sha1s);
    934 
    935     return StringValue(strdup(result == 0 ? "t" : ""));
    936 }
    937 
    938 Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
    939     char** args = ReadVarArgs(state, argc, argv);
    940     if (args == NULL) {
    941         return NULL;
    942     }
    943 
    944     int size = 0;
    945     int i;
    946     for (i = 0; i < argc; ++i) {
    947         size += strlen(args[i]);
    948     }
    949     char* buffer = malloc(size+1);
    950     size = 0;
    951     for (i = 0; i < argc; ++i) {
    952         strcpy(buffer+size, args[i]);
    953         size += strlen(args[i]);
    954         free(args[i]);
    955     }
    956     free(args);
    957     buffer[size] = '\0';
    958 
    959     char* line = strtok(buffer, "\n");
    960     while (line) {
    961         fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
    962                 "ui_print %s\n", line);
    963         line = strtok(NULL, "\n");
    964     }
    965     fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
    966 
    967     return StringValue(buffer);
    968 }
    969 
    970 Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) {
    971     if (argc != 0) {
    972         return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
    973     }
    974     fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "wipe_cache\n");
    975     return StringValue(strdup("t"));
    976 }
    977 
    978 Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
    979     if (argc < 1) {
    980         return ErrorAbort(state, "%s() expects at least 1 arg", name);
    981     }
    982     char** args = ReadVarArgs(state, argc, argv);
    983     if (args == NULL) {
    984         return NULL;
    985     }
    986 
    987     char** args2 = malloc(sizeof(char*) * (argc+1));
    988     memcpy(args2, args, sizeof(char*) * argc);
    989     args2[argc] = NULL;
    990 
    991     fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc);
    992 
    993     pid_t child = fork();
    994     if (child == 0) {
    995         execv(args2[0], args2);
    996         fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno));
    997         _exit(1);
    998     }
    999     int status;
   1000     waitpid(child, &status, 0);
   1001     if (WIFEXITED(status)) {
   1002         if (WEXITSTATUS(status) != 0) {
   1003             fprintf(stderr, "run_program: child exited with status %d\n",
   1004                     WEXITSTATUS(status));
   1005         }
   1006     } else if (WIFSIGNALED(status)) {
   1007         fprintf(stderr, "run_program: child terminated by signal %d\n",
   1008                 WTERMSIG(status));
   1009     }
   1010 
   1011     int i;
   1012     for (i = 0; i < argc; ++i) {
   1013         free(args[i]);
   1014     }
   1015     free(args);
   1016     free(args2);
   1017 
   1018     char buffer[20];
   1019     sprintf(buffer, "%d", status);
   1020 
   1021     return StringValue(strdup(buffer));
   1022 }
   1023 
   1024 // Take a sha-1 digest and return it as a newly-allocated hex string.
   1025 static char* PrintSha1(uint8_t* digest) {
   1026     char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
   1027     int i;
   1028     const char* alphabet = "0123456789abcdef";
   1029     for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
   1030         buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
   1031         buffer[i*2+1] = alphabet[digest[i] & 0xf];
   1032     }
   1033     buffer[i*2] = '\0';
   1034     return buffer;
   1035 }
   1036 
   1037 // sha1_check(data)
   1038 //    to return the sha1 of the data (given in the format returned by
   1039 //    read_file).
   1040 //
   1041 // sha1_check(data, sha1_hex, [sha1_hex, ...])
   1042 //    returns the sha1 of the file if it matches any of the hex
   1043 //    strings passed, or "" if it does not equal any of them.
   1044 //
   1045 Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
   1046     if (argc < 1) {
   1047         return ErrorAbort(state, "%s() expects at least 1 arg", name);
   1048     }
   1049 
   1050     Value** args = ReadValueVarArgs(state, argc, argv);
   1051     if (args == NULL) {
   1052         return NULL;
   1053     }
   1054 
   1055     if (args[0]->size < 0) {
   1056         fprintf(stderr, "%s(): no file contents received", name);
   1057         return StringValue(strdup(""));
   1058     }
   1059     uint8_t digest[SHA_DIGEST_SIZE];
   1060     SHA(args[0]->data, args[0]->size, digest);
   1061     FreeValue(args[0]);
   1062 
   1063     if (argc == 1) {
   1064         return StringValue(PrintSha1(digest));
   1065     }
   1066 
   1067     int i;
   1068     uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE);
   1069     for (i = 1; i < argc; ++i) {
   1070         if (args[i]->type != VAL_STRING) {
   1071             fprintf(stderr, "%s(): arg %d is not a string; skipping",
   1072                     name, i);
   1073         } else if (ParseSha1(args[i]->data, arg_digest) != 0) {
   1074             // Warn about bad args and skip them.
   1075             fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping",
   1076                     name, args[i]->data);
   1077         } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
   1078             break;
   1079         }
   1080         FreeValue(args[i]);
   1081     }
   1082     if (i >= argc) {
   1083         // Didn't match any of the hex strings; return false.
   1084         return StringValue(strdup(""));
   1085     }
   1086     // Found a match; free all the remaining arguments and return the
   1087     // matched one.
   1088     int j;
   1089     for (j = i+1; j < argc; ++j) {
   1090         FreeValue(args[j]);
   1091     }
   1092     return args[i];
   1093 }
   1094 
   1095 // Read a local file and return its contents (the Value* returned
   1096 // is actually a FileContents*).
   1097 Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
   1098     if (argc != 1) {
   1099         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
   1100     }
   1101     char* filename;
   1102     if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
   1103 
   1104     Value* v = malloc(sizeof(Value));
   1105     v->type = VAL_BLOB;
   1106 
   1107     FileContents fc;
   1108     if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) {
   1109         ErrorAbort(state, "%s() loading \"%s\" failed: %s",
   1110                    name, filename, strerror(errno));
   1111         free(filename);
   1112         free(v);
   1113         free(fc.data);
   1114         return NULL;
   1115     }
   1116 
   1117     v->size = fc.size;
   1118     v->data = (char*)fc.data;
   1119 
   1120     free(filename);
   1121     return v;
   1122 }
   1123 
   1124 void RegisterInstallFunctions() {
   1125     RegisterFunction("mount", MountFn);
   1126     RegisterFunction("is_mounted", IsMountedFn);
   1127     RegisterFunction("unmount", UnmountFn);
   1128     RegisterFunction("format", FormatFn);
   1129     RegisterFunction("show_progress", ShowProgressFn);
   1130     RegisterFunction("set_progress", SetProgressFn);
   1131     RegisterFunction("delete", DeleteFn);
   1132     RegisterFunction("delete_recursive", DeleteFn);
   1133     RegisterFunction("package_extract_dir", PackageExtractDirFn);
   1134     RegisterFunction("package_extract_file", PackageExtractFileFn);
   1135     RegisterFunction("symlink", SymlinkFn);
   1136     RegisterFunction("set_perm", SetPermFn);
   1137     RegisterFunction("set_perm_recursive", SetPermFn);
   1138 
   1139     RegisterFunction("getprop", GetPropFn);
   1140     RegisterFunction("file_getprop", FileGetPropFn);
   1141     RegisterFunction("write_raw_image", WriteRawImageFn);
   1142 
   1143     RegisterFunction("apply_patch", ApplyPatchFn);
   1144     RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
   1145     RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
   1146 
   1147     RegisterFunction("read_file", ReadFileFn);
   1148     RegisterFunction("sha1_check", Sha1CheckFn);
   1149 
   1150     RegisterFunction("wipe_cache", WipeCacheFn);
   1151 
   1152     RegisterFunction("ui_print", UIPrintFn);
   1153 
   1154     RegisterFunction("run_program", RunProgramFn);
   1155 }
   1156