blob: 0bd09399ca9d0c6d0533aa3dff2ff5ca7d7a76e2 [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
17#include <stdio.h>
18#include <errno.h>
19#include <stdarg.h>
20#include <stdlib.h>
21#include <string.h>
22#include <sys/mount.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25#include <unistd.h>
26
Doug Zongker8edb00c2009-06-11 17:21:44 -070027#include "cutils/misc.h"
28#include "cutils/properties.h"
Doug Zongker9931f7f2009-06-10 14:11:53 -070029#include "edify/expr.h"
30#include "minzip/DirUtil.h"
31#include "mtdutils/mounts.h"
32#include "mtdutils/mtdutils.h"
33#include "updater.h"
34
Doug Zongker8edb00c2009-06-11 17:21:44 -070035
Doug Zongker9931f7f2009-06-10 14:11:53 -070036// mount(type, location, mount_point)
37//
38// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem
39// type="vfat" location="/dev/block/<whatever>" to mount a device
Doug Zongkerd9c9d102009-06-12 12:24:39 -070040char* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070041 char* result = NULL;
42 if (argc != 3) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070043 return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -070044 }
45 char* type;
46 char* location;
47 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -070048 if (ReadArgs(state, argv, 3, &type, &location, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070049 return NULL;
50 }
51
52 if (strlen(type) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070053 ErrorAbort(state, "type argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070054 goto done;
55 }
56 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070057 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070058 goto done;
59 }
60 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070061 ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -070062 goto done;
63 }
64
65 mkdir(mount_point, 0755);
66
67 if (strcmp(type, "MTD") == 0) {
68 mtd_scan_partitions();
69 const MtdPartition* mtd;
70 mtd = mtd_find_partition_by_name(location);
71 if (mtd == NULL) {
72 fprintf(stderr, "%s: no mtd partition named \"%s\"",
73 name, location);
74 result = strdup("");
75 goto done;
76 }
77 if (mtd_mount_partition(mtd, mount_point, "yaffs2", 0 /* rw */) != 0) {
78 fprintf(stderr, "mtd mount of %s failed: %s\n",
79 location, strerror(errno));
80 result = strdup("");
81 goto done;
82 }
83 result = mount_point;
84 } else {
85 if (mount(location, mount_point, type,
86 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
87 result = strdup("");
88 } else {
89 result = mount_point;
90 }
91 }
92
93done:
94 free(type);
95 free(location);
96 if (result != mount_point) free(mount_point);
97 return result;
98}
99
Doug Zongker8edb00c2009-06-11 17:21:44 -0700100
101// is_mounted(mount_point)
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700102char* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700103 char* result = NULL;
104 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700105 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700106 }
107 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700108 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700109 return NULL;
110 }
111 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700112 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker8edb00c2009-06-11 17:21:44 -0700113 goto done;
114 }
115
116 scan_mounted_volumes();
117 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
118 if (vol == NULL) {
119 result = strdup("");
120 } else {
121 result = mount_point;
122 }
123
124done:
125 if (result != mount_point) free(mount_point);
126 return result;
127}
128
129
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700130char* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700131 char* result = NULL;
132 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700133 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700134 }
135 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700136 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700137 return NULL;
138 }
139 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700140 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker9931f7f2009-06-10 14:11:53 -0700141 goto done;
142 }
143
144 scan_mounted_volumes();
145 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
146 if (vol == NULL) {
147 fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
148 result = strdup("");
149 } else {
150 unmount_mounted_volume(vol);
151 result = mount_point;
152 }
153
154done:
155 if (result != mount_point) free(mount_point);
156 return result;
157}
Doug Zongker8edb00c2009-06-11 17:21:44 -0700158
159
Doug Zongker9931f7f2009-06-10 14:11:53 -0700160// format(type, location)
161//
162// type="MTD" location=partition
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700163char* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700164 char* result = NULL;
165 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700166 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700167 }
168 char* type;
169 char* location;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700170 if (ReadArgs(state, argv, 2, &type, &location) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700171 return NULL;
172 }
173
174 if (strlen(type) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700175 ErrorAbort(state, "type argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700176 goto done;
177 }
178 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700179 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700180 goto done;
181 }
182
183 if (strcmp(type, "MTD") == 0) {
184 mtd_scan_partitions();
185 const MtdPartition* mtd = mtd_find_partition_by_name(location);
186 if (mtd == NULL) {
187 fprintf(stderr, "%s: no mtd partition named \"%s\"",
188 name, location);
189 result = strdup("");
190 goto done;
191 }
192 MtdWriteContext* ctx = mtd_write_partition(mtd);
193 if (ctx == NULL) {
194 fprintf(stderr, "%s: can't write \"%s\"", name, location);
195 result = strdup("");
196 goto done;
197 }
198 if (mtd_erase_blocks(ctx, -1) == -1) {
199 mtd_write_close(ctx);
200 fprintf(stderr, "%s: failed to erase \"%s\"", name, location);
201 result = strdup("");
202 goto done;
203 }
204 if (mtd_write_close(ctx) != 0) {
205 fprintf(stderr, "%s: failed to close \"%s\"", name, location);
206 result = strdup("");
207 goto done;
208 }
209 result = location;
210 } else {
211 fprintf(stderr, "%s: unsupported type \"%s\"", name, type);
212 }
213
214done:
215 free(type);
216 if (result != location) free(location);
217 return result;
218}
219
Doug Zongker8edb00c2009-06-11 17:21:44 -0700220
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700221char* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700222 char** paths = malloc(argc * sizeof(char*));
223 int i;
224 for (i = 0; i < argc; ++i) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700225 paths[i] = Evaluate(state, argv[i]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700226 if (paths[i] == NULL) {
227 int j;
228 for (j = 0; j < i; ++i) {
229 free(paths[j]);
230 }
231 free(paths);
232 return NULL;
233 }
234 }
235
236 bool recursive = (strcmp(name, "delete_recursive") == 0);
237
238 int success = 0;
239 for (i = 0; i < argc; ++i) {
240 if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
241 ++success;
242 free(paths[i]);
243 }
244 free(paths);
245
246 char buffer[10];
247 sprintf(buffer, "%d", success);
248 return strdup(buffer);
249}
250
Doug Zongker8edb00c2009-06-11 17:21:44 -0700251
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700252char* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700253 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700254 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700255 }
256 char* frac_str;
257 char* sec_str;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700258 if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700259 return NULL;
260 }
261
262 double frac = strtod(frac_str, NULL);
263 int sec = strtol(sec_str, NULL, 10);
264
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700265 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700266 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
267
268 free(frac_str);
269 free(sec_str);
270 return strdup("");
271}
272
Doug Zongker8edb00c2009-06-11 17:21:44 -0700273// package_extract_dir(package_path, destination_path)
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700274char* PackageExtractDirFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700275 int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700276 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700277 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700278 }
279 char* zip_path;
280 char* dest_path;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700281 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700282
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700283 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700284
285 // To create a consistent system image, never use the clock for timestamps.
286 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
287
288 bool success = mzExtractRecursive(za, zip_path, dest_path,
289 MZ_EXTRACT_FILES_ONLY, &timestamp,
290 NULL, NULL);
291 free(zip_path);
292 free(dest_path);
293 return strdup(success ? "t" : "");
294}
295
Doug Zongker8edb00c2009-06-11 17:21:44 -0700296
297// package_extract_file(package_path, destination_path)
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700298char* PackageExtractFileFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700299 int argc, Expr* argv[]) {
300 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700301 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700302 }
303 char* zip_path;
304 char* dest_path;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700305 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700306
307 bool success = false;
308
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700309 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700310 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
311 if (entry == NULL) {
312 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
313 goto done;
314 }
315
316 FILE* f = fopen(dest_path, "wb");
317 if (f == NULL) {
318 fprintf(stderr, "%s: can't open %s for write: %s\n",
319 name, dest_path, strerror(errno));
320 goto done;
321 }
322 success = mzExtractZipEntryToFile(za, entry, fileno(f));
323 fclose(f);
324
325 done:
326 free(zip_path);
327 free(dest_path);
328 return strdup(success ? "t" : "");
329}
330
331
Doug Zongker9931f7f2009-06-10 14:11:53 -0700332// symlink target src1 src2 ...
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700333char* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700334 if (argc == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700335 return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700336 }
337 char* target;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700338 target = Evaluate(state, argv[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700339 if (target == NULL) return NULL;
340
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700341 char** srcs = ReadVarArgs(state, argc-1, argv+1);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700342 if (srcs == NULL) {
343 free(target);
344 return NULL;
345 }
346
347 int i;
348 for (i = 0; i < argc-1; ++i) {
349 symlink(target, srcs[i]);
350 free(srcs[i]);
351 }
352 free(srcs);
353 return strdup("");
354}
355
Doug Zongker8edb00c2009-06-11 17:21:44 -0700356
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700357char* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700358 char* result = NULL;
359 bool recursive = (strcmp(name, "set_perm_recursive") == 0);
360
361 int min_args = 4 + (recursive ? 1 : 0);
362 if (argc < min_args) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700363 return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700364 }
365
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700366 char** args = ReadVarArgs(state, argc, argv);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700367 if (args == NULL) return NULL;
368
369 char* end;
370 int i;
371
372 int uid = strtoul(args[0], &end, 0);
373 if (*end != '\0' || args[0][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700374 ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700375 goto done;
376 }
377
378 int gid = strtoul(args[1], &end, 0);
379 if (*end != '\0' || args[1][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700380 ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700381 goto done;
382 }
383
384 if (recursive) {
385 int dir_mode = strtoul(args[2], &end, 0);
386 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700387 ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700388 goto done;
389 }
390
391 int file_mode = strtoul(args[3], &end, 0);
392 if (*end != '\0' || args[3][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700393 ErrorAbort(state, "%s: \"%s\" not a valid filemode",
Doug Zongker9931f7f2009-06-10 14:11:53 -0700394 name, args[3]);
395 goto done;
396 }
397
398 for (i = 4; i < argc; ++i) {
399 dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
400 }
401 } else {
402 int mode = strtoul(args[2], &end, 0);
403 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700404 ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700405 goto done;
406 }
407
408 for (i = 4; i < argc; ++i) {
409 chown(args[i], uid, gid);
410 chmod(args[i], mode);
411 }
412 }
413 result = strdup("");
414
415done:
416 for (i = 0; i < argc; ++i) {
417 free(args[i]);
418 }
419 free(args);
420
421 return result;
422}
423
Doug Zongker8edb00c2009-06-11 17:21:44 -0700424
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700425char* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700426 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700427 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700428 }
429 char* key;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700430 key = Evaluate(state, argv[0]);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700431 if (key == NULL) return NULL;
432
433 char value[PROPERTY_VALUE_MAX];
434 property_get(key, value, "");
435 free(key);
436
437 return strdup(value);
438}
439
440
Doug Zongker47cace92009-06-18 10:11:50 -0700441// file_getprop(file, key)
442//
443// interprets 'file' as a getprop-style file (key=value pairs, one
444// per line, # comment lines and blank lines okay), and returns the value
445// for 'key' (or "" if it isn't defined).
446char* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
447 char* result = NULL;
448 char* buffer = NULL;
449 char* filename;
450 char* key;
451 if (ReadArgs(state, argv, 2, &filename, &key) < 0) {
452 return NULL;
453 }
454
455 struct stat st;
456 if (stat(filename, &st) < 0) {
457 ErrorAbort(state, "%s: failed to stat \"%s\": %s",
458 name, filename, strerror(errno));
459 goto done;
460 }
461
462#define MAX_FILE_GETPROP_SIZE 65536
463
464 if (st.st_size > MAX_FILE_GETPROP_SIZE) {
465 ErrorAbort(state, "%s too large for %s (max %d)",
466 filename, name, MAX_FILE_GETPROP_SIZE);
467 goto done;
468 }
469
470 buffer = malloc(st.st_size+1);
471 if (buffer == NULL) {
472 ErrorAbort(state, "%s: failed to alloc %d bytes", name, st.st_size+1);
473 goto done;
474 }
475
476 FILE* f = fopen(filename, "rb");
477 if (f == NULL) {
478 ErrorAbort(state, "%s: failed to open %s: %s",
479 name, filename, strerror(errno));
480 goto done;
481 }
482
483 if (fread(buffer, 1, st.st_size, f) != st.st_size) {
484 ErrorAbort(state, "%s: failed to read %d bytes from %s",
485 name, st.st_size+1, filename);
486 fclose(f);
487 goto done;
488 }
489 buffer[st.st_size] = '\0';
490
491 fclose(f);
492
493 char* line = strtok(buffer, "\n");
494 do {
495 // skip whitespace at start of line
496 while (*line && isspace(*line)) ++line;
497
498 // comment or blank line: skip to next line
499 if (*line == '\0' || *line == '#') continue;
500
501 char* equal = strchr(line, '=');
502 if (equal == NULL) {
503 ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
504 name, line, filename);
505 goto done;
506 }
507
508 // trim whitespace between key and '='
509 char* key_end = equal-1;
510 while (key_end > line && isspace(*key_end)) --key_end;
511 key_end[1] = '\0';
512
513 // not the key we're looking for
514 if (strcmp(key, line) != 0) continue;
515
516 // skip whitespace after the '=' to the start of the value
517 char* val_start = equal+1;
518 while(*val_start && isspace(*val_start)) ++val_start;
519
520 // trim trailing whitespace
521 char* val_end = val_start + strlen(val_start)-1;
522 while (val_end > val_start && isspace(*val_end)) --val_end;
523 val_end[1] = '\0';
524
525 result = strdup(val_start);
526 break;
527
528 } while ((line = strtok(NULL, "\n")));
529
530 if (result == NULL) result = strdup("");
531
532 done:
533 free(filename);
534 free(key);
535 free(buffer);
536 return result;
537}
538
539
Doug Zongker8edb00c2009-06-11 17:21:44 -0700540static bool write_raw_image_cb(const unsigned char* data,
541 int data_len, void* ctx) {
542 int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
543 if (r == data_len) return true;
544 fprintf(stderr, "%s\n", strerror(errno));
545 return false;
546}
547
548// write_raw_image(file, partition)
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700549char* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700550 char* result = NULL;
551
552 char* partition;
553 char* filename;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700554 if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700555 return NULL;
556 }
557
558 if (strlen(partition) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700559 ErrorAbort(state, "partition argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700560 goto done;
561 }
562 if (strlen(filename) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700563 ErrorAbort(state, "file argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700564 goto done;
565 }
566
567 mtd_scan_partitions();
568 const MtdPartition* mtd = mtd_find_partition_by_name(partition);
569 if (mtd == NULL) {
570 fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition);
571 result = strdup("");
572 goto done;
573 }
574
575 MtdWriteContext* ctx = mtd_write_partition(mtd);
576 if (ctx == NULL) {
577 fprintf(stderr, "%s: can't write mtd partition \"%s\"\n",
578 name, partition);
579 result = strdup("");
580 goto done;
581 }
582
583 bool success;
584
585 FILE* f = fopen(filename, "rb");
586 if (f == NULL) {
587 fprintf(stderr, "%s: can't open %s: %s\n",
588 name, filename, strerror(errno));
589 result = strdup("");
590 goto done;
591 }
592
593 success = true;
594 char* buffer = malloc(BUFSIZ);
595 int read;
596 while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
597 int wrote = mtd_write_data(ctx, buffer, read);
598 success = success && (wrote == read);
599 if (!success) {
600 fprintf(stderr, "mtd_write_data to %s failed: %s\n",
601 partition, strerror(errno));
602 }
603 }
604 free(buffer);
605 fclose(f);
606
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700607 if (mtd_erase_blocks(ctx, -1) == -1) {
608 fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition);
609 }
610 if (mtd_write_close(ctx) != 0) {
611 fprintf(stderr, "%s: error closing write of %s\n", name, partition);
612 }
613
Doug Zongker8edb00c2009-06-11 17:21:44 -0700614 printf("%s %s partition from %s\n",
615 success ? "wrote" : "failed to write", partition, filename);
616
617 result = success ? partition : strdup("");
618
619done:
620 if (result != partition) free(partition);
621 free(filename);
622 return result;
623}
624
625// write_firmware_image(file, partition)
626//
627// partition is "radio" or "hboot"
628// file is not used until after updater exits
629//
630// TODO: this should live in some HTC-specific library
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700631char* WriteFirmwareImageFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700632 int argc, Expr* argv[]) {
633 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
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700650 FILE* cmd = ((UpdaterInfo*)(state->cookie))->cmd_pipe;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700651 fprintf(cmd, "firmware %s %s\n", partition, filename);
652
653 printf("will write %s firmware from %s\n", partition, filename);
654 result = partition;
655
656done:
657 if (result != partition) free(partition);
658 free(filename);
659 return result;
660}
661
662
663extern int applypatch(int argc, char** argv);
664
665// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...)
666// apply_patch_check(file, sha1, ...)
667// apply_patch_space(bytes)
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700668char* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700669 printf("in applypatchfn (%s)\n", name);
670
671 char* prepend = NULL;
672 if (strstr(name, "check") != NULL) {
673 prepend = "-c";
674 } else if (strstr(name, "space") != NULL) {
675 prepend = "-s";
676 }
677
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700678 char** args = ReadVarArgs(state, argc, argv);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700679 if (args == NULL) return NULL;
680
681 // insert the "program name" argv[0] and a copy of the "prepend"
682 // string (if any) at the start of the args.
683
684 int extra = 1 + (prepend != NULL ? 1 : 0);
685 char** temp = malloc((argc+extra) * sizeof(char*));
686 memcpy(temp+extra, args, argc * sizeof(char*));
687 temp[0] = strdup("updater");
688 if (prepend) {
689 temp[1] = strdup(prepend);
690 }
691 free(args);
692 args = temp;
693 argc += extra;
694
695 printf("calling applypatch\n");
696 fflush(stdout);
697 int result = applypatch(argc, args);
698 printf("applypatch returned %d\n", result);
699
700 int i;
701 for (i = 0; i < argc; ++i) {
702 free(args[i]);
703 }
704 free(args);
705
706 switch (result) {
707 case 0: return strdup("t");
708 case 1: return strdup("");
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700709 default: return ErrorAbort(state, "applypatch couldn't parse args");
Doug Zongker8edb00c2009-06-11 17:21:44 -0700710 }
711}
712
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700713char* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
714 char** args = ReadVarArgs(state, argc, argv);
715 if (args == NULL) {
716 return NULL;
717 }
718
719 int size = 0;
720 int i;
721 for (i = 0; i < argc; ++i) {
722 size += strlen(args[i]);
723 }
724 char* buffer = malloc(size+1);
725 size = 0;
726 for (i = 0; i < argc; ++i) {
727 strcpy(buffer+size, args[i]);
728 size += strlen(args[i]);
729 free(args[i]);
730 }
731 free(args);
732 buffer[size] = '\0';
733
734 char* line = strtok(buffer, "\n");
735 while (line) {
736 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
737 "ui_print %s\n", line);
738 line = strtok(NULL, "\n");
739 }
740 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
741
742 return buffer;
743}
744
Doug Zongker8edb00c2009-06-11 17:21:44 -0700745
Doug Zongker9931f7f2009-06-10 14:11:53 -0700746void RegisterInstallFunctions() {
747 RegisterFunction("mount", MountFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700748 RegisterFunction("is_mounted", IsMountedFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700749 RegisterFunction("unmount", UnmountFn);
750 RegisterFunction("format", FormatFn);
751 RegisterFunction("show_progress", ShowProgressFn);
752 RegisterFunction("delete", DeleteFn);
753 RegisterFunction("delete_recursive", DeleteFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700754 RegisterFunction("package_extract_dir", PackageExtractDirFn);
755 RegisterFunction("package_extract_file", PackageExtractFileFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700756 RegisterFunction("symlink", SymlinkFn);
757 RegisterFunction("set_perm", SetPermFn);
758 RegisterFunction("set_perm_recursive", SetPermFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700759
760 RegisterFunction("getprop", GetPropFn);
Doug Zongker47cace92009-06-18 10:11:50 -0700761 RegisterFunction("file_getprop", FileGetPropFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700762 RegisterFunction("write_raw_image", WriteRawImageFn);
763 RegisterFunction("write_firmware_image", WriteFirmwareImageFn);
764
765 RegisterFunction("apply_patch", ApplyPatchFn);
766 RegisterFunction("apply_patch_check", ApplyPatchFn);
767 RegisterFunction("apply_patch_space", ApplyPatchFn);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700768
769 RegisterFunction("ui_print", UIPrintFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700770}