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