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 21#include "edify/expr.h" 22#include "updater.h" 23#include "install.h" 24#include "minzip/Zip.h" 25 26// Generated by the makefile, this function defines the 27// RegisterDeviceExtensions() function, which calls all the 28// registration functions for device-specific extensions. 29#include "register.inc" 30 31// Where in the package we expect to find the edify script to execute. 32// (Note it's "updateR-script", not the older "update-script".) 33#define SCRIPT_NAME "META-INF/com/google/android/updater-script" 34 35struct selabel_handle *sehandle; 36 37int main(int argc, char** argv) { 38 // Various things log information to stdout or stderr more or less 39 // at random (though we've tried to standardize on stdout). The 40 // log file makes more sense if buffering is turned off so things 41 // appear in the right order. 42 setbuf(stdout, NULL); 43 setbuf(stderr, NULL); 44 45 if (argc != 4) { 46 printf("unexpected number of arguments (%d)\n", argc); 47 return 1; 48 } 49 50 char* version = argv[1]; 51 if ((version[0] != '1' && version[0] != '2' && version[0] != '3') || 52 version[1] != '\0') { 53 // We support version 1, 2, or 3. 54 printf("wrong updater binary API; expected 1, 2, or 3; " 55 "got %s\n", 56 argv[1]); 57 return 2; 58 } 59 60 // Set up the pipe for sending commands back to the parent process. 61 62 int fd = atoi(argv[2]); 63 FILE* cmd_pipe = fdopen(fd, "wb"); 64 setlinebuf(cmd_pipe); 65 66 // Extract the script from the package. 67 68 char* package_data = argv[3]; 69 ZipArchive za; 70 int err; 71 err = mzOpenZipArchive(package_data, &za); 72 if (err != 0) { 73 printf("failed to open package %s: %s\n", 74 package_data, strerror(err)); 75 return 3; 76 } 77 78 const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME); 79 if (script_entry == NULL) { 80 printf("failed to find %s in %s\n", SCRIPT_NAME, package_data); 81 return 4; 82 } 83 84 char* script = malloc(script_entry->uncompLen+1); 85 if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) { 86 printf("failed to read script from package\n"); 87 return 5; 88 } 89 script[script_entry->uncompLen] = '\0'; 90 91 // Configure edify's functions. 92 93 RegisterBuiltins(); 94 RegisterInstallFunctions(); 95 RegisterDeviceExtensions(); 96 FinishRegistration(); 97 98 // Parse the script. 99 100 Expr* root; 101 int error_count = 0; 102 yy_scan_string(script); 103 int error = yyparse(&root, &error_count); 104 if (error != 0 || error_count > 0) { 105 printf("%d parse errors\n", error_count); 106 return 6; 107 } 108 109 struct selinux_opt seopts[] = { 110 { SELABEL_OPT_PATH, "/file_contexts" } 111 }; 112 113 sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); 114 115 if (!sehandle) { 116 fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n"); 117 } 118 119 // Evaluate the parsed script. 120 121 UpdaterInfo updater_info; 122 updater_info.cmd_pipe = cmd_pipe; 123 updater_info.package_zip = &za; 124 updater_info.version = atoi(version); 125 126 State state; 127 state.cookie = &updater_info; 128 state.script = script; 129 state.errmsg = NULL; 130 131 char* result = Evaluate(&state, root); 132 if (result == NULL) { 133 if (state.errmsg == NULL) { 134 printf("script aborted (no error message)\n"); 135 fprintf(cmd_pipe, "ui_print script aborted (no error message)\n"); 136 } else { 137 printf("script aborted: %s\n", state.errmsg); 138 char* line = strtok(state.errmsg, "\n"); 139 while (line) { 140 fprintf(cmd_pipe, "ui_print %s\n", line); 141 line = strtok(NULL, "\n"); 142 } 143 fprintf(cmd_pipe, "ui_print\n"); 144 } 145 free(state.errmsg); 146 return 7; 147 } else { 148 fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result); 149 free(result); 150 } 151 152 if (updater_info.package_zip) { 153 mzCloseZipArchive(updater_info.package_zip); 154 } 155 free(script); 156 157 return 0; 158} 159