blob: c71781a42bb19bd5bc42d0321a92f9457d0d7044 [file] [log] [blame]
Doug Zongker9931f7f2009-06-10 14:11:53 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
Shashank Mittal815ca5d2010-07-27 11:09:19 -07003 * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
Doug Zongker9931f7f2009-06-10 14:11:53 -07004 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Doug Zongkerfbf3c102009-06-24 09:36:20 -070018#include <ctype.h>
Doug Zongker9931f7f2009-06-10 14:11:53 -070019#include <errno.h>
20#include <stdarg.h>
Doug Zongkerfbf3c102009-06-24 09:36:20 -070021#include <stdio.h>
Doug Zongker9931f7f2009-06-10 14:11:53 -070022#include <stdlib.h>
23#include <string.h>
24#include <sys/mount.h>
25#include <sys/stat.h>
26#include <sys/types.h>
Doug Zongkera3f89ea2009-09-10 14:10:48 -070027#include <sys/wait.h>
Doug Zongker9931f7f2009-06-10 14:11:53 -070028#include <unistd.h>
29
Doug Zongker8edb00c2009-06-11 17:21:44 -070030#include "cutils/misc.h"
31#include "cutils/properties.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070032#include "edify/expr.h"
Doug Zongker512536a2010-02-17 16:11:44 -080033#include "mincrypt/sha.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070034#include "minzip/DirUtil.h"
Koushik Dutta1b867542010-11-10 23:52:09 -080035#include "mounts.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070036#include "mtdutils/mtdutils.h"
Shashank Mittal815ca5d2010-07-27 11:09:19 -070037#include "mmcutils/mmcutils.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070038#include "updater.h"
Doug Zongker512536a2010-02-17 16:11:44 -080039#include "applypatch/applypatch.h"
Doug Zongker8edb00c2009-06-11 17:21:44 -070040
Koushik Dutta1b867542010-11-10 23:52:09 -080041#ifndef BOARD_USES_MMCUTILS
42#define DEFAULT_FILESYSTEM "yaffs2"
43#else
44#define DEFAULT_FILESYSTEM "ext3"
45#endif
46
Doug Zongker9931f7f2009-06-10 14:11:53 -070047// mount(type, location, mount_point)
48//
49// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem
50// type="vfat" location="/dev/block/<whatever>" to mount a device
Doug Zongker512536a2010-02-17 16:11:44 -080051Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070052 char* result = NULL;
53 if (argc != 3) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070054 return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -070055 }
56 char* type;
57 char* location;
58 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -070059 if (ReadArgs(state, argv, 3, &type, &location, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070060 return NULL;
61 }
62
63 if (strlen(type) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070064 ErrorAbort(state, "type argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070065 goto done;
66 }
67 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070068 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070069 goto done;
70 }
71 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070072 ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070073 goto done;
74 }
75
76 mkdir(mount_point, 0755);
77
Koushik Dutta1b867542010-11-10 23:52:09 -080078 if (strcmp(type, "MTD") == 0 || strcmp(type, "MMC") == 0) {
79 if (0 == mount_partition(location, mount_point, DEFAULT_FILESYSTEM, 0))
80 result = mount_point;
81 else
Doug Zongker9931f7f2009-06-10 14:11:53 -070082 result = strdup("");
Doug Zongker9931f7f2009-06-10 14:11:53 -070083 } else {
84 if (mount(location, mount_point, type,
85 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
Doug Zongker60babf82009-09-18 15:11:24 -070086 fprintf(stderr, "%s: failed to mount %s at %s: %s\n",
87 name, location, mount_point, strerror(errno));
Doug Zongker9931f7f2009-06-10 14:11:53 -070088 result = strdup("");
89 } else {
90 result = mount_point;
91 }
92 }
93
94done:
95 free(type);
96 free(location);
97 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -080098 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -070099}
100
Doug Zongker8edb00c2009-06-11 17:21:44 -0700101
102// is_mounted(mount_point)
Doug Zongker512536a2010-02-17 16:11:44 -0800103Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700104 char* result = NULL;
105 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700106 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700107 }
108 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700109 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700110 return NULL;
111 }
112 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700113 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker8edb00c2009-06-11 17:21:44 -0700114 goto done;
115 }
116
117 scan_mounted_volumes();
118 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
119 if (vol == NULL) {
120 result = strdup("");
121 } else {
122 result = mount_point;
123 }
124
125done:
126 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800127 return StringValue(result);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700128}
129
130
Doug Zongker512536a2010-02-17 16:11:44 -0800131Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700132 char* result = NULL;
133 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700134 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700135 }
136 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700137 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700138 return NULL;
139 }
140 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700141 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker9931f7f2009-06-10 14:11:53 -0700142 goto done;
143 }
144
145 scan_mounted_volumes();
146 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
147 if (vol == NULL) {
148 fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
149 result = strdup("");
150 } else {
151 unmount_mounted_volume(vol);
152 result = mount_point;
153 }
154
155done:
156 if (result != mount_point) free(mount_point);
Doug Zongker512536a2010-02-17 16:11:44 -0800157 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700158}
Doug Zongker8edb00c2009-06-11 17:21:44 -0700159
160
Doug Zongker9931f7f2009-06-10 14:11:53 -0700161// format(type, location)
162//
163// type="MTD" location=partition
Doug Zongker512536a2010-02-17 16:11:44 -0800164Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700165 char* result = NULL;
166 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700167 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700168 }
169 char* type;
170 char* location;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700171 if (ReadArgs(state, argv, 2, &type, &location) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700172 return NULL;
173 }
174
175 if (strlen(type) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700176 ErrorAbort(state, "type argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700177 goto done;
178 }
179 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700180 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700181 goto done;
182 }
183
Koushik Dutta1b867542010-11-10 23:52:09 -0800184 if (strcmp(type, "MTD") == 0 || strcmp(type, "MMC") == 0) {
185 if (0 != erase_partition(location, NULL)) {
Shashank Mittal815ca5d2010-07-27 11:09:19 -0700186 result = strdup("");
187 goto done;
188 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700189 } else {
190 fprintf(stderr, "%s: unsupported type \"%s\"", name, type);
191 }
Shashank Mittal815ca5d2010-07-27 11:09:19 -0700192 result = location;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700193done:
194 free(type);
195 if (result != location) free(location);
Doug Zongker512536a2010-02-17 16:11:44 -0800196 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700197}
198
Doug Zongker8edb00c2009-06-11 17:21:44 -0700199
Doug Zongker512536a2010-02-17 16:11:44 -0800200Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700201 char** paths = malloc(argc * sizeof(char*));
202 int i;
203 for (i = 0; i < argc; ++i) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700204 paths[i] = Evaluate(state, argv[i]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700205 if (paths[i] == NULL) {
206 int j;
207 for (j = 0; j < i; ++i) {
208 free(paths[j]);
209 }
210 free(paths);
211 return NULL;
212 }
213 }
214
215 bool recursive = (strcmp(name, "delete_recursive") == 0);
216
217 int success = 0;
218 for (i = 0; i < argc; ++i) {
219 if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
220 ++success;
221 free(paths[i]);
222 }
223 free(paths);
224
225 char buffer[10];
226 sprintf(buffer, "%d", success);
Doug Zongker512536a2010-02-17 16:11:44 -0800227 return StringValue(strdup(buffer));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700228}
229
Doug Zongker8edb00c2009-06-11 17:21:44 -0700230
Doug Zongker512536a2010-02-17 16:11:44 -0800231Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700232 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700233 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700234 }
235 char* frac_str;
236 char* sec_str;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700237 if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700238 return NULL;
239 }
240
241 double frac = strtod(frac_str, NULL);
242 int sec = strtol(sec_str, NULL, 10);
243
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700244 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700245 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
246
Doug Zongker9931f7f2009-06-10 14:11:53 -0700247 free(sec_str);
Doug Zongker512536a2010-02-17 16:11:44 -0800248 return StringValue(frac_str);
Doug Zongkerfbf3c102009-06-24 09:36:20 -0700249}
250
Doug Zongker512536a2010-02-17 16:11:44 -0800251Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerfbf3c102009-06-24 09:36:20 -0700252 if (argc != 1) {
253 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
254 }
255 char* frac_str;
256 if (ReadArgs(state, argv, 1, &frac_str) < 0) {
257 return NULL;
258 }
259
260 double frac = strtod(frac_str, NULL);
261
262 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
263 fprintf(ui->cmd_pipe, "set_progress %f\n", frac);
264
Doug Zongker512536a2010-02-17 16:11:44 -0800265 return StringValue(frac_str);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700266}
267
Doug Zongker8edb00c2009-06-11 17:21:44 -0700268// package_extract_dir(package_path, destination_path)
Doug Zongker512536a2010-02-17 16:11:44 -0800269Value* PackageExtractDirFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700270 int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700271 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700272 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700273 }
274 char* zip_path;
275 char* dest_path;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700276 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700277
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700278 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700279
280 // To create a consistent system image, never use the clock for timestamps.
281 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
282
283 bool success = mzExtractRecursive(za, zip_path, dest_path,
284 MZ_EXTRACT_FILES_ONLY, &timestamp,
285 NULL, NULL);
286 free(zip_path);
287 free(dest_path);
Doug Zongker512536a2010-02-17 16:11:44 -0800288 return StringValue(strdup(success ? "t" : ""));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700289}
290
Doug Zongker8edb00c2009-06-11 17:21:44 -0700291
292// package_extract_file(package_path, destination_path)
Doug Zongker6aece332010-02-01 14:40:12 -0800293// or
294// package_extract_file(package_path)
295// to return the entire contents of the file as the result of this
Doug Zongker512536a2010-02-17 16:11:44 -0800296// function (the char* returned is actually a FileContents*).
297Value* PackageExtractFileFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700298 int argc, Expr* argv[]) {
Doug Zongker6aece332010-02-01 14:40:12 -0800299 if (argc != 1 && argc != 2) {
300 return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
301 name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700302 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700303 bool success = false;
Doug Zongker6aece332010-02-01 14:40:12 -0800304 if (argc == 2) {
305 // The two-argument version extracts to a file.
Doug Zongker8edb00c2009-06-11 17:21:44 -0700306
Doug Zongker6aece332010-02-01 14:40:12 -0800307 char* zip_path;
308 char* dest_path;
309 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
310
311 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
312 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
313 if (entry == NULL) {
314 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
315 goto done2;
316 }
317
318 FILE* f = fopen(dest_path, "wb");
319 if (f == NULL) {
320 fprintf(stderr, "%s: can't open %s for write: %s\n",
321 name, dest_path, strerror(errno));
322 goto done2;
323 }
324 success = mzExtractZipEntryToFile(za, entry, fileno(f));
325 fclose(f);
326
327 done2:
328 free(zip_path);
329 free(dest_path);
Doug Zongker512536a2010-02-17 16:11:44 -0800330 return StringValue(strdup(success ? "t" : ""));
Doug Zongker6aece332010-02-01 14:40:12 -0800331 } else {
332 // The one-argument version returns the contents of the file
333 // as the result.
334
335 char* zip_path;
Doug Zongker512536a2010-02-17 16:11:44 -0800336 Value* v = malloc(sizeof(Value));
337 v->type = VAL_BLOB;
338 v->size = -1;
339 v->data = NULL;
Doug Zongker6aece332010-02-01 14:40:12 -0800340
341 if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
342
343 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
344 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
345 if (entry == NULL) {
346 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
347 goto done1;
348 }
349
Doug Zongker512536a2010-02-17 16:11:44 -0800350 v->size = mzGetZipEntryUncompLen(entry);
351 v->data = malloc(v->size);
352 if (v->data == NULL) {
Doug Zongker6aece332010-02-01 14:40:12 -0800353 fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n",
Doug Zongker512536a2010-02-17 16:11:44 -0800354 name, (long)v->size, zip_path);
Doug Zongker6aece332010-02-01 14:40:12 -0800355 goto done1;
356 }
357
Doug Zongker512536a2010-02-17 16:11:44 -0800358 success = mzExtractZipEntryToBuffer(za, entry,
359 (unsigned char *)v->data);
Doug Zongker6aece332010-02-01 14:40:12 -0800360
361 done1:
362 free(zip_path);
363 if (!success) {
Doug Zongker512536a2010-02-17 16:11:44 -0800364 free(v->data);
365 v->data = NULL;
366 v->size = -1;
Doug Zongker6aece332010-02-01 14:40:12 -0800367 }
Doug Zongker512536a2010-02-17 16:11:44 -0800368 return v;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700369 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700370}
371
372
Doug Zongker9931f7f2009-06-10 14:11:53 -0700373// symlink target src1 src2 ...
Doug Zongker60babf82009-09-18 15:11:24 -0700374// unlinks any previously existing src1, src2, etc before creating symlinks.
Doug Zongker512536a2010-02-17 16:11:44 -0800375Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700376 if (argc == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700377 return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700378 }
379 char* target;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700380 target = Evaluate(state, argv[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700381 if (target == NULL) return NULL;
382
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700383 char** srcs = ReadVarArgs(state, argc-1, argv+1);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700384 if (srcs == NULL) {
385 free(target);
386 return NULL;
387 }
388
389 int i;
390 for (i = 0; i < argc-1; ++i) {
Doug Zongker60babf82009-09-18 15:11:24 -0700391 if (unlink(srcs[i]) < 0) {
392 if (errno != ENOENT) {
393 fprintf(stderr, "%s: failed to remove %s: %s\n",
394 name, srcs[i], strerror(errno));
395 }
396 }
397 if (symlink(target, srcs[i]) < 0) {
398 fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
399 name, srcs[i], target, strerror(errno));
400 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700401 free(srcs[i]);
402 }
403 free(srcs);
Doug Zongker512536a2010-02-17 16:11:44 -0800404 return StringValue(strdup(""));
Doug Zongker9931f7f2009-06-10 14:11:53 -0700405}
406
Doug Zongker8edb00c2009-06-11 17:21:44 -0700407
Doug Zongker512536a2010-02-17 16:11:44 -0800408Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700409 char* result = NULL;
410 bool recursive = (strcmp(name, "set_perm_recursive") == 0);
411
412 int min_args = 4 + (recursive ? 1 : 0);
413 if (argc < min_args) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700414 return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700415 }
416
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700417 char** args = ReadVarArgs(state, argc, argv);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700418 if (args == NULL) return NULL;
419
420 char* end;
421 int i;
422
423 int uid = strtoul(args[0], &end, 0);
424 if (*end != '\0' || args[0][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700425 ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700426 goto done;
427 }
428
429 int gid = strtoul(args[1], &end, 0);
430 if (*end != '\0' || args[1][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700431 ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700432 goto done;
433 }
434
435 if (recursive) {
436 int dir_mode = strtoul(args[2], &end, 0);
437 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700438 ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700439 goto done;
440 }
441
442 int file_mode = strtoul(args[3], &end, 0);
443 if (*end != '\0' || args[3][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700444 ErrorAbort(state, "%s: \"%s\" not a valid filemode",
Doug Zongker9931f7f2009-06-10 14:11:53 -0700445 name, args[3]);
446 goto done;
447 }
448
449 for (i = 4; i < argc; ++i) {
450 dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
451 }
452 } else {
453 int mode = strtoul(args[2], &end, 0);
454 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700455 ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700456 goto done;
457 }
458
Doug Zongker0bbfe3d2009-06-25 13:37:31 -0700459 for (i = 3; i < argc; ++i) {
Doug Zongker60babf82009-09-18 15:11:24 -0700460 if (chown(args[i], uid, gid) < 0) {
461 fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n",
462 name, args[i], uid, gid, strerror(errno));
463 }
464 if (chmod(args[i], mode) < 0) {
465 fprintf(stderr, "%s: chmod of %s to %o failed: %s\n",
466 name, args[i], mode, strerror(errno));
467 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700468 }
469 }
470 result = strdup("");
471
472done:
473 for (i = 0; i < argc; ++i) {
474 free(args[i]);
475 }
476 free(args);
477
Doug Zongker512536a2010-02-17 16:11:44 -0800478 return StringValue(result);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700479}
480
Doug Zongker8edb00c2009-06-11 17:21:44 -0700481
Doug Zongker512536a2010-02-17 16:11:44 -0800482Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700483 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700484 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700485 }
486 char* key;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700487 key = Evaluate(state, argv[0]);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700488 if (key == NULL) return NULL;
489
490 char value[PROPERTY_VALUE_MAX];
491 property_get(key, value, "");
492 free(key);
493
Doug Zongker512536a2010-02-17 16:11:44 -0800494 return StringValue(strdup(value));
Doug Zongker8edb00c2009-06-11 17:21:44 -0700495}
496
497
Doug Zongker47cace92009-06-18 10:11:50 -0700498// file_getprop(file, key)
499//
500// interprets 'file' as a getprop-style file (key=value pairs, one
501// per line, # comment lines and blank lines okay), and returns the value
502// for 'key' (or "" if it isn't defined).
Doug Zongker512536a2010-02-17 16:11:44 -0800503Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker47cace92009-06-18 10:11:50 -0700504 char* result = NULL;
505 char* buffer = NULL;
506 char* filename;
507 char* key;
508 if (ReadArgs(state, argv, 2, &filename, &key) < 0) {
509 return NULL;
510 }
511
512 struct stat st;
513 if (stat(filename, &st) < 0) {
514 ErrorAbort(state, "%s: failed to stat \"%s\": %s",
515 name, filename, strerror(errno));
516 goto done;
517 }
518
519#define MAX_FILE_GETPROP_SIZE 65536
520
521 if (st.st_size > MAX_FILE_GETPROP_SIZE) {
522 ErrorAbort(state, "%s too large for %s (max %d)",
523 filename, name, MAX_FILE_GETPROP_SIZE);
524 goto done;
525 }
526
527 buffer = malloc(st.st_size+1);
528 if (buffer == NULL) {
529 ErrorAbort(state, "%s: failed to alloc %d bytes", name, st.st_size+1);
530 goto done;
531 }
532
533 FILE* f = fopen(filename, "rb");
534 if (f == NULL) {
535 ErrorAbort(state, "%s: failed to open %s: %s",
536 name, filename, strerror(errno));
537 goto done;
538 }
539
540 if (fread(buffer, 1, st.st_size, f) != st.st_size) {
541 ErrorAbort(state, "%s: failed to read %d bytes from %s",
542 name, st.st_size+1, filename);
543 fclose(f);
544 goto done;
545 }
546 buffer[st.st_size] = '\0';
547
548 fclose(f);
549
550 char* line = strtok(buffer, "\n");
551 do {
552 // skip whitespace at start of line
553 while (*line && isspace(*line)) ++line;
554
555 // comment or blank line: skip to next line
556 if (*line == '\0' || *line == '#') continue;
557
558 char* equal = strchr(line, '=');
559 if (equal == NULL) {
560 ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
561 name, line, filename);
562 goto done;
563 }
564
565 // trim whitespace between key and '='
566 char* key_end = equal-1;
567 while (key_end > line && isspace(*key_end)) --key_end;
568 key_end[1] = '\0';
569
570 // not the key we're looking for
571 if (strcmp(key, line) != 0) continue;
572
573 // skip whitespace after the '=' to the start of the value
574 char* val_start = equal+1;
575 while(*val_start && isspace(*val_start)) ++val_start;
576
577 // trim trailing whitespace
578 char* val_end = val_start + strlen(val_start)-1;
579 while (val_end > val_start && isspace(*val_end)) --val_end;
580 val_end[1] = '\0';
581
582 result = strdup(val_start);
583 break;
584
585 } while ((line = strtok(NULL, "\n")));
586
587 if (result == NULL) result = strdup("");
588
589 done:
590 free(filename);
591 free(key);
592 free(buffer);
Doug Zongker512536a2010-02-17 16:11:44 -0800593 return StringValue(result);
Doug Zongker47cace92009-06-18 10:11:50 -0700594}
595
596
Doug Zongker8edb00c2009-06-11 17:21:44 -0700597static bool write_raw_image_cb(const unsigned char* data,
598 int data_len, void* ctx) {
599 int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
600 if (r == data_len) return true;
601 fprintf(stderr, "%s\n", strerror(errno));
602 return false;
603}
604
605// write_raw_image(file, partition)
Doug Zongker512536a2010-02-17 16:11:44 -0800606Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700607 char* result = NULL;
608
609 char* partition;
610 char* filename;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700611 if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700612 return NULL;
613 }
614
615 if (strlen(partition) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700616 ErrorAbort(state, "partition argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700617 goto done;
618 }
619 if (strlen(filename) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700620 ErrorAbort(state, "file argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700621 goto done;
622 }
623
Koushik Dutta1b867542010-11-10 23:52:09 -0800624 if (0 == restore_raw_partition(partition, filename))
625 result = strdup(partition);
626 else
Doug Zongker8edb00c2009-06-11 17:21:44 -0700627 result = strdup("");
Doug Zongker8edb00c2009-06-11 17:21:44 -0700628
629done:
630 if (result != partition) free(partition);
631 free(filename);
Doug Zongker512536a2010-02-17 16:11:44 -0800632 return StringValue(result);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700633}
634
Doug Zongker8edb00c2009-06-11 17:21:44 -0700635// apply_patch_space(bytes)
Doug Zongkerc4351c72010-02-22 14:46:32 -0800636Value* ApplyPatchSpaceFn(const char* name, State* state,
637 int argc, Expr* argv[]) {
638 char* bytes_str;
639 if (ReadArgs(state, argv, 1, &bytes_str) < 0) {
640 return NULL;
641 }
642
643 char* endptr;
644 size_t bytes = strtol(bytes_str, &endptr, 10);
645 if (bytes == 0 && endptr == bytes_str) {
646 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
647 name, bytes_str);
648 free(bytes_str);
649 return NULL;
650 }
651
652 return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
653}
654
655
656// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
Doug Zongker512536a2010-02-17 16:11:44 -0800657Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800658 if (argc < 6 || (argc % 2) == 1) {
659 return ErrorAbort(state, "%s(): expected at least 6 args and an "
660 "even number, got %d",
661 name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700662 }
663
Doug Zongkerc4351c72010-02-22 14:46:32 -0800664 char* source_filename;
665 char* target_filename;
666 char* target_sha1;
667 char* target_size_str;
668 if (ReadArgs(state, argv, 4, &source_filename, &target_filename,
669 &target_sha1, &target_size_str) < 0) {
670 return NULL;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700671 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700672
Doug Zongkerc4351c72010-02-22 14:46:32 -0800673 char* endptr;
674 size_t target_size = strtol(target_size_str, &endptr, 10);
675 if (target_size == 0 && endptr == target_size_str) {
676 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count",
677 name, target_size_str);
678 free(source_filename);
679 free(target_filename);
680 free(target_sha1);
681 free(target_size_str);
682 return NULL;
683 }
684
685 int patchcount = (argc-4) / 2;
686 Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700687
688 int i;
Doug Zongkerc4351c72010-02-22 14:46:32 -0800689 for (i = 0; i < patchcount; ++i) {
690 if (patches[i*2]->type != VAL_STRING) {
691 ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
692 break;
693 }
694 if (patches[i*2+1]->type != VAL_BLOB) {
695 ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
696 break;
697 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700698 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800699 if (i != patchcount) {
700 for (i = 0; i < patchcount*2; ++i) {
701 FreeValue(patches[i]);
702 }
703 free(patches);
704 return NULL;
705 }
Doug Zongker8edb00c2009-06-11 17:21:44 -0700706
Doug Zongkerc4351c72010-02-22 14:46:32 -0800707 char** patch_sha_str = malloc(patchcount * sizeof(char*));
708 for (i = 0; i < patchcount; ++i) {
709 patch_sha_str[i] = patches[i*2]->data;
710 patches[i*2]->data = NULL;
711 FreeValue(patches[i*2]);
712 patches[i] = patches[i*2+1];
Doug Zongker8edb00c2009-06-11 17:21:44 -0700713 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800714
715 int result = applypatch(source_filename, target_filename,
716 target_sha1, target_size,
717 patchcount, patch_sha_str, patches);
718
719 for (i = 0; i < patchcount; ++i) {
720 FreeValue(patches[i]);
721 }
722 free(patch_sha_str);
723 free(patches);
724
725 return StringValue(strdup(result == 0 ? "t" : ""));
726}
727
728// apply_patch_check(file, [sha1_1, ...])
729Value* ApplyPatchCheckFn(const char* name, State* state,
730 int argc, Expr* argv[]) {
731 if (argc < 1) {
732 return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
733 name, argc);
734 }
735
736 char* filename;
737 if (ReadArgs(state, argv, 1, &filename) < 0) {
738 return NULL;
739 }
740
741 int patchcount = argc-1;
742 char** sha1s = ReadVarArgs(state, argc-1, argv+1);
743
744 int result = applypatch_check(filename, patchcount, sha1s);
745
746 int i;
747 for (i = 0; i < patchcount; ++i) {
748 free(sha1s[i]);
749 }
750 free(sha1s);
751
752 return StringValue(strdup(result == 0 ? "t" : ""));
Doug Zongker8edb00c2009-06-11 17:21:44 -0700753}
754
Doug Zongker512536a2010-02-17 16:11:44 -0800755Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700756 char** args = ReadVarArgs(state, argc, argv);
757 if (args == NULL) {
758 return NULL;
759 }
760
761 int size = 0;
762 int i;
763 for (i = 0; i < argc; ++i) {
764 size += strlen(args[i]);
765 }
766 char* buffer = malloc(size+1);
767 size = 0;
768 for (i = 0; i < argc; ++i) {
769 strcpy(buffer+size, args[i]);
770 size += strlen(args[i]);
771 free(args[i]);
772 }
773 free(args);
774 buffer[size] = '\0';
775
776 char* line = strtok(buffer, "\n");
777 while (line) {
778 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
779 "ui_print %s\n", line);
780 line = strtok(NULL, "\n");
781 }
782 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
783
Doug Zongker512536a2010-02-17 16:11:44 -0800784 return StringValue(buffer);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700785}
786
Doug Zongker512536a2010-02-17 16:11:44 -0800787Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkera3f89ea2009-09-10 14:10:48 -0700788 if (argc < 1) {
789 return ErrorAbort(state, "%s() expects at least 1 arg", name);
790 }
791 char** args = ReadVarArgs(state, argc, argv);
792 if (args == NULL) {
793 return NULL;
794 }
795
796 char** args2 = malloc(sizeof(char*) * (argc+1));
797 memcpy(args2, args, sizeof(char*) * argc);
798 args2[argc] = NULL;
799
800 fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc);
801
802 pid_t child = fork();
803 if (child == 0) {
804 execv(args2[0], args2);
805 fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno));
806 _exit(1);
807 }
808 int status;
809 waitpid(child, &status, 0);
810 if (WIFEXITED(status)) {
811 if (WEXITSTATUS(status) != 0) {
812 fprintf(stderr, "run_program: child exited with status %d\n",
813 WEXITSTATUS(status));
814 }
815 } else if (WIFSIGNALED(status)) {
816 fprintf(stderr, "run_program: child terminated by signal %d\n",
817 WTERMSIG(status));
818 }
819
820 int i;
821 for (i = 0; i < argc; ++i) {
822 free(args[i]);
823 }
824 free(args);
825 free(args2);
826
827 char buffer[20];
828 sprintf(buffer, "%d", status);
829
Doug Zongker512536a2010-02-17 16:11:44 -0800830 return StringValue(strdup(buffer));
Doug Zongkera3f89ea2009-09-10 14:10:48 -0700831}
832
Doug Zongker512536a2010-02-17 16:11:44 -0800833// Take a sha-1 digest and return it as a newly-allocated hex string.
834static char* PrintSha1(uint8_t* digest) {
835 char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
836 int i;
837 const char* alphabet = "0123456789abcdef";
838 for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
839 buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
840 buffer[i*2+1] = alphabet[digest[i] & 0xf];
841 }
842 buffer[i*2] = '\0';
843 return buffer;
844}
845
846// sha1_check(data)
847// to return the sha1 of the data (given in the format returned by
848// read_file).
849//
850// sha1_check(data, sha1_hex, [sha1_hex, ...])
851// returns the sha1 of the file if it matches any of the hex
852// strings passed, or "" if it does not equal any of them.
853//
854Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
855 if (argc < 1) {
856 return ErrorAbort(state, "%s() expects at least 1 arg", name);
857 }
858
859 Value** args = ReadValueVarArgs(state, argc, argv);
860 if (args == NULL) {
861 return NULL;
862 }
863
864 if (args[0]->size < 0) {
865 fprintf(stderr, "%s(): no file contents received", name);
866 return StringValue(strdup(""));
867 }
868 uint8_t digest[SHA_DIGEST_SIZE];
869 SHA(args[0]->data, args[0]->size, digest);
870 FreeValue(args[0]);
871
872 if (argc == 1) {
873 return StringValue(PrintSha1(digest));
874 }
875
876 int i;
877 uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE);
878 for (i = 1; i < argc; ++i) {
879 if (args[i]->type != VAL_STRING) {
880 fprintf(stderr, "%s(): arg %d is not a string; skipping",
881 name, i);
882 } else if (ParseSha1(args[i]->data, arg_digest) != 0) {
883 // Warn about bad args and skip them.
884 fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping",
885 name, args[i]->data);
886 } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
887 break;
888 }
889 FreeValue(args[i]);
890 }
891 if (i >= argc) {
892 // Didn't match any of the hex strings; return false.
893 return StringValue(strdup(""));
894 }
895 // Found a match; free all the remaining arguments and return the
896 // matched one.
897 int j;
898 for (j = i+1; j < argc; ++j) {
899 FreeValue(args[j]);
900 }
901 return args[i];
902}
903
904// Read a local file and return its contents (the char* returned
905// is actually a FileContents*).
906Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
907 if (argc != 1) {
908 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
909 }
910 char* filename;
911 if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
912
913 Value* v = malloc(sizeof(Value));
914 v->type = VAL_BLOB;
915
916 FileContents fc;
917 if (LoadFileContents(filename, &fc) != 0) {
918 ErrorAbort(state, "%s() loading \"%s\" failed: %s",
919 name, filename, strerror(errno));
920 free(filename);
921 free(v);
922 free(fc.data);
923 return NULL;
924 }
925
926 v->size = fc.size;
927 v->data = (char*)fc.data;
928
929 free(filename);
930 return v;
931}
Doug Zongker8edb00c2009-06-11 17:21:44 -0700932
Doug Zongker9931f7f2009-06-10 14:11:53 -0700933void RegisterInstallFunctions() {
934 RegisterFunction("mount", MountFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700935 RegisterFunction("is_mounted", IsMountedFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700936 RegisterFunction("unmount", UnmountFn);
937 RegisterFunction("format", FormatFn);
938 RegisterFunction("show_progress", ShowProgressFn);
Doug Zongkerfbf3c102009-06-24 09:36:20 -0700939 RegisterFunction("set_progress", SetProgressFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700940 RegisterFunction("delete", DeleteFn);
941 RegisterFunction("delete_recursive", DeleteFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700942 RegisterFunction("package_extract_dir", PackageExtractDirFn);
943 RegisterFunction("package_extract_file", PackageExtractFileFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700944 RegisterFunction("symlink", SymlinkFn);
945 RegisterFunction("set_perm", SetPermFn);
946 RegisterFunction("set_perm_recursive", SetPermFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700947
948 RegisterFunction("getprop", GetPropFn);
Doug Zongker47cace92009-06-18 10:11:50 -0700949 RegisterFunction("file_getprop", FileGetPropFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700950 RegisterFunction("write_raw_image", WriteRawImageFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700951
952 RegisterFunction("apply_patch", ApplyPatchFn);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800953 RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
954 RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700955
Doug Zongker512536a2010-02-17 16:11:44 -0800956 RegisterFunction("read_file", ReadFileFn);
957 RegisterFunction("sha1_check", Sha1CheckFn);
958
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700959 RegisterFunction("ui_print", UIPrintFn);
Doug Zongkera3f89ea2009-09-10 14:10:48 -0700960
961 RegisterFunction("run_program", RunProgramFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700962}