1cc290419Sopenharmony_ci/* 2cc290419Sopenharmony_ci * Copyright (C) 2021 Huawei Device Co., Ltd. 3cc290419Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4cc290419Sopenharmony_ci * you may not use this file except in compliance with the License. 5cc290419Sopenharmony_ci * You may obtain a copy of the License at 6cc290419Sopenharmony_ci * 7cc290419Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8cc290419Sopenharmony_ci * 9cc290419Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10cc290419Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11cc290419Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12cc290419Sopenharmony_ci * See the License for the specific language governing permissions and 13cc290419Sopenharmony_ci * limitations under the License. 14cc290419Sopenharmony_ci */ 15cc290419Sopenharmony_ci#include "daemon_app.h" 16cc290419Sopenharmony_ci#include "decompress.h" 17cc290419Sopenharmony_ci 18cc290419Sopenharmony_cinamespace Hdc { 19cc290419Sopenharmony_ciHdcDaemonApp::HdcDaemonApp(HTaskInfo hTaskInfo) 20cc290419Sopenharmony_ci : HdcTransferBase(hTaskInfo) 21cc290419Sopenharmony_ci{ 22cc290419Sopenharmony_ci commandBegin = CMD_APP_BEGIN; 23cc290419Sopenharmony_ci commandData = CMD_APP_DATA; 24cc290419Sopenharmony_ci funcAppModFinish = nullptr; 25cc290419Sopenharmony_ci} 26cc290419Sopenharmony_ci 27cc290419Sopenharmony_ciHdcDaemonApp::~HdcDaemonApp() 28cc290419Sopenharmony_ci{ 29cc290419Sopenharmony_ci WRITE_LOG(LOG_INFO, "~HdcDaemonApp channelId:%u", taskInfo->channelId); 30cc290419Sopenharmony_ci} 31cc290419Sopenharmony_ci 32cc290419Sopenharmony_cibool HdcDaemonApp::ReadyForRelease() 33cc290419Sopenharmony_ci{ 34cc290419Sopenharmony_ci if (!HdcTaskBase::ReadyForRelease()) { 35cc290419Sopenharmony_ci WRITE_LOG(LOG_WARN, "HdcTaskBase not ready for release channelId:%u", taskInfo->channelId); 36cc290419Sopenharmony_ci return false; 37cc290419Sopenharmony_ci } 38cc290419Sopenharmony_ci if (!asyncCommand.ReadyForRelease()) { 39cc290419Sopenharmony_ci WRITE_LOG(LOG_WARN, "asyncCommand not ready for release channelId:%u", taskInfo->channelId); 40cc290419Sopenharmony_ci return false; 41cc290419Sopenharmony_ci } 42cc290419Sopenharmony_ci WRITE_LOG(LOG_INFO, "ReadyForRelease channelId:%u", taskInfo->channelId); 43cc290419Sopenharmony_ci return true; 44cc290419Sopenharmony_ci} 45cc290419Sopenharmony_ci 46cc290419Sopenharmony_civoid HdcDaemonApp::MakeCtxForAppCheck(uint8_t *payload, const int payloadSize) 47cc290419Sopenharmony_ci{ 48cc290419Sopenharmony_ci string dstPath = "/data/local/tmp/"; 49cc290419Sopenharmony_ci string bufString(reinterpret_cast<char *>(payload), payloadSize); 50cc290419Sopenharmony_ci SerialStruct::ParseFromString(ctxNow.transferConfig, bufString); 51cc290419Sopenharmony_ci // update transferconfig to main context 52cc290419Sopenharmony_ci ctxNow.master = false; 53cc290419Sopenharmony_ci#ifdef HDC_PCDEBUG 54cc290419Sopenharmony_ci char tmpPath[256] = ""; 55cc290419Sopenharmony_ci size_t size = 256; 56cc290419Sopenharmony_ci uv_os_tmpdir(tmpPath, &size); 57cc290419Sopenharmony_ci dstPath = tmpPath; 58cc290419Sopenharmony_ci dstPath += Base::GetPathSep(); 59cc290419Sopenharmony_ci#endif 60cc290419Sopenharmony_ci dstPath += ctxNow.transferConfig.optionalName; 61cc290419Sopenharmony_ci ctxNow.localPath = dstPath; 62cc290419Sopenharmony_ci ctxNow.transferBegin = Base::GetRuntimeMSec(); 63cc290419Sopenharmony_ci ctxNow.fileSize = ctxNow.transferConfig.fileSize; 64cc290419Sopenharmony_ci return; 65cc290419Sopenharmony_ci} 66cc290419Sopenharmony_ci 67cc290419Sopenharmony_cibool HdcDaemonApp::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize) 68cc290419Sopenharmony_ci{ 69cc290419Sopenharmony_ci if (!HdcTransferBase::CommandDispatch(command, payload, payloadSize)) { 70cc290419Sopenharmony_ci WRITE_LOG(LOG_WARN, "HdcTransferBase::CommandDispatch false command:%u channelId:%u", 71cc290419Sopenharmony_ci command, taskInfo->channelId); 72cc290419Sopenharmony_ci return false; 73cc290419Sopenharmony_ci } 74cc290419Sopenharmony_ci bool ret = true; 75cc290419Sopenharmony_ci switch (command) { 76cc290419Sopenharmony_ci case CMD_APP_CHECK: { 77cc290419Sopenharmony_ci uv_fs_t *openReq = new uv_fs_t; 78cc290419Sopenharmony_ci if (openReq == nullptr) { 79cc290419Sopenharmony_ci WRITE_LOG(LOG_FATAL, "HdcDaemonApp::CommandDispatch new uv_fs_t failed"); 80cc290419Sopenharmony_ci return false; 81cc290419Sopenharmony_ci } 82cc290419Sopenharmony_ci memset_s(openReq, sizeof(uv_fs_t), 0, sizeof(uv_fs_t)); 83cc290419Sopenharmony_ci MakeCtxForAppCheck(payload, payloadSize); 84cc290419Sopenharmony_ci openReq->data = &ctxNow; 85cc290419Sopenharmony_ci ++refCount; 86cc290419Sopenharmony_ci uv_fs_open(loopTask, openReq, ctxNow.localPath.c_str(), 87cc290419Sopenharmony_ci UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, 88cc290419Sopenharmony_ci OnFileOpen); 89cc290419Sopenharmony_ci break; 90cc290419Sopenharmony_ci } 91cc290419Sopenharmony_ci case CMD_APP_UNINSTALL: { 92cc290419Sopenharmony_ci // This maybe has a command implanting risk, since it is a controllable device, it can be ignored 93cc290419Sopenharmony_ci string bufString(reinterpret_cast<char *>(payload), payloadSize); 94cc290419Sopenharmony_ci string options = ""; 95cc290419Sopenharmony_ci string packages = ""; 96cc290419Sopenharmony_ci vector<string> segments; 97cc290419Sopenharmony_ci Base::SplitString(bufString, " ", segments); 98cc290419Sopenharmony_ci for (auto seg: segments) { 99cc290419Sopenharmony_ci if (seg[0] == '-') { 100cc290419Sopenharmony_ci options += " " + seg; 101cc290419Sopenharmony_ci } else { 102cc290419Sopenharmony_ci packages += " " + seg; 103cc290419Sopenharmony_ci } 104cc290419Sopenharmony_ci } 105cc290419Sopenharmony_ci PackageShell(false, options.c_str(), packages); 106cc290419Sopenharmony_ci break; 107cc290419Sopenharmony_ci } 108cc290419Sopenharmony_ci default: 109cc290419Sopenharmony_ci break; 110cc290419Sopenharmony_ci } 111cc290419Sopenharmony_ci return ret; 112cc290419Sopenharmony_ci}; 113cc290419Sopenharmony_ci 114cc290419Sopenharmony_cibool HdcDaemonApp::AsyncInstallFinish(bool finish, int64_t exitStatus, const string result) 115cc290419Sopenharmony_ci{ 116cc290419Sopenharmony_ci if (mode == APPMOD_INSTALL) { 117cc290419Sopenharmony_ci unlink(ctxNow.localPath.c_str()); 118cc290419Sopenharmony_ci string::size_type rindex = ctxNow.localPath.rfind(".tar"); 119cc290419Sopenharmony_ci if (rindex != string::npos) { 120cc290419Sopenharmony_ci string dir = ctxNow.localPath.substr(0, rindex); 121cc290419Sopenharmony_ci RemovePath(dir); 122cc290419Sopenharmony_ci WRITE_LOG(LOG_DEBUG, "RemovePath dir:%s", dir.c_str()); 123cc290419Sopenharmony_ci } 124cc290419Sopenharmony_ci } 125cc290419Sopenharmony_ci asyncCommand.DoRelease(); 126cc290419Sopenharmony_ci string echo = result; 127cc290419Sopenharmony_ci echo = Base::ReplaceAll(echo, "\n", " "); 128cc290419Sopenharmony_ci vector<uint8_t> vecBuf; 129cc290419Sopenharmony_ci vecBuf.push_back(mode); 130cc290419Sopenharmony_ci vecBuf.push_back(exitStatus == 0); 131cc290419Sopenharmony_ci vecBuf.insert(vecBuf.end(), (uint8_t *)echo.c_str(), (uint8_t *)echo.c_str() + echo.size()); 132cc290419Sopenharmony_ci SendToAnother(CMD_APP_FINISH, vecBuf.data(), vecBuf.size()); 133cc290419Sopenharmony_ci --refCount; 134cc290419Sopenharmony_ci#ifdef UNIT_TEST 135cc290419Sopenharmony_ci Base::WriteBinFile((UT_TMP_PATH + "/appinstall.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(), 136cc290419Sopenharmony_ci MESSAGE_SUCCESS.size(), true); 137cc290419Sopenharmony_ci#endif 138cc290419Sopenharmony_ci return true; 139cc290419Sopenharmony_ci} 140cc290419Sopenharmony_ci 141cc290419Sopenharmony_civoid HdcDaemonApp::PackageShell(bool installOrUninstall, const char *options, const string package) 142cc290419Sopenharmony_ci{ 143cc290419Sopenharmony_ci ++refCount; 144cc290419Sopenharmony_ci // asynccmd Other processes, no RunningProtect protection 145cc290419Sopenharmony_ci chmod(package.c_str(), 0755); 146cc290419Sopenharmony_ci string doBuf; 147cc290419Sopenharmony_ci string opts = string(options); 148cc290419Sopenharmony_ci if (installOrUninstall) { // either -p or -s is always required in install 149cc290419Sopenharmony_ci if (opts.find("p") == string::npos && opts.find("s") == string::npos) { 150cc290419Sopenharmony_ci // basic mode: blank options or both "-s" / "-p" are omitted 151cc290419Sopenharmony_ci // eg. hdc install x.hap --> bm install -p x.hap 152cc290419Sopenharmony_ci // eg. hdc install -r x.hap --> bm install -r -p x.hap 153cc290419Sopenharmony_ci doBuf = Base::StringFormat("bm install %s -p %s", options, package.c_str()); 154cc290419Sopenharmony_ci } else { 155cc290419Sopenharmony_ci // advansed mode for -p/-r/-s and some other options in the future 156cc290419Sopenharmony_ci doBuf = Base::StringFormat("bm install %s %s", options, package.c_str()); 157cc290419Sopenharmony_ci } 158cc290419Sopenharmony_ci } else { // -n is always required in uninstall 159cc290419Sopenharmony_ci if (opts.find("n") == string::npos) { 160cc290419Sopenharmony_ci // basic mode: blank options or "-n" is omitted 161cc290419Sopenharmony_ci // eg. hdc uninstall com.xx.xx --> bm uninstall -n com.xx.xx 162cc290419Sopenharmony_ci // eg. hdc uninstall -s com.xx.xx --> bm uninstall -s -n com.xx.xx 163cc290419Sopenharmony_ci doBuf = Base::StringFormat("bm uninstall %s -n %s", options, package.c_str()); 164cc290419Sopenharmony_ci } else { 165cc290419Sopenharmony_ci // advansed mode for -s/-n and some other options in the future 166cc290419Sopenharmony_ci doBuf = Base::StringFormat("bm uninstall %s %s", options, package.c_str()); 167cc290419Sopenharmony_ci } 168cc290419Sopenharmony_ci } 169cc290419Sopenharmony_ci 170cc290419Sopenharmony_ci funcAppModFinish = [this](bool finish, int64_t exitStatus, const string result) -> bool { 171cc290419Sopenharmony_ci return this->AsyncInstallFinish(finish, exitStatus, result); 172cc290419Sopenharmony_ci }; 173cc290419Sopenharmony_ci if (installOrUninstall) { 174cc290419Sopenharmony_ci mode = APPMOD_INSTALL; 175cc290419Sopenharmony_ci } else { 176cc290419Sopenharmony_ci mode = APPMOD_UNINSTALL; 177cc290419Sopenharmony_ci } 178cc290419Sopenharmony_ci asyncCommand.Initial(loopTask, funcAppModFinish, AsyncCmd::OPTION_COMMAND_ONETIME); 179cc290419Sopenharmony_ci asyncCommand.ExecuteCommand(doBuf); 180cc290419Sopenharmony_ci} 181cc290419Sopenharmony_ci 182cc290419Sopenharmony_civoid HdcDaemonApp::Sideload(const char *pathOTA) 183cc290419Sopenharmony_ci{ 184cc290419Sopenharmony_ci mode = APPMOD_SIDELOAD; 185cc290419Sopenharmony_ci LogMsg(MSG_OK, "[placeholders] sideload %s", pathOTA); 186cc290419Sopenharmony_ci TaskFinish(); 187cc290419Sopenharmony_ci unlink(pathOTA); 188cc290419Sopenharmony_ci} 189cc290419Sopenharmony_ci 190cc290419Sopenharmony_cistring HdcDaemonApp::Tar2Dir(const char *path) 191cc290419Sopenharmony_ci{ 192cc290419Sopenharmony_ci string dir; 193cc290419Sopenharmony_ci string tarpath = path; 194cc290419Sopenharmony_ci string::size_type rindex = tarpath.rfind(".tar"); 195cc290419Sopenharmony_ci if (rindex != string::npos) { 196cc290419Sopenharmony_ci dir = tarpath.substr(0, rindex) + Base::GetPathSep(); 197cc290419Sopenharmony_ci WRITE_LOG(LOG_DEBUG, "path:%s dir:%s", path, dir.c_str()); 198cc290419Sopenharmony_ci Decompress dc(tarpath); 199cc290419Sopenharmony_ci dc.DecompressToLocal(dir); 200cc290419Sopenharmony_ci } 201cc290419Sopenharmony_ci return dir; 202cc290419Sopenharmony_ci} 203cc290419Sopenharmony_ci 204cc290419Sopenharmony_ciint HdcDaemonApp::RemoveDir(const string &dir) 205cc290419Sopenharmony_ci{ 206cc290419Sopenharmony_ci DIR *pdir = opendir(dir.c_str()); 207cc290419Sopenharmony_ci if (pdir == nullptr) { 208cc290419Sopenharmony_ci WRITE_LOG(LOG_FATAL, "opendir failed dir:%s", dir.c_str()); 209cc290419Sopenharmony_ci return -1; 210cc290419Sopenharmony_ci } 211cc290419Sopenharmony_ci struct dirent *ent; 212cc290419Sopenharmony_ci struct stat st; 213cc290419Sopenharmony_ci while ((ent = readdir(pdir)) != nullptr) { 214cc290419Sopenharmony_ci if (ent->d_name[0] == '.') { 215cc290419Sopenharmony_ci continue; 216cc290419Sopenharmony_ci } 217cc290419Sopenharmony_ci std::string subpath = dir + Base::GetPathSep() + ent->d_name; 218cc290419Sopenharmony_ci if (lstat(subpath.c_str(), &st) == -1) { 219cc290419Sopenharmony_ci WRITE_LOG(LOG_WARN, "lstat failed subpath:%s", subpath.c_str()); 220cc290419Sopenharmony_ci continue; 221cc290419Sopenharmony_ci } 222cc290419Sopenharmony_ci if (S_ISDIR(st.st_mode)) { 223cc290419Sopenharmony_ci if (RemoveDir(subpath) == -1) { 224cc290419Sopenharmony_ci closedir(pdir); 225cc290419Sopenharmony_ci return -1; 226cc290419Sopenharmony_ci } 227cc290419Sopenharmony_ci rmdir(subpath.c_str()); 228cc290419Sopenharmony_ci } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { 229cc290419Sopenharmony_ci unlink(subpath.c_str()); 230cc290419Sopenharmony_ci } else { 231cc290419Sopenharmony_ci WRITE_LOG(LOG_DEBUG, "lstat st_mode:%07o subpath:%s", st.st_mode, subpath.c_str()); 232cc290419Sopenharmony_ci } 233cc290419Sopenharmony_ci } 234cc290419Sopenharmony_ci if (rmdir(dir.c_str()) == -1) { 235cc290419Sopenharmony_ci closedir(pdir); 236cc290419Sopenharmony_ci return -1; 237cc290419Sopenharmony_ci } 238cc290419Sopenharmony_ci closedir(pdir); 239cc290419Sopenharmony_ci return 0; 240cc290419Sopenharmony_ci} 241cc290419Sopenharmony_ci 242cc290419Sopenharmony_civoid HdcDaemonApp::RemovePath(const string &path) 243cc290419Sopenharmony_ci{ 244cc290419Sopenharmony_ci struct stat st; 245cc290419Sopenharmony_ci if (lstat(path.c_str(), &st) == -1) { 246cc290419Sopenharmony_ci WRITE_LOG(LOG_WARN, "lstat failed path:%s", path.c_str()); 247cc290419Sopenharmony_ci return; 248cc290419Sopenharmony_ci } 249cc290419Sopenharmony_ci if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { 250cc290419Sopenharmony_ci unlink(path.c_str()); 251cc290419Sopenharmony_ci } else if (S_ISDIR(st.st_mode)) { 252cc290419Sopenharmony_ci if (path == "." || path == "..") { 253cc290419Sopenharmony_ci return; 254cc290419Sopenharmony_ci } 255cc290419Sopenharmony_ci int rc = RemoveDir(path); 256cc290419Sopenharmony_ci WRITE_LOG(LOG_INFO, "RemoveDir rc:%d path:%s", rc, path.c_str()); 257cc290419Sopenharmony_ci } 258cc290419Sopenharmony_ci} 259cc290419Sopenharmony_ci 260cc290419Sopenharmony_civoid HdcDaemonApp::WhenTransferFinish(CtxFile *context) 261cc290419Sopenharmony_ci{ 262cc290419Sopenharmony_ci if (context->lastErrno > 0) { 263cc290419Sopenharmony_ci constexpr int bufSize = 1024; 264cc290419Sopenharmony_ci char buf[bufSize] = { 0 }; 265cc290419Sopenharmony_ci uv_strerror_r(static_cast<int>(-context->lastErrno), buf, bufSize); 266cc290419Sopenharmony_ci WRITE_LOG(LOG_DEBUG, "HdcDaemonApp WhenTransferFinish with errno:%d", context->lastErrno); 267cc290419Sopenharmony_ci LogMsg(MSG_FAIL, "Transfer App at:%lld/%lld(Bytes), Reason: %s", 268cc290419Sopenharmony_ci context->indexIO, context->fileSize, buf); 269cc290419Sopenharmony_ci return; 270cc290419Sopenharmony_ci } 271cc290419Sopenharmony_ci if (ctxNow.transferConfig.functionName == CMDSTR_APP_SIDELOAD) { 272cc290419Sopenharmony_ci Sideload(context->localPath.c_str()); 273cc290419Sopenharmony_ci } else if (ctxNow.transferConfig.functionName == CMDSTR_APP_INSTALL) { 274cc290419Sopenharmony_ci string dir = Tar2Dir(context->localPath.c_str()); 275cc290419Sopenharmony_ci if (!dir.empty()) { 276cc290419Sopenharmony_ci PackageShell(true, context->transferConfig.options.c_str(), dir.c_str()); 277cc290419Sopenharmony_ci } else { 278cc290419Sopenharmony_ci PackageShell(true, context->transferConfig.options.c_str(), context->localPath.c_str()); 279cc290419Sopenharmony_ci } 280cc290419Sopenharmony_ci } else { 281cc290419Sopenharmony_ci } 282cc290419Sopenharmony_ci}; 283cc290419Sopenharmony_ci} 284