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