blob: 685b97906c8b35b29c28b7571984bcafc1ca3b91 [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>
Hristo Bojinovdb314d62010-08-02 10:29:49 -070028#include <fcntl.h>
29#include <time.h>
Doug Zongker9931f7f2009-06-10 14:11:53 -070030
Doug Zongker8edb00c2009-06-11 17:21:44 -070031#include "cutils/misc.h"
32#include "cutils/properties.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070033#include "edify/expr.h"
Doug Zongker512536a2010-02-17 16:11:44 -080034#include "mincrypt/sha.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070035#include "minzip/DirUtil.h"
Hristo Bojinovdb314d62010-08-02 10:29:49 -070036#include "minelf/Retouch.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070037#include "mtdutils/mounts.h"
38#include "mtdutils/mtdutils.h"
39#include "updater.h"
Doug Zongker512536a2010-02-17 16:11:44 -080040#include "applypatch/applypatch.h"
Doug Zongker8edb00c2009-06-11 17:21:44 -070041
Doug Zongker3d177d02010-07-01 09:18:44 -070042#ifdef USE_EXT4
43#include "make_ext4fs.h"
44#endif
45
46// mount(fs_type, partition_type, location, mount_point)
Doug Zongker9931f7f2009-06-10 14:11:53 -070047//
Doug Zongker3d177d02010-07-01 09:18:44 -070048// fs_type="yaffs2" partition_type="MTD" location=partition
49// fs_type="ext4" partition_type="EMMC" location=device
Doug Zongker512536a2010-02-17 16:11:44 -080050Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070051 char* result = NULL;
Doug Zongker3d177d02010-07-01 09:18:44 -070052 if (argc != 4) {
53 return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -070054 }
Doug Zongker3d177d02010-07-01 09:18:44 -070055 char* fs_type;
56 char* partition_type;
Doug Zongker9931f7f2009-06-10 14:11:53 -070057 char* location;
58 char* mount_point;
Doug Zongker3d177d02010-07-01 09:18:44 -070059 if (ReadArgs(state, argv, 4, &fs_type, &partition_type,
60 &location, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070061 return NULL;
62 }
63
Doug Zongker3d177d02010-07-01 09:18:44 -070064 if (strlen(fs_type) == 0) {
65 ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
66 goto done;
67 }
68 if (strlen(partition_type) == 0) {
69 ErrorAbort(state, "partition_type argument to %s() can't be empty",
70 name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070071 goto done;
72 }
73 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070074 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070075 goto done;
76 }
77 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070078 ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070079 goto done;
80 }
81
82 mkdir(mount_point, 0755);
83
Doug Zongker3d177d02010-07-01 09:18:44 -070084 if (strcmp(partition_type, "MTD") == 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070085 mtd_scan_partitions();
86 const MtdPartition* mtd;
87 mtd = mtd_find_partition_by_name(location);
88 if (mtd == NULL) {
89 fprintf(stderr, "%s: no mtd partition named \"%s\"",
90 name, location);
91 result = strdup("");
92 goto done;
93 }
Doug Zongker3d177d02010-07-01 09:18:44 -070094 if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070095 fprintf(stderr, "mtd mount of %s failed: %s\n",
96 location, strerror(errno));
97 result = strdup("");
98 goto done;
99 }
100 result = mount_point;
101 } else {
Doug Zongker3d177d02010-07-01 09:18:44 -0700102 if (mount(location, mount_point, fs_type,
Doug Zongker9931f7f2009-06-10 14:11:53 -0700103 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
Doug Zongker60babf82009-09-18 15:11:24 -0700104 fprintf(stderr, "%s: failed to mount %s at %s: %s\n",
105 name, location, mount_point, strerror(errno));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700106 result = strdup("");
107 } else {
108 result = mount_point;
109 }
110 }
111
112done:
Doug Zongker3d177d02010-07-01 09:18:44 -0700113 free(fs_type);
114 free(partition_type);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700115 free(location);
116 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800117 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700118}
119
Doug Zongker8edb00c2009-06-11 17:21:44 -0700120
121// is_mounted(mount_point)
Doug Zongker512536a2010-02-17 16:11:44 -0800122Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700123 char* result = NULL;
124 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700125 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700126 }
127 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700128 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700129 return NULL;
130 }
131 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700132 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker8edb00c2009-06-11 17:21:44 -0700133 goto done;
134 }
135
136 scan_mounted_volumes();
137 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
138 if (vol == NULL) {
139 result = strdup("");
140 } else {
141 result = mount_point;
142 }
143
144done:
145 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800146 return StringValue(result);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700147}
148
149
Doug Zongker512536a2010-02-17 16:11:44 -0800150Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700151 char* result = NULL;
152 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700153 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700154 }
155 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700156 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700157 return NULL;
158 }
159 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700160 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker9931f7f2009-06-10 14:11:53 -0700161 goto done;
162 }
163
164 scan_mounted_volumes();
165 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
166 if (vol == NULL) {
167 fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
168 result = strdup("");
169 } else {
170 unmount_mounted_volume(vol);
171 result = mount_point;
172 }
173
174done:
175 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800176 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700177}
Doug Zongker8edb00c2009-06-11 17:21:44 -0700178
179
Doug Zongker3d177d02010-07-01 09:18:44 -0700180// format(fs_type, partition_type, location)
Doug Zongker9931f7f2009-06-10 14:11:53 -0700181//
Doug Zongker3d177d02010-07-01 09:18:44 -0700182// fs_type="yaffs2" partition_type="MTD" location=partition
183// fs_type="ext4" partition_type="EMMC" location=device
Doug Zongker512536a2010-02-17 16:11:44 -0800184Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700185 char* result = NULL;
Doug Zongker3d177d02010-07-01 09:18:44 -0700186 if (argc != 3) {
187 return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700188 }
Doug Zongker3d177d02010-07-01 09:18:44 -0700189 char* fs_type;
190 char* partition_type;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700191 char* location;
Doug Zongker3d177d02010-07-01 09:18:44 -0700192 if (ReadArgs(state, argv, 3, &fs_type, &partition_type, &location) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700193 return NULL;
194 }
195
Doug Zongker3d177d02010-07-01 09:18:44 -0700196 if (strlen(fs_type) == 0) {
197 ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
198 goto done;
199 }
200 if (strlen(partition_type) == 0) {
201 ErrorAbort(state, "partition_type argument to %s() can't be empty",
202 name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700203 goto done;
204 }
205 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700206 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700207 goto done;
208 }
209
Doug Zongker3d177d02010-07-01 09:18:44 -0700210 if (strcmp(partition_type, "MTD") == 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700211 mtd_scan_partitions();
212 const MtdPartition* mtd = mtd_find_partition_by_name(location);
213 if (mtd == NULL) {
214 fprintf(stderr, "%s: no mtd partition named \"%s\"",
215 name, location);
216 result = strdup("");
217 goto done;
218 }
219 MtdWriteContext* ctx = mtd_write_partition(mtd);
220 if (ctx == NULL) {
221 fprintf(stderr, "%s: can't write \"%s\"", name, location);
222 result = strdup("");
223 goto done;
224 }
225 if (mtd_erase_blocks(ctx, -1) == -1) {
226 mtd_write_close(ctx);
227 fprintf(stderr, "%s: failed to erase \"%s\"", name, location);
228 result = strdup("");
229 goto done;
230 }
231 if (mtd_write_close(ctx) != 0) {
232 fprintf(stderr, "%s: failed to close \"%s\"", name, location);
233 result = strdup("");
234 goto done;
235 }
236 result = location;
Doug Zongker3d177d02010-07-01 09:18:44 -0700237#ifdef USE_EXT4
238 } else if (strcmp(fs_type, "ext4") == 0) {
239 reset_ext4fs_info();
Ken Sumrall81011252010-08-13 16:08:03 -0700240 int status = make_ext4fs(location, NULL, NULL, 0, 0, 0);
Doug Zongker3d177d02010-07-01 09:18:44 -0700241 if (status != 0) {
242 fprintf(stderr, "%s: make_ext4fs failed (%d) on %s",
243 name, status, location);
244 result = strdup("");
245 goto done;
246 }
247 result = location;
248#endif
Doug Zongker9931f7f2009-06-10 14:11:53 -0700249 } else {
Doug Zongker3d177d02010-07-01 09:18:44 -0700250 fprintf(stderr, "%s: unsupported fs_type \"%s\" partition_type \"%s\"",
251 name, fs_type, partition_type);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700252 }
253
254done:
Doug Zongker3d177d02010-07-01 09:18:44 -0700255 free(fs_type);
256 free(partition_type);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700257 if (result != location) free(location);
Doug Zongker512536a2010-02-17 16:11:44 -0800258 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700259}
260
Doug Zongker8edb00c2009-06-11 17:21:44 -0700261
Doug Zongker512536a2010-02-17 16:11:44 -0800262Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700263 char** paths = malloc(argc * sizeof(char*));
264 int i;
265 for (i = 0; i < argc; ++i) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700266 paths[i] = Evaluate(state, argv[i]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700267 if (paths[i] == NULL) {
268 int j;
269 for (j = 0; j < i; ++i) {
270 free(paths[j]);
271 }
272 free(paths);
273 return NULL;
274 }
275 }
276
277 bool recursive = (strcmp(name, "delete_recursive") == 0);
278
279 int success = 0;
280 for (i = 0; i < argc; ++i) {
281 if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
282 ++success;
283 free(paths[i]);
284 }
285 free(paths);
286
287 char buffer[10];
288 sprintf(buffer, "%d", success);
Doug Zongker512536a2010-02-17 16:11:44 -0800289 return StringValue(strdup(buffer));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700290}
291
Doug Zongker8edb00c2009-06-11 17:21:44 -0700292
Doug Zongker512536a2010-02-17 16:11:44 -0800293Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700294 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700295 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700296 }
297 char* frac_str;
298 char* sec_str;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700299 if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700300 return NULL;
301 }
302
303 double frac = strtod(frac_str, NULL);
304 int sec = strtol(sec_str, NULL, 10);
305
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700306 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700307 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
308
Doug Zongker9931f7f2009-06-10 14:11:53 -0700309 free(sec_str);
Doug Zongker512536a2010-02-17 16:11:44 -0800310 return StringValue(frac_str);
Doug Zongkerfbf3c102009-06-24 09:36:20 -0700311}
312
Doug Zongker512536a2010-02-17 16:11:44 -0800313Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerfbf3c102009-06-24 09:36:20 -0700314 if (argc != 1) {
315 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
316 }
317 char* frac_str;
318 if (ReadArgs(state, argv, 1, &frac_str) < 0) {
319 return NULL;
320 }
321
322 double frac = strtod(frac_str, NULL);
323
324 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
325 fprintf(ui->cmd_pipe, "set_progress %f\n", frac);
326
Doug Zongker512536a2010-02-17 16:11:44 -0800327 return StringValue(frac_str);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700328}
329
Doug Zongker8edb00c2009-06-11 17:21:44 -0700330// package_extract_dir(package_path, destination_path)
Doug Zongker512536a2010-02-17 16:11:44 -0800331Value* PackageExtractDirFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700332 int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700333 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700334 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700335 }
336 char* zip_path;
337 char* dest_path;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700338 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700339
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700340 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700341
342 // To create a consistent system image, never use the clock for timestamps.
343 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
344
345 bool success = mzExtractRecursive(za, zip_path, dest_path,
346 MZ_EXTRACT_FILES_ONLY, &timestamp,
347 NULL, NULL);
348 free(zip_path);
349 free(dest_path);
Doug Zongker512536a2010-02-17 16:11:44 -0800350 return StringValue(strdup(success ? "t" : ""));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700351}
352
Doug Zongker8edb00c2009-06-11 17:21:44 -0700353
354// package_extract_file(package_path, destination_path)
Doug Zongker6aece332010-02-01 14:40:12 -0800355// or
356// package_extract_file(package_path)
357// to return the entire contents of the file as the result of this
Doug Zongker512536a2010-02-17 16:11:44 -0800358// function (the char* returned is actually a FileContents*).
359Value* PackageExtractFileFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700360 int argc, Expr* argv[]) {
Doug Zongker6aece332010-02-01 14:40:12 -0800361 if (argc != 1 && argc != 2) {
362 return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
363 name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700364 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700365 bool success = false;
Doug Zongker6aece332010-02-01 14:40:12 -0800366 if (argc == 2) {
367 // The two-argument version extracts to a file.
Doug Zongker8edb00c2009-06-11 17:21:44 -0700368
Doug Zongker6aece332010-02-01 14:40:12 -0800369 char* zip_path;
370 char* dest_path;
371 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
372
373 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
374 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
375 if (entry == NULL) {
376 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
377 goto done2;
378 }
379
380 FILE* f = fopen(dest_path, "wb");
381 if (f == NULL) {
382 fprintf(stderr, "%s: can't open %s for write: %s\n",
383 name, dest_path, strerror(errno));
384 goto done2;
385 }
386 success = mzExtractZipEntryToFile(za, entry, fileno(f));
387 fclose(f);
388
389 done2:
390 free(zip_path);
391 free(dest_path);
Doug Zongker512536a2010-02-17 16:11:44 -0800392 return StringValue(strdup(success ? "t" : ""));
Doug Zongker6aece332010-02-01 14:40:12 -0800393 } else {
394 // The one-argument version returns the contents of the file
395 // as the result.
396
397 char* zip_path;
Doug Zongker512536a2010-02-17 16:11:44 -0800398 Value* v = malloc(sizeof(Value));
399 v->type = VAL_BLOB;
400 v->size = -1;
401 v->data = NULL;
Doug Zongker6aece332010-02-01 14:40:12 -0800402
403 if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
404
405 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
406 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
407 if (entry == NULL) {
408 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
409 goto done1;
410 }
411
Doug Zongker512536a2010-02-17 16:11:44 -0800412 v->size = mzGetZipEntryUncompLen(entry);
413 v->data = malloc(v->size);
414 if (v->data == NULL) {
Doug Zongker6aece332010-02-01 14:40:12 -0800415 fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n",
Doug Zongker512536a2010-02-17 16:11:44 -0800416 name, (long)v->size, zip_path);
Doug Zongker6aece332010-02-01 14:40:12 -0800417 goto done1;
418 }
419
Doug Zongker512536a2010-02-17 16:11:44 -0800420 success = mzExtractZipEntryToBuffer(za, entry,
421 (unsigned char *)v->data);
Doug Zongker6aece332010-02-01 14:40:12 -0800422
423 done1:
424 free(zip_path);
425 if (!success) {
Doug Zongker512536a2010-02-17 16:11:44 -0800426 free(v->data);
427 v->data = NULL;
428 v->size = -1;
Doug Zongker6aece332010-02-01 14:40:12 -0800429 }
Doug Zongker512536a2010-02-17 16:11:44 -0800430 return v;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700431 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700432}
433
434
Hristo Bojinovdb314d62010-08-02 10:29:49 -0700435// retouch_binaries(lib1, lib2, ...)
436Value* RetouchBinariesFn(const char* name, State* state,
437 int argc, Expr* argv[]) {
438 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
439
440 char **retouch_entries = ReadVarArgs(state, argc, argv);
441 if (retouch_entries == NULL) {
442 return StringValue(strdup("t"));
443 }
444
445 // some randomness from the clock
446 int32_t override_base;
447 bool override_set = false;
448 int32_t random_base = time(NULL) % 1024;
449 // some more randomness from /dev/random
450 FILE *f_random = fopen("/dev/random", "rb");
451 uint16_t random_bits = 0;
452 if (f_random != NULL) {
453 fread(&random_bits, 2, 1, f_random);
454 random_bits = random_bits % 1024;
455 fclose(f_random);
456 }
457 random_base = (random_base + random_bits) % 1024;
458 fprintf(ui->cmd_pipe, "ui_print Random offset: 0x%x\n", random_base);
459 fprintf(ui->cmd_pipe, "ui_print\n");
460
461 // make sure we never randomize to zero; this let's us look at a file
462 // and know for sure whether it has been processed; important in the
463 // crash recovery process
464 if (random_base == 0) random_base = 1;
465 // make sure our randomization is page-aligned
466 random_base *= -0x1000;
467 override_base = random_base;
468
469 int i = 0;
470 bool success = true;
471 while (i < (argc - 1)) {
472 success = success && retouch_one_library(retouch_entries[i],
473 retouch_entries[i+1],
474 random_base,
475 override_set ?
476 NULL :
477 &override_base);
478 if (!success)
479 ErrorAbort(state, "Failed to retouch '%s'.", retouch_entries[i]);
480
481 free(retouch_entries[i]);
482 free(retouch_entries[i+1]);
483 i += 2;
484
485 if (success && override_base != 0) {
486 random_base = override_base;
487 override_set = true;
488 }
489 }
490 if (i < argc) {
491 free(retouch_entries[i]);
492 success = false;
493 }
494 free(retouch_entries);
495
496 if (!success) {
497 Value* v = malloc(sizeof(Value));
498 v->type = VAL_STRING;
499 v->data = NULL;
500 v->size = -1;
501 return v;
502 }
503 return StringValue(strdup("t"));
504}
505
506
507// undo_retouch_binaries(lib1, lib2, ...)
508Value* UndoRetouchBinariesFn(const char* name, State* state,
509 int argc, Expr* argv[]) {
510 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
511
512 char **retouch_entries = ReadVarArgs(state, argc, argv);
513 if (retouch_entries == NULL) {
514 return StringValue(strdup("t"));
515 }
516
517 int i = 0;
518 bool success = true;
519 int32_t override_base;
520 while (i < (argc-1)) {
521 success = success && retouch_one_library(retouch_entries[i],
522 retouch_entries[i+1],
523 0 /* undo => offset==0 */,
524 NULL);
525 if (!success)
526 ErrorAbort(state, "Failed to unretouch '%s'.",
527 retouch_entries[i]);
528
529 free(retouch_entries[i]);
530 free(retouch_entries[i+1]);
531 i += 2;
532 }
533 if (i < argc) {
534 free(retouch_entries[i]);
535 success = false;
536 }
537 free(retouch_entries);
538
539 if (!success) {
540 Value* v = malloc(sizeof(Value));
541 v->type = VAL_STRING;
542 v->data = NULL;
543 v->size = -1;
544 return v;
545 }
546 return StringValue(strdup("t"));
547}
548
549
Doug Zongker9931f7f2009-06-10 14:11:53 -0700550// symlink target src1 src2 ...
Doug Zongker60babf82009-09-18 15:11:24 -0700551// unlinks any previously existing src1, src2, etc before creating symlinks.
Doug Zongker512536a2010-02-17 16:11:44 -0800552Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700553 if (argc == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700554 return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700555 }
556 char* target;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700557 target = Evaluate(state, argv[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700558 if (target == NULL) return NULL;
559
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700560 char** srcs = ReadVarArgs(state, argc-1, argv+1);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700561 if (srcs == NULL) {
562 free(target);
563 return NULL;
564 }
565
566 int i;
567 for (i = 0; i < argc-1; ++i) {
Doug Zongker60babf82009-09-18 15:11:24 -0700568 if (unlink(srcs[i]) < 0) {
569 if (errno != ENOENT) {
570 fprintf(stderr, "%s: failed to remove %s: %s\n",
571 name, srcs[i], strerror(errno));
572 }
573 }
574 if (symlink(target, srcs[i]) < 0) {
575 fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
576 name, srcs[i], target, strerror(errno));
577 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700578 free(srcs[i]);
579 }
580 free(srcs);
Doug Zongker512536a2010-02-17 16:11:44 -0800581 return StringValue(strdup(""));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700582}
583
Doug Zongker8edb00c2009-06-11 17:21:44 -0700584
Doug Zongker512536a2010-02-17 16:11:44 -0800585Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700586 char* result = NULL;
587 bool recursive = (strcmp(name, "set_perm_recursive") == 0);
588
589 int min_args = 4 + (recursive ? 1 : 0);
590 if (argc < min_args) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700591 return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700592 }
593
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700594 char** args = ReadVarArgs(state, argc, argv);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700595 if (args == NULL) return NULL;
596
597 char* end;
598 int i;
599
600 int uid = strtoul(args[0], &end, 0);
601 if (*end != '\0' || args[0][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700602 ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700603 goto done;
604 }
605
606 int gid = strtoul(args[1], &end, 0);
607 if (*end != '\0' || args[1][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700608 ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700609 goto done;
610 }
611
612 if (recursive) {
613 int dir_mode = strtoul(args[2], &end, 0);
614 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700615 ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700616 goto done;
617 }
618
619 int file_mode = strtoul(args[3], &end, 0);
620 if (*end != '\0' || args[3][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700621 ErrorAbort(state, "%s: \"%s\" not a valid filemode",
Doug Zongker9931f7f2009-06-10 14:11:53 -0700622 name, args[3]);
623 goto done;
624 }
625
626 for (i = 4; i < argc; ++i) {
627 dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
628 }
629 } else {
630 int mode = strtoul(args[2], &end, 0);
631 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700632 ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700633 goto done;
634 }
635
Doug Zongker0bbfe3d2009-06-25 13:37:31 -0700636 for (i = 3; i < argc; ++i) {
Doug Zongker60babf82009-09-18 15:11:24 -0700637 if (chown(args[i], uid, gid) < 0) {
638 fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n",
639 name, args[i], uid, gid, strerror(errno));
640 }
641 if (chmod(args[i], mode) < 0) {
642 fprintf(stderr, "%s: chmod of %s to %o failed: %s\n",
643 name, args[i], mode, strerror(errno));
644 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700645 }
646 }
647 result = strdup("");
648
649done:
650 for (i = 0; i < argc; ++i) {
651 free(args[i]);
652 }
653 free(args);
654
Doug Zongker512536a2010-02-17 16:11:44 -0800655 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700656}
657
Doug Zongker8edb00c2009-06-11 17:21:44 -0700658
Doug Zongker512536a2010-02-17 16:11:44 -0800659Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700660 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700661 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700662 }
663 char* key;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700664 key = Evaluate(state, argv[0]);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700665 if (key == NULL) return NULL;
666
667 char value[PROPERTY_VALUE_MAX];
668 property_get(key, value, "");
669 free(key);
670
Doug Zongker512536a2010-02-17 16:11:44 -0800671 return StringValue(strdup(value));
Doug Zongker8edb00c2009-06-11 17:21:44 -0700672}
673
674
Doug Zongker47cace92009-06-18 10:11:50 -0700675// file_getprop(file, key)
676//
677// interprets 'file' as a getprop-style file (key=value pairs, one
678// per line, # comment lines and blank lines okay), and returns the value
679// for 'key' (or "" if it isn't defined).
Doug Zongker512536a2010-02-17 16:11:44 -0800680Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker47cace92009-06-18 10:11:50 -0700681 char* result = NULL;
682 char* buffer = NULL;
683 char* filename;
684 char* key;
685 if (ReadArgs(state, argv, 2, &filename, &key) < 0) {
686 return NULL;
687 }
688
689 struct stat st;
690 if (stat(filename, &st) < 0) {
691 ErrorAbort(state, "%s: failed to stat \"%s\": %s",
692 name, filename, strerror(errno));
693 goto done;
694 }
695
696#define MAX_FILE_GETPROP_SIZE 65536
697
698 if (st.st_size > MAX_FILE_GETPROP_SIZE) {
699 ErrorAbort(state, "%s too large for %s (max %d)",
700 filename, name, MAX_FILE_GETPROP_SIZE);
701 goto done;
702 }
703
704 buffer = malloc(st.st_size+1);
705 if (buffer == NULL) {
706 ErrorAbort(state, "%s: failed to alloc %d bytes", name, st.st_size+1);
707 goto done;
708 }
709
710 FILE* f = fopen(filename, "rb");
711 if (f == NULL) {
712 ErrorAbort(state, "%s: failed to open %s: %s",
713 name, filename, strerror(errno));
714 goto done;
715 }
716
717 if (fread(buffer, 1, st.st_size, f) != st.st_size) {
718 ErrorAbort(state, "%s: failed to read %d bytes from %s",
719 name, st.st_size+1, filename);
720 fclose(f);
721 goto done;
722 }
723 buffer[st.st_size] = '\0';
724
725 fclose(f);
726
727 char* line = strtok(buffer, "\n");
728 do {
729 // skip whitespace at start of line
730 while (*line && isspace(*line)) ++line;
731
732 // comment or blank line: skip to next line
733 if (*line == '\0' || *line == '#') continue;
734
735 char* equal = strchr(line, '=');
736 if (equal == NULL) {
737 ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
738 name, line, filename);
739 goto done;
740 }
741
742 // trim whitespace between key and '='
743 char* key_end = equal-1;
744 while (key_end > line && isspace(*key_end)) --key_end;
745 key_end[1] = '\0';
746
747 // not the key we're looking for
748 if (strcmp(key, line) != 0) continue;
749
750 // skip whitespace after the '=' to the start of the value
751 char* val_start = equal+1;
752 while(*val_start && isspace(*val_start)) ++val_start;
753
754 // trim trailing whitespace
755 char* val_end = val_start + strlen(val_start)-1;
756 while (val_end > val_start && isspace(*val_end)) --val_end;
757 val_end[1] = '\0';
758
759 result = strdup(val_start);
760 break;
761
762 } while ((line = strtok(NULL, "\n")));
763
764 if (result == NULL) result = strdup("");
765
766 done:
767 free(filename);
768 free(key);
769 free(buffer);
Doug Zongker512536a2010-02-17 16:11:44 -0800770 return StringValue(result);
Doug Zongker47cace92009-06-18 10:11:50 -0700771}
772
773
Doug Zongker8edb00c2009-06-11 17:21:44 -0700774static bool write_raw_image_cb(const unsigned char* data,
775 int data_len, void* ctx) {
776 int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
777 if (r == data_len) return true;
778 fprintf(stderr, "%s\n", strerror(errno));
779 return false;
780}
781
782// write_raw_image(file, partition)
Doug Zongker512536a2010-02-17 16:11:44 -0800783Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700784 char* result = NULL;
785
786 char* partition;
787 char* filename;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700788 if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700789 return NULL;
790 }
791
792 if (strlen(partition) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700793 ErrorAbort(state, "partition argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700794 goto done;
795 }
796 if (strlen(filename) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700797 ErrorAbort(state, "file argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700798 goto done;
799 }
800
801 mtd_scan_partitions();
802 const MtdPartition* mtd = mtd_find_partition_by_name(partition);
803 if (mtd == NULL) {
804 fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition);
805 result = strdup("");
806 goto done;
807 }
808
809 MtdWriteContext* ctx = mtd_write_partition(mtd);
810 if (ctx == NULL) {
811 fprintf(stderr, "%s: can't write mtd partition \"%s\"\n",
812 name, partition);
813 result = strdup("");
814 goto done;
815 }
816
817 bool success;
818
819 FILE* f = fopen(filename, "rb");
820 if (f == NULL) {
821 fprintf(stderr, "%s: can't open %s: %s\n",
822 name, filename, strerror(errno));
823 result = strdup("");
824 goto done;
825 }
826
827 success = true;
828 char* buffer = malloc(BUFSIZ);
829 int read;
830 while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
831 int wrote = mtd_write_data(ctx, buffer, read);
832 success = success && (wrote == read);
833 if (!success) {
834 fprintf(stderr, "mtd_write_data to %s failed: %s\n",
835 partition, strerror(errno));
836 }
837 }
838 free(buffer);
839 fclose(f);
840
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700841 if (mtd_erase_blocks(ctx, -1) == -1) {
842 fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition);
843 }
844 if (mtd_write_close(ctx) != 0) {
845 fprintf(stderr, "%s: error closing write of %s\n", name, partition);
846 }
847
Doug Zongker8edb00c2009-06-11 17:21:44 -0700848 printf("%s %s partition from %s\n",
849 success ? "wrote" : "failed to write", partition, filename);
850
851 result = success ? partition : strdup("");
852
853done:
854 if (result != partition) free(partition);
855 free(filename);
Doug Zongker512536a2010-02-17 16:11:44 -0800856 return StringValue(result);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700857}
858
Doug Zongker8edb00c2009-06-11 17:21:44 -0700859// apply_patch_space(bytes)
Doug Zongkerc4351c72010-02-22 14:46:32 -0800860Value* ApplyPatchSpaceFn(const char* name, State* state,
861 int argc, Expr* argv[]) {
862 char* bytes_str;
863 if (ReadArgs(state, argv, 1, &bytes_str) < 0) {
864 return NULL;
865 }
866
867 char* endptr;
868 size_t bytes = strtol(bytes_str, &endptr, 10);
869 if (bytes == 0 && endptr == bytes_str) {
870 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
871 name, bytes_str);
872 free(bytes_str);
873 return NULL;
874 }
875
876 return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
877}
878
879
880// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
Doug Zongker512536a2010-02-17 16:11:44 -0800881Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800882 if (argc < 6 || (argc % 2) == 1) {
883 return ErrorAbort(state, "%s(): expected at least 6 args and an "
884 "even number, got %d",
885 name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700886 }
887
Doug Zongkerc4351c72010-02-22 14:46:32 -0800888 char* source_filename;
889 char* target_filename;
890 char* target_sha1;
891 char* target_size_str;
892 if (ReadArgs(state, argv, 4, &source_filename, &target_filename,
893 &target_sha1, &target_size_str) < 0) {
894 return NULL;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700895 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700896
Doug Zongkerc4351c72010-02-22 14:46:32 -0800897 char* endptr;
898 size_t target_size = strtol(target_size_str, &endptr, 10);
899 if (target_size == 0 && endptr == target_size_str) {
900 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count",
901 name, target_size_str);
902 free(source_filename);
903 free(target_filename);
904 free(target_sha1);
905 free(target_size_str);
906 return NULL;
907 }
908
909 int patchcount = (argc-4) / 2;
910 Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700911
912 int i;
Doug Zongkerc4351c72010-02-22 14:46:32 -0800913 for (i = 0; i < patchcount; ++i) {
914 if (patches[i*2]->type != VAL_STRING) {
915 ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
916 break;
917 }
918 if (patches[i*2+1]->type != VAL_BLOB) {
919 ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
920 break;
921 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700922 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800923 if (i != patchcount) {
924 for (i = 0; i < patchcount*2; ++i) {
925 FreeValue(patches[i]);
926 }
927 free(patches);
928 return NULL;
929 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700930
Doug Zongkerc4351c72010-02-22 14:46:32 -0800931 char** patch_sha_str = malloc(patchcount * sizeof(char*));
932 for (i = 0; i < patchcount; ++i) {
933 patch_sha_str[i] = patches[i*2]->data;
934 patches[i*2]->data = NULL;
935 FreeValue(patches[i*2]);
936 patches[i] = patches[i*2+1];
Doug Zongker8edb00c2009-06-11 17:21:44 -0700937 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800938
939 int result = applypatch(source_filename, target_filename,
940 target_sha1, target_size,
941 patchcount, patch_sha_str, patches);
942
943 for (i = 0; i < patchcount; ++i) {
944 FreeValue(patches[i]);
945 }
946 free(patch_sha_str);
947 free(patches);
948
949 return StringValue(strdup(result == 0 ? "t" : ""));
950}
951
952// apply_patch_check(file, [sha1_1, ...])
953Value* ApplyPatchCheckFn(const char* name, State* state,
954 int argc, Expr* argv[]) {
955 if (argc < 1) {
956 return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
957 name, argc);
958 }
959
960 char* filename;
961 if (ReadArgs(state, argv, 1, &filename) < 0) {
962 return NULL;
963 }
964
965 int patchcount = argc-1;
966 char** sha1s = ReadVarArgs(state, argc-1, argv+1);
967
968 int result = applypatch_check(filename, patchcount, sha1s);
969
970 int i;
971 for (i = 0; i < patchcount; ++i) {
972 free(sha1s[i]);
973 }
974 free(sha1s);
975
976 return StringValue(strdup(result == 0 ? "t" : ""));
Doug Zongker8edb00c2009-06-11 17:21:44 -0700977}
978
Doug Zongker512536a2010-02-17 16:11:44 -0800979Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700980 char** args = ReadVarArgs(state, argc, argv);
981 if (args == NULL) {
982 return NULL;
983 }
984
985 int size = 0;
986 int i;
987 for (i = 0; i < argc; ++i) {
988 size += strlen(args[i]);
989 }
990 char* buffer = malloc(size+1);
991 size = 0;
992 for (i = 0; i < argc; ++i) {
993 strcpy(buffer+size, args[i]);
994 size += strlen(args[i]);
995 free(args[i]);
996 }
997 free(args);
998 buffer[size] = '\0';
999
1000 char* line = strtok(buffer, "\n");
1001 while (line) {
1002 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
1003 "ui_print %s\n", line);
1004 line = strtok(NULL, "\n");
1005 }
1006 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
1007
Doug Zongker512536a2010-02-17 16:11:44 -08001008 return StringValue(buffer);
Doug Zongkerd9c9d102009-06-12 12:24:39 -07001009}
1010
Doug Zongker512536a2010-02-17 16:11:44 -08001011Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkera3f89ea2009-09-10 14:10:48 -07001012 if (argc < 1) {
1013 return ErrorAbort(state, "%s() expects at least 1 arg", name);
1014 }
1015 char** args = ReadVarArgs(state, argc, argv);
1016 if (args == NULL) {
1017 return NULL;
1018 }
1019
1020 char** args2 = malloc(sizeof(char*) * (argc+1));
1021 memcpy(args2, args, sizeof(char*) * argc);
1022 args2[argc] = NULL;
1023
1024 fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc);
1025
1026 pid_t child = fork();
1027 if (child == 0) {
1028 execv(args2[0], args2);
1029 fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno));
1030 _exit(1);
1031 }
1032 int status;
1033 waitpid(child, &status, 0);
1034 if (WIFEXITED(status)) {
1035 if (WEXITSTATUS(status) != 0) {
1036 fprintf(stderr, "run_program: child exited with status %d\n",
1037 WEXITSTATUS(status));
1038 }
1039 } else if (WIFSIGNALED(status)) {
1040 fprintf(stderr, "run_program: child terminated by signal %d\n",
1041 WTERMSIG(status));
1042 }
1043
1044 int i;
1045 for (i = 0; i < argc; ++i) {
1046 free(args[i]);
1047 }
1048 free(args);
1049 free(args2);
1050
1051 char buffer[20];
1052 sprintf(buffer, "%d", status);
1053
Doug Zongker512536a2010-02-17 16:11:44 -08001054 return StringValue(strdup(buffer));
Doug Zongkera3f89ea2009-09-10 14:10:48 -07001055}
1056
Doug Zongker512536a2010-02-17 16:11:44 -08001057// Take a sha-1 digest and return it as a newly-allocated hex string.
1058static char* PrintSha1(uint8_t* digest) {
1059 char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
1060 int i;
1061 const char* alphabet = "0123456789abcdef";
1062 for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
1063 buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
1064 buffer[i*2+1] = alphabet[digest[i] & 0xf];
1065 }
1066 buffer[i*2] = '\0';
1067 return buffer;
1068}
1069
1070// sha1_check(data)
1071// to return the sha1 of the data (given in the format returned by
1072// read_file).
1073//
1074// sha1_check(data, sha1_hex, [sha1_hex, ...])
1075// returns the sha1 of the file if it matches any of the hex
1076// strings passed, or "" if it does not equal any of them.
1077//
1078Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
1079 if (argc < 1) {
1080 return ErrorAbort(state, "%s() expects at least 1 arg", name);
1081 }
1082
1083 Value** args = ReadValueVarArgs(state, argc, argv);
1084 if (args == NULL) {
1085 return NULL;
1086 }
1087
1088 if (args[0]->size < 0) {
1089 fprintf(stderr, "%s(): no file contents received", name);
1090 return StringValue(strdup(""));
1091 }
1092 uint8_t digest[SHA_DIGEST_SIZE];
1093 SHA(args[0]->data, args[0]->size, digest);
1094 FreeValue(args[0]);
1095
1096 if (argc == 1) {
1097 return StringValue(PrintSha1(digest));
1098 }
1099
1100 int i;
1101 uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE);
1102 for (i = 1; i < argc; ++i) {
1103 if (args[i]->type != VAL_STRING) {
1104 fprintf(stderr, "%s(): arg %d is not a string; skipping",
1105 name, i);
1106 } else if (ParseSha1(args[i]->data, arg_digest) != 0) {
1107 // Warn about bad args and skip them.
1108 fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping",
1109 name, args[i]->data);
1110 } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
1111 break;
1112 }
1113 FreeValue(args[i]);
1114 }
1115 if (i >= argc) {
1116 // Didn't match any of the hex strings; return false.
1117 return StringValue(strdup(""));
1118 }
1119 // Found a match; free all the remaining arguments and return the
1120 // matched one.
1121 int j;
1122 for (j = i+1; j < argc; ++j) {
1123 FreeValue(args[j]);
1124 }
1125 return args[i];
1126}
1127
Hristo Bojinovdb314d62010-08-02 10:29:49 -07001128// Read a local file and return its contents (the Value* returned
Doug Zongker512536a2010-02-17 16:11:44 -08001129// is actually a FileContents*).
1130Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
1131 if (argc != 1) {
1132 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
1133 }
1134 char* filename;
1135 if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
1136
1137 Value* v = malloc(sizeof(Value));
1138 v->type = VAL_BLOB;
1139
1140 FileContents fc;
Hristo Bojinovdb314d62010-08-02 10:29:49 -07001141 if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) {
Doug Zongker512536a2010-02-17 16:11:44 -08001142 ErrorAbort(state, "%s() loading \"%s\" failed: %s",
1143 name, filename, strerror(errno));
1144 free(filename);
1145 free(v);
1146 free(fc.data);
1147 return NULL;
1148 }
1149
1150 v->size = fc.size;
1151 v->data = (char*)fc.data;
1152
1153 free(filename);
1154 return v;
1155}
Doug Zongker8edb00c2009-06-11 17:21:44 -07001156
Doug Zongker9931f7f2009-06-10 14:11:53 -07001157void RegisterInstallFunctions() {
1158 RegisterFunction("mount", MountFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001159 RegisterFunction("is_mounted", IsMountedFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001160 RegisterFunction("unmount", UnmountFn);
1161 RegisterFunction("format", FormatFn);
1162 RegisterFunction("show_progress", ShowProgressFn);
Doug Zongkerfbf3c102009-06-24 09:36:20 -07001163 RegisterFunction("set_progress", SetProgressFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001164 RegisterFunction("delete", DeleteFn);
1165 RegisterFunction("delete_recursive", DeleteFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001166 RegisterFunction("package_extract_dir", PackageExtractDirFn);
1167 RegisterFunction("package_extract_file", PackageExtractFileFn);
Hristo Bojinovdb314d62010-08-02 10:29:49 -07001168 RegisterFunction("retouch_binaries", RetouchBinariesFn);
1169 RegisterFunction("undo_retouch_binaries", UndoRetouchBinariesFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001170 RegisterFunction("symlink", SymlinkFn);
1171 RegisterFunction("set_perm", SetPermFn);
1172 RegisterFunction("set_perm_recursive", SetPermFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001173
1174 RegisterFunction("getprop", GetPropFn);
Doug Zongker47cace92009-06-18 10:11:50 -07001175 RegisterFunction("file_getprop", FileGetPropFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001176 RegisterFunction("write_raw_image", WriteRawImageFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001177
1178 RegisterFunction("apply_patch", ApplyPatchFn);
Doug Zongkerc4351c72010-02-22 14:46:32 -08001179 RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
1180 RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
Doug Zongkerd9c9d102009-06-12 12:24:39 -07001181
Doug Zongker512536a2010-02-17 16:11:44 -08001182 RegisterFunction("read_file", ReadFileFn);
1183 RegisterFunction("sha1_check", Sha1CheckFn);
1184
Doug Zongkerd9c9d102009-06-12 12:24:39 -07001185 RegisterFunction("ui_print", UIPrintFn);
Doug Zongkera3f89ea2009-09-10 14:10:48 -07001186
1187 RegisterFunction("run_program", RunProgramFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001188}