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