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 49Value* 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 127done: 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) 137Value* 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 159done: 160 if (result != mount_point) free(mount_point); 161 return StringValue(result); 162} 163 164 165Value* 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 189done: 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 202Value* 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 279done: 280 free(fs_type); 281 free(partition_type); 282 if (result != location) free(location); 283 return StringValue(result); 284} 285 286 287Value* 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 318Value* 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 338Value* 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) 356Value* 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*). 384Value* 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// Create all parent directories of name, if necessary. 460static int make_parents(char* name) { 461 char* p; 462 for (p = name + (strlen(name)-1); p > name; --p) { 463 if (*p != '/') continue; 464 *p = '\0'; 465 if (make_parents(name) < 0) return -1; 466 int result = mkdir(name, 0700); 467 if (result == 0) fprintf(stderr, "symlink(): created [%s]\n", name); 468 *p = '/'; 469 if (result == 0 || errno == EEXIST) { 470 // successfully created or already existed; we're done 471 return 0; 472 } else { 473 fprintf(stderr, "failed to mkdir %s: %s\n", name, strerror(errno)); 474 return -1; 475 } 476 } 477 return 0; 478} 479 480// symlink target src1 src2 ... 481// unlinks any previously existing src1, src2, etc before creating symlinks. 482Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { 483 if (argc == 0) { 484 return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc); 485 } 486 char* target; 487 target = Evaluate(state, argv[0]); 488 if (target == NULL) return NULL; 489 490 char** srcs = ReadVarArgs(state, argc-1, argv+1); 491 if (srcs == NULL) { 492 free(target); 493 return NULL; 494 } 495 496 int bad = 0; 497 int i; 498 for (i = 0; i < argc-1; ++i) { 499 if (unlink(srcs[i]) < 0) { 500 if (errno != ENOENT) { 501 fprintf(stderr, "%s: failed to remove %s: %s\n", 502 name, srcs[i], strerror(errno)); 503 ++bad; 504 } 505 } 506 if (make_parents(srcs[i])) { 507 fprintf(stderr, "%s: failed to symlink %s to %s: making parents failed\n", 508 name, srcs[i], target); 509 ++bad; 510 } 511 if (symlink(target, srcs[i]) < 0) { 512 fprintf(stderr, "%s: failed to symlink %s to %s: %s\n", 513 name, srcs[i], target, strerror(errno)); 514 ++bad; 515 } 516 free(srcs[i]); 517 } 518 free(srcs); 519 if (bad) { 520 return ErrorAbort(state, "%s: some symlinks failed", name); 521 } 522 return StringValue(strdup("")); 523} 524 525 526Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { 527 char* result = NULL; 528 bool recursive = (strcmp(name, "set_perm_recursive") == 0); 529 530 int min_args = 4 + (recursive ? 1 : 0); 531 if (argc < min_args) { 532 return ErrorAbort(state, "%s() expects %d+ args, got %d", 533 name, min_args, argc); 534 } 535 536 char** args = ReadVarArgs(state, argc, argv); 537 if (args == NULL) return NULL; 538 539 char* end; 540 int i; 541 int bad = 0; 542 543 int uid = strtoul(args[0], &end, 0); 544 if (*end != '\0' || args[0][0] == 0) { 545 ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]); 546 goto done; 547 } 548 549 int gid = strtoul(args[1], &end, 0); 550 if (*end != '\0' || args[1][0] == 0) { 551 ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]); 552 goto done; 553 } 554 555 if (recursive) { 556 int dir_mode = strtoul(args[2], &end, 0); 557 if (*end != '\0' || args[2][0] == 0) { 558 ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]); 559 goto done; 560 } 561 562 int file_mode = strtoul(args[3], &end, 0); 563 if (*end != '\0' || args[3][0] == 0) { 564 ErrorAbort(state, "%s: \"%s\" not a valid filemode", 565 name, args[3]); 566 goto done; 567 } 568 569 for (i = 4; i < argc; ++i) { 570 dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode); 571 } 572 } else { 573 int mode = strtoul(args[2], &end, 0); 574 if (*end != '\0' || args[2][0] == 0) { 575 ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]); 576 goto done; 577 } 578 579 for (i = 3; i < argc; ++i) { 580 if (chown(args[i], uid, gid) < 0) { 581 fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n", 582 name, args[i], uid, gid, strerror(errno)); 583 ++bad; 584 } 585 if (chmod(args[i], mode) < 0) { 586 fprintf(stderr, "%s: chmod of %s to %o failed: %s\n", 587 name, args[i], mode, strerror(errno)); 588 ++bad; 589 } 590 } 591 } 592 result = strdup(""); 593 594done: 595 for (i = 0; i < argc; ++i) { 596 free(args[i]); 597 } 598 free(args); 599 600 if (bad) { 601 free(result); 602 return ErrorAbort(state, "%s: some changes failed", name); 603 } 604 return StringValue(result); 605} 606 607 608Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { 609 if (argc != 1) { 610 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); 611 } 612 char* key; 613 key = Evaluate(state, argv[0]); 614 if (key == NULL) return NULL; 615 616 char value[PROPERTY_VALUE_MAX]; 617 property_get(key, value, ""); 618 free(key); 619 620 return StringValue(strdup(value)); 621} 622 623 624// file_getprop(file, key) 625// 626// interprets 'file' as a getprop-style file (key=value pairs, one 627// per line, # comment lines and blank lines okay), and returns the value 628// for 'key' (or "" if it isn't defined). 629Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { 630 char* result = NULL; 631 char* buffer = NULL; 632 char* filename; 633 char* key; 634 if (ReadArgs(state, argv, 2, &filename, &key) < 0) { 635 return NULL; 636 } 637 638 struct stat st; 639 if (stat(filename, &st) < 0) { 640 ErrorAbort(state, "%s: failed to stat \"%s\": %s", 641 name, filename, strerror(errno)); 642 goto done; 643 } 644 645#define MAX_FILE_GETPROP_SIZE 65536 646 647 if (st.st_size > MAX_FILE_GETPROP_SIZE) { 648 ErrorAbort(state, "%s too large for %s (max %d)", 649 filename, name, MAX_FILE_GETPROP_SIZE); 650 goto done; 651 } 652 653 buffer = malloc(st.st_size+1); 654 if (buffer == NULL) { 655 ErrorAbort(state, "%s: failed to alloc %lld bytes", name, st.st_size+1); 656 goto done; 657 } 658 659 FILE* f = fopen(filename, "rb"); 660 if (f == NULL) { 661 ErrorAbort(state, "%s: failed to open %s: %s", 662 name, filename, strerror(errno)); 663 goto done; 664 } 665 666 if (fread(buffer, 1, st.st_size, f) != st.st_size) { 667 ErrorAbort(state, "%s: failed to read %lld bytes from %s", 668 name, st.st_size+1, filename); 669 fclose(f); 670 goto done; 671 } 672 buffer[st.st_size] = '\0'; 673 674 fclose(f); 675 676 char* line = strtok(buffer, "\n"); 677 do { 678 // skip whitespace at start of line 679 while (*line && isspace(*line)) ++line; 680 681 // comment or blank line: skip to next line 682 if (*line == '\0' || *line == '#') continue; 683 684 char* equal = strchr(line, '='); 685 if (equal == NULL) { 686 ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?", 687 name, line, filename); 688 goto done; 689 } 690 691 // trim whitespace between key and '=' 692 char* key_end = equal-1; 693 while (key_end > line && isspace(*key_end)) --key_end; 694 key_end[1] = '\0'; 695 696 // not the key we're looking for 697 if (strcmp(key, line) != 0) continue; 698 699 // skip whitespace after the '=' to the start of the value 700 char* val_start = equal+1; 701 while(*val_start && isspace(*val_start)) ++val_start; 702 703 // trim trailing whitespace 704 char* val_end = val_start + strlen(val_start)-1; 705 while (val_end > val_start && isspace(*val_end)) --val_end; 706 val_end[1] = '\0'; 707 708 result = strdup(val_start); 709 break; 710 711 } while ((line = strtok(NULL, "\n"))); 712 713 if (result == NULL) result = strdup(""); 714 715 done: 716 free(filename); 717 free(key); 718 free(buffer); 719 return StringValue(result); 720} 721 722 723static bool write_raw_image_cb(const unsigned char* data, 724 int data_len, void* ctx) { 725 int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len); 726 if (r == data_len) return true; 727 fprintf(stderr, "%s\n", strerror(errno)); 728 return false; 729} 730 731// write_raw_image(filename_or_blob, partition) 732Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { 733 char* result = NULL; 734 735 Value* partition_value; 736 Value* contents; 737 if (ReadValueArgs(state, argv, 2, &contents, &partition_value) < 0) { 738 return NULL; 739 } 740 741 char* partition = NULL; 742 if (partition_value->type != VAL_STRING) { 743 ErrorAbort(state, "partition argument to %s must be string", name); 744 goto done; 745 } 746 partition = partition_value->data; 747 if (strlen(partition) == 0) { 748 ErrorAbort(state, "partition argument to %s can't be empty", name); 749 goto done; 750 } 751 if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) { 752 ErrorAbort(state, "file argument to %s can't be empty", name); 753 goto done; 754 } 755 756 mtd_scan_partitions(); 757 const MtdPartition* mtd = mtd_find_partition_by_name(partition); 758 if (mtd == NULL) { 759 fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition); 760 result = strdup(""); 761 goto done; 762 } 763 764 MtdWriteContext* ctx = mtd_write_partition(mtd); 765 if (ctx == NULL) { 766 fprintf(stderr, "%s: can't write mtd partition \"%s\"\n", 767 name, partition); 768 result = strdup(""); 769 goto done; 770 } 771 772 bool success; 773 774 if (contents->type == VAL_STRING) { 775 // we're given a filename as the contents 776 char* filename = contents->data; 777 FILE* f = fopen(filename, "rb"); 778 if (f == NULL) { 779 fprintf(stderr, "%s: can't open %s: %s\n", 780 name, filename, strerror(errno)); 781 result = strdup(""); 782 goto done; 783 } 784 785 success = true; 786 char* buffer = malloc(BUFSIZ); 787 int read; 788 while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) { 789 int wrote = mtd_write_data(ctx, buffer, read); 790 success = success && (wrote == read); 791 } 792 free(buffer); 793 fclose(f); 794 } else { 795 // we're given a blob as the contents 796 ssize_t wrote = mtd_write_data(ctx, contents->data, contents->size); 797 success = (wrote == contents->size); 798 } 799 if (!success) { 800 fprintf(stderr, "mtd_write_data to %s failed: %s\n", 801 partition, strerror(errno)); 802 } 803 804 if (mtd_erase_blocks(ctx, -1) == -1) { 805 fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition); 806 } 807 if (mtd_write_close(ctx) != 0) { 808 fprintf(stderr, "%s: error closing write of %s\n", name, partition); 809 } 810 811 printf("%s %s partition\n", 812 success ? "wrote" : "failed to write", partition); 813 814 result = success ? partition : strdup(""); 815 816done: 817 if (result != partition) FreeValue(partition_value); 818 FreeValue(contents); 819 return StringValue(result); 820} 821 822// apply_patch_space(bytes) 823Value* ApplyPatchSpaceFn(const char* name, State* state, 824 int argc, Expr* argv[]) { 825 char* bytes_str; 826 if (ReadArgs(state, argv, 1, &bytes_str) < 0) { 827 return NULL; 828 } 829 830 char* endptr; 831 size_t bytes = strtol(bytes_str, &endptr, 10); 832 if (bytes == 0 && endptr == bytes_str) { 833 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n", 834 name, bytes_str); 835 free(bytes_str); 836 return NULL; 837 } 838 839 return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t")); 840} 841 842 843// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...) 844Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { 845 if (argc < 6 || (argc % 2) == 1) { 846 return ErrorAbort(state, "%s(): expected at least 6 args and an " 847 "even number, got %d", 848 name, argc); 849 } 850 851 char* source_filename; 852 char* target_filename; 853 char* target_sha1; 854 char* target_size_str; 855 if (ReadArgs(state, argv, 4, &source_filename, &target_filename, 856 &target_sha1, &target_size_str) < 0) { 857 return NULL; 858 } 859 860 char* endptr; 861 size_t target_size = strtol(target_size_str, &endptr, 10); 862 if (target_size == 0 && endptr == target_size_str) { 863 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count", 864 name, target_size_str); 865 free(source_filename); 866 free(target_filename); 867 free(target_sha1); 868 free(target_size_str); 869 return NULL; 870 } 871 872 int patchcount = (argc-4) / 2; 873 Value** patches = ReadValueVarArgs(state, argc-4, argv+4); 874 875 int i; 876 for (i = 0; i < patchcount; ++i) { 877 if (patches[i*2]->type != VAL_STRING) { 878 ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i); 879 break; 880 } 881 if (patches[i*2+1]->type != VAL_BLOB) { 882 ErrorAbort(state, "%s(): patch #%d is not blob", name, i); 883 break; 884 } 885 } 886 if (i != patchcount) { 887 for (i = 0; i < patchcount*2; ++i) { 888 FreeValue(patches[i]); 889 } 890 free(patches); 891 return NULL; 892 } 893 894 char** patch_sha_str = malloc(patchcount * sizeof(char*)); 895 for (i = 0; i < patchcount; ++i) { 896 patch_sha_str[i] = patches[i*2]->data; 897 patches[i*2]->data = NULL; 898 FreeValue(patches[i*2]); 899 patches[i] = patches[i*2+1]; 900 } 901 902 int result = applypatch(source_filename, target_filename, 903 target_sha1, target_size, 904 patchcount, patch_sha_str, patches, NULL); 905 906 for (i = 0; i < patchcount; ++i) { 907 FreeValue(patches[i]); 908 } 909 free(patch_sha_str); 910 free(patches); 911 912 return StringValue(strdup(result == 0 ? "t" : "")); 913} 914 915// apply_patch_check(file, [sha1_1, ...]) 916Value* ApplyPatchCheckFn(const char* name, State* state, 917 int argc, Expr* argv[]) { 918 if (argc < 1) { 919 return ErrorAbort(state, "%s(): expected at least 1 arg, got %d", 920 name, argc); 921 } 922 923 char* filename; 924 if (ReadArgs(state, argv, 1, &filename) < 0) { 925 return NULL; 926 } 927 928 int patchcount = argc-1; 929 char** sha1s = ReadVarArgs(state, argc-1, argv+1); 930 931 int result = applypatch_check(filename, patchcount, sha1s); 932 933 int i; 934 for (i = 0; i < patchcount; ++i) { 935 free(sha1s[i]); 936 } 937 free(sha1s); 938 939 return StringValue(strdup(result == 0 ? "t" : "")); 940} 941 942Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { 943 char** args = ReadVarArgs(state, argc, argv); 944 if (args == NULL) { 945 return NULL; 946 } 947 948 int size = 0; 949 int i; 950 for (i = 0; i < argc; ++i) { 951 size += strlen(args[i]); 952 } 953 char* buffer = malloc(size+1); 954 size = 0; 955 for (i = 0; i < argc; ++i) { 956 strcpy(buffer+size, args[i]); 957 size += strlen(args[i]); 958 free(args[i]); 959 } 960 free(args); 961 buffer[size] = '\0'; 962 963 char* line = strtok(buffer, "\n"); 964 while (line) { 965 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, 966 "ui_print %s\n", line); 967 line = strtok(NULL, "\n"); 968 } 969 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n"); 970 971 return StringValue(buffer); 972} 973 974Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) { 975 if (argc != 0) { 976 return ErrorAbort(state, "%s() expects no args, got %d", name, argc); 977 } 978 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "wipe_cache\n"); 979 return StringValue(strdup("t")); 980} 981 982Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { 983 if (argc < 1) { 984 return ErrorAbort(state, "%s() expects at least 1 arg", name); 985 } 986 char** args = ReadVarArgs(state, argc, argv); 987 if (args == NULL) { 988 return NULL; 989 } 990 991 char** args2 = malloc(sizeof(char*) * (argc+1)); 992 memcpy(args2, args, sizeof(char*) * argc); 993 args2[argc] = NULL; 994 995 fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc); 996 997 pid_t child = fork(); 998 if (child == 0) { 999 execv(args2[0], args2); 1000 fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno)); 1001 _exit(1); 1002 } 1003 int status; 1004 waitpid(child, &status, 0); 1005 if (WIFEXITED(status)) { 1006 if (WEXITSTATUS(status) != 0) { 1007 fprintf(stderr, "run_program: child exited with status %d\n", 1008 WEXITSTATUS(status)); 1009 } 1010 } else if (WIFSIGNALED(status)) { 1011 fprintf(stderr, "run_program: child terminated by signal %d\n", 1012 WTERMSIG(status)); 1013 } 1014 1015 int i; 1016 for (i = 0; i < argc; ++i) { 1017 free(args[i]); 1018 } 1019 free(args); 1020 free(args2); 1021 1022 char buffer[20]; 1023 sprintf(buffer, "%d", status); 1024 1025 return StringValue(strdup(buffer)); 1026} 1027 1028// Take a sha-1 digest and return it as a newly-allocated hex string. 1029static char* PrintSha1(uint8_t* digest) { 1030 char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1); 1031 int i; 1032 const char* alphabet = "0123456789abcdef"; 1033 for (i = 0; i < SHA_DIGEST_SIZE; ++i) { 1034 buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf]; 1035 buffer[i*2+1] = alphabet[digest[i] & 0xf]; 1036 } 1037 buffer[i*2] = '\0'; 1038 return buffer; 1039} 1040 1041// sha1_check(data) 1042// to return the sha1 of the data (given in the format returned by 1043// read_file). 1044// 1045// sha1_check(data, sha1_hex, [sha1_hex, ...]) 1046// returns the sha1 of the file if it matches any of the hex 1047// strings passed, or "" if it does not equal any of them. 1048// 1049Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { 1050 if (argc < 1) { 1051 return ErrorAbort(state, "%s() expects at least 1 arg", name); 1052 } 1053 1054 Value** args = ReadValueVarArgs(state, argc, argv); 1055 if (args == NULL) { 1056 return NULL; 1057 } 1058 1059 if (args[0]->size < 0) { 1060 fprintf(stderr, "%s(): no file contents received", name); 1061 return StringValue(strdup("")); 1062 } 1063 uint8_t digest[SHA_DIGEST_SIZE]; 1064 SHA(args[0]->data, args[0]->size, digest); 1065 FreeValue(args[0]); 1066 1067 if (argc == 1) { 1068 return StringValue(PrintSha1(digest)); 1069 } 1070 1071 int i; 1072 uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE); 1073 for (i = 1; i < argc; ++i) { 1074 if (args[i]->type != VAL_STRING) { 1075 fprintf(stderr, "%s(): arg %d is not a string; skipping", 1076 name, i); 1077 } else if (ParseSha1(args[i]->data, arg_digest) != 0) { 1078 // Warn about bad args and skip them. 1079 fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping", 1080 name, args[i]->data); 1081 } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) { 1082 break; 1083 } 1084 FreeValue(args[i]); 1085 } 1086 if (i >= argc) { 1087 // Didn't match any of the hex strings; return false. 1088 return StringValue(strdup("")); 1089 } 1090 // Found a match; free all the remaining arguments and return the 1091 // matched one. 1092 int j; 1093 for (j = i+1; j < argc; ++j) { 1094 FreeValue(args[j]); 1095 } 1096 return args[i]; 1097} 1098 1099// Read a local file and return its contents (the Value* returned 1100// is actually a FileContents*). 1101Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) { 1102 if (argc != 1) { 1103 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); 1104 } 1105 char* filename; 1106 if (ReadArgs(state, argv, 1, &filename) < 0) return NULL; 1107 1108 Value* v = malloc(sizeof(Value)); 1109 v->type = VAL_BLOB; 1110 1111 FileContents fc; 1112 if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) { 1113 ErrorAbort(state, "%s() loading \"%s\" failed: %s", 1114 name, filename, strerror(errno)); 1115 free(filename); 1116 free(v); 1117 free(fc.data); 1118 return NULL; 1119 } 1120 1121 v->size = fc.size; 1122 v->data = (char*)fc.data; 1123 1124 free(filename); 1125 return v; 1126} 1127 1128void RegisterInstallFunctions() { 1129 RegisterFunction("mount", MountFn); 1130 RegisterFunction("is_mounted", IsMountedFn); 1131 RegisterFunction("unmount", UnmountFn); 1132 RegisterFunction("format", FormatFn); 1133 RegisterFunction("show_progress", ShowProgressFn); 1134 RegisterFunction("set_progress", SetProgressFn); 1135 RegisterFunction("delete", DeleteFn); 1136 RegisterFunction("delete_recursive", DeleteFn); 1137 RegisterFunction("package_extract_dir", PackageExtractDirFn); 1138 RegisterFunction("package_extract_file", PackageExtractFileFn); 1139 RegisterFunction("symlink", SymlinkFn); 1140 RegisterFunction("set_perm", SetPermFn); 1141 RegisterFunction("set_perm_recursive", SetPermFn); 1142 1143 RegisterFunction("getprop", GetPropFn); 1144 RegisterFunction("file_getprop", FileGetPropFn); 1145 RegisterFunction("write_raw_image", WriteRawImageFn); 1146 1147 RegisterFunction("apply_patch", ApplyPatchFn); 1148 RegisterFunction("apply_patch_check", ApplyPatchCheckFn); 1149 RegisterFunction("apply_patch_space", ApplyPatchSpaceFn); 1150 1151 RegisterFunction("read_file", ReadFileFn); 1152 RegisterFunction("sha1_check", Sha1CheckFn); 1153 1154 RegisterFunction("wipe_cache", WipeCacheFn); 1155 1156 RegisterFunction("ui_print", UIPrintFn); 1157 1158 RegisterFunction("run_program", RunProgramFn); 1159} 1160