Loading tests/component/updater_test.cpp +0 −113 Original line number Original line Diff line number Diff line Loading @@ -161,119 +161,6 @@ TEST_F(UpdaterTest, file_getprop) { expect("", script6.c_str(), kNoCause); expect("", script6.c_str(), kNoCause); } } TEST_F(UpdaterTest, delete) { // Delete none. expect("0", "delete()", kNoCause); expect("0", "delete(\"/doesntexist\")", kNoCause); expect("0", "delete(\"/doesntexist1\", \"/doesntexist2\")", kNoCause); expect("0", "delete(\"/doesntexist1\", \"/doesntexist2\", \"/doesntexist3\")", kNoCause); // Delete one file. TemporaryFile temp_file1; ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file1.path)); std::string script1("delete(\"" + std::string(temp_file1.path) + "\")"); expect("1", script1.c_str(), kNoCause); // Delete two files. TemporaryFile temp_file2; ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file2.path)); TemporaryFile temp_file3; ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file3.path)); std::string script2("delete(\"" + std::string(temp_file2.path) + "\", \"" + std::string(temp_file3.path) + "\")"); expect("2", script2.c_str(), kNoCause); // Delete already deleted files. expect("0", script2.c_str(), kNoCause); // Delete one out of three. TemporaryFile temp_file4; ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file4.path)); std::string script3("delete(\"/doesntexist1\", \"" + std::string(temp_file4.path) + "\", \"/doesntexist2\")"); expect("1", script3.c_str(), kNoCause); } TEST_F(UpdaterTest, rename) { // rename() expects two arguments. expect(nullptr, "rename()", kArgsParsingFailure); expect(nullptr, "rename(\"arg1\")", kArgsParsingFailure); expect(nullptr, "rename(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure); // src_name or dst_name cannot be empty. expect(nullptr, "rename(\"\", \"arg2\")", kArgsParsingFailure); expect(nullptr, "rename(\"arg1\", \"\")", kArgsParsingFailure); // File doesn't exist (both of src and dst). expect(nullptr, "rename(\"/doesntexist\", \"/doesntexisteither\")" , kFileRenameFailure); // Can't create parent directory. TemporaryFile temp_file1; ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file1.path)); std::string script1("rename(\"" + std::string(temp_file1.path) + "\", \"/proc/0/file1\")"); expect(nullptr, script1.c_str(), kFileRenameFailure); // Rename. TemporaryFile temp_file2; std::string script2("rename(\"" + std::string(temp_file1.path) + "\", \"" + std::string(temp_file2.path) + "\")"); expect(temp_file2.path, script2.c_str(), kNoCause); // Already renamed. expect(temp_file2.path, script2.c_str(), kNoCause); // Parents create successfully. TemporaryFile temp_file3; TemporaryDir td; std::string temp_dir(td.path); std::string dst_file = temp_dir + "/aaa/bbb/a.txt"; std::string script3("rename(\"" + std::string(temp_file3.path) + "\", \"" + dst_file + "\")"); expect(dst_file.c_str(), script3.c_str(), kNoCause); // Clean up the temp files under td. ASSERT_EQ(0, unlink(dst_file.c_str())); ASSERT_EQ(0, rmdir((temp_dir + "/aaa/bbb").c_str())); ASSERT_EQ(0, rmdir((temp_dir + "/aaa").c_str())); } TEST_F(UpdaterTest, symlink) { // symlink expects 1+ argument. expect(nullptr, "symlink()", kArgsParsingFailure); // symlink should fail if src is an empty string. TemporaryFile temp_file1; std::string script1("symlink(\"" + std::string(temp_file1.path) + "\", \"\")"); expect(nullptr, script1.c_str(), kSymlinkFailure); std::string script2("symlink(\"" + std::string(temp_file1.path) + "\", \"src1\", \"\")"); expect(nullptr, script2.c_str(), kSymlinkFailure); // symlink failed to remove old src. std::string script3("symlink(\"" + std::string(temp_file1.path) + "\", \"/proc\")"); expect(nullptr, script3.c_str(), kSymlinkFailure); // symlink can create symlinks. TemporaryFile temp_file; std::string content = "magicvalue"; ASSERT_TRUE(android::base::WriteStringToFile(content, temp_file.path)); TemporaryDir td; std::string src1 = std::string(td.path) + "/symlink1"; std::string src2 = std::string(td.path) + "/symlink2"; std::string script4("symlink(\"" + std::string(temp_file.path) + "\", \"" + src1 + "\", \"" + src2 + "\")"); expect("t", script4.c_str(), kNoCause); // Verify the created symlinks. struct stat sb; ASSERT_TRUE(lstat(src1.c_str(), &sb) == 0 && S_ISLNK(sb.st_mode)); ASSERT_TRUE(lstat(src2.c_str(), &sb) == 0 && S_ISLNK(sb.st_mode)); // Clean up the leftovers. ASSERT_EQ(0, unlink(src1.c_str())); ASSERT_EQ(0, unlink(src2.c_str())); } TEST_F(UpdaterTest, package_extract_dir) { TEST_F(UpdaterTest, package_extract_dir) { // package_extract_dir expects 2 arguments. // package_extract_dir expects 2 arguments. expect(nullptr, "package_extract_dir()", kArgsParsingFailure); expect(nullptr, "package_extract_dir()", kArgsParsingFailure); Loading updater/install.cpp +0 −362 Original line number Original line Diff line number Diff line Loading @@ -332,68 +332,6 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { return nullptr; return nullptr; } } // rename(src_name, dst_name) // Renames src_name to dst_name. It automatically creates the necessary directories for dst_name. // Example: rename("system/app/Hangouts/Hangouts.apk", "system/priv-app/Hangouts/Hangouts.apk") Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 2) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); } std::vector<std::string> args; if (!ReadArgs(state, argc, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& src_name = args[0]; const std::string& dst_name = args[1]; if (src_name.empty()) { return ErrorAbort(state, kArgsParsingFailure, "src_name argument to %s() can't be empty", name); } if (dst_name.empty()) { return ErrorAbort(state, kArgsParsingFailure, "dst_name argument to %s() can't be empty", name); } if (!make_parents(dst_name)) { return ErrorAbort(state, kFileRenameFailure, "Creating parent of %s failed, error %s", dst_name.c_str(), strerror(errno)); } else if (access(dst_name.c_str(), F_OK) == 0 && access(src_name.c_str(), F_OK) != 0) { // File was already moved return StringValue(dst_name); } else if (rename(src_name.c_str(), dst_name.c_str()) != 0) { return ErrorAbort(state, kFileRenameFailure, "Rename of %s to %s failed, error %s", src_name.c_str(), dst_name.c_str(), strerror(errno)); } return StringValue(dst_name); } // delete([filename, ...]) // Deletes all the filenames listed. Returns the number of files successfully deleted. // // delete_recursive([dirname, ...]) // Recursively deletes dirnames and all their contents. Returns the number of directories // successfully deleted. Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { std::vector<std::string> paths(argc); for (int i = 0; i < argc; ++i) { if (!Evaluate(state, argv[i], &paths[i])) { return nullptr; } } bool recursive = (strcmp(name, "delete_recursive") == 0); int success = 0; for (int i = 0; i < argc; ++i) { if ((recursive ? dirUnlinkHierarchy(paths[i].c_str()) : unlink(paths[i].c_str())) == 0) { ++success; } } return StringValue(std::to_string(success)); } Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) { Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 2) { if (argc != 2) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); Loading Loading @@ -557,288 +495,6 @@ Value* PackageExtractFileFn(const char* name, State* state, int argc, Expr* argv } } } } // symlink(target, [src1, src2, ...]) // Creates all sources as symlinks to target. It 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, kArgsParsingFailure, "%s() expects 1+ args, got %d", name, argc); } std::string target; if (!Evaluate(state, argv[0], &target)) { return nullptr; } std::vector<std::string> srcs; if (!ReadArgs(state, argc - 1, argv + 1, &srcs)) { return ErrorAbort(state, kArgsParsingFailure, "%s(): Failed to parse the argument(s)", name); } size_t bad = 0; for (const auto& src : srcs) { if (unlink(src.c_str()) == -1 && errno != ENOENT) { PLOG(ERROR) << name << ": failed to remove " << src; ++bad; } else if (!make_parents(src)) { LOG(ERROR) << name << ": failed to symlink " << src << " to " << target << ": making parents failed"; ++bad; } else if (symlink(target.c_str(), src.c_str()) == -1) { PLOG(ERROR) << name << ": failed to symlink " << src << " to " << target; ++bad; } } if (bad != 0) { return ErrorAbort(state, kSymlinkFailure, "%s: Failed to create %zu symlink(s)", name, bad); } return StringValue("t"); } struct perm_parsed_args { bool has_uid; uid_t uid; bool has_gid; gid_t gid; bool has_mode; mode_t mode; bool has_fmode; mode_t fmode; bool has_dmode; mode_t dmode; bool has_selabel; const char* selabel; bool has_capabilities; uint64_t capabilities; }; static struct perm_parsed_args ParsePermArgs(State * state, int argc, const std::vector<std::string>& args) { struct perm_parsed_args parsed; int bad = 0; static int max_warnings = 20; memset(&parsed, 0, sizeof(parsed)); for (int i = 1; i < argc; i += 2) { if (args[i] == "uid") { int64_t uid; if (sscanf(args[i + 1].c_str(), "%" SCNd64, &uid) == 1) { parsed.uid = uid; parsed.has_uid = true; } else { uiPrintf(state, "ParsePermArgs: invalid UID \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (args[i] == "gid") { int64_t gid; if (sscanf(args[i + 1].c_str(), "%" SCNd64, &gid) == 1) { parsed.gid = gid; parsed.has_gid = true; } else { uiPrintf(state, "ParsePermArgs: invalid GID \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (args[i] == "mode") { int32_t mode; if (sscanf(args[i + 1].c_str(), "%" SCNi32, &mode) == 1) { parsed.mode = mode; parsed.has_mode = true; } else { uiPrintf(state, "ParsePermArgs: invalid mode \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (args[i] == "dmode") { int32_t mode; if (sscanf(args[i + 1].c_str(), "%" SCNi32, &mode) == 1) { parsed.dmode = mode; parsed.has_dmode = true; } else { uiPrintf(state, "ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (args[i] == "fmode") { int32_t mode; if (sscanf(args[i + 1].c_str(), "%" SCNi32, &mode) == 1) { parsed.fmode = mode; parsed.has_fmode = true; } else { uiPrintf(state, "ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (args[i] == "capabilities") { int64_t capabilities; if (sscanf(args[i + 1].c_str(), "%" SCNi64, &capabilities) == 1) { parsed.capabilities = capabilities; parsed.has_capabilities = true; } else { uiPrintf(state, "ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (args[i] == "selabel") { if (!args[i + 1].empty()) { parsed.selabel = args[i + 1].c_str(); parsed.has_selabel = true; } else { uiPrintf(state, "ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (max_warnings != 0) { printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i].c_str()); max_warnings--; if (max_warnings == 0) { LOG(INFO) << "ParsedPermArgs: suppressing further warnings"; } } } return parsed; } static int ApplyParsedPerms(State* state, const char* filename, const struct stat* statptr, struct perm_parsed_args parsed) { int bad = 0; if (parsed.has_selabel) { if (lsetfilecon(filename, parsed.selabel) != 0) { uiPrintf(state, "ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n", filename, parsed.selabel, strerror(errno)); bad++; } } /* ignore symlinks */ if (S_ISLNK(statptr->st_mode)) { return bad; } if (parsed.has_uid) { if (chown(filename, parsed.uid, -1) < 0) { uiPrintf(state, "ApplyParsedPerms: chown of %s to %d failed: %s\n", filename, parsed.uid, strerror(errno)); bad++; } } if (parsed.has_gid) { if (chown(filename, -1, parsed.gid) < 0) { uiPrintf(state, "ApplyParsedPerms: chgrp of %s to %d failed: %s\n", filename, parsed.gid, strerror(errno)); bad++; } } if (parsed.has_mode) { if (chmod(filename, parsed.mode) < 0) { uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", filename, parsed.mode, strerror(errno)); bad++; } } if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) { if (chmod(filename, parsed.dmode) < 0) { uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", filename, parsed.dmode, strerror(errno)); bad++; } } if (parsed.has_fmode && S_ISREG(statptr->st_mode)) { if (chmod(filename, parsed.fmode) < 0) { uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", filename, parsed.fmode, strerror(errno)); bad++; } } if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) { if (parsed.capabilities == 0) { if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) { // Report failure unless it's ENODATA (attribute not set) uiPrintf(state, "ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n", filename, parsed.capabilities, strerror(errno)); bad++; } } else { struct vfs_cap_data cap_data; memset(&cap_data, 0, sizeof(cap_data)); cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE; cap_data.data[0].permitted = (uint32_t)(parsed.capabilities & 0xffffffff); cap_data.data[0].inheritable = 0; cap_data.data[1].permitted = (uint32_t)(parsed.capabilities >> 32); cap_data.data[1].inheritable = 0; if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) { uiPrintf(state, "ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n", filename, parsed.capabilities, strerror(errno)); bad++; } } } return bad; } // nftw doesn't allow us to pass along context, so we need to use // global variables. *sigh* static struct perm_parsed_args recursive_parsed_args; static State* recursive_state; static int do_SetMetadataRecursive(const char* filename, const struct stat* statptr, int fileflags, struct FTW* pfwt) { return ApplyParsedPerms(recursive_state, filename, statptr, recursive_parsed_args); } static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) { if ((argc % 2) != 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects an odd number of arguments, got %d", name, argc); } std::vector<std::string> args; if (!ReadArgs(state, argc, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } struct stat sb; if (lstat(args[0].c_str(), &sb) == -1) { return ErrorAbort(state, kSetMetadataFailure, "%s: Error on lstat of \"%s\": %s", name, args[0].c_str(), strerror(errno)); } struct perm_parsed_args parsed = ParsePermArgs(state, argc, args); int bad = 0; bool recursive = (strcmp(name, "set_metadata_recursive") == 0); if (recursive) { recursive_parsed_args = parsed; recursive_state = state; bad += nftw(args[0].c_str(), do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS); memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args)); recursive_state = NULL; } else { bad += ApplyParsedPerms(state, args[0].c_str(), &sb, parsed); } if (bad > 0) { return ErrorAbort(state, kSetMetadataFailure, "%s: some changes failed", name); } return StringValue(""); } Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 1) { if (argc != 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); Loading Loading @@ -1356,25 +1012,8 @@ void RegisterInstallFunctions() { RegisterFunction("format", FormatFn); RegisterFunction("format", FormatFn); RegisterFunction("show_progress", ShowProgressFn); RegisterFunction("show_progress", ShowProgressFn); RegisterFunction("set_progress", SetProgressFn); RegisterFunction("set_progress", SetProgressFn); RegisterFunction("delete", DeleteFn); RegisterFunction("delete_recursive", DeleteFn); RegisterFunction("package_extract_dir", PackageExtractDirFn); RegisterFunction("package_extract_dir", PackageExtractDirFn); RegisterFunction("package_extract_file", PackageExtractFileFn); RegisterFunction("package_extract_file", PackageExtractFileFn); RegisterFunction("symlink", SymlinkFn); // Usage: // set_metadata("filename", "key1", "value1", "key2", "value2", ...) // Example: // set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", // "u:object_r:system_file:s0", "capabilities", 0x0); RegisterFunction("set_metadata", SetMetadataFn); // Usage: // set_metadata_recursive("dirname", "key1", "value1", "key2", "value2", ...) // Example: // set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, // "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); RegisterFunction("set_metadata_recursive", SetMetadataFn); RegisterFunction("getprop", GetPropFn); RegisterFunction("getprop", GetPropFn); RegisterFunction("file_getprop", FileGetPropFn); RegisterFunction("file_getprop", FileGetPropFn); Loading @@ -1387,7 +1026,6 @@ void RegisterInstallFunctions() { RegisterFunction("read_file", ReadFileFn); RegisterFunction("read_file", ReadFileFn); RegisterFunction("sha1_check", Sha1CheckFn); RegisterFunction("sha1_check", Sha1CheckFn); RegisterFunction("rename", RenameFn); RegisterFunction("write_value", WriteValueFn); RegisterFunction("write_value", WriteValueFn); RegisterFunction("wipe_cache", WipeCacheFn); RegisterFunction("wipe_cache", WipeCacheFn); Loading Loading
tests/component/updater_test.cpp +0 −113 Original line number Original line Diff line number Diff line Loading @@ -161,119 +161,6 @@ TEST_F(UpdaterTest, file_getprop) { expect("", script6.c_str(), kNoCause); expect("", script6.c_str(), kNoCause); } } TEST_F(UpdaterTest, delete) { // Delete none. expect("0", "delete()", kNoCause); expect("0", "delete(\"/doesntexist\")", kNoCause); expect("0", "delete(\"/doesntexist1\", \"/doesntexist2\")", kNoCause); expect("0", "delete(\"/doesntexist1\", \"/doesntexist2\", \"/doesntexist3\")", kNoCause); // Delete one file. TemporaryFile temp_file1; ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file1.path)); std::string script1("delete(\"" + std::string(temp_file1.path) + "\")"); expect("1", script1.c_str(), kNoCause); // Delete two files. TemporaryFile temp_file2; ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file2.path)); TemporaryFile temp_file3; ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file3.path)); std::string script2("delete(\"" + std::string(temp_file2.path) + "\", \"" + std::string(temp_file3.path) + "\")"); expect("2", script2.c_str(), kNoCause); // Delete already deleted files. expect("0", script2.c_str(), kNoCause); // Delete one out of three. TemporaryFile temp_file4; ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file4.path)); std::string script3("delete(\"/doesntexist1\", \"" + std::string(temp_file4.path) + "\", \"/doesntexist2\")"); expect("1", script3.c_str(), kNoCause); } TEST_F(UpdaterTest, rename) { // rename() expects two arguments. expect(nullptr, "rename()", kArgsParsingFailure); expect(nullptr, "rename(\"arg1\")", kArgsParsingFailure); expect(nullptr, "rename(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure); // src_name or dst_name cannot be empty. expect(nullptr, "rename(\"\", \"arg2\")", kArgsParsingFailure); expect(nullptr, "rename(\"arg1\", \"\")", kArgsParsingFailure); // File doesn't exist (both of src and dst). expect(nullptr, "rename(\"/doesntexist\", \"/doesntexisteither\")" , kFileRenameFailure); // Can't create parent directory. TemporaryFile temp_file1; ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file1.path)); std::string script1("rename(\"" + std::string(temp_file1.path) + "\", \"/proc/0/file1\")"); expect(nullptr, script1.c_str(), kFileRenameFailure); // Rename. TemporaryFile temp_file2; std::string script2("rename(\"" + std::string(temp_file1.path) + "\", \"" + std::string(temp_file2.path) + "\")"); expect(temp_file2.path, script2.c_str(), kNoCause); // Already renamed. expect(temp_file2.path, script2.c_str(), kNoCause); // Parents create successfully. TemporaryFile temp_file3; TemporaryDir td; std::string temp_dir(td.path); std::string dst_file = temp_dir + "/aaa/bbb/a.txt"; std::string script3("rename(\"" + std::string(temp_file3.path) + "\", \"" + dst_file + "\")"); expect(dst_file.c_str(), script3.c_str(), kNoCause); // Clean up the temp files under td. ASSERT_EQ(0, unlink(dst_file.c_str())); ASSERT_EQ(0, rmdir((temp_dir + "/aaa/bbb").c_str())); ASSERT_EQ(0, rmdir((temp_dir + "/aaa").c_str())); } TEST_F(UpdaterTest, symlink) { // symlink expects 1+ argument. expect(nullptr, "symlink()", kArgsParsingFailure); // symlink should fail if src is an empty string. TemporaryFile temp_file1; std::string script1("symlink(\"" + std::string(temp_file1.path) + "\", \"\")"); expect(nullptr, script1.c_str(), kSymlinkFailure); std::string script2("symlink(\"" + std::string(temp_file1.path) + "\", \"src1\", \"\")"); expect(nullptr, script2.c_str(), kSymlinkFailure); // symlink failed to remove old src. std::string script3("symlink(\"" + std::string(temp_file1.path) + "\", \"/proc\")"); expect(nullptr, script3.c_str(), kSymlinkFailure); // symlink can create symlinks. TemporaryFile temp_file; std::string content = "magicvalue"; ASSERT_TRUE(android::base::WriteStringToFile(content, temp_file.path)); TemporaryDir td; std::string src1 = std::string(td.path) + "/symlink1"; std::string src2 = std::string(td.path) + "/symlink2"; std::string script4("symlink(\"" + std::string(temp_file.path) + "\", \"" + src1 + "\", \"" + src2 + "\")"); expect("t", script4.c_str(), kNoCause); // Verify the created symlinks. struct stat sb; ASSERT_TRUE(lstat(src1.c_str(), &sb) == 0 && S_ISLNK(sb.st_mode)); ASSERT_TRUE(lstat(src2.c_str(), &sb) == 0 && S_ISLNK(sb.st_mode)); // Clean up the leftovers. ASSERT_EQ(0, unlink(src1.c_str())); ASSERT_EQ(0, unlink(src2.c_str())); } TEST_F(UpdaterTest, package_extract_dir) { TEST_F(UpdaterTest, package_extract_dir) { // package_extract_dir expects 2 arguments. // package_extract_dir expects 2 arguments. expect(nullptr, "package_extract_dir()", kArgsParsingFailure); expect(nullptr, "package_extract_dir()", kArgsParsingFailure); Loading
updater/install.cpp +0 −362 Original line number Original line Diff line number Diff line Loading @@ -332,68 +332,6 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { return nullptr; return nullptr; } } // rename(src_name, dst_name) // Renames src_name to dst_name. It automatically creates the necessary directories for dst_name. // Example: rename("system/app/Hangouts/Hangouts.apk", "system/priv-app/Hangouts/Hangouts.apk") Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 2) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); } std::vector<std::string> args; if (!ReadArgs(state, argc, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& src_name = args[0]; const std::string& dst_name = args[1]; if (src_name.empty()) { return ErrorAbort(state, kArgsParsingFailure, "src_name argument to %s() can't be empty", name); } if (dst_name.empty()) { return ErrorAbort(state, kArgsParsingFailure, "dst_name argument to %s() can't be empty", name); } if (!make_parents(dst_name)) { return ErrorAbort(state, kFileRenameFailure, "Creating parent of %s failed, error %s", dst_name.c_str(), strerror(errno)); } else if (access(dst_name.c_str(), F_OK) == 0 && access(src_name.c_str(), F_OK) != 0) { // File was already moved return StringValue(dst_name); } else if (rename(src_name.c_str(), dst_name.c_str()) != 0) { return ErrorAbort(state, kFileRenameFailure, "Rename of %s to %s failed, error %s", src_name.c_str(), dst_name.c_str(), strerror(errno)); } return StringValue(dst_name); } // delete([filename, ...]) // Deletes all the filenames listed. Returns the number of files successfully deleted. // // delete_recursive([dirname, ...]) // Recursively deletes dirnames and all their contents. Returns the number of directories // successfully deleted. Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { std::vector<std::string> paths(argc); for (int i = 0; i < argc; ++i) { if (!Evaluate(state, argv[i], &paths[i])) { return nullptr; } } bool recursive = (strcmp(name, "delete_recursive") == 0); int success = 0; for (int i = 0; i < argc; ++i) { if ((recursive ? dirUnlinkHierarchy(paths[i].c_str()) : unlink(paths[i].c_str())) == 0) { ++success; } } return StringValue(std::to_string(success)); } Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) { Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 2) { if (argc != 2) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); Loading Loading @@ -557,288 +495,6 @@ Value* PackageExtractFileFn(const char* name, State* state, int argc, Expr* argv } } } } // symlink(target, [src1, src2, ...]) // Creates all sources as symlinks to target. It 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, kArgsParsingFailure, "%s() expects 1+ args, got %d", name, argc); } std::string target; if (!Evaluate(state, argv[0], &target)) { return nullptr; } std::vector<std::string> srcs; if (!ReadArgs(state, argc - 1, argv + 1, &srcs)) { return ErrorAbort(state, kArgsParsingFailure, "%s(): Failed to parse the argument(s)", name); } size_t bad = 0; for (const auto& src : srcs) { if (unlink(src.c_str()) == -1 && errno != ENOENT) { PLOG(ERROR) << name << ": failed to remove " << src; ++bad; } else if (!make_parents(src)) { LOG(ERROR) << name << ": failed to symlink " << src << " to " << target << ": making parents failed"; ++bad; } else if (symlink(target.c_str(), src.c_str()) == -1) { PLOG(ERROR) << name << ": failed to symlink " << src << " to " << target; ++bad; } } if (bad != 0) { return ErrorAbort(state, kSymlinkFailure, "%s: Failed to create %zu symlink(s)", name, bad); } return StringValue("t"); } struct perm_parsed_args { bool has_uid; uid_t uid; bool has_gid; gid_t gid; bool has_mode; mode_t mode; bool has_fmode; mode_t fmode; bool has_dmode; mode_t dmode; bool has_selabel; const char* selabel; bool has_capabilities; uint64_t capabilities; }; static struct perm_parsed_args ParsePermArgs(State * state, int argc, const std::vector<std::string>& args) { struct perm_parsed_args parsed; int bad = 0; static int max_warnings = 20; memset(&parsed, 0, sizeof(parsed)); for (int i = 1; i < argc; i += 2) { if (args[i] == "uid") { int64_t uid; if (sscanf(args[i + 1].c_str(), "%" SCNd64, &uid) == 1) { parsed.uid = uid; parsed.has_uid = true; } else { uiPrintf(state, "ParsePermArgs: invalid UID \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (args[i] == "gid") { int64_t gid; if (sscanf(args[i + 1].c_str(), "%" SCNd64, &gid) == 1) { parsed.gid = gid; parsed.has_gid = true; } else { uiPrintf(state, "ParsePermArgs: invalid GID \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (args[i] == "mode") { int32_t mode; if (sscanf(args[i + 1].c_str(), "%" SCNi32, &mode) == 1) { parsed.mode = mode; parsed.has_mode = true; } else { uiPrintf(state, "ParsePermArgs: invalid mode \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (args[i] == "dmode") { int32_t mode; if (sscanf(args[i + 1].c_str(), "%" SCNi32, &mode) == 1) { parsed.dmode = mode; parsed.has_dmode = true; } else { uiPrintf(state, "ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (args[i] == "fmode") { int32_t mode; if (sscanf(args[i + 1].c_str(), "%" SCNi32, &mode) == 1) { parsed.fmode = mode; parsed.has_fmode = true; } else { uiPrintf(state, "ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (args[i] == "capabilities") { int64_t capabilities; if (sscanf(args[i + 1].c_str(), "%" SCNi64, &capabilities) == 1) { parsed.capabilities = capabilities; parsed.has_capabilities = true; } else { uiPrintf(state, "ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (args[i] == "selabel") { if (!args[i + 1].empty()) { parsed.selabel = args[i + 1].c_str(); parsed.has_selabel = true; } else { uiPrintf(state, "ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (max_warnings != 0) { printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i].c_str()); max_warnings--; if (max_warnings == 0) { LOG(INFO) << "ParsedPermArgs: suppressing further warnings"; } } } return parsed; } static int ApplyParsedPerms(State* state, const char* filename, const struct stat* statptr, struct perm_parsed_args parsed) { int bad = 0; if (parsed.has_selabel) { if (lsetfilecon(filename, parsed.selabel) != 0) { uiPrintf(state, "ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n", filename, parsed.selabel, strerror(errno)); bad++; } } /* ignore symlinks */ if (S_ISLNK(statptr->st_mode)) { return bad; } if (parsed.has_uid) { if (chown(filename, parsed.uid, -1) < 0) { uiPrintf(state, "ApplyParsedPerms: chown of %s to %d failed: %s\n", filename, parsed.uid, strerror(errno)); bad++; } } if (parsed.has_gid) { if (chown(filename, -1, parsed.gid) < 0) { uiPrintf(state, "ApplyParsedPerms: chgrp of %s to %d failed: %s\n", filename, parsed.gid, strerror(errno)); bad++; } } if (parsed.has_mode) { if (chmod(filename, parsed.mode) < 0) { uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", filename, parsed.mode, strerror(errno)); bad++; } } if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) { if (chmod(filename, parsed.dmode) < 0) { uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", filename, parsed.dmode, strerror(errno)); bad++; } } if (parsed.has_fmode && S_ISREG(statptr->st_mode)) { if (chmod(filename, parsed.fmode) < 0) { uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", filename, parsed.fmode, strerror(errno)); bad++; } } if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) { if (parsed.capabilities == 0) { if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) { // Report failure unless it's ENODATA (attribute not set) uiPrintf(state, "ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n", filename, parsed.capabilities, strerror(errno)); bad++; } } else { struct vfs_cap_data cap_data; memset(&cap_data, 0, sizeof(cap_data)); cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE; cap_data.data[0].permitted = (uint32_t)(parsed.capabilities & 0xffffffff); cap_data.data[0].inheritable = 0; cap_data.data[1].permitted = (uint32_t)(parsed.capabilities >> 32); cap_data.data[1].inheritable = 0; if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) { uiPrintf(state, "ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n", filename, parsed.capabilities, strerror(errno)); bad++; } } } return bad; } // nftw doesn't allow us to pass along context, so we need to use // global variables. *sigh* static struct perm_parsed_args recursive_parsed_args; static State* recursive_state; static int do_SetMetadataRecursive(const char* filename, const struct stat* statptr, int fileflags, struct FTW* pfwt) { return ApplyParsedPerms(recursive_state, filename, statptr, recursive_parsed_args); } static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) { if ((argc % 2) != 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects an odd number of arguments, got %d", name, argc); } std::vector<std::string> args; if (!ReadArgs(state, argc, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } struct stat sb; if (lstat(args[0].c_str(), &sb) == -1) { return ErrorAbort(state, kSetMetadataFailure, "%s: Error on lstat of \"%s\": %s", name, args[0].c_str(), strerror(errno)); } struct perm_parsed_args parsed = ParsePermArgs(state, argc, args); int bad = 0; bool recursive = (strcmp(name, "set_metadata_recursive") == 0); if (recursive) { recursive_parsed_args = parsed; recursive_state = state; bad += nftw(args[0].c_str(), do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS); memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args)); recursive_state = NULL; } else { bad += ApplyParsedPerms(state, args[0].c_str(), &sb, parsed); } if (bad > 0) { return ErrorAbort(state, kSetMetadataFailure, "%s: some changes failed", name); } return StringValue(""); } Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 1) { if (argc != 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); Loading Loading @@ -1356,25 +1012,8 @@ void RegisterInstallFunctions() { RegisterFunction("format", FormatFn); RegisterFunction("format", FormatFn); RegisterFunction("show_progress", ShowProgressFn); RegisterFunction("show_progress", ShowProgressFn); RegisterFunction("set_progress", SetProgressFn); RegisterFunction("set_progress", SetProgressFn); RegisterFunction("delete", DeleteFn); RegisterFunction("delete_recursive", DeleteFn); RegisterFunction("package_extract_dir", PackageExtractDirFn); RegisterFunction("package_extract_dir", PackageExtractDirFn); RegisterFunction("package_extract_file", PackageExtractFileFn); RegisterFunction("package_extract_file", PackageExtractFileFn); RegisterFunction("symlink", SymlinkFn); // Usage: // set_metadata("filename", "key1", "value1", "key2", "value2", ...) // Example: // set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", // "u:object_r:system_file:s0", "capabilities", 0x0); RegisterFunction("set_metadata", SetMetadataFn); // Usage: // set_metadata_recursive("dirname", "key1", "value1", "key2", "value2", ...) // Example: // set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, // "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); RegisterFunction("set_metadata_recursive", SetMetadataFn); RegisterFunction("getprop", GetPropFn); RegisterFunction("getprop", GetPropFn); RegisterFunction("file_getprop", FileGetPropFn); RegisterFunction("file_getprop", FileGetPropFn); Loading @@ -1387,7 +1026,6 @@ void RegisterInstallFunctions() { RegisterFunction("read_file", ReadFileFn); RegisterFunction("read_file", ReadFileFn); RegisterFunction("sha1_check", Sha1CheckFn); RegisterFunction("sha1_check", Sha1CheckFn); RegisterFunction("rename", RenameFn); RegisterFunction("write_value", WriteValueFn); RegisterFunction("write_value", WriteValueFn); RegisterFunction("wipe_cache", WipeCacheFn); RegisterFunction("wipe_cache", WipeCacheFn); Loading