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 #include <selinux/selinux.h> 31 #include <ftw.h> 32 #include <sys/capability.h> 33 #include <sys/xattr.h> 34 #include <linux/xattr.h> 35 #include <inttypes.h> 36 37 #include "bootloader.h" 38 #include "applypatch/applypatch.h" 39 #include "cutils/android_reboot.h" 40 #include "cutils/misc.h" 41 #include "cutils/properties.h" 42 #include "edify/expr.h" 43 #include "mincrypt/sha.h" 44 #include "minzip/DirUtil.h" 45 #include "mtdutils/mounts.h" 46 #include "mtdutils/mtdutils.h" 47 #include "updater.h" 48 49 #ifdef USE_EXT4 50 #include "make_ext4fs.h" 51 #endif 52 53 // mount(fs_type, partition_type, location, mount_point) 54 // 55 // fs_type="yaffs2" partition_type="MTD" location=partition 56 // fs_type="ext4" partition_type="EMMC" location=device 57 Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { 58 char* result = NULL; 59 if (argc != 4) { 60 return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc); 61 } 62 char* fs_type; 63 char* partition_type; 64 char* location; 65 char* mount_point; 66 if (ReadArgs(state, argv, 4, &fs_type, &partition_type, 67 &location, &mount_point) < 0) { 68 return NULL; 69 } 70 71 if (strlen(fs_type) == 0) { 72 ErrorAbort(state, "fs_type argument to %s() can't be empty", name); 73 goto done; 74 } 75 if (strlen(partition_type) == 0) { 76 ErrorAbort(state, "partition_type argument to %s() can't be empty", 77 name); 78 goto done; 79 } 80 if (strlen(location) == 0) { 81 ErrorAbort(state, "location argument to %s() can't be empty", name); 82 goto done; 83 } 84 if (strlen(mount_point) == 0) { 85 ErrorAbort(state, "mount_point argument to %s() can't be empty", name); 86 goto done; 87 } 88 89 char *secontext = NULL; 90 91 if (sehandle) { 92 selabel_lookup(sehandle, &secontext, mount_point, 0755); 93 setfscreatecon(secontext); 94 } 95 96 mkdir(mount_point, 0755); 97 98 if (secontext) { 99 freecon(secontext); 100 setfscreatecon(NULL); 101 } 102 103 if (strcmp(partition_type, "MTD") == 0) { 104 mtd_scan_partitions(); 105 const MtdPartition* mtd; 106 mtd = mtd_find_partition_by_name(location); 107 if (mtd == NULL) { 108 printf("%s: no mtd partition named \"%s\"", 109 name, location); 110 result = strdup(""); 111 goto done; 112 } 113 if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) { 114 printf("mtd mount of %s failed: %s\n", 115 location, strerror(errno)); 116 result = strdup(""); 117 goto done; 118 } 119 result = mount_point; 120 } else { 121 if (mount(location, mount_point, fs_type, 122 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) { 123 printf("%s: failed to mount %s at %s: %s\n", 124 name, location, mount_point, strerror(errno)); 125 result = strdup(""); 126 } else { 127 result = mount_point; 128 } 129 } 130 131 done: 132 free(fs_type); 133 free(partition_type); 134 free(location); 135 if (result != mount_point) free(mount_point); 136 return StringValue(result); 137 } 138 139 140 // is_mounted(mount_point) 141 Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) { 142 char* result = NULL; 143 if (argc != 1) { 144 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); 145 } 146 char* mount_point; 147 if (ReadArgs(state, argv, 1, &mount_point) < 0) { 148 return NULL; 149 } 150 if (strlen(mount_point) == 0) { 151 ErrorAbort(state, "mount_point argument to unmount() can't be empty"); 152 goto done; 153 } 154 155 scan_mounted_volumes(); 156 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); 157 if (vol == NULL) { 158 result = strdup(""); 159 } else { 160 result = mount_point; 161 } 162 163 done: 164 if (result != mount_point) free(mount_point); 165 return StringValue(result); 166 } 167 168 169 Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) { 170 char* result = NULL; 171 if (argc != 1) { 172 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); 173 } 174 char* mount_point; 175 if (ReadArgs(state, argv, 1, &mount_point) < 0) { 176 return NULL; 177 } 178 if (strlen(mount_point) == 0) { 179 ErrorAbort(state, "mount_point argument to unmount() can't be empty"); 180 goto done; 181 } 182 183 scan_mounted_volumes(); 184 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); 185 if (vol == NULL) { 186 printf("unmount of %s failed; no such volume\n", mount_point); 187 result = strdup(""); 188 } else { 189 unmount_mounted_volume(vol); 190 result = mount_point; 191 } 192 193 done: 194 if (result != mount_point) free(mount_point); 195 return StringValue(result); 196 } 197 198 199 // format(fs_type, partition_type, location, fs_size, mount_point) 200 // 201 // fs_type="yaffs2" partition_type="MTD" location=partition fs_size=<bytes> mount_point=<location> 202 // fs_type="ext4" partition_type="EMMC" location=device fs_size=<bytes> mount_point=<location> 203 // if fs_size == 0, then make_ext4fs uses the entire partition. 204 // if fs_size > 0, that is the size to use 205 // if fs_size < 0, then reserve that many bytes at the end of the partition 206 Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { 207 char* result = NULL; 208 if (argc != 5) { 209 return ErrorAbort(state, "%s() expects 5 args, got %d", name, argc); 210 } 211 char* fs_type; 212 char* partition_type; 213 char* location; 214 char* fs_size; 215 char* mount_point; 216 217 if (ReadArgs(state, argv, 5, &fs_type, &partition_type, &location, &fs_size, &mount_point) < 0) { 218 return NULL; 219 } 220 221 if (strlen(fs_type) == 0) { 222 ErrorAbort(state, "fs_type argument to %s() can't be empty", name); 223 goto done; 224 } 225 if (strlen(partition_type) == 0) { 226 ErrorAbort(state, "partition_type argument to %s() can't be empty", 227 name); 228 goto done; 229 } 230 if (strlen(location) == 0) { 231 ErrorAbort(state, "location argument to %s() can't be empty", name); 232 goto done; 233 } 234 235 if (strlen(mount_point) == 0) { 236 ErrorAbort(state, "mount_point argument to %s() can't be empty", name); 237 goto done; 238 } 239 240 if (strcmp(partition_type, "MTD") == 0) { 241 mtd_scan_partitions(); 242 const MtdPartition* mtd = mtd_find_partition_by_name(location); 243 if (mtd == NULL) { 244 printf("%s: no mtd partition named \"%s\"", 245 name, location); 246 result = strdup(""); 247 goto done; 248 } 249 MtdWriteContext* ctx = mtd_write_partition(mtd); 250 if (ctx == NULL) { 251 printf("%s: can't write \"%s\"", name, location); 252 result = strdup(""); 253 goto done; 254 } 255 if (mtd_erase_blocks(ctx, -1) == -1) { 256 mtd_write_close(ctx); 257 printf("%s: failed to erase \"%s\"", name, location); 258 result = strdup(""); 259 goto done; 260 } 261 if (mtd_write_close(ctx) != 0) { 262 printf("%s: failed to close \"%s\"", name, location); 263 result = strdup(""); 264 goto done; 265 } 266 result = location; 267 #ifdef USE_EXT4 268 } else if (strcmp(fs_type, "ext4") == 0) { 269 int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle); 270 if (status != 0) { 271 printf("%s: make_ext4fs failed (%d) on %s", 272 name, status, location); 273 result = strdup(""); 274 goto done; 275 } 276 result = location; 277 #endif 278 } else { 279 printf("%s: unsupported fs_type \"%s\" partition_type \"%s\"", 280 name, fs_type, partition_type); 281 } 282 283 done: 284 free(fs_type); 285 free(partition_type); 286 if (result != location) free(location); 287 return StringValue(result); 288 } 289 290 Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { 291 char* result = NULL; 292 if (argc != 2) { 293 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); 294 } 295 296 char* src_name; 297 char* dst_name; 298 299 if (ReadArgs(state, argv, 2, &src_name, &dst_name) < 0) { 300 return NULL; 301 } 302 if (strlen(src_name) == 0) { 303 ErrorAbort(state, "src_name argument to %s() can't be empty", name); 304 goto done; 305 } 306 if (strlen(dst_name) == 0) { 307 ErrorAbort(state, "dst_name argument to %s() can't be empty", 308 name); 309 goto done; 310 } 311 312 if (rename(src_name, dst_name) != 0) { 313 ErrorAbort(state, "Rename of %s() to %s() failed, error %s()", 314 src_name, dst_name, strerror(errno)); 315 } else { 316 result = dst_name; 317 } 318 319 done: 320 free(src_name); 321 if (result != dst_name) free(dst_name); 322 return StringValue(result); 323 } 324 325 Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { 326 char** paths = malloc(argc * sizeof(char*)); 327 int i; 328 for (i = 0; i < argc; ++i) { 329 paths[i] = Evaluate(state, argv[i]); 330 if (paths[i] == NULL) { 331 int j; 332 for (j = 0; j < i; ++i) { 333 free(paths[j]); 334 } 335 free(paths); 336 return NULL; 337 } 338 } 339 340 bool recursive = (strcmp(name, "delete_recursive") == 0); 341 342 int success = 0; 343 for (i = 0; i < argc; ++i) { 344 if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0) 345 ++success; 346 free(paths[i]); 347 } 348 free(paths); 349 350 char buffer[10]; 351 sprintf(buffer, "%d", success); 352 return StringValue(strdup(buffer)); 353 } 354 355 356 Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) { 357 if (argc != 2) { 358 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); 359 } 360 char* frac_str; 361 char* sec_str; 362 if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) { 363 return NULL; 364 } 365 366 double frac = strtod(frac_str, NULL); 367 int sec = strtol(sec_str, NULL, 10); 368 369 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); 370 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec); 371 372 free(sec_str); 373 return StringValue(frac_str); 374 } 375 376 Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) { 377 if (argc != 1) { 378 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); 379 } 380 char* frac_str; 381 if (ReadArgs(state, argv, 1, &frac_str) < 0) { 382 return NULL; 383 } 384 385 double frac = strtod(frac_str, NULL); 386 387 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); 388 fprintf(ui->cmd_pipe, "set_progress %f\n", frac); 389 390 return StringValue(frac_str); 391 } 392 393 // package_extract_dir(package_path, destination_path) 394 Value* PackageExtractDirFn(const char* name, State* state, 395 int argc, Expr* argv[]) { 396 if (argc != 2) { 397 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); 398 } 399 char* zip_path; 400 char* dest_path; 401 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL; 402 403 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; 404 405 // To create a consistent system image, never use the clock for timestamps. 406 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default 407 408 bool success = mzExtractRecursive(za, zip_path, dest_path, 409 MZ_EXTRACT_FILES_ONLY, ×tamp, 410 NULL, NULL, sehandle); 411 free(zip_path); 412 free(dest_path); 413 return StringValue(strdup(success ? "t" : "")); 414 } 415 416 417 // package_extract_file(package_path, destination_path) 418 // or 419 // package_extract_file(package_path) 420 // to return the entire contents of the file as the result of this 421 // function (the char* returned is actually a FileContents*). 422 Value* PackageExtractFileFn(const char* name, State* state, 423 int argc, Expr* argv[]) { 424 if (argc != 1 && argc != 2) { 425 return ErrorAbort(state, "%s() expects 1 or 2 args, got %d", 426 name, argc); 427 } 428 bool success = false; 429 if (argc == 2) { 430 // The two-argument version extracts to a file. 431 432 char* zip_path; 433 char* dest_path; 434 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL; 435 436 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; 437 const ZipEntry* entry = mzFindZipEntry(za, zip_path); 438 if (entry == NULL) { 439 printf("%s: no %s in package\n", name, zip_path); 440 goto done2; 441 } 442 443 FILE* f = fopen(dest_path, "wb"); 444 if (f == NULL) { 445 printf("%s: can't open %s for write: %s\n", 446 name, dest_path, strerror(errno)); 447 goto done2; 448 } 449 success = mzExtractZipEntryToFile(za, entry, fileno(f)); 450 fclose(f); 451 452 done2: 453 free(zip_path); 454 free(dest_path); 455 return StringValue(strdup(success ? "t" : "")); 456 } else { 457 // The one-argument version returns the contents of the file 458 // as the result. 459 460 char* zip_path; 461 Value* v = malloc(sizeof(Value)); 462 v->type = VAL_BLOB; 463 v->size = -1; 464 v->data = NULL; 465 466 if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL; 467 468 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; 469 const ZipEntry* entry = mzFindZipEntry(za, zip_path); 470 if (entry == NULL) { 471 printf("%s: no %s in package\n", name, zip_path); 472 goto done1; 473 } 474 475 v->size = mzGetZipEntryUncompLen(entry); 476 v->data = malloc(v->size); 477 if (v->data == NULL) { 478 printf("%s: failed to allocate %ld bytes for %s\n", 479 name, (long)v->size, zip_path); 480 goto done1; 481 } 482 483 success = mzExtractZipEntryToBuffer(za, entry, 484 (unsigned char *)v->data); 485 486 done1: 487 free(zip_path); 488 if (!success) { 489 free(v->data); 490 v->data = NULL; 491 v->size = -1; 492 } 493 return v; 494 } 495 } 496 497 // Create all parent directories of name, if necessary. 498 static int make_parents(char* name) { 499 char* p; 500 for (p = name + (strlen(name)-1); p > name; --p) { 501 if (*p != '/') continue; 502 *p = '\0'; 503 if (make_parents(name) < 0) return -1; 504 int result = mkdir(name, 0700); 505 if (result == 0) printf("symlink(): created [%s]\n", name); 506 *p = '/'; 507 if (result == 0 || errno == EEXIST) { 508 // successfully created or already existed; we're done 509 return 0; 510 } else { 511 printf("failed to mkdir %s: %s\n", name, strerror(errno)); 512 return -1; 513 } 514 } 515 return 0; 516 } 517 518 // symlink target src1 src2 ... 519 // unlinks any previously existing src1, src2, etc before creating symlinks. 520 Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { 521 if (argc == 0) { 522 return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc); 523 } 524 char* target; 525 target = Evaluate(state, argv[0]); 526 if (target == NULL) return NULL; 527 528 char** srcs = ReadVarArgs(state, argc-1, argv+1); 529 if (srcs == NULL) { 530 free(target); 531 return NULL; 532 } 533 534 int bad = 0; 535 int i; 536 for (i = 0; i < argc-1; ++i) { 537 if (unlink(srcs[i]) < 0) { 538 if (errno != ENOENT) { 539 printf("%s: failed to remove %s: %s\n", 540 name, srcs[i], strerror(errno)); 541 ++bad; 542 } 543 } 544 if (make_parents(srcs[i])) { 545 printf("%s: failed to symlink %s to %s: making parents failed\n", 546 name, srcs[i], target); 547 ++bad; 548 } 549 if (symlink(target, srcs[i]) < 0) { 550 printf("%s: failed to symlink %s to %s: %s\n", 551 name, srcs[i], target, strerror(errno)); 552 ++bad; 553 } 554 free(srcs[i]); 555 } 556 free(srcs); 557 if (bad) { 558 return ErrorAbort(state, "%s: some symlinks failed", name); 559 } 560 return StringValue(strdup("")); 561 } 562 563 564 Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { 565 char* result = NULL; 566 bool recursive = (strcmp(name, "set_perm_recursive") == 0); 567 568 int min_args = 4 + (recursive ? 1 : 0); 569 if (argc < min_args) { 570 return ErrorAbort(state, "%s() expects %d+ args, got %d", 571 name, min_args, argc); 572 } 573 574 char** args = ReadVarArgs(state, argc, argv); 575 if (args == NULL) return NULL; 576 577 char* end; 578 int i; 579 int bad = 0; 580 581 int uid = strtoul(args[0], &end, 0); 582 if (*end != '\0' || args[0][0] == 0) { 583 ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]); 584 goto done; 585 } 586 587 int gid = strtoul(args[1], &end, 0); 588 if (*end != '\0' || args[1][0] == 0) { 589 ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]); 590 goto done; 591 } 592 593 if (recursive) { 594 int dir_mode = strtoul(args[2], &end, 0); 595 if (*end != '\0' || args[2][0] == 0) { 596 ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]); 597 goto done; 598 } 599 600 int file_mode = strtoul(args[3], &end, 0); 601 if (*end != '\0' || args[3][0] == 0) { 602 ErrorAbort(state, "%s: \"%s\" not a valid filemode", 603 name, args[3]); 604 goto done; 605 } 606 607 for (i = 4; i < argc; ++i) { 608 dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode); 609 } 610 } else { 611 int mode = strtoul(args[2], &end, 0); 612 if (*end != '\0' || args[2][0] == 0) { 613 ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]); 614 goto done; 615 } 616 617 for (i = 3; i < argc; ++i) { 618 if (chown(args[i], uid, gid) < 0) { 619 printf("%s: chown of %s to %d %d failed: %s\n", 620 name, args[i], uid, gid, strerror(errno)); 621 ++bad; 622 } 623 if (chmod(args[i], mode) < 0) { 624 printf("%s: chmod of %s to %o failed: %s\n", 625 name, args[i], mode, strerror(errno)); 626 ++bad; 627 } 628 } 629 } 630 result = strdup(""); 631 632 done: 633 for (i = 0; i < argc; ++i) { 634 free(args[i]); 635 } 636 free(args); 637 638 if (bad) { 639 free(result); 640 return ErrorAbort(state, "%s: some changes failed", name); 641 } 642 return StringValue(result); 643 } 644 645 struct perm_parsed_args { 646 bool has_uid; 647 uid_t uid; 648 bool has_gid; 649 gid_t gid; 650 bool has_mode; 651 mode_t mode; 652 bool has_fmode; 653 mode_t fmode; 654 bool has_dmode; 655 mode_t dmode; 656 bool has_selabel; 657 char* selabel; 658 bool has_capabilities; 659 uint64_t capabilities; 660 }; 661 662 static struct perm_parsed_args ParsePermArgs(int argc, char** args) { 663 int i; 664 struct perm_parsed_args parsed; 665 int bad = 0; 666 static int max_warnings = 20; 667 668 memset(&parsed, 0, sizeof(parsed)); 669 670 for (i = 1; i < argc; i += 2) { 671 if (strcmp("uid", args[i]) == 0) { 672 int64_t uid; 673 if (sscanf(args[i+1], "%" SCNd64, &uid) == 1) { 674 parsed.uid = uid; 675 parsed.has_uid = true; 676 } else { 677 printf("ParsePermArgs: invalid UID \"%s\"\n", args[i + 1]); 678 bad++; 679 } 680 continue; 681 } 682 if (strcmp("gid", args[i]) == 0) { 683 int64_t gid; 684 if (sscanf(args[i+1], "%" SCNd64, &gid) == 1) { 685 parsed.gid = gid; 686 parsed.has_gid = true; 687 } else { 688 printf("ParsePermArgs: invalid GID \"%s\"\n", args[i + 1]); 689 bad++; 690 } 691 continue; 692 } 693 if (strcmp("mode", args[i]) == 0) { 694 int32_t mode; 695 if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { 696 parsed.mode = mode; 697 parsed.has_mode = true; 698 } else { 699 printf("ParsePermArgs: invalid mode \"%s\"\n", args[i + 1]); 700 bad++; 701 } 702 continue; 703 } 704 if (strcmp("dmode", args[i]) == 0) { 705 int32_t mode; 706 if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { 707 parsed.dmode = mode; 708 parsed.has_dmode = true; 709 } else { 710 printf("ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1]); 711 bad++; 712 } 713 continue; 714 } 715 if (strcmp("fmode", args[i]) == 0) { 716 int32_t mode; 717 if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { 718 parsed.fmode = mode; 719 parsed.has_fmode = true; 720 } else { 721 printf("ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1]); 722 bad++; 723 } 724 continue; 725 } 726 if (strcmp("capabilities", args[i]) == 0) { 727 int64_t capabilities; 728 if (sscanf(args[i+1], "%" SCNi64, &capabilities) == 1) { 729 parsed.capabilities = capabilities; 730 parsed.has_capabilities = true; 731 } else { 732 printf("ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1]); 733 bad++; 734 } 735 continue; 736 } 737 if (strcmp("selabel", args[i]) == 0) { 738 if (args[i+1][0] != '\0') { 739 parsed.selabel = args[i+1]; 740 parsed.has_selabel = true; 741 } else { 742 printf("ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1]); 743 bad++; 744 } 745 continue; 746 } 747 if (max_warnings != 0) { 748 printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i]); 749 max_warnings--; 750 if (max_warnings == 0) { 751 printf("ParsedPermArgs: suppressing further warnings\n"); 752 } 753 } 754 } 755 return parsed; 756 } 757 758 static int ApplyParsedPerms( 759 const char* filename, 760 const struct stat *statptr, 761 struct perm_parsed_args parsed) 762 { 763 int bad = 0; 764 765 /* ignore symlinks */ 766 if (S_ISLNK(statptr->st_mode)) { 767 return 0; 768 } 769 770 if (parsed.has_uid) { 771 if (chown(filename, parsed.uid, -1) < 0) { 772 printf("ApplyParsedPerms: chown of %s to %d failed: %s\n", 773 filename, parsed.uid, strerror(errno)); 774 bad++; 775 } 776 } 777 778 if (parsed.has_gid) { 779 if (chown(filename, -1, parsed.gid) < 0) { 780 printf("ApplyParsedPerms: chgrp of %s to %d failed: %s\n", 781 filename, parsed.gid, strerror(errno)); 782 bad++; 783 } 784 } 785 786 if (parsed.has_mode) { 787 if (chmod(filename, parsed.mode) < 0) { 788 printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", 789 filename, parsed.mode, strerror(errno)); 790 bad++; 791 } 792 } 793 794 if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) { 795 if (chmod(filename, parsed.dmode) < 0) { 796 printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", 797 filename, parsed.dmode, strerror(errno)); 798 bad++; 799 } 800 } 801 802 if (parsed.has_fmode && S_ISREG(statptr->st_mode)) { 803 if (chmod(filename, parsed.fmode) < 0) { 804 printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", 805 filename, parsed.fmode, strerror(errno)); 806 bad++; 807 } 808 } 809 810 if (parsed.has_selabel) { 811 // TODO: Don't silently ignore ENOTSUP 812 if (lsetfilecon(filename, parsed.selabel) && (errno != ENOTSUP)) { 813 printf("ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n", 814 filename, parsed.selabel, strerror(errno)); 815 bad++; 816 } 817 } 818 819 if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) { 820 if (parsed.capabilities == 0) { 821 if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) { 822 // Report failure unless it's ENODATA (attribute not set) 823 printf("ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n", 824 filename, parsed.capabilities, strerror(errno)); 825 bad++; 826 } 827 } else { 828 struct vfs_cap_data cap_data; 829 memset(&cap_data, 0, sizeof(cap_data)); 830 cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE; 831 cap_data.data[0].permitted = (uint32_t) (parsed.capabilities & 0xffffffff); 832 cap_data.data[0].inheritable = 0; 833 cap_data.data[1].permitted = (uint32_t) (parsed.capabilities >> 32); 834 cap_data.data[1].inheritable = 0; 835 if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) { 836 printf("ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n", 837 filename, parsed.capabilities, strerror(errno)); 838 bad++; 839 } 840 } 841 } 842 843 return bad; 844 } 845 846 // nftw doesn't allow us to pass along context, so we need to use 847 // global variables. *sigh* 848 static struct perm_parsed_args recursive_parsed_args; 849 850 static int do_SetMetadataRecursive(const char* filename, const struct stat *statptr, 851 int fileflags, struct FTW *pfwt) { 852 return ApplyParsedPerms(filename, statptr, recursive_parsed_args); 853 } 854 855 static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) { 856 int i; 857 int bad = 0; 858 static int nwarnings = 0; 859 struct stat sb; 860 Value* result = NULL; 861 862 bool recursive = (strcmp(name, "set_metadata_recursive") == 0); 863 864 if ((argc % 2) != 1) { 865 return ErrorAbort(state, "%s() expects an odd number of arguments, got %d", 866 name, argc); 867 } 868 869 char** args = ReadVarArgs(state, argc, argv); 870 if (args == NULL) return NULL; 871 872 if (lstat(args[0], &sb) == -1) { 873 result = ErrorAbort(state, "%s: Error on lstat of \"%s\": %s", name, args[0], strerror(errno)); 874 goto done; 875 } 876 877 struct perm_parsed_args parsed = ParsePermArgs(argc, args); 878 879 if (recursive) { 880 recursive_parsed_args = parsed; 881 bad += nftw(args[0], do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS); 882 memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args)); 883 } else { 884 bad += ApplyParsedPerms(args[0], &sb, parsed); 885 } 886 887 done: 888 for (i = 0; i < argc; ++i) { 889 free(args[i]); 890 } 891 free(args); 892 893 if (result != NULL) { 894 return result; 895 } 896 897 if (bad > 0) { 898 return ErrorAbort(state, "%s: some changes failed", name); 899 } 900 901 return StringValue(strdup("")); 902 } 903 904 Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { 905 if (argc != 1) { 906 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); 907 } 908 char* key; 909 key = Evaluate(state, argv[0]); 910 if (key == NULL) return NULL; 911 912 char value[PROPERTY_VALUE_MAX]; 913 property_get(key, value, ""); 914 free(key); 915 916 return StringValue(strdup(value)); 917 } 918 919 920 // file_getprop(file, key) 921 // 922 // interprets 'file' as a getprop-style file (key=value pairs, one 923 // per line, # comment lines and blank lines okay), and returns the value 924 // for 'key' (or "" if it isn't defined). 925 Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { 926 char* result = NULL; 927 char* buffer = NULL; 928 char* filename; 929 char* key; 930 if (ReadArgs(state, argv, 2, &filename, &key) < 0) { 931 return NULL; 932 } 933 934 struct stat st; 935 if (stat(filename, &st) < 0) { 936 ErrorAbort(state, "%s: failed to stat \"%s\": %s", 937 name, filename, strerror(errno)); 938 goto done; 939 } 940 941 #define MAX_FILE_GETPROP_SIZE 65536 942 943 if (st.st_size > MAX_FILE_GETPROP_SIZE) { 944 ErrorAbort(state, "%s too large for %s (max %d)", 945 filename, name, MAX_FILE_GETPROP_SIZE); 946 goto done; 947 } 948 949 buffer = malloc(st.st_size+1); 950 if (buffer == NULL) { 951 ErrorAbort(state, "%s: failed to alloc %lld bytes", name, st.st_size+1); 952 goto done; 953 } 954 955 FILE* f = fopen(filename, "rb"); 956 if (f == NULL) { 957 ErrorAbort(state, "%s: failed to open %s: %s", 958 name, filename, strerror(errno)); 959 goto done; 960 } 961 962 if (fread(buffer, 1, st.st_size, f) != st.st_size) { 963 ErrorAbort(state, "%s: failed to read %lld bytes from %s", 964 name, st.st_size+1, filename); 965 fclose(f); 966 goto done; 967 } 968 buffer[st.st_size] = '\0'; 969 970 fclose(f); 971 972 char* line = strtok(buffer, "\n"); 973 do { 974 // skip whitespace at start of line 975 while (*line && isspace(*line)) ++line; 976 977 // comment or blank line: skip to next line 978 if (*line == '\0' || *line == '#') continue; 979 980 char* equal = strchr(line, '='); 981 if (equal == NULL) { 982 ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?", 983 name, line, filename); 984 goto done; 985 } 986 987 // trim whitespace between key and '=' 988 char* key_end = equal-1; 989 while (key_end > line && isspace(*key_end)) --key_end; 990 key_end[1] = '\0'; 991 992 // not the key we're looking for 993 if (strcmp(key, line) != 0) continue; 994 995 // skip whitespace after the '=' to the start of the value 996 char* val_start = equal+1; 997 while(*val_start && isspace(*val_start)) ++val_start; 998 999 // trim trailing whitespace 1000 char* val_end = val_start + strlen(val_start)-1; 1001 while (val_end > val_start && isspace(*val_end)) --val_end; 1002 val_end[1] = '\0'; 1003 1004 result = strdup(val_start); 1005 break; 1006 1007 } while ((line = strtok(NULL, "\n"))); 1008 1009 if (result == NULL) result = strdup(""); 1010 1011 done: 1012 free(filename); 1013 free(key); 1014 free(buffer); 1015 return StringValue(result); 1016 } 1017 1018 1019 static bool write_raw_image_cb(const unsigned char* data, 1020 int data_len, void* ctx) { 1021 int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len); 1022 if (r == data_len) return true; 1023 printf("%s\n", strerror(errno)); 1024 return false; 1025 } 1026 1027 // write_raw_image(filename_or_blob, partition) 1028 Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { 1029 char* result = NULL; 1030 1031 Value* partition_value; 1032 Value* contents; 1033 if (ReadValueArgs(state, argv, 2, &contents, &partition_value) < 0) { 1034 return NULL; 1035 } 1036 1037 char* partition = NULL; 1038 if (partition_value->type != VAL_STRING) { 1039 ErrorAbort(state, "partition argument to %s must be string", name); 1040 goto done; 1041 } 1042 partition = partition_value->data; 1043 if (strlen(partition) == 0) { 1044 ErrorAbort(state, "partition argument to %s can't be empty", name); 1045 goto done; 1046 } 1047 if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) { 1048 ErrorAbort(state, "file argument to %s can't be empty", name); 1049 goto done; 1050 } 1051 1052 mtd_scan_partitions(); 1053 const MtdPartition* mtd = mtd_find_partition_by_name(partition); 1054 if (mtd == NULL) { 1055 printf("%s: no mtd partition named \"%s\"\n", name, partition); 1056 result = strdup(""); 1057 goto done; 1058 } 1059 1060 MtdWriteContext* ctx = mtd_write_partition(mtd); 1061 if (ctx == NULL) { 1062 printf("%s: can't write mtd partition \"%s\"\n", 1063 name, partition); 1064 result = strdup(""); 1065 goto done; 1066 } 1067 1068 bool success; 1069 1070 if (contents->type == VAL_STRING) { 1071 // we're given a filename as the contents 1072 char* filename = contents->data; 1073 FILE* f = fopen(filename, "rb"); 1074 if (f == NULL) { 1075 printf("%s: can't open %s: %s\n", 1076 name, filename, strerror(errno)); 1077 result = strdup(""); 1078 goto done; 1079 } 1080 1081 success = true; 1082 char* buffer = malloc(BUFSIZ); 1083 int read; 1084 while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) { 1085 int wrote = mtd_write_data(ctx, buffer, read); 1086 success = success && (wrote == read); 1087 } 1088 free(buffer); 1089 fclose(f); 1090 } else { 1091 // we're given a blob as the contents 1092 ssize_t wrote = mtd_write_data(ctx, contents->data, contents->size); 1093 success = (wrote == contents->size); 1094 } 1095 if (!success) { 1096 printf("mtd_write_data to %s failed: %s\n", 1097 partition, strerror(errno)); 1098 } 1099 1100 if (mtd_erase_blocks(ctx, -1) == -1) { 1101 printf("%s: error erasing blocks of %s\n", name, partition); 1102 } 1103 if (mtd_write_close(ctx) != 0) { 1104 printf("%s: error closing write of %s\n", name, partition); 1105 } 1106 1107 printf("%s %s partition\n", 1108 success ? "wrote" : "failed to write", partition); 1109 1110 result = success ? partition : strdup(""); 1111 1112 done: 1113 if (result != partition) FreeValue(partition_value); 1114 FreeValue(contents); 1115 return StringValue(result); 1116 } 1117 1118 // apply_patch_space(bytes) 1119 Value* ApplyPatchSpaceFn(const char* name, State* state, 1120 int argc, Expr* argv[]) { 1121 char* bytes_str; 1122 if (ReadArgs(state, argv, 1, &bytes_str) < 0) { 1123 return NULL; 1124 } 1125 1126 char* endptr; 1127 size_t bytes = strtol(bytes_str, &endptr, 10); 1128 if (bytes == 0 && endptr == bytes_str) { 1129 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n", 1130 name, bytes_str); 1131 free(bytes_str); 1132 return NULL; 1133 } 1134 1135 return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t")); 1136 } 1137 1138 1139 // apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...) 1140 Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { 1141 if (argc < 6 || (argc % 2) == 1) { 1142 return ErrorAbort(state, "%s(): expected at least 6 args and an " 1143 "even number, got %d", 1144 name, argc); 1145 } 1146 1147 char* source_filename; 1148 char* target_filename; 1149 char* target_sha1; 1150 char* target_size_str; 1151 if (ReadArgs(state, argv, 4, &source_filename, &target_filename, 1152 &target_sha1, &target_size_str) < 0) { 1153 return NULL; 1154 } 1155 1156 char* endptr; 1157 size_t target_size = strtol(target_size_str, &endptr, 10); 1158 if (target_size == 0 && endptr == target_size_str) { 1159 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count", 1160 name, target_size_str); 1161 free(source_filename); 1162 free(target_filename); 1163 free(target_sha1); 1164 free(target_size_str); 1165 return NULL; 1166 } 1167 1168 int patchcount = (argc-4) / 2; 1169 Value** patches = ReadValueVarArgs(state, argc-4, argv+4); 1170 1171 int i; 1172 for (i = 0; i < patchcount; ++i) { 1173 if (patches[i*2]->type != VAL_STRING) { 1174 ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i); 1175 break; 1176 } 1177 if (patches[i*2+1]->type != VAL_BLOB) { 1178 ErrorAbort(state, "%s(): patch #%d is not blob", name, i); 1179 break; 1180 } 1181 } 1182 if (i != patchcount) { 1183 for (i = 0; i < patchcount*2; ++i) { 1184 FreeValue(patches[i]); 1185 } 1186 free(patches); 1187 return NULL; 1188 } 1189 1190 char** patch_sha_str = malloc(patchcount * sizeof(char*)); 1191 for (i = 0; i < patchcount; ++i) { 1192 patch_sha_str[i] = patches[i*2]->data; 1193 patches[i*2]->data = NULL; 1194 FreeValue(patches[i*2]); 1195 patches[i] = patches[i*2+1]; 1196 } 1197 1198 int result = applypatch(source_filename, target_filename, 1199 target_sha1, target_size, 1200 patchcount, patch_sha_str, patches, NULL); 1201 1202 for (i = 0; i < patchcount; ++i) { 1203 FreeValue(patches[i]); 1204 } 1205 free(patch_sha_str); 1206 free(patches); 1207 1208 return StringValue(strdup(result == 0 ? "t" : "")); 1209 } 1210 1211 // apply_patch_check(file, [sha1_1, ...]) 1212 Value* ApplyPatchCheckFn(const char* name, State* state, 1213 int argc, Expr* argv[]) { 1214 if (argc < 1) { 1215 return ErrorAbort(state, "%s(): expected at least 1 arg, got %d", 1216 name, argc); 1217 } 1218 1219 char* filename; 1220 if (ReadArgs(state, argv, 1, &filename) < 0) { 1221 return NULL; 1222 } 1223 1224 int patchcount = argc-1; 1225 char** sha1s = ReadVarArgs(state, argc-1, argv+1); 1226 1227 int result = applypatch_check(filename, patchcount, sha1s); 1228 1229 int i; 1230 for (i = 0; i < patchcount; ++i) { 1231 free(sha1s[i]); 1232 } 1233 free(sha1s); 1234 1235 return StringValue(strdup(result == 0 ? "t" : "")); 1236 } 1237 1238 Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { 1239 char** args = ReadVarArgs(state, argc, argv); 1240 if (args == NULL) { 1241 return NULL; 1242 } 1243 1244 int size = 0; 1245 int i; 1246 for (i = 0; i < argc; ++i) { 1247 size += strlen(args[i]); 1248 } 1249 char* buffer = malloc(size+1); 1250 size = 0; 1251 for (i = 0; i < argc; ++i) { 1252 strcpy(buffer+size, args[i]); 1253 size += strlen(args[i]); 1254 free(args[i]); 1255 } 1256 free(args); 1257 buffer[size] = '\0'; 1258 1259 char* line = strtok(buffer, "\n"); 1260 while (line) { 1261 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, 1262 "ui_print %s\n", line); 1263 line = strtok(NULL, "\n"); 1264 } 1265 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n"); 1266 1267 return StringValue(buffer); 1268 } 1269 1270 Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) { 1271 if (argc != 0) { 1272 return ErrorAbort(state, "%s() expects no args, got %d", name, argc); 1273 } 1274 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "wipe_cache\n"); 1275 return StringValue(strdup("t")); 1276 } 1277 1278 Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { 1279 if (argc < 1) { 1280 return ErrorAbort(state, "%s() expects at least 1 arg", name); 1281 } 1282 char** args = ReadVarArgs(state, argc, argv); 1283 if (args == NULL) { 1284 return NULL; 1285 } 1286 1287 char** args2 = malloc(sizeof(char*) * (argc+1)); 1288 memcpy(args2, args, sizeof(char*) * argc); 1289 args2[argc] = NULL; 1290 1291 printf("about to run program [%s] with %d args\n", args2[0], argc); 1292 1293 pid_t child = fork(); 1294 if (child == 0) { 1295 execv(args2[0], args2); 1296 printf("run_program: execv failed: %s\n", strerror(errno)); 1297 _exit(1); 1298 } 1299 int status; 1300 waitpid(child, &status, 0); 1301 if (WIFEXITED(status)) { 1302 if (WEXITSTATUS(status) != 0) { 1303 printf("run_program: child exited with status %d\n", 1304 WEXITSTATUS(status)); 1305 } 1306 } else if (WIFSIGNALED(status)) { 1307 printf("run_program: child terminated by signal %d\n", 1308 WTERMSIG(status)); 1309 } 1310 1311 int i; 1312 for (i = 0; i < argc; ++i) { 1313 free(args[i]); 1314 } 1315 free(args); 1316 free(args2); 1317 1318 char buffer[20]; 1319 sprintf(buffer, "%d", status); 1320 1321 return StringValue(strdup(buffer)); 1322 } 1323 1324 // Take a sha-1 digest and return it as a newly-allocated hex string. 1325 static char* PrintSha1(uint8_t* digest) { 1326 char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1); 1327 int i; 1328 const char* alphabet = "0123456789abcdef"; 1329 for (i = 0; i < SHA_DIGEST_SIZE; ++i) { 1330 buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf]; 1331 buffer[i*2+1] = alphabet[digest[i] & 0xf]; 1332 } 1333 buffer[i*2] = '\0'; 1334 return buffer; 1335 } 1336 1337 // sha1_check(data) 1338 // to return the sha1 of the data (given in the format returned by 1339 // read_file). 1340 // 1341 // sha1_check(data, sha1_hex, [sha1_hex, ...]) 1342 // returns the sha1 of the file if it matches any of the hex 1343 // strings passed, or "" if it does not equal any of them. 1344 // 1345 Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { 1346 if (argc < 1) { 1347 return ErrorAbort(state, "%s() expects at least 1 arg", name); 1348 } 1349 1350 Value** args = ReadValueVarArgs(state, argc, argv); 1351 if (args == NULL) { 1352 return NULL; 1353 } 1354 1355 if (args[0]->size < 0) { 1356 return StringValue(strdup("")); 1357 } 1358 uint8_t digest[SHA_DIGEST_SIZE]; 1359 SHA_hash(args[0]->data, args[0]->size, digest); 1360 FreeValue(args[0]); 1361 1362 if (argc == 1) { 1363 return StringValue(PrintSha1(digest)); 1364 } 1365 1366 int i; 1367 uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE); 1368 for (i = 1; i < argc; ++i) { 1369 if (args[i]->type != VAL_STRING) { 1370 printf("%s(): arg %d is not a string; skipping", 1371 name, i); 1372 } else if (ParseSha1(args[i]->data, arg_digest) != 0) { 1373 // Warn about bad args and skip them. 1374 printf("%s(): error parsing \"%s\" as sha-1; skipping", 1375 name, args[i]->data); 1376 } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) { 1377 break; 1378 } 1379 FreeValue(args[i]); 1380 } 1381 if (i >= argc) { 1382 // Didn't match any of the hex strings; return false. 1383 return StringValue(strdup("")); 1384 } 1385 // Found a match; free all the remaining arguments and return the 1386 // matched one. 1387 int j; 1388 for (j = i+1; j < argc; ++j) { 1389 FreeValue(args[j]); 1390 } 1391 return args[i]; 1392 } 1393 1394 // Read a local file and return its contents (the Value* returned 1395 // is actually a FileContents*). 1396 Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) { 1397 if (argc != 1) { 1398 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); 1399 } 1400 char* filename; 1401 if (ReadArgs(state, argv, 1, &filename) < 0) return NULL; 1402 1403 Value* v = malloc(sizeof(Value)); 1404 v->type = VAL_BLOB; 1405 1406 FileContents fc; 1407 if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) { 1408 free(filename); 1409 v->size = -1; 1410 v->data = NULL; 1411 free(fc.data); 1412 return v; 1413 } 1414 1415 v->size = fc.size; 1416 v->data = (char*)fc.data; 1417 1418 free(filename); 1419 return v; 1420 } 1421 1422 // Immediately reboot the device. Recovery is not finished normally, 1423 // so if you reboot into recovery it will re-start applying the 1424 // current package (because nothing has cleared the copy of the 1425 // arguments stored in the BCB). 1426 // 1427 // The argument is the partition name passed to the android reboot 1428 // property. It can be "recovery" to boot from the recovery 1429 // partition, or "" (empty string) to boot from the regular boot 1430 // partition. 1431 Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) { 1432 if (argc != 2) { 1433 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); 1434 } 1435 1436 char* filename; 1437 char* property; 1438 if (ReadArgs(state, argv, 2, &filename, &property) < 0) return NULL; 1439 1440 char buffer[80]; 1441 1442 // zero out the 'command' field of the bootloader message. 1443 memset(buffer, 0, sizeof(((struct bootloader_message*)0)->command)); 1444 FILE* f = fopen(filename, "r+b"); 1445 fseek(f, offsetof(struct bootloader_message, command), SEEK_SET); 1446 fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f); 1447 fclose(f); 1448 free(filename); 1449 1450 strcpy(buffer, "reboot,"); 1451 if (property != NULL) { 1452 strncat(buffer, property, sizeof(buffer)-10); 1453 } 1454 1455 property_set(ANDROID_RB_PROPERTY, buffer); 1456 1457 sleep(5); 1458 free(property); 1459 ErrorAbort(state, "%s() failed to reboot", name); 1460 return NULL; 1461 } 1462 1463 // Store a string value somewhere that future invocations of recovery 1464 // can access it. This value is called the "stage" and can be used to 1465 // drive packages that need to do reboots in the middle of 1466 // installation and keep track of where they are in the multi-stage 1467 // install. 1468 // 1469 // The first argument is the block device for the misc partition 1470 // ("/misc" in the fstab), which is where this value is stored. The 1471 // second argument is the string to store; it should not exceed 31 1472 // bytes. 1473 Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) { 1474 if (argc != 2) { 1475 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); 1476 } 1477 1478 char* filename; 1479 char* stagestr; 1480 if (ReadArgs(state, argv, 2, &filename, &stagestr) < 0) return NULL; 1481 1482 // Store this value in the misc partition, immediately after the 1483 // bootloader message that the main recovery uses to save its 1484 // arguments in case of the device restarting midway through 1485 // package installation. 1486 FILE* f = fopen(filename, "r+b"); 1487 fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET); 1488 int to_write = strlen(stagestr)+1; 1489 int max_size = sizeof(((struct bootloader_message*)0)->stage); 1490 if (to_write > max_size) { 1491 to_write = max_size; 1492 stagestr[max_size-1] = 0; 1493 } 1494 fwrite(stagestr, to_write, 1, f); 1495 fclose(f); 1496 1497 free(stagestr); 1498 return StringValue(filename); 1499 } 1500 1501 // Return the value most recently saved with SetStageFn. The argument 1502 // is the block device for the misc partition. 1503 Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) { 1504 if (argc != 2) { 1505 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); 1506 } 1507 1508 char* filename; 1509 if (ReadArgs(state, argv, 1, &filename) < 0) return NULL; 1510 1511 char buffer[sizeof(((struct bootloader_message*)0)->stage)]; 1512 FILE* f = fopen(filename, "rb"); 1513 fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET); 1514 fread(buffer, sizeof(buffer), 1, f); 1515 fclose(f); 1516 buffer[sizeof(buffer)-1] = '\0'; 1517 1518 return StringValue(strdup(buffer)); 1519 } 1520 1521 void RegisterInstallFunctions() { 1522 RegisterFunction("mount", MountFn); 1523 RegisterFunction("is_mounted", IsMountedFn); 1524 RegisterFunction("unmount", UnmountFn); 1525 RegisterFunction("format", FormatFn); 1526 RegisterFunction("show_progress", ShowProgressFn); 1527 RegisterFunction("set_progress", SetProgressFn); 1528 RegisterFunction("delete", DeleteFn); 1529 RegisterFunction("delete_recursive", DeleteFn); 1530 RegisterFunction("package_extract_dir", PackageExtractDirFn); 1531 RegisterFunction("package_extract_file", PackageExtractFileFn); 1532 RegisterFunction("symlink", SymlinkFn); 1533 1534 // Maybe, at some future point, we can delete these functions? They have been 1535 // replaced by perm_set and perm_set_recursive. 1536 RegisterFunction("set_perm", SetPermFn); 1537 RegisterFunction("set_perm_recursive", SetPermFn); 1538 1539 // Usage: 1540 // set_metadata("filename", "key1", "value1", "key2", "value2", ...) 1541 // Example: 1542 // set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); 1543 RegisterFunction("set_metadata", SetMetadataFn); 1544 1545 // Usage: 1546 // set_metadata_recursive("dirname", "key1", "value1", "key2", "value2", ...) 1547 // Example: 1548 // set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); 1549 RegisterFunction("set_metadata_recursive", SetMetadataFn); 1550 1551 RegisterFunction("getprop", GetPropFn); 1552 RegisterFunction("file_getprop", FileGetPropFn); 1553 RegisterFunction("write_raw_image", WriteRawImageFn); 1554 1555 RegisterFunction("apply_patch", ApplyPatchFn); 1556 RegisterFunction("apply_patch_check", ApplyPatchCheckFn); 1557 RegisterFunction("apply_patch_space", ApplyPatchSpaceFn); 1558 1559 RegisterFunction("read_file", ReadFileFn); 1560 RegisterFunction("sha1_check", Sha1CheckFn); 1561 RegisterFunction("rename", RenameFn); 1562 1563 RegisterFunction("wipe_cache", WipeCacheFn); 1564 1565 RegisterFunction("ui_print", UIPrintFn); 1566 1567 RegisterFunction("run_program", RunProgramFn); 1568 1569 RegisterFunction("reboot_now", RebootNowFn); 1570 RegisterFunction("get_stage", GetStageFn); 1571 RegisterFunction("set_stage", SetStageFn); 1572 } 1573