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 50 Value* 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 112 done: 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) 122 Value* 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 144 done: 145 if (result != mount_point) free(mount_point); 146 return StringValue(result); 147 } 148 149 150 Value* 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 174 done: 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 187 Value* 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 257 done: 258 free(fs_type); 259 free(partition_type); 260 if (result != location) free(location); 261 return StringValue(result); 262 } 263 264 265 Value* 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 296 Value* 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 316 Value* 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) 334 Value* 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*). 362 Value* 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, ...) 439 Value* 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, ...) 511 Value* 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. 555 Value* 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 588 Value* 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 652 done: 653 for (i = 0; i < argc; ++i) { 654 free(args[i]); 655 } 656 free(args); 657 658 return StringValue(result); 659 } 660 661 662 Value* 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). 683 Value* 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 777 static 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) 786 Value* 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 if (partition_value->type != VAL_STRING) { 796 ErrorAbort(state, "partition argument to %s must be string", name); 797 goto done; 798 } 799 char* partition = partition_value->data; 800 if (strlen(partition) == 0) { 801 ErrorAbort(state, "partition argument to %s can't be empty", name); 802 goto done; 803 } 804 if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) { 805 ErrorAbort(state, "file argument to %s can't be empty", name); 806 goto done; 807 } 808 809 mtd_scan_partitions(); 810 const MtdPartition* mtd = mtd_find_partition_by_name(partition); 811 if (mtd == NULL) { 812 fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition); 813 result = strdup(""); 814 goto done; 815 } 816 817 MtdWriteContext* ctx = mtd_write_partition(mtd); 818 if (ctx == NULL) { 819 fprintf(stderr, "%s: can't write mtd partition \"%s\"\n", 820 name, partition); 821 result = strdup(""); 822 goto done; 823 } 824 825 bool success; 826 827 if (contents->type == VAL_STRING) { 828 // we're given a filename as the contents 829 char* filename = contents->data; 830 FILE* f = fopen(filename, "rb"); 831 if (f == NULL) { 832 fprintf(stderr, "%s: can't open %s: %s\n", 833 name, filename, strerror(errno)); 834 result = strdup(""); 835 goto done; 836 } 837 838 success = true; 839 char* buffer = malloc(BUFSIZ); 840 int read; 841 while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) { 842 int wrote = mtd_write_data(ctx, buffer, read); 843 success = success && (wrote == read); 844 } 845 free(buffer); 846 fclose(f); 847 } else { 848 // we're given a blob as the contents 849 ssize_t wrote = mtd_write_data(ctx, contents->data, contents->size); 850 success = (wrote == contents->size); 851 } 852 if (!success) { 853 fprintf(stderr, "mtd_write_data to %s failed: %s\n", 854 partition, strerror(errno)); 855 } 856 857 if (mtd_erase_blocks(ctx, -1) == -1) { 858 fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition); 859 } 860 if (mtd_write_close(ctx) != 0) { 861 fprintf(stderr, "%s: error closing write of %s\n", name, partition); 862 } 863 864 printf("%s %s partition\n", 865 success ? "wrote" : "failed to write", partition); 866 867 result = success ? partition : strdup(""); 868 869 done: 870 if (result != partition) FreeValue(partition_value); 871 FreeValue(contents); 872 return StringValue(result); 873 } 874 875 // apply_patch_space(bytes) 876 Value* ApplyPatchSpaceFn(const char* name, State* state, 877 int argc, Expr* argv[]) { 878 char* bytes_str; 879 if (ReadArgs(state, argv, 1, &bytes_str) < 0) { 880 return NULL; 881 } 882 883 char* endptr; 884 size_t bytes = strtol(bytes_str, &endptr, 10); 885 if (bytes == 0 && endptr == bytes_str) { 886 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n", 887 name, bytes_str); 888 free(bytes_str); 889 return NULL; 890 } 891 892 return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t")); 893 } 894 895 896 // apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...) 897 Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { 898 if (argc < 6 || (argc % 2) == 1) { 899 return ErrorAbort(state, "%s(): expected at least 6 args and an " 900 "even number, got %d", 901 name, argc); 902 } 903 904 char* source_filename; 905 char* target_filename; 906 char* target_sha1; 907 char* target_size_str; 908 if (ReadArgs(state, argv, 4, &source_filename, &target_filename, 909 &target_sha1, &target_size_str) < 0) { 910 return NULL; 911 } 912 913 char* endptr; 914 size_t target_size = strtol(target_size_str, &endptr, 10); 915 if (target_size == 0 && endptr == target_size_str) { 916 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count", 917 name, target_size_str); 918 free(source_filename); 919 free(target_filename); 920 free(target_sha1); 921 free(target_size_str); 922 return NULL; 923 } 924 925 int patchcount = (argc-4) / 2; 926 Value** patches = ReadValueVarArgs(state, argc-4, argv+4); 927 928 int i; 929 for (i = 0; i < patchcount; ++i) { 930 if (patches[i*2]->type != VAL_STRING) { 931 ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i); 932 break; 933 } 934 if (patches[i*2+1]->type != VAL_BLOB) { 935 ErrorAbort(state, "%s(): patch #%d is not blob", name, i); 936 break; 937 } 938 } 939 if (i != patchcount) { 940 for (i = 0; i < patchcount*2; ++i) { 941 FreeValue(patches[i]); 942 } 943 free(patches); 944 return NULL; 945 } 946 947 char** patch_sha_str = malloc(patchcount * sizeof(char*)); 948 for (i = 0; i < patchcount; ++i) { 949 patch_sha_str[i] = patches[i*2]->data; 950 patches[i*2]->data = NULL; 951 FreeValue(patches[i*2]); 952 patches[i] = patches[i*2+1]; 953 } 954 955 int result = applypatch(source_filename, target_filename, 956 target_sha1, target_size, 957 patchcount, patch_sha_str, patches); 958 959 for (i = 0; i < patchcount; ++i) { 960 FreeValue(patches[i]); 961 } 962 free(patch_sha_str); 963 free(patches); 964 965 return StringValue(strdup(result == 0 ? "t" : "")); 966 } 967 968 // apply_patch_check(file, [sha1_1, ...]) 969 Value* ApplyPatchCheckFn(const char* name, State* state, 970 int argc, Expr* argv[]) { 971 if (argc < 1) { 972 return ErrorAbort(state, "%s(): expected at least 1 arg, got %d", 973 name, argc); 974 } 975 976 char* filename; 977 if (ReadArgs(state, argv, 1, &filename) < 0) { 978 return NULL; 979 } 980 981 int patchcount = argc-1; 982 char** sha1s = ReadVarArgs(state, argc-1, argv+1); 983 984 int result = applypatch_check(filename, patchcount, sha1s); 985 986 int i; 987 for (i = 0; i < patchcount; ++i) { 988 free(sha1s[i]); 989 } 990 free(sha1s); 991 992 return StringValue(strdup(result == 0 ? "t" : "")); 993 } 994 995 Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { 996 char** args = ReadVarArgs(state, argc, argv); 997 if (args == NULL) { 998 return NULL; 999 } 1000 1001 int size = 0; 1002 int i; 1003 for (i = 0; i < argc; ++i) { 1004 size += strlen(args[i]); 1005 } 1006 char* buffer = malloc(size+1); 1007 size = 0; 1008 for (i = 0; i < argc; ++i) { 1009 strcpy(buffer+size, args[i]); 1010 size += strlen(args[i]); 1011 free(args[i]); 1012 } 1013 free(args); 1014 buffer[size] = '\0'; 1015 1016 char* line = strtok(buffer, "\n"); 1017 while (line) { 1018 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, 1019 "ui_print %s\n", line); 1020 line = strtok(NULL, "\n"); 1021 } 1022 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n"); 1023 1024 return StringValue(buffer); 1025 } 1026 1027 Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { 1028 if (argc < 1) { 1029 return ErrorAbort(state, "%s() expects at least 1 arg", name); 1030 } 1031 char** args = ReadVarArgs(state, argc, argv); 1032 if (args == NULL) { 1033 return NULL; 1034 } 1035 1036 char** args2 = malloc(sizeof(char*) * (argc+1)); 1037 memcpy(args2, args, sizeof(char*) * argc); 1038 args2[argc] = NULL; 1039 1040 fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc); 1041 1042 pid_t child = fork(); 1043 if (child == 0) { 1044 execv(args2[0], args2); 1045 fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno)); 1046 _exit(1); 1047 } 1048 int status; 1049 waitpid(child, &status, 0); 1050 if (WIFEXITED(status)) { 1051 if (WEXITSTATUS(status) != 0) { 1052 fprintf(stderr, "run_program: child exited with status %d\n", 1053 WEXITSTATUS(status)); 1054 } 1055 } else if (WIFSIGNALED(status)) { 1056 fprintf(stderr, "run_program: child terminated by signal %d\n", 1057 WTERMSIG(status)); 1058 } 1059 1060 int i; 1061 for (i = 0; i < argc; ++i) { 1062 free(args[i]); 1063 } 1064 free(args); 1065 free(args2); 1066 1067 char buffer[20]; 1068 sprintf(buffer, "%d", status); 1069 1070 return StringValue(strdup(buffer)); 1071 } 1072 1073 // Take a sha-1 digest and return it as a newly-allocated hex string. 1074 static char* PrintSha1(uint8_t* digest) { 1075 char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1); 1076 int i; 1077 const char* alphabet = "0123456789abcdef"; 1078 for (i = 0; i < SHA_DIGEST_SIZE; ++i) { 1079 buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf]; 1080 buffer[i*2+1] = alphabet[digest[i] & 0xf]; 1081 } 1082 buffer[i*2] = '\0'; 1083 return buffer; 1084 } 1085 1086 // sha1_check(data) 1087 // to return the sha1 of the data (given in the format returned by 1088 // read_file). 1089 // 1090 // sha1_check(data, sha1_hex, [sha1_hex, ...]) 1091 // returns the sha1 of the file if it matches any of the hex 1092 // strings passed, or "" if it does not equal any of them. 1093 // 1094 Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { 1095 if (argc < 1) { 1096 return ErrorAbort(state, "%s() expects at least 1 arg", name); 1097 } 1098 1099 Value** args = ReadValueVarArgs(state, argc, argv); 1100 if (args == NULL) { 1101 return NULL; 1102 } 1103 1104 if (args[0]->size < 0) { 1105 fprintf(stderr, "%s(): no file contents received", name); 1106 return StringValue(strdup("")); 1107 } 1108 uint8_t digest[SHA_DIGEST_SIZE]; 1109 SHA(args[0]->data, args[0]->size, digest); 1110 FreeValue(args[0]); 1111 1112 if (argc == 1) { 1113 return StringValue(PrintSha1(digest)); 1114 } 1115 1116 int i; 1117 uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE); 1118 for (i = 1; i < argc; ++i) { 1119 if (args[i]->type != VAL_STRING) { 1120 fprintf(stderr, "%s(): arg %d is not a string; skipping", 1121 name, i); 1122 } else if (ParseSha1(args[i]->data, arg_digest) != 0) { 1123 // Warn about bad args and skip them. 1124 fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping", 1125 name, args[i]->data); 1126 } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) { 1127 break; 1128 } 1129 FreeValue(args[i]); 1130 } 1131 if (i >= argc) { 1132 // Didn't match any of the hex strings; return false. 1133 return StringValue(strdup("")); 1134 } 1135 // Found a match; free all the remaining arguments and return the 1136 // matched one. 1137 int j; 1138 for (j = i+1; j < argc; ++j) { 1139 FreeValue(args[j]); 1140 } 1141 return args[i]; 1142 } 1143 1144 // Read a local file and return its contents (the Value* returned 1145 // is actually a FileContents*). 1146 Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) { 1147 if (argc != 1) { 1148 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); 1149 } 1150 char* filename; 1151 if (ReadArgs(state, argv, 1, &filename) < 0) return NULL; 1152 1153 Value* v = malloc(sizeof(Value)); 1154 v->type = VAL_BLOB; 1155 1156 FileContents fc; 1157 if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) { 1158 ErrorAbort(state, "%s() loading \"%s\" failed: %s", 1159 name, filename, strerror(errno)); 1160 free(filename); 1161 free(v); 1162 free(fc.data); 1163 return NULL; 1164 } 1165 1166 v->size = fc.size; 1167 v->data = (char*)fc.data; 1168 1169 free(filename); 1170 return v; 1171 } 1172 1173 void RegisterInstallFunctions() { 1174 RegisterFunction("mount", MountFn); 1175 RegisterFunction("is_mounted", IsMountedFn); 1176 RegisterFunction("unmount", UnmountFn); 1177 RegisterFunction("format", FormatFn); 1178 RegisterFunction("show_progress", ShowProgressFn); 1179 RegisterFunction("set_progress", SetProgressFn); 1180 RegisterFunction("delete", DeleteFn); 1181 RegisterFunction("delete_recursive", DeleteFn); 1182 RegisterFunction("package_extract_dir", PackageExtractDirFn); 1183 RegisterFunction("package_extract_file", PackageExtractFileFn); 1184 RegisterFunction("retouch_binaries", RetouchBinariesFn); 1185 RegisterFunction("undo_retouch_binaries", UndoRetouchBinariesFn); 1186 RegisterFunction("symlink", SymlinkFn); 1187 RegisterFunction("set_perm", SetPermFn); 1188 RegisterFunction("set_perm_recursive", SetPermFn); 1189 1190 RegisterFunction("getprop", GetPropFn); 1191 RegisterFunction("file_getprop", FileGetPropFn); 1192 RegisterFunction("write_raw_image", WriteRawImageFn); 1193 1194 RegisterFunction("apply_patch", ApplyPatchFn); 1195 RegisterFunction("apply_patch_check", ApplyPatchCheckFn); 1196 RegisterFunction("apply_patch_space", ApplyPatchSpaceFn); 1197 1198 RegisterFunction("read_file", ReadFileFn); 1199 RegisterFunction("sha1_check", Sha1CheckFn); 1200 1201 RegisterFunction("ui_print", UIPrintFn); 1202 1203 RegisterFunction("run_program", RunProgramFn); 1204 } 1205