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