blob: d23ec64a560839f1180aa4266e33cef10908a052 [file] [log] [blame]
preludedrew38058dc2011-01-29 23:30:44 -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 <ctype.h>
18#include <errno.h>
19#include <stdarg.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/mount.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <sys/wait.h>
27#include <unistd.h>
28
29#include "cutils/misc.h"
30#include "cutils/properties.h"
31#include "edify/expr.h"
32#include "mincrypt/sha.h"
33#include "minzip/DirUtil.h"
34#include "mounts.h"
35#include "mtdutils/mtdutils.h"
36#include "updater.h"
37#include "applypatch/applypatch.h"
38
39#ifdef USE_EXT4
40#include "make_ext4fs.h"
41#endif
42
43// mount(fs_type, partition_type, location, mount_point)
44//
45// fs_type="yaffs2" partition_type="MTD" location=partition
46// fs_type="ext4" partition_type="EMMC" location=device
47Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
48 char* result = NULL;
49 if (argc != 4) {
50 return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc);
51 }
52 char* fs_type;
53 char* partition_type;
54 char* location;
55 char* mount_point;
56 if (ReadArgs(state, argv, 4, &fs_type, &partition_type,
57 &location, &mount_point) < 0) {
58 return NULL;
59 }
60
61 if (strlen(fs_type) == 0) {
62 ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
63 goto done;
64 }
65 if (strlen(partition_type) == 0) {
66 ErrorAbort(state, "partition_type argument to %s() can't be empty",
67 name);
68 goto done;
69 }
70 if (strlen(location) == 0) {
71 ErrorAbort(state, "location argument to %s() can't be empty", name);
72 goto done;
73 }
74 if (strlen(mount_point) == 0) {
75 ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
76 goto done;
77 }
78
79 mkdir(mount_point, 0755);
80
81 if (strcmp(partition_type, "MTD") == 0) {
82 mtd_scan_partitions();
83 const MtdPartition* mtd;
84 mtd = mtd_find_partition_by_name(location);
85 if (mtd == NULL) {
86 fprintf(stderr, "%s: no mtd partition named \"%s\"",
87 name, location);
88 result = strdup("");
89 goto done;
90 }
91 if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
92 fprintf(stderr, "mtd mount of %s failed: %s\n",
93 location, strerror(errno));
94 result = strdup("");
95 goto done;
96 }
97 result = mount_point;
98 } else {
99 if (mount(location, mount_point, fs_type,
100 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
101 fprintf(stderr, "%s: failed to mount %s at %s: %s\n",
102 name, location, mount_point, strerror(errno));
103 result = strdup("");
104 } else {
105 result = mount_point;
106 }
107 }
108
109done:
110 free(fs_type);
111 free(partition_type);
112 free(location);
113 if (result != mount_point) free(mount_point);
114 return StringValue(result);
115}
116
117
118// is_mounted(mount_point)
119Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
120 char* result = NULL;
121 if (argc != 1) {
122 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
123 }
124 char* mount_point;
125 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
126 return NULL;
127 }
128 if (strlen(mount_point) == 0) {
129 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
130 goto done;
131 }
132
133 scan_mounted_volumes();
134 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
135 if (vol == NULL) {
136 result = strdup("");
137 } else {
138 result = mount_point;
139 }
140
141done:
142 if (result != mount_point) free(mount_point);
143 return StringValue(result);
144}
145
146
147Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
148 char* result = NULL;
149 if (argc != 1) {
150 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
151 }
152 char* mount_point;
153 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
154 return NULL;
155 }
156 if (strlen(mount_point) == 0) {
157 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
158 goto done;
159 }
160
161 scan_mounted_volumes();
162 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
163 if (vol == NULL) {
164 fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
165 result = strdup("");
166 } else {
167 unmount_mounted_volume(vol);
168 result = mount_point;
169 }
170
171done:
172 if (result != mount_point) free(mount_point);
173 return StringValue(result);
174}
175
176
177// format(fs_type, partition_type, location)
178//
179// fs_type="yaffs2" partition_type="MTD" location=partition
180// fs_type="ext4" partition_type="EMMC" location=device
181Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
182 char* result = NULL;
183 if (argc != 3) {
184 return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
185 }
186 char* fs_type;
187 char* partition_type;
188 char* location;
189 if (ReadArgs(state, argv, 3, &fs_type, &partition_type, &location) < 0) {
190 return NULL;
191 }
192
193 if (strlen(fs_type) == 0) {
194 ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
195 goto done;
196 }
197 if (strlen(partition_type) == 0) {
198 ErrorAbort(state, "partition_type argument to %s() can't be empty",
199 name);
200 goto done;
201 }
202 if (strlen(location) == 0) {
203 ErrorAbort(state, "location argument to %s() can't be empty", name);
204 goto done;
205 }
206
207 if (strcmp(partition_type, "MTD") == 0) {
208 mtd_scan_partitions();
209 const MtdPartition* mtd = mtd_find_partition_by_name(location);
210 if (mtd == NULL) {
211 fprintf(stderr, "%s: no mtd partition named \"%s\"",
212 name, location);
213 result = strdup("");
214 goto done;
215 }
216 MtdWriteContext* ctx = mtd_write_partition(mtd);
217 if (ctx == NULL) {
218 fprintf(stderr, "%s: can't write \"%s\"", name, location);
219 result = strdup("");
220 goto done;
221 }
222 if (mtd_erase_blocks(ctx, -1) == -1) {
223 mtd_write_close(ctx);
224 fprintf(stderr, "%s: failed to erase \"%s\"", name, location);
225 result = strdup("");
226 goto done;
227 }
228 if (mtd_write_close(ctx) != 0) {
229 fprintf(stderr, "%s: failed to close \"%s\"", name, location);
230 result = strdup("");
231 goto done;
232 }
233 result = location;
234#ifdef USE_EXT4
235 } else if (strcmp(fs_type, "ext4") == 0) {
236 reset_ext4fs_info();
237 int status = make_ext4fs(location, NULL, NULL, 0, 0, 0);
238 if (status != 0) {
239 fprintf(stderr, "%s: make_ext4fs failed (%d) on %s",
240 name, status, location);
241 result = strdup("");
242 goto done;
243 }
244 result = location;
245#endif
246 } else if (strcmp(fs_type, "ext2") == 0) {
247 int status = format_ext2_device(location);
248 if (status != 0) {
249 fprintf(stderr, "%s: format_ext2_device failed (%d) on %s",
250 name, status, location);
251 result = strdup("");
252 goto done;
253 }
254 result = location;
255 } else if (strcmp(fs_type, "ext3") == 0) {
256 int status = format_ext3_device(location);
257 if (status != 0) {
258 fprintf(stderr, "%s: format_ext3_device failed (%d) on %s",
259 name, status, location);
260 result = strdup("");
261 goto done;
262 }
263 result = location;
264 } else {
265 fprintf(stderr, "%s: unsupported fs_type \"%s\" partition_type \"%s\"",
266 name, fs_type, partition_type);
267 }
268
269done:
270 free(fs_type);
271 free(partition_type);
272 if (result != location) free(location);
273 return StringValue(result);
274}
275
276
277Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
278 char** paths = malloc(argc * sizeof(char*));
279 int i;
280 for (i = 0; i < argc; ++i) {
281 paths[i] = Evaluate(state, argv[i]);
282 if (paths[i] == NULL) {
283 int j;
284 for (j = 0; j < i; ++i) {
285 free(paths[j]);
286 }
287 free(paths);
288 return NULL;
289 }
290 }
291
292 bool recursive = (strcmp(name, "delete_recursive") == 0);
293
294 int success = 0;
295 for (i = 0; i < argc; ++i) {
296 if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
297 ++success;
298 free(paths[i]);
299 }
300 free(paths);
301
302 char buffer[10];
303 sprintf(buffer, "%d", success);
304 return StringValue(strdup(buffer));
305}
306
307
308Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
309 if (argc != 2) {
310 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
311 }
312 char* frac_str;
313 char* sec_str;
314 if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
315 return NULL;
316 }
317
318 double frac = strtod(frac_str, NULL);
319 int sec = strtol(sec_str, NULL, 10);
320
321 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
322 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
323
324 free(sec_str);
325 return StringValue(frac_str);
326}
327
328Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
329 if (argc != 1) {
330 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
331 }
332 char* frac_str;
333 if (ReadArgs(state, argv, 1, &frac_str) < 0) {
334 return NULL;
335 }
336
337 double frac = strtod(frac_str, NULL);
338
339 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
340 fprintf(ui->cmd_pipe, "set_progress %f\n", frac);
341
342 return StringValue(frac_str);
343}
344
345// package_extract_dir(package_path, destination_path)
346Value* PackageExtractDirFn(const char* name, State* state,
347 int argc, Expr* argv[]) {
348 if (argc != 2) {
349 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
350 }
351 char* zip_path;
352 char* dest_path;
353 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
354
355 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
356
357 // To create a consistent system image, never use the clock for timestamps.
358 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
359
360 bool success = mzExtractRecursive(za, zip_path, dest_path,
361 MZ_EXTRACT_FILES_ONLY, &timestamp,
362 NULL, NULL);
363 free(zip_path);
364 free(dest_path);
365 return StringValue(strdup(success ? "t" : ""));
366}
367
368
369// package_extract_file(package_path, destination_path)
370// or
371// package_extract_file(package_path)
372// to return the entire contents of the file as the result of this
373// function (the char* returned is actually a FileContents*).
374Value* PackageExtractFileFn(const char* name, State* state,
375 int argc, Expr* argv[]) {
376 if (argc != 1 && argc != 2) {
377 return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
378 name, argc);
379 }
380 bool success = false;
381 if (argc == 2) {
382 // The two-argument version extracts to a file.
383
384 char* zip_path;
385 char* dest_path;
386 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
387
388 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
389 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
390 if (entry == NULL) {
391 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
392 goto done2;
393 }
394
395 FILE* f = fopen(dest_path, "wb");
396 if (f == NULL) {
397 fprintf(stderr, "%s: can't open %s for write: %s\n",
398 name, dest_path, strerror(errno));
399 goto done2;
400 }
401 success = mzExtractZipEntryToFile(za, entry, fileno(f));
402 fclose(f);
403
404 done2:
405 free(zip_path);
406 free(dest_path);
407 return StringValue(strdup(success ? "t" : ""));
408 } else {
409 // The one-argument version returns the contents of the file
410 // as the result.
411
412 char* zip_path;
413 Value* v = malloc(sizeof(Value));
414 v->type = VAL_BLOB;
415 v->size = -1;
416 v->data = NULL;
417
418 if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
419
420 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
421 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
422 if (entry == NULL) {
423 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
424 goto done1;
425 }
426
427 v->size = mzGetZipEntryUncompLen(entry);
428 v->data = malloc(v->size);
429 if (v->data == NULL) {
430 fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n",
431 name, (long)v->size, zip_path);
432 goto done1;
433 }
434
435 success = mzExtractZipEntryToBuffer(za, entry,
436 (unsigned char *)v->data);
437
438 done1:
439 free(zip_path);
440 if (!success) {
441 free(v->data);
442 v->data = NULL;
443 v->size = -1;
444 }
445 return v;
446 }
447}
448
449
450// symlink target src1 src2 ...
451// unlinks any previously existing src1, src2, etc before creating symlinks.
452Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
453 if (argc == 0) {
454 return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
455 }
456 char* target;
457 target = Evaluate(state, argv[0]);
458 if (target == NULL) return NULL;
459
460 char** srcs = ReadVarArgs(state, argc-1, argv+1);
461 if (srcs == NULL) {
462 free(target);
463 return NULL;
464 }
465
466 int i;
467 for (i = 0; i < argc-1; ++i) {
468 if (unlink(srcs[i]) < 0) {
469 if (errno != ENOENT) {
470 fprintf(stderr, "%s: failed to remove %s: %s\n",
471 name, srcs[i], strerror(errno));
472 }
473 }
474 if (symlink(target, srcs[i]) < 0) {
475 fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
476 name, srcs[i], target, strerror(errno));
477 }
478 free(srcs[i]);
479 }
480 free(srcs);
481 return StringValue(strdup(""));
482}
483
484
485Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
486 char* result = NULL;
487 bool recursive = (strcmp(name, "set_perm_recursive") == 0);
488
489 int min_args = 4 + (recursive ? 1 : 0);
490 if (argc < min_args) {
491 return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
492 }
493
494 char** args = ReadVarArgs(state, argc, argv);
495 if (args == NULL) return NULL;
496
497 char* end;
498 int i;
499
500 int uid = strtoul(args[0], &end, 0);
501 if (*end != '\0' || args[0][0] == 0) {
502 ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
503 goto done;
504 }
505
506 int gid = strtoul(args[1], &end, 0);
507 if (*end != '\0' || args[1][0] == 0) {
508 ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
509 goto done;
510 }
511
512 if (recursive) {
513 int dir_mode = strtoul(args[2], &end, 0);
514 if (*end != '\0' || args[2][0] == 0) {
515 ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
516 goto done;
517 }
518
519 int file_mode = strtoul(args[3], &end, 0);
520 if (*end != '\0' || args[3][0] == 0) {
521 ErrorAbort(state, "%s: \"%s\" not a valid filemode",
522 name, args[3]);
523 goto done;
524 }
525
526 for (i = 4; i < argc; ++i) {
527 dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
528 }
529 } else {
530 int mode = strtoul(args[2], &end, 0);
531 if (*end != '\0' || args[2][0] == 0) {
532 ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
533 goto done;
534 }
535
536 for (i = 3; i < argc; ++i) {
537 if (chown(args[i], uid, gid) < 0) {
538 fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n",
539 name, args[i], uid, gid, strerror(errno));
540 }
541 if (chmod(args[i], mode) < 0) {
542 fprintf(stderr, "%s: chmod of %s to %o failed: %s\n",
543 name, args[i], mode, strerror(errno));
544 }
545 }
546 }
547 result = strdup("");
548
549done:
550 for (i = 0; i < argc; ++i) {
551 free(args[i]);
552 }
553 free(args);
554
555 return StringValue(result);
556}
557
558
559Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
560 if (argc != 1) {
561 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
562 }
563 char* key;
564 key = Evaluate(state, argv[0]);
565 if (key == NULL) return NULL;
566
567 char value[PROPERTY_VALUE_MAX];
568 property_get(key, value, "");
569 free(key);
570
571 return StringValue(strdup(value));
572}
573
574
575// file_getprop(file, key)
576//
577// interprets 'file' as a getprop-style file (key=value pairs, one
578// per line, # comment lines and blank lines okay), and returns the value
579// for 'key' (or "" if it isn't defined).
580Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
581 char* result = NULL;
582 char* buffer = NULL;
583 char* filename;
584 char* key;
585 if (ReadArgs(state, argv, 2, &filename, &key) < 0) {
586 return NULL;
587 }
588
589 struct stat st;
590 if (stat(filename, &st) < 0) {
591 ErrorAbort(state, "%s: failed to stat \"%s\": %s",
592 name, filename, strerror(errno));
593 goto done;
594 }
595
596#define MAX_FILE_GETPROP_SIZE 65536
597
598 if (st.st_size > MAX_FILE_GETPROP_SIZE) {
599 ErrorAbort(state, "%s too large for %s (max %d)",
600 filename, name, MAX_FILE_GETPROP_SIZE);
601 goto done;
602 }
603
604 buffer = malloc(st.st_size+1);
605 if (buffer == NULL) {
606 ErrorAbort(state, "%s: failed to alloc %d bytes", name, st.st_size+1);
607 goto done;
608 }
609
610 FILE* f = fopen(filename, "rb");
611 if (f == NULL) {
612 ErrorAbort(state, "%s: failed to open %s: %s",
613 name, filename, strerror(errno));
614 goto done;
615 }
616
617 if (fread(buffer, 1, st.st_size, f) != st.st_size) {
618 ErrorAbort(state, "%s: failed to read %d bytes from %s",
619 name, st.st_size+1, filename);
620 fclose(f);
621 goto done;
622 }
623 buffer[st.st_size] = '\0';
624
625 fclose(f);
626
627 char* line = strtok(buffer, "\n");
628 do {
629 // skip whitespace at start of line
630 while (*line && isspace(*line)) ++line;
631
632 // comment or blank line: skip to next line
633 if (*line == '\0' || *line == '#') continue;
634
635 char* equal = strchr(line, '=');
636 if (equal == NULL) {
637 ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
638 name, line, filename);
639 goto done;
640 }
641
642 // trim whitespace between key and '='
643 char* key_end = equal-1;
644 while (key_end > line && isspace(*key_end)) --key_end;
645 key_end[1] = '\0';
646
647 // not the key we're looking for
648 if (strcmp(key, line) != 0) continue;
649
650 // skip whitespace after the '=' to the start of the value
651 char* val_start = equal+1;
652 while(*val_start && isspace(*val_start)) ++val_start;
653
654 // trim trailing whitespace
655 char* val_end = val_start + strlen(val_start)-1;
656 while (val_end > val_start && isspace(*val_end)) --val_end;
657 val_end[1] = '\0';
658
659 result = strdup(val_start);
660 break;
661
662 } while ((line = strtok(NULL, "\n")));
663
664 if (result == NULL) result = strdup("");
665
666 done:
667 free(filename);
668 free(key);
669 free(buffer);
670 return StringValue(result);
671}
672
673
674static bool write_raw_image_cb(const unsigned char* data,
675 int data_len, void* ctx) {
676 int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
677 if (r == data_len) return true;
678 fprintf(stderr, "%s\n", strerror(errno));
679 return false;
680}
681
682// write_raw_image(file, partition)
683Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
684 char* result = NULL;
685
686 char* partition;
687 char* filename;
688 if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
689 return NULL;
690 }
691
692 if (strlen(partition) == 0) {
693 ErrorAbort(state, "partition argument to %s can't be empty", name);
694 goto done;
695 }
696 if (strlen(filename) == 0) {
697 ErrorAbort(state, "file argument to %s can't be empty", name);
698 goto done;
699 }
700
701 if (0 == restore_raw_partition(partition, filename))
702 result = strdup(partition);
703 else
704 result = strdup("");
705
706done:
707 if (result != partition) free(partition);
708 free(filename);
709 return StringValue(result);
710}
711
712// apply_patch_space(bytes)
713Value* ApplyPatchSpaceFn(const char* name, State* state,
714 int argc, Expr* argv[]) {
715 char* bytes_str;
716 if (ReadArgs(state, argv, 1, &bytes_str) < 0) {
717 return NULL;
718 }
719
720 char* endptr;
721 size_t bytes = strtol(bytes_str, &endptr, 10);
722 if (bytes == 0 && endptr == bytes_str) {
723 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
724 name, bytes_str);
725 free(bytes_str);
726 return NULL;
727 }
728
729 return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
730}
731
732
733// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
734Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
735 if (argc < 6 || (argc % 2) == 1) {
736 return ErrorAbort(state, "%s(): expected at least 6 args and an "
737 "even number, got %d",
738 name, argc);
739 }
740
741 char* source_filename;
742 char* target_filename;
743 char* target_sha1;
744 char* target_size_str;
745 if (ReadArgs(state, argv, 4, &source_filename, &target_filename,
746 &target_sha1, &target_size_str) < 0) {
747 return NULL;
748 }
749
750 char* endptr;
751 size_t target_size = strtol(target_size_str, &endptr, 10);
752 if (target_size == 0 && endptr == target_size_str) {
753 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count",
754 name, target_size_str);
755 free(source_filename);
756 free(target_filename);
757 free(target_sha1);
758 free(target_size_str);
759 return NULL;
760 }
761
762 int patchcount = (argc-4) / 2;
763 Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
764
765 int i;
766 for (i = 0; i < patchcount; ++i) {
767 if (patches[i*2]->type != VAL_STRING) {
768 ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
769 break;
770 }
771 if (patches[i*2+1]->type != VAL_BLOB) {
772 ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
773 break;
774 }
775 }
776 if (i != patchcount) {
777 for (i = 0; i < patchcount*2; ++i) {
778 FreeValue(patches[i]);
779 }
780 free(patches);
781 return NULL;
782 }
783
784 char** patch_sha_str = malloc(patchcount * sizeof(char*));
785 for (i = 0; i < patchcount; ++i) {
786 patch_sha_str[i] = patches[i*2]->data;
787 patches[i*2]->data = NULL;
788 FreeValue(patches[i*2]);
789 patches[i] = patches[i*2+1];
790 }
791
792 int result = applypatch(source_filename, target_filename,
793 target_sha1, target_size,
794 patchcount, patch_sha_str, patches);
795
796 for (i = 0; i < patchcount; ++i) {
797 FreeValue(patches[i]);
798 }
799 free(patch_sha_str);
800 free(patches);
801
802 return StringValue(strdup(result == 0 ? "t" : ""));
803}
804
805// apply_patch_check(file, [sha1_1, ...])
806Value* ApplyPatchCheckFn(const char* name, State* state,
807 int argc, Expr* argv[]) {
808 if (argc < 1) {
809 return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
810 name, argc);
811 }
812
813 char* filename;
814 if (ReadArgs(state, argv, 1, &filename) < 0) {
815 return NULL;
816 }
817
818 int patchcount = argc-1;
819 char** sha1s = ReadVarArgs(state, argc-1, argv+1);
820
821 int result = applypatch_check(filename, patchcount, sha1s);
822
823 int i;
824 for (i = 0; i < patchcount; ++i) {
825 free(sha1s[i]);
826 }
827 free(sha1s);
828
829 return StringValue(strdup(result == 0 ? "t" : ""));
830}
831
832Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
833 char** args = ReadVarArgs(state, argc, argv);
834 if (args == NULL) {
835 return NULL;
836 }
837
838 int size = 0;
839 int i;
840 for (i = 0; i < argc; ++i) {
841 size += strlen(args[i]);
842 }
843 char* buffer = malloc(size+1);
844 size = 0;
845 for (i = 0; i < argc; ++i) {
846 strcpy(buffer+size, args[i]);
847 size += strlen(args[i]);
848 free(args[i]);
849 }
850 free(args);
851 buffer[size] = '\0';
852
853 char* line = strtok(buffer, "\n");
854 while (line) {
855 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
856 "ui_print %s\n", line);
857 line = strtok(NULL, "\n");
858 }
859 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
860
861 return StringValue(buffer);
862}
863
864Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
865 if (argc < 1) {
866 return ErrorAbort(state, "%s() expects at least 1 arg", name);
867 }
868 char** args = ReadVarArgs(state, argc, argv);
869 if (args == NULL) {
870 return NULL;
871 }
872
873 char** args2 = malloc(sizeof(char*) * (argc+1));
874 memcpy(args2, args, sizeof(char*) * argc);
875 args2[argc] = NULL;
876
877 fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc);
878
879 pid_t child = fork();
880 if (child == 0) {
881 execv(args2[0], args2);
882 fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno));
883 _exit(1);
884 }
885 int status;
886 waitpid(child, &status, 0);
887 if (WIFEXITED(status)) {
888 if (WEXITSTATUS(status) != 0) {
889 fprintf(stderr, "run_program: child exited with status %d\n",
890 WEXITSTATUS(status));
891 }
892 } else if (WIFSIGNALED(status)) {
893 fprintf(stderr, "run_program: child terminated by signal %d\n",
894 WTERMSIG(status));
895 }
896
897 int i;
898 for (i = 0; i < argc; ++i) {
899 free(args[i]);
900 }
901 free(args);
902 free(args2);
903
904 char buffer[20];
905 sprintf(buffer, "%d", status);
906
907 return StringValue(strdup(buffer));
908}
909
910// Take a sha-1 digest and return it as a newly-allocated hex string.
911static char* PrintSha1(uint8_t* digest) {
912 char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
913 int i;
914 const char* alphabet = "0123456789abcdef";
915 for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
916 buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
917 buffer[i*2+1] = alphabet[digest[i] & 0xf];
918 }
919 buffer[i*2] = '\0';
920 return buffer;
921}
922
923// sha1_check(data)
924// to return the sha1 of the data (given in the format returned by
925// read_file).
926//
927// sha1_check(data, sha1_hex, [sha1_hex, ...])
928// returns the sha1 of the file if it matches any of the hex
929// strings passed, or "" if it does not equal any of them.
930//
931Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
932 if (argc < 1) {
933 return ErrorAbort(state, "%s() expects at least 1 arg", name);
934 }
935
936 Value** args = ReadValueVarArgs(state, argc, argv);
937 if (args == NULL) {
938 return NULL;
939 }
940
941 if (args[0]->size < 0) {
942 fprintf(stderr, "%s(): no file contents received", name);
943 return StringValue(strdup(""));
944 }
945 uint8_t digest[SHA_DIGEST_SIZE];
946 SHA(args[0]->data, args[0]->size, digest);
947 FreeValue(args[0]);
948
949 if (argc == 1) {
950 return StringValue(PrintSha1(digest));
951 }
952
953 int i;
954 uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE);
955 for (i = 1; i < argc; ++i) {
956 if (args[i]->type != VAL_STRING) {
957 fprintf(stderr, "%s(): arg %d is not a string; skipping",
958 name, i);
959 } else if (ParseSha1(args[i]->data, arg_digest) != 0) {
960 // Warn about bad args and skip them.
961 fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping",
962 name, args[i]->data);
963 } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
964 break;
965 }
966 FreeValue(args[i]);
967 }
968 if (i >= argc) {
969 // Didn't match any of the hex strings; return false.
970 return StringValue(strdup(""));
971 }
972 // Found a match; free all the remaining arguments and return the
973 // matched one.
974 int j;
975 for (j = i+1; j < argc; ++j) {
976 FreeValue(args[j]);
977 }
978 return args[i];
979}
980
981// Read a local file and return its contents (the char* returned
982// is actually a FileContents*).
983Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
984 if (argc != 1) {
985 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
986 }
987 char* filename;
988 if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
989
990 Value* v = malloc(sizeof(Value));
991 v->type = VAL_BLOB;
992
993 FileContents fc;
994 if (LoadFileContents(filename, &fc) != 0) {
995 ErrorAbort(state, "%s() loading \"%s\" failed: %s",
996 name, filename, strerror(errno));
997 free(filename);
998 free(v);
999 free(fc.data);
1000 return NULL;
1001 }
1002
1003 v->size = fc.size;
1004 v->data = (char*)fc.data;
1005
1006 free(filename);
1007 return v;
1008}
1009
1010void RegisterInstallFunctions() {
1011 RegisterFunction("mount", MountFn);
1012 RegisterFunction("is_mounted", IsMountedFn);
1013 RegisterFunction("unmount", UnmountFn);
1014 RegisterFunction("format", FormatFn);
1015 RegisterFunction("show_progress", ShowProgressFn);
1016 RegisterFunction("set_progress", SetProgressFn);
1017 RegisterFunction("delete", DeleteFn);
1018 RegisterFunction("delete_recursive", DeleteFn);
1019 RegisterFunction("package_extract_dir", PackageExtractDirFn);
1020 RegisterFunction("package_extract_file", PackageExtractFileFn);
1021 RegisterFunction("symlink", SymlinkFn);
1022 RegisterFunction("set_perm", SetPermFn);
1023 RegisterFunction("set_perm_recursive", SetPermFn);
1024
1025 RegisterFunction("getprop", GetPropFn);
1026 RegisterFunction("file_getprop", FileGetPropFn);
1027 RegisterFunction("write_raw_image", WriteRawImageFn);
1028
1029 RegisterFunction("apply_patch", ApplyPatchFn);
1030 RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
1031 RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
1032
1033 RegisterFunction("read_file", ReadFileFn);
1034 RegisterFunction("sha1_check", Sha1CheckFn);
1035
1036 RegisterFunction("ui_print", UIPrintFn);
1037
1038 RegisterFunction("run_program", RunProgramFn);
1039}