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