install.c revision a3f89eabb7ddcf44add8ce3b321ceab6d35289cb
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <ctype.h> 18#include <errno.h> 19#include <stdarg.h> 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23#include <sys/mount.h> 24#include <sys/stat.h> 25#include <sys/types.h> 26#include <sys/wait.h> 27#include <unistd.h> 28 29#include "cutils/misc.h" 30#include "cutils/properties.h" 31#include "edify/expr.h" 32#include "minzip/DirUtil.h" 33#include "mtdutils/mounts.h" 34#include "mtdutils/mtdutils.h" 35#include "updater.h" 36 37 38// mount(type, location, mount_point) 39// 40// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem 41// type="vfat" location="/dev/block/<whatever>" to mount a device 42char* MountFn(const char* name, State* state, int argc, Expr* argv[]) { 43 char* result = NULL; 44 if (argc != 3) { 45 return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc); 46 } 47 char* type; 48 char* location; 49 char* mount_point; 50 if (ReadArgs(state, argv, 3, &type, &location, &mount_point) < 0) { 51 return NULL; 52 } 53 54 if (strlen(type) == 0) { 55 ErrorAbort(state, "type argument to %s() can't be empty", name); 56 goto done; 57 } 58 if (strlen(location) == 0) { 59 ErrorAbort(state, "location argument to %s() can't be empty", name); 60 goto done; 61 } 62 if (strlen(mount_point) == 0) { 63 ErrorAbort(state, "mount_point argument to %s() can't be empty", name); 64 goto done; 65 } 66 67 mkdir(mount_point, 0755); 68 69 if (strcmp(type, "MTD") == 0) { 70 mtd_scan_partitions(); 71 const MtdPartition* mtd; 72 mtd = mtd_find_partition_by_name(location); 73 if (mtd == NULL) { 74 fprintf(stderr, "%s: no mtd partition named \"%s\"", 75 name, location); 76 result = strdup(""); 77 goto done; 78 } 79 if (mtd_mount_partition(mtd, mount_point, "yaffs2", 0 /* rw */) != 0) { 80 fprintf(stderr, "mtd mount of %s failed: %s\n", 81 location, strerror(errno)); 82 result = strdup(""); 83 goto done; 84 } 85 result = mount_point; 86 } else { 87 if (mount(location, mount_point, type, 88 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) { 89 result = strdup(""); 90 } else { 91 result = mount_point; 92 } 93 } 94 95done: 96 free(type); 97 free(location); 98 if (result != mount_point) free(mount_point); 99 return result; 100} 101 102 103// is_mounted(mount_point) 104char* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) { 105 char* result = NULL; 106 if (argc != 1) { 107 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); 108 } 109 char* mount_point; 110 if (ReadArgs(state, argv, 1, &mount_point) < 0) { 111 return NULL; 112 } 113 if (strlen(mount_point) == 0) { 114 ErrorAbort(state, "mount_point argument to unmount() can't be empty"); 115 goto done; 116 } 117 118 scan_mounted_volumes(); 119 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); 120 if (vol == NULL) { 121 result = strdup(""); 122 } else { 123 result = mount_point; 124 } 125 126done: 127 if (result != mount_point) free(mount_point); 128 return result; 129} 130 131 132char* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) { 133 char* result = NULL; 134 if (argc != 1) { 135 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); 136 } 137 char* mount_point; 138 if (ReadArgs(state, argv, 1, &mount_point) < 0) { 139 return NULL; 140 } 141 if (strlen(mount_point) == 0) { 142 ErrorAbort(state, "mount_point argument to unmount() can't be empty"); 143 goto done; 144 } 145 146 scan_mounted_volumes(); 147 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); 148 if (vol == NULL) { 149 fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point); 150 result = strdup(""); 151 } else { 152 unmount_mounted_volume(vol); 153 result = mount_point; 154 } 155 156done: 157 if (result != mount_point) free(mount_point); 158 return result; 159} 160 161 162// format(type, location) 163// 164// type="MTD" location=partition 165char* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { 166 char* result = NULL; 167 if (argc != 2) { 168 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); 169 } 170 char* type; 171 char* location; 172 if (ReadArgs(state, argv, 2, &type, &location) < 0) { 173 return NULL; 174 } 175 176 if (strlen(type) == 0) { 177 ErrorAbort(state, "type argument to %s() can't be empty", name); 178 goto done; 179 } 180 if (strlen(location) == 0) { 181 ErrorAbort(state, "location argument to %s() can't be empty", name); 182 goto done; 183 } 184 185 if (strcmp(type, "MTD") == 0) { 186 mtd_scan_partitions(); 187 const MtdPartition* mtd = mtd_find_partition_by_name(location); 188 if (mtd == NULL) { 189 fprintf(stderr, "%s: no mtd partition named \"%s\"", 190 name, location); 191 result = strdup(""); 192 goto done; 193 } 194 MtdWriteContext* ctx = mtd_write_partition(mtd); 195 if (ctx == NULL) { 196 fprintf(stderr, "%s: can't write \"%s\"", name, location); 197 result = strdup(""); 198 goto done; 199 } 200 if (mtd_erase_blocks(ctx, -1) == -1) { 201 mtd_write_close(ctx); 202 fprintf(stderr, "%s: failed to erase \"%s\"", name, location); 203 result = strdup(""); 204 goto done; 205 } 206 if (mtd_write_close(ctx) != 0) { 207 fprintf(stderr, "%s: failed to close \"%s\"", name, location); 208 result = strdup(""); 209 goto done; 210 } 211 result = location; 212 } else { 213 fprintf(stderr, "%s: unsupported type \"%s\"", name, type); 214 } 215 216done: 217 free(type); 218 if (result != location) free(location); 219 return result; 220} 221 222 223char* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { 224 char** paths = malloc(argc * sizeof(char*)); 225 int i; 226 for (i = 0; i < argc; ++i) { 227 paths[i] = Evaluate(state, argv[i]); 228 if (paths[i] == NULL) { 229 int j; 230 for (j = 0; j < i; ++i) { 231 free(paths[j]); 232 } 233 free(paths); 234 return NULL; 235 } 236 } 237 238 bool recursive = (strcmp(name, "delete_recursive") == 0); 239 240 int success = 0; 241 for (i = 0; i < argc; ++i) { 242 if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0) 243 ++success; 244 free(paths[i]); 245 } 246 free(paths); 247 248 char buffer[10]; 249 sprintf(buffer, "%d", success); 250 return strdup(buffer); 251} 252 253 254char* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) { 255 if (argc != 2) { 256 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); 257 } 258 char* frac_str; 259 char* sec_str; 260 if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) { 261 return NULL; 262 } 263 264 double frac = strtod(frac_str, NULL); 265 int sec = strtol(sec_str, NULL, 10); 266 267 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); 268 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec); 269 270 free(sec_str); 271 return frac_str; 272} 273 274char* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) { 275 if (argc != 1) { 276 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); 277 } 278 char* frac_str; 279 if (ReadArgs(state, argv, 1, &frac_str) < 0) { 280 return NULL; 281 } 282 283 double frac = strtod(frac_str, NULL); 284 285 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); 286 fprintf(ui->cmd_pipe, "set_progress %f\n", frac); 287 288 return frac_str; 289} 290 291// package_extract_dir(package_path, destination_path) 292char* PackageExtractDirFn(const char* name, State* state, 293 int argc, Expr* argv[]) { 294 if (argc != 2) { 295 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); 296 } 297 char* zip_path; 298 char* dest_path; 299 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL; 300 301 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; 302 303 // To create a consistent system image, never use the clock for timestamps. 304 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default 305 306 bool success = mzExtractRecursive(za, zip_path, dest_path, 307 MZ_EXTRACT_FILES_ONLY, ×tamp, 308 NULL, NULL); 309 free(zip_path); 310 free(dest_path); 311 return strdup(success ? "t" : ""); 312} 313 314 315// package_extract_file(package_path, destination_path) 316char* PackageExtractFileFn(const char* name, State* state, 317 int argc, Expr* argv[]) { 318 if (argc != 2) { 319 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); 320 } 321 char* zip_path; 322 char* dest_path; 323 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL; 324 325 bool success = false; 326 327 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; 328 const ZipEntry* entry = mzFindZipEntry(za, zip_path); 329 if (entry == NULL) { 330 fprintf(stderr, "%s: no %s in package\n", name, zip_path); 331 goto done; 332 } 333 334 FILE* f = fopen(dest_path, "wb"); 335 if (f == NULL) { 336 fprintf(stderr, "%s: can't open %s for write: %s\n", 337 name, dest_path, strerror(errno)); 338 goto done; 339 } 340 success = mzExtractZipEntryToFile(za, entry, fileno(f)); 341 fclose(f); 342 343 done: 344 free(zip_path); 345 free(dest_path); 346 return strdup(success ? "t" : ""); 347} 348 349 350// symlink target src1 src2 ... 351char* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { 352 if (argc == 0) { 353 return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc); 354 } 355 char* target; 356 target = Evaluate(state, argv[0]); 357 if (target == NULL) return NULL; 358 359 char** srcs = ReadVarArgs(state, argc-1, argv+1); 360 if (srcs == NULL) { 361 free(target); 362 return NULL; 363 } 364 365 int i; 366 for (i = 0; i < argc-1; ++i) { 367 symlink(target, srcs[i]); 368 free(srcs[i]); 369 } 370 free(srcs); 371 return strdup(""); 372} 373 374 375char* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { 376 char* result = NULL; 377 bool recursive = (strcmp(name, "set_perm_recursive") == 0); 378 379 int min_args = 4 + (recursive ? 1 : 0); 380 if (argc < min_args) { 381 return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc); 382 } 383 384 char** args = ReadVarArgs(state, argc, argv); 385 if (args == NULL) return NULL; 386 387 char* end; 388 int i; 389 390 int uid = strtoul(args[0], &end, 0); 391 if (*end != '\0' || args[0][0] == 0) { 392 ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]); 393 goto done; 394 } 395 396 int gid = strtoul(args[1], &end, 0); 397 if (*end != '\0' || args[1][0] == 0) { 398 ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]); 399 goto done; 400 } 401 402 if (recursive) { 403 int dir_mode = strtoul(args[2], &end, 0); 404 if (*end != '\0' || args[2][0] == 0) { 405 ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]); 406 goto done; 407 } 408 409 int file_mode = strtoul(args[3], &end, 0); 410 if (*end != '\0' || args[3][0] == 0) { 411 ErrorAbort(state, "%s: \"%s\" not a valid filemode", 412 name, args[3]); 413 goto done; 414 } 415 416 for (i = 4; i < argc; ++i) { 417 dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode); 418 } 419 } else { 420 int mode = strtoul(args[2], &end, 0); 421 if (*end != '\0' || args[2][0] == 0) { 422 ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]); 423 goto done; 424 } 425 426 for (i = 3; i < argc; ++i) { 427 chown(args[i], uid, gid); 428 chmod(args[i], mode); 429 } 430 } 431 result = strdup(""); 432 433done: 434 for (i = 0; i < argc; ++i) { 435 free(args[i]); 436 } 437 free(args); 438 439 return result; 440} 441 442 443char* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { 444 if (argc != 1) { 445 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); 446 } 447 char* key; 448 key = Evaluate(state, argv[0]); 449 if (key == NULL) return NULL; 450 451 char value[PROPERTY_VALUE_MAX]; 452 property_get(key, value, ""); 453 free(key); 454 455 return strdup(value); 456} 457 458 459// file_getprop(file, key) 460// 461// interprets 'file' as a getprop-style file (key=value pairs, one 462// per line, # comment lines and blank lines okay), and returns the value 463// for 'key' (or "" if it isn't defined). 464char* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { 465 char* result = NULL; 466 char* buffer = NULL; 467 char* filename; 468 char* key; 469 if (ReadArgs(state, argv, 2, &filename, &key) < 0) { 470 return NULL; 471 } 472 473 struct stat st; 474 if (stat(filename, &st) < 0) { 475 ErrorAbort(state, "%s: failed to stat \"%s\": %s", 476 name, filename, strerror(errno)); 477 goto done; 478 } 479 480#define MAX_FILE_GETPROP_SIZE 65536 481 482 if (st.st_size > MAX_FILE_GETPROP_SIZE) { 483 ErrorAbort(state, "%s too large for %s (max %d)", 484 filename, name, MAX_FILE_GETPROP_SIZE); 485 goto done; 486 } 487 488 buffer = malloc(st.st_size+1); 489 if (buffer == NULL) { 490 ErrorAbort(state, "%s: failed to alloc %d bytes", name, st.st_size+1); 491 goto done; 492 } 493 494 FILE* f = fopen(filename, "rb"); 495 if (f == NULL) { 496 ErrorAbort(state, "%s: failed to open %s: %s", 497 name, filename, strerror(errno)); 498 goto done; 499 } 500 501 if (fread(buffer, 1, st.st_size, f) != st.st_size) { 502 ErrorAbort(state, "%s: failed to read %d bytes from %s", 503 name, st.st_size+1, filename); 504 fclose(f); 505 goto done; 506 } 507 buffer[st.st_size] = '\0'; 508 509 fclose(f); 510 511 char* line = strtok(buffer, "\n"); 512 do { 513 // skip whitespace at start of line 514 while (*line && isspace(*line)) ++line; 515 516 // comment or blank line: skip to next line 517 if (*line == '\0' || *line == '#') continue; 518 519 char* equal = strchr(line, '='); 520 if (equal == NULL) { 521 ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?", 522 name, line, filename); 523 goto done; 524 } 525 526 // trim whitespace between key and '=' 527 char* key_end = equal-1; 528 while (key_end > line && isspace(*key_end)) --key_end; 529 key_end[1] = '\0'; 530 531 // not the key we're looking for 532 if (strcmp(key, line) != 0) continue; 533 534 // skip whitespace after the '=' to the start of the value 535 char* val_start = equal+1; 536 while(*val_start && isspace(*val_start)) ++val_start; 537 538 // trim trailing whitespace 539 char* val_end = val_start + strlen(val_start)-1; 540 while (val_end > val_start && isspace(*val_end)) --val_end; 541 val_end[1] = '\0'; 542 543 result = strdup(val_start); 544 break; 545 546 } while ((line = strtok(NULL, "\n"))); 547 548 if (result == NULL) result = strdup(""); 549 550 done: 551 free(filename); 552 free(key); 553 free(buffer); 554 return result; 555} 556 557 558static bool write_raw_image_cb(const unsigned char* data, 559 int data_len, void* ctx) { 560 int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len); 561 if (r == data_len) return true; 562 fprintf(stderr, "%s\n", strerror(errno)); 563 return false; 564} 565 566// write_raw_image(file, partition) 567char* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { 568 char* result = NULL; 569 570 char* partition; 571 char* filename; 572 if (ReadArgs(state, argv, 2, &filename, &partition) < 0) { 573 return NULL; 574 } 575 576 if (strlen(partition) == 0) { 577 ErrorAbort(state, "partition argument to %s can't be empty", name); 578 goto done; 579 } 580 if (strlen(filename) == 0) { 581 ErrorAbort(state, "file argument to %s can't be empty", name); 582 goto done; 583 } 584 585 mtd_scan_partitions(); 586 const MtdPartition* mtd = mtd_find_partition_by_name(partition); 587 if (mtd == NULL) { 588 fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition); 589 result = strdup(""); 590 goto done; 591 } 592 593 MtdWriteContext* ctx = mtd_write_partition(mtd); 594 if (ctx == NULL) { 595 fprintf(stderr, "%s: can't write mtd partition \"%s\"\n", 596 name, partition); 597 result = strdup(""); 598 goto done; 599 } 600 601 bool success; 602 603 FILE* f = fopen(filename, "rb"); 604 if (f == NULL) { 605 fprintf(stderr, "%s: can't open %s: %s\n", 606 name, filename, strerror(errno)); 607 result = strdup(""); 608 goto done; 609 } 610 611 success = true; 612 char* buffer = malloc(BUFSIZ); 613 int read; 614 while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) { 615 int wrote = mtd_write_data(ctx, buffer, read); 616 success = success && (wrote == read); 617 if (!success) { 618 fprintf(stderr, "mtd_write_data to %s failed: %s\n", 619 partition, strerror(errno)); 620 } 621 } 622 free(buffer); 623 fclose(f); 624 625 if (mtd_erase_blocks(ctx, -1) == -1) { 626 fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition); 627 } 628 if (mtd_write_close(ctx) != 0) { 629 fprintf(stderr, "%s: error closing write of %s\n", name, partition); 630 } 631 632 printf("%s %s partition from %s\n", 633 success ? "wrote" : "failed to write", partition, filename); 634 635 result = success ? partition : strdup(""); 636 637done: 638 if (result != partition) free(partition); 639 free(filename); 640 return result; 641} 642 643// write_firmware_image(file, partition) 644// 645// partition is "radio" or "hboot" 646// file is not used until after updater exits 647// 648// TODO: this should live in some HTC-specific library 649char* WriteFirmwareImageFn(const char* name, State* state, 650 int argc, Expr* argv[]) { 651 char* result = NULL; 652 653 char* partition; 654 char* filename; 655 if (ReadArgs(state, argv, 2, &filename, &partition) < 0) { 656 return NULL; 657 } 658 659 if (strlen(partition) == 0) { 660 ErrorAbort(state, "partition argument to %s can't be empty", name); 661 goto done; 662 } 663 if (strlen(filename) == 0) { 664 ErrorAbort(state, "file argument to %s can't be empty", name); 665 goto done; 666 } 667 668 FILE* cmd = ((UpdaterInfo*)(state->cookie))->cmd_pipe; 669 fprintf(cmd, "firmware %s %s\n", partition, filename); 670 671 printf("will write %s firmware from %s\n", partition, filename); 672 result = partition; 673 674done: 675 if (result != partition) free(partition); 676 free(filename); 677 return result; 678} 679 680 681extern int applypatch(int argc, char** argv); 682 683// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...) 684// apply_patch_check(file, sha1, ...) 685// apply_patch_space(bytes) 686char* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { 687 printf("in applypatchfn (%s)\n", name); 688 689 char* prepend = NULL; 690 if (strstr(name, "check") != NULL) { 691 prepend = "-c"; 692 } else if (strstr(name, "space") != NULL) { 693 prepend = "-s"; 694 } 695 696 char** args = ReadVarArgs(state, argc, argv); 697 if (args == NULL) return NULL; 698 699 // insert the "program name" argv[0] and a copy of the "prepend" 700 // string (if any) at the start of the args. 701 702 int extra = 1 + (prepend != NULL ? 1 : 0); 703 char** temp = malloc((argc+extra) * sizeof(char*)); 704 memcpy(temp+extra, args, argc * sizeof(char*)); 705 temp[0] = strdup("updater"); 706 if (prepend) { 707 temp[1] = strdup(prepend); 708 } 709 free(args); 710 args = temp; 711 argc += extra; 712 713 printf("calling applypatch\n"); 714 fflush(stdout); 715 int result = applypatch(argc, args); 716 printf("applypatch returned %d\n", result); 717 718 int i; 719 for (i = 0; i < argc; ++i) { 720 free(args[i]); 721 } 722 free(args); 723 724 switch (result) { 725 case 0: return strdup("t"); 726 case 1: return strdup(""); 727 default: return ErrorAbort(state, "applypatch couldn't parse args"); 728 } 729} 730 731char* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { 732 char** args = ReadVarArgs(state, argc, argv); 733 if (args == NULL) { 734 return NULL; 735 } 736 737 int size = 0; 738 int i; 739 for (i = 0; i < argc; ++i) { 740 size += strlen(args[i]); 741 } 742 char* buffer = malloc(size+1); 743 size = 0; 744 for (i = 0; i < argc; ++i) { 745 strcpy(buffer+size, args[i]); 746 size += strlen(args[i]); 747 free(args[i]); 748 } 749 free(args); 750 buffer[size] = '\0'; 751 752 char* line = strtok(buffer, "\n"); 753 while (line) { 754 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, 755 "ui_print %s\n", line); 756 line = strtok(NULL, "\n"); 757 } 758 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n"); 759 760 return buffer; 761} 762 763char* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { 764 if (argc < 1) { 765 return ErrorAbort(state, "%s() expects at least 1 arg", name); 766 } 767 char** args = ReadVarArgs(state, argc, argv); 768 if (args == NULL) { 769 return NULL; 770 } 771 772 char** args2 = malloc(sizeof(char*) * (argc+1)); 773 memcpy(args2, args, sizeof(char*) * argc); 774 args2[argc] = NULL; 775 776 fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc); 777 778 pid_t child = fork(); 779 if (child == 0) { 780 execv(args2[0], args2); 781 fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno)); 782 _exit(1); 783 } 784 int status; 785 waitpid(child, &status, 0); 786 if (WIFEXITED(status)) { 787 if (WEXITSTATUS(status) != 0) { 788 fprintf(stderr, "run_program: child exited with status %d\n", 789 WEXITSTATUS(status)); 790 } 791 } else if (WIFSIGNALED(status)) { 792 fprintf(stderr, "run_program: child terminated by signal %d\n", 793 WTERMSIG(status)); 794 } 795 796 int i; 797 for (i = 0; i < argc; ++i) { 798 free(args[i]); 799 } 800 free(args); 801 free(args2); 802 803 char buffer[20]; 804 sprintf(buffer, "%d", status); 805 806 return strdup(buffer); 807} 808 809 810void RegisterInstallFunctions() { 811 RegisterFunction("mount", MountFn); 812 RegisterFunction("is_mounted", IsMountedFn); 813 RegisterFunction("unmount", UnmountFn); 814 RegisterFunction("format", FormatFn); 815 RegisterFunction("show_progress", ShowProgressFn); 816 RegisterFunction("set_progress", SetProgressFn); 817 RegisterFunction("delete", DeleteFn); 818 RegisterFunction("delete_recursive", DeleteFn); 819 RegisterFunction("package_extract_dir", PackageExtractDirFn); 820 RegisterFunction("package_extract_file", PackageExtractFileFn); 821 RegisterFunction("symlink", SymlinkFn); 822 RegisterFunction("set_perm", SetPermFn); 823 RegisterFunction("set_perm_recursive", SetPermFn); 824 825 RegisterFunction("getprop", GetPropFn); 826 RegisterFunction("file_getprop", FileGetPropFn); 827 RegisterFunction("write_raw_image", WriteRawImageFn); 828 RegisterFunction("write_firmware_image", WriteFirmwareImageFn); 829 830 RegisterFunction("apply_patch", ApplyPatchFn); 831 RegisterFunction("apply_patch_check", ApplyPatchFn); 832 RegisterFunction("apply_patch_space", ApplyPatchFn); 833 834 RegisterFunction("ui_print", UIPrintFn); 835 836 RegisterFunction("run_program", RunProgramFn); 837} 838