1cc290419Sopenharmony_ci/* 2cc290419Sopenharmony_ci * Copyright (C) 2024 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 16cc290419Sopenharmony_ci#include <termios.h> 17cc290419Sopenharmony_ci#include <cstring> 18cc290419Sopenharmony_ci#include <unistd.h> 19cc290419Sopenharmony_ci#include <climits> 20cc290419Sopenharmony_ci#include <sys/types.h> 21cc290419Sopenharmony_ci#include <sys/wait.h> 22cc290419Sopenharmony_ci#include <sys/stat.h> 23cc290419Sopenharmony_ci#include <securec.h> 24cc290419Sopenharmony_ci 25cc290419Sopenharmony_ci#if defined(SURPPORT_SELINUX) 26cc290419Sopenharmony_ci#include "selinux/selinux.h" 27cc290419Sopenharmony_ci#endif 28cc290419Sopenharmony_ci#include "account_iam_client.h" 29cc290419Sopenharmony_ci#include "os_account_manager.h" 30cc290419Sopenharmony_ci#include "sudo_iam.h" 31cc290419Sopenharmony_ci 32cc290419Sopenharmony_ci#define PWD_BUF_LEN 128 33cc290419Sopenharmony_ci#define DEFAULT_PATH "/system/bin" 34cc290419Sopenharmony_ci#define DEFAULT_BASH "/system/bin/sh" 35cc290419Sopenharmony_ci 36cc290419Sopenharmony_ciusing namespace OHOS::UserIam; 37cc290419Sopenharmony_ciusing namespace OHOS::AccountSA; 38cc290419Sopenharmony_ci 39cc290419Sopenharmony_cistatic FILE *g_ttyFp = nullptr; 40cc290419Sopenharmony_ci 41cc290419Sopenharmony_cistatic const char *OUT_OF_MEM = "[E0001] out of memory\n"; 42cc290419Sopenharmony_cistatic const char *COMMAND_NOT_FOUND = "[E0002] command not found\n"; 43cc290419Sopenharmony_cistatic const char *USER_VERIFY_FAILED = "[E0003] Sorry, try again. If screen lock password not set, set it first.\n"; 44cc290419Sopenharmony_ci 45cc290419Sopenharmony_cistatic void WriteStdErr(const char *str) 46cc290419Sopenharmony_ci{ 47cc290419Sopenharmony_ci (void)fwrite(str, 1, strlen(str), stderr); 48cc290419Sopenharmony_ci fflush(stderr); 49cc290419Sopenharmony_ci} 50cc290419Sopenharmony_ci 51cc290419Sopenharmony_cistatic void WriteTty(const char *str) 52cc290419Sopenharmony_ci{ 53cc290419Sopenharmony_ci if (g_ttyFp != nullptr) { 54cc290419Sopenharmony_ci (void)fwrite(str, 1, strlen(str), g_ttyFp); 55cc290419Sopenharmony_ci fflush(g_ttyFp); 56cc290419Sopenharmony_ci } else { 57cc290419Sopenharmony_ci g_ttyFp = fopen("/dev/tty", "w"); 58cc290419Sopenharmony_ci if (g_ttyFp != nullptr) { 59cc290419Sopenharmony_ci (void)fwrite(str, 1, strlen(str), g_ttyFp); 60cc290419Sopenharmony_ci fflush(g_ttyFp); 61cc290419Sopenharmony_ci return; 62cc290419Sopenharmony_ci } 63cc290419Sopenharmony_ci WriteStdErr("open /dev/tty for write failed\n"); 64cc290419Sopenharmony_ci } 65cc290419Sopenharmony_ci} 66cc290419Sopenharmony_ci 67cc290419Sopenharmony_cistatic void CloseTty(void) 68cc290419Sopenharmony_ci{ 69cc290419Sopenharmony_ci if (g_ttyFp != nullptr) { 70cc290419Sopenharmony_ci fclose(g_ttyFp); 71cc290419Sopenharmony_ci } 72cc290419Sopenharmony_ci g_ttyFp = nullptr; 73cc290419Sopenharmony_ci} 74cc290419Sopenharmony_ci 75cc290419Sopenharmony_cistatic char *StrDup(const char *str) 76cc290419Sopenharmony_ci{ 77cc290419Sopenharmony_ci int ret; 78cc290419Sopenharmony_ci char *result = new(std::nothrow)char[strlen(str) + 1]; 79cc290419Sopenharmony_ci if (result == nullptr) { 80cc290419Sopenharmony_ci WriteStdErr(OUT_OF_MEM); 81cc290419Sopenharmony_ci exit(1); 82cc290419Sopenharmony_ci } 83cc290419Sopenharmony_ci ret = strcpy_s(result, strlen(str) + 1, str); 84cc290419Sopenharmony_ci if (ret != 0) { 85cc290419Sopenharmony_ci WriteStdErr(OUT_OF_MEM); 86cc290419Sopenharmony_ci exit(1); 87cc290419Sopenharmony_ci } 88cc290419Sopenharmony_ci return result; 89cc290419Sopenharmony_ci} 90cc290419Sopenharmony_ci 91cc290419Sopenharmony_cistatic void FreeArgvNew(char **argvNew) 92cc290419Sopenharmony_ci{ 93cc290419Sopenharmony_ci char **p = nullptr; 94cc290419Sopenharmony_ci for (p = argvNew; *p != nullptr; p++) { 95cc290419Sopenharmony_ci delete [] *p; 96cc290419Sopenharmony_ci } 97cc290419Sopenharmony_ci delete [] argvNew; 98cc290419Sopenharmony_ci} 99cc290419Sopenharmony_ci 100cc290419Sopenharmony_ci/* 101cc290419Sopenharmony_ci * Find cmd from PATH 102cc290419Sopenharmony_ci*/ 103cc290419Sopenharmony_cistatic bool GetCmdInPath(char *cmd, int cmdBufLen, char *envp[]) 104cc290419Sopenharmony_ci{ 105cc290419Sopenharmony_ci struct stat st; 106cc290419Sopenharmony_ci char *path = nullptr; 107cc290419Sopenharmony_ci char *pathBak = nullptr; 108cc290419Sopenharmony_ci char **ep = nullptr; 109cc290419Sopenharmony_ci char *cp = nullptr; 110cc290419Sopenharmony_ci char pathBuf[PATH_MAX + 1] = {0}; 111cc290419Sopenharmony_ci bool findSuccess = false; 112cc290419Sopenharmony_ci 113cc290419Sopenharmony_ci if (strchr(cmd, '/') != nullptr) { 114cc290419Sopenharmony_ci return true; 115cc290419Sopenharmony_ci } 116cc290419Sopenharmony_ci 117cc290419Sopenharmony_ci for (ep = envp; *ep != nullptr; ep++) { 118cc290419Sopenharmony_ci if (strcmp(*ep, "PATH=") == 0) { 119cc290419Sopenharmony_ci path = *ep + strlen("PATH="); 120cc290419Sopenharmony_ci break; 121cc290419Sopenharmony_ci } 122cc290419Sopenharmony_ci } 123cc290419Sopenharmony_ci 124cc290419Sopenharmony_ci path = StrDup((path != nullptr && *path != '\0') ? path : DEFAULT_PATH); 125cc290419Sopenharmony_ci pathBak = path; 126cc290419Sopenharmony_ci do { 127cc290419Sopenharmony_ci if ((cp = strchr(path, ':')) != nullptr) { 128cc290419Sopenharmony_ci *cp = '\0'; 129cc290419Sopenharmony_ci } 130cc290419Sopenharmony_ci int ret = sprintf_s(pathBuf, sizeof(pathBuf), "%s/%s", *path ? path : ".", cmd); 131cc290419Sopenharmony_ci if (ret > 0 && stat(pathBuf, &st) == 0 && S_ISREG(st.st_mode)) { 132cc290419Sopenharmony_ci findSuccess = true; 133cc290419Sopenharmony_ci break; 134cc290419Sopenharmony_ci } 135cc290419Sopenharmony_ci path = cp + 1; 136cc290419Sopenharmony_ci } while (cp != nullptr); 137cc290419Sopenharmony_ci 138cc290419Sopenharmony_ci free(pathBak); 139cc290419Sopenharmony_ci if (!findSuccess) { 140cc290419Sopenharmony_ci WriteTty(COMMAND_NOT_FOUND); 141cc290419Sopenharmony_ci return false; 142cc290419Sopenharmony_ci } 143cc290419Sopenharmony_ci return (sprintf_s(cmd, cmdBufLen, "%s", pathBuf) < 0) ? false : true; 144cc290419Sopenharmony_ci} 145cc290419Sopenharmony_ci 146cc290419Sopenharmony_cistatic char **ParseCmd(int argc, char* argv[], char* env[], char *cmd, int cmdLen) 147cc290419Sopenharmony_ci{ 148cc290419Sopenharmony_ci int startCopyArgvIndex = 1; 149cc290419Sopenharmony_ci int argvNewIndex = 0; 150cc290419Sopenharmony_ci char **argvTmp = nullptr; 151cc290419Sopenharmony_ci bool isShc = false; 152cc290419Sopenharmony_ci int ret; 153cc290419Sopenharmony_ci 154cc290419Sopenharmony_ci /* 155cc290419Sopenharmony_ci * Here, we construct the command and its argv 156cc290419Sopenharmony_ci * sudo sh -c xxx yyy -----> sh -c xxx yyy 157cc290419Sopenharmony_ci * sudo xxx yyy -----> xxx yyy 158cc290419Sopenharmony_ci */ 159cc290419Sopenharmony_ci if (argc <= 0) { 160cc290419Sopenharmony_ci return nullptr; 161cc290419Sopenharmony_ci } 162cc290419Sopenharmony_ci argvTmp = new(std::nothrow) char* [argc]; 163cc290419Sopenharmony_ci if (argvTmp == nullptr) { 164cc290419Sopenharmony_ci WriteStdErr(OUT_OF_MEM); 165cc290419Sopenharmony_ci return nullptr; 166cc290419Sopenharmony_ci } 167cc290419Sopenharmony_ci (void)memset_s(argvTmp, sizeof(char*) * argc, 0, sizeof(char*) * argc); 168cc290419Sopenharmony_ci /* 169cc290419Sopenharmony_ci * sudo sh -c xxxx 170cc290419Sopenharmony_ci */ 171cc290419Sopenharmony_ci if (argc >= 3) { //3:argc of main 172cc290419Sopenharmony_ci if (strcmp(argv[1], "sh") == 0 && strcmp(argv[2], "-c") == 0) { //2:argv 2 of main 173cc290419Sopenharmony_ci // argvNew[0] is "/system/bin/sh" 174cc290419Sopenharmony_ci argvTmp[argvNewIndex++] = StrDup(DEFAULT_BASH); 175cc290419Sopenharmony_ci // argvNew[1] is "-c" 176cc290419Sopenharmony_ci argvTmp[argvNewIndex++] = StrDup("-c"); 177cc290419Sopenharmony_ci ret = sprintf_s(cmd, cmdLen, "%s", DEFAULT_BASH); 178cc290419Sopenharmony_ci if (ret < 0) { 179cc290419Sopenharmony_ci FreeArgvNew(argvTmp); 180cc290419Sopenharmony_ci return nullptr; 181cc290419Sopenharmony_ci } 182cc290419Sopenharmony_ci startCopyArgvIndex = 3; //3:start copy index of argv 183cc290419Sopenharmony_ci isShc = true; 184cc290419Sopenharmony_ci } 185cc290419Sopenharmony_ci } 186cc290419Sopenharmony_ci 187cc290419Sopenharmony_ci /* 188cc290419Sopenharmony_ci * if not "sudo sh -c xxxx", just as "sudo xxxx" 189cc290419Sopenharmony_ci */ 190cc290419Sopenharmony_ci if (!isShc) { 191cc290419Sopenharmony_ci ret = sprintf_s(cmd, cmdLen, "%s", argv[1]); 192cc290419Sopenharmony_ci if (ret < 0 || !GetCmdInPath(cmd, cmdLen, env)) { 193cc290419Sopenharmony_ci FreeArgvNew(argvTmp); 194cc290419Sopenharmony_ci return nullptr; 195cc290419Sopenharmony_ci } 196cc290419Sopenharmony_ci argvTmp[argvNewIndex++] = StrDup(cmd); 197cc290419Sopenharmony_ci startCopyArgvIndex = 2; //2:start copy index of argv 198cc290419Sopenharmony_ci } 199cc290419Sopenharmony_ci 200cc290419Sopenharmony_ci for (int i = startCopyArgvIndex; i < argc; i++) { 201cc290419Sopenharmony_ci argvTmp[argvNewIndex++] = StrDup(argv[i]); 202cc290419Sopenharmony_ci } 203cc290419Sopenharmony_ci argvTmp[argvNewIndex] = nullptr; 204cc290419Sopenharmony_ci 205cc290419Sopenharmony_ci return argvTmp; 206cc290419Sopenharmony_ci} 207cc290419Sopenharmony_ci 208cc290419Sopenharmony_cistatic void GetUserPwd(char *pwdBuf, int bufLen) 209cc290419Sopenharmony_ci{ 210cc290419Sopenharmony_ci const char *prompts = "[sudo] password for current user:"; 211cc290419Sopenharmony_ci const char *newline = "\n"; 212cc290419Sopenharmony_ci struct termios oldTerm; 213cc290419Sopenharmony_ci struct termios newTerm; 214cc290419Sopenharmony_ci 215cc290419Sopenharmony_ci WriteTty(prompts); 216cc290419Sopenharmony_ci 217cc290419Sopenharmony_ci tcgetattr(STDIN_FILENO, &oldTerm); 218cc290419Sopenharmony_ci newTerm = oldTerm; 219cc290419Sopenharmony_ci newTerm.c_lflag &= ~(ECHO); 220cc290419Sopenharmony_ci tcsetattr(STDIN_FILENO, TCSANOW, &newTerm); 221cc290419Sopenharmony_ci (void)fgets(pwdBuf, bufLen, stdin); 222cc290419Sopenharmony_ci if (pwdBuf[strlen(pwdBuf) - 1] == '\n') { 223cc290419Sopenharmony_ci pwdBuf[strlen(pwdBuf) - 1] = '\0'; 224cc290419Sopenharmony_ci } 225cc290419Sopenharmony_ci tcsetattr(STDIN_FILENO, TCSANOW, &oldTerm); 226cc290419Sopenharmony_ci 227cc290419Sopenharmony_ci WriteTty(newline); 228cc290419Sopenharmony_ci} 229cc290419Sopenharmony_ci 230cc290419Sopenharmony_cistatic bool SetUidGid(void) 231cc290419Sopenharmony_ci{ 232cc290419Sopenharmony_ci if (setuid(0) != 0) { 233cc290419Sopenharmony_ci return false; 234cc290419Sopenharmony_ci } 235cc290419Sopenharmony_ci if (setegid(0) != 0) { 236cc290419Sopenharmony_ci return false; 237cc290419Sopenharmony_ci } 238cc290419Sopenharmony_ci if (setgid(0) != 0) { 239cc290419Sopenharmony_ci return false; 240cc290419Sopenharmony_ci } 241cc290419Sopenharmony_ci return true; 242cc290419Sopenharmony_ci} 243cc290419Sopenharmony_ci 244cc290419Sopenharmony_cistatic void WaitForAuth(void) 245cc290419Sopenharmony_ci{ 246cc290419Sopenharmony_ci std::unique_lock<std::mutex> lock(g_mutexForAuth); 247cc290419Sopenharmony_ci g_condVarForAuth.wait(lock, [] { return g_authFinish; }); 248cc290419Sopenharmony_ci} 249cc290419Sopenharmony_ci 250cc290419Sopenharmony_cistatic bool VerifyAccount(int32_t userId) 251cc290419Sopenharmony_ci{ 252cc290419Sopenharmony_ci std::vector<uint8_t> challenge; 253cc290419Sopenharmony_ci AuthOptions authOptions; 254cc290419Sopenharmony_ci bool verifyResult = false; 255cc290419Sopenharmony_ci 256cc290419Sopenharmony_ci AccountIAMClient &sudoIAMClient = AccountIAMClient::GetInstance(); 257cc290419Sopenharmony_ci std::shared_ptr<IDMCallback> callback = std::make_shared<SudoIDMCallback>(); 258cc290419Sopenharmony_ci authOptions.accountId = userId; 259cc290419Sopenharmony_ci sudoIAMClient.AuthUser(authOptions, challenge, AuthType::PIN, AuthTrustLevel::ATL1, callback); 260cc290419Sopenharmony_ci std::shared_ptr<SudoIDMCallback> sudoCallback = std::static_pointer_cast<SudoIDMCallback>(callback); 261cc290419Sopenharmony_ci WaitForAuth(); 262cc290419Sopenharmony_ci verifyResult = sudoCallback->GetVerifyResult(); 263cc290419Sopenharmony_ci return verifyResult; 264cc290419Sopenharmony_ci} 265cc290419Sopenharmony_ci 266cc290419Sopenharmony_cistatic bool UserAccountVerify(char *pwd, int pwdLen) 267cc290419Sopenharmony_ci{ 268cc290419Sopenharmony_ci std::shared_ptr<PinAuth::IInputer> inputer = nullptr; 269cc290419Sopenharmony_ci OHOS::ErrCode err; 270cc290419Sopenharmony_ci int verifyResult = 0; 271cc290419Sopenharmony_ci pid_t pid; 272cc290419Sopenharmony_ci int fds[2]; 273cc290419Sopenharmony_ci 274cc290419Sopenharmony_ci if (pipe(fds) != 0) { 275cc290419Sopenharmony_ci WriteStdErr("exec pipe failed\n"); 276cc290419Sopenharmony_ci return false; 277cc290419Sopenharmony_ci } 278cc290419Sopenharmony_ci pid = fork(); 279cc290419Sopenharmony_ci if (pid == -1) { 280cc290419Sopenharmony_ci WriteStdErr("exec fork failed\n"); 281cc290419Sopenharmony_ci return false; 282cc290419Sopenharmony_ci } 283cc290419Sopenharmony_ci if (pid == 0) { 284cc290419Sopenharmony_ci int32_t userId = -1; 285cc290419Sopenharmony_ci close(fds[0]); 286cc290419Sopenharmony_ci err = OsAccountManager::GetForegroundOsAccountLocalId(userId); 287cc290419Sopenharmony_ci if (err != 0) { 288cc290419Sopenharmony_ci WriteStdErr("get os account local id failed\n"); 289cc290419Sopenharmony_ci exit(1); 290cc290419Sopenharmony_ci } 291cc290419Sopenharmony_ci inputer = std::make_shared<PinAuth::SudoIInputer>(); 292cc290419Sopenharmony_ci std::shared_ptr<PinAuth::SudoIInputer> sudoInputer = std::static_pointer_cast<PinAuth::SudoIInputer>(inputer); 293cc290419Sopenharmony_ci sudoInputer->SetPasswd(pwd, pwdLen); 294cc290419Sopenharmony_ci err = AccountIAMClient::GetInstance().RegisterPINInputer(inputer); 295cc290419Sopenharmony_ci if (err != 0) { 296cc290419Sopenharmony_ci WriteStdErr("register pin inputer failed\n"); 297cc290419Sopenharmony_ci exit(1); 298cc290419Sopenharmony_ci } 299cc290419Sopenharmony_ci if (VerifyAccount(userId)) { 300cc290419Sopenharmony_ci verifyResult = 1; 301cc290419Sopenharmony_ci } 302cc290419Sopenharmony_ci AccountIAMClient::GetInstance().UnregisterPINInputer(); 303cc290419Sopenharmony_ci write(fds[1], &verifyResult, sizeof(verifyResult)); 304cc290419Sopenharmony_ci close(fds[1]); 305cc290419Sopenharmony_ci exit(0); 306cc290419Sopenharmony_ci } else { 307cc290419Sopenharmony_ci close(fds[1]); 308cc290419Sopenharmony_ci waitpid(pid, nullptr, 0); 309cc290419Sopenharmony_ci read(fds[0], &verifyResult, sizeof(verifyResult)); 310cc290419Sopenharmony_ci close(fds[0]); 311cc290419Sopenharmony_ci return (verifyResult == 1); 312cc290419Sopenharmony_ci } 313cc290419Sopenharmony_ci} 314cc290419Sopenharmony_ci 315cc290419Sopenharmony_cistatic bool VerifyUserPin(void) 316cc290419Sopenharmony_ci{ 317cc290419Sopenharmony_ci char passwd[PWD_BUF_LEN] = {0}; 318cc290419Sopenharmony_ci bool pwdVerifyResult = false; 319cc290419Sopenharmony_ci 320cc290419Sopenharmony_ci if (getuid() == 0) { 321cc290419Sopenharmony_ci return true; 322cc290419Sopenharmony_ci } 323cc290419Sopenharmony_ci 324cc290419Sopenharmony_ci GetUserPwd(passwd, PWD_BUF_LEN); 325cc290419Sopenharmony_ci pwdVerifyResult = UserAccountVerify(passwd, strnlen(passwd, PWD_BUF_LEN)); 326cc290419Sopenharmony_ci memset_s(passwd, sizeof(passwd), 0, sizeof(passwd)); 327cc290419Sopenharmony_ci if (!pwdVerifyResult) { 328cc290419Sopenharmony_ci WriteTty(USER_VERIFY_FAILED); 329cc290419Sopenharmony_ci } 330cc290419Sopenharmony_ci return pwdVerifyResult; 331cc290419Sopenharmony_ci} 332cc290419Sopenharmony_ci 333cc290419Sopenharmony_ciint main(int argc, char* argv[], char* env[]) 334cc290419Sopenharmony_ci{ 335cc290419Sopenharmony_ci char execCmd[PATH_MAX + 1] = {0}; 336cc290419Sopenharmony_ci char **argvNew = nullptr; 337cc290419Sopenharmony_ci const char *help = "sudo - execute command as root\n\n" 338cc290419Sopenharmony_ci "usage: sudo command ...\n" 339cc290419Sopenharmony_ci "usage: sudo sh -c command ...\n"; 340cc290419Sopenharmony_ci if (argc < 2) { //2:argc check number 341cc290419Sopenharmony_ci WriteStdErr(help); 342cc290419Sopenharmony_ci return 1; 343cc290419Sopenharmony_ci } 344cc290419Sopenharmony_ci 345cc290419Sopenharmony_ci /* 346cc290419Sopenharmony_ci * Get and verify user pwd 347cc290419Sopenharmony_ci */ 348cc290419Sopenharmony_ci if (!VerifyUserPin()) { 349cc290419Sopenharmony_ci return 1; 350cc290419Sopenharmony_ci } 351cc290419Sopenharmony_ci 352cc290419Sopenharmony_ci /* 353cc290419Sopenharmony_ci * Make exec cmd and the args 354cc290419Sopenharmony_ci */ 355cc290419Sopenharmony_ci argvNew = ParseCmd(argc, argv, env, execCmd, PATH_MAX + 1); 356cc290419Sopenharmony_ci if (argvNew == nullptr) { 357cc290419Sopenharmony_ci return 1; 358cc290419Sopenharmony_ci } 359cc290419Sopenharmony_ci CloseTty(); 360cc290419Sopenharmony_ci 361cc290419Sopenharmony_ci /* 362cc290419Sopenharmony_ci * set uid, gid, egid 363cc290419Sopenharmony_ci */ 364cc290419Sopenharmony_ci if (!SetUidGid()) { 365cc290419Sopenharmony_ci FreeArgvNew(argvNew); 366cc290419Sopenharmony_ci WriteStdErr("setuid failed\n"); 367cc290419Sopenharmony_ci return 1; 368cc290419Sopenharmony_ci } 369cc290419Sopenharmony_ci 370cc290419Sopenharmony_ci#if defined(SURPPORT_SELINUX) 371cc290419Sopenharmony_ci setcon("u:r:privilege_app:s0"); 372cc290419Sopenharmony_ci#endif 373cc290419Sopenharmony_ci 374cc290419Sopenharmony_ci execvp(execCmd, argvNew); 375cc290419Sopenharmony_ci 376cc290419Sopenharmony_ci WriteStdErr("execvp failed\n"); 377cc290419Sopenharmony_ci return 1; 378cc290419Sopenharmony_ci} 379