blob: 77a98193d2b0194a2e2e3a1c3d47ac13fc433572 [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"
Koushik Dutta7c1bffe2010-12-18 19:44:33 -080037#include "mounts.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070038#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
Koushik Duttacf5195a2011-05-29 18:45:42 -070042#include "flashutils/flashutils.h"
43
Doug Zongker56c51052010-07-01 09:18:44 -070044#ifdef USE_EXT4
45#include "make_ext4fs.h"
46#endif
47
48// mount(fs_type, partition_type, location, mount_point)
Doug Zongker9931f7f2009-06-10 14:11:53 -070049//
Doug Zongker56c51052010-07-01 09:18:44 -070050// fs_type="yaffs2" partition_type="MTD" location=partition
51// fs_type="ext4" partition_type="EMMC" location=device
Doug Zongker512536a2010-02-17 16:11:44 -080052Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070053 char* result = NULL;
Doug Zongker56c51052010-07-01 09:18:44 -070054 if (argc != 4) {
55 return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -070056 }
Doug Zongker56c51052010-07-01 09:18:44 -070057 char* fs_type;
58 char* partition_type;
Doug Zongker9931f7f2009-06-10 14:11:53 -070059 char* location;
60 char* mount_point;
Doug Zongker56c51052010-07-01 09:18:44 -070061 if (ReadArgs(state, argv, 4, &fs_type, &partition_type,
62 &location, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070063 return NULL;
64 }
65
Doug Zongker56c51052010-07-01 09:18:44 -070066 if (strlen(fs_type) == 0) {
67 ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
68 goto done;
69 }
70 if (strlen(partition_type) == 0) {
71 ErrorAbort(state, "partition_type argument to %s() can't be empty",
72 name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070073 goto done;
74 }
75 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070076 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070077 goto done;
78 }
79 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070080 ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070081 goto done;
82 }
83
84 mkdir(mount_point, 0755);
85
Koushik Dutta8637c732010-12-18 18:18:44 -080086 if (strcmp(partition_type, "MTD") == 0) {
87 mtd_scan_partitions();
88 const MtdPartition* mtd;
89 mtd = mtd_find_partition_by_name(location);
90 if (mtd == NULL) {
91 fprintf(stderr, "%s: no mtd partition named \"%s\"",
92 name, location);
Doug Zongker9931f7f2009-06-10 14:11:53 -070093 result = strdup("");
Koushik Dutta8637c732010-12-18 18:18:44 -080094 goto done;
95 }
96 if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
97 fprintf(stderr, "mtd mount of %s failed: %s\n",
98 location, strerror(errno));
99 result = strdup("");
100 goto done;
101 }
102 result = mount_point;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700103 } else {
Doug Zongker56c51052010-07-01 09:18:44 -0700104 if (mount(location, mount_point, fs_type,
Doug Zongker9931f7f2009-06-10 14:11:53 -0700105 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
Doug Zongker60babf82009-09-18 15:11:24 -0700106 fprintf(stderr, "%s: failed to mount %s at %s: %s\n",
107 name, location, mount_point, strerror(errno));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700108 result = strdup("");
109 } else {
110 result = mount_point;
111 }
112 }
113
114done:
Doug Zongker56c51052010-07-01 09:18:44 -0700115 free(fs_type);
116 free(partition_type);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700117 free(location);
118 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800119 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700120}
121
Doug Zongker8edb00c2009-06-11 17:21:44 -0700122
123// is_mounted(mount_point)
Doug Zongker512536a2010-02-17 16:11:44 -0800124Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700125 char* result = NULL;
126 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700127 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700128 }
129 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700130 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700131 return NULL;
132 }
133 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700134 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker8edb00c2009-06-11 17:21:44 -0700135 goto done;
136 }
137
138 scan_mounted_volumes();
139 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
140 if (vol == NULL) {
141 result = strdup("");
142 } else {
143 result = mount_point;
144 }
145
146done:
147 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800148 return StringValue(result);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700149}
150
151
Doug Zongker512536a2010-02-17 16:11:44 -0800152Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700153 char* result = NULL;
154 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700155 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700156 }
157 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700158 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700159 return NULL;
160 }
161 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700162 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker9931f7f2009-06-10 14:11:53 -0700163 goto done;
164 }
165
166 scan_mounted_volumes();
167 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
168 if (vol == NULL) {
169 fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
170 result = strdup("");
171 } else {
172 unmount_mounted_volume(vol);
173 result = mount_point;
174 }
175
176done:
177 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800178 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700179}
Doug Zongker8edb00c2009-06-11 17:21:44 -0700180
181
Ken Sumrall8f132ed2011-01-14 18:55:05 -0800182// format(fs_type, partition_type, location, fs_size)
Doug Zongker9931f7f2009-06-10 14:11:53 -0700183//
Ken Sumrall8f132ed2011-01-14 18:55:05 -0800184// fs_type="yaffs2" partition_type="MTD" location=partition fs_size=<bytes>
185// fs_type="ext4" partition_type="EMMC" location=device fs_size=<bytes>
186// if fs_size == 0, then make_ext4fs uses the entire partition.
187// if fs_size > 0, that is the size to use
188// if fs_size < 0, then reserve that many bytes at the end of the partition
Doug Zongker512536a2010-02-17 16:11:44 -0800189Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700190 char* result = NULL;
Ken Sumrall8f132ed2011-01-14 18:55:05 -0800191 if (argc != 4) {
192 return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700193 }
Doug Zongker56c51052010-07-01 09:18:44 -0700194 char* fs_type;
195 char* partition_type;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700196 char* location;
Ken Sumrall8f132ed2011-01-14 18:55:05 -0800197 char* fs_size;
198 if (ReadArgs(state, argv, 4, &fs_type, &partition_type, &location, &fs_size) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700199 return NULL;
200 }
201
Doug Zongker56c51052010-07-01 09:18:44 -0700202 if (strlen(fs_type) == 0) {
203 ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
204 goto done;
205 }
206 if (strlen(partition_type) == 0) {
207 ErrorAbort(state, "partition_type argument to %s() can't be empty",
208 name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700209 goto done;
210 }
211 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700212 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700213 goto done;
214 }
215
Koushik Dutta8637c732010-12-18 18:18:44 -0800216 if (strcmp(partition_type, "MTD") == 0) {
217 mtd_scan_partitions();
218 const MtdPartition* mtd = mtd_find_partition_by_name(location);
219 if (mtd == NULL) {
220 fprintf(stderr, "%s: no mtd partition named \"%s\"",
221 name, location);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700222 result = strdup("");
223 goto done;
224 }
Koushik Dutta8637c732010-12-18 18:18:44 -0800225 MtdWriteContext* ctx = mtd_write_partition(mtd);
226 if (ctx == NULL) {
227 fprintf(stderr, "%s: can't write \"%s\"", name, location);
228 result = strdup("");
229 goto done;
230 }
231 if (mtd_erase_blocks(ctx, -1) == -1) {
232 mtd_write_close(ctx);
233 fprintf(stderr, "%s: failed to erase \"%s\"", name, location);
234 result = strdup("");
235 goto done;
236 }
237 if (mtd_write_close(ctx) != 0) {
238 fprintf(stderr, "%s: failed to close \"%s\"", name, location);
239 result = strdup("");
240 goto done;
241 }
242 result = location;
Doug Zongker56c51052010-07-01 09:18:44 -0700243#ifdef USE_EXT4
244 } else if (strcmp(fs_type, "ext4") == 0) {
Ken Sumrall8f132ed2011-01-14 18:55:05 -0800245 int status = make_ext4fs(location, atoll(fs_size));
Doug Zongker56c51052010-07-01 09:18:44 -0700246 if (status != 0) {
247 fprintf(stderr, "%s: make_ext4fs failed (%d) on %s",
248 name, status, location);
249 result = strdup("");
250 goto done;
251 }
252 result = location;
253#endif
Koushik Duttab4c5fd62011-01-02 22:54:31 -0800254 } else if (strcmp(fs_type, "ext2") == 0) {
255 int status = format_ext2_device(location);
256 if (status != 0) {
257 fprintf(stderr, "%s: format_ext2_device failed (%d) on %s",
258 name, status, location);
259 result = strdup("");
260 goto done;
261 }
262 result = location;
263 } else if (strcmp(fs_type, "ext3") == 0) {
264 int status = format_ext3_device(location);
265 if (status != 0) {
266 fprintf(stderr, "%s: format_ext3_device failed (%d) on %s",
267 name, status, location);
268 result = strdup("");
269 goto done;
270 }
271 result = location;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700272 } else {
Doug Zongker56c51052010-07-01 09:18:44 -0700273 fprintf(stderr, "%s: unsupported fs_type \"%s\" partition_type \"%s\"",
274 name, fs_type, partition_type);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700275 }
Koushik Dutta8637c732010-12-18 18:18:44 -0800276
Doug Zongker9931f7f2009-06-10 14:11:53 -0700277done:
Doug Zongker56c51052010-07-01 09:18:44 -0700278 free(fs_type);
279 free(partition_type);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700280 if (result != location) free(location);
Doug Zongker512536a2010-02-17 16:11:44 -0800281 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700282}
283
Doug Zongker8edb00c2009-06-11 17:21:44 -0700284
Doug Zongker512536a2010-02-17 16:11:44 -0800285Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700286 char** paths = malloc(argc * sizeof(char*));
287 int i;
288 for (i = 0; i < argc; ++i) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700289 paths[i] = Evaluate(state, argv[i]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700290 if (paths[i] == NULL) {
291 int j;
292 for (j = 0; j < i; ++i) {
293 free(paths[j]);
294 }
295 free(paths);
296 return NULL;
297 }
298 }
299
300 bool recursive = (strcmp(name, "delete_recursive") == 0);
301
302 int success = 0;
303 for (i = 0; i < argc; ++i) {
304 if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
305 ++success;
306 free(paths[i]);
307 }
308 free(paths);
309
310 char buffer[10];
311 sprintf(buffer, "%d", success);
Doug Zongker512536a2010-02-17 16:11:44 -0800312 return StringValue(strdup(buffer));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700313}
314
Doug Zongker8edb00c2009-06-11 17:21:44 -0700315
Doug Zongker512536a2010-02-17 16:11:44 -0800316Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700317 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700318 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700319 }
320 char* frac_str;
321 char* sec_str;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700322 if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700323 return NULL;
324 }
325
326 double frac = strtod(frac_str, NULL);
327 int sec = strtol(sec_str, NULL, 10);
328
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700329 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700330 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
331
Doug Zongker9931f7f2009-06-10 14:11:53 -0700332 free(sec_str);
Doug Zongker512536a2010-02-17 16:11:44 -0800333 return StringValue(frac_str);
Doug Zongkerfbf3c102009-06-24 09:36:20 -0700334}
335
Doug Zongker512536a2010-02-17 16:11:44 -0800336Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerfbf3c102009-06-24 09:36:20 -0700337 if (argc != 1) {
338 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
339 }
340 char* frac_str;
341 if (ReadArgs(state, argv, 1, &frac_str) < 0) {
342 return NULL;
343 }
344
345 double frac = strtod(frac_str, NULL);
346
347 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
348 fprintf(ui->cmd_pipe, "set_progress %f\n", frac);
349
Doug Zongker512536a2010-02-17 16:11:44 -0800350 return StringValue(frac_str);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700351}
352
Doug Zongker8edb00c2009-06-11 17:21:44 -0700353// package_extract_dir(package_path, destination_path)
Doug Zongker512536a2010-02-17 16:11:44 -0800354Value* PackageExtractDirFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700355 int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700356 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700357 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700358 }
359 char* zip_path;
360 char* dest_path;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700361 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700362
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700363 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700364
365 // To create a consistent system image, never use the clock for timestamps.
366 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
367
368 bool success = mzExtractRecursive(za, zip_path, dest_path,
369 MZ_EXTRACT_FILES_ONLY, &timestamp,
370 NULL, NULL);
371 free(zip_path);
372 free(dest_path);
Doug Zongker512536a2010-02-17 16:11:44 -0800373 return StringValue(strdup(success ? "t" : ""));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700374}
375
Doug Zongker8edb00c2009-06-11 17:21:44 -0700376
377// package_extract_file(package_path, destination_path)
Doug Zongker6aece332010-02-01 14:40:12 -0800378// or
379// package_extract_file(package_path)
380// to return the entire contents of the file as the result of this
Doug Zongker512536a2010-02-17 16:11:44 -0800381// function (the char* returned is actually a FileContents*).
382Value* PackageExtractFileFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700383 int argc, Expr* argv[]) {
Doug Zongker6aece332010-02-01 14:40:12 -0800384 if (argc != 1 && argc != 2) {
385 return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
386 name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700387 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700388 bool success = false;
Doug Zongker6aece332010-02-01 14:40:12 -0800389 if (argc == 2) {
390 // The two-argument version extracts to a file.
Doug Zongker8edb00c2009-06-11 17:21:44 -0700391
Doug Zongker6aece332010-02-01 14:40:12 -0800392 char* zip_path;
393 char* dest_path;
394 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
395
396 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
397 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
398 if (entry == NULL) {
399 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
400 goto done2;
401 }
402
403 FILE* f = fopen(dest_path, "wb");
404 if (f == NULL) {
405 fprintf(stderr, "%s: can't open %s for write: %s\n",
406 name, dest_path, strerror(errno));
407 goto done2;
408 }
409 success = mzExtractZipEntryToFile(za, entry, fileno(f));
410 fclose(f);
411
412 done2:
413 free(zip_path);
414 free(dest_path);
Doug Zongker512536a2010-02-17 16:11:44 -0800415 return StringValue(strdup(success ? "t" : ""));
Doug Zongker6aece332010-02-01 14:40:12 -0800416 } else {
417 // The one-argument version returns the contents of the file
418 // as the result.
419
420 char* zip_path;
Doug Zongker512536a2010-02-17 16:11:44 -0800421 Value* v = malloc(sizeof(Value));
422 v->type = VAL_BLOB;
423 v->size = -1;
424 v->data = NULL;
Doug Zongker6aece332010-02-01 14:40:12 -0800425
426 if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
427
428 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
429 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
430 if (entry == NULL) {
431 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
432 goto done1;
433 }
434
Doug Zongker512536a2010-02-17 16:11:44 -0800435 v->size = mzGetZipEntryUncompLen(entry);
436 v->data = malloc(v->size);
437 if (v->data == NULL) {
Doug Zongker6aece332010-02-01 14:40:12 -0800438 fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n",
Doug Zongker512536a2010-02-17 16:11:44 -0800439 name, (long)v->size, zip_path);
Doug Zongker6aece332010-02-01 14:40:12 -0800440 goto done1;
441 }
442
Doug Zongker512536a2010-02-17 16:11:44 -0800443 success = mzExtractZipEntryToBuffer(za, entry,
444 (unsigned char *)v->data);
Doug Zongker6aece332010-02-01 14:40:12 -0800445
446 done1:
447 free(zip_path);
448 if (!success) {
Doug Zongker512536a2010-02-17 16:11:44 -0800449 free(v->data);
450 v->data = NULL;
451 v->size = -1;
Doug Zongker6aece332010-02-01 14:40:12 -0800452 }
Doug Zongker512536a2010-02-17 16:11:44 -0800453 return v;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700454 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700455}
456
457
Hristo Bojinovdb314d62010-08-02 10:29:49 -0700458// retouch_binaries(lib1, lib2, ...)
459Value* RetouchBinariesFn(const char* name, State* state,
460 int argc, Expr* argv[]) {
461 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
462
463 char **retouch_entries = ReadVarArgs(state, argc, argv);
464 if (retouch_entries == NULL) {
465 return StringValue(strdup("t"));
466 }
467
468 // some randomness from the clock
469 int32_t override_base;
470 bool override_set = false;
471 int32_t random_base = time(NULL) % 1024;
472 // some more randomness from /dev/random
473 FILE *f_random = fopen("/dev/random", "rb");
474 uint16_t random_bits = 0;
475 if (f_random != NULL) {
476 fread(&random_bits, 2, 1, f_random);
477 random_bits = random_bits % 1024;
478 fclose(f_random);
479 }
480 random_base = (random_base + random_bits) % 1024;
481 fprintf(ui->cmd_pipe, "ui_print Random offset: 0x%x\n", random_base);
482 fprintf(ui->cmd_pipe, "ui_print\n");
483
484 // make sure we never randomize to zero; this let's us look at a file
485 // and know for sure whether it has been processed; important in the
486 // crash recovery process
487 if (random_base == 0) random_base = 1;
488 // make sure our randomization is page-aligned
489 random_base *= -0x1000;
490 override_base = random_base;
491
492 int i = 0;
493 bool success = true;
494 while (i < (argc - 1)) {
495 success = success && retouch_one_library(retouch_entries[i],
496 retouch_entries[i+1],
497 random_base,
498 override_set ?
499 NULL :
500 &override_base);
501 if (!success)
502 ErrorAbort(state, "Failed to retouch '%s'.", retouch_entries[i]);
503
504 free(retouch_entries[i]);
505 free(retouch_entries[i+1]);
506 i += 2;
507
508 if (success && override_base != 0) {
509 random_base = override_base;
510 override_set = true;
511 }
512 }
513 if (i < argc) {
514 free(retouch_entries[i]);
515 success = false;
516 }
517 free(retouch_entries);
518
519 if (!success) {
520 Value* v = malloc(sizeof(Value));
521 v->type = VAL_STRING;
522 v->data = NULL;
523 v->size = -1;
524 return v;
525 }
526 return StringValue(strdup("t"));
527}
528
529
530// undo_retouch_binaries(lib1, lib2, ...)
531Value* UndoRetouchBinariesFn(const char* name, State* state,
532 int argc, Expr* argv[]) {
533 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
534
535 char **retouch_entries = ReadVarArgs(state, argc, argv);
536 if (retouch_entries == NULL) {
537 return StringValue(strdup("t"));
538 }
539
540 int i = 0;
541 bool success = true;
542 int32_t override_base;
543 while (i < (argc-1)) {
544 success = success && retouch_one_library(retouch_entries[i],
545 retouch_entries[i+1],
546 0 /* undo => offset==0 */,
547 NULL);
548 if (!success)
549 ErrorAbort(state, "Failed to unretouch '%s'.",
550 retouch_entries[i]);
551
552 free(retouch_entries[i]);
553 free(retouch_entries[i+1]);
554 i += 2;
555 }
556 if (i < argc) {
557 free(retouch_entries[i]);
558 success = false;
559 }
560 free(retouch_entries);
561
562 if (!success) {
563 Value* v = malloc(sizeof(Value));
564 v->type = VAL_STRING;
565 v->data = NULL;
566 v->size = -1;
567 return v;
568 }
569 return StringValue(strdup("t"));
570}
571
572
Doug Zongker9931f7f2009-06-10 14:11:53 -0700573// symlink target src1 src2 ...
Doug Zongker60babf82009-09-18 15:11:24 -0700574// unlinks any previously existing src1, src2, etc before creating symlinks.
Doug Zongker512536a2010-02-17 16:11:44 -0800575Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700576 if (argc == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700577 return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700578 }
579 char* target;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700580 target = Evaluate(state, argv[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700581 if (target == NULL) return NULL;
582
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700583 char** srcs = ReadVarArgs(state, argc-1, argv+1);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700584 if (srcs == NULL) {
585 free(target);
586 return NULL;
587 }
588
589 int i;
590 for (i = 0; i < argc-1; ++i) {
Doug Zongker60babf82009-09-18 15:11:24 -0700591 if (unlink(srcs[i]) < 0) {
592 if (errno != ENOENT) {
593 fprintf(stderr, "%s: failed to remove %s: %s\n",
594 name, srcs[i], strerror(errno));
595 }
596 }
597 if (symlink(target, srcs[i]) < 0) {
598 fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
599 name, srcs[i], target, strerror(errno));
600 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700601 free(srcs[i]);
602 }
603 free(srcs);
Doug Zongker512536a2010-02-17 16:11:44 -0800604 return StringValue(strdup(""));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700605}
606
Doug Zongker8edb00c2009-06-11 17:21:44 -0700607
Doug Zongker512536a2010-02-17 16:11:44 -0800608Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700609 char* result = NULL;
610 bool recursive = (strcmp(name, "set_perm_recursive") == 0);
611
612 int min_args = 4 + (recursive ? 1 : 0);
613 if (argc < min_args) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700614 return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700615 }
616
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700617 char** args = ReadVarArgs(state, argc, argv);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700618 if (args == NULL) return NULL;
619
620 char* end;
621 int i;
622
623 int uid = strtoul(args[0], &end, 0);
624 if (*end != '\0' || args[0][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700625 ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700626 goto done;
627 }
628
629 int gid = strtoul(args[1], &end, 0);
630 if (*end != '\0' || args[1][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700631 ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700632 goto done;
633 }
634
635 if (recursive) {
636 int dir_mode = strtoul(args[2], &end, 0);
637 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700638 ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700639 goto done;
640 }
641
642 int file_mode = strtoul(args[3], &end, 0);
643 if (*end != '\0' || args[3][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700644 ErrorAbort(state, "%s: \"%s\" not a valid filemode",
Doug Zongker9931f7f2009-06-10 14:11:53 -0700645 name, args[3]);
646 goto done;
647 }
648
649 for (i = 4; i < argc; ++i) {
650 dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
651 }
652 } else {
653 int mode = strtoul(args[2], &end, 0);
654 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700655 ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700656 goto done;
657 }
658
Doug Zongker0bbfe3d2009-06-25 13:37:31 -0700659 for (i = 3; i < argc; ++i) {
Doug Zongker60babf82009-09-18 15:11:24 -0700660 if (chown(args[i], uid, gid) < 0) {
661 fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n",
662 name, args[i], uid, gid, strerror(errno));
663 }
664 if (chmod(args[i], mode) < 0) {
665 fprintf(stderr, "%s: chmod of %s to %o failed: %s\n",
666 name, args[i], mode, strerror(errno));
667 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700668 }
669 }
670 result = strdup("");
671
672done:
673 for (i = 0; i < argc; ++i) {
674 free(args[i]);
675 }
676 free(args);
677
Doug Zongker512536a2010-02-17 16:11:44 -0800678 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700679}
680
Doug Zongker8edb00c2009-06-11 17:21:44 -0700681
Doug Zongker512536a2010-02-17 16:11:44 -0800682Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700683 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700684 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700685 }
686 char* key;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700687 key = Evaluate(state, argv[0]);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700688 if (key == NULL) return NULL;
689
690 char value[PROPERTY_VALUE_MAX];
691 property_get(key, value, "");
692 free(key);
693
Doug Zongker512536a2010-02-17 16:11:44 -0800694 return StringValue(strdup(value));
Doug Zongker8edb00c2009-06-11 17:21:44 -0700695}
696
697
Doug Zongker47cace92009-06-18 10:11:50 -0700698// file_getprop(file, key)
699//
700// interprets 'file' as a getprop-style file (key=value pairs, one
701// per line, # comment lines and blank lines okay), and returns the value
702// for 'key' (or "" if it isn't defined).
Doug Zongker512536a2010-02-17 16:11:44 -0800703Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker47cace92009-06-18 10:11:50 -0700704 char* result = NULL;
705 char* buffer = NULL;
706 char* filename;
707 char* key;
708 if (ReadArgs(state, argv, 2, &filename, &key) < 0) {
709 return NULL;
710 }
711
712 struct stat st;
713 if (stat(filename, &st) < 0) {
714 ErrorAbort(state, "%s: failed to stat \"%s\": %s",
715 name, filename, strerror(errno));
716 goto done;
717 }
718
719#define MAX_FILE_GETPROP_SIZE 65536
720
721 if (st.st_size > MAX_FILE_GETPROP_SIZE) {
722 ErrorAbort(state, "%s too large for %s (max %d)",
723 filename, name, MAX_FILE_GETPROP_SIZE);
724 goto done;
725 }
726
727 buffer = malloc(st.st_size+1);
728 if (buffer == NULL) {
729 ErrorAbort(state, "%s: failed to alloc %d bytes", name, st.st_size+1);
730 goto done;
731 }
732
733 FILE* f = fopen(filename, "rb");
734 if (f == NULL) {
735 ErrorAbort(state, "%s: failed to open %s: %s",
736 name, filename, strerror(errno));
737 goto done;
738 }
739
740 if (fread(buffer, 1, st.st_size, f) != st.st_size) {
741 ErrorAbort(state, "%s: failed to read %d bytes from %s",
742 name, st.st_size+1, filename);
743 fclose(f);
744 goto done;
745 }
746 buffer[st.st_size] = '\0';
747
748 fclose(f);
749
750 char* line = strtok(buffer, "\n");
751 do {
752 // skip whitespace at start of line
753 while (*line && isspace(*line)) ++line;
754
755 // comment or blank line: skip to next line
756 if (*line == '\0' || *line == '#') continue;
757
758 char* equal = strchr(line, '=');
759 if (equal == NULL) {
760 ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
761 name, line, filename);
762 goto done;
763 }
764
765 // trim whitespace between key and '='
766 char* key_end = equal-1;
767 while (key_end > line && isspace(*key_end)) --key_end;
768 key_end[1] = '\0';
769
770 // not the key we're looking for
771 if (strcmp(key, line) != 0) continue;
772
773 // skip whitespace after the '=' to the start of the value
774 char* val_start = equal+1;
775 while(*val_start && isspace(*val_start)) ++val_start;
776
777 // trim trailing whitespace
778 char* val_end = val_start + strlen(val_start)-1;
779 while (val_end > val_start && isspace(*val_end)) --val_end;
780 val_end[1] = '\0';
781
782 result = strdup(val_start);
783 break;
784
785 } while ((line = strtok(NULL, "\n")));
786
787 if (result == NULL) result = strdup("");
788
789 done:
790 free(filename);
791 free(key);
792 free(buffer);
Doug Zongker512536a2010-02-17 16:11:44 -0800793 return StringValue(result);
Doug Zongker47cace92009-06-18 10:11:50 -0700794}
795
796
Doug Zongker8edb00c2009-06-11 17:21:44 -0700797static bool write_raw_image_cb(const unsigned char* data,
798 int data_len, void* ctx) {
799 int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
800 if (r == data_len) return true;
801 fprintf(stderr, "%s\n", strerror(errno));
802 return false;
803}
804
Doug Zongker179b2d92011-04-12 15:49:04 -0700805// write_raw_image(filename_or_blob, partition)
Doug Zongker512536a2010-02-17 16:11:44 -0800806Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700807 char* result = NULL;
808
Doug Zongker179b2d92011-04-12 15:49:04 -0700809 Value* partition_value;
810 Value* contents;
811 if (ReadValueArgs(state, argv, 2, &contents, &partition_value) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700812 return NULL;
813 }
814
Doug Zongker179b2d92011-04-12 15:49:04 -0700815 if (partition_value->type != VAL_STRING) {
816 ErrorAbort(state, "partition argument to %s must be string", name);
817 goto done;
818 }
819 char* partition = partition_value->data;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700820 if (strlen(partition) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700821 ErrorAbort(state, "partition argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700822 goto done;
823 }
Doug Zongker179b2d92011-04-12 15:49:04 -0700824 if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700825 ErrorAbort(state, "file argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700826 goto done;
827 }
828
Koushik Duttacf5195a2011-05-29 18:45:42 -0700829 if (0 == restore_raw_partition(NULL, partition, filename))
Koushik Dutta1b867542010-11-10 23:52:09 -0800830 result = strdup(partition);
831 else
Koushik Dutta7c1bffe2010-12-18 19:44:33 -0800832 result = strdup("");
Doug Zongker8edb00c2009-06-11 17:21:44 -0700833 goto done;
834 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700835
836done:
Doug Zongker179b2d92011-04-12 15:49:04 -0700837 if (result != partition) FreeValue(partition_value);
838 FreeValue(contents);
Doug Zongker512536a2010-02-17 16:11:44 -0800839 return StringValue(result);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700840}
841
Doug Zongker8edb00c2009-06-11 17:21:44 -0700842// apply_patch_space(bytes)
Doug Zongkerc4351c72010-02-22 14:46:32 -0800843Value* ApplyPatchSpaceFn(const char* name, State* state,
844 int argc, Expr* argv[]) {
845 char* bytes_str;
846 if (ReadArgs(state, argv, 1, &bytes_str) < 0) {
847 return NULL;
848 }
849
850 char* endptr;
851 size_t bytes = strtol(bytes_str, &endptr, 10);
852 if (bytes == 0 && endptr == bytes_str) {
853 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
854 name, bytes_str);
855 free(bytes_str);
856 return NULL;
857 }
858
859 return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
860}
861
862
863// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
Doug Zongker512536a2010-02-17 16:11:44 -0800864Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800865 if (argc < 6 || (argc % 2) == 1) {
866 return ErrorAbort(state, "%s(): expected at least 6 args and an "
867 "even number, got %d",
868 name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700869 }
870
Doug Zongkerc4351c72010-02-22 14:46:32 -0800871 char* source_filename;
872 char* target_filename;
873 char* target_sha1;
874 char* target_size_str;
875 if (ReadArgs(state, argv, 4, &source_filename, &target_filename,
876 &target_sha1, &target_size_str) < 0) {
877 return NULL;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700878 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700879
Doug Zongkerc4351c72010-02-22 14:46:32 -0800880 char* endptr;
881 size_t target_size = strtol(target_size_str, &endptr, 10);
882 if (target_size == 0 && endptr == target_size_str) {
883 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count",
884 name, target_size_str);
885 free(source_filename);
886 free(target_filename);
887 free(target_sha1);
888 free(target_size_str);
889 return NULL;
890 }
891
892 int patchcount = (argc-4) / 2;
893 Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700894
895 int i;
Doug Zongkerc4351c72010-02-22 14:46:32 -0800896 for (i = 0; i < patchcount; ++i) {
897 if (patches[i*2]->type != VAL_STRING) {
898 ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
899 break;
900 }
901 if (patches[i*2+1]->type != VAL_BLOB) {
902 ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
903 break;
904 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700905 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800906 if (i != patchcount) {
907 for (i = 0; i < patchcount*2; ++i) {
908 FreeValue(patches[i]);
909 }
910 free(patches);
911 return NULL;
912 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700913
Doug Zongkerc4351c72010-02-22 14:46:32 -0800914 char** patch_sha_str = malloc(patchcount * sizeof(char*));
915 for (i = 0; i < patchcount; ++i) {
916 patch_sha_str[i] = patches[i*2]->data;
917 patches[i*2]->data = NULL;
918 FreeValue(patches[i*2]);
919 patches[i] = patches[i*2+1];
Doug Zongker8edb00c2009-06-11 17:21:44 -0700920 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800921
922 int result = applypatch(source_filename, target_filename,
923 target_sha1, target_size,
924 patchcount, patch_sha_str, patches);
925
926 for (i = 0; i < patchcount; ++i) {
927 FreeValue(patches[i]);
928 }
929 free(patch_sha_str);
930 free(patches);
931
932 return StringValue(strdup(result == 0 ? "t" : ""));
933}
934
935// apply_patch_check(file, [sha1_1, ...])
936Value* ApplyPatchCheckFn(const char* name, State* state,
937 int argc, Expr* argv[]) {
938 if (argc < 1) {
939 return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
940 name, argc);
941 }
942
943 char* filename;
944 if (ReadArgs(state, argv, 1, &filename) < 0) {
945 return NULL;
946 }
947
948 int patchcount = argc-1;
949 char** sha1s = ReadVarArgs(state, argc-1, argv+1);
950
951 int result = applypatch_check(filename, patchcount, sha1s);
952
953 int i;
954 for (i = 0; i < patchcount; ++i) {
955 free(sha1s[i]);
956 }
957 free(sha1s);
958
959 return StringValue(strdup(result == 0 ? "t" : ""));
Doug Zongker8edb00c2009-06-11 17:21:44 -0700960}
961
Doug Zongker512536a2010-02-17 16:11:44 -0800962Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700963 char** args = ReadVarArgs(state, argc, argv);
964 if (args == NULL) {
965 return NULL;
966 }
967
968 int size = 0;
969 int i;
970 for (i = 0; i < argc; ++i) {
971 size += strlen(args[i]);
972 }
973 char* buffer = malloc(size+1);
974 size = 0;
975 for (i = 0; i < argc; ++i) {
976 strcpy(buffer+size, args[i]);
977 size += strlen(args[i]);
978 free(args[i]);
979 }
980 free(args);
981 buffer[size] = '\0';
982
983 char* line = strtok(buffer, "\n");
984 while (line) {
985 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
986 "ui_print %s\n", line);
987 line = strtok(NULL, "\n");
988 }
989 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
990
Doug Zongker512536a2010-02-17 16:11:44 -0800991 return StringValue(buffer);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700992}
993
Doug Zongker512536a2010-02-17 16:11:44 -0800994Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkera3f89ea2009-09-10 14:10:48 -0700995 if (argc < 1) {
996 return ErrorAbort(state, "%s() expects at least 1 arg", name);
997 }
998 char** args = ReadVarArgs(state, argc, argv);
999 if (args == NULL) {
1000 return NULL;
1001 }
1002
1003 char** args2 = malloc(sizeof(char*) * (argc+1));
1004 memcpy(args2, args, sizeof(char*) * argc);
1005 args2[argc] = NULL;
1006
1007 fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc);
1008
1009 pid_t child = fork();
1010 if (child == 0) {
1011 execv(args2[0], args2);
1012 fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno));
1013 _exit(1);
1014 }
1015 int status;
1016 waitpid(child, &status, 0);
1017 if (WIFEXITED(status)) {
1018 if (WEXITSTATUS(status) != 0) {
1019 fprintf(stderr, "run_program: child exited with status %d\n",
1020 WEXITSTATUS(status));
1021 }
1022 } else if (WIFSIGNALED(status)) {
1023 fprintf(stderr, "run_program: child terminated by signal %d\n",
1024 WTERMSIG(status));
1025 }
1026
1027 int i;
1028 for (i = 0; i < argc; ++i) {
1029 free(args[i]);
1030 }
1031 free(args);
1032 free(args2);
1033
1034 char buffer[20];
1035 sprintf(buffer, "%d", status);
1036
Doug Zongker512536a2010-02-17 16:11:44 -08001037 return StringValue(strdup(buffer));
Doug Zongkera3f89ea2009-09-10 14:10:48 -07001038}
1039
Doug Zongker512536a2010-02-17 16:11:44 -08001040// Take a sha-1 digest and return it as a newly-allocated hex string.
1041static char* PrintSha1(uint8_t* digest) {
1042 char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
1043 int i;
1044 const char* alphabet = "0123456789abcdef";
1045 for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
1046 buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
1047 buffer[i*2+1] = alphabet[digest[i] & 0xf];
1048 }
1049 buffer[i*2] = '\0';
1050 return buffer;
1051}
1052
1053// sha1_check(data)
1054// to return the sha1 of the data (given in the format returned by
1055// read_file).
1056//
1057// sha1_check(data, sha1_hex, [sha1_hex, ...])
1058// returns the sha1 of the file if it matches any of the hex
1059// strings passed, or "" if it does not equal any of them.
1060//
1061Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
1062 if (argc < 1) {
1063 return ErrorAbort(state, "%s() expects at least 1 arg", name);
1064 }
1065
1066 Value** args = ReadValueVarArgs(state, argc, argv);
1067 if (args == NULL) {
1068 return NULL;
1069 }
1070
1071 if (args[0]->size < 0) {
1072 fprintf(stderr, "%s(): no file contents received", name);
1073 return StringValue(strdup(""));
1074 }
1075 uint8_t digest[SHA_DIGEST_SIZE];
1076 SHA(args[0]->data, args[0]->size, digest);
1077 FreeValue(args[0]);
1078
1079 if (argc == 1) {
1080 return StringValue(PrintSha1(digest));
1081 }
1082
1083 int i;
1084 uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE);
1085 for (i = 1; i < argc; ++i) {
1086 if (args[i]->type != VAL_STRING) {
1087 fprintf(stderr, "%s(): arg %d is not a string; skipping",
1088 name, i);
1089 } else if (ParseSha1(args[i]->data, arg_digest) != 0) {
1090 // Warn about bad args and skip them.
1091 fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping",
1092 name, args[i]->data);
1093 } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
1094 break;
1095 }
1096 FreeValue(args[i]);
1097 }
1098 if (i >= argc) {
1099 // Didn't match any of the hex strings; return false.
1100 return StringValue(strdup(""));
1101 }
1102 // Found a match; free all the remaining arguments and return the
1103 // matched one.
1104 int j;
1105 for (j = i+1; j < argc; ++j) {
1106 FreeValue(args[j]);
1107 }
1108 return args[i];
1109}
1110
Hristo Bojinovdb314d62010-08-02 10:29:49 -07001111// Read a local file and return its contents (the Value* returned
Doug Zongker512536a2010-02-17 16:11:44 -08001112// is actually a FileContents*).
1113Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
1114 if (argc != 1) {
1115 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
1116 }
1117 char* filename;
1118 if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
1119
1120 Value* v = malloc(sizeof(Value));
1121 v->type = VAL_BLOB;
1122
1123 FileContents fc;
Hristo Bojinovdb314d62010-08-02 10:29:49 -07001124 if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) {
Doug Zongker512536a2010-02-17 16:11:44 -08001125 ErrorAbort(state, "%s() loading \"%s\" failed: %s",
1126 name, filename, strerror(errno));
1127 free(filename);
1128 free(v);
1129 free(fc.data);
1130 return NULL;
1131 }
1132
1133 v->size = fc.size;
1134 v->data = (char*)fc.data;
1135
1136 free(filename);
1137 return v;
1138}
Doug Zongker8edb00c2009-06-11 17:21:44 -07001139
Doug Zongker9931f7f2009-06-10 14:11:53 -07001140void RegisterInstallFunctions() {
1141 RegisterFunction("mount", MountFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001142 RegisterFunction("is_mounted", IsMountedFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001143 RegisterFunction("unmount", UnmountFn);
1144 RegisterFunction("format", FormatFn);
1145 RegisterFunction("show_progress", ShowProgressFn);
Doug Zongkerfbf3c102009-06-24 09:36:20 -07001146 RegisterFunction("set_progress", SetProgressFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001147 RegisterFunction("delete", DeleteFn);
1148 RegisterFunction("delete_recursive", DeleteFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001149 RegisterFunction("package_extract_dir", PackageExtractDirFn);
1150 RegisterFunction("package_extract_file", PackageExtractFileFn);
Hristo Bojinovdb314d62010-08-02 10:29:49 -07001151 RegisterFunction("retouch_binaries", RetouchBinariesFn);
1152 RegisterFunction("undo_retouch_binaries", UndoRetouchBinariesFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001153 RegisterFunction("symlink", SymlinkFn);
1154 RegisterFunction("set_perm", SetPermFn);
1155 RegisterFunction("set_perm_recursive", SetPermFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001156
1157 RegisterFunction("getprop", GetPropFn);
Doug Zongker47cace92009-06-18 10:11:50 -07001158 RegisterFunction("file_getprop", FileGetPropFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001159 RegisterFunction("write_raw_image", WriteRawImageFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -07001160
1161 RegisterFunction("apply_patch", ApplyPatchFn);
Doug Zongkerc4351c72010-02-22 14:46:32 -08001162 RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
1163 RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
Doug Zongkerd9c9d102009-06-12 12:24:39 -07001164
Doug Zongker512536a2010-02-17 16:11:44 -08001165 RegisterFunction("read_file", ReadFileFn);
1166 RegisterFunction("sha1_check", Sha1CheckFn);
1167
Doug Zongkerd9c9d102009-06-12 12:24:39 -07001168 RegisterFunction("ui_print", UIPrintFn);
Doug Zongkera3f89ea2009-09-10 14:10:48 -07001169
1170 RegisterFunction("run_program", RunProgramFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -07001171}