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 <stdio.h>
     18 #include <unistd.h>
     19 #include <stdlib.h>
     20 #include <string.h>
     21 
     22 #include "edify/expr.h"
     23 #include "updater.h"
     24 #include "install.h"
     25 #include "blockimg.h"
     26 #include "minzip/Zip.h"
     27 #include "minzip/SysUtil.h"
     28 #include "config.h"
     29 
     30 // Generated by the makefile, this function defines the
     31 // RegisterDeviceExtensions() function, which calls all the
     32 // registration functions for device-specific extensions.
     33 #include "register.inc"
     34 
     35 // Where in the package we expect to find the edify script to execute.
     36 // (Note it's "updateR-script", not the older "update-script".)
     37 #define SCRIPT_NAME "META-INF/com/google/android/updater-script"
     38 
     39 extern bool have_eio_error;
     40 
     41 struct selabel_handle *sehandle;
     42 
     43 int main(int argc, char** argv) {
     44     // Various things log information to stdout or stderr more or less
     45     // at random (though we've tried to standardize on stdout).  The
     46     // log file makes more sense if buffering is turned off so things
     47     // appear in the right order.
     48     setbuf(stdout, NULL);
     49     setbuf(stderr, NULL);
     50 
     51     if (argc != 4 && argc != 5) {
     52         printf("unexpected number of arguments (%d)\n", argc);
     53         return 1;
     54     }
     55 
     56     char* version = argv[1];
     57     if ((version[0] != '1' && version[0] != '2' && version[0] != '3') ||
     58         version[1] != '\0') {
     59         // We support version 1, 2, or 3.
     60         printf("wrong updater binary API; expected 1, 2, or 3; "
     61                         "got %s\n",
     62                 argv[1]);
     63         return 2;
     64     }
     65 
     66     // Set up the pipe for sending commands back to the parent process.
     67 
     68     int fd = atoi(argv[2]);
     69     FILE* cmd_pipe = fdopen(fd, "wb");
     70     setlinebuf(cmd_pipe);
     71 
     72     // Extract the script from the package.
     73 
     74     const char* package_filename = argv[3];
     75     MemMapping map;
     76     if (sysMapFile(package_filename, &map) != 0) {
     77         printf("failed to map package %s\n", argv[3]);
     78         return 3;
     79     }
     80     ZipArchive za;
     81     int err;
     82     err = mzOpenZipArchive(map.addr, map.length, &za);
     83     if (err != 0) {
     84         printf("failed to open package %s: %s\n",
     85                argv[3], strerror(err));
     86         return 3;
     87     }
     88     ota_io_init(&za);
     89 
     90     const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME);
     91     if (script_entry == NULL) {
     92         printf("failed to find %s in %s\n", SCRIPT_NAME, package_filename);
     93         return 4;
     94     }
     95 
     96     char* script = reinterpret_cast<char*>(malloc(script_entry->uncompLen+1));
     97     if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) {
     98         printf("failed to read script from package\n");
     99         return 5;
    100     }
    101     script[script_entry->uncompLen] = '\0';
    102 
    103     // Configure edify's functions.
    104 
    105     RegisterBuiltins();
    106     RegisterInstallFunctions();
    107     RegisterBlockImageFunctions();
    108     RegisterDeviceExtensions();
    109     FinishRegistration();
    110 
    111     // Parse the script.
    112 
    113     Expr* root;
    114     int error_count = 0;
    115     int error = parse_string(script, &root, &error_count);
    116     if (error != 0 || error_count > 0) {
    117         printf("%d parse errors\n", error_count);
    118         return 6;
    119     }
    120 
    121     struct selinux_opt seopts[] = {
    122       { SELABEL_OPT_PATH, "/file_contexts" }
    123     };
    124 
    125     sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
    126 
    127     if (!sehandle) {
    128         fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n");
    129     }
    130 
    131     // Evaluate the parsed script.
    132 
    133     UpdaterInfo updater_info;
    134     updater_info.cmd_pipe = cmd_pipe;
    135     updater_info.package_zip = &za;
    136     updater_info.version = atoi(version);
    137     updater_info.package_zip_addr = map.addr;
    138     updater_info.package_zip_len = map.length;
    139 
    140     State state;
    141     state.cookie = &updater_info;
    142     state.script = script;
    143     state.errmsg = NULL;
    144 
    145     if (argc == 5) {
    146         if (strcmp(argv[4], "retry") == 0) {
    147             state.is_retry = true;
    148         } else {
    149             printf("unexpected argument: %s", argv[4]);
    150         }
    151     }
    152 
    153     char* result = Evaluate(&state, root);
    154 
    155     if (have_eio_error) {
    156         fprintf(cmd_pipe, "retry_update\n");
    157     }
    158 
    159     if (result == NULL) {
    160         if (state.errmsg == NULL) {
    161             printf("script aborted (no error message)\n");
    162             fprintf(cmd_pipe, "ui_print script aborted (no error message)\n");
    163         } else {
    164             printf("script aborted: %s\n", state.errmsg);
    165             char* line = strtok(state.errmsg, "\n");
    166             while (line) {
    167                 // Parse the error code in abort message.
    168                 // Example: "E30: This package is for bullhead devices."
    169                 if (*line == 'E') {
    170                     if (sscanf(line, "E%u: ", &state.error_code) != 1) {
    171                          printf("Failed to parse error code: [%s]\n", line);
    172                     }
    173                 }
    174                 fprintf(cmd_pipe, "ui_print %s\n", line);
    175                 line = strtok(NULL, "\n");
    176             }
    177             fprintf(cmd_pipe, "ui_print\n");
    178         }
    179 
    180         if (state.error_code != kNoError) {
    181             fprintf(cmd_pipe, "log error: %d\n", state.error_code);
    182             // Cause code should provide additional information about the abort;
    183             // report only when an error exists.
    184             if (state.cause_code != kNoCause) {
    185                 fprintf(cmd_pipe, "log cause: %d\n", state.cause_code);
    186             }
    187         }
    188 
    189         free(state.errmsg);
    190         return 7;
    191     } else {
    192         fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result);
    193         free(result);
    194     }
    195 
    196     if (updater_info.package_zip) {
    197         mzCloseZipArchive(updater_info.package_zip);
    198     }
    199     sysReleaseMap(&map);
    200     free(script);
    201 
    202     return 0;
    203 }
    204