edify extensions for OTA package installation, part 1
Adds the following edify functions: mount unmount format show_progress delete delete_recursive package_extract symlink set_perm set_perm_recursive This set is enough to extract and install the system part of a (full) OTA package. Adds the updater binary that extracts an edify script from the OTA package and then executes it. Minor changes to the edify core (adds a sleep() builtin for debugging, adds "." to the set of characters that can appear in an unquoted string).
This commit is contained in:
		| @@ -44,4 +44,6 @@ include $(commands_recovery_local_path)/amend/Android.mk | ||||
| include $(commands_recovery_local_path)/minzip/Android.mk | ||||
| include $(commands_recovery_local_path)/mtdutils/Android.mk | ||||
| include $(commands_recovery_local_path)/tools/Android.mk | ||||
| include $(commands_recovery_local_path)/edify/Android.mk | ||||
| include $(commands_recovery_local_path)/updater/Android.mk | ||||
| commands_recovery_local_path := | ||||
|   | ||||
| @@ -26,15 +26,14 @@ LOCAL_YACCFLAGS := -v | ||||
|  | ||||
| include $(BUILD_HOST_EXECUTABLE) | ||||
|  | ||||
| # # | ||||
| # # Build the device-side library | ||||
| # # | ||||
| # include $(CLEAR_VARS) | ||||
| # | ||||
| # Build the device-side library | ||||
| # | ||||
| include $(CLEAR_VARS) | ||||
|  | ||||
| # LOCAL_SRC_FILES := $(edify_src_files) | ||||
| # LOCAL_SRC_FILES += $(edify_test_files) | ||||
| LOCAL_SRC_FILES := $(edify_src_files) | ||||
|  | ||||
| # LOCAL_CFLAGS := $(edify_cflags) | ||||
| # LOCAL_MODULE := libedify | ||||
| LOCAL_CFLAGS := $(edify_cflags) | ||||
| LOCAL_MODULE := libedify | ||||
|  | ||||
| # include $(BUILD_STATIC_LIBRARY) | ||||
| include $(BUILD_STATIC_LIBRARY) | ||||
|   | ||||
| @@ -10,7 +10,7 @@ the old one ("amend").  This is a brief overview of the new language. | ||||
|   understood, as are hexadecimal escapes like \x4a. | ||||
|  | ||||
| - String literals consisting of only letters, numbers, colons, | ||||
|   underscores, and slashes don't need to be in double quotes. | ||||
|   underscores, slashes, and periods don't need to be in double quotes. | ||||
|  | ||||
| - The following words are reserved: | ||||
|  | ||||
|   | ||||
							
								
								
									
										95
									
								
								edify/expr.c
									
									
									
									
									
								
							
							
						
						
									
										95
									
								
								edify/expr.c
									
									
									
									
									
								
							| @@ -19,6 +19,7 @@ | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdarg.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #include "expr.h" | ||||
|  | ||||
| @@ -92,6 +93,12 @@ char* IfElseFn(const char* name, void* cookie, int argc, Expr* argv[]) { | ||||
| } | ||||
|  | ||||
| char* AbortFn(const char* name, void* cookie, int argc, Expr* argv[]) { | ||||
|   char* msg = NULL; | ||||
|   if (argc > 0) { | ||||
|     msg = Evaluate(cookie, argv[0]); | ||||
|   } | ||||
|   SetError(msg == NULL ? "called abort()" : msg); | ||||
|   free(msg); | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| @@ -105,12 +112,23 @@ char* AssertFn(const char* name, void* cookie, int argc, Expr* argv[]) { | ||||
|     int b = BooleanString(v); | ||||
|     free(v); | ||||
|     if (!b) { | ||||
|       SetError("assert() failed"); | ||||
|       return NULL; | ||||
|     } | ||||
|   } | ||||
|   return strdup(""); | ||||
| } | ||||
|  | ||||
| char* SleepFn(const char* name, void* cookie, int argc, Expr* argv[]) { | ||||
|   char* val = Evaluate(cookie, argv[0]); | ||||
|   if (val == NULL) { | ||||
|     return NULL; | ||||
|   } | ||||
|   int v = strtol(val, NULL, 10); | ||||
|   sleep(v); | ||||
|   return val; | ||||
| } | ||||
|  | ||||
| char* PrintFn(const char* name, void* cookie, int argc, Expr* argv[]) { | ||||
|   int i; | ||||
|   for (i = 0; i < argc; ++i) { | ||||
| @@ -234,6 +252,32 @@ Expr* Build(Function fn, int count, ...) { | ||||
|   return e; | ||||
| } | ||||
|  | ||||
| // ----------------------------------------------------------------- | ||||
| //   error reporting | ||||
| // ----------------------------------------------------------------- | ||||
|  | ||||
| static char* error_message = NULL; | ||||
|  | ||||
| void SetError(const char* message) { | ||||
|   if (error_message) { | ||||
|     free(error_message); | ||||
|   } | ||||
|   error_message = strdup(message); | ||||
| } | ||||
|  | ||||
| const char* GetError() { | ||||
|   return error_message; | ||||
| } | ||||
|  | ||||
| void ClearError() { | ||||
|   free(error_message); | ||||
|   error_message = NULL; | ||||
| } | ||||
|  | ||||
| // ----------------------------------------------------------------- | ||||
| //   the function table | ||||
| // ----------------------------------------------------------------- | ||||
|  | ||||
| static int fn_entries = 0; | ||||
| static int fn_size = 0; | ||||
| NamedFunction* fn_table = NULL; | ||||
| @@ -276,4 +320,55 @@ void RegisterBuiltins() { | ||||
|   RegisterFunction("concat", ConcatFn); | ||||
|   RegisterFunction("is_substring", SubstringFn); | ||||
|   RegisterFunction("print", PrintFn); | ||||
|   RegisterFunction("sleep", SleepFn); | ||||
| } | ||||
|  | ||||
|  | ||||
| // ----------------------------------------------------------------- | ||||
| //   convenience methods for functions | ||||
| // ----------------------------------------------------------------- | ||||
|  | ||||
| // Evaluate the expressions in argv, giving 'count' char* (the ... is | ||||
| // zero or more char** to put them in).  If any expression evaluates | ||||
| // to NULL, free the rest and return -1.  Return 0 on success. | ||||
| int ReadArgs(void* cookie, Expr* argv[], int count, ...) { | ||||
|   char** args = malloc(count * sizeof(char*)); | ||||
|   va_list v; | ||||
|   va_start(v, count); | ||||
|   int i; | ||||
|   for (i = 0; i < count; ++i) { | ||||
|     args[i] = Evaluate(cookie, argv[i]); | ||||
|     if (args[i] == NULL) { | ||||
|       va_end(v); | ||||
|       int j; | ||||
|       for (j = 0; j < i; ++j) { | ||||
|         free(args[j]); | ||||
|       } | ||||
|       return -1; | ||||
|     } | ||||
|     *(va_arg(v, char**)) = args[i]; | ||||
|   } | ||||
|   va_end(v); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| // Evaluate the expressions in argv, returning an array of char* | ||||
| // results.  If any evaluate to NULL, free the rest and return NULL. | ||||
| // The caller is responsible for freeing the returned array and the | ||||
| // strings it contains. | ||||
| char** ReadVarArgs(void* cookie, int argc, Expr* argv[]) { | ||||
|   char** args = (char**)malloc(argc * sizeof(char*)); | ||||
|   int i = 0; | ||||
|   for (i = 0; i < argc; ++i) { | ||||
|     args[i] = Evaluate(cookie, argv[i]); | ||||
|     if (args[i] == NULL) { | ||||
|       int j; | ||||
|       for (j = 0; j < i; ++j) { | ||||
|         free(args[j]); | ||||
|       } | ||||
|       free(args); | ||||
|       return NULL; | ||||
|     } | ||||
|   } | ||||
|   return args; | ||||
| } | ||||
|   | ||||
							
								
								
									
										23
									
								
								edify/expr.h
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								edify/expr.h
									
									
									
									
									
								
							| @@ -57,6 +57,14 @@ char* IfElseFn(const char* name, void* cookie, int argc, Expr* argv[]); | ||||
| char* AssertFn(const char* name, void* cookie, int argc, Expr* argv[]); | ||||
| char* AbortFn(const char* name, void* cookie, int argc, Expr* argv[]); | ||||
|  | ||||
|  | ||||
| // For setting and getting the global error string (when returning | ||||
| // NULL from a function). | ||||
| void SetError(const char* message);  // makes a copy | ||||
| const char* GetError();              // retains ownership | ||||
| void ClearError(); | ||||
|  | ||||
|  | ||||
| typedef struct { | ||||
|   const char* name; | ||||
|   Function fn; | ||||
| @@ -77,4 +85,19 @@ void FinishRegistration(); | ||||
| // exists. | ||||
| Function FindFunction(const char* name); | ||||
|  | ||||
|  | ||||
| // --- convenience functions for use in functions --- | ||||
|  | ||||
| // Evaluate the expressions in argv, giving 'count' char* (the ... is | ||||
| // zero or more char** to put them in).  If any expression evaluates | ||||
| // to NULL, free the rest and return -1.  Return 0 on success. | ||||
| int ReadArgs(void* cookie, Expr* argv[], int count, ...); | ||||
|  | ||||
| // Evaluate the expressions in argv, returning an array of char* | ||||
| // results.  If any evaluate to NULL, free the rest and return NULL. | ||||
| // The caller is responsible for freeing the returned array and the | ||||
| // strings it contains. | ||||
| char** ReadVarArgs(void* cookie, int argc, Expr* argv[]); | ||||
|  | ||||
|  | ||||
| #endif  // _EXPRESSION_H | ||||
|   | ||||
| @@ -77,7 +77,7 @@ then              { gColumn += yyleng; return THEN; } | ||||
| else              { gColumn += yyleng; return ELSE; } | ||||
| endif             { gColumn += yyleng; return ENDIF; } | ||||
|  | ||||
| [a-zA-Z0-9_:/]+ { | ||||
| [a-zA-Z0-9_:/.]+ { | ||||
|   gColumn += yyleng; | ||||
|   yylval.str = strdup(yytext); | ||||
|   return STRING; | ||||
|   | ||||
| @@ -158,7 +158,14 @@ int main(int argc, char** argv) { | ||||
|   printf("parse returned %d\n", error); | ||||
|   if (error == 0) { | ||||
|     char* result = Evaluate(NULL, root); | ||||
|     printf("result is [%s]\n", result == NULL ? "(NULL)" : result); | ||||
|     if (result == NULL) { | ||||
|       char* errmsg = GetError(); | ||||
|       printf("result was NULL, message is: %s\n", | ||||
|              (errmsg == NULL ? "(NULL)" : errmsg)); | ||||
|       ClearError(); | ||||
|     } else { | ||||
|       printf("result is [%s]\n", result); | ||||
|     } | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|   | ||||
| @@ -256,7 +256,7 @@ try_update_binary(const char *path, ZipArchive *zip) { | ||||
|     int status; | ||||
|     waitpid(pid, &status, 0); | ||||
|     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { | ||||
|         LOGE("Error in %s\n(Status %d)\n", path, status); | ||||
|         LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status)); | ||||
|         return INSTALL_ERROR; | ||||
|     } | ||||
|  | ||||
|   | ||||
							
								
								
									
										24
									
								
								updater/Android.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								updater/Android.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| # Copyright 2009 The Android Open Source Project | ||||
|  | ||||
| LOCAL_PATH := $(call my-dir) | ||||
|  | ||||
| updater_src_files := \ | ||||
| 	install.c \ | ||||
| 	updater.c | ||||
|  | ||||
| # | ||||
| # Build the device-side library | ||||
| # | ||||
| include $(CLEAR_VARS) | ||||
|  | ||||
| LOCAL_SRC_FILES := $(updater_src_files) | ||||
|  | ||||
| LOCAL_STATIC_LIBRARIES := libedify libmtdutils libminzip libz | ||||
| LOCAL_STATIC_LIBRARIES += libcutils libstdc++ libc | ||||
| LOCAL_C_INCLUDES += $(LOCAL_PATH)/.. | ||||
|  | ||||
| LOCAL_MODULE := updater | ||||
|  | ||||
| LOCAL_FORCE_STATIC_EXECUTABLE := true | ||||
|  | ||||
| include $(BUILD_EXECUTABLE) | ||||
							
								
								
									
										370
									
								
								updater/install.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										370
									
								
								updater/install.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,370 @@ | ||||
| /* | ||||
|  * Copyright (C) 2009 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <errno.h> | ||||
| #include <stdarg.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <sys/mount.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/types.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #include "edify/expr.h" | ||||
| #include "minzip/DirUtil.h" | ||||
| #include "mtdutils/mounts.h" | ||||
| #include "mtdutils/mtdutils.h" | ||||
| #include "updater.h" | ||||
|  | ||||
| char* ErrorAbort(void* cookie, char* format, ...) { | ||||
|     char* buffer = malloc(4096); | ||||
|     va_list v; | ||||
|     va_start(v, format); | ||||
|     vsnprintf(buffer, 4096, format, v); | ||||
|     va_end(v); | ||||
|     SetError(buffer); | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| // mount(type, location, mount_point) | ||||
| // | ||||
| //   what:  type="MTD"   location="<partition>"            to mount a yaffs2 filesystem | ||||
| //          type="vfat"  location="/dev/block/<whatever>"  to mount a device | ||||
| char* MountFn(const char* name, void* cookie, int argc, Expr* argv[]) { | ||||
|     char* result = NULL; | ||||
|     if (argc != 3) { | ||||
|         return ErrorAbort(cookie, "%s() expects 3 args, got %d", name, argc); | ||||
|     } | ||||
|     char* type; | ||||
|     char* location; | ||||
|     char* mount_point; | ||||
|     if (ReadArgs(cookie, argv, 3, &type, &location, &mount_point) < 0) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     if (strlen(type) == 0) { | ||||
|         ErrorAbort(cookie, "type argument to %s() can't be empty", name); | ||||
|         goto done; | ||||
|     } | ||||
|     if (strlen(location) == 0) { | ||||
|         ErrorAbort(cookie, "location argument to %s() can't be empty", name); | ||||
|         goto done; | ||||
|     } | ||||
|     if (strlen(mount_point) == 0) { | ||||
|         ErrorAbort(cookie, "mount_point argument to %s() can't be empty", name); | ||||
|         goto done; | ||||
|     } | ||||
|  | ||||
|     mkdir(mount_point, 0755); | ||||
|  | ||||
|     if (strcmp(type, "MTD") == 0) { | ||||
|         mtd_scan_partitions(); | ||||
|         const MtdPartition* mtd; | ||||
|         mtd = mtd_find_partition_by_name(location); | ||||
|         if (mtd == NULL) { | ||||
|             fprintf(stderr, "%s: no mtd partition named \"%s\"", | ||||
|                     name, location); | ||||
|             result = strdup(""); | ||||
|             goto done; | ||||
|         } | ||||
|         if (mtd_mount_partition(mtd, mount_point, "yaffs2", 0 /* rw */) != 0) { | ||||
|             fprintf(stderr, "mtd mount of %s failed: %s\n", | ||||
|                     location, strerror(errno)); | ||||
|             result = strdup(""); | ||||
|             goto done; | ||||
|         } | ||||
|         result = mount_point; | ||||
|     } else { | ||||
|         if (mount(location, mount_point, type, | ||||
|                   MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) { | ||||
|             result = strdup(""); | ||||
|         } else { | ||||
|             result = mount_point; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| done: | ||||
|     free(type); | ||||
|     free(location); | ||||
|     if (result != mount_point) free(mount_point); | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| char* UnmountFn(const char* name, void* cookie, int argc, Expr* argv[]) { | ||||
|     char* result = NULL; | ||||
|     if (argc != 1) { | ||||
|         return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc); | ||||
|     } | ||||
|     char* mount_point; | ||||
|     if (ReadArgs(cookie, argv, 1, &mount_point) < 0) { | ||||
|         return NULL; | ||||
|     } | ||||
|     if (strlen(mount_point) == 0) { | ||||
|         ErrorAbort(cookie, "mount_point argument to unmount() can't be empty"); | ||||
|         goto done; | ||||
|     } | ||||
|  | ||||
|     scan_mounted_volumes(); | ||||
|     const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); | ||||
|     if (vol == NULL) { | ||||
|         fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point); | ||||
|         result = strdup(""); | ||||
|     } else { | ||||
|         unmount_mounted_volume(vol); | ||||
|         result = mount_point; | ||||
|     } | ||||
|  | ||||
| done: | ||||
|     if (result != mount_point) free(mount_point); | ||||
|     return result; | ||||
| } | ||||
| // format(type, location) | ||||
| // | ||||
| //    type="MTD"  location=partition | ||||
| char* FormatFn(const char* name, void* cookie, int argc, Expr* argv[]) { | ||||
|     char* result = NULL; | ||||
|     if (argc != 2) { | ||||
|         return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc); | ||||
|     } | ||||
|     char* type; | ||||
|     char* location; | ||||
|     if (ReadArgs(cookie, argv, 2, &type, &location) < 0) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     if (strlen(type) == 0) { | ||||
|         ErrorAbort(cookie, "type argument to %s() can't be empty", name); | ||||
|         goto done; | ||||
|     } | ||||
|     if (strlen(location) == 0) { | ||||
|         ErrorAbort(cookie, "location argument to %s() can't be empty", name); | ||||
|         goto done; | ||||
|     } | ||||
|  | ||||
|     if (strcmp(type, "MTD") == 0) { | ||||
|         mtd_scan_partitions(); | ||||
|         const MtdPartition* mtd = mtd_find_partition_by_name(location); | ||||
|         if (mtd == NULL) { | ||||
|             fprintf(stderr, "%s: no mtd partition named \"%s\"", | ||||
|                     name, location); | ||||
|             result = strdup(""); | ||||
|             goto done; | ||||
|         } | ||||
|         MtdWriteContext* ctx = mtd_write_partition(mtd); | ||||
|         if (ctx == NULL) { | ||||
|             fprintf(stderr, "%s: can't write \"%s\"", name, location); | ||||
|             result = strdup(""); | ||||
|             goto done; | ||||
|         } | ||||
|         if (mtd_erase_blocks(ctx, -1) == -1) { | ||||
|             mtd_write_close(ctx); | ||||
|             fprintf(stderr, "%s: failed to erase \"%s\"", name, location); | ||||
|             result = strdup(""); | ||||
|             goto done; | ||||
|         } | ||||
|         if (mtd_write_close(ctx) != 0) { | ||||
|             fprintf(stderr, "%s: failed to close \"%s\"", name, location); | ||||
|             result = strdup(""); | ||||
|             goto done; | ||||
|         } | ||||
|         result = location; | ||||
|     } else { | ||||
|         fprintf(stderr, "%s: unsupported type \"%s\"", name, type); | ||||
|     } | ||||
|  | ||||
| done: | ||||
|     free(type); | ||||
|     if (result != location) free(location); | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| char* DeleteFn(const char* name, void* cookie, int argc, Expr* argv[]) { | ||||
|     char** paths = malloc(argc * sizeof(char*)); | ||||
|     int i; | ||||
|     for (i = 0; i < argc; ++i) { | ||||
|         paths[i] = Evaluate(cookie, argv[i]); | ||||
|         if (paths[i] == NULL) { | ||||
|             int j; | ||||
|             for (j = 0; j < i; ++i) { | ||||
|                 free(paths[j]); | ||||
|             } | ||||
|             free(paths); | ||||
|             return NULL; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool recursive = (strcmp(name, "delete_recursive") == 0); | ||||
|  | ||||
|     int success = 0; | ||||
|     for (i = 0; i < argc; ++i) { | ||||
|         if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0) | ||||
|             ++success; | ||||
|         free(paths[i]); | ||||
|     } | ||||
|     free(paths); | ||||
|  | ||||
|     char buffer[10]; | ||||
|     sprintf(buffer, "%d", success); | ||||
|     return strdup(buffer); | ||||
| } | ||||
|  | ||||
| char* ShowProgressFn(const char* name, void* cookie, int argc, Expr* argv[]) { | ||||
|     if (argc != 2) { | ||||
|         return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc); | ||||
|     } | ||||
|     char* frac_str; | ||||
|     char* sec_str; | ||||
|     if (ReadArgs(cookie, argv, 2, &frac_str, &sec_str) < 0) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     double frac = strtod(frac_str, NULL); | ||||
|     int sec = strtol(sec_str, NULL, 10); | ||||
|  | ||||
|     UpdaterInfo* ui = (UpdaterInfo*)cookie; | ||||
|     fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec); | ||||
|  | ||||
|     free(frac_str); | ||||
|     free(sec_str); | ||||
|     return strdup(""); | ||||
| } | ||||
|  | ||||
| // package_extract package_path destination_path | ||||
| char* PackageExtractFn(const char* name, void* cookie, int argc, Expr* argv[]) { | ||||
|     if (argc != 2) { | ||||
|         return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc); | ||||
|     } | ||||
|     char* zip_path; | ||||
|     char* dest_path; | ||||
|     if (ReadArgs(cookie, argv, 2, &zip_path, &dest_path) < 0) return NULL; | ||||
|  | ||||
|     ZipArchive* za = ((UpdaterInfo*)cookie)->package_zip; | ||||
|  | ||||
|     // To create a consistent system image, never use the clock for timestamps. | ||||
|     struct utimbuf timestamp = { 1217592000, 1217592000 };  // 8/1/2008 default | ||||
|  | ||||
|     bool success = mzExtractRecursive(za, zip_path, dest_path, | ||||
|                                       MZ_EXTRACT_FILES_ONLY, ×tamp, | ||||
|                                       NULL, NULL); | ||||
|     free(zip_path); | ||||
|     free(dest_path); | ||||
|     return strdup(success ? "t" : ""); | ||||
| } | ||||
|  | ||||
| // symlink target src1 src2 ... | ||||
| char* SymlinkFn(const char* name, void* cookie, int argc, Expr* argv[]) { | ||||
|     if (argc == 0) { | ||||
|         return ErrorAbort(cookie, "%s() expects 1+ args, got %d", name, argc); | ||||
|     } | ||||
|     char* target; | ||||
|     target = Evaluate(cookie, argv[0]); | ||||
|     if (target == NULL) return NULL; | ||||
|  | ||||
|     char** srcs = ReadVarArgs(cookie, argc-1, argv+1); | ||||
|     if (srcs == NULL) { | ||||
|         free(target); | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     int i; | ||||
|     for (i = 0; i < argc-1; ++i) { | ||||
|         symlink(target, srcs[i]); | ||||
|         free(srcs[i]); | ||||
|     } | ||||
|     free(srcs); | ||||
|     return strdup(""); | ||||
| } | ||||
|  | ||||
| char* SetPermFn(const char* name, void* cookie, int argc, Expr* argv[]) { | ||||
|     char* result = NULL; | ||||
|     bool recursive = (strcmp(name, "set_perm_recursive") == 0); | ||||
|  | ||||
|     int min_args = 4 + (recursive ? 1 : 0); | ||||
|     if (argc < min_args) { | ||||
|         return ErrorAbort(cookie, "%s() expects %d+ args, got %d", name, argc); | ||||
|     } | ||||
|  | ||||
|     char** args = ReadVarArgs(cookie, argc, argv); | ||||
|     if (args == NULL) return NULL; | ||||
|  | ||||
|     char* end; | ||||
|     int i; | ||||
|  | ||||
|     int uid = strtoul(args[0], &end, 0); | ||||
|     if (*end != '\0' || args[0][0] == 0) { | ||||
|         ErrorAbort(cookie, "%s: \"%s\" not a valid uid", name, args[0]); | ||||
|         goto done; | ||||
|     } | ||||
|  | ||||
|     int gid = strtoul(args[1], &end, 0); | ||||
|     if (*end != '\0' || args[1][0] == 0) { | ||||
|         ErrorAbort(cookie, "%s: \"%s\" not a valid gid", name, args[1]); | ||||
|         goto done; | ||||
|     } | ||||
|  | ||||
|     if (recursive) { | ||||
|         int dir_mode = strtoul(args[2], &end, 0); | ||||
|         if (*end != '\0' || args[2][0] == 0) { | ||||
|             ErrorAbort(cookie, "%s: \"%s\" not a valid dirmode", name, args[2]); | ||||
|             goto done; | ||||
|         } | ||||
|  | ||||
|         int file_mode = strtoul(args[3], &end, 0); | ||||
|         if (*end != '\0' || args[3][0] == 0) { | ||||
|             ErrorAbort(cookie, "%s: \"%s\" not a valid filemode", | ||||
|                        name, args[3]); | ||||
|             goto done; | ||||
|         } | ||||
|  | ||||
|         for (i = 4; i < argc; ++i) { | ||||
|             dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode); | ||||
|         } | ||||
|     } else { | ||||
|         int mode = strtoul(args[2], &end, 0); | ||||
|         if (*end != '\0' || args[2][0] == 0) { | ||||
|             ErrorAbort(cookie, "%s: \"%s\" not a valid mode", name, args[2]); | ||||
|             goto done; | ||||
|         } | ||||
|  | ||||
|         for (i = 4; i < argc; ++i) { | ||||
|             chown(args[i], uid, gid); | ||||
|             chmod(args[i], mode); | ||||
|         } | ||||
|     } | ||||
|     result = strdup(""); | ||||
|  | ||||
| done: | ||||
|     for (i = 0; i < argc; ++i) { | ||||
|         free(args[i]); | ||||
|     } | ||||
|     free(args); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| void RegisterInstallFunctions() { | ||||
|     RegisterFunction("mount", MountFn); | ||||
|     RegisterFunction("unmount", UnmountFn); | ||||
|     RegisterFunction("format", FormatFn); | ||||
|     RegisterFunction("show_progress", ShowProgressFn); | ||||
|     RegisterFunction("delete", DeleteFn); | ||||
|     RegisterFunction("delete_recursive", DeleteFn); | ||||
|     RegisterFunction("package_extract", PackageExtractFn); | ||||
|     RegisterFunction("symlink", SymlinkFn); | ||||
|     RegisterFunction("set_perm", SetPermFn); | ||||
|     RegisterFunction("set_perm_recursive", SetPermFn); | ||||
| } | ||||
							
								
								
									
										22
									
								
								updater/install.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								updater/install.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| /* | ||||
|  * Copyright (C) 2009 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #ifndef _UPDATER_INSTALL_H_ | ||||
| #define _UPDATER_INSTALL_H_ | ||||
|  | ||||
| void RegisterInstallFunctions(); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										111
									
								
								updater/updater.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								updater/updater.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | ||||
| /* | ||||
|  * Copyright (C) 2009 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| #include "edify/expr.h" | ||||
| #include "updater.h" | ||||
| #include "install.h" | ||||
| #include "minzip/Zip.h" | ||||
|  | ||||
| // Where in the package we expect to find the edify script to execute. | ||||
| // (Note it's "updateR-script", not the older "update-script".) | ||||
| #define SCRIPT_NAME "META-INF/com/google/android/updater-script" | ||||
|  | ||||
| int main(int argc, char** argv) { | ||||
|     if (argc != 4) { | ||||
|         fprintf(stderr, "unexpected number of arguments (%d)\n", argc); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     char* version = argv[1]; | ||||
|     if (version[0] != '1' || version[1] != '\0') { | ||||
|         fprintf(stderr, "wrong updater binary API; expected 1, got %s\n", | ||||
|                 version); | ||||
|         return 2; | ||||
|     } | ||||
|  | ||||
|     // Set up the pipe for sending commands back to the parent process. | ||||
|  | ||||
|     int fd = atoi(argv[2]); | ||||
|     FILE* cmd_pipe = fdopen(fd, "wb"); | ||||
|     setlinebuf(cmd_pipe); | ||||
|  | ||||
|     // Extract the script from the package. | ||||
|  | ||||
|     char* package_data = argv[3]; | ||||
|     ZipArchive za; | ||||
|     int err; | ||||
|     err = mzOpenZipArchive(package_data, &za); | ||||
|     if (err != 0) { | ||||
|         fprintf(stderr, "failed to open package %s: %s\n", | ||||
|                 package_data, strerror(err)); | ||||
|         return 3; | ||||
|     } | ||||
|  | ||||
|     const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME); | ||||
|     if (script_entry == NULL) { | ||||
|         fprintf(stderr, "failed to find %s in %s\n", SCRIPT_NAME, package_data); | ||||
|         return 4; | ||||
|     } | ||||
|  | ||||
|     char* script = malloc(script_entry->uncompLen+1); | ||||
|     if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) { | ||||
|         fprintf(stderr, "failed to read script from package\n"); | ||||
|         return 5; | ||||
|     } | ||||
|     script[script_entry->uncompLen] = '\0'; | ||||
|  | ||||
|     // Configure edify's functions. | ||||
|  | ||||
|     RegisterBuiltins(); | ||||
|     RegisterInstallFunctions(); | ||||
|     FinishRegistration(); | ||||
|  | ||||
|     // Parse the script. | ||||
|  | ||||
|     Expr* root; | ||||
|     yy_scan_string(script); | ||||
|     int error = yyparse(&root); | ||||
|     if (error != 0) { | ||||
|         fprintf(stderr, "%d parse errors\n", error); | ||||
|         return 6; | ||||
|     } | ||||
|  | ||||
|     // Evaluate the parsed script. | ||||
|  | ||||
|     UpdaterInfo updater_info; | ||||
|     updater_info.cmd_pipe = cmd_pipe; | ||||
|     updater_info.package_zip = &za; | ||||
|  | ||||
|     char* result = Evaluate(&updater_info, root); | ||||
|     if (result == NULL) { | ||||
|         const char* errmsg = GetError(); | ||||
|         fprintf(stderr, "script aborted with error: %s\n", | ||||
|                 errmsg == NULL ? "(none)" : errmsg); | ||||
|         ClearError(); | ||||
|         return 7; | ||||
|     } else { | ||||
|         fprintf(stderr, "script result was [%s]\n", result); | ||||
|         free(result); | ||||
|     } | ||||
|  | ||||
|     mzCloseZipArchive(&za); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										28
									
								
								updater/updater.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								updater/updater.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * Copyright (C) 2009 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #ifndef _UPDATER_UPDATER_H_ | ||||
| #define _UPDATER_UPDATER_H_ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include "minzip/Zip.h" | ||||
|  | ||||
| typedef struct { | ||||
|     FILE* cmd_pipe; | ||||
|     ZipArchive* package_zip; | ||||
| } UpdaterInfo; | ||||
|  | ||||
| #endif | ||||
		Reference in New Issue
	
	Block a user