blob: d23ec64a560839f1180aa4266e33cef10908a052 [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"
Koushik Dutta7c1bffe2010-12-18 19:44:33 -080034#include "mounts.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070035#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 Zongker56c51052010-07-01 09:18:44 -070039#ifdef USE_EXT4
40#include "make_ext4fs.h"
41#endif
42
43// mount(fs_type, partition_type, location, mount_point)
Doug Zongker9931f7f2009-06-10 14:11:53 -070044//
Doug Zongker56c51052010-07-01 09:18:44 -070045// fs_type="yaffs2" partition_type="MTD" location=partition
46// fs_type="ext4" partition_type="EMMC" location=device
Doug Zongker512536a2010-02-17 16:11:44 -080047Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070048 char* result = NULL;
Doug Zongker56c51052010-07-01 09:18:44 -070049 if (argc != 4) {
50 return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -070051 }
Doug Zongker56c51052010-07-01 09:18:44 -070052 char* fs_type;
53 char* partition_type;
Doug Zongker9931f7f2009-06-10 14:11:53 -070054 char* location;
55 char* mount_point;
Doug Zongker56c51052010-07-01 09:18:44 -070056 if (ReadArgs(state, argv, 4, &fs_type, &partition_type,
57 &location, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070058 return NULL;
59 }
60
Doug Zongker56c51052010-07-01 09:18:44 -070061 if (strlen(fs_type) == 0) {
62 ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
63 goto done;
64 }
65 if (strlen(partition_type) == 0) {
66 ErrorAbort(state, "partition_type argument to %s() can't be empty",
67 name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070068 goto done;
69 }
70 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070071 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070072 goto done;
73 }
74 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070075 ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070076 goto done;
77 }
78
79 mkdir(mount_point, 0755);
80
Koushik Dutta8637c732010-12-18 18:18:44 -080081 if (strcmp(partition_type, "MTD") == 0) {
82 mtd_scan_partitions();
83 const MtdPartition* mtd;
84 mtd = mtd_find_partition_by_name(location);
85 if (mtd == NULL) {
86 fprintf(stderr, "%s: no mtd partition named \"%s\"",
87 name, location);
Doug Zongker9931f7f2009-06-10 14:11:53 -070088 result = strdup("");
Koushik Dutta8637c732010-12-18 18:18:44 -080089 goto done;
90 }
91 if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
92 fprintf(stderr, "mtd mount of %s failed: %s\n",
93 location, strerror(errno));
94 result = strdup("");
95 goto done;
96 }
97 result = mount_point;
Doug Zongker9931f7f2009-06-10 14:11:53 -070098 } else {
Doug Zongker56c51052010-07-01 09:18:44 -070099 if (mount(location, mount_point, fs_type,
Doug Zongker9931f7f2009-06-10 14:11:53 -0700100 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
Doug Zongker60babf82009-09-18 15:11:24 -0700101 fprintf(stderr, "%s: failed to mount %s at %s: %s\n",
102 name, location, mount_point, strerror(errno));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700103 result = strdup("");
104 } else {
105 result = mount_point;
106 }
107 }
108
109done:
Doug Zongker56c51052010-07-01 09:18:44 -0700110 free(fs_type);
111 free(partition_type);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700112 free(location);
113 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800114 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700115}
116
Doug Zongker8edb00c2009-06-11 17:21:44 -0700117
118// is_mounted(mount_point)
Doug Zongker512536a2010-02-17 16:11:44 -0800119Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700120 char* result = NULL;
121 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700122 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700123 }
124 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700125 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700126 return NULL;
127 }
128 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700129 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker8edb00c2009-06-11 17:21:44 -0700130 goto done;
131 }
132
133 scan_mounted_volumes();
134 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
135 if (vol == NULL) {
136 result = strdup("");
137 } else {
138 result = mount_point;
139 }
140
141done:
142 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800143 return StringValue(result);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700144}
145
146
Doug Zongker512536a2010-02-17 16:11:44 -0800147Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700148 char* result = NULL;
149 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700150 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700151 }
152 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700153 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700154 return NULL;
155 }
156 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700157 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker9931f7f2009-06-10 14:11:53 -0700158 goto done;
159 }
160
161 scan_mounted_volumes();
162 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
163 if (vol == NULL) {
164 fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
165 result = strdup("");
166 } else {
167 unmount_mounted_volume(vol);
168 result = mount_point;
169 }
170
171done:
172 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800173 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700174}
Doug Zongker8edb00c2009-06-11 17:21:44 -0700175
176
Doug Zongker56c51052010-07-01 09:18:44 -0700177// format(fs_type, partition_type, location)
Doug Zongker9931f7f2009-06-10 14:11:53 -0700178//
Doug Zongker56c51052010-07-01 09:18:44 -0700179// fs_type="yaffs2" partition_type="MTD" location=partition
180// fs_type="ext4" partition_type="EMMC" location=device
Doug Zongker512536a2010-02-17 16:11:44 -0800181Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700182 char* result = NULL;
Doug Zongker56c51052010-07-01 09:18:44 -0700183 if (argc != 3) {
184 return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700185 }
Doug Zongker56c51052010-07-01 09:18:44 -0700186 char* fs_type;
187 char* partition_type;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700188 char* location;
Doug Zongker56c51052010-07-01 09:18:44 -0700189 if (ReadArgs(state, argv, 3, &fs_type, &partition_type, &location) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700190 return NULL;
191 }
192
Doug Zongker56c51052010-07-01 09:18:44 -0700193 if (strlen(fs_type) == 0) {
194 ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
195 goto done;
196 }
197 if (strlen(partition_type) == 0) {
198 ErrorAbort(state, "partition_type argument to %s() can't be empty",
199 name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700200 goto done;
201 }
202 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700203 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700204 goto done;
205 }
206
Koushik Dutta8637c732010-12-18 18:18:44 -0800207 if (strcmp(partition_type, "MTD") == 0) {
208 mtd_scan_partitions();
209 const MtdPartition* mtd = mtd_find_partition_by_name(location);
210 if (mtd == NULL) {
211 fprintf(stderr, "%s: no mtd partition named \"%s\"",
212 name, location);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700213 result = strdup("");
214 goto done;
215 }
Koushik Dutta8637c732010-12-18 18:18:44 -0800216 MtdWriteContext* ctx = mtd_write_partition(mtd);
217 if (ctx == NULL) {
218 fprintf(stderr, "%s: can't write \"%s\"", name, location);
219 result = strdup("");
220 goto done;
221 }
222 if (mtd_erase_blocks(ctx, -1) == -1) {
223 mtd_write_close(ctx);
224 fprintf(stderr, "%s: failed to erase \"%s\"", name, location);
225 result = strdup("");
226 goto done;
227 }
228 if (mtd_write_close(ctx) != 0) {
229 fprintf(stderr, "%s: failed to close \"%s\"", name, location);
230 result = strdup("");
231 goto done;
232 }
233 result = location;
Doug Zongker56c51052010-07-01 09:18:44 -0700234#ifdef USE_EXT4
235 } else if (strcmp(fs_type, "ext4") == 0) {
236 reset_ext4fs_info();
Brian Swetland792b0072010-09-15 18:03:58 -0700237 int status = make_ext4fs(location, NULL, NULL, 0, 0, 0);
Doug Zongker56c51052010-07-01 09:18:44 -0700238 if (status != 0) {
239 fprintf(stderr, "%s: make_ext4fs failed (%d) on %s",
240 name, status, location);
241 result = strdup("");
242 goto done;
243 }
244 result = location;
245#endif
Koushik Duttab4c5fd62011-01-02 22:54:31 -0800246 } else if (strcmp(fs_type, "ext2") == 0) {
247 int status = format_ext2_device(location);
248 if (status != 0) {
249 fprintf(stderr, "%s: format_ext2_device failed (%d) on %s",
250 name, status, location);
251 result = strdup("");
252 goto done;
253 }
254 result = location;
255 } else if (strcmp(fs_type, "ext3") == 0) {
256 int status = format_ext3_device(location);
257 if (status != 0) {
258 fprintf(stderr, "%s: format_ext3_device failed (%d) on %s",
259 name, status, location);
260 result = strdup("");
261 goto done;
262 }
263 result = location;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700264 } else {
Doug Zongker56c51052010-07-01 09:18:44 -0700265 fprintf(stderr, "%s: unsupported fs_type \"%s\" partition_type \"%s\"",
266 name, fs_type, partition_type);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700267 }
Koushik Dutta8637c732010-12-18 18:18:44 -0800268
Doug Zongker9931f7f2009-06-10 14:11:53 -0700269done:
Doug Zongker56c51052010-07-01 09:18:44 -0700270 free(fs_type);
271 free(partition_type);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700272 if (result != location) free(location);
Doug Zongker512536a2010-02-17 16:11:44 -0800273 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700274}
275
Doug Zongker8edb00c2009-06-11 17:21:44 -0700276
Doug Zongker512536a2010-02-17 16:11:44 -0800277Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700278 char** paths = malloc(argc * sizeof(char*));
279 int i;
280 for (i = 0; i < argc; ++i) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700281 paths[i] = Evaluate(state, argv[i]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700282 if (paths[i] == NULL) {
283 int j;
284 for (j = 0; j < i; ++i) {
285 free(paths[j]);
286 }
287 free(paths);
288 return NULL;
289 }
290 }
291
292 bool recursive = (strcmp(name, "delete_recursive") == 0);
293
294 int success = 0;
295 for (i = 0; i < argc; ++i) {
296 if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
297 ++success;
298 free(paths[i]);
299 }
300 free(paths);
301
302 char buffer[10];
303 sprintf(buffer, "%d", success);
Doug Zongker512536a2010-02-17 16:11:44 -0800304 return StringValue(strdup(buffer));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700305}
306
Doug Zongker8edb00c2009-06-11 17:21:44 -0700307
Doug Zongker512536a2010-02-17 16:11:44 -0800308Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700309 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700310 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700311 }
312 char* frac_str;
313 char* sec_str;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700314 if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700315 return NULL;
316 }
317
318 double frac = strtod(frac_str, NULL);
319 int sec = strtol(sec_str, NULL, 10);
320
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700321 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700322 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
323
Doug Zongker9931f7f2009-06-10 14:11:53 -0700324 free(sec_str);
Doug Zongker512536a2010-02-17 16:11:44 -0800325 return StringValue(frac_str);
Doug Zongkerfbf3c102009-06-24 09:36:20 -0700326}
327
Doug Zongker512536a2010-02-17 16:11:44 -0800328Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerfbf3c102009-06-24 09:36:20 -0700329 if (argc != 1) {
330 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
331 }
332 char* frac_str;
333 if (ReadArgs(state, argv, 1, &frac_str) < 0) {
334 return NULL;
335 }
336
337 double frac = strtod(frac_str, NULL);
338
339 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
340 fprintf(ui->cmd_pipe, "set_progress %f\n", frac);
341
Doug Zongker512536a2010-02-17 16:11:44 -0800342 return StringValue(frac_str);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700343}
344
Doug Zongker8edb00c2009-06-11 17:21:44 -0700345// package_extract_dir(package_path, destination_path)
Doug Zongker512536a2010-02-17 16:11:44 -0800346Value* PackageExtractDirFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700347 int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700348 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700349 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700350 }
351 char* zip_path;
352 char* dest_path;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700353 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700354
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700355 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700356
357 // To create a consistent system image, never use the clock for timestamps.
358 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
359
360 bool success = mzExtractRecursive(za, zip_path, dest_path,
361 MZ_EXTRACT_FILES_ONLY, &timestamp,
362 NULL, NULL);
363 free(zip_path);
364 free(dest_path);
Doug Zongker512536a2010-02-17 16:11:44 -0800365 return StringValue(strdup(success ? "t" : ""));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700366}
367
Doug Zongker8edb00c2009-06-11 17:21:44 -0700368
369// package_extract_file(package_path, destination_path)
Doug Zongker6aece332010-02-01 14:40:12 -0800370// or
371// package_extract_file(package_path)
372// to return the entire contents of the file as the result of this
Doug Zongker512536a2010-02-17 16:11:44 -0800373// function (the char* returned is actually a FileContents*).
374Value* PackageExtractFileFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700375 int argc, Expr* argv[]) {
Doug Zongker6aece332010-02-01 14:40:12 -0800376 if (argc != 1 && argc != 2) {
377 return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
378 name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700379 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700380 bool success = false;
Doug Zongker6aece332010-02-01 14:40:12 -0800381 if (argc == 2) {
382 // The two-argument version extracts to a file.
Doug Zongker8edb00c2009-06-11 17:21:44 -0700383
Doug Zongker6aece332010-02-01 14:40:12 -0800384 char* zip_path;
385 char* dest_path;
386 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
387
388 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
389 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
390 if (entry == NULL) {
391 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
392 goto done2;
393 }
394
395 FILE* f = fopen(dest_path, "wb");
396 if (f == NULL) {
397 fprintf(stderr, "%s: can't open %s for write: %s\n",
398 name, dest_path, strerror(errno));
399 goto done2;
400 }
401 success = mzExtractZipEntryToFile(za, entry, fileno(f));
402 fclose(f);
403
404 done2:
405 free(zip_path);
406 free(dest_path);
Doug Zongker512536a2010-02-17 16:11:44 -0800407 return StringValue(strdup(success ? "t" : ""));
Doug Zongker6aece332010-02-01 14:40:12 -0800408 } else {
409 // The one-argument version returns the contents of the file
410 // as the result.
411
412 char* zip_path;
Doug Zongker512536a2010-02-17 16:11:44 -0800413 Value* v = malloc(sizeof(Value));
414 v->type = VAL_BLOB;
415 v->size = -1;
416 v->data = NULL;
Doug Zongker6aece332010-02-01 14:40:12 -0800417
418 if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
419
420 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
421 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
422 if (entry == NULL) {
423 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
424 goto done1;
425 }
426
Doug Zongker512536a2010-02-17 16:11:44 -0800427 v->size = mzGetZipEntryUncompLen(entry);
428 v->data = malloc(v->size);
429 if (v->data == NULL) {
Doug Zongker6aece332010-02-01 14:40:12 -0800430 fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n",
Doug Zongker512536a2010-02-17 16:11:44 -0800431 name, (long)v->size, zip_path);
Doug Zongker6aece332010-02-01 14:40:12 -0800432 goto done1;
433 }
434
Doug Zongker512536a2010-02-17 16:11:44 -0800435 success = mzExtractZipEntryToBuffer(za, entry,
436 (unsigned char *)v->data);
Doug Zongker6aece332010-02-01 14:40:12 -0800437
438 done1:
439 free(zip_path);
440 if (!success) {
Doug Zongker512536a2010-02-17 16:11:44 -0800441 free(v->data);
442 v->data = NULL;
443 v->size = -1;
Doug Zongker6aece332010-02-01 14:40:12 -0800444 }
Doug Zongker512536a2010-02-17 16:11:44 -0800445 return v;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700446 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700447}
448
449
Doug Zongker9931f7f2009-06-10 14:11:53 -0700450// symlink target src1 src2 ...
Doug Zongker60babf82009-09-18 15:11:24 -0700451// unlinks any previously existing src1, src2, etc before creating symlinks.
Doug Zongker512536a2010-02-17 16:11:44 -0800452Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700453 if (argc == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700454 return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700455 }
456 char* target;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700457 target = Evaluate(state, argv[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700458 if (target == NULL) return NULL;
459
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700460 char** srcs = ReadVarArgs(state, argc-1, argv+1);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700461 if (srcs == NULL) {
462 free(target);
463 return NULL;
464 }
465
466 int i;
467 for (i = 0; i < argc-1; ++i) {
Doug Zongker60babf82009-09-18 15:11:24 -0700468 if (unlink(srcs[i]) < 0) {
469 if (errno != ENOENT) {
470 fprintf(stderr, "%s: failed to remove %s: %s\n",
471 name, srcs[i], strerror(errno));
472 }
473 }
474 if (symlink(target, srcs[i]) < 0) {
475 fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
476 name, srcs[i], target, strerror(errno));
477 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700478 free(srcs[i]);
479 }
480 free(srcs);
Doug Zongker512536a2010-02-17 16:11:44 -0800481 return StringValue(strdup(""));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700482}
483
Doug Zongker8edb00c2009-06-11 17:21:44 -0700484
Doug Zongker512536a2010-02-17 16:11:44 -0800485Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700486 char* result = NULL;
487 bool recursive = (strcmp(name, "set_perm_recursive") == 0);
488
489 int min_args = 4 + (recursive ? 1 : 0);
490 if (argc < min_args) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700491 return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700492 }
493
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700494 char** args = ReadVarArgs(state, argc, argv);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700495 if (args == NULL) return NULL;
496
497 char* end;
498 int i;
499
500 int uid = strtoul(args[0], &end, 0);
501 if (*end != '\0' || args[0][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700502 ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700503 goto done;
504 }
505
506 int gid = strtoul(args[1], &end, 0);
507 if (*end != '\0' || args[1][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700508 ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700509 goto done;
510 }
511
512 if (recursive) {
513 int dir_mode = strtoul(args[2], &end, 0);
514 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700515 ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700516 goto done;
517 }
518
519 int file_mode = strtoul(args[3], &end, 0);
520 if (*end != '\0' || args[3][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700521 ErrorAbort(state, "%s: \"%s\" not a valid filemode",
Doug Zongker9931f7f2009-06-10 14:11:53 -0700522 name, args[3]);
523 goto done;
524 }
525
526 for (i = 4; i < argc; ++i) {
527 dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
528 }
529 } else {
530 int mode = strtoul(args[2], &end, 0);
531 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700532 ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700533 goto done;
534 }
535
Doug Zongker0bbfe3d2009-06-25 13:37:31 -0700536 for (i = 3; i < argc; ++i) {
Doug Zongker60babf82009-09-18 15:11:24 -0700537 if (chown(args[i], uid, gid) < 0) {
538 fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n",
539 name, args[i], uid, gid, strerror(errno));
540 }
541 if (chmod(args[i], mode) < 0) {
542 fprintf(stderr, "%s: chmod of %s to %o failed: %s\n",
543 name, args[i], mode, strerror(errno));
544 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700545 }
546 }
547 result = strdup("");
548
549done:
550 for (i = 0; i < argc; ++i) {
551 free(args[i]);
552 }
553 free(args);
554
Doug Zongker512536a2010-02-17 16:11:44 -0800555 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700556}
557
Doug Zongker8edb00c2009-06-11 17:21:44 -0700558
Doug Zongker512536a2010-02-17 16:11:44 -0800559Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700560 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700561 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700562 }
563 char* key;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700564 key = Evaluate(state, argv[0]);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700565 if (key == NULL) return NULL;
566
567 char value[PROPERTY_VALUE_MAX];
568 property_get(key, value, "");
569 free(key);
570
Doug Zongker512536a2010-02-17 16:11:44 -0800571 return StringValue(strdup(value));
Doug Zongker8edb00c2009-06-11 17:21:44 -0700572}
573
574
Doug Zongker47cace92009-06-18 10:11:50 -0700575// file_getprop(file, key)
576//
577// interprets 'file' as a getprop-style file (key=value pairs, one
578// per line, # comment lines and blank lines okay), and returns the value
579// for 'key' (or "" if it isn't defined).
Doug Zongker512536a2010-02-17 16:11:44 -0800580Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker47cace92009-06-18 10:11:50 -0700581 char* result = NULL;
582 char* buffer = NULL;
583 char* filename;
584 char* key;
585 if (ReadArgs(state, argv, 2, &filename, &key) < 0) {
586 return NULL;
587 }
588
589 struct stat st;
590 if (stat(filename, &st) < 0) {
591 ErrorAbort(state, "%s: failed to stat \"%s\": %s",
592 name, filename, strerror(errno));
593 goto done;
594 }
595
596#define MAX_FILE_GETPROP_SIZE 65536
597
598 if (st.st_size > MAX_FILE_GETPROP_SIZE) {
599 ErrorAbort(state, "%s too large for %s (max %d)",
600 filename, name, MAX_FILE_GETPROP_SIZE);
601 goto done;
602 }
603
604 buffer = malloc(st.st_size+1);
605 if (buffer == NULL) {
606 ErrorAbort(state, "%s: failed to alloc %d bytes", name, st.st_size+1);
607 goto done;
608 }
609
610 FILE* f = fopen(filename, "rb");
611 if (f == NULL) {
612 ErrorAbort(state, "%s: failed to open %s: %s",
613 name, filename, strerror(errno));
614 goto done;
615 }
616
617 if (fread(buffer, 1, st.st_size, f) != st.st_size) {
618 ErrorAbort(state, "%s: failed to read %d bytes from %s",
619 name, st.st_size+1, filename);
620 fclose(f);
621 goto done;
622 }
623 buffer[st.st_size] = '\0';
624
625 fclose(f);
626
627 char* line = strtok(buffer, "\n");
628 do {
629 // skip whitespace at start of line
630 while (*line && isspace(*line)) ++line;
631
632 // comment or blank line: skip to next line
633 if (*line == '\0' || *line == '#') continue;
634
635 char* equal = strchr(line, '=');
636 if (equal == NULL) {
637 ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
638 name, line, filename);
639 goto done;
640 }
641
642 // trim whitespace between key and '='
643 char* key_end = equal-1;
644 while (key_end > line && isspace(*key_end)) --key_end;
645 key_end[1] = '\0';
646
647 // not the key we're looking for
648 if (strcmp(key, line) != 0) continue;
649
650 // skip whitespace after the '=' to the start of the value
651 char* val_start = equal+1;
652 while(*val_start && isspace(*val_start)) ++val_start;
653
654 // trim trailing whitespace
655 char* val_end = val_start + strlen(val_start)-1;
656 while (val_end > val_start && isspace(*val_end)) --val_end;
657 val_end[1] = '\0';
658
659 result = strdup(val_start);
660 break;
661
662 } while ((line = strtok(NULL, "\n")));
663
664 if (result == NULL) result = strdup("");
665
666 done:
667 free(filename);
668 free(key);
669 free(buffer);
Doug Zongker512536a2010-02-17 16:11:44 -0800670 return StringValue(result);
Doug Zongker47cace92009-06-18 10:11:50 -0700671}
672
673
Doug Zongker8edb00c2009-06-11 17:21:44 -0700674static bool write_raw_image_cb(const unsigned char* data,
675 int data_len, void* ctx) {
676 int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
677 if (r == data_len) return true;
678 fprintf(stderr, "%s\n", strerror(errno));
679 return false;
680}
681
682// write_raw_image(file, partition)
Doug Zongker512536a2010-02-17 16:11:44 -0800683Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700684 char* result = NULL;
685
686 char* partition;
687 char* filename;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700688 if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700689 return NULL;
690 }
691
692 if (strlen(partition) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700693 ErrorAbort(state, "partition argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700694 goto done;
695 }
696 if (strlen(filename) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700697 ErrorAbort(state, "file argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700698 goto done;
699 }
700
Koushik Dutta1b867542010-11-10 23:52:09 -0800701 if (0 == restore_raw_partition(partition, filename))
702 result = strdup(partition);
703 else
Koushik Dutta7c1bffe2010-12-18 19:44:33 -0800704 result = strdup("");
Doug Zongker8edb00c2009-06-11 17:21:44 -0700705
706done:
707 if (result != partition) free(partition);
708 free(filename);
Doug Zongker512536a2010-02-17 16:11:44 -0800709 return StringValue(result);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700710}
711
Doug Zongker8edb00c2009-06-11 17:21:44 -0700712// apply_patch_space(bytes)
Doug Zongkerc4351c72010-02-22 14:46:32 -0800713Value* ApplyPatchSpaceFn(const char* name, State* state,
714 int argc, Expr* argv[]) {
715 char* bytes_str;
716 if (ReadArgs(state, argv, 1, &bytes_str) < 0) {
717 return NULL;
718 }
719
720 char* endptr;
721 size_t bytes = strtol(bytes_str, &endptr, 10);
722 if (bytes == 0 && endptr == bytes_str) {
723 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
724 name, bytes_str);
725 free(bytes_str);
726 return NULL;
727 }
728
729 return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
730}
731
732
733// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
Doug Zongker512536a2010-02-17 16:11:44 -0800734Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800735 if (argc < 6 || (argc % 2) == 1) {
736 return ErrorAbort(state, "%s(): expected at least 6 args and an "
737 "even number, got %d",
738 name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700739 }
740
Doug Zongkerc4351c72010-02-22 14:46:32 -0800741 char* source_filename;
742 char* target_filename;
743 char* target_sha1;
744 char* target_size_str;
745 if (ReadArgs(state, argv, 4, &source_filename, &target_filename,
746 &target_sha1, &target_size_str) < 0) {
747 return NULL;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700748 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700749
Doug Zongkerc4351c72010-02-22 14:46:32 -0800750 char* endptr;
751 size_t target_size = strtol(target_size_str, &endptr, 10);
752 if (target_size == 0 && endptr == target_size_str) {
753 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count",
754 name, target_size_str);
755 free(source_filename);
756 free(target_filename);
757 free(target_sha1);
758 free(target_size_str);
759 return NULL;
760 }
761
762 int patchcount = (argc-4) / 2;
763 Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700764
765 int i;
Doug Zongkerc4351c72010-02-22 14:46:32 -0800766 for (i = 0; i < patchcount; ++i) {
767 if (patches[i*2]->type != VAL_STRING) {
768 ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
769 break;
770 }
771 if (patches[i*2+1]->type != VAL_BLOB) {
772 ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
773 break;
774 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700775 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800776 if (i != patchcount) {
777 for (i = 0; i < patchcount*2; ++i) {
778 FreeValue(patches[i]);
779 }
780 free(patches);
781 return NULL;
782 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700783
Doug Zongkerc4351c72010-02-22 14:46:32 -0800784 char** patch_sha_str = malloc(patchcount * sizeof(char*));
785 for (i = 0; i < patchcount; ++i) {
786 patch_sha_str[i] = patches[i*2]->data;
787 patches[i*2]->data = NULL;
788 FreeValue(patches[i*2]);
789 patches[i] = patches[i*2+1];
Doug Zongker8edb00c2009-06-11 17:21:44 -0700790 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800791
792 int result = applypatch(source_filename, target_filename,
793 target_sha1, target_size,
794 patchcount, patch_sha_str, patches);
795
796 for (i = 0; i < patchcount; ++i) {
797 FreeValue(patches[i]);
798 }
799 free(patch_sha_str);
800 free(patches);
801
802 return StringValue(strdup(result == 0 ? "t" : ""));
803}
804
805// apply_patch_check(file, [sha1_1, ...])
806Value* ApplyPatchCheckFn(const char* name, State* state,
807 int argc, Expr* argv[]) {
808 if (argc < 1) {
809 return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
810 name, argc);
811 }
812
813 char* filename;
814 if (ReadArgs(state, argv, 1, &filename) < 0) {
815 return NULL;
816 }
817
818 int patchcount = argc-1;
819 char** sha1s = ReadVarArgs(state, argc-1, argv+1);
820
821 int result = applypatch_check(filename, patchcount, sha1s);
822
823 int i;
824 for (i = 0; i < patchcount; ++i) {
825 free(sha1s[i]);
826 }
827 free(sha1s);
828
829 return StringValue(strdup(result == 0 ? "t" : ""));
Doug Zongker8edb00c2009-06-11 17:21:44 -0700830}
831
Doug Zongker512536a2010-02-17 16:11:44 -0800832Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700833 char** args = ReadVarArgs(state, argc, argv);
834 if (args == NULL) {
835 return NULL;
836 }
837
838 int size = 0;
839 int i;
840 for (i = 0; i < argc; ++i) {
841 size += strlen(args[i]);
842 }
843 char* buffer = malloc(size+1);
844 size = 0;
845 for (i = 0; i < argc; ++i) {
846 strcpy(buffer+size, args[i]);
847 size += strlen(args[i]);
848 free(args[i]);
849 }
850 free(args);
851 buffer[size] = '\0';
852
853 char* line = strtok(buffer, "\n");
854 while (line) {
855 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
856 "ui_print %s\n", line);
857 line = strtok(NULL, "\n");
858 }
859 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
860
Doug Zongker512536a2010-02-17 16:11:44 -0800861 return StringValue(buffer);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700862}
863
Doug Zongker512536a2010-02-17 16:11:44 -0800864Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkera3f89ea2009-09-10 14:10:48 -0700865 if (argc < 1) {
866 return ErrorAbort(state, "%s() expects at least 1 arg", name);
867 }
868 char** args = ReadVarArgs(state, argc, argv);
869 if (args == NULL) {
870 return NULL;
871 }
872
873 char** args2 = malloc(sizeof(char*) * (argc+1));
874 memcpy(args2, args, sizeof(char*) * argc);
875 args2[argc] = NULL;
876
877 fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc);
878
879 pid_t child = fork();
880 if (child == 0) {
881 execv(args2[0], args2);
882 fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno));
883 _exit(1);
884 }
885 int status;
886 waitpid(child, &status, 0);
887 if (WIFEXITED(status)) {
888 if (WEXITSTATUS(status) != 0) {
889 fprintf(stderr, "run_program: child exited with status %d\n",
890 WEXITSTATUS(status));
891 }
892 } else if (WIFSIGNALED(status)) {
893 fprintf(stderr, "run_program: child terminated by signal %d\n",
894 WTERMSIG(status));
895 }
896
897 int i;
898 for (i = 0; i < argc; ++i) {
899 free(args[i]);
900 }
901 free(args);
902 free(args2);
903
904 char buffer[20];
905 sprintf(buffer, "%d", status);
906
Doug Zongker512536a2010-02-17 16:11:44 -0800907 return StringValue(strdup(buffer));
Doug Zongkera3f89ea2009-09-10 14:10:48 -0700908}
909
Doug Zongker512536a2010-02-17 16:11:44 -0800910// Take a sha-1 digest and return it as a newly-allocated hex string.
911static char* PrintSha1(uint8_t* digest) {
912 char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
913 int i;
914 const char* alphabet = "0123456789abcdef";
915 for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
916 buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
917 buffer[i*2+1] = alphabet[digest[i] & 0xf];
918 }
919 buffer[i*2] = '\0';
920 return buffer;
921}
922
923// sha1_check(data)
924// to return the sha1 of the data (given in the format returned by
925// read_file).
926//
927// sha1_check(data, sha1_hex, [sha1_hex, ...])
928// returns the sha1 of the file if it matches any of the hex
929// strings passed, or "" if it does not equal any of them.
930//
931Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
932 if (argc < 1) {
933 return ErrorAbort(state, "%s() expects at least 1 arg", name);
934 }
935
936 Value** args = ReadValueVarArgs(state, argc, argv);
937 if (args == NULL) {
938 return NULL;
939 }
940
941 if (args[0]->size < 0) {
942 fprintf(stderr, "%s(): no file contents received", name);
943 return StringValue(strdup(""));
944 }
945 uint8_t digest[SHA_DIGEST_SIZE];
946 SHA(args[0]->data, args[0]->size, digest);
947 FreeValue(args[0]);
948
949 if (argc == 1) {
950 return StringValue(PrintSha1(digest));
951 }
952
953 int i;
954 uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE);
955 for (i = 1; i < argc; ++i) {
956 if (args[i]->type != VAL_STRING) {
957 fprintf(stderr, "%s(): arg %d is not a string; skipping",
958 name, i);
959 } else if (ParseSha1(args[i]->data, arg_digest) != 0) {
960 // Warn about bad args and skip them.
961 fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping",
962 name, args[i]->data);
963 } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
964 break;
965 }
966 FreeValue(args[i]);
967 }
968 if (i >= argc) {
969 // Didn't match any of the hex strings; return false.
970 return StringValue(strdup(""));
971 }
972 // Found a match; free all the remaining arguments and return the
973 // matched one.
974 int j;
975 for (j = i+1; j < argc; ++j) {
976 FreeValue(args[j]);
977 }
978 return args[i];
979}
980
981// Read a local file and return its contents (the char* returned
982// is actually a FileContents*).
983Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
984 if (argc != 1) {
985 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
986 }
987 char* filename;
988 if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
989
990 Value* v = malloc(sizeof(Value));
991 v->type = VAL_BLOB;
992
993 FileContents fc;
994 if (LoadFileContents(filename, &fc) != 0) {
995 ErrorAbort(state, "%s() loading \"%s\" failed: %s",
996 name, filename, strerror(errno));
997 free(filename);
998 free(v);
999 free(fc.data);
1000 return NULL;
1001 }
1002
1003 v->size = fc.size;
1004 v->data = (char*)fc.data;
1005
1006 free(filename);
1007 return v;
1008}
Doug Zongker8edb00c2009-06-11 17:21:44 -07001009
Doug Zongker9931f7f2009-06-10 14:11:53 -07001010void RegisterInstallFunctions() {
1011 RegisterFunction("mount", MountFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001012 RegisterFunction("is_mounted", IsMountedFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001013 RegisterFunction("unmount", UnmountFn);
1014 RegisterFunction("format", FormatFn);
1015 RegisterFunction("show_progress", ShowProgressFn);
Doug Zongkerfbf3c102009-06-24 09:36:20 -07001016 RegisterFunction("set_progress", SetProgressFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001017 RegisterFunction("delete", DeleteFn);
1018 RegisterFunction("delete_recursive", DeleteFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001019 RegisterFunction("package_extract_dir", PackageExtractDirFn);
1020 RegisterFunction("package_extract_file", PackageExtractFileFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001021 RegisterFunction("symlink", SymlinkFn);
1022 RegisterFunction("set_perm", SetPermFn);
1023 RegisterFunction("set_perm_recursive", SetPermFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001024
1025 RegisterFunction("getprop", GetPropFn);
Doug Zongker47cace92009-06-18 10:11:50 -07001026 RegisterFunction("file_getprop", FileGetPropFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001027 RegisterFunction("write_raw_image", WriteRawImageFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001028
1029 RegisterFunction("apply_patch", ApplyPatchFn);
Doug Zongkerc4351c72010-02-22 14:46:32 -08001030 RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
1031 RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
Doug Zongkerd9c9d102009-06-12 12:24:39 -07001032
Doug Zongker512536a2010-02-17 16:11:44 -08001033 RegisterFunction("read_file", ReadFileFn);
1034 RegisterFunction("sha1_check", Sha1CheckFn);
1035
Doug Zongkerd9c9d102009-06-12 12:24:39 -07001036 RegisterFunction("ui_print", UIPrintFn);
Doug Zongkera3f89ea2009-09-10 14:10:48 -07001037
1038 RegisterFunction("run_program", RunProgramFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001039}