blob: 616cb2c8bd33b6fa3c1adb1a2550523fcc328271 [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 Zongkerd9c9d102009-06-12 12:24:39 -070035char* ErrorAbort(State* state, char* format, ...) {
Doug Zongker9931f7f2009-06-10 14:11:53 -070036 char* buffer = malloc(4096);
37 va_list v;
38 va_start(v, format);
39 vsnprintf(buffer, 4096, format, v);
40 va_end(v);
Doug Zongkerd9c9d102009-06-12 12:24:39 -070041 free(state->errmsg);
42 state->errmsg = buffer;
Doug Zongker9931f7f2009-06-10 14:11:53 -070043 return NULL;
44}
45
Doug Zongker8edb00c2009-06-11 17:21:44 -070046
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 Zongkerd9c9d102009-06-12 12:24:39 -070051char* 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
78 if (strcmp(type, "MTD") == 0) {
79 mtd_scan_partitions();
80 const MtdPartition* mtd;
81 mtd = mtd_find_partition_by_name(location);
82 if (mtd == NULL) {
83 fprintf(stderr, "%s: no mtd partition named \"%s\"",
84 name, location);
85 result = strdup("");
86 goto done;
87 }
88 if (mtd_mount_partition(mtd, mount_point, "yaffs2", 0 /* rw */) != 0) {
89 fprintf(stderr, "mtd mount of %s failed: %s\n",
90 location, strerror(errno));
91 result = strdup("");
92 goto done;
93 }
94 result = mount_point;
95 } else {
96 if (mount(location, mount_point, type,
97 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
98 result = strdup("");
99 } else {
100 result = mount_point;
101 }
102 }
103
104done:
105 free(type);
106 free(location);
107 if (result != mount_point) free(mount_point);
108 return result;
109}
110
Doug Zongker8edb00c2009-06-11 17:21:44 -0700111
112// is_mounted(mount_point)
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700113char* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700114 char* result = NULL;
115 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700116 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700117 }
118 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700119 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700120 return NULL;
121 }
122 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700123 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker8edb00c2009-06-11 17:21:44 -0700124 goto done;
125 }
126
127 scan_mounted_volumes();
128 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
129 if (vol == NULL) {
130 result = strdup("");
131 } else {
132 result = mount_point;
133 }
134
135done:
136 if (result != mount_point) free(mount_point);
137 return result;
138}
139
140
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700141char* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700142 char* result = NULL;
143 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700144 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700145 }
146 char* mount_point;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700147 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700148 return NULL;
149 }
150 if (strlen(mount_point) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700151 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
Doug Zongker9931f7f2009-06-10 14:11:53 -0700152 goto done;
153 }
154
155 scan_mounted_volumes();
156 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
157 if (vol == NULL) {
158 fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
159 result = strdup("");
160 } else {
161 unmount_mounted_volume(vol);
162 result = mount_point;
163 }
164
165done:
166 if (result != mount_point) free(mount_point);
167 return result;
168}
Doug Zongker8edb00c2009-06-11 17:21:44 -0700169
170
Doug Zongker9931f7f2009-06-10 14:11:53 -0700171// format(type, location)
172//
173// type="MTD" location=partition
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700174char* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700175 char* result = NULL;
176 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700177 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700178 }
179 char* type;
180 char* location;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700181 if (ReadArgs(state, argv, 2, &type, &location) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700182 return NULL;
183 }
184
185 if (strlen(type) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700186 ErrorAbort(state, "type argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700187 goto done;
188 }
189 if (strlen(location) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700190 ErrorAbort(state, "location argument to %s() can't be empty", name);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700191 goto done;
192 }
193
194 if (strcmp(type, "MTD") == 0) {
195 mtd_scan_partitions();
196 const MtdPartition* mtd = mtd_find_partition_by_name(location);
197 if (mtd == NULL) {
198 fprintf(stderr, "%s: no mtd partition named \"%s\"",
199 name, location);
200 result = strdup("");
201 goto done;
202 }
203 MtdWriteContext* ctx = mtd_write_partition(mtd);
204 if (ctx == NULL) {
205 fprintf(stderr, "%s: can't write \"%s\"", name, location);
206 result = strdup("");
207 goto done;
208 }
209 if (mtd_erase_blocks(ctx, -1) == -1) {
210 mtd_write_close(ctx);
211 fprintf(stderr, "%s: failed to erase \"%s\"", name, location);
212 result = strdup("");
213 goto done;
214 }
215 if (mtd_write_close(ctx) != 0) {
216 fprintf(stderr, "%s: failed to close \"%s\"", name, location);
217 result = strdup("");
218 goto done;
219 }
220 result = location;
221 } else {
222 fprintf(stderr, "%s: unsupported type \"%s\"", name, type);
223 }
224
225done:
226 free(type);
227 if (result != location) free(location);
228 return result;
229}
230
Doug Zongker8edb00c2009-06-11 17:21:44 -0700231
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700232char* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700233 char** paths = malloc(argc * sizeof(char*));
234 int i;
235 for (i = 0; i < argc; ++i) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700236 paths[i] = Evaluate(state, argv[i]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700237 if (paths[i] == NULL) {
238 int j;
239 for (j = 0; j < i; ++i) {
240 free(paths[j]);
241 }
242 free(paths);
243 return NULL;
244 }
245 }
246
247 bool recursive = (strcmp(name, "delete_recursive") == 0);
248
249 int success = 0;
250 for (i = 0; i < argc; ++i) {
251 if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
252 ++success;
253 free(paths[i]);
254 }
255 free(paths);
256
257 char buffer[10];
258 sprintf(buffer, "%d", success);
259 return strdup(buffer);
260}
261
Doug Zongker8edb00c2009-06-11 17:21:44 -0700262
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700263char* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700264 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700265 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700266 }
267 char* frac_str;
268 char* sec_str;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700269 if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700270 return NULL;
271 }
272
273 double frac = strtod(frac_str, NULL);
274 int sec = strtol(sec_str, NULL, 10);
275
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700276 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700277 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
278
279 free(frac_str);
280 free(sec_str);
281 return strdup("");
282}
283
Doug Zongker8edb00c2009-06-11 17:21:44 -0700284// package_extract_dir(package_path, destination_path)
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700285char* PackageExtractDirFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700286 int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700287 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700288 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700289 }
290 char* zip_path;
291 char* dest_path;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700292 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700293
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700294 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700295
296 // To create a consistent system image, never use the clock for timestamps.
297 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
298
299 bool success = mzExtractRecursive(za, zip_path, dest_path,
300 MZ_EXTRACT_FILES_ONLY, &timestamp,
301 NULL, NULL);
302 free(zip_path);
303 free(dest_path);
304 return strdup(success ? "t" : "");
305}
306
Doug Zongker8edb00c2009-06-11 17:21:44 -0700307
308// package_extract_file(package_path, destination_path)
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700309char* PackageExtractFileFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700310 int argc, Expr* argv[]) {
311 if (argc != 2) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700312 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700313 }
314 char* zip_path;
315 char* dest_path;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700316 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700317
318 bool success = false;
319
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700320 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700321 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
322 if (entry == NULL) {
323 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
324 goto done;
325 }
326
327 FILE* f = fopen(dest_path, "wb");
328 if (f == NULL) {
329 fprintf(stderr, "%s: can't open %s for write: %s\n",
330 name, dest_path, strerror(errno));
331 goto done;
332 }
333 success = mzExtractZipEntryToFile(za, entry, fileno(f));
334 fclose(f);
335
336 done:
337 free(zip_path);
338 free(dest_path);
339 return strdup(success ? "t" : "");
340}
341
342
Doug Zongker9931f7f2009-06-10 14:11:53 -0700343// symlink target src1 src2 ...
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700344char* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700345 if (argc == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700346 return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700347 }
348 char* target;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700349 target = Evaluate(state, argv[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700350 if (target == NULL) return NULL;
351
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700352 char** srcs = ReadVarArgs(state, argc-1, argv+1);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700353 if (srcs == NULL) {
354 free(target);
355 return NULL;
356 }
357
358 int i;
359 for (i = 0; i < argc-1; ++i) {
360 symlink(target, srcs[i]);
361 free(srcs[i]);
362 }
363 free(srcs);
364 return strdup("");
365}
366
Doug Zongker8edb00c2009-06-11 17:21:44 -0700367
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700368char* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker9931f7f2009-06-10 14:11:53 -0700369 char* result = NULL;
370 bool recursive = (strcmp(name, "set_perm_recursive") == 0);
371
372 int min_args = 4 + (recursive ? 1 : 0);
373 if (argc < min_args) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700374 return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700375 }
376
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700377 char** args = ReadVarArgs(state, argc, argv);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700378 if (args == NULL) return NULL;
379
380 char* end;
381 int i;
382
383 int uid = strtoul(args[0], &end, 0);
384 if (*end != '\0' || args[0][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700385 ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700386 goto done;
387 }
388
389 int gid = strtoul(args[1], &end, 0);
390 if (*end != '\0' || args[1][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700391 ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700392 goto done;
393 }
394
395 if (recursive) {
396 int dir_mode = strtoul(args[2], &end, 0);
397 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700398 ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700399 goto done;
400 }
401
402 int file_mode = strtoul(args[3], &end, 0);
403 if (*end != '\0' || args[3][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700404 ErrorAbort(state, "%s: \"%s\" not a valid filemode",
Doug Zongker9931f7f2009-06-10 14:11:53 -0700405 name, args[3]);
406 goto done;
407 }
408
409 for (i = 4; i < argc; ++i) {
410 dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
411 }
412 } else {
413 int mode = strtoul(args[2], &end, 0);
414 if (*end != '\0' || args[2][0] == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700415 ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700416 goto done;
417 }
418
419 for (i = 4; i < argc; ++i) {
420 chown(args[i], uid, gid);
421 chmod(args[i], mode);
422 }
423 }
424 result = strdup("");
425
426done:
427 for (i = 0; i < argc; ++i) {
428 free(args[i]);
429 }
430 free(args);
431
432 return result;
433}
434
Doug Zongker8edb00c2009-06-11 17:21:44 -0700435
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700436char* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700437 if (argc != 1) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700438 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700439 }
440 char* key;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700441 key = Evaluate(state, argv[0]);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700442 if (key == NULL) return NULL;
443
444 char value[PROPERTY_VALUE_MAX];
445 property_get(key, value, "");
446 free(key);
447
448 return strdup(value);
449}
450
451
452static bool write_raw_image_cb(const unsigned char* data,
453 int data_len, void* ctx) {
454 int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
455 if (r == data_len) return true;
456 fprintf(stderr, "%s\n", strerror(errno));
457 return false;
458}
459
460// write_raw_image(file, partition)
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700461char* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700462 char* result = NULL;
463
464 char* partition;
465 char* filename;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700466 if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700467 return NULL;
468 }
469
470 if (strlen(partition) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700471 ErrorAbort(state, "partition argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700472 goto done;
473 }
474 if (strlen(filename) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700475 ErrorAbort(state, "file argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700476 goto done;
477 }
478
479 mtd_scan_partitions();
480 const MtdPartition* mtd = mtd_find_partition_by_name(partition);
481 if (mtd == NULL) {
482 fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition);
483 result = strdup("");
484 goto done;
485 }
486
487 MtdWriteContext* ctx = mtd_write_partition(mtd);
488 if (ctx == NULL) {
489 fprintf(stderr, "%s: can't write mtd partition \"%s\"\n",
490 name, partition);
491 result = strdup("");
492 goto done;
493 }
494
495 bool success;
496
497 FILE* f = fopen(filename, "rb");
498 if (f == NULL) {
499 fprintf(stderr, "%s: can't open %s: %s\n",
500 name, filename, strerror(errno));
501 result = strdup("");
502 goto done;
503 }
504
505 success = true;
506 char* buffer = malloc(BUFSIZ);
507 int read;
508 while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
509 int wrote = mtd_write_data(ctx, buffer, read);
510 success = success && (wrote == read);
511 if (!success) {
512 fprintf(stderr, "mtd_write_data to %s failed: %s\n",
513 partition, strerror(errno));
514 }
515 }
516 free(buffer);
517 fclose(f);
518
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700519 if (mtd_erase_blocks(ctx, -1) == -1) {
520 fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition);
521 }
522 if (mtd_write_close(ctx) != 0) {
523 fprintf(stderr, "%s: error closing write of %s\n", name, partition);
524 }
525
Doug Zongker8edb00c2009-06-11 17:21:44 -0700526 printf("%s %s partition from %s\n",
527 success ? "wrote" : "failed to write", partition, filename);
528
529 result = success ? partition : strdup("");
530
531done:
532 if (result != partition) free(partition);
533 free(filename);
534 return result;
535}
536
537// write_firmware_image(file, partition)
538//
539// partition is "radio" or "hboot"
540// file is not used until after updater exits
541//
542// TODO: this should live in some HTC-specific library
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700543char* WriteFirmwareImageFn(const char* name, State* state,
Doug Zongker8edb00c2009-06-11 17:21:44 -0700544 int argc, Expr* argv[]) {
545 char* result = NULL;
546
547 char* partition;
548 char* filename;
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700549 if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700550 return NULL;
551 }
552
553 if (strlen(partition) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700554 ErrorAbort(state, "partition argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700555 goto done;
556 }
557 if (strlen(filename) == 0) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700558 ErrorAbort(state, "file argument to %s can't be empty", name);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700559 goto done;
560 }
561
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700562 FILE* cmd = ((UpdaterInfo*)(state->cookie))->cmd_pipe;
Doug Zongker8edb00c2009-06-11 17:21:44 -0700563 fprintf(cmd, "firmware %s %s\n", partition, filename);
564
565 printf("will write %s firmware from %s\n", partition, filename);
566 result = partition;
567
568done:
569 if (result != partition) free(partition);
570 free(filename);
571 return result;
572}
573
574
575extern int applypatch(int argc, char** argv);
576
577// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...)
578// apply_patch_check(file, sha1, ...)
579// apply_patch_space(bytes)
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700580char* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongker8edb00c2009-06-11 17:21:44 -0700581 printf("in applypatchfn (%s)\n", name);
582
583 char* prepend = NULL;
584 if (strstr(name, "check") != NULL) {
585 prepend = "-c";
586 } else if (strstr(name, "space") != NULL) {
587 prepend = "-s";
588 }
589
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700590 char** args = ReadVarArgs(state, argc, argv);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700591 if (args == NULL) return NULL;
592
593 // insert the "program name" argv[0] and a copy of the "prepend"
594 // string (if any) at the start of the args.
595
596 int extra = 1 + (prepend != NULL ? 1 : 0);
597 char** temp = malloc((argc+extra) * sizeof(char*));
598 memcpy(temp+extra, args, argc * sizeof(char*));
599 temp[0] = strdup("updater");
600 if (prepend) {
601 temp[1] = strdup(prepend);
602 }
603 free(args);
604 args = temp;
605 argc += extra;
606
607 printf("calling applypatch\n");
608 fflush(stdout);
609 int result = applypatch(argc, args);
610 printf("applypatch returned %d\n", result);
611
612 int i;
613 for (i = 0; i < argc; ++i) {
614 free(args[i]);
615 }
616 free(args);
617
618 switch (result) {
619 case 0: return strdup("t");
620 case 1: return strdup("");
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700621 default: return ErrorAbort(state, "applypatch couldn't parse args");
Doug Zongker8edb00c2009-06-11 17:21:44 -0700622 }
623}
624
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700625char* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
626 char** args = ReadVarArgs(state, argc, argv);
627 if (args == NULL) {
628 return NULL;
629 }
630
631 int size = 0;
632 int i;
633 for (i = 0; i < argc; ++i) {
634 size += strlen(args[i]);
635 }
636 char* buffer = malloc(size+1);
637 size = 0;
638 for (i = 0; i < argc; ++i) {
639 strcpy(buffer+size, args[i]);
640 size += strlen(args[i]);
641 free(args[i]);
642 }
643 free(args);
644 buffer[size] = '\0';
645
646 char* line = strtok(buffer, "\n");
647 while (line) {
648 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
649 "ui_print %s\n", line);
650 line = strtok(NULL, "\n");
651 }
652 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
653
654 return buffer;
655}
656
Doug Zongker8edb00c2009-06-11 17:21:44 -0700657
Doug Zongker9931f7f2009-06-10 14:11:53 -0700658void RegisterInstallFunctions() {
659 RegisterFunction("mount", MountFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700660 RegisterFunction("is_mounted", IsMountedFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700661 RegisterFunction("unmount", UnmountFn);
662 RegisterFunction("format", FormatFn);
663 RegisterFunction("show_progress", ShowProgressFn);
664 RegisterFunction("delete", DeleteFn);
665 RegisterFunction("delete_recursive", DeleteFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700666 RegisterFunction("package_extract_dir", PackageExtractDirFn);
667 RegisterFunction("package_extract_file", PackageExtractFileFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700668 RegisterFunction("symlink", SymlinkFn);
669 RegisterFunction("set_perm", SetPermFn);
670 RegisterFunction("set_perm_recursive", SetPermFn);
Doug Zongker8edb00c2009-06-11 17:21:44 -0700671
672 RegisterFunction("getprop", GetPropFn);
673 RegisterFunction("write_raw_image", WriteRawImageFn);
674 RegisterFunction("write_firmware_image", WriteFirmwareImageFn);
675
676 RegisterFunction("apply_patch", ApplyPatchFn);
677 RegisterFunction("apply_patch_check", ApplyPatchFn);
678 RegisterFunction("apply_patch_space", ApplyPatchFn);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700679
680 RegisterFunction("ui_print", UIPrintFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700681}