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