static struct selabel_handle* get_sehnd(const char* context_file) {
  struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, context_file } };
  struct selabel_handle* sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);

  if (!sehnd) {
    perror("error running selabel_open");
    exit(EXIT_FAILURE);
  }
  return sehnd;
}
Exemple #2
0
struct selabel_handle* selinux_android_prop_context_handle(void)
{
    int policy_index = selinux_android_use_data_policy() ? 1 : 0;
    struct selabel_handle* sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP,
                                                   &seopts_prop[policy_index], 1);
    if (!sehandle) {
        ERROR("SELinux:  Could not load property_contexts:  %s\n",
              strerror(errno));
        return NULL;
    }
    INFO("SELinux: Loaded property contexts from %s\n", seopts_prop[policy_index].value);
    return sehandle;
}
Exemple #3
0
/*
 * Open the label handle
 * returns 1 on success, 0 if no selinux, negative on error
 */
int selinux_util_open(void)
{
    int retval = 0;

    retval = is_selinux_enabled();
    if (retval <= 0)
        return retval;

    hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
    if (!hnd)
        return -2;

    return 1;
}
Exemple #4
0
/* Set fcon to the appropriate label for path and mode, or return -1.  */
static int
getContext(const char *newpath, mode_t mode, security_context_t *fcon)
{
#if HAVE_SELINUX_LABEL_H
    struct selabel_handle *handle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
    int ret;

    if (handle == NULL)
        return -1;

    ret = selabel_lookup(handle, fcon, newpath, mode);
    selabel_close(handle);
    return ret;
#else
    return matchpathcon(newpath, mode, fcon);
#endif
}
struct selabel_handle* selinux_android_prop_context_handle(void)
{
    int i = 0;
    struct selabel_handle* sehandle = NULL;
    while ((sehandle == NULL) && seopts_prop[i].value) {
        sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP, &seopts_prop[i], 1);
        i++;
    }

    if (!sehandle) {
        ERROR("SELinux:  Could not load property_contexts:  %s\n",
              strerror(errno));
        return NULL;
    }
    INFO("SELinux: Loaded property contexts from %s\n", seopts_prop[i - 1].value);
    return sehandle;
}
static void do_compare_and_die_on_error(struct selinux_opt opts[], unsigned int backend, char *paths[])
{
    enum selabel_cmp_result result;
     char *result_str[] = { "subset", "equal", "superset", "incomparable" };
     int i;

     opts[0].value = NULL; /* not validating against a policy when comparing */

     for (i = 0; i < SEHANDLE_CNT; i++) {
         opts[1].value = paths[i];
         global_state.sepolicy.sehnd[i] = selabel_open(backend, opts, 2);
         if (!global_state.sepolicy.sehnd[i]) {
             fprintf(stderr, "Error: could not load context file from %s\n", paths[i]);
             exit(1);
         }
     }

     result = selabel_cmp(global_state.sepolicy.sehnd[0], global_state.sepolicy.sehnd[1]);
     printf("%s\n", result_str[result]);
}
int main(int argc, char **argv)
{
	struct statfs buf;
	int ret = 0;
	/* Files written only read/writable by root */
	umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);

	/* initialize libmicroui */
#ifdef USE_GUI
	mui_init();
#endif

	pr_info(" -- UserFastBoot %s for %s --\n", USERFASTBOOT_VERSION, DEVICE_NAME);

	mui_set_background(BACKGROUND_ICON_INSTALLING);

	struct selinux_opt seopts[] = {
		{ SELABEL_OPT_PATH, "/file_contexts" }
	};

	sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);

	if (!sehandle) {
		pr_error("Warning: No file_contexts\n");
	}

	load_volume_table();
	aboot_register_commands();
	register_userfastboot_plugins();
	ret = statfs("/tmp", &buf);
	if (!ret){
		unsigned long size = buf.f_bsize * buf.f_bfree;
		fastboot_init(size);
	}
	else
		pr_error("Error when acuiring tmpfs size:-%d\n", errno);


	/* Shouldn't get here */
	exit(1);
}
Exemple #8
0
int label_init(void) {
        int r = 0;

#ifdef HAVE_SELINUX

        if (!use_selinux())
                return 0;

        if (label_hnd)
                return 0;

        label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
        if (!label_hnd) {
                log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
                         "Failed to initialize SELinux context: %m");
                r = security_getenforce() == 1 ? -errno : 0;
        }
#endif

        return r;
}
Exemple #9
0
void
dpkg_selabel_load(void)
{
#ifdef WITH_LIBSELINUX
	static int selinux_enabled = -1;

	if (selinux_enabled < 0) {
		int rc;

		/* Set selinux_enabled if it is not already set (singleton). */
		selinux_enabled = (in_force(FORCE_SECURITY_MAC) &&
		                   is_selinux_enabled() > 0);
		if (!selinux_enabled)
			return;

		/* Open the SELinux status notification channel, with fallback
		 * enabled for older kernels. */
		rc = selinux_status_open(1);
		if (rc < 0)
			ohshit(_("cannot open security status notification channel"));

		/* XXX: We could use selinux_set_callback() to redirect the
		 * errors from the other SELinux calls, but that does not seem
		 * worth it right now. */
	} else if (selinux_enabled && selinux_status_updated()) {
		/* The SELinux policy got updated in the kernel, usually after
		 * upgrading the package shipping it, we need to reload. */
		selabel_close(sehandle);
	} else {
		/* SELinux is either disabled or it does not need a reload. */
		return;
	}

	sehandle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
	if (sehandle == NULL && security_getenforce() == 1)
		ohshite(_("cannot get security labeling handle"));
#endif
}
Exemple #10
0
int mac_selinux_init(const char *prefix) {
        int r = 0;

#ifdef HAVE_SELINUX
        usec_t before_timestamp, after_timestamp;
        struct mallinfo before_mallinfo, after_mallinfo;

        if (!mac_selinux_use())
                return 0;

        if (label_hnd)
                return 0;

        before_mallinfo = mallinfo();
        before_timestamp = now(CLOCK_MONOTONIC);

        if (prefix) {
                struct selinux_opt options[] = {
                        { .type = SELABEL_OPT_SUBSET, .value = prefix },
                };

                label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options));
        } else
Exemple #11
0
int mac_selinux_init(void) {
        int r = 0;

#ifdef HAVE_SELINUX
        usec_t before_timestamp, after_timestamp;
        struct mallinfo before_mallinfo, after_mallinfo;

        if (label_hnd)
                return 0;

        if (!mac_selinux_use())
                return 0;

        before_mallinfo = mallinfo();
        before_timestamp = now(CLOCK_MONOTONIC);

        label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
        if (!label_hnd) {
                log_enforcing("Failed to initialize SELinux context: %m");
                r = security_getenforce() == 1 ? -errno : 0;
        } else  {
                char timespan[FORMAT_TIMESPAN_MAX];
                int l;

                after_timestamp = now(CLOCK_MONOTONIC);
                after_mallinfo = mallinfo();

                l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;

                log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
                          format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
                          (l+1023)/1024);
        }
#endif

        return r;
}
int main(int argc, char *argv[])
{
	int fixstats = 0;
	struct stat stats;
	int opt;
	char *image;
	char *dir;
	char *secontext = NULL;

	while ((opt = getopt(argc, argv, "fc:s:")) != -1) {
		switch (opt) {
		case 'f':
			fixstats = 1;
			break;
		case 'c':
			chunkSize = (unsigned)strtoul(optarg, NULL, 0);
			break;
		case 's':
			spareSize = (unsigned)strtoul(optarg, NULL, 0);
			break;
		default:
			usage();
			exit(1);
		}
	}

	if (!chunkSize || !spareSize) {
		usage();
		exit(1);
	}

	if ((argc - optind < 2) || (argc - optind > 4)) {
		usage();
		exit(1);
	}

	dir = argv[optind];
	seprefixlen = strlen(dir);
	image = argv[optind + 1];

	if (optind + 2 < argc) {
		if (!strncmp(argv[optind + 2], "convert", strlen("convert")))
			convert_endian = 1;
		else {
			struct selinux_opt seopts[] = {
				{ SELABEL_OPT_PATH, argv[optind + 2] }
			};
			sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
			if (!sehnd) {
				perror(argv[optind + 2]);
				usage();
				exit(1);
			}
			if (optind + 3 >= argc) {
				usage();
				exit(1);
			}
			mntpoint = argv[optind + 3];
			if (optind + 4 < argc) {
				if (!strncmp(argv[optind + 4], "convert", strlen("convert")))
					convert_endian = 1;
			}
		}
	}

	if(stat(dir,&stats) < 0)
	{
		fprintf(stderr,"Could not stat %s\n",dir);
		exit(1);
	}
	
	if(!S_ISDIR(stats.st_mode))
	{
		fprintf(stderr," %s is not a directory\n",dir);
		exit(1);
	}
	
	outFile = open(image,O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE);
	
	
	if(outFile < 0)
	{
		fprintf(stderr,"Could not open output file %s\n",image);
		exit(1);
	}

    if (fixstats) {
        int len = strlen(dir);
        
        if((len >= 4) && (!strcmp(dir + len - 4, "data"))) {
            source_path_len = len - 4;
        } else if((len >= 6) && (!strcmp(dir + len - 6, "system"))) {
            source_path_len = len - 6;
        } else {            
            fprintf(stderr,"Fixstats (-f) option requested but filesystem is not data or android!\n");
            exit(1);
        }
        fix_stat(dir, &stats);
    }
    
	//printf("Processing directory %s into image file %s\n",dir,image);
    if (sehnd) {

        char *sepath = NULL;
        if (mntpoint[0] == '/')
	    sepath = strdup(mntpoint);
        else if (asprintf(&sepath, "/%s", mntpoint) < 0)
            sepath = NULL;

        if (!sepath) {
	    perror("malloc");
	    exit(1);
	}

	if (selabel_lookup(sehnd, &secontext, sepath, stats.st_mode) < 0) {
	    perror("selabel_lookup");
	    free(sepath);
	    exit(1);
	}

	free(sepath);
    }

    error =  write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL, secontext);
	if(error)
	error = process_directory(YAFFS_OBJECTID_ROOT,dir,fixstats);
	
	close(outFile);
	
	if(error < 0)
	{
		perror("operation incomplete");
		exit(1);
	}
	else
	{
        /*
		printf("Operation complete.\n"
		       "%d objects in %d directories\n"
		       "%d NAND pages\n",nObjects, nDirectories, nPages);
        */
	}
	
	close(outFile);
	
	exit(0);
}	
Exemple #13
0
int main(int argc, char** argv) {
    // Various things log information to stdout or stderr more or less
    // at random (though we've tried to standardize on stdout).  The
    // log file makes more sense if buffering is turned off so things
    // appear in the right order.
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    if (argc != 4) {
        printf("unexpected number of arguments (%d)\n", argc);
        return 1;
    }

    char* version = argv[1];
    if ((version[0] != '1' && version[0] != '2' && version[0] != '3') ||
        version[1] != '\0') {
        // We support version 1, 2, or 3.
        printf("wrong updater binary API; expected 1, 2, or 3; "
                        "got %s\n",
                argv[1]);
        return 2;
    }

    // Set up the pipe for sending commands back to the parent process.

    int fd = atoi(argv[2]);
    FILE* cmd_pipe = fdopen(fd, "wb");
    setlinebuf(cmd_pipe);

    // Extract the script from the package.

    const char* package_filename = argv[3];
    MemMapping map;
    if (sysMapFile(package_filename, &map) != 0) {
        printf("failed to map package %s\n", argv[3]);
        return 3;
    }
    ZipArchive za;
    int err;
    err = mzOpenZipArchive(map.addr, map.length, &za);
    if (err != 0) {
        printf("failed to open package %s: %s\n",
               argv[3], strerror(err));
        return 3;
    }

    const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME);
    if (script_entry == NULL) {
        printf("failed to find %s in %s\n", SCRIPT_NAME, package_filename);
        return 4;
    }

    char* script = malloc(script_entry->uncompLen+1);
    if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) {
        printf("failed to read script from package\n");
        return 5;
    }
    script[script_entry->uncompLen] = '\0';

    const ZipEntry* file_contexts_entry = mzFindZipEntry(&za, SELINUX_CONTEXTS_ZIP);
    if (file_contexts_entry != NULL) {
        int file_contexts_fd = creat(SELINUX_CONTEXTS_TMP, 0644);
		if (file_contexts_fd < 0) {
			fprintf(stderr, "Could not extract %s to '%s'\n", SELINUX_CONTEXTS_ZIP, SELINUX_CONTEXTS_TMP);
			return 3;
		}

		int ret_val = mzExtractZipEntryToFile(&za, file_contexts_entry, file_contexts_fd);
		close(file_contexts_fd);

		if (!ret_val) {
			fprintf(stderr, "Could not extract '%s'\n", SELINUX_CONTEXTS_ZIP);
			return 3;
		}
    }

    // Configure edify's functions.

    RegisterBuiltins();
    RegisterInstallFunctions();
    RegisterBlockImageFunctions();
    RegisterDeviceExtensions();
    FinishRegistration();

    // Parse the script.

    Expr* root;
    int error_count = 0;
    int error = parse_string(script, &root, &error_count);
    if (error != 0 || error_count > 0) {
        printf("%d parse errors\n", error_count);
        return 6;
    }

    if (access(SELINUX_CONTEXTS_TMP, R_OK) == 0) {
        struct selinux_opt seopts[] = {
          { SELABEL_OPT_PATH, SELINUX_CONTEXTS_TMP }
        };

        sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
    } else {
        struct selinux_opt seopts[] = {
          { SELABEL_OPT_PATH, "/file_contexts" }
        };

        sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
    }

    if (!sehandle) {
        fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n");
    }

    // Evaluate the parsed script.

    UpdaterInfo updater_info;
    updater_info.cmd_pipe = cmd_pipe;
    updater_info.package_zip = &za;
    updater_info.version = atoi(version);
    updater_info.package_zip_addr = map.addr;
    updater_info.package_zip_len = map.length;

    State state;
    state.cookie = &updater_info;
    state.script = script;
    state.errmsg = NULL;

    char* result = Evaluate(&state, root);
    if (result == NULL) {
        if (state.errmsg == NULL) {
            printf("script aborted (no error message)\n");
            fprintf(cmd_pipe, "ui_print script aborted (no error message)\n");
        } else {
            printf("script aborted: %s\n", state.errmsg);
            char* line = strtok(state.errmsg, "\n");
            while (line) {
                fprintf(cmd_pipe, "ui_print %s\n", line);
                line = strtok(NULL, "\n");
            }
            fprintf(cmd_pipe, "ui_print\n");
        }
        free(state.errmsg);
        return 7;
    } else {
        fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result);
        free(result);
    }

    if (updater_info.package_zip) {
        mzCloseZipArchive(updater_info.package_zip);
    }
    sysReleaseMap(&map);
    free(script);

    return 0;
}
Exemple #14
0
int
main(int argc, char **argv) {

    if (argc == 2 && strcmp(argv[1], "adbd") == 0) {
        adb_main();
        return 0;
    }

    // Recovery needs to install world-readable files, so clear umask
    // set by init
    umask(0);

    char* command = argv[0];
    char* stripped = strrchr(argv[0], '/');
    if (stripped)
        command = stripped + 1;

    if (strcmp(command, "recovery") != 0)
    {
        struct recovery_cmd cmd = get_command(command);
        if (cmd.name)
            return cmd.main_func(argc, argv);

#ifdef BOARD_RECOVERY_HANDLES_MOUNT
        if (!strcmp(command, "mount") && argc == 2)
        {
            load_volume_table();
            return ensure_path_mounted(argv[1]);
        }
#endif
        if (!strcmp(command, "setup_adbd")) {
            load_volume_table();
            setup_adbd();
            return 0;
        }
        if (!strcmp(command, "start")) {
            property_set("ctl.start", argv[1]);
            return 0;
        }
        if (!strcmp(command, "stop")) {
            property_set("ctl.stop", argv[1]);
            return 0;
        }
        /* Make sure stdout is not fully buffered, we don't want to
         * have issues when calling busybox commands */
        setlinebuf(stdout);
        return busybox_driver(argc, argv);
    }
    __system("/sbin/postrecoveryboot.sh");

    int is_user_initiated_recovery = 0;
    time_t start = time(NULL);

    // If these fail, there's not really anywhere to complain...
    freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
    freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);
    printf("Starting recovery on %s\n", ctime(&start));

    device_ui_init(&ui_parameters);
    ui_init();
    ui_print(EXPAND(RECOVERY_VERSION)"\n");

#ifdef BOARD_RECOVERY_SWIPE
#ifndef BOARD_TOUCH_RECOVERY
    //display directions for swipe controls
    ui_print("Swipe up/down to change selections.\n");
    ui_print("Swipe to the right for enter.\n");
    ui_print("Swipe to the left for back.\n");
#endif
#endif

    load_volume_table();
    process_volumes();
    vold_client_start(&v_callbacks, 0);
    vold_set_automount(1);
    setup_legacy_storage_paths();
    LOGI("Processing arguments.\n");
    ensure_path_mounted(LAST_LOG_FILE);
    rotate_last_logs(10);
    get_args(&argc, &argv);

    int previous_runs = 0;
    const char *send_intent = NULL;
    const char *update_package = NULL;
    const char *update_ubuntu_package = NULL;
    const char *user_data_update_package = NULL;
    int wipe_data = 0, wipe_cache = 0;
    int sideload = 0;
    int headless = 0;

    try_autodeploy(AUTODEPLOY_PACKAGE_FILE);
    try_autodeploy(AUTODEPLOY_PACKAGE_FILE_MULTI);

    LOGI("Checking arguments.\n");
    int arg;
    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
        switch (arg) {
        case 'p': previous_runs = atoi(optarg); break;
        case 's': send_intent = optarg; break;
        case 'u': update_package = optarg; break;
        case 'd': user_data_update_package = optarg; break;
        case 'w':
#ifndef BOARD_RECOVERY_ALWAYS_WIPES
        wipe_data = wipe_cache = 1;
#endif
        break;
        case 'h':
            ui_set_background(BACKGROUND_ICON_CID);
            ui_show_text(0);
            headless = 1;
            break;
        case 'c': wipe_cache = 1; break;
        case 't': ui_show_text(1); break;
        case 'l': sideload = 1; break;
        case 'v': update_ubuntu_package = UBUNTU_UPDATE_SCRIPT; break;
        case '?':
            LOGE("Invalid command argument\n");
            continue;
        }
    }

    struct selinux_opt seopts[] = {
      { SELABEL_OPT_PATH, "/file_contexts" }
    };

    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);

    if (!sehandle) {
        fprintf(stderr, "Warning: No file_contexts\n");
        ui_print("Warning:  No file_contexts\n");
    }

    LOGI("device_recovery_start()\n");
    device_recovery_start();

    printf("Command:");
    for (arg = 0; arg < argc; arg++) {
        printf(" \"%s\"", argv[arg]);
    }
    printf("\n");

    if (update_package) {
        // For backwards compatibility on the cache partition only, if
        // we're given an old 'root' path "CACHE:foo", change it to
        // "/cache/foo".
        if (strncmp(update_package, "CACHE:", 6) == 0) {
            int len = strlen(update_package) + 10;
            char* modified_path = malloc(len);
            strlcpy(modified_path, "/cache/", len);
            strlcat(modified_path, update_package+6, len);
            printf("(replacing path \"%s\" with \"%s\")\n",
                   update_package, modified_path);
            update_package = modified_path;
        }
    }
    printf("\n");

    property_list(print_property, NULL);
    printf("\n");

    int status = INSTALL_SUCCESS;

    if (update_package != NULL) {
        status = install_package(update_package);
        if (status != INSTALL_SUCCESS) {
            copy_logs();
            ui_print("Installation aborted.\n");
        }
    } else if (update_ubuntu_package != NULL) {
        LOGI("Performing Ubuntu update");
        ui_set_background(BACKGROUND_ICON_INSTALLING);
        ui_show_indeterminate_progress();
        ui_print("Installing Ubuntu update.\n");
        char tmp[PATH_MAX];
        sprintf(tmp, "%s %s", UBUNTU_UPDATE_SCRIPT, UBUNTU_COMMAND_FILE );
        __system(tmp);
        LOGI("Ubuntu update complete");
        ui_print("Ubuntu update complete.\n");
    } else if (wipe_data) {
        if (device_wipe_data()) status = INSTALL_ERROR;
        ignore_data_media_workaround(1);
        if (erase_volume("/data")) status = INSTALL_ERROR;
        ignore_data_media_workaround(0);
        if (has_datadata() && erase_volume("/datadata")) status = INSTALL_ERROR;
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) {
            copy_logs();
            ui_print("Data wipe failed.\n");
        }
    } else if (wipe_cache) {
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) {
            copy_logs();
            ui_print("Cache wipe failed.\n");
        }
    } else {
        LOGI("Checking for extendedcommand...\n");
        status = INSTALL_ERROR;  // No command specified
        // we are starting up in user initiated recovery here
        // let's set up some default options
        signature_check_enabled = 0;
        script_assert_enabled = 0;
        is_user_initiated_recovery = 1;
        if (!headless) {
            ui_set_show_text(1);
            ui_set_background(BACKGROUND_ICON_UBUNTU);
        }

        if (extendedcommand_file_exists()) {
            LOGI("Running extendedcommand...\n");
            int ret;
            if (0 == (ret = run_and_remove_extendedcommand())) {
                status = INSTALL_SUCCESS;
                ui_set_show_text(0);
            }
            else {
                handle_failure(ret);
            }
        } else {
            LOGI("Skipping execution of extendedcommand, file not found...\n");
        }
    }

    if (sideload) {
        signature_check_enabled = 0;
        if (!headless)
            ui_set_show_text(1);
        if (0 == apply_from_adb()) {
            status = INSTALL_SUCCESS;
            ui_set_show_text(0);
        }
    }

    if (headless) {
        headless_wait();
    }

    if (user_data_update_package != NULL) {
        status = install_package(user_data_update_package);
        if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n");
    }

    if (status != INSTALL_SUCCESS && !is_user_initiated_recovery) {
        ui_set_show_text(1);
        ui_set_background(BACKGROUND_ICON_ERROR);
    }
    else if (status != INSTALL_SUCCESS || ui_text_visible()) {
        prompt_and_wait();
    }

    // We reach here when in main menu we choose reboot main system or for some wipe commands on start
    // If there is a radio image pending, reboot now to install it.
    maybe_install_firmware_update(send_intent);

    // Otherwise, get ready to boot the main system...
    finish_recovery(send_intent);
    ui_print("Rebooting...\n");
    reboot_main_system(ANDROID_RB_RESTART, 0, 0);

    return EXIT_SUCCESS;
}
int
main(int argc, char **argv) {

    if (argc == 2 && strcmp(argv[1], "adbd") == 0) {
        adb_main();
        return 0;
    }

    // Recovery needs to install world-readable files, so clear umask
    // set by init
    umask(0);

    if (strcmp(basename(argv[0]), "recovery") != 0)
    {
        if (strstr(argv[0], "minizip") != NULL)
            return minizip_main(argc, argv);
        if (strstr(argv[0], "dedupe") != NULL)
            return dedupe_main(argc, argv);
        if (strstr(argv[0], "flash_image") != NULL)
            return flash_image_main(argc, argv);
        if (strstr(argv[0], "volume") != NULL)
            return volume_main(argc, argv);
        if (strstr(argv[0], "edify") != NULL)
            return edify_main(argc, argv);
        if (strstr(argv[0], "dump_image") != NULL)
            return dump_image_main(argc, argv);
        if (strstr(argv[0], "erase_image") != NULL)
            return erase_image_main(argc, argv);
        if (strstr(argv[0], "mkyaffs2image") != NULL)
             return mkyaffs2image_main(argc, argv);
        if (strstr(argv[0], "make_ext4fs") != NULL)
            return make_ext4fs_main(argc, argv);
        if (strstr(argv[0], "unyaffs") != NULL)
            return unyaffs_main(argc, argv);
        if (strstr(argv[0], "nandroid"))
            return nandroid_main(argc, argv);
        if (strstr(argv[0], "bu") == argv[0] + strlen(argv[0]) - 2)
            return bu_main(argc, argv);
        if (strstr(argv[0], "reboot"))
            return reboot_main(argc, argv);
#ifdef BOARD_RECOVERY_HANDLES_MOUNT
        if (strstr(argv[0], "mount") && argc == 2 && !strstr(argv[0], "umount"))
        {
            load_volume_table();
            return ensure_path_mounted(argv[1]);
        }
#endif
        if (strstr(argv[0], "poweroff")){
            return reboot_main(argc, argv);
        }
        if (strstr(argv[0], "setprop"))
            return setprop_main(argc, argv);
        if (strstr(argv[0], "getprop"))
            return getprop_main(argc, argv);
        return busybox_driver(argc, argv);
    }
    __system("/sbin/postrecoveryboot.sh");

    int is_user_initiated_recovery = 0;
    time_t start = time(NULL);

    // If these fail, there's not really anywhere to complain...
    freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
    freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);
    printf("Starting recovery on %s", ctime(&start));

    device_ui_init(&ui_parameters);
    ui_init();
    ui_print(EXPAND(RECOVERY_VERSION)"\n");
    load_volume_table();
    process_volumes();
    LOGI("Processing arguments.\n");
    get_args(&argc, &argv);

    int previous_runs = 0;
    const char *send_intent = NULL;
    const char *update_package = NULL;
    int wipe_data = 0, wipe_cache = 0;
    int sideload = 0;

    LOGI("Checking arguments.\n");
    int arg;
    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
        switch (arg) {
        case 'p': previous_runs = atoi(optarg); break;
        case 's': send_intent = optarg; break;
        case 'u': update_package = optarg; break;
        case 'w': 
#ifndef BOARD_RECOVERY_ALWAYS_WIPES
        wipe_data = wipe_cache = 1;
#endif
        break;
        case 'c': wipe_cache = 1; break;
        case 't': ui_show_text(1); break;
        case 'l': sideload = 1; break;
        case '?':
            LOGE("Invalid command argument\n");
            continue;
        }
    }

    struct selinux_opt seopts[] = {
      { SELABEL_OPT_PATH, "/file_contexts" }
    };

    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);

    if (!sehandle) {
        fprintf(stderr, "Warning: No file_contexts\n");
        // ui_print("Warning:  No file_contexts\n");
    }

    LOGI("device_recovery_start()\n");
    device_recovery_start();

    printf("命令:");
    for (arg = 0; arg < argc; arg++) {
        printf(" \"%s\"", argv[arg]);
    }
    printf("\n");

    if (update_package) {
        // For backwards compatibility on the cache partition only, if
        // we're given an old 'root' path "CACHE:foo", change it to
        // "/cache/foo".
        if (strncmp(update_package, "CACHE:", 6) == 0) {
            int len = strlen(update_package) + 10;
            char* modified_path = malloc(len);
            strlcpy(modified_path, "/cache/", len);
            strlcat(modified_path, update_package+6, len);
            printf("(replacing path \"%s\" with \"%s\")\n",
                   update_package, modified_path);
            update_package = modified_path;
        }
    }
    printf("\n");

    property_list(print_property, NULL);
    printf("\n");

    int status = INSTALL_SUCCESS;

    if (update_package != NULL) {
        status = install_package(update_package);
        if (status != INSTALL_SUCCESS) ui_print("安装失败.\n");
    } else if (wipe_data) {
        if (device_wipe_data()) status = INSTALL_ERROR;
        if (erase_volume("/data")) status = INSTALL_ERROR;
        if (has_datadata() && erase_volume("/datadata")) status = INSTALL_ERROR;
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui_print("清空data失败.\n");
    } else if (wipe_cache) {
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui_print("清空cache失败.\n");
    } else if (sideload) {
        signature_check_enabled = 0;
        ui_set_show_text(1);
        if (0 == apply_from_adb()) {
            status = INSTALL_SUCCESS;
            ui_set_show_text(0);
        }
    } else {
        LOGI("Checking for extendedcommand...\n");
        status = INSTALL_ERROR;  // No command specified
        // we are starting up in user initiated recovery here
        // let's set up some default options
        signature_check_enabled = 0;
        script_assert_enabled = 0;
        is_user_initiated_recovery = 1;
        ui_set_show_text(1);
        ui_set_background(BACKGROUND_ICON_CLOCKWORK);
        
        if (extendedcommand_file_exists()) {
            LOGI("Running extendedcommand...\n");
            int ret;
            if (0 == (ret = run_and_remove_extendedcommand())) {
                status = INSTALL_SUCCESS;
                ui_set_show_text(0);
            }
            else {
                handle_failure(ret);
            }
        } else {
            LOGI("Skipping execution of extendedcommand, file not found...\n");
        }
    }

    setup_adbd();

    if (status != INSTALL_SUCCESS && !is_user_initiated_recovery) {
        ui_set_show_text(1);
        ui_set_background(BACKGROUND_ICON_ERROR);
    }
    if (status != INSTALL_SUCCESS || ui_text_visible()) {
        prompt_and_wait();
    }

    verify_root_and_recovery();

    // If there is a radio image pending, reboot now to install it.
    maybe_install_firmware_update(send_intent);

    // Otherwise, get ready to boot the main system...
    finish_recovery(send_intent);

    sync();
    if(!poweroff) {
        ui_print("正在重启...\n");
        android_reboot(ANDROID_RB_RESTART, 0, 0);
    }
    else {
        ui_print("正在关机...\n");
        android_reboot(ANDROID_RB_POWEROFF, 0, 0);
    }
    return EXIT_SUCCESS;
}
static void do_fc_check_and_die_on_error(struct selinux_opt opts[], unsigned int backend, filemode mode,
        const char *sepolicy_file, const char *context_file, bool allow_empty)
{
    struct stat sb;
    if (stat(context_file, &sb) < 0) {
        perror("Error: could not get stat on file contexts file");
        exit(1);
    }

    if (sb.st_size == 0) {
        /* Nothing to check on empty file_contexts file if allowed*/
        if (allow_empty) {
            return;
        }
        /* else: We could throw the error here, but libselinux backend will catch it */
    }

    global_state.sepolicy.file = fopen(sepolicy_file, "r");
    if (!global_state.sepolicy.file) {
      perror("Error: could not open policy file");
      exit(1);
    }

    global_state.sepolicy.handle = sepol_handle_create();
    if (!global_state.sepolicy.handle) {
        fprintf(stderr, "Error: could not create policy handle: %s\n", strerror(errno));
        exit(1);
    }

    if (sepol_policy_file_create(&global_state.sepolicy.pf) < 0) {
      perror("Error: could not create policy handle");
      exit(1);
    }

    sepol_policy_file_set_fp(global_state.sepolicy.pf, global_state.sepolicy.file);
    sepol_policy_file_set_handle(global_state.sepolicy.pf, global_state.sepolicy.handle);

    int rc = sepol_policydb_create(&global_state.sepolicy.sdb);
    if (rc < 0) {
      perror("Error: could not create policy db");
      exit(1);
    }

    rc = sepol_policydb_read(global_state.sepolicy.sdb, global_state.sepolicy.pf);
    if (rc < 0) {
      perror("Error: could not read file into policy db");
      exit(1);
    }

    global_state.assert.attrs = filemode_to_assert_attrs(mode);

    bool ret = ebitmap_attribute_assertion_init(&global_state.assert.set, global_state.assert.attrs);
    if (!ret) {
        /* error messages logged by ebitmap_attribute_assertion_init() */
        exit(1);
    }

    selinux_set_callback(SELINUX_CB_VALIDATE,
                         (union selinux_callback)&validate);

    opts[1].value = context_file;

    global_state.sepolicy.sehnd[0] = selabel_open(backend, opts, 2);
    if (!global_state.sepolicy.sehnd[0]) {
      fprintf(stderr, "Error: could not load context file from %s\n", context_file);
      exit(1);
    }
}
Exemple #17
0
int main(int argc, char** argv) {
    // Various things log information to stdout or stderr more or less
    // at random.  The log file makes more sense if buffering is
    // turned off so things appear in the right order.
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    if (argc != 4) {
        fprintf(stderr, "unexpected number of arguments (%d)\n", argc);
        return 1;
    }

    char* version = argv[1];
    if ((version[0] != '1' && version[0] != '2' && version[0] != '3') ||
        version[1] != '\0') {
        // We support version 1, 2, or 3.
        fprintf(stderr, "wrong updater binary API; expected 1, 2, or 3; "
                        "got %s\n",
                argv[1]);
	//printf("Wrong updater binary API; expected 1, 2, or 3; we just got '%s' \n",argv[1]);
        return 2;
    }

    // Set up the pipe for sending commands back to the parent process.

    int fd = atoi(argv[2]);
    FILE* cmd_pipe = fdopen(fd, "wb");
    setlinebuf(cmd_pipe);

    // Extract the script from the package.

    char* package_data = argv[3];
    ZipArchive za;
    int err;
    err = mzOpenZipArchive(package_data, &za);
    if (err != 0) {
        fprintf(stderr, "failed to open package %s: %s\n",
                package_data, strerror(err));
        return 3;
    }

    const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME);
    if (script_entry == NULL) {
        fprintf(stderr, "failed to find %s in %s\n", SCRIPT_NAME, package_data);
        return 4;
    }

    char* script = malloc(script_entry->uncompLen+1);
    if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) {
        fprintf(stderr, "failed to read script from package\n");
        return 5;
    }
    script[script_entry->uncompLen] = '\0';

    // Configure edify's functions.

    RegisterBuiltins();
    RegisterInstallFunctions();
    RegisterDeviceExtensions();
    FinishRegistration();

    // Parse the script.

    Expr* root;
    int error_count = 0;
    yy_scan_string(script);
    int error = yyparse(&root, &error_count);
    if (error != 0 || error_count > 0) {
        fprintf(stderr, "%d parse errors\n", error_count);
        return 6;
    }

    struct selinux_opt seopts[] = {
      { SELABEL_OPT_PATH, "/file_contexts" }
    };

    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);

    if (!sehandle) {
        fprintf(stderr, "Warning:  No file_contexts\n");
        // fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n");
    }

    // Evaluate the parsed script.

    UpdaterInfo updater_info;
    updater_info.cmd_pipe = cmd_pipe;
    updater_info.package_zip = &za;
    updater_info.version = atoi(version);

    State state;
    state.cookie = &updater_info;
    state.script = script;
    state.errmsg = NULL;

    char* result = Evaluate(&state, root);
    if (result == NULL) {
        if (state.errmsg == NULL) {
            fprintf(stderr, "script aborted (no error message)\n");
            fprintf(cmd_pipe, "ui_print script aborted (no error message)\n");
        } else {
            fprintf(stderr, "script aborted: %s\n", state.errmsg);
            char* line = strtok(state.errmsg, "\n");
            while (line) {
                fprintf(cmd_pipe, "ui_print %s\n", line);
                line = strtok(NULL, "\n");
            }
            fprintf(cmd_pipe, "ui_print\n");
        }
        free(state.errmsg);
        return 7;
    } else {
        fprintf(stderr, "script result was [%s]\n", result);
        free(result);
    }

    if (updater_info.package_zip) {
        mzCloseZipArchive(updater_info.package_zip);
    }
    free(script);

    return 0;
}
Exemple #18
0
int main(int argc, char **argv) {
	// Recovery needs to install world-readable files, so clear umask
	// set by init
	umask(0);

	Log_Offset = 0;

	// Set up temporary log file (/tmp/recovery.log)
	freopen(TMP_LOG_FILE, "a", stdout);
	setbuf(stdout, NULL);
	freopen(TMP_LOG_FILE, "a", stderr);
	setbuf(stderr, NULL);

	signal(SIGPIPE, SIG_IGN);

	// Handle ADB sideload
	if (argc == 3 && strcmp(argv[1], "--adbd") == 0) {
		property_set("ctl.stop", "adbd");
		adb_main(argv[2]);
		return 0;
	}

#ifdef RECOVERY_SDCARD_ON_DATA
	datamedia = true;
#endif

	char crash_prop_val[PROPERTY_VALUE_MAX];
	int crash_counter;
	property_get("twrp.crash_counter", crash_prop_val, "-1");
	crash_counter = atoi(crash_prop_val) + 1;
	snprintf(crash_prop_val, sizeof(crash_prop_val), "%d", crash_counter);
	property_set("twrp.crash_counter", crash_prop_val);
	property_set("ro.twrp.boot", "1");
	property_set("ro.twrp.version", TW_VERSION_STR);

	time_t StartupTime = time(NULL);
	printf("Starting TWRP %s on %s (pid %d)\n", TW_VERSION_STR, ctime(&StartupTime), getpid());

	// Load default values to set DataManager constants and handle ifdefs
	DataManager::SetDefaultValues();
	printf("Starting the UI...");
	gui_init();
	printf("=> Linking mtab\n");
	symlink("/proc/mounts", "/etc/mtab");
	if (TWFunc::Path_Exists("/etc/twrp.fstab")) {
		if (TWFunc::Path_Exists("/etc/recovery.fstab")) {
			printf("Renaming regular /etc/recovery.fstab -> /etc/recovery.fstab.bak\n");
			rename("/etc/recovery.fstab", "/etc/recovery.fstab.bak");
		}
		printf("Moving /etc/twrp.fstab -> /etc/recovery.fstab\n");
		rename("/etc/twrp.fstab", "/etc/recovery.fstab");
	}
	printf("=> Processing recovery.fstab\n");
	if (!PartitionManager.Process_Fstab("/etc/recovery.fstab", 1)) {
		LOGERR("Failing out of recovery due to problem with recovery.fstab.\n");
		return -1;
	}
	PartitionManager.Output_Partition_Logging();
	// Load up all the resources
	gui_loadResources();

#ifdef HAVE_SELINUX
	if (TWFunc::Path_Exists("/prebuilt_file_contexts")) {
		if (TWFunc::Path_Exists("/file_contexts")) {
			printf("Renaming regular /file_contexts -> /file_contexts.bak\n");
			rename("/file_contexts", "/file_contexts.bak");
		}
		printf("Moving /prebuilt_file_contexts -> /file_contexts\n");
		rename("/prebuilt_file_contexts", "/file_contexts");
	}
	struct selinux_opt selinux_options[] = {
		{ SELABEL_OPT_PATH, "/file_contexts" }
	};
	selinux_handle = selabel_open(SELABEL_CTX_FILE, selinux_options, 1);
	if (!selinux_handle)
		printf("No file contexts for SELinux\n");
	else
		printf("SELinux contexts loaded from /file_contexts\n");
	{ // Check to ensure SELinux can be supported by the kernel
		char *contexts = NULL;

		if (PartitionManager.Mount_By_Path("/cache", true) && TWFunc::Path_Exists("/cache/recovery")) {
			lgetfilecon("/cache/recovery", &contexts);
			if (!contexts) {
				lsetfilecon("/cache/recovery", "test");
				lgetfilecon("/cache/recovery", &contexts);
			}
		} else {
			LOGINFO("Could not check /cache/recovery SELinux contexts, using /sbin/teamwin instead which may be inaccurate.\n");
			lgetfilecon("/sbin/teamwin", &contexts);
		}
		if (!contexts) {
			gui_print_color("warning", "Kernel does not have support for reading SELinux contexts.\n");
		} else {
			free(contexts);
			gui_print("Full SELinux support is present.\n");
		}
	}
#else
	gui_print_color("warning", "No SELinux support (no libselinux).\n");
#endif

	PartitionManager.Mount_By_Path("/cache", true);

	string Zip_File, Reboot_Value;
	bool Cache_Wipe = false, Factory_Reset = false, Perform_Backup = false, Shutdown = false;

	{
		TWPartition* misc = PartitionManager.Find_Partition_By_Path("/misc");
		if (misc != NULL) {
			if (misc->Current_File_System == "emmc") {
				set_device_type('e');
				set_device_name(misc->Actual_Block_Device.c_str());
			} else if (misc->Current_File_System == "mtd") {
				set_device_type('m');
				set_device_name(misc->MTD_Name.c_str());
			} else {
				LOGERR("Unknown file system for /misc\n");
			}
		}
		get_args(&argc, &argv);

		int index, index2, len;
		char* argptr;
		char* ptr;
		printf("Startup Commands: ");
		for (index = 1; index < argc; index++) {
			argptr = argv[index];
			printf(" '%s'", argv[index]);
			len = strlen(argv[index]);
			if (*argptr == '-') {argptr++; len--;}
			if (*argptr == '-') {argptr++; len--;}
			if (*argptr == 'u') {
				ptr = argptr;
				index2 = 0;
				while (*ptr != '=' && *ptr != '\n')
					ptr++;
				// skip the = before grabbing Zip_File
				while (*ptr == '=')
					ptr++;
				if (*ptr) {
					Zip_File = ptr;
				} else
					LOGERR("argument error specifying zip file\n");
			} else if (*argptr == 'w') {
				if (len == 9)
					Factory_Reset = true;
				else if (len == 10)
					Cache_Wipe = true;
			} else if (*argptr == 'n') {
				Perform_Backup = true;
			} else if (*argptr == 'p') {
				Shutdown = true;
			} else if (*argptr == 's') {
				ptr = argptr;
				index2 = 0;
				while (*ptr != '=' && *ptr != '\n')
					ptr++;
				if (*ptr) {
					Reboot_Value = *ptr;
				}
			}
		}
		printf("\n");
	}

	if(crash_counter == 0) {
		property_list(Print_Prop, NULL);
		printf("\n");
	} else {
		printf("twrp.crash_counter=%d\n", crash_counter);
	}

	// Check for and run startup script if script exists
	TWFunc::check_and_run_script("/sbin/runatboot.sh", "boot");
	TWFunc::check_and_run_script("/sbin/postrecoveryboot.sh", "boot");

#ifdef TW_INCLUDE_INJECTTWRP
	// Back up TWRP Ramdisk if needed:
	TWPartition* Boot = PartitionManager.Find_Partition_By_Path("/boot");
	LOGINFO("Backing up TWRP ramdisk...\n");
	if (Boot == NULL || Boot->Current_File_System != "emmc")
		TWFunc::Exec_Cmd("injecttwrp --backup /tmp/backup_recovery_ramdisk.img");
	else {
		string injectcmd = "injecttwrp --backup /tmp/backup_recovery_ramdisk.img bd=" + Boot->Actual_Block_Device;
		TWFunc::Exec_Cmd(injectcmd);
	}
	LOGINFO("Backup of TWRP ramdisk done.\n");
#endif

	bool Keep_Going = true;
	if (Perform_Backup) {
		DataManager::SetValue(TW_BACKUP_NAME, "(Auto Generate)");
		if (!OpenRecoveryScript::Insert_ORS_Command("backup BSDCAE\n"))
			Keep_Going = false;
	}
	if (Keep_Going && !Zip_File.empty()) {
		string ORSCommand = "install " + Zip_File;

		if (!OpenRecoveryScript::Insert_ORS_Command(ORSCommand))
			Keep_Going = false;
	}
	if (Keep_Going) {
		if (Factory_Reset) {
			if (!OpenRecoveryScript::Insert_ORS_Command("wipe data\n"))
				Keep_Going = false;
		} else if (Cache_Wipe) {
			if (!OpenRecoveryScript::Insert_ORS_Command("wipe cache\n"))
				Keep_Going = false;
		}
	}

	TWFunc::Update_Log_File();
	// Offer to decrypt if the device is encrypted
	if (DataManager::GetIntValue(TW_IS_ENCRYPTED) != 0) {
		LOGINFO("Is encrypted, do decrypt page first\n");
		if (gui_startPage("decrypt", 1, 1) != 0) {
			LOGERR("Failed to start decrypt GUI page.\n");
		} else {
			// Check for and load custom theme if present
			gui_loadCustomResources();
		}
	} else if (datamedia) {
		if (tw_get_default_metadata(DataManager::GetSettingsStoragePath().c_str()) != 0) {
			LOGINFO("Failed to get default contexts and file mode for storage files.\n");
		} else {
			LOGINFO("Got default contexts and file mode for storage files.\n");
		}
	}

	// Read the settings file
#ifdef TW_HAS_MTP
	// We unmount partitions sometimes during early boot which may override
	// the default of MTP being enabled by auto toggling MTP off. This
	// will force it back to enabled then get overridden by the settings
	// file, assuming that an entry for tw_mtp_enabled is set.
	DataManager::SetValue("tw_mtp_enabled", 1);
#endif
	DataManager::ReadSettingsFile();

	// Fixup the RTC clock on devices which require it
	if(crash_counter == 0)
		TWFunc::Fixup_Time_On_Boot();

	// Run any outstanding OpenRecoveryScript
	if (DataManager::GetIntValue(TW_IS_ENCRYPTED) == 0 && (TWFunc::Path_Exists(SCRIPT_FILE_TMP) || TWFunc::Path_Exists(SCRIPT_FILE_CACHE))) {
		OpenRecoveryScript::Run_OpenRecoveryScript();
	}

#ifdef TW_HAS_MTP
	// Enable MTP?
	char mtp_crash_check[PROPERTY_VALUE_MAX];
	property_get("mtp.crash_check", mtp_crash_check, "0");
	if (strcmp(mtp_crash_check, "0") == 0) {
		property_set("mtp.crash_check", "1");
		if (DataManager::GetIntValue("tw_mtp_enabled") == 1 && ((DataManager::GetIntValue(TW_IS_ENCRYPTED) != 0 && DataManager::GetIntValue(TW_IS_DECRYPTED) != 0) || DataManager::GetIntValue(TW_IS_ENCRYPTED) == 0)) {
			LOGINFO("Enabling MTP during startup\n");
			if (!PartitionManager.Enable_MTP())
				PartitionManager.Disable_MTP();
			else
				gui_print("MTP Enabled\n");
		} else {
			PartitionManager.Disable_MTP();
		}
		property_set("mtp.crash_check", "0");
	} else {
		gui_print_color("warning", "MTP Crashed, not starting MTP on boot.\n");
		DataManager::SetValue("tw_mtp_enabled", 0);
		PartitionManager.Disable_MTP();
	}
#else
	PartitionManager.Disable_MTP();
#endif

	// Launch the main GUI
	gui_start();

	// Disable flashing of stock recovery
	TWFunc::Disable_Stock_Recovery_Replace();
	// Check for su to see if the device is rooted or not
	if (PartitionManager.Mount_By_Path("/system", false)) {
		if (TWFunc::Path_Exists("/supersu/su") && !TWFunc::Path_Exists("/system/bin/su") && !TWFunc::Path_Exists("/system/xbin/su") && !TWFunc::Path_Exists("/system/bin/.ext/.su")) {
			// Device doesn't have su installed
			DataManager::SetValue("tw_busy", 1);
			if (gui_startPage("installsu", 1, 1) != 0) {
				LOGERR("Failed to start SuperSU install page.\n");
			}
		}
		sync();
		PartitionManager.UnMount_By_Path("/system", false);
	}

	// Reboot
	TWFunc::Update_Intent_File(Reboot_Value);
	TWFunc::Update_Log_File();
	gui_print("Rebooting...\n");
	string Reboot_Arg;
	DataManager::GetValue("tw_reboot_arg", Reboot_Arg);
	if (Reboot_Arg == "recovery")
		TWFunc::tw_reboot(rb_recovery);
	else if (Reboot_Arg == "poweroff")
		TWFunc::tw_reboot(rb_poweroff);
	else if (Reboot_Arg == "bootloader")
		TWFunc::tw_reboot(rb_bootloader);
	else if (Reboot_Arg == "download")
		TWFunc::tw_reboot(rb_download);
	else
		TWFunc::tw_reboot(rb_system);

	return 0;
}
int
main(int argc, char **argv) {
    time_t start = time(NULL);

    // If this binary is started with the single argument "--adbd",
    // instead of being the normal recovery binary, it turns into kind
    // of a stripped-down version of adbd that only supports the
    // 'sideload' command.  Note this must be a real argument, not
    // anything in the command file or bootloader control block; the
    // only way recovery should be run with this argument is when it
    // starts a copy of itself from the apply_from_adb() function.
    if (argc == 2 && strcmp(argv[1], "--adbd") == 0) {
        adb_main();
        return 0;
    }

    // Handle alternative invocations
    char* command = argv[0];
    char* stripped = strrchr(argv[0], '/');
    if (stripped)
        command = stripped + 1;

    if (strcmp(command, "recovery") != 0) {
        struct recovery_cmd cmd = get_command(command);
        if (cmd.name)
            return cmd.main_func(argc, argv);

#ifdef BOARD_RECOVERY_HANDLES_MOUNT
        if (!strcmp(command, "mount") && argc == 2)
        {
            load_volume_table();
            return ensure_path_mounted(argv[1]);
        }
#endif
        if (!strcmp(command, "setup_adbd")) {
            load_volume_table();
            setup_adbd();
            return 0;
        }
        if (strstr(argv[0], "start")) {
            property_set("ctl.start", argv[1]);
            return 0;
        }
        if (strstr(argv[0], "stop")) {
            property_set("ctl.stop", argv[1]);
            return 0;
        }
        return busybox_driver(argc, argv);
    }

    // devices can run specific tasks on recovery start
    __system("/sbin/postrecoveryboot.sh");

    // Clear umask for packages that copy files out to /tmp and then over
    // to /system without properly setting all permissions (eg. gapps).
    umask(0);

    // If these fail, there's not really anywhere to complain...
    freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
    freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);

    printf("Starting recovery on %s", ctime(&start));

    load_volume_table();
    setup_data_media(1);
    vold_client_start(&v_callbacks, 0);
    vold_set_automount(1);
    setup_legacy_storage_paths();
    ensure_path_mounted(LAST_LOG_FILE);
    rotate_last_logs(10);
    get_args(&argc, &argv);

    const char *send_intent = NULL;
    const char *update_package = NULL;
    int wipe_data = 0, wipe_cache = 0, wipe_media = 0, show_text = 0, sideload = 0;
    bool just_exit = false;
    bool shutdown_after = false;

    printf("Checking arguments.\n");
    int arg;
    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
        switch (arg) {
        case 's': send_intent = optarg; break;
        case 'u': update_package = optarg; break;
        case 'w': wipe_data = wipe_cache = 1; break;
        case 'm': wipe_media = 1; break;
        case 'c': wipe_cache = 1; break;
        case 't': show_text = 1; break;
        case 'x': just_exit = true; break;
        case 'a': sideload = 1; break;
        case 'p': shutdown_after = true; break;
        case 'g': {
            if (stage == NULL || *stage == '\0') {
                char buffer[20] = "1/";
                strncat(buffer, optarg, sizeof(buffer)-3);
                stage = strdup(buffer);
            }
            break;
        }
        case '?':
            LOGE("Invalid command argument\n");
            continue;
        }
    }

    printf("stage is [%s]\n", stage);

    device_ui_init(&ui_parameters);
    ui_init();
    ui_print(EXPAND(RECOVERY_MOD_VERSION_BUILD) "\n");
    ui_print("ClockworkMod " EXPAND(CWM_BASE_VERSION) "\n");
    LOGI("Device target: " EXPAND(TARGET_COMMON_NAME) "\n");
#ifdef PHILZ_TOUCH_RECOVERY
    print_libtouch_version(0);
#endif

    int st_cur, st_max;
    if (stage != NULL && sscanf(stage, "%d/%d", &st_cur, &st_max) == 2) {
        ui_SetStage(st_cur, st_max);
    }
    // ui_SetStage(5, 8); // debug

    if (show_text) ui_ShowText(true);

    struct selinux_opt seopts[] = {
      { SELABEL_OPT_PATH, "/file_contexts" }
    };

    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);

    if (!sehandle) {
        ui_print("Warning:  No file_contexts\n");
    }

    LOGI("device_recovery_start()\n");
    device_recovery_start();

    printf("Command:");
    for (arg = 0; arg < argc; arg++) {
        printf(" \"%s\"", argv[arg]);
    }
    printf("\n");

    if (update_package) {
        // For backwards compatibility on the cache partition only, if
        // we're given an old 'root' path "CACHE:foo", change it to
        // "/cache/foo".
        if (strncmp(update_package, "CACHE:", 6) == 0) {
            int len = strlen(update_package) + 10;
            char* modified_path = (char*)malloc(len);
            strlcpy(modified_path, "/cache/", len);
            strlcat(modified_path, update_package+6, len);
            printf("(replacing path \"%s\" with \"%s\")\n",
                   update_package, modified_path);
            update_package = modified_path;
        }
    }
    printf("\n");

    property_list(print_property, NULL);
    printf("\n");

    int status = INSTALL_SUCCESS;

    if (update_package != NULL) {
        status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE);
        if (status == INSTALL_SUCCESS && wipe_cache) {
            if (erase_volume("/cache")) {
                LOGE("Cache wipe (requested by package) failed.\n");
            }
        }
        if (status != INSTALL_SUCCESS) {
            ui_print("Installation aborted.\n");

            // If this is an eng or userdebug build, then automatically
            // turn the text display on if the script fails so the error
            // message is visible.
            char buffer[PROPERTY_VALUE_MAX+1];
            property_get("ro.build.fingerprint", buffer, "");
            if (strstr(buffer, ":userdebug/") || strstr(buffer, ":eng/")) {
                ui_ShowText(true);
            }
        }
    } else if (wipe_data) {
        if (device_wipe_data()) status = INSTALL_ERROR;
        if (erase_volume("/data")) status = INSTALL_ERROR;
        if (has_datadata() && erase_volume("/datadata")) status = INSTALL_ERROR;
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n");
    } else if (wipe_cache) {
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed.\n");
    } else if (wipe_media) {
        if (is_data_media() && erase_volume("/data/media")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui_print("Media wipe failed.\n");
    } else if (sideload) {
        status = enter_sideload_mode(status);
    } else if (!just_exit) {
        // let's check recovery start up scripts (openrecoveryscript and ROM Manager extendedcommands)
        status = INSTALL_NONE; // No command specified, it is a normal recovery boot unless we find a boot script to run

        LOGI("Checking for extendedcommand & OpenRecoveryScript...\n");

        // we need show_text to show boot scripts log
        bool text_visible = ui_IsTextVisible();
        ui_SetShowText(true);
        if (0 == check_boot_script_file(EXTENDEDCOMMAND_SCRIPT)) {
            LOGI("Running extendedcommand...\n");
            status = INSTALL_ERROR;
            if (0 == run_and_remove_extendedcommand())
                status = INSTALL_SUCCESS;
        }

        if (0 == check_boot_script_file(ORS_BOOT_SCRIPT_FILE)) {
            LOGI("Running openrecoveryscript....\n");
            status = INSTALL_ERROR;
            if (0 == run_ors_boot_script())
                status = INSTALL_SUCCESS;
        }

        ui_SetShowText(text_visible);
    }

    if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) {
        copy_logs();
        // ui_set_background(BACKGROUND_ICON_ERROR); // will be set in prompt_and_wait() after recovery lock check
        handle_failure();
    }
    if (status != INSTALL_SUCCESS || ui_IsTextVisible()) {
        ui_SetShowText(true);
#ifdef PHILZ_TOUCH_RECOVERY
        check_recovery_lock();
#endif
        prompt_and_wait(status);
    }

    // We reach here when in main menu we choose reboot main system or on success install of boot scripts and recovery commands
    finish_recovery(send_intent);
    if (shutdown_after) {
        ui_print("Shutting down...\n");
        reboot_main_system(ANDROID_RB_POWEROFF, 0, 0);
    } else {
        ui_print("Rebooting...\n");
        reboot_main_system(ANDROID_RB_RESTART, 0, 0);
    }
    return EXIT_SUCCESS;
}
int
main(int argc, char **argv) {
    // Recovery needs to install world-readable files, so clear umask
    // set by init
    umask(0);

    time_t start = time(NULL);

    // If these fail, there's not really anywhere to complain...
    freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
    freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);

    // If this binary is started with the single argument "--adbd",
    // instead of being the normal recovery binary, it turns into kind
    // of a stripped-down version of adbd that only supports the
    // 'sideload' command.  Note this must be a real argument, not
    // anything in the command file or bootloader control block; the
    // only way recovery should be run with this argument is when it
    // starts a copy of itself from the apply_from_adb() function.
    if (argc == 3 && strcmp(argv[1], "--adbd") == 0) {
        adb_main(argv[2]);
        return 0;
    }

    printf("Starting TWRP %s on %s", TW_VERSION_STR, ctime(&start));

    Device* device = make_device();
    ui = device->GetUI();

	//ui->Init();
    //ui->SetBackground(RecoveryUI::NONE);
    //load_volume_table();

	// Load default values to set DataManager constants and handle ifdefs
	DataManager_LoadDefaults();
	printf("Starting the UI...");
	gui_init();
	printf("=> Linking mtab\n");
	symlink("/proc/mounts", "/etc/mtab");
	printf("=> Processing recovery.fstab\n");
	if (!PartitionManager.Process_Fstab("/etc/recovery.fstab", 1)) {
		LOGE("Failing out of recovery due to problem with recovery.fstab.\n");
		//return -1;
	}
	PartitionManager.Output_Partition_Logging();
	// Load up all the resources
	gui_loadResources();

	PartitionManager.Mount_By_Path("/cache", true);
    get_args(&argc, &argv);

    int previous_runs = 0;
    const char *send_intent = NULL;
    const char *update_package = NULL;
    int wipe_data = 0, wipe_cache = 0;
    bool just_exit = false;
	bool perform_backup = false;

    int arg;
    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
        switch (arg) {
        case 'p': previous_runs = atoi(optarg); break;
        case 's': send_intent = optarg; break;
        case 'u': update_package = optarg; break;
        case 'w': wipe_data = wipe_cache = 1; break;
        case 'c': wipe_cache = 1; break;
        case 't': ui->ShowText(true); break;
        case 'x': just_exit = true; break;
        case 'n': perform_backup = true; LOGI("nandroid\n"); break;
        case '?':
            LOGE("Invalid command argument\n");
            continue;
        }
    }

#ifdef HAVE_SELINUX
    struct selinux_opt seopts[] = {
      { SELABEL_OPT_PATH, "/file_contexts" }
    };

    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);

    if (!sehandle) {
        fprintf(stderr, "Warning: No file_contexts\n");
        ui->Print("Warning:  No file_contexts\n");
    }
#endif

    //device->StartRecovery();

    printf("Command:");
    for (arg = 0; arg < argc; arg++) {
        printf(" \"%s\"", argv[arg]);
    }
    printf("\n");

    if (update_package) {
        // For backwards compatibility on the cache partition only, if
        // we're given an old 'root' path "CACHE:foo", change it to
        // "/cache/foo".
        if (strncmp(update_package, "CACHE:", 6) == 0) {
            int len = strlen(update_package) + 10;
            char* modified_path = (char*)malloc(len);
            strlcpy(modified_path, "/cache/", len);
            strlcat(modified_path, update_package+6, len);
            printf("(replacing path \"%s\" with \"%s\")\n",
                   update_package, modified_path);
            update_package = modified_path;
        }
    }
    printf("\n");

    property_list(print_property, NULL);
    printf("\n");

	// Check for and run startup script if script exists
	TWFunc::check_and_run_script("/sbin/runatboot.sh", "boot");
	TWFunc::check_and_run_script("/sbin/postrecoveryboot.sh", "boot");

#ifdef TW_INCLUDE_INJECTTWRP
	// Back up TWRP Ramdisk if needed:
	TWPartition* Boot = PartitionManager.Find_Partition_By_Path("/boot");
	string result;
	LOGI("Backing up TWRP ramdisk...\n");
	if (Boot == NULL || Boot->Current_File_System != "emmc")
		TWFunc::Exec_Cmd("injecttwrp --backup /tmp/backup_recovery_ramdisk.img", result);
	else {
		string injectcmd = "injecttwrp --backup /tmp/backup_recovery_ramdisk.img bd=" + Boot->Actual_Block_Device;
		TWFunc::Exec_Cmd(injectcmd, result);
	}
	LOGI("Backup of TWRP ramdisk done.\n");
#endif

    int status = INSTALL_SUCCESS;
	string ORSCommand;

	if (perform_backup) {
		char empt[50];
		gui_console_only();
		strcpy(empt, "(Current Date)");
		DataManager_SetStrValue(TW_BACKUP_NAME, empt);
		if (!OpenRecoveryScript::Insert_ORS_Command("backup BSDCAE\n"))
			status = INSTALL_ERROR;
	}
	if (status == INSTALL_SUCCESS) { // Prevent other actions if backup failed
    if (update_package != NULL) {
		ORSCommand = "install ";
		ORSCommand += update_package;
		ORSCommand += "\n";

		if (OpenRecoveryScript::Insert_ORS_Command(ORSCommand))
			status = INSTALL_SUCCESS;
		else
			status = INSTALL_ERROR;
		/*
        status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE);
        if (status == INSTALL_SUCCESS && wipe_cache) {
            if (erase_volume("/cache")) {
                LOGE("Cache wipe (requested by package) failed.");
            }
        }
        if (status != INSTALL_SUCCESS) ui->Print("Installation aborted.\n");
		*/
    } else if (wipe_data) {
		if (!OpenRecoveryScript::Insert_ORS_Command("wipe data\n"))
			status = INSTALL_ERROR;
		/*
        if (device->WipeData()) status = INSTALL_ERROR;
        if (erase_volume("/data")) status = INSTALL_ERROR;
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
		*/
        if (status != INSTALL_SUCCESS) ui->Print("Data wipe failed.\n");
    } else if (wipe_cache) {
        if (!OpenRecoveryScript::Insert_ORS_Command("wipe cache\n"))
			status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n");
    } else if (!just_exit) {
        status = INSTALL_ERROR;  // No command specified
    }
	}

	finish_recovery(NULL);
	// Offer to decrypt if the device is encrypted
	if (DataManager_GetIntValue(TW_IS_ENCRYPTED) != 0) {
		LOGI("Is encrypted, do decrypt page first\n");
		if (gui_startPage("decrypt") != 0) {
			LOGE("Failed to start decrypt GUI page.\n");
		}
	}

	// Read the settings file
	DataManager_ReadSettingsFile();
	// Run any outstanding OpenRecoveryScript
	if (DataManager_GetIntValue(TW_IS_ENCRYPTED) == 0 && (TWFunc::Path_Exists(SCRIPT_FILE_TMP) || TWFunc::Path_Exists(SCRIPT_FILE_CACHE))) {
		OpenRecoveryScript::Run_OpenRecoveryScript();
	}
	// Launch the main GUI
	gui_start();

	// Check for su to see if the device is rooted or not
	if (PartitionManager.Mount_By_Path("/system", false)) {
		// Disable flashing of stock recovery
		if (TWFunc::Path_Exists("/system/recovery-from-boot.p")) {
			rename("/system/recovery-from-boot.p", "/system/recovery-from-boot.bak");
			ui_print("Renamed stock recovery file in /system to prevent\nthe stock ROM from replacing TWRP.\n");
		}
		if (TWFunc::Path_Exists("/supersu/su") && !TWFunc::Path_Exists("/system/bin/su") && !TWFunc::Path_Exists("/system/xbin/su") && !TWFunc::Path_Exists("/system/bin/.ext/.su")) {
			// Device doesn't have su installed
			DataManager_SetIntValue("tw_busy", 1);
			if (gui_startPage("installsu") != 0) {
				LOGE("Failed to start decrypt GUI page.\n");
			}
		} else if (TWFunc::Check_su_Perms() > 0) {
			// su perms are set incorrectly
			DataManager_SetIntValue("tw_busy", 1);
			if (gui_startPage("fixsu") != 0) {
				LOGE("Failed to start decrypt GUI page.\n");
			}
		}
		sync();
		PartitionManager.UnMount_By_Path("/system", false);
	}

    // Otherwise, get ready to boot the main system...
    finish_recovery(send_intent);
    ui->Print("Rebooting...\n");
	char backup_arg_char[50];
	strcpy(backup_arg_char, DataManager_GetStrValue("tw_reboot_arg"));
	string backup_arg = backup_arg_char;
	if (backup_arg == "recovery")
		TWFunc::tw_reboot(rb_recovery);
	else if (backup_arg == "poweroff")
		TWFunc::tw_reboot(rb_poweroff);
	else if (backup_arg == "bootloader")
		TWFunc::tw_reboot(rb_bootloader);
	else if (backup_arg == "download")
		TWFunc::tw_reboot(rb_download);
	else
		TWFunc::tw_reboot(rb_system);

#ifdef ANDROID_RB_RESTART
    android_reboot(ANDROID_RB_RESTART, 0, 0);
#else
	reboot(RB_AUTOBOOT);
#endif
    return EXIT_SUCCESS;
}
int
main(int argc, char **argv) {
    // Recovery needs to install world-readable files, so clear umask
    // set by init
    umask(0);

    time_t start = time(NULL);

    // If these fail, there's not really anywhere to complain...
    freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
    freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);

    // If this binary is started with the single argument "--adbd",
    // instead of being the normal recovery binary, it turns into kind
    // of a stripped-down version of adbd that only supports the
    // 'sideload' command.  Note this must be a real argument, not
    // anything in the command file or bootloader control block; the
    // only way recovery should be run with this argument is when it
    // starts a copy of itself from the apply_from_adb() function.
    if (argc == 3 && strcmp(argv[1], "--adbd") == 0) {
        adb_main(argv[2]);
        return 0;
    }

    printf("Starting TWRP %s on %s", TW_VERSION_STR, ctime(&start));

    Device* device = make_device();
    ui = device->GetUI();

	//ui->Init();
    //ui->SetBackground(RecoveryUI::NONE);
    //load_volume_table();

	// Load default values to set DataManager constants and handle ifdefs
	DataManager_LoadDefaults();
	printf("Starting the UI...");
	gui_init();
	printf("=> Linking mtab\n");
	system("ln -s /proc/mounts /etc/mtab"); // Link mtab for mke2fs
	printf("=> Processing recovery.fstab\n");
	if (!PartitionManager.Process_Fstab("/etc/recovery.fstab", 1)) {
		LOGE("Failing out of recovery due to problem with recovery.fstab.\n");
		//return -1;
	}
	PartitionManager.Output_Partition_Logging();
	// Load up all the resources
	gui_loadResources();

    get_args(&argc, &argv);

    int previous_runs = 0;
    const char *send_intent = NULL;
    const char *update_package = NULL;
    int wipe_data = 0, wipe_cache = 0;
    bool just_exit = false;
	bool perform_backup = false;

    int arg;
    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
        switch (arg) {
        case 'p': previous_runs = atoi(optarg); break;
        case 's': send_intent = optarg; break;
        case 'u': update_package = optarg; break;
        case 'w': wipe_data = wipe_cache = 1; break;
        case 'c': wipe_cache = 1; break;
        case 't': ui->ShowText(true); break;
        case 'x': just_exit = true; break;
        case 'n': perform_backup = true; LOGI("nandroid\n"); break;
        case '?':
            LOGE("Invalid command argument\n");
            continue;
        }
    }

#ifdef HAVE_SELINUX
    struct selinux_opt seopts[] = {
      { SELABEL_OPT_PATH, "/file_contexts" }
    };

    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);

    if (!sehandle) {
        fprintf(stderr, "Warning: No file_contexts\n");
        ui->Print("Warning:  No file_contexts\n");
    }
#endif

    //device->StartRecovery();

    printf("Command:");
    for (arg = 0; arg < argc; arg++) {
        printf(" \"%s\"", argv[arg]);
    }
    printf("\n");

    if (update_package) {
        // For backwards compatibility on the cache partition only, if
        // we're given an old 'root' path "CACHE:foo", change it to
        // "/cache/foo".
        if (strncmp(update_package, "CACHE:", 6) == 0) {
            int len = strlen(update_package) + 10;
            char* modified_path = (char*)malloc(len);
            strlcpy(modified_path, "/cache/", len);
            strlcat(modified_path, update_package+6, len);
            printf("(replacing path \"%s\" with \"%s\")\n",
                   update_package, modified_path);
            update_package = modified_path;
        }
    }
    printf("\n");

    property_list(print_property, NULL);
    printf("\n");

	// Check for and run startup script if script exists
	TWFunc::check_and_run_script("/sbin/runatboot.sh", "boot");
	TWFunc::check_and_run_script("/sbin/postrecoveryboot.sh", "boot");

#ifdef TW_INCLUDE_INJECTTWRP
	// Back up TWRP Ramdisk if needed:
	LOGI("Backing up TWRP ramdisk...\n");
	system("injecttwrp --backup /tmp/backup_recovery_ramdisk.img");
	LOGI("Backup of TWRP ramdisk done.\n");
#endif

    int status = INSTALL_SUCCESS;

	if (perform_backup) {
		char empt[50];
		gui_console_only();
		strcpy(empt, "(Current Date)");
		DataManager_SetStrValue(TW_BACKUP_NAME, empt);
		if (OpenRecoveryScript::Backup_Command("BSDCAE") != 0)
			status = INSTALL_ERROR;
	}
	if (status == INSTALL_SUCCESS) { // Prevent other actions if backup failed
    if (update_package != NULL) {
		gui_console_only();
		if (OpenRecoveryScript::Install_Command(update_package) == 0)
			status = INSTALL_SUCCESS;
		else
			status = INSTALL_ERROR;
		/*
        status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE);
        if (status == INSTALL_SUCCESS && wipe_cache) {
            if (erase_volume("/cache")) {
                LOGE("Cache wipe (requested by package) failed.");
            }
        }
        if (status != INSTALL_SUCCESS) ui->Print("Installation aborted.\n");
		*/
    } else if (wipe_data) {
		gui_console_only();
		if (!PartitionManager.Factory_Reset()) status = INSTALL_ERROR;
		/*
        if (device->WipeData()) status = INSTALL_ERROR;
        if (erase_volume("/data")) status = INSTALL_ERROR;
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
		*/
        if (status != INSTALL_SUCCESS) ui->Print("Data wipe failed.\n");
    } else if (wipe_cache) {
		gui_console_only();
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n");
    } else if (!just_exit) {
        status = INSTALL_ERROR;  // No command specified
    }
	}

    //if (status != INSTALL_SUCCESS) ui->SetBackground(RecoveryUI::ERROR);
    if (status != INSTALL_SUCCESS /*|| ui->IsTextVisible()*/) {
		finish_recovery(NULL);
		DataManager_ReadSettingsFile();
		if (PartitionManager.Mount_By_Path("/system", false) && TWFunc::Path_Exists("/system/recovery-from-boot.p")) {
			system("mv /system/recovery-from-boot.p /system/recovery-from-boot.bak");
			ui_print("Renamed stock recovery file in /system to prevent\nthe stock ROM from replacing TWRP.\n");
		}
		PartitionManager.UnMount_By_Path("/system", false);
		if (DataManager_GetIntValue(TW_IS_ENCRYPTED) == 0 && OpenRecoveryScript::check_for_script_file()) {
			gui_console_only();
			if (OpenRecoveryScript::run_script_file() != 0) {
				// There was an error, boot the recovery
				gui_start();
			} else {
				usleep(2000000); // Sleep for 2 seconds before rebooting
			}
		} else
			gui_start();
		//prompt_and_wait(device);
    }

    // Otherwise, get ready to boot the main system...
    finish_recovery(send_intent);
    ui->Print("Rebooting...\n");
#ifdef ANDROID_RB_RESTART
    android_reboot(ANDROID_RB_RESTART, 0, 0);
#else
	reboot(RB_AUTOBOOT);
#endif
    return EXIT_SUCCESS;
}
int main(int argc, char **argv)
{
  struct selinux_opt opts[] = {
    { SELABEL_OPT_VALIDATE, (void*)1 },
    { SELABEL_OPT_PATH, NULL }
  };

  // Default backend unless changed by input argument.
  unsigned int backend = SELABEL_CTX_FILE;

  FILE *fp;
  struct selabel_handle *sehnd;
  char c;

  while ((c = getopt(argc, argv, "ph")) != -1) {
    switch (c) {
      case 'p':
        backend = SELABEL_CTX_ANDROID_PROP;
        break;
      case 'h':
      default:
        usage(argv[0]);
        break;
    }
  }

  int index = optind;
  if (argc - optind != 2) {
    fprintf(stderr, "Expected sepolicy file and context file as arguments.\n");
    usage(argv[0]);
  }

  // remaining args are sepolicy file and context file
  char *sepolicyFile = argv[index];
  char *contextFile = argv[index + 1];

  fp = fopen(sepolicyFile, "r");
  if (!fp) {
    perror(sepolicyFile);
    exit(2);
  }
  if (sepol_set_policydb_from_file(fp) < 0) {
    fprintf(stderr, "Error loading policy from %s\n", sepolicyFile);
    exit(3);
  }

  selinux_set_callback(SELINUX_CB_VALIDATE,
                       (union selinux_callback)&validate);

  opts[1].value = contextFile;

  sehnd = selabel_open(backend, opts, 2);
  if (!sehnd) {
    fprintf(stderr, "Error loading context file from %s\n", contextFile);
    exit(4);
  }
  if (nerr) {
    fprintf(stderr, "Invalid context file found in %s\n", contextFile);
    exit(5);
  }

  exit(0);
}
int
main(int argc, char **argv) {
    time_t start = time(NULL);
	char firmware[50] = {0};
	property_get("ro.reversion.aw_sdk_tag", firmware, "unknow");
	strcat(reversion,firmware);
	
	char storage_type[50] = {0};
	property_get("ro.sys.storage_type",storage_type,"");
	if(!strcmp(storage_type,"emulated")){
		internal_storage_type = 1;
	}

    // If these fail, there's not really anywhere to complain...
    freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
    freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);
    

    // If this binary is started with the single argument "--adbd",
    // instead of being the normal recovery binary, it turns into kind
    // of a stripped-down version of adbd that only supports the
    // 'sideload' command.  Note this must be a real argument, not
    // anything in the command file or bootloader control block; the
    // only way recovery should be run with this argument is when it
    // starts a copy of itself from the apply_from_adb() function.
    if (argc == 2 && strcmp(argv[1], "--adbd") == 0) {
        adb_main();
        return 0;
    }
    
    printf("Starting recovery on %s", ctime(&start));

    load_volume_table();
    get_args(&argc, &argv);

    int previous_runs = 0;
    const char *send_intent = NULL;
    const char *update_package = NULL;
    int wipe_data = 0, wipe_cache = 0, show_text = 0;
    bool just_exit = false;

    int arg;
    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
        switch (arg) {
        case 'p': previous_runs = atoi(optarg); break;
        case 's': send_intent = optarg; break;
        case 'u': update_package = optarg; break;
        case 'w': wipe_data = wipe_cache = 1; break;
        case 'c': wipe_cache = 1; break;
        case 't': show_text = 1; break;
        case 'x': just_exit = true; break;
        case 'l': locale = optarg; break;
        case '?':
            LOGE("Invalid command argument\n");
            continue;
        }
    }

    if (locale == NULL) {
        load_locale_from_cache();
    }
    printf("locale is [%s]\n", locale);

    Device* device = make_device();
    ui = device->GetUI();

    ui->Init();
    ui->SetLocale(locale);
    ui->SetBackground(RecoveryUI::NONE);
    if (show_text) ui->ShowText(true);

#ifdef HAVE_SELINUX
    struct selinux_opt seopts[] = {
      { SELABEL_OPT_PATH, "/file_contexts" }
    };

    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);

    if (!sehandle) {
        fprintf(stderr, "Warning: No file_contexts\n");
        ui->Print("Warning:  No file_contexts\n");
    }
#endif

    device->StartRecovery();

    printf("Command:");
    for (arg = 0; arg < argc; arg++) {
        printf(" \"%s\"", argv[arg]);
    }
    printf("\n");

    if (update_package) {
        // For backwards compatibility on the cache partition only, if
        // we're given an old 'root' path "CACHE:foo", change it to
        // "/cache/foo".
        if (strncmp(update_package, "CACHE:", 6) == 0) {
            int len = strlen(update_package) + 10;
            char* modified_path = (char*)malloc(len);
            strlcpy(modified_path, "/cache/", len);
            strlcat(modified_path, update_package+6, len);
            printf("(replacing path \"%s\" with \"%s\")\n",
                   update_package, modified_path);
            update_package = modified_path;
        }
    }
    printf("\n");

    property_list(print_property, NULL);
    printf("\n");

    int status = INSTALL_SUCCESS;

    if (update_package != NULL) {
        status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE);
        if (status == INSTALL_SUCCESS && wipe_cache) {
            if (erase_volume("/cache")) {
                LOGE("Cache wipe (requested by package) failed.");
            }
        }
        if (status != INSTALL_SUCCESS) ui->Print("Installation aborted.\n");
    } else if (wipe_data) {
        if (device->WipeData()) status = INSTALL_ERROR;
        if (erase_volume("/data")) status = INSTALL_ERROR;
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
		copy_databk_to_data();
        if (status != INSTALL_SUCCESS) ui->Print("Data wipe failed.\n");
    } else if (wipe_cache) {
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n");
    } else if (!just_exit) {
        status = INSTALL_NONE;  // No command specified
//        ui->SetBackground(RecoveryUI::NO_COMMAND); // modify by cjcheng
    }

    if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) {
        ui->SetBackground(RecoveryUI::ERROR);
    }
    if (status != INSTALL_SUCCESS || ui->IsTextVisible()) {
        ui->ShowText(false); // modify by cjcheng
        ui->SetTipTitle(RecoveryUI::TIP_TITLE_READY); // add by cjcheng
        prompt_and_wait(device, status);

	/* add by cjcheng start... */
        if (install_flag == INSTALL_SUCCESS){
            ui->SetTipTitle(RecoveryUI::TIP_TITLE_SUCCESS);
            status = INSTALL_SUCCESS;
        }
	/* add by cjcheng end... */
    }

    /* add by cjcheng start... */
    if (status != INSTALL_SUCCESS){
        ui->SetBackground(RecoveryUI::ERROR);
        ui->SetTipTitle(RecoveryUI::TIP_TITLE_ERROR);
    }
    /* add by cjcheng end... */

    sleep(2);

    // Otherwise, get ready to boot the main system...
    finish_recovery(send_intent);
    ui->Print("Rebooting...\n");
    sync();
    android_reboot(ANDROID_RB_RESTART, 0, 0);
    return EXIT_SUCCESS;
}
int
main(int argc, char **argv) {

    if (argc == 2 && strcmp(argv[1], "adbd") == 0) {
        adb_main();
        return 0;
    }

    // Recovery needs to install world-readable files, so clear umask
    // set by init
    umask(0);

    char* command = argv[0];
    char* stripped = strrchr(argv[0], '/');
    if (stripped)
        command = stripped + 1;

    if (strcmp(command, "recovery") != 0)
    {
        struct recovery_cmd cmd = get_command(command);
        if (cmd.name)
            return cmd.main_func(argc, argv);

#ifdef BOARD_RECOVERY_HANDLES_MOUNT
        if (!strcmp(command, "mount") && argc == 2)
        {
            load_volume_table();
            return ensure_path_mounted(argv[1]);
        }
#endif
        if (!strcmp(command, "setup_adbd")) {
            load_volume_table();
            setup_adbd();
            return 0;
        }
        if (!strcmp(command, "start")) {
            property_set("ctl.start", argv[1]);
            return 0;
        }
        if (!strcmp(command, "stop")) {
            property_set("ctl.stop", argv[1]);
            return 0;
        }
        return busybox_driver(argc, argv);
    }
    //__system("/sbin/postrecoveryboot.sh");

    int is_user_initiated_recovery = 0;
    time_t start = time(NULL);

    // If these fail, there's not really anywhere to complain...
    freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
    freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);
    printf("Starting recovery on %s\n", ctime(&start));

    device_ui_init(&ui_parameters);
    ui_init();
    ui_print(EXPAND(RECOVERY_VERSION)"\n");
	ui_print("Builder: "EXPAND(RECOVERY_BUILDER)"\n");
	ui_print("Date: "EXPAND(RECOVERY_BUILD_TIME)"\n");
	ui_print("weibo:@nx-baby\n");
	__system("/sbin/postrecoveryboot.sh");

//#ifdef BOARD_RECOVERY_SWIPE
//#ifndef BOARD_TOUCH_RECOVERY
    //display directions for swipe controls
    ui_print("Swipe up/down to change selections.\n");
    ui_print("Swipe to the right for enter.\n");
    ui_print("Swipe to the left for back.\n");
//#endif
//#endif

    load_volume_table();
    process_volumes();
    vold_init();
    setup_legacy_storage_paths();
#ifdef QCOM_HARDWARE
    parse_t_daemon_data_files();
	apply_time_zone();
#endif
    LOGI("Processing arguments.\n");
    ensure_path_mounted(LAST_LOG_FILE);
    rotate_last_logs(10);
    get_args(&argc, &argv);

    const char *send_intent = NULL;
    const char *update_package = NULL;
    int wipe_data = 0, wipe_cache = 0;
    int sideload = 0;
    int headless = 0;
    int shutdown_after = 0;

    LOGI("Checking arguments.\n");
    int arg;
    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
        switch (arg) {
        case 's': send_intent = optarg; break;
        case 'u':
            if (update_package == NULL)
                update_package = optarg;
            break;
        case 'w':
#ifndef BOARD_RECOVERY_ALWAYS_WIPES
        wipe_data = wipe_cache = 1;
#endif
        break;
        case 'h':
            ui_set_background(BACKGROUND_ICON_CID);
            ui_show_text(0);
            headless = 1;
            break;
        case 'c': wipe_cache = 1; break;
        case 't': ui_show_text(1); break;
        case 'l': sideload = 1; break;
        case 'p': shutdown_after = 1; break;
        case '?':
            LOGE("Invalid command argument\n");
            continue;
        }
    }

    struct selinux_opt seopts[] = {
      { SELABEL_OPT_PATH, "/file_contexts" }
    };

    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);

    if (!sehandle) {
        fprintf(stderr, "Warning: No file_contexts\n");
        //ui_print("Warning:  No file_contexts\n");
    }

    LOGI("device_recovery_start()\n");
    device_recovery_start();

    printf("Command:");
    for (arg = 0; arg < argc; arg++) {
        printf(" \"%s\"", argv[arg]);
    }
    printf("\n");

    if (update_package) {
        // For backwards compatibility on the cache partition only, if
        // we're given an old 'root' path "CACHE:foo", change it to
        // "/cache/foo".
        if (strncmp(update_package, "CACHE:", 6) == 0) {
            int len = strlen(update_package) + 10;
            char* modified_path = malloc(len);
            strlcpy(modified_path, "/cache/", len);
            strlcat(modified_path, update_package+6, len);
            printf("(replacing path \"%s\" with \"%s\")\n",
                   update_package, modified_path);
            update_package = modified_path;
        }
    }
    printf("\n");

    property_list(print_property, NULL);
    printf("\n");

    int status = INSTALL_SUCCESS;

    if (update_package != NULL) {
        status = install_package(update_package);
        if (status != INSTALL_SUCCESS) {
            copy_logs();
            ui_print("Installation aborted.\n");
        } else if (!strcmp(TARGET_DEVICE, "A0001")) { //hack for a0001 ota
            if (strstr(update_package, "/.OTA/"))
                send_intent = "0";
        }
    } else if (wipe_data) {
        if (device_wipe_data()) status = INSTALL_ERROR;
        preserve_data_media(0);
        if (erase_volume("/data")) status = INSTALL_ERROR;
        preserve_data_media(1);
        if (has_datadata() && erase_volume("/datadata")) status = INSTALL_ERROR;
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) {
            copy_logs();
            ui_print("Data wipe failed.\n");
        }
    } else if (wipe_cache) {
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) {
            copy_logs();
            ui_print("Cache wipe failed.\n");
        }
    } else {
        LOGI("Checking for extendedcommand...\n");
        status = INSTALL_ERROR;  // No command specified
        // we are starting up in user initiated recovery here
        // let's set up some default options
        signature_check_enabled = 0;
        is_user_initiated_recovery = 1;
        if (!headless) {
            ui_set_show_text(1);
            ui_set_background(BACKGROUND_ICON_CLOCKWORK);
        }

        if (extendedcommand_file_exists()) {
            LOGI("Running extendedcommand...\n");
            int ret;
            if (0 == (ret = run_and_remove_extendedcommand())) {
                status = INSTALL_SUCCESS;
                ui_set_show_text(0);
            }
            else {
                handle_failure(ret);
            }
        } else {
            LOGI("Skipping execution of extendedcommand, file not found...\n");
        }
    }

    if (sideload) {
        signature_check_enabled = 0;
        if (!headless)
            ui_set_show_text(1);
        if (0 == apply_from_adb()) {
            status = INSTALL_SUCCESS;
            ui_set_show_text(0);
        }
    }

    if (headless) {
        headless_wait();
    }
    if (status != INSTALL_SUCCESS && !is_user_initiated_recovery) {
        ui_set_show_text(1);
        ui_set_background(BACKGROUND_ICON_ERROR);
    }
    else if (status != INSTALL_SUCCESS || ui_text_visible()) {
        prompt_and_wait();
    }

    // We reach here when in main menu we choose reboot main system or for some wipe commands on start
    // If there is a radio image pending, reboot now to install it.
    maybe_install_firmware_update(send_intent);

    // Otherwise, get ready to boot the main system...
    finish_recovery(send_intent);
    if (shutdown_after) {
        ui_print("Shutting down...\n");
        reboot_main_system(ANDROID_RB_POWEROFF, 0, 0);
    } else {
        ui_print("Rebooting...\n");
        reboot_main_system(ANDROID_RB_RESTART, 0, 0);
    }
    return EXIT_SUCCESS;
}
Exemple #25
0
int main(int argc, char **argv)
{
	int backend = 0, rc, opt, validate = 0;
	char *baseonly = NULL, *file = NULL, *digest = (char *)1;
	char **specfiles = NULL;
	unsigned char *sha1_digest = NULL;
	size_t i, num_specfiles;

	char cmd_buf[4096];
	char *cmd_ptr;
	char *sha1_buf;

	struct selabel_handle *hnd;
	struct selinux_opt selabel_option[] = {
		{ SELABEL_OPT_PATH, file },
		{ SELABEL_OPT_BASEONLY, baseonly },
		{ SELABEL_OPT_DIGEST, digest }
	};

	if (argc < 3)
		usage(argv[0]);

	while ((opt = getopt(argc, argv, "ib:Bvf:")) > 0) {
		switch (opt) {
		case 'b':
			if (!strcasecmp(optarg, "file")) {
				backend = SELABEL_CTX_FILE;
			} else if (!strcmp(optarg, "media")) {
				backend = SELABEL_CTX_MEDIA;
			} else if (!strcmp(optarg, "x")) {
				backend = SELABEL_CTX_X;
			} else if (!strcmp(optarg, "db")) {
				backend = SELABEL_CTX_DB;
			} else if (!strcmp(optarg, "prop")) {
				backend = SELABEL_CTX_ANDROID_PROP;
			} else if (!strcmp(optarg, "service")) {
				backend = SELABEL_CTX_ANDROID_SERVICE;
			} else {
				fprintf(stderr, "Unknown backend: %s\n",
								    optarg);
				usage(argv[0]);
			}
			break;
		case 'B':
			baseonly = (char *)1;
			break;
		case 'v':
			validate = 1;
			break;
		case 'i':
			digest = NULL;
			break;
		case 'f':
			file = optarg;
			break;
		default:
			usage(argv[0]);
		}
	}

	memset(cmd_buf, 0, sizeof(cmd_buf));

	selabel_option[0].value = file;
	selabel_option[1].value = baseonly;
	selabel_option[2].value = digest;

	hnd = selabel_open(backend, selabel_option, 3);
	if (!hnd) {
		switch (errno) {
		case EOVERFLOW:
			fprintf(stderr, "ERROR Number of specfiles or specfile"
					" buffer caused an overflow.\n");
			break;
		default:
			fprintf(stderr, "ERROR: selabel_open: %s\n",
						    strerror(errno));
		}
		return -1;
	}

	rc = selabel_digest(hnd, &sha1_digest, &digest_len, &specfiles,
							    &num_specfiles);

	if (rc) {
		switch (errno) {
		case EINVAL:
			fprintf(stderr, "No digest available.\n");
			break;
		default:
			fprintf(stderr, "selabel_digest ERROR: %s\n",
						    strerror(errno));
		}
		goto err;
	}

	sha1_buf = malloc(digest_len * 2 + 1);
	if (!sha1_buf) {
		fprintf(stderr, "Could not malloc buffer ERROR: %s\n",
						    strerror(errno));
		rc = -1;
		goto err;
	}

	printf("SHA1 digest: ");
	for (i = 0; i < digest_len; i++)
		sprintf(&(sha1_buf[i * 2]), "%02x", sha1_digest[i]);

	printf("%s\n", sha1_buf);
	printf("calculated using the following specfile(s):\n");

	if (specfiles) {
		cmd_ptr = &cmd_buf[0];
		sprintf(cmd_ptr, "/usr/bin/cat ");
		cmd_ptr = &cmd_buf[0] + strlen(cmd_buf);

		for (i = 0; i < num_specfiles; i++) {
			sprintf(cmd_ptr, "%s ", specfiles[i]);
			cmd_ptr += strlen(specfiles[i]) + 1;
			printf("%s\n", specfiles[i]);
		}
		sprintf(cmd_ptr, "| /usr/bin/openssl dgst -sha1 -hex");

		if (validate)
			rc = run_check_digest(cmd_buf, sha1_buf);
	}

	free(sha1_buf);
err:
	selabel_close(hnd);
	return rc;
}
Exemple #26
0
Datum
sepgsql_restorecon(PG_FUNCTION_ARGS)
{
	struct selabel_handle  *sehnd;
	struct selinux_opt		seopts;

	/*
	 * SELinux has to be enabled on the running platform.
	 */
	if (!sepgsql_is_enabled())
		ereport(ERROR,
				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
				 errmsg("sepgsql is not currently enabled")));
	/*
	 * Check DAC permission. Only superuser can set up initial
	 * security labels, like root-user in filesystems
	 */
	if (!superuser())
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("SELinux: must be superuser to restore initial contexts")));

	/*
	 * Open selabel_lookup(3) stuff. It provides a set of mapping
	 * between an initial security label and object class/name due
	 * to the system setting.
	 */
	if (PG_ARGISNULL(0))
	{
		seopts.type = SELABEL_OPT_UNUSED;
		seopts.value = NULL;
	}
	else
	{
		seopts.type = SELABEL_OPT_PATH;
		seopts.value = TextDatumGetCString(PG_GETARG_DATUM(0));
	}
	sehnd = selabel_open(SELABEL_CTX_DB, &seopts, 1);
	if (!sehnd)
		ereport(ERROR,
				(errcode(ERRCODE_INTERNAL_ERROR),
				 errmsg("SELinux: failed to initialize labeling handle: %m")));
	PG_TRY();
	{
		/*
		 * Right now, we have no support labeling on the shared
		 * database objects, such as database, role, or tablespace.
		 */
		exec_object_restorecon(sehnd, NamespaceRelationId);
		exec_object_restorecon(sehnd, RelationRelationId);
		exec_object_restorecon(sehnd, AttributeRelationId);
		exec_object_restorecon(sehnd, ProcedureRelationId);
	}
	PG_CATCH();
	{
		selabel_close(sehnd);
		PG_RE_THROW();
	}
	PG_END_TRY();	

	selabel_close(sehnd);

	PG_RETURN_BOOL(true);
}
int
main(int argc, char **argv) {
    time_t start = time(NULL);

    // If these fail, there's not really anywhere to complain...
    freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
    freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);

    // If this binary is started with the single argument "--adbd",
    // instead of being the normal recovery binary, it turns into kind
    // of a stripped-down version of adbd that only supports the
    // 'sideload' command.  Note this must be a real argument, not
    // anything in the command file or bootloader control block; the
    // only way recovery should be run with this argument is when it
    // starts a copy of itself from the apply_from_adb() function.
    if (argc == 2 && strcmp(argv[1], "--adbd") == 0) {
        adb_main();
        return 0;
    }

    printf("Starting recovery on %s", ctime(&start));

    load_volume_table();
    ensure_path_mounted(LAST_LOG_FILE);
    rotate_last_logs(10);
    get_args(&argc, &argv);

    const char *send_intent = NULL;
    const char *update_package = NULL;
    int wipe_data = 0, wipe_cache = 0, show_text = 0;
    bool just_exit = false;
    bool shutdown_after = false;

    int arg;
    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
        switch (arg) {
        case 's': send_intent = optarg; break;
        case 'u': update_package = optarg; break;
        case 'w': wipe_data = wipe_cache = 1; break;
        case 'c': wipe_cache = 1; break;
        case 't': show_text = 1; break;
        case 'x': just_exit = true; break;
        case 'l': locale = optarg; break;
        case 'g': {
            if (stage == NULL || *stage == '\0') {
                char buffer[20] = "1/";
                strncat(buffer, optarg, sizeof(buffer)-3);
                stage = strdup(buffer);
            }
            break;
        }
        case 'p': shutdown_after = true; break;
        case '?':
            LOGE("Invalid command argument\n");
            continue;
        }
    }

    if (locale == NULL) {
        load_locale_from_cache();
    }
    printf("locale is [%s]\n", locale);
    printf("stage is [%s]\n", stage, stage);

    Device* device = make_device();
    ui = device->GetUI();
    gCurrentUI = ui;

    ui->SetLocale(locale);
    ui->Init();

    int st_cur, st_max;
    if (stage != NULL && sscanf(stage, "%d/%d", &st_cur, &st_max) == 2) {
        ui->SetStage(st_cur, st_max);
    }

    ui->SetBackground(RecoveryUI::NONE);
    if (show_text) ui->ShowText(true);

    struct selinux_opt seopts[] = {
      { SELABEL_OPT_PATH, "/file_contexts" }
    };

    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);

    if (!sehandle) {
        ui->Print("Warning: No file_contexts\n");
    }

    device->StartRecovery();

    printf("Command:");
    for (arg = 0; arg < argc; arg++) {
        printf(" \"%s\"", argv[arg]);
    }
    printf("\n");

    if (update_package) {
        // For backwards compatibility on the cache partition only, if
        // we're given an old 'root' path "CACHE:foo", change it to
        // "/cache/foo".
        if (strncmp(update_package, "CACHE:", 6) == 0) {
            int len = strlen(update_package) + 10;
            char* modified_path = (char*)malloc(len);
            strlcpy(modified_path, "/cache/", len);
            strlcat(modified_path, update_package+6, len);
            printf("(replacing path \"%s\" with \"%s\")\n",
                   update_package, modified_path);
            update_package = modified_path;
        }
    }
    printf("\n");

    property_list(print_property, NULL);
    property_get("ro.build.display.id", recovery_version, "");
    printf("\n");

    int status = INSTALL_SUCCESS;

    if (update_package != NULL) {
        status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE);
        if (status == INSTALL_SUCCESS && wipe_cache) {
            if (erase_volume("/cache")) {
                LOGE("Cache wipe (requested by package) failed.");
            }
        }
        if (status != INSTALL_SUCCESS) {
            ui->Print("Installation aborted.\n");

            // If this is an eng or userdebug build, then automatically
            // turn the text display on if the script fails so the error
            // message is visible.
            char buffer[PROPERTY_VALUE_MAX+1];
            property_get("ro.build.fingerprint", buffer, "");
            if (strstr(buffer, ":userdebug/") || strstr(buffer, ":eng/")) {
                ui->ShowText(true);
            }
        }
    } else if (wipe_data) {
        if (device->WipeData()) status = INSTALL_ERROR;
        if (erase_volume("/data")) status = INSTALL_ERROR;
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui->Print("Data wipe failed.\n");
    } else if (wipe_cache) {
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n");
    } else if (!just_exit) {
        status = INSTALL_NONE;  // No command specified
        ui->SetBackground(RecoveryUI::NO_COMMAND);
    }

    if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) {
        copy_logs();
        ui->SetBackground(RecoveryUI::ERROR);
    }
    if (status != INSTALL_SUCCESS || ui->IsTextVisible()) {
        prompt_and_wait(device, status);
    }

    // Otherwise, get ready to boot the main system...
    finish_recovery(send_intent);
    if (shutdown_after) {
        ui->Print("Shutting down...\n");
        property_set(ANDROID_RB_PROPERTY, "shutdown,");
    } else {
        ui->Print("Rebooting...\n");
        property_set(ANDROID_RB_PROPERTY, "reboot,");
    }
    return EXIT_SUCCESS;
}
int main(int argc, char **argv)
{
	int opt;
	const char *filename = NULL;
	const char *directory = NULL;
	char *mountpoint = NULL;
	fs_config_func_t fs_config_func = NULL;
	int gzip = 0;
	int sparse = 0;
	int crc = 0;
	int wipe = 0;
	int fd;
	int exitcode;
	int verbose = 0;
	struct selabel_handle *sehnd = NULL;
#ifndef USE_MINGW
	struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "" } };
#endif

	while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:S:fwzJsctv")) != -1) {
		switch (opt) {
		case 'l':
			info.len = parse_num(optarg);
			break;
		case 'j':
			info.journal_blocks = parse_num(optarg);
			break;
		case 'b':
			info.block_size = parse_num(optarg);
			break;
		case 'g':
			info.blocks_per_group = parse_num(optarg);
			break;
		case 'i':
			info.inodes = parse_num(optarg);
			break;
		case 'I':
			info.inode_size = parse_num(optarg);
			break;
		case 'L':
			info.label = optarg;
			break;
		case 'f':
			force = 1;
			break;
		case 'a':
#ifdef ANDROID
			fs_config_func = fs_config;
			mountpoint = optarg;
#else
			fprintf(stderr, "can't set android permissions - built without android support\n");
			usage(argv[0]);
			exit(EXIT_FAILURE);
#endif
			break;
		case 'w':
			wipe = 1;
			break;
		case 'z':
			gzip = 1;
			break;
		case 'J':
			info.no_journal = 1;
			break;
		case 'c':
			crc = 1;
			break;
		case 's':
			sparse = 1;
			break;
		case 't':
			fprintf(stderr, "Warning: -t (initialize inode tables) is deprecated\n");
			break;
		case 'S':
#ifndef USE_MINGW
			seopts[0].value = optarg;
			sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
			if (!sehnd) {
				perror(optarg);
				exit(EXIT_FAILURE);
			}
#endif
			break;
		case 'v':
			verbose = 1;
			break;
		default: /* '?' */
			usage(argv[0]);
			exit(EXIT_FAILURE);
		}
	}

#if !defined(HOST)
	// Use only if -S option not requested
	if (!sehnd && mountpoint) {
		sehnd = selinux_android_file_context_handle();

		if (!sehnd) {
			perror(optarg);
			exit(EXIT_FAILURE);
		}
	}
#endif

	if (wipe && sparse) {
		fprintf(stderr, "Cannot specifiy both wipe and sparse\n");
		usage(argv[0]);
		exit(EXIT_FAILURE);
	}

	if (wipe && gzip) {
		fprintf(stderr, "Cannot specifiy both wipe and gzip\n");
		usage(argv[0]);
		exit(EXIT_FAILURE);
	}

	if (optind >= argc) {
		fprintf(stderr, "Expected filename after options\n");
		usage(argv[0]);
		exit(EXIT_FAILURE);
	}

	filename = argv[optind++];

	if (optind < argc)
		directory = argv[optind++];

	if (optind < argc) {
		fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
		usage(argv[0]);
		exit(EXIT_FAILURE);
	}

	if (strcmp(filename, "-")) {
		fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
		if (fd < 0) {
			perror("open");
			return EXIT_FAILURE;
		}
	} else {
		fd = STDOUT_FILENO;
	}

	exitcode = make_ext4fs_internal(fd, directory, mountpoint, fs_config_func, gzip,
			sparse, crc, wipe, sehnd, verbose);
	close(fd);
	if (exitcode && strcmp(filename, "-"))
		unlink(filename);
	return exitcode;
}