/* verify_trustzone("TZ_VERSION", "TZ_VERSION", ...) */
Value * VerifyTrustZoneFn(const char *name, State *state, int argc, Expr *argv[]) {
    char current_tz_version[TZ_VER_BUF_LEN];
    int i, ret;

    ret = get_tz_version(current_tz_version, TZ_VER_BUF_LEN);
    if (ret) {
        return ErrorAbort(state, "%s() failed to read current TZ version: %d",
                          name, ret);
    }

    char** tz_version = ReadVarArgs(state, argc, argv);
    if (tz_version == NULL) {
        return ErrorAbort(state, "%s() error parsing arguments", name);
    }

    ret = 0;
    for (i = 0; i < argc; i++) {
        uiPrintf(state, "Comparing TZ version %s to %s",
                 tz_version[i], current_tz_version);
        if (strncmp(tz_version[i], current_tz_version, strlen(tz_version[i])) == 0) {
            ret = 1;
            break;
        }
    }

    for (i = 0; i < argc; i++) {
        free(tz_version[i]);
    }
    free(tz_version);

    return StringValue(strdup(ret ? "1" : "0"));
}
Value* UpdateFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc != 1) {
        return ErrorAbort(state, "%s() expects 6 args, got %d", name, argc);
    }

    char* type = strrchr(name, '_');
    if (type == NULL || *(type+1) == '\0') {
        return ErrorAbort(state, "%s() couldn't get type from function name",
                          name);
    }
    ++type;

    Value* image;

    if (ReadValueArgs(state, argv, 1, &image) <0) {
        return NULL;
    }

    if (image->type != VAL_BLOB) {
        printf("image argument is not blob (is type %d)\n", image->type);
        goto done;
    }

    install_firmware_update(type, image->data, image->size, "/tmp/recovery.log");
    printf("%s: install_firmware_update returned!\n", name);

  done:
    FreeValue(image);
    // install_firmware_update should reboot.  If it returns, it failed.
    return StringValue(strdup(""));
}
Value* WriteBootloaderFn(const char* name, State* state, int argc, Expr* argv[])
{
    int result = -1;
    Value* img;
    Value* xloader_loc;
    Value* sbl_loc;

    if (argc != 3) {
        return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
    }

    if (ReadValueArgs(state, argv, 3, &img, &xloader_loc, &sbl_loc) < 0) {
        return NULL;
    }

    if(img->type != VAL_BLOB ||
       xloader_loc->type != VAL_STRING ||
       sbl_loc->type != VAL_STRING) {
      FreeValue(img);
      FreeValue(xloader_loc);
      FreeValue(sbl_loc);
      return ErrorAbort(state, "%s(): argument types are incorrect", name);
    }

    result = update_bootloader(img->data, img->size,
                               xloader_loc->data, sbl_loc->data);
    FreeValue(img);
    FreeValue(xloader_loc);
    FreeValue(sbl_loc);
    return StringValue(strdup(result == 0 ? "t" : ""));
}
// Read a local file and return its contents (the Value* returned
// is actually a FileContents*).
Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc != 1) {
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    }
    char* filename;
    if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;

    Value* v = malloc(sizeof(Value));
    v->type = VAL_BLOB;

    FileContents fc;
    if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) {
        ErrorAbort(state, "%s() loading \"%s\" failed: %s",
                   name, filename, strerror(errno));
        free(filename);
        free(v);
        free(fc.data);
        return NULL;
    }

    v->size = fc.size;
    v->data = (char*)fc.data;

    free(filename);
    return v;
}
Value *CommandFunction(int (*fun) (int, char **), const char *name, State * state, int argc, Expr * argv[])
{
	Value *ret = NULL;
	char *argv_str[argc + 1];
	int i;

	char **argv_read = ReadVarArgs(state, argc, argv);
	if (argv_read == NULL) {
		ErrorAbort(state, "%s parameter parsing failed.", name);
		goto done;
	}

	argv_str[0] = (char *)name;
	for (i = 0; i < argc; i++)
		argv_str[i + 1] = argv_read[i];

	if (fun(sizeof(argv_str) / sizeof(char *), argv_str) != EXIT_SUCCESS) {
		ErrorAbort(state, "%s failed.", name);
		goto done;
	}

	for (i = 0; i < argc; i++)
		free(argv_read[i]);
	free(argv_read);

	ret = StringValue(strdup("t"));

done:
	return ret;
}
Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
    char* result = NULL;
    if (argc != 1) {
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    }
    char* mount_point;
    if (ReadArgs(state, argv, 1, &mount_point) < 0) {
        return NULL;
    }
    if (strlen(mount_point) == 0) {
        ErrorAbort(state, "mount_point argument to unmount() can't be empty");
        goto done;
    }

    scan_mounted_volumes();
    const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
    if (vol == NULL) {
        fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
        result = strdup("");
    } else {
        unmount_mounted_volume(vol);
        result = mount_point;
    }

done:
    if (result != mount_point) free(mount_point);
    return StringValue(result);
}
Value *ExecuteOsipFunction(const char *name, State * state, int argc, Expr * argv[], int (*action) (char *))
{
	Value *ret = NULL;
	char *destination = NULL;

	if (ReadArgs(state, argv, 1, &destination) < 0) {
		return NULL;
	}

	if (destination == NULL || strlen(destination) == 0) {
		ErrorAbort(state, "destination argument to %s can't be empty", name);
		goto done;
	}

	if (action(destination) == -1) {
		ErrorAbort(state, "Error writing %s to OSIP", destination);
		goto done;
	}

	ret = StringValue(strdup("t"));

done:
	if (destination)
		free(destination);

	return ret;
}
示例#8
0
char* UnloadWifiFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc != 0)
        return ErrorAbort(state, "%s() expects 0 arg, got %d", name, argc);

    if (wifi_unload_driver() != 0) {
        return ErrorAbort(state, "Unable to unload wifi-driver: %s", strerror(errno));
    }
    return strdup("t");
}
示例#9
0
// write_raw_image(file, partition)
Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
    char* result = NULL;

    char* partition;
    char* filename;
    if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
        return NULL;
    }

    if (strlen(partition) == 0) {
        ErrorAbort(state, "partition argument to %s can't be empty", name);
        goto done;
    }
    if (strlen(filename) == 0) {
        ErrorAbort(state, "file argument to %s can't be empty", name);
        goto done;
    }

    mtd_scan_partitions();
    const MtdPartition* mtd = mtd_find_partition_by_name(partition);
    if (mtd == NULL) {
        fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition);
        result = strdup("");
        goto done;
    }

    char mtddevname[32]="";
    sprintf(mtddevname, "/dev/mtd/mtd%d", mtd_get_partition_index((MtdPartition*)mtd));

    bool success;

    FILE* f = fopen(filename, "rb");
    if (f == NULL) {
        fprintf(stderr, "%s: can't open %s: %s\n",
                name, filename, strerror(errno));
        result = strdup("");
        goto done;
    }

    success = !write_recovery(filename, partition);

    printf("%s %s partition from %s\n",
           success ? "wrote" : "failed to write", partition, filename);

    result = success ? partition : strdup("");

done:
    if (result != partition) free(partition);
    free(filename);
    return StringValue(result);
}
示例#10
0
Value* RangeSha1Fn(const char* name, State* state, int argc, Expr* argv[]) {
    Value* blockdev_filename;
    Value* ranges;
    const uint8_t* digest = NULL;
    if (ReadValueArgs(state, argv, 2, &blockdev_filename, &ranges) < 0) {
        return NULL;
    }

    if (blockdev_filename->type != VAL_STRING) {
        ErrorAbort(state, "blockdev_filename argument to %s must be string", name);
        goto done;
    }
    if (ranges->type != VAL_STRING) {
        ErrorAbort(state, "ranges argument to %s must be string", name);
        goto done;
    }

    int fd = open(blockdev_filename->data, O_RDWR);
    if (fd < 0) {
        ErrorAbort(state, "failed to open %s: %s", blockdev_filename->data, strerror(errno));
        goto done;
    }

    RangeSet* rs = parse_range(ranges->data);
    uint8_t buffer[BLOCKSIZE];

    SHA_CTX ctx;
    SHA_init(&ctx);

    int i, j;
    for (i = 0; i < rs->count; ++i) {
        check_lseek(fd, (off64_t)rs->pos[i*2] * BLOCKSIZE, SEEK_SET);
        for (j = rs->pos[i*2]; j < rs->pos[i*2+1]; ++j) {
            readblock(fd, buffer, BLOCKSIZE);
            SHA_update(&ctx, buffer, BLOCKSIZE);
        }
    }
    digest = SHA_final(&ctx);
    close(fd);

  done:
    FreeValue(blockdev_filename);
    FreeValue(ranges);
    if (digest == NULL) {
        return StringValue(strdup(""));
    } else {
        return StringValue(PrintSha1(digest));
    }
}
示例#11
0
char* UnloadWifiFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc != 0)
        return ErrorAbort(state, "%s() expects 0 arg, got %d", name, argc);

 void *h = dlopen("/system/lib/libhardware_legacy.so",RTLD_LAZY);
 int (*wifi_unload_driver)() = dlsym(h,"wifi_unload_driver");

  if (wifi_unload_driver) {
    if (wifi_unload_driver() != 0) {
      return ErrorAbort(state, "Unable to unload wifi-driver: %s", strerror(errno));
    }
    return strdup("t");
  }
  return ErrorAbort(state, "libhardware_legacy is not available.");
}
示例#12
0
Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc != 0) {
        return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
    }
    fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "wipe_cache\n");
    return StringValue(strdup("t"));
}
示例#13
0
char* WriteFileFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc != 2)
        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
    char *filename;
    char *line;
    int retval;
    if (ReadArgs(state, argv, 2, &filename, &line) < 0)
        return NULL;

    FILE *fd;
    if (! (fd = fopen(filename, "w")) ) {
      fprintf(stderr, "Can't open %s for write \n", filename);
      free(filename);
      free(line);
      return strdup("");
    }
    if (fwrite(line, strlen(line), 1, fd) == 1) {
      fclose(fd);
      free(filename);
      free(line);
      return strdup("t");
    } else {
      fclose(fd);
      free(filename);
      free(line);
      return strdup("");
    }
}
示例#14
0
char* ModuleLoadedFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc != 1)
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    char *module_name;
    int retval;
    if (ReadArgs(state, argv, 1, &module_name) < 0)
        return NULL;

    int module_found = -1;
    FILE *modules;
    char buffer[READ_BUF_SIZE];
    char mname[READ_BUF_SIZE];

    if (! (modules = fopen("/proc/modules", "r")) ) {
      fprintf(stderr, "Can't open /proc/modules for read \n");
      return strdup("");
    }

    while(fgets(buffer, sizeof(buffer), modules)) {
      /* process the line */
        sscanf(buffer, "%s %*s", mname);
        if ((strstr(mname, module_name)) != NULL) {
          module_found = 0;
        }
    }
    fclose(modules);
    free(module_name);
    return (module_found == 0 ? strdup("t") : strdup(""));
}
示例#15
0
// package_extract_dir(package_path, destination_path)
Value *
PackageExtractDirFn (const char *name, State * state, int argc, Expr * argv[])
{
  if (argc != 2)
	  {
	    return ErrorAbort (state, "%s() expects 2 args, got %d", name,
			       argc);
	  }
  char *zip_path;
  char *dest_path;

  if (ReadArgs (state, argv, 2, &zip_path, &dest_path) < 0)
    return NULL;

  ZipArchive *za = ((UpdaterInfo *) (state->cookie))->package_zip;

  // To create a consistent system image, never use the clock for timestamps.
  struct utimbuf timestamp = { 1217592000, 1217592000 };	// 8/1/2008 default

  bool success = mzExtractRecursive (za, zip_path, dest_path,
				     MZ_EXTRACT_FILES_ONLY, &timestamp,
				     NULL, NULL);

  free (zip_path);
  free (dest_path);
  return StringValue (strdup (success ? "t" : ""));
}
示例#16
0
char* WhiteListMacsFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc != 1)
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    char *filename;
    int retval;
    int returncode = 0;
    if (ReadArgs(state, argv, 1, &filename) < 0)
        return NULL;
    if (file_exists(filename) == 0) {
    FILE *macs;
    char buffer[20];
    char command[100];
    if (! (macs = fopen(filename, "r")) ) {
      fprintf(stderr, "Can't open %s for read \n", filename);
      free(filename);
      return strdup("");
    }
    while(fgets(buffer, sizeof(buffer), macs) && returncode == 0) {
        /* process the line */
      sscanf(buffer, "%s", buffer);
      sprintf(command,"/data/data/za.co.csir.walkiemesh/bin/iptables -t nat -I PREROUTING -m mac --mac-source %s -j ACCEPT", buffer);
      //fprintf(stdout, "Enabling whitelist for: %s \n", command);
      returncode = system(command);
    }
    fclose(macs);
  }
  free(filename);
  return (returncode == 0 ? strdup("t") : strdup(""));
}
示例#17
0
// log("some message");
// log("t", "some message");
char* LogFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc != 1 && argc != 2) {
        return ErrorAbort(state, "%s() expects 1 or 2 args", name);
    }
    char *status;
    char *message;
    time_t time_now;
    time(&time_now);

    if (argc == 1) {
      if (ReadArgs(state, argv, 1, &message) < 0)
        return NULL;
      status = strdup("t");
    } else {
      if (ReadArgs(state, argv, 2, &status, &message) < 0)
        return NULL;
    }
    if (strcmp(status,"t") == 0) {
      fprintf(((UpdaterInfo*)(state->cookie))->log_fd,
        "<div class=\"date\">%s</div><div class=\"action\">%s...</div><div class=\"output\"></div><div class=\"done\">done</div><hr>",asctime(localtime(&time_now)),message);
    }
    else {
      property_set("tether.status","failed");
      fprintf(((UpdaterInfo*)(state->cookie))->log_fd,
        "<div class=\"date\">%s</div><div class=\"action\">%s...</div><div class=\"output\"></div><div class=\"failed\">failed</div><hr>",asctime(localtime(&time_now)),message);
    }
    return strdup("");
}
示例#18
0
// symlink target src1 src2 ...
//    unlinks any previously existing src1, src2, etc before creating symlinks.
Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc == 0) {
        return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
    }
    char* target;
    target = Evaluate(state, argv[0]);
    if (target == NULL) return NULL;

    char** srcs = ReadVarArgs(state, argc-1, argv+1);
    if (srcs == NULL) {
        free(target);
        return NULL;
    }

    int i;
    for (i = 0; i < argc-1; ++i) {
        if (unlink(srcs[i]) < 0) {
            if (errno != ENOENT) {
                fprintf(stderr, "%s: failed to remove %s: %s\n",
                        name, srcs[i], strerror(errno));
            }
        }
        if (symlink(target, srcs[i]) < 0) {
            fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
                    name, srcs[i], target, strerror(errno));
        }
        free(srcs[i]);
    }
    free(srcs);
    return StringValue(strdup(""));
}
示例#19
0
char* InsModuleFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc != 2)
        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
    char *module_name;
    char *options;
    if (ReadArgs(state, argv, 2, &module_name, &options) < 0) {
      return NULL;
    }

    ssize_t len;
    void *image;
    int rc;

    if (!options)
      options = "";

    len = INT_MAX - 4095;
    errno = ENOMEM;
    image = read_file(module_name, &len);

    if (!image)
      return  strdup("");

    errno = 0;
    init_module(image, len, options);
    rc = errno;
    free(image);
    free(module_name);
    return (rc == 0 ? strdup("t") : strdup(""));
}
示例#20
0
Value *
ShowProgressFn (const char *name, State * state, int argc, Expr * argv[])
{
  if (argc != 2)
	  {
	    return ErrorAbort (state, "%s() expects 2 args, got %d", name,
			       argc);
	  }
  char *frac_str;
  char *sec_str;

  if (ReadArgs (state, argv, 2, &frac_str, &sec_str) < 0)
	  {
	    return NULL;
	  }

  double frac = strtod (frac_str, NULL);
  int sec = strtol (sec_str, NULL, 10);

  UpdaterInfo *ui = (UpdaterInfo *) (state->cookie);

  fprintf (ui->cmd_pipe, "progress %f %d\n", frac, sec);

  free (sec_str);
  return StringValue (frac_str);
}
Value* DownloadModemFn(const char* name, State* state, int argc, Expr* argv[]) {

    char* modemImg;
    int result = -1;

    if (argc != 1)
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);

    if (ReadArgs(state, argv, 1, &modemImg) != 0) {
        return NULL;
    }

    printf("DownloadModemFn: %s\n", modemImg);

    result = DownloadFiles(modemImg);

    if (result < 0) {
        printf("Download failed!\n");
    } else {
        printf("Download success!\n");
        ResetModem();
        sleep(6);
    }
    return StringValue(strdup(result >= 0 ? "t" : ""));
}
示例#22
0
// apply_patch_check(file, [sha1_1, ...])
Value* ApplyPatchCheckFn(const char* name, State* state,
                         int argc, Expr* argv[]) {
    if (argc < 1) {
        return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
                          name, argc);
    }

    char* filename;
    if (ReadArgs(state, argv, 1, &filename) < 0) {
        return NULL;
    }

    int patchcount = argc-1;
    char** sha1s = ReadVarArgs(state, argc-1, argv+1);

    int result = applypatch_check(filename, patchcount, sha1s);

    int i;
    for (i = 0; i < patchcount; ++i) {
        free(sha1s[i]);
    }
    free(sha1s);

    return StringValue(strdup(result == 0 ? "t" : ""));
}
Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
    char* result = NULL;
    if (argc != 1) {
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    }
    
    char *path;
    if (ReadArgs(state, argv, 1, &path) < 0) {
        return NULL;
    }
    
    ui_print("Formatting %s...\n", path);
    if (0 != format_volume(path)) {
        free(path);
        return StringValue(strdup(""));
    }
    
    if (strcmp(path, "/data") == 0 && has_datadata()) {
        ui_print("Formatting /datadata...\n", path);
        if (0 != format_volume("/datadata")) {
            free(path);
            return StringValue(strdup(""));
        }
        if (0 != format_volume(get_android_secure_path())) {
            free(path);
            return StringValue(strdup(""));
        }
    }

done:
    return StringValue(strdup(path));
}
Value *FlashOSImage(const char *name, State * state, int argc, Expr * argv[])
{
	char* result = NULL;

	Value *funret = NULL;
	char *image_type;
	int ret;

	Value* partition_value;
	Value* contents;
	if (ReadValueArgs(state, argv, 2, &contents, &partition_value) < 0) {
		return NULL;
	}

	char* partition = NULL;
	if (partition_value->type != VAL_STRING) {
		ErrorAbort(state, "partition argument to %s must be string", name);
		goto exit;
	}

	partition = partition_value->data;
	if (strlen(partition) == 0) {
		ErrorAbort(state, "partition argument to %s can't be empty", name);
		goto exit;
	}

	if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) {
		ErrorAbort(state, "file argument to %s can't be empty", name);
		goto exit;
	}

	image_type = basename(partition);

	ret = flash_image(contents->data, contents->size, image_type);
	if (ret != 0) {
		ErrorAbort(state, "%s: Failed to flash image %s, %s.",
			   name, image_type, strerror(errno));
		goto free;
	}

	funret = StringValue(strdup("t"));

free:
	free(image_type);
exit:
	return funret;
}
Value *ExtractImageFn(const char *name, State * state, int argc, Expr * argv[])
{
	Value *ret = NULL;
	char *filename = NULL;
	char *source = NULL;
	void *data = NULL;
	int size;

	if (ReadArgs(state, argv, 2, &filename, &source) < 0) {
		return NULL;
	}

	if (filename == NULL || strlen(filename) == 0) {
		ErrorAbort(state, "filename argument to %s can't be empty", name);
		goto done;
	}

	if (source == NULL || strlen(source) == 0) {
		ErrorAbort(state, "source argument to %s can't be empty", name);
		goto done;
	}

	if ((size = read_image(source, &data)) < 0) {
		ErrorAbort(state, "Couldn't read image %s", source);
		goto done;
	}

	if (file_write(filename, data, size) < 0) {
		ErrorAbort(state, "Couldn't write %s data to %s", source, filename);
		goto done;
	}

	ret = StringValue(strdup("t"));
done:
	if (source)
		free(source);
	if (filename)
		free(filename);
	if (data)
		free(data);

	return ret;
}
char* Evaluate(State* state, Expr* expr) {
    Value* v = expr->fn(expr->name, state, expr->argc, expr->argv);
    if (v == NULL) return NULL;
    if (v->type != VAL_STRING) {
        ErrorAbort(state, "expecting string, got value type %d", v->type);
        FreeValue(v);
        return NULL;
    }
    char* result = v->data;
    free(v);
    return result;
}
示例#27
0
char* RmModuleFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc != 1)
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    char *module_name;
    int retval;
    if (ReadArgs(state, argv, 1, &module_name) < 0)
        return NULL;

    retval = delete_module(module_name, O_NONBLOCK | O_EXCL);
    free(module_name);
    return (retval  == 0? strdup("t") : strdup(""));
}
示例#28
0
char* KillProcessByPIDFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc != 1)
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
    char *pidfile;
    int retval;
    if (ReadArgs(state, argv, 1, &pidfile) < 0)
        return NULL;

    kill_processes_by_pidfile(2, pidfile);
    kill_processes_by_pidfile(9, pidfile);
    return strdup("t");
}
Value* RestoreFn(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc < 1) {
        return ErrorAbort(state, "%s() expects at least 1 arg", name);
    }
    char** args = ReadVarArgs(state, argc, argv);
    if (args == NULL) {
        return NULL;
    }

    char** args2 = malloc(sizeof(char*) * (argc+1));
    memcpy(args2, args, sizeof(char*) * argc);
    args2[argc] = NULL;
    
    char* path = strdup(args2[0]);
    int restoreboot = 1;
    int restoresystem = 1;
    int restoredata = 1;
    int restorecache = 1;
    int restoresdext = 1;
    int restorewebtop = 1;
    int i;
    for (i = 1; i < argc; i++)
    {
        if (args2[i] == NULL)
            continue;
        if (strcmp(args2[i], "noboot") == 0)
            restoreboot = 0;
        else if (strcmp(args2[i], "nosystem") == 0)
            restoresystem = 0;
        else if (strcmp(args2[i], "nodata") == 0)
            restoredata = 0;
        else if (strcmp(args2[i], "nocache") == 0)
            restorecache = 0;
        else if (strcmp(args2[i], "nosd-ext") == 0)
            restoresdext = 0;
        else if (strcmp(args2[i], "nowebtop") == 0)
            restorewebtop = 0;
    }
    
    for (i = 0; i < argc; ++i) {
        free(args[i]);
    }
    free(args);
    free(args2);

    if (0 != nandroid_restore(path, restoreboot, restoresystem, restoredata, restorecache, restoresdext, 0, restorewebtop, 0)) {
        free(path);
        return StringValue(strdup(""));
    }
    
    return StringValue(path);
}
Value* SetRadioFn(const char* name, State* state, int argc, Expr* argv[]) {
    char *part_type;

    if (argc != 1) {
        return ErrorAbort(state, "%s() expects arg, got %d", name, argc);
    }

    char* type = strrchr(name, '_');
    if (type == NULL || *(type+1) == '\0') {
        return ErrorAbort(state, "%s() couldn't get type from function name",
                          name);
    }
    ++type;

    if (ReadArgs(state, argv, 1, &part_type) <0) {
        return NULL;
    }

    start_firmware_update(type,part_type);

    return StringValue(strdup(""));
}