blob: 000b5250ac70fcff73e5ffdcd975044fefc21c07 [file] [log] [blame]
Doug Zongker9931f7f2009-06-10 14:11:53 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
Shashank Mittal815ca5d2010-07-27 11:09:19 -07003 * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
Doug Zongker9931f7f2009-06-10 14:11:53 -07004 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Doug Zongkerfbf3c102009-06-24 09:36:20 -070018#include <ctype.h>
Doug Zongker9931f7f2009-06-10 14:11:53 -070019#include <errno.h>
20#include <stdarg.h>
Doug Zongkerfbf3c102009-06-24 09:36:20 -070021#include <stdio.h>
Doug Zongker9931f7f2009-06-10 14:11:53 -070022#include <stdlib.h>
23#include <string.h>
24#include <sys/mount.h>
25#include <sys/stat.h>
26#include <sys/types.h>
Doug Zongkera3f89ea2009-09-10 14:10:48 -070027#include <sys/wait.h>
Doug Zongker9931f7f2009-06-10 14:11:53 -070028#include <unistd.h>
29
Doug Zongker8edb00c2009-06-11 17:21:44 -070030#include "cutils/misc.h"
31#include "cutils/properties.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070032#include "edify/expr.h"
Doug Zongker512536a2010-02-17 16:11:44 -080033#include "mincrypt/sha.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070034#include "minzip/DirUtil.h"
35#include "mtdutils/mounts.h"
36#include "mtdutils/mtdutils.h"
Shashank Mittal815ca5d2010-07-27 11:09:19 -070037#include "mmcutils/mmcutils.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070038#include "updater.h"
Doug Zongker512536a2010-02-17 16:11:44 -080039#include "applypatch/applypatch.h"
Doug Zongker8edb00c2009-06-11 17:21:44 -070040
Doug Zongker9931f7f2009-06-10 14:11:53 -070041// mount(type, location, mount_point)
42//
43// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem
44// type="vfat" location="/dev/block/<whatever>" to mount a device
Doug Zongker512536a2010-02-17 16:11:44 -080045Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070046 char* result = NULL;
47 if (argc != 3) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070048 return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -070049 }
50 char* type;
51 char* location;
52 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -070053 if (ReadArgs(state, argv, 3, &type, &location, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070054 return NULL;
55 }
56
57 if (strlen(type) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070058 ErrorAbort(state, "type argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070059 goto done;
60 }
61 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070062 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070063 goto done;
64 }
65 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070066 ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070067 goto done;
68 }
69
70 mkdir(mount_point, 0755);
71
72 if (strcmp(type, "MTD") == 0) {
73 mtd_scan_partitions();
74 const MtdPartition* mtd;
75 mtd = mtd_find_partition_by_name(location);
76 if (mtd == NULL) {
77 fprintf(stderr, "%s: no mtd partition named \"%s\"",
78 name, location);
79 result = strdup("");
80 goto done;
81 }
82 if (mtd_mount_partition(mtd, mount_point, "yaffs2", 0 /* rw */) != 0) {
83 fprintf(stderr, "mtd mount of %s failed: %s\n",
84 location, strerror(errno));
85 result = strdup("");
86 goto done;
87 }
88 result = mount_point;
Shashank Mittal815ca5d2010-07-27 11:09:19 -070089 } else if (strcmp(type, "MMC") == 0) {
90 mmc_scan_partitions();
91 const MmcPartition* mmc;
92 mmc = mmc_find_partition_by_name(location);
93 if (mmc == NULL) {
94 fprintf(stderr, "%s: no mmc partition named \"%s\"",
95 name, location);
96 result = strdup("");
97 goto done;
98 }
99 if (mmc_mount_partition(mmc, mount_point, 0 /* rw */) != 0) {
100 fprintf(stderr, "mmc mount of %s failed: %s\n",
101 location, strerror(errno));
102 result = strdup("");
103 goto done;
104 }
105 result = mount_point;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700106 } else {
107 if (mount(location, mount_point, type,
108 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
Doug Zongker60babf82009-09-18 15:11:24 -0700109 fprintf(stderr, "%s: failed to mount %s at %s: %s\n",
110 name, location, mount_point, strerror(errno));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700111 result = strdup("");
112 } else {
113 result = mount_point;
114 }
115 }
116
117done:
118 free(type);
119 free(location);
120 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800121 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700122}
123
Doug Zongker8edb00c2009-06-11 17:21:44 -0700124
125// is_mounted(mount_point)
Doug Zongker512536a2010-02-17 16:11:44 -0800126Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700127 char* result = NULL;
128 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700129 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700130 }
131 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700132 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700133 return NULL;
134 }
135 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700136 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker8edb00c2009-06-11 17:21:44 -0700137 goto done;
138 }
139
140 scan_mounted_volumes();
141 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
142 if (vol == NULL) {
143 result = strdup("");
144 } else {
145 result = mount_point;
146 }
147
148done:
149 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800150 return StringValue(result);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700151}
152
153
Doug Zongker512536a2010-02-17 16:11:44 -0800154Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700155 char* result = NULL;
156 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700157 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700158 }
159 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700160 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700161 return NULL;
162 }
163 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700164 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker9931f7f2009-06-10 14:11:53 -0700165 goto done;
166 }
167
168 scan_mounted_volumes();
169 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
170 if (vol == NULL) {
171 fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
172 result = strdup("");
173 } else {
174 unmount_mounted_volume(vol);
175 result = mount_point;
176 }
177
178done:
179 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800180 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700181}
Doug Zongker8edb00c2009-06-11 17:21:44 -0700182
183
Doug Zongker9931f7f2009-06-10 14:11:53 -0700184// format(type, location)
185//
186// type="MTD" location=partition
Doug Zongker512536a2010-02-17 16:11:44 -0800187Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700188 char* result = NULL;
189 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700190 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700191 }
192 char* type;
193 char* location;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700194 if (ReadArgs(state, argv, 2, &type, &location) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700195 return NULL;
196 }
197
198 if (strlen(type) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700199 ErrorAbort(state, "type argument to %s() can't be empty", 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
207 if (strcmp(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);
213 result = strdup("");
214 goto done;
215 }
216 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 }
Shashank Mittal815ca5d2010-07-27 11:09:19 -0700233 } else if (strcmp(type, "MMC") == 0) {
234 mmc_scan_partitions();
235 const MmcPartition* mmc = mmc_find_partition_by_name(location);
236 if (mmc == NULL) {
237 fprintf(stderr, "%s: no mmc partition named \"%s\"",
238 name, location);
239 result = strdup("");
240 goto done;
241 }
242 if (mmc_format_ext3(mmc))
243 {
244 result = strdup("");
245 goto done;
246 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700247 } else {
248 fprintf(stderr, "%s: unsupported type \"%s\"", name, type);
249 }
Shashank Mittal815ca5d2010-07-27 11:09:19 -0700250 result = location;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700251done:
252 free(type);
253 if (result != location) free(location);
Doug Zongker512536a2010-02-17 16:11:44 -0800254 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700255}
256
Doug Zongker8edb00c2009-06-11 17:21:44 -0700257
Doug Zongker512536a2010-02-17 16:11:44 -0800258Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700259 char** paths = malloc(argc * sizeof(char*));
260 int i;
261 for (i = 0; i < argc; ++i) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700262 paths[i] = Evaluate(state, argv[i]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700263 if (paths[i] == NULL) {
264 int j;
265 for (j = 0; j < i; ++i) {
266 free(paths[j]);
267 }
268 free(paths);
269 return NULL;
270 }
271 }
272
273 bool recursive = (strcmp(name, "delete_recursive") == 0);
274
275 int success = 0;
276 for (i = 0; i < argc; ++i) {
277 if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
278 ++success;
279 free(paths[i]);
280 }
281 free(paths);
282
283 char buffer[10];
284 sprintf(buffer, "%d", success);
Doug Zongker512536a2010-02-17 16:11:44 -0800285 return StringValue(strdup(buffer));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700286}
287
Doug Zongker8edb00c2009-06-11 17:21:44 -0700288
Doug Zongker512536a2010-02-17 16:11:44 -0800289Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700290 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700291 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700292 }
293 char* frac_str;
294 char* sec_str;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700295 if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700296 return NULL;
297 }
298
299 double frac = strtod(frac_str, NULL);
300 int sec = strtol(sec_str, NULL, 10);
301
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700302 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700303 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
304
Doug Zongker9931f7f2009-06-10 14:11:53 -0700305 free(sec_str);
Doug Zongker512536a2010-02-17 16:11:44 -0800306 return StringValue(frac_str);
Doug Zongkerfbf3c102009-06-24 09:36:20 -0700307}
308
Doug Zongker512536a2010-02-17 16:11:44 -0800309Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerfbf3c102009-06-24 09:36:20 -0700310 if (argc != 1) {
311 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
312 }
313 char* frac_str;
314 if (ReadArgs(state, argv, 1, &frac_str) < 0) {
315 return NULL;
316 }
317
318 double frac = strtod(frac_str, NULL);
319
320 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
321 fprintf(ui->cmd_pipe, "set_progress %f\n", frac);
322
Doug Zongker512536a2010-02-17 16:11:44 -0800323 return StringValue(frac_str);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700324}
325
Doug Zongker8edb00c2009-06-11 17:21:44 -0700326// package_extract_dir(package_path, destination_path)
Doug Zongker512536a2010-02-17 16:11:44 -0800327Value* PackageExtractDirFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700328 int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700329 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700330 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700331 }
332 char* zip_path;
333 char* dest_path;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700334 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700335
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700336 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700337
338 // To create a consistent system image, never use the clock for timestamps.
339 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
340
341 bool success = mzExtractRecursive(za, zip_path, dest_path,
342 MZ_EXTRACT_FILES_ONLY, &timestamp,
343 NULL, NULL);
344 free(zip_path);
345 free(dest_path);
Doug Zongker512536a2010-02-17 16:11:44 -0800346 return StringValue(strdup(success ? "t" : ""));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700347}
348
Doug Zongker8edb00c2009-06-11 17:21:44 -0700349
350// package_extract_file(package_path, destination_path)
Doug Zongker6aece332010-02-01 14:40:12 -0800351// or
352// package_extract_file(package_path)
353// to return the entire contents of the file as the result of this
Doug Zongker512536a2010-02-17 16:11:44 -0800354// function (the char* returned is actually a FileContents*).
355Value* PackageExtractFileFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700356 int argc, Expr* argv[]) {
Doug Zongker6aece332010-02-01 14:40:12 -0800357 if (argc != 1 && argc != 2) {
358 return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
359 name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700360 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700361 bool success = false;
Doug Zongker6aece332010-02-01 14:40:12 -0800362 if (argc == 2) {
363 // The two-argument version extracts to a file.
Doug Zongker8edb00c2009-06-11 17:21:44 -0700364
Doug Zongker6aece332010-02-01 14:40:12 -0800365 char* zip_path;
366 char* dest_path;
367 if (ReadArgs(state, argv, 2, &zip_path, &dest_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 done2;
374 }
375
376 FILE* f = fopen(dest_path, "wb");
377 if (f == NULL) {
378 fprintf(stderr, "%s: can't open %s for write: %s\n",
379 name, dest_path, strerror(errno));
380 goto done2;
381 }
382 success = mzExtractZipEntryToFile(za, entry, fileno(f));
383 fclose(f);
384
385 done2:
386 free(zip_path);
387 free(dest_path);
Doug Zongker512536a2010-02-17 16:11:44 -0800388 return StringValue(strdup(success ? "t" : ""));
Doug Zongker6aece332010-02-01 14:40:12 -0800389 } else {
390 // The one-argument version returns the contents of the file
391 // as the result.
392
393 char* zip_path;
Doug Zongker512536a2010-02-17 16:11:44 -0800394 Value* v = malloc(sizeof(Value));
395 v->type = VAL_BLOB;
396 v->size = -1;
397 v->data = NULL;
Doug Zongker6aece332010-02-01 14:40:12 -0800398
399 if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
400
401 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
402 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
403 if (entry == NULL) {
404 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
405 goto done1;
406 }
407
Doug Zongker512536a2010-02-17 16:11:44 -0800408 v->size = mzGetZipEntryUncompLen(entry);
409 v->data = malloc(v->size);
410 if (v->data == NULL) {
Doug Zongker6aece332010-02-01 14:40:12 -0800411 fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n",
Doug Zongker512536a2010-02-17 16:11:44 -0800412 name, (long)v->size, zip_path);
Doug Zongker6aece332010-02-01 14:40:12 -0800413 goto done1;
414 }
415
Doug Zongker512536a2010-02-17 16:11:44 -0800416 success = mzExtractZipEntryToBuffer(za, entry,
417 (unsigned char *)v->data);
Doug Zongker6aece332010-02-01 14:40:12 -0800418
419 done1:
420 free(zip_path);
421 if (!success) {
Doug Zongker512536a2010-02-17 16:11:44 -0800422 free(v->data);
423 v->data = NULL;
424 v->size = -1;
Doug Zongker6aece332010-02-01 14:40:12 -0800425 }
Doug Zongker512536a2010-02-17 16:11:44 -0800426 return v;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700427 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700428}
429
430
Doug Zongker9931f7f2009-06-10 14:11:53 -0700431// symlink target src1 src2 ...
Doug Zongker60babf82009-09-18 15:11:24 -0700432// unlinks any previously existing src1, src2, etc before creating symlinks.
Doug Zongker512536a2010-02-17 16:11:44 -0800433Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700434 if (argc == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700435 return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700436 }
437 char* target;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700438 target = Evaluate(state, argv[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700439 if (target == NULL) return NULL;
440
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700441 char** srcs = ReadVarArgs(state, argc-1, argv+1);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700442 if (srcs == NULL) {
443 free(target);
444 return NULL;
445 }
446
447 int i;
448 for (i = 0; i < argc-1; ++i) {
Doug Zongker60babf82009-09-18 15:11:24 -0700449 if (unlink(srcs[i]) < 0) {
450 if (errno != ENOENT) {
451 fprintf(stderr, "%s: failed to remove %s: %s\n",
452 name, srcs[i], strerror(errno));
453 }
454 }
455 if (symlink(target, srcs[i]) < 0) {
456 fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
457 name, srcs[i], target, strerror(errno));
458 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700459 free(srcs[i]);
460 }
461 free(srcs);
Doug Zongker512536a2010-02-17 16:11:44 -0800462 return StringValue(strdup(""));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700463}
464
Doug Zongker8edb00c2009-06-11 17:21:44 -0700465
Doug Zongker512536a2010-02-17 16:11:44 -0800466Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700467 char* result = NULL;
468 bool recursive = (strcmp(name, "set_perm_recursive") == 0);
469
470 int min_args = 4 + (recursive ? 1 : 0);
471 if (argc < min_args) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700472 return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700473 }
474
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700475 char** args = ReadVarArgs(state, argc, argv);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700476 if (args == NULL) return NULL;
477
478 char* end;
479 int i;
480
481 int uid = strtoul(args[0], &end, 0);
482 if (*end != '\0' || args[0][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700483 ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700484 goto done;
485 }
486
487 int gid = strtoul(args[1], &end, 0);
488 if (*end != '\0' || args[1][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700489 ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700490 goto done;
491 }
492
493 if (recursive) {
494 int dir_mode = strtoul(args[2], &end, 0);
495 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700496 ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700497 goto done;
498 }
499
500 int file_mode = strtoul(args[3], &end, 0);
501 if (*end != '\0' || args[3][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700502 ErrorAbort(state, "%s: \"%s\" not a valid filemode",
Doug Zongker9931f7f2009-06-10 14:11:53 -0700503 name, args[3]);
504 goto done;
505 }
506
507 for (i = 4; i < argc; ++i) {
508 dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
509 }
510 } else {
511 int mode = strtoul(args[2], &end, 0);
512 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700513 ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700514 goto done;
515 }
516
Doug Zongker0bbfe3d2009-06-25 13:37:31 -0700517 for (i = 3; i < argc; ++i) {
Doug Zongker60babf82009-09-18 15:11:24 -0700518 if (chown(args[i], uid, gid) < 0) {
519 fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n",
520 name, args[i], uid, gid, strerror(errno));
521 }
522 if (chmod(args[i], mode) < 0) {
523 fprintf(stderr, "%s: chmod of %s to %o failed: %s\n",
524 name, args[i], mode, strerror(errno));
525 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700526 }
527 }
528 result = strdup("");
529
530done:
531 for (i = 0; i < argc; ++i) {
532 free(args[i]);
533 }
534 free(args);
535
Doug Zongker512536a2010-02-17 16:11:44 -0800536 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700537}
538
Doug Zongker8edb00c2009-06-11 17:21:44 -0700539
Doug Zongker512536a2010-02-17 16:11:44 -0800540Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700541 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700542 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700543 }
544 char* key;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700545 key = Evaluate(state, argv[0]);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700546 if (key == NULL) return NULL;
547
548 char value[PROPERTY_VALUE_MAX];
549 property_get(key, value, "");
550 free(key);
551
Doug Zongker512536a2010-02-17 16:11:44 -0800552 return StringValue(strdup(value));
Doug Zongker8edb00c2009-06-11 17:21:44 -0700553}
554
555
Doug Zongker47cace92009-06-18 10:11:50 -0700556// file_getprop(file, key)
557//
558// interprets 'file' as a getprop-style file (key=value pairs, one
559// per line, # comment lines and blank lines okay), and returns the value
560// for 'key' (or "" if it isn't defined).
Doug Zongker512536a2010-02-17 16:11:44 -0800561Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker47cace92009-06-18 10:11:50 -0700562 char* result = NULL;
563 char* buffer = NULL;
564 char* filename;
565 char* key;
566 if (ReadArgs(state, argv, 2, &filename, &key) < 0) {
567 return NULL;
568 }
569
570 struct stat st;
571 if (stat(filename, &st) < 0) {
572 ErrorAbort(state, "%s: failed to stat \"%s\": %s",
573 name, filename, strerror(errno));
574 goto done;
575 }
576
577#define MAX_FILE_GETPROP_SIZE 65536
578
579 if (st.st_size > MAX_FILE_GETPROP_SIZE) {
580 ErrorAbort(state, "%s too large for %s (max %d)",
581 filename, name, MAX_FILE_GETPROP_SIZE);
582 goto done;
583 }
584
585 buffer = malloc(st.st_size+1);
586 if (buffer == NULL) {
587 ErrorAbort(state, "%s: failed to alloc %d bytes", name, st.st_size+1);
588 goto done;
589 }
590
591 FILE* f = fopen(filename, "rb");
592 if (f == NULL) {
593 ErrorAbort(state, "%s: failed to open %s: %s",
594 name, filename, strerror(errno));
595 goto done;
596 }
597
598 if (fread(buffer, 1, st.st_size, f) != st.st_size) {
599 ErrorAbort(state, "%s: failed to read %d bytes from %s",
600 name, st.st_size+1, filename);
601 fclose(f);
602 goto done;
603 }
604 buffer[st.st_size] = '\0';
605
606 fclose(f);
607
608 char* line = strtok(buffer, "\n");
609 do {
610 // skip whitespace at start of line
611 while (*line && isspace(*line)) ++line;
612
613 // comment or blank line: skip to next line
614 if (*line == '\0' || *line == '#') continue;
615
616 char* equal = strchr(line, '=');
617 if (equal == NULL) {
618 ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
619 name, line, filename);
620 goto done;
621 }
622
623 // trim whitespace between key and '='
624 char* key_end = equal-1;
625 while (key_end > line && isspace(*key_end)) --key_end;
626 key_end[1] = '\0';
627
628 // not the key we're looking for
629 if (strcmp(key, line) != 0) continue;
630
631 // skip whitespace after the '=' to the start of the value
632 char* val_start = equal+1;
633 while(*val_start && isspace(*val_start)) ++val_start;
634
635 // trim trailing whitespace
636 char* val_end = val_start + strlen(val_start)-1;
637 while (val_end > val_start && isspace(*val_end)) --val_end;
638 val_end[1] = '\0';
639
640 result = strdup(val_start);
641 break;
642
643 } while ((line = strtok(NULL, "\n")));
644
645 if (result == NULL) result = strdup("");
646
647 done:
648 free(filename);
649 free(key);
650 free(buffer);
Doug Zongker512536a2010-02-17 16:11:44 -0800651 return StringValue(result);
Doug Zongker47cace92009-06-18 10:11:50 -0700652}
653
654
Doug Zongker8edb00c2009-06-11 17:21:44 -0700655static bool write_raw_image_cb(const unsigned char* data,
656 int data_len, void* ctx) {
657 int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
658 if (r == data_len) return true;
659 fprintf(stderr, "%s\n", strerror(errno));
660 return false;
661}
662
Koushik Duttae5678e92010-09-13 13:25:11 -0700663int write_raw_image(const char* partition, const char* filename);
664
Doug Zongker8edb00c2009-06-11 17:21:44 -0700665// write_raw_image(file, partition)
Doug Zongker512536a2010-02-17 16:11:44 -0800666Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700667 char* result = NULL;
668
669 char* partition;
670 char* filename;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700671 if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700672 return NULL;
673 }
674
675 if (strlen(partition) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700676 ErrorAbort(state, "partition argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700677 goto done;
678 }
679 if (strlen(filename) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700680 ErrorAbort(state, "file argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700681 goto done;
682 }
683
Koushik Duttab5a36a02010-09-13 14:33:15 -0700684#ifdef BOARD_USES_BMLUTILS
Koushik Duttae5678e92010-09-13 13:25:11 -0700685 if (0 == write_raw_image(name, filename)) {
686 result = partition;
687 }
688 result = strdup("Failure");
689#else
Doug Zongker8edb00c2009-06-11 17:21:44 -0700690 mtd_scan_partitions();
691 const MtdPartition* mtd = mtd_find_partition_by_name(partition);
692 if (mtd == NULL) {
693 fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition);
694 result = strdup("");
Shashank Mittal815ca5d2010-07-27 11:09:19 -0700695 goto MMC;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700696 }
697
698 MtdWriteContext* ctx = mtd_write_partition(mtd);
699 if (ctx == NULL) {
700 fprintf(stderr, "%s: can't write mtd partition \"%s\"\n",
701 name, partition);
702 result = strdup("");
703 goto done;
704 }
705
706 bool success;
707
708 FILE* f = fopen(filename, "rb");
709 if (f == NULL) {
710 fprintf(stderr, "%s: can't open %s: %s\n",
711 name, filename, strerror(errno));
712 result = strdup("");
713 goto done;
714 }
715
716 success = true;
717 char* buffer = malloc(BUFSIZ);
718 int read;
719 while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
720 int wrote = mtd_write_data(ctx, buffer, read);
721 success = success && (wrote == read);
722 if (!success) {
723 fprintf(stderr, "mtd_write_data to %s failed: %s\n",
724 partition, strerror(errno));
725 }
726 }
727 free(buffer);
728 fclose(f);
729
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700730 if (mtd_erase_blocks(ctx, -1) == -1) {
731 fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition);
732 }
733 if (mtd_write_close(ctx) != 0) {
734 fprintf(stderr, "%s: error closing write of %s\n", name, partition);
735 }
736
Doug Zongker8edb00c2009-06-11 17:21:44 -0700737 printf("%s %s partition from %s\n",
738 success ? "wrote" : "failed to write", partition, filename);
739
740 result = success ? partition : strdup("");
Shashank Mittal815ca5d2010-07-27 11:09:19 -0700741 goto done;
742
743MMC:
744 mmc_scan_partitions();
745 const MmcPartition* mmc = mmc_find_partition_by_name(partition);
746 if (mmc == NULL) {
747 fprintf(stderr, "%s: no mmc partition named \"%s\"\n", name, partition);
748 result = strdup("");
749 goto done;
750 }
751 if (mmc_raw_copy(mmc, filename)) {
752 fprintf(stderr, "%s: error erasing mmc partition named \"%s\"\n", name, partition);
753 result = strdup("");
754 goto done;
755 }
756 result = partition;
Koushik Duttae5678e92010-09-13 13:25:11 -0700757#endif
Doug Zongker8edb00c2009-06-11 17:21:44 -0700758
759done:
760 if (result != partition) free(partition);
761 free(filename);
Doug Zongker512536a2010-02-17 16:11:44 -0800762 return StringValue(result);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700763}
764
Doug Zongker8edb00c2009-06-11 17:21:44 -0700765// apply_patch_space(bytes)
Doug Zongkerc4351c72010-02-22 14:46:32 -0800766Value* ApplyPatchSpaceFn(const char* name, State* state,
767 int argc, Expr* argv[]) {
768 char* bytes_str;
769 if (ReadArgs(state, argv, 1, &bytes_str) < 0) {
770 return NULL;
771 }
772
773 char* endptr;
774 size_t bytes = strtol(bytes_str, &endptr, 10);
775 if (bytes == 0 && endptr == bytes_str) {
776 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
777 name, bytes_str);
778 free(bytes_str);
779 return NULL;
780 }
781
782 return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
783}
784
785
786// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
Doug Zongker512536a2010-02-17 16:11:44 -0800787Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800788 if (argc < 6 || (argc % 2) == 1) {
789 return ErrorAbort(state, "%s(): expected at least 6 args and an "
790 "even number, got %d",
791 name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700792 }
793
Doug Zongkerc4351c72010-02-22 14:46:32 -0800794 char* source_filename;
795 char* target_filename;
796 char* target_sha1;
797 char* target_size_str;
798 if (ReadArgs(state, argv, 4, &source_filename, &target_filename,
799 &target_sha1, &target_size_str) < 0) {
800 return NULL;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700801 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700802
Doug Zongkerc4351c72010-02-22 14:46:32 -0800803 char* endptr;
804 size_t target_size = strtol(target_size_str, &endptr, 10);
805 if (target_size == 0 && endptr == target_size_str) {
806 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count",
807 name, target_size_str);
808 free(source_filename);
809 free(target_filename);
810 free(target_sha1);
811 free(target_size_str);
812 return NULL;
813 }
814
815 int patchcount = (argc-4) / 2;
816 Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700817
818 int i;
Doug Zongkerc4351c72010-02-22 14:46:32 -0800819 for (i = 0; i < patchcount; ++i) {
820 if (patches[i*2]->type != VAL_STRING) {
821 ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
822 break;
823 }
824 if (patches[i*2+1]->type != VAL_BLOB) {
825 ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
826 break;
827 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700828 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800829 if (i != patchcount) {
830 for (i = 0; i < patchcount*2; ++i) {
831 FreeValue(patches[i]);
832 }
833 free(patches);
834 return NULL;
835 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700836
Doug Zongkerc4351c72010-02-22 14:46:32 -0800837 char** patch_sha_str = malloc(patchcount * sizeof(char*));
838 for (i = 0; i < patchcount; ++i) {
839 patch_sha_str[i] = patches[i*2]->data;
840 patches[i*2]->data = NULL;
841 FreeValue(patches[i*2]);
842 patches[i] = patches[i*2+1];
Doug Zongker8edb00c2009-06-11 17:21:44 -0700843 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800844
845 int result = applypatch(source_filename, target_filename,
846 target_sha1, target_size,
847 patchcount, patch_sha_str, patches);
848
849 for (i = 0; i < patchcount; ++i) {
850 FreeValue(patches[i]);
851 }
852 free(patch_sha_str);
853 free(patches);
854
855 return StringValue(strdup(result == 0 ? "t" : ""));
856}
857
858// apply_patch_check(file, [sha1_1, ...])
859Value* ApplyPatchCheckFn(const char* name, State* state,
860 int argc, Expr* argv[]) {
861 if (argc < 1) {
862 return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
863 name, argc);
864 }
865
866 char* filename;
867 if (ReadArgs(state, argv, 1, &filename) < 0) {
868 return NULL;
869 }
870
871 int patchcount = argc-1;
872 char** sha1s = ReadVarArgs(state, argc-1, argv+1);
873
874 int result = applypatch_check(filename, patchcount, sha1s);
875
876 int i;
877 for (i = 0; i < patchcount; ++i) {
878 free(sha1s[i]);
879 }
880 free(sha1s);
881
882 return StringValue(strdup(result == 0 ? "t" : ""));
Doug Zongker8edb00c2009-06-11 17:21:44 -0700883}
884
Doug Zongker512536a2010-02-17 16:11:44 -0800885Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700886 char** args = ReadVarArgs(state, argc, argv);
887 if (args == NULL) {
888 return NULL;
889 }
890
891 int size = 0;
892 int i;
893 for (i = 0; i < argc; ++i) {
894 size += strlen(args[i]);
895 }
896 char* buffer = malloc(size+1);
897 size = 0;
898 for (i = 0; i < argc; ++i) {
899 strcpy(buffer+size, args[i]);
900 size += strlen(args[i]);
901 free(args[i]);
902 }
903 free(args);
904 buffer[size] = '\0';
905
906 char* line = strtok(buffer, "\n");
907 while (line) {
908 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
909 "ui_print %s\n", line);
910 line = strtok(NULL, "\n");
911 }
912 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
913
Doug Zongker512536a2010-02-17 16:11:44 -0800914 return StringValue(buffer);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700915}
916
Doug Zongker512536a2010-02-17 16:11:44 -0800917Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkera3f89ea2009-09-10 14:10:48 -0700918 if (argc < 1) {
919 return ErrorAbort(state, "%s() expects at least 1 arg", name);
920 }
921 char** args = ReadVarArgs(state, argc, argv);
922 if (args == NULL) {
923 return NULL;
924 }
925
926 char** args2 = malloc(sizeof(char*) * (argc+1));
927 memcpy(args2, args, sizeof(char*) * argc);
928 args2[argc] = NULL;
929
930 fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc);
931
932 pid_t child = fork();
933 if (child == 0) {
934 execv(args2[0], args2);
935 fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno));
936 _exit(1);
937 }
938 int status;
939 waitpid(child, &status, 0);
940 if (WIFEXITED(status)) {
941 if (WEXITSTATUS(status) != 0) {
942 fprintf(stderr, "run_program: child exited with status %d\n",
943 WEXITSTATUS(status));
944 }
945 } else if (WIFSIGNALED(status)) {
946 fprintf(stderr, "run_program: child terminated by signal %d\n",
947 WTERMSIG(status));
948 }
949
950 int i;
951 for (i = 0; i < argc; ++i) {
952 free(args[i]);
953 }
954 free(args);
955 free(args2);
956
957 char buffer[20];
958 sprintf(buffer, "%d", status);
959
Doug Zongker512536a2010-02-17 16:11:44 -0800960 return StringValue(strdup(buffer));
Doug Zongkera3f89ea2009-09-10 14:10:48 -0700961}
962
Doug Zongker512536a2010-02-17 16:11:44 -0800963// Take a sha-1 digest and return it as a newly-allocated hex string.
964static char* PrintSha1(uint8_t* digest) {
965 char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
966 int i;
967 const char* alphabet = "0123456789abcdef";
968 for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
969 buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
970 buffer[i*2+1] = alphabet[digest[i] & 0xf];
971 }
972 buffer[i*2] = '\0';
973 return buffer;
974}
975
976// sha1_check(data)
977// to return the sha1 of the data (given in the format returned by
978// read_file).
979//
980// sha1_check(data, sha1_hex, [sha1_hex, ...])
981// returns the sha1 of the file if it matches any of the hex
982// strings passed, or "" if it does not equal any of them.
983//
984Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
985 if (argc < 1) {
986 return ErrorAbort(state, "%s() expects at least 1 arg", name);
987 }
988
989 Value** args = ReadValueVarArgs(state, argc, argv);
990 if (args == NULL) {
991 return NULL;
992 }
993
994 if (args[0]->size < 0) {
995 fprintf(stderr, "%s(): no file contents received", name);
996 return StringValue(strdup(""));
997 }
998 uint8_t digest[SHA_DIGEST_SIZE];
999 SHA(args[0]->data, args[0]->size, digest);
1000 FreeValue(args[0]);
1001
1002 if (argc == 1) {
1003 return StringValue(PrintSha1(digest));
1004 }
1005
1006 int i;
1007 uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE);
1008 for (i = 1; i < argc; ++i) {
1009 if (args[i]->type != VAL_STRING) {
1010 fprintf(stderr, "%s(): arg %d is not a string; skipping",
1011 name, i);
1012 } else if (ParseSha1(args[i]->data, arg_digest) != 0) {
1013 // Warn about bad args and skip them.
1014 fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping",
1015 name, args[i]->data);
1016 } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
1017 break;
1018 }
1019 FreeValue(args[i]);
1020 }
1021 if (i >= argc) {
1022 // Didn't match any of the hex strings; return false.
1023 return StringValue(strdup(""));
1024 }
1025 // Found a match; free all the remaining arguments and return the
1026 // matched one.
1027 int j;
1028 for (j = i+1; j < argc; ++j) {
1029 FreeValue(args[j]);
1030 }
1031 return args[i];
1032}
1033
1034// Read a local file and return its contents (the char* returned
1035// is actually a FileContents*).
1036Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
1037 if (argc != 1) {
1038 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
1039 }
1040 char* filename;
1041 if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
1042
1043 Value* v = malloc(sizeof(Value));
1044 v->type = VAL_BLOB;
1045
1046 FileContents fc;
1047 if (LoadFileContents(filename, &fc) != 0) {
1048 ErrorAbort(state, "%s() loading \"%s\" failed: %s",
1049 name, filename, strerror(errno));
1050 free(filename);
1051 free(v);
1052 free(fc.data);
1053 return NULL;
1054 }
1055
1056 v->size = fc.size;
1057 v->data = (char*)fc.data;
1058
1059 free(filename);
1060 return v;
1061}
Doug Zongker8edb00c2009-06-11 17:21:44 -07001062
Doug Zongker9931f7f2009-06-10 14:11:53 -07001063void RegisterInstallFunctions() {
1064 RegisterFunction("mount", MountFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001065 RegisterFunction("is_mounted", IsMountedFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001066 RegisterFunction("unmount", UnmountFn);
1067 RegisterFunction("format", FormatFn);
1068 RegisterFunction("show_progress", ShowProgressFn);
Doug Zongkerfbf3c102009-06-24 09:36:20 -07001069 RegisterFunction("set_progress", SetProgressFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001070 RegisterFunction("delete", DeleteFn);
1071 RegisterFunction("delete_recursive", DeleteFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001072 RegisterFunction("package_extract_dir", PackageExtractDirFn);
1073 RegisterFunction("package_extract_file", PackageExtractFileFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001074 RegisterFunction("symlink", SymlinkFn);
1075 RegisterFunction("set_perm", SetPermFn);
1076 RegisterFunction("set_perm_recursive", SetPermFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001077
1078 RegisterFunction("getprop", GetPropFn);
Doug Zongker47cace92009-06-18 10:11:50 -07001079 RegisterFunction("file_getprop", FileGetPropFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001080 RegisterFunction("write_raw_image", WriteRawImageFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001081
1082 RegisterFunction("apply_patch", ApplyPatchFn);
Doug Zongkerc4351c72010-02-22 14:46:32 -08001083 RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
1084 RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
Doug Zongkerd9c9d102009-06-12 12:24:39 -07001085
Doug Zongker512536a2010-02-17 16:11:44 -08001086 RegisterFunction("read_file", ReadFileFn);
1087 RegisterFunction("sha1_check", Sha1CheckFn);
1088
Doug Zongkerd9c9d102009-06-12 12:24:39 -07001089 RegisterFunction("ui_print", UIPrintFn);
Doug Zongkera3f89ea2009-09-10 14:10:48 -07001090
1091 RegisterFunction("run_program", RunProgramFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001092}