blob: 759b688121f29e96e9780648c8b3526196ab6843 [file] [log] [blame]
Doug Zongker9931f7f2009-06-10 14:11:53 -07001/*
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
Doug Zongkerfbf3c102009-06-24 09:36:20 -070017#include <ctype.h>
Doug Zongker9931f7f2009-06-10 14:11:53 -070018#include <errno.h>
19#include <stdarg.h>
Doug Zongkerfbf3c102009-06-24 09:36:20 -070020#include <stdio.h>
Doug Zongker9931f7f2009-06-10 14:11:53 -070021#include <stdlib.h>
22#include <string.h>
23#include <sys/mount.h>
24#include <sys/stat.h>
25#include <sys/types.h>
Doug Zongkera3f89ea2009-09-10 14:10:48 -070026#include <sys/wait.h>
Doug Zongker9931f7f2009-06-10 14:11:53 -070027#include <unistd.h>
28
Doug Zongker8edb00c2009-06-11 17:21:44 -070029#include "cutils/misc.h"
30#include "cutils/properties.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070031#include "edify/expr.h"
Doug Zongker512536a2010-02-17 16:11:44 -080032#include "mincrypt/sha.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070033#include "minzip/DirUtil.h"
34#include "mtdutils/mounts.h"
35#include "mtdutils/mtdutils.h"
36#include "updater.h"
Doug Zongker512536a2010-02-17 16:11:44 -080037#include "applypatch/applypatch.h"
Doug Zongker8edb00c2009-06-11 17:21:44 -070038
Doug Zongker9931f7f2009-06-10 14:11:53 -070039// mount(type, location, mount_point)
40//
41// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem
42// type="vfat" location="/dev/block/<whatever>" to mount a device
Doug Zongker512536a2010-02-17 16:11:44 -080043Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070044 char* result = NULL;
45 if (argc != 3) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070046 return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -070047 }
48 char* type;
49 char* location;
50 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -070051 if (ReadArgs(state, argv, 3, &type, &location, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070052 return NULL;
53 }
54
55 if (strlen(type) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070056 ErrorAbort(state, "type argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070057 goto done;
58 }
59 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070060 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070061 goto done;
62 }
63 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070064 ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070065 goto done;
66 }
67
68 mkdir(mount_point, 0755);
69
70 if (strcmp(type, "MTD") == 0) {
71 mtd_scan_partitions();
72 const MtdPartition* mtd;
73 mtd = mtd_find_partition_by_name(location);
74 if (mtd == NULL) {
75 fprintf(stderr, "%s: no mtd partition named \"%s\"",
76 name, location);
77 result = strdup("");
78 goto done;
79 }
80 if (mtd_mount_partition(mtd, mount_point, "yaffs2", 0 /* rw */) != 0) {
81 fprintf(stderr, "mtd mount of %s failed: %s\n",
82 location, strerror(errno));
83 result = strdup("");
84 goto done;
85 }
86 result = mount_point;
87 } else {
88 if (mount(location, mount_point, type,
89 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
Doug Zongker60babf82009-09-18 15:11:24 -070090 fprintf(stderr, "%s: failed to mount %s at %s: %s\n",
91 name, location, mount_point, strerror(errno));
Doug Zongker9931f7f2009-06-10 14:11:53 -070092 result = strdup("");
93 } else {
94 result = mount_point;
95 }
96 }
97
98done:
99 free(type);
100 free(location);
101 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800102 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700103}
104
Doug Zongker8edb00c2009-06-11 17:21:44 -0700105
106// is_mounted(mount_point)
Doug Zongker512536a2010-02-17 16:11:44 -0800107Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700108 char* result = NULL;
109 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700110 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700111 }
112 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700113 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700114 return NULL;
115 }
116 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700117 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker8edb00c2009-06-11 17:21:44 -0700118 goto done;
119 }
120
121 scan_mounted_volumes();
122 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
123 if (vol == NULL) {
124 result = strdup("");
125 } else {
126 result = mount_point;
127 }
128
129done:
130 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800131 return StringValue(result);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700132}
133
134
Doug Zongker512536a2010-02-17 16:11:44 -0800135Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700136 char* result = NULL;
137 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700138 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700139 }
140 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700141 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700142 return NULL;
143 }
144 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700145 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker9931f7f2009-06-10 14:11:53 -0700146 goto done;
147 }
148
149 scan_mounted_volumes();
150 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
151 if (vol == NULL) {
152 fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
153 result = strdup("");
154 } else {
155 unmount_mounted_volume(vol);
156 result = mount_point;
157 }
158
159done:
160 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800161 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700162}
Doug Zongker8edb00c2009-06-11 17:21:44 -0700163
164
Doug Zongker9931f7f2009-06-10 14:11:53 -0700165// format(type, location)
166//
167// type="MTD" location=partition
Doug Zongker512536a2010-02-17 16:11:44 -0800168Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700169 char* result = NULL;
170 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700171 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700172 }
173 char* type;
174 char* location;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700175 if (ReadArgs(state, argv, 2, &type, &location) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700176 return NULL;
177 }
178
179 if (strlen(type) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700180 ErrorAbort(state, "type argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700181 goto done;
182 }
183 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700184 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700185 goto done;
186 }
187
188 if (strcmp(type, "MTD") == 0) {
189 mtd_scan_partitions();
190 const MtdPartition* mtd = mtd_find_partition_by_name(location);
191 if (mtd == NULL) {
192 fprintf(stderr, "%s: no mtd partition named \"%s\"",
193 name, location);
194 result = strdup("");
195 goto done;
196 }
197 MtdWriteContext* ctx = mtd_write_partition(mtd);
198 if (ctx == NULL) {
199 fprintf(stderr, "%s: can't write \"%s\"", name, location);
200 result = strdup("");
201 goto done;
202 }
203 if (mtd_erase_blocks(ctx, -1) == -1) {
204 mtd_write_close(ctx);
205 fprintf(stderr, "%s: failed to erase \"%s\"", name, location);
206 result = strdup("");
207 goto done;
208 }
209 if (mtd_write_close(ctx) != 0) {
210 fprintf(stderr, "%s: failed to close \"%s\"", name, location);
211 result = strdup("");
212 goto done;
213 }
214 result = location;
215 } else {
216 fprintf(stderr, "%s: unsupported type \"%s\"", name, type);
217 }
218
219done:
220 free(type);
221 if (result != location) free(location);
Doug Zongker512536a2010-02-17 16:11:44 -0800222 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700223}
224
Doug Zongker8edb00c2009-06-11 17:21:44 -0700225
Doug Zongker512536a2010-02-17 16:11:44 -0800226Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700227 char** paths = malloc(argc * sizeof(char*));
228 int i;
229 for (i = 0; i < argc; ++i) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700230 paths[i] = Evaluate(state, argv[i]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700231 if (paths[i] == NULL) {
232 int j;
233 for (j = 0; j < i; ++i) {
234 free(paths[j]);
235 }
236 free(paths);
237 return NULL;
238 }
239 }
240
241 bool recursive = (strcmp(name, "delete_recursive") == 0);
242
243 int success = 0;
244 for (i = 0; i < argc; ++i) {
245 if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
246 ++success;
247 free(paths[i]);
248 }
249 free(paths);
250
251 char buffer[10];
252 sprintf(buffer, "%d", success);
Doug Zongker512536a2010-02-17 16:11:44 -0800253 return StringValue(strdup(buffer));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700254}
255
Doug Zongker8edb00c2009-06-11 17:21:44 -0700256
Doug Zongker512536a2010-02-17 16:11:44 -0800257Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700258 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700259 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700260 }
261 char* frac_str;
262 char* sec_str;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700263 if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700264 return NULL;
265 }
266
267 double frac = strtod(frac_str, NULL);
268 int sec = strtol(sec_str, NULL, 10);
269
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700270 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700271 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
272
Doug Zongker9931f7f2009-06-10 14:11:53 -0700273 free(sec_str);
Doug Zongker512536a2010-02-17 16:11:44 -0800274 return StringValue(frac_str);
Doug Zongkerfbf3c102009-06-24 09:36:20 -0700275}
276
Doug Zongker512536a2010-02-17 16:11:44 -0800277Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerfbf3c102009-06-24 09:36:20 -0700278 if (argc != 1) {
279 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
280 }
281 char* frac_str;
282 if (ReadArgs(state, argv, 1, &frac_str) < 0) {
283 return NULL;
284 }
285
286 double frac = strtod(frac_str, NULL);
287
288 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
289 fprintf(ui->cmd_pipe, "set_progress %f\n", frac);
290
Doug Zongker512536a2010-02-17 16:11:44 -0800291 return StringValue(frac_str);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700292}
293
Doug Zongker8edb00c2009-06-11 17:21:44 -0700294// package_extract_dir(package_path, destination_path)
Doug Zongker512536a2010-02-17 16:11:44 -0800295Value* PackageExtractDirFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700296 int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700297 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700298 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700299 }
300 char* zip_path;
301 char* dest_path;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700302 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700303
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700304 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700305
306 // To create a consistent system image, never use the clock for timestamps.
307 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
308
309 bool success = mzExtractRecursive(za, zip_path, dest_path,
310 MZ_EXTRACT_FILES_ONLY, &timestamp,
311 NULL, NULL);
312 free(zip_path);
313 free(dest_path);
Doug Zongker512536a2010-02-17 16:11:44 -0800314 return StringValue(strdup(success ? "t" : ""));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700315}
316
Doug Zongker8edb00c2009-06-11 17:21:44 -0700317
318// package_extract_file(package_path, destination_path)
Doug Zongker6aece332010-02-01 14:40:12 -0800319// or
320// package_extract_file(package_path)
321// to return the entire contents of the file as the result of this
Doug Zongker512536a2010-02-17 16:11:44 -0800322// function (the char* returned is actually a FileContents*).
323Value* PackageExtractFileFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700324 int argc, Expr* argv[]) {
Doug Zongker6aece332010-02-01 14:40:12 -0800325 if (argc != 1 && argc != 2) {
326 return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
327 name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700328 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700329 bool success = false;
Doug Zongker6aece332010-02-01 14:40:12 -0800330 if (argc == 2) {
331 // The two-argument version extracts to a file.
Doug Zongker8edb00c2009-06-11 17:21:44 -0700332
Doug Zongker6aece332010-02-01 14:40:12 -0800333 char* zip_path;
334 char* dest_path;
335 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
336
337 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
338 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
339 if (entry == NULL) {
340 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
341 goto done2;
342 }
343
344 FILE* f = fopen(dest_path, "wb");
345 if (f == NULL) {
346 fprintf(stderr, "%s: can't open %s for write: %s\n",
347 name, dest_path, strerror(errno));
348 goto done2;
349 }
350 success = mzExtractZipEntryToFile(za, entry, fileno(f));
351 fclose(f);
352
353 done2:
354 free(zip_path);
355 free(dest_path);
Doug Zongker512536a2010-02-17 16:11:44 -0800356 return StringValue(strdup(success ? "t" : ""));
Doug Zongker6aece332010-02-01 14:40:12 -0800357 } else {
358 // The one-argument version returns the contents of the file
359 // as the result.
360
361 char* zip_path;
Doug Zongker512536a2010-02-17 16:11:44 -0800362 Value* v = malloc(sizeof(Value));
363 v->type = VAL_BLOB;
364 v->size = -1;
365 v->data = NULL;
Doug Zongker6aece332010-02-01 14:40:12 -0800366
367 if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
368
369 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
370 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
371 if (entry == NULL) {
372 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
373 goto done1;
374 }
375
Doug Zongker512536a2010-02-17 16:11:44 -0800376 v->size = mzGetZipEntryUncompLen(entry);
377 v->data = malloc(v->size);
378 if (v->data == NULL) {
Doug Zongker6aece332010-02-01 14:40:12 -0800379 fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n",
Doug Zongker512536a2010-02-17 16:11:44 -0800380 name, (long)v->size, zip_path);
Doug Zongker6aece332010-02-01 14:40:12 -0800381 goto done1;
382 }
383
Doug Zongker512536a2010-02-17 16:11:44 -0800384 success = mzExtractZipEntryToBuffer(za, entry,
385 (unsigned char *)v->data);
Doug Zongker6aece332010-02-01 14:40:12 -0800386
387 done1:
388 free(zip_path);
389 if (!success) {
Doug Zongker512536a2010-02-17 16:11:44 -0800390 free(v->data);
391 v->data = NULL;
392 v->size = -1;
Doug Zongker6aece332010-02-01 14:40:12 -0800393 }
Doug Zongker512536a2010-02-17 16:11:44 -0800394 return v;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700395 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700396}
397
398
Doug Zongker9931f7f2009-06-10 14:11:53 -0700399// symlink target src1 src2 ...
Doug Zongker60babf82009-09-18 15:11:24 -0700400// unlinks any previously existing src1, src2, etc before creating symlinks.
Doug Zongker512536a2010-02-17 16:11:44 -0800401Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700402 if (argc == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700403 return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700404 }
405 char* target;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700406 target = Evaluate(state, argv[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700407 if (target == NULL) return NULL;
408
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700409 char** srcs = ReadVarArgs(state, argc-1, argv+1);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700410 if (srcs == NULL) {
411 free(target);
412 return NULL;
413 }
414
415 int i;
416 for (i = 0; i < argc-1; ++i) {
Doug Zongker60babf82009-09-18 15:11:24 -0700417 if (unlink(srcs[i]) < 0) {
418 if (errno != ENOENT) {
419 fprintf(stderr, "%s: failed to remove %s: %s\n",
420 name, srcs[i], strerror(errno));
421 }
422 }
423 if (symlink(target, srcs[i]) < 0) {
424 fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
425 name, srcs[i], target, strerror(errno));
426 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700427 free(srcs[i]);
428 }
429 free(srcs);
Doug Zongker512536a2010-02-17 16:11:44 -0800430 return StringValue(strdup(""));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700431}
432
Doug Zongker8edb00c2009-06-11 17:21:44 -0700433
Doug Zongker512536a2010-02-17 16:11:44 -0800434Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700435 char* result = NULL;
436 bool recursive = (strcmp(name, "set_perm_recursive") == 0);
437
438 int min_args = 4 + (recursive ? 1 : 0);
439 if (argc < min_args) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700440 return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700441 }
442
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700443 char** args = ReadVarArgs(state, argc, argv);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700444 if (args == NULL) return NULL;
445
446 char* end;
447 int i;
448
449 int uid = strtoul(args[0], &end, 0);
450 if (*end != '\0' || args[0][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700451 ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700452 goto done;
453 }
454
455 int gid = strtoul(args[1], &end, 0);
456 if (*end != '\0' || args[1][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700457 ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700458 goto done;
459 }
460
461 if (recursive) {
462 int dir_mode = strtoul(args[2], &end, 0);
463 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700464 ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700465 goto done;
466 }
467
468 int file_mode = strtoul(args[3], &end, 0);
469 if (*end != '\0' || args[3][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700470 ErrorAbort(state, "%s: \"%s\" not a valid filemode",
Doug Zongker9931f7f2009-06-10 14:11:53 -0700471 name, args[3]);
472 goto done;
473 }
474
475 for (i = 4; i < argc; ++i) {
476 dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
477 }
478 } else {
479 int mode = strtoul(args[2], &end, 0);
480 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700481 ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700482 goto done;
483 }
484
Doug Zongker0bbfe3d2009-06-25 13:37:31 -0700485 for (i = 3; i < argc; ++i) {
Doug Zongker60babf82009-09-18 15:11:24 -0700486 if (chown(args[i], uid, gid) < 0) {
487 fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n",
488 name, args[i], uid, gid, strerror(errno));
489 }
490 if (chmod(args[i], mode) < 0) {
491 fprintf(stderr, "%s: chmod of %s to %o failed: %s\n",
492 name, args[i], mode, strerror(errno));
493 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700494 }
495 }
496 result = strdup("");
497
498done:
499 for (i = 0; i < argc; ++i) {
500 free(args[i]);
501 }
502 free(args);
503
Doug Zongker512536a2010-02-17 16:11:44 -0800504 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700505}
506
Doug Zongker8edb00c2009-06-11 17:21:44 -0700507
Doug Zongker512536a2010-02-17 16:11:44 -0800508Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700509 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700510 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700511 }
512 char* key;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700513 key = Evaluate(state, argv[0]);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700514 if (key == NULL) return NULL;
515
516 char value[PROPERTY_VALUE_MAX];
517 property_get(key, value, "");
518 free(key);
519
Doug Zongker512536a2010-02-17 16:11:44 -0800520 return StringValue(strdup(value));
Doug Zongker8edb00c2009-06-11 17:21:44 -0700521}
522
523
Doug Zongker47cace92009-06-18 10:11:50 -0700524// file_getprop(file, key)
525//
526// interprets 'file' as a getprop-style file (key=value pairs, one
527// per line, # comment lines and blank lines okay), and returns the value
528// for 'key' (or "" if it isn't defined).
Doug Zongker512536a2010-02-17 16:11:44 -0800529Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker47cace92009-06-18 10:11:50 -0700530 char* result = NULL;
531 char* buffer = NULL;
532 char* filename;
533 char* key;
534 if (ReadArgs(state, argv, 2, &filename, &key) < 0) {
535 return NULL;
536 }
537
538 struct stat st;
539 if (stat(filename, &st) < 0) {
540 ErrorAbort(state, "%s: failed to stat \"%s\": %s",
541 name, filename, strerror(errno));
542 goto done;
543 }
544
545#define MAX_FILE_GETPROP_SIZE 65536
546
547 if (st.st_size > MAX_FILE_GETPROP_SIZE) {
548 ErrorAbort(state, "%s too large for %s (max %d)",
549 filename, name, MAX_FILE_GETPROP_SIZE);
550 goto done;
551 }
552
553 buffer = malloc(st.st_size+1);
554 if (buffer == NULL) {
555 ErrorAbort(state, "%s: failed to alloc %d bytes", name, st.st_size+1);
556 goto done;
557 }
558
559 FILE* f = fopen(filename, "rb");
560 if (f == NULL) {
561 ErrorAbort(state, "%s: failed to open %s: %s",
562 name, filename, strerror(errno));
563 goto done;
564 }
565
566 if (fread(buffer, 1, st.st_size, f) != st.st_size) {
567 ErrorAbort(state, "%s: failed to read %d bytes from %s",
568 name, st.st_size+1, filename);
569 fclose(f);
570 goto done;
571 }
572 buffer[st.st_size] = '\0';
573
574 fclose(f);
575
576 char* line = strtok(buffer, "\n");
577 do {
578 // skip whitespace at start of line
579 while (*line && isspace(*line)) ++line;
580
581 // comment or blank line: skip to next line
582 if (*line == '\0' || *line == '#') continue;
583
584 char* equal = strchr(line, '=');
585 if (equal == NULL) {
586 ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
587 name, line, filename);
588 goto done;
589 }
590
591 // trim whitespace between key and '='
592 char* key_end = equal-1;
593 while (key_end > line && isspace(*key_end)) --key_end;
594 key_end[1] = '\0';
595
596 // not the key we're looking for
597 if (strcmp(key, line) != 0) continue;
598
599 // skip whitespace after the '=' to the start of the value
600 char* val_start = equal+1;
601 while(*val_start && isspace(*val_start)) ++val_start;
602
603 // trim trailing whitespace
604 char* val_end = val_start + strlen(val_start)-1;
605 while (val_end > val_start && isspace(*val_end)) --val_end;
606 val_end[1] = '\0';
607
608 result = strdup(val_start);
609 break;
610
611 } while ((line = strtok(NULL, "\n")));
612
613 if (result == NULL) result = strdup("");
614
615 done:
616 free(filename);
617 free(key);
618 free(buffer);
Doug Zongker512536a2010-02-17 16:11:44 -0800619 return StringValue(result);
Doug Zongker47cace92009-06-18 10:11:50 -0700620}
621
622
Doug Zongker8edb00c2009-06-11 17:21:44 -0700623static bool write_raw_image_cb(const unsigned char* data,
624 int data_len, void* ctx) {
625 int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
626 if (r == data_len) return true;
627 fprintf(stderr, "%s\n", strerror(errno));
628 return false;
629}
630
Koushik Duttae5678e92010-09-13 13:25:11 -0700631int write_raw_image(const char* partition, const char* filename);
632
Doug Zongker8edb00c2009-06-11 17:21:44 -0700633// write_raw_image(file, partition)
Doug Zongker512536a2010-02-17 16:11:44 -0800634Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700635 char* result = NULL;
636
637 char* partition;
638 char* filename;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700639 if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700640 return NULL;
641 }
642
643 if (strlen(partition) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700644 ErrorAbort(state, "partition argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700645 goto done;
646 }
647 if (strlen(filename) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700648 ErrorAbort(state, "file argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700649 goto done;
650 }
651
Koushik Duttae5678e92010-09-13 13:25:11 -0700652#ifdef BOARD_HAS_CUSTOM_WRITE_RAW_IMAGE
653 if (0 == write_raw_image(name, filename)) {
654 result = partition;
655 }
656 result = strdup("Failure");
657#else
Doug Zongker8edb00c2009-06-11 17:21:44 -0700658 mtd_scan_partitions();
659 const MtdPartition* mtd = mtd_find_partition_by_name(partition);
660 if (mtd == NULL) {
661 fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition);
662 result = strdup("");
663 goto done;
664 }
665
666 MtdWriteContext* ctx = mtd_write_partition(mtd);
667 if (ctx == NULL) {
668 fprintf(stderr, "%s: can't write mtd partition \"%s\"\n",
669 name, partition);
670 result = strdup("");
671 goto done;
672 }
673
674 bool success;
675
676 FILE* f = fopen(filename, "rb");
677 if (f == NULL) {
678 fprintf(stderr, "%s: can't open %s: %s\n",
679 name, filename, strerror(errno));
680 result = strdup("");
681 goto done;
682 }
683
684 success = true;
685 char* buffer = malloc(BUFSIZ);
686 int read;
687 while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
688 int wrote = mtd_write_data(ctx, buffer, read);
689 success = success && (wrote == read);
690 if (!success) {
691 fprintf(stderr, "mtd_write_data to %s failed: %s\n",
692 partition, strerror(errno));
693 }
694 }
695 free(buffer);
696 fclose(f);
697
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700698 if (mtd_erase_blocks(ctx, -1) == -1) {
699 fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition);
700 }
701 if (mtd_write_close(ctx) != 0) {
702 fprintf(stderr, "%s: error closing write of %s\n", name, partition);
703 }
704
Doug Zongker8edb00c2009-06-11 17:21:44 -0700705 printf("%s %s partition from %s\n",
706 success ? "wrote" : "failed to write", partition, filename);
707
708 result = success ? partition : strdup("");
Koushik Duttae5678e92010-09-13 13:25:11 -0700709#endif
Doug Zongker8edb00c2009-06-11 17:21:44 -0700710
711done:
712 if (result != partition) free(partition);
713 free(filename);
Doug Zongker512536a2010-02-17 16:11:44 -0800714 return StringValue(result);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700715}
716
Doug Zongker8edb00c2009-06-11 17:21:44 -0700717// apply_patch_space(bytes)
Doug Zongkerc4351c72010-02-22 14:46:32 -0800718Value* ApplyPatchSpaceFn(const char* name, State* state,
719 int argc, Expr* argv[]) {
720 char* bytes_str;
721 if (ReadArgs(state, argv, 1, &bytes_str) < 0) {
722 return NULL;
723 }
724
725 char* endptr;
726 size_t bytes = strtol(bytes_str, &endptr, 10);
727 if (bytes == 0 && endptr == bytes_str) {
728 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
729 name, bytes_str);
730 free(bytes_str);
731 return NULL;
732 }
733
734 return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
735}
736
737
738// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
Doug Zongker512536a2010-02-17 16:11:44 -0800739Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800740 if (argc < 6 || (argc % 2) == 1) {
741 return ErrorAbort(state, "%s(): expected at least 6 args and an "
742 "even number, got %d",
743 name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700744 }
745
Doug Zongkerc4351c72010-02-22 14:46:32 -0800746 char* source_filename;
747 char* target_filename;
748 char* target_sha1;
749 char* target_size_str;
750 if (ReadArgs(state, argv, 4, &source_filename, &target_filename,
751 &target_sha1, &target_size_str) < 0) {
752 return NULL;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700753 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700754
Doug Zongkerc4351c72010-02-22 14:46:32 -0800755 char* endptr;
756 size_t target_size = strtol(target_size_str, &endptr, 10);
757 if (target_size == 0 && endptr == target_size_str) {
758 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count",
759 name, target_size_str);
760 free(source_filename);
761 free(target_filename);
762 free(target_sha1);
763 free(target_size_str);
764 return NULL;
765 }
766
767 int patchcount = (argc-4) / 2;
768 Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700769
770 int i;
Doug Zongkerc4351c72010-02-22 14:46:32 -0800771 for (i = 0; i < patchcount; ++i) {
772 if (patches[i*2]->type != VAL_STRING) {
773 ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
774 break;
775 }
776 if (patches[i*2+1]->type != VAL_BLOB) {
777 ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
778 break;
779 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700780 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800781 if (i != patchcount) {
782 for (i = 0; i < patchcount*2; ++i) {
783 FreeValue(patches[i]);
784 }
785 free(patches);
786 return NULL;
787 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700788
Doug Zongkerc4351c72010-02-22 14:46:32 -0800789 char** patch_sha_str = malloc(patchcount * sizeof(char*));
790 for (i = 0; i < patchcount; ++i) {
791 patch_sha_str[i] = patches[i*2]->data;
792 patches[i*2]->data = NULL;
793 FreeValue(patches[i*2]);
794 patches[i] = patches[i*2+1];
Doug Zongker8edb00c2009-06-11 17:21:44 -0700795 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800796
797 int result = applypatch(source_filename, target_filename,
798 target_sha1, target_size,
799 patchcount, patch_sha_str, patches);
800
801 for (i = 0; i < patchcount; ++i) {
802 FreeValue(patches[i]);
803 }
804 free(patch_sha_str);
805 free(patches);
806
807 return StringValue(strdup(result == 0 ? "t" : ""));
808}
809
810// apply_patch_check(file, [sha1_1, ...])
811Value* ApplyPatchCheckFn(const char* name, State* state,
812 int argc, Expr* argv[]) {
813 if (argc < 1) {
814 return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
815 name, argc);
816 }
817
818 char* filename;
819 if (ReadArgs(state, argv, 1, &filename) < 0) {
820 return NULL;
821 }
822
823 int patchcount = argc-1;
824 char** sha1s = ReadVarArgs(state, argc-1, argv+1);
825
826 int result = applypatch_check(filename, patchcount, sha1s);
827
828 int i;
829 for (i = 0; i < patchcount; ++i) {
830 free(sha1s[i]);
831 }
832 free(sha1s);
833
834 return StringValue(strdup(result == 0 ? "t" : ""));
Doug Zongker8edb00c2009-06-11 17:21:44 -0700835}
836
Doug Zongker512536a2010-02-17 16:11:44 -0800837Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700838 char** args = ReadVarArgs(state, argc, argv);
839 if (args == NULL) {
840 return NULL;
841 }
842
843 int size = 0;
844 int i;
845 for (i = 0; i < argc; ++i) {
846 size += strlen(args[i]);
847 }
848 char* buffer = malloc(size+1);
849 size = 0;
850 for (i = 0; i < argc; ++i) {
851 strcpy(buffer+size, args[i]);
852 size += strlen(args[i]);
853 free(args[i]);
854 }
855 free(args);
856 buffer[size] = '\0';
857
858 char* line = strtok(buffer, "\n");
859 while (line) {
860 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
861 "ui_print %s\n", line);
862 line = strtok(NULL, "\n");
863 }
864 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
865
Doug Zongker512536a2010-02-17 16:11:44 -0800866 return StringValue(buffer);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700867}
868
Doug Zongker512536a2010-02-17 16:11:44 -0800869Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkera3f89ea2009-09-10 14:10:48 -0700870 if (argc < 1) {
871 return ErrorAbort(state, "%s() expects at least 1 arg", name);
872 }
873 char** args = ReadVarArgs(state, argc, argv);
874 if (args == NULL) {
875 return NULL;
876 }
877
878 char** args2 = malloc(sizeof(char*) * (argc+1));
879 memcpy(args2, args, sizeof(char*) * argc);
880 args2[argc] = NULL;
881
882 fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc);
883
884 pid_t child = fork();
885 if (child == 0) {
886 execv(args2[0], args2);
887 fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno));
888 _exit(1);
889 }
890 int status;
891 waitpid(child, &status, 0);
892 if (WIFEXITED(status)) {
893 if (WEXITSTATUS(status) != 0) {
894 fprintf(stderr, "run_program: child exited with status %d\n",
895 WEXITSTATUS(status));
896 }
897 } else if (WIFSIGNALED(status)) {
898 fprintf(stderr, "run_program: child terminated by signal %d\n",
899 WTERMSIG(status));
900 }
901
902 int i;
903 for (i = 0; i < argc; ++i) {
904 free(args[i]);
905 }
906 free(args);
907 free(args2);
908
909 char buffer[20];
910 sprintf(buffer, "%d", status);
911
Doug Zongker512536a2010-02-17 16:11:44 -0800912 return StringValue(strdup(buffer));
Doug Zongkera3f89ea2009-09-10 14:10:48 -0700913}
914
Doug Zongker512536a2010-02-17 16:11:44 -0800915// Take a sha-1 digest and return it as a newly-allocated hex string.
916static char* PrintSha1(uint8_t* digest) {
917 char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
918 int i;
919 const char* alphabet = "0123456789abcdef";
920 for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
921 buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
922 buffer[i*2+1] = alphabet[digest[i] & 0xf];
923 }
924 buffer[i*2] = '\0';
925 return buffer;
926}
927
928// sha1_check(data)
929// to return the sha1 of the data (given in the format returned by
930// read_file).
931//
932// sha1_check(data, sha1_hex, [sha1_hex, ...])
933// returns the sha1 of the file if it matches any of the hex
934// strings passed, or "" if it does not equal any of them.
935//
936Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
937 if (argc < 1) {
938 return ErrorAbort(state, "%s() expects at least 1 arg", name);
939 }
940
941 Value** args = ReadValueVarArgs(state, argc, argv);
942 if (args == NULL) {
943 return NULL;
944 }
945
946 if (args[0]->size < 0) {
947 fprintf(stderr, "%s(): no file contents received", name);
948 return StringValue(strdup(""));
949 }
950 uint8_t digest[SHA_DIGEST_SIZE];
951 SHA(args[0]->data, args[0]->size, digest);
952 FreeValue(args[0]);
953
954 if (argc == 1) {
955 return StringValue(PrintSha1(digest));
956 }
957
958 int i;
959 uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE);
960 for (i = 1; i < argc; ++i) {
961 if (args[i]->type != VAL_STRING) {
962 fprintf(stderr, "%s(): arg %d is not a string; skipping",
963 name, i);
964 } else if (ParseSha1(args[i]->data, arg_digest) != 0) {
965 // Warn about bad args and skip them.
966 fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping",
967 name, args[i]->data);
968 } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
969 break;
970 }
971 FreeValue(args[i]);
972 }
973 if (i >= argc) {
974 // Didn't match any of the hex strings; return false.
975 return StringValue(strdup(""));
976 }
977 // Found a match; free all the remaining arguments and return the
978 // matched one.
979 int j;
980 for (j = i+1; j < argc; ++j) {
981 FreeValue(args[j]);
982 }
983 return args[i];
984}
985
986// Read a local file and return its contents (the char* returned
987// is actually a FileContents*).
988Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
989 if (argc != 1) {
990 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
991 }
992 char* filename;
993 if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
994
995 Value* v = malloc(sizeof(Value));
996 v->type = VAL_BLOB;
997
998 FileContents fc;
999 if (LoadFileContents(filename, &fc) != 0) {
1000 ErrorAbort(state, "%s() loading \"%s\" failed: %s",
1001 name, filename, strerror(errno));
1002 free(filename);
1003 free(v);
1004 free(fc.data);
1005 return NULL;
1006 }
1007
1008 v->size = fc.size;
1009 v->data = (char*)fc.data;
1010
1011 free(filename);
1012 return v;
1013}
Doug Zongker8edb00c2009-06-11 17:21:44 -07001014
Doug Zongker9931f7f2009-06-10 14:11:53 -07001015void RegisterInstallFunctions() {
1016 RegisterFunction("mount", MountFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001017 RegisterFunction("is_mounted", IsMountedFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001018 RegisterFunction("unmount", UnmountFn);
1019 RegisterFunction("format", FormatFn);
1020 RegisterFunction("show_progress", ShowProgressFn);
Doug Zongkerfbf3c102009-06-24 09:36:20 -07001021 RegisterFunction("set_progress", SetProgressFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001022 RegisterFunction("delete", DeleteFn);
1023 RegisterFunction("delete_recursive", DeleteFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001024 RegisterFunction("package_extract_dir", PackageExtractDirFn);
1025 RegisterFunction("package_extract_file", PackageExtractFileFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001026 RegisterFunction("symlink", SymlinkFn);
1027 RegisterFunction("set_perm", SetPermFn);
1028 RegisterFunction("set_perm_recursive", SetPermFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001029
1030 RegisterFunction("getprop", GetPropFn);
Doug Zongker47cace92009-06-18 10:11:50 -07001031 RegisterFunction("file_getprop", FileGetPropFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001032 RegisterFunction("write_raw_image", WriteRawImageFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001033
1034 RegisterFunction("apply_patch", ApplyPatchFn);
Doug Zongkerc4351c72010-02-22 14:46:32 -08001035 RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
1036 RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
Doug Zongkerd9c9d102009-06-12 12:24:39 -07001037
Doug Zongker512536a2010-02-17 16:11:44 -08001038 RegisterFunction("read_file", ReadFileFn);
1039 RegisterFunction("sha1_check", Sha1CheckFn);
1040
Doug Zongkerd9c9d102009-06-12 12:24:39 -07001041 RegisterFunction("ui_print", UIPrintFn);
Doug Zongkera3f89ea2009-09-10 14:10:48 -07001042
1043 RegisterFunction("run_program", RunProgramFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001044}