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