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