1/* 2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. 3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this list of 9 * conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 * of conditions and the following disclaimer in the documentation and/or other materials 13 * provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used 16 * to endorse or promote products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include "shmsg.h" 33#include "shell_pri.h" 34#include "shcmd.h" 35#include "stdlib.h" 36#include "stdio.h" 37#include "unistd.h" 38#include "securec.h" 39#include "los_base.h" 40#include "los_task.h" 41#include "los_event.h" 42#include "los_list.h" 43#include "los_printf.h" 44 45#ifdef LOSCFG_FS_VFS 46#include "console.h" 47#endif 48 49 50CHAR *ShellGetInputBuf(ShellCB *shellCB) 51{ 52 CmdKeyLink *cmdkey = shellCB->cmdKeyLink; 53 CmdKeyLink *cmdNode = NULL; 54 55 (VOID)pthread_mutex_lock(&shellCB->keyMutex); 56 if ((cmdkey == NULL) || LOS_ListEmpty(&cmdkey->list)) { 57 (VOID)pthread_mutex_unlock(&shellCB->keyMutex); 58 return NULL; 59 } 60 61 cmdNode = LOS_DL_LIST_ENTRY(cmdkey->list.pstNext, CmdKeyLink, list); 62 LOS_ListDelete(&(cmdNode->list)); /* 'cmdNode' freed in history save process */ 63 (VOID)pthread_mutex_unlock(&shellCB->keyMutex); 64 65 return cmdNode->cmdString; 66} 67 68STATIC VOID ShellSaveHistoryCmd(const CHAR *string, ShellCB *shellCB) 69{ 70 CmdKeyLink *cmdHistory = shellCB->cmdHistoryKeyLink; 71 CmdKeyLink *cmdkey = LOS_DL_LIST_ENTRY(string, CmdKeyLink, cmdString); 72 CmdKeyLink *cmdNxt = NULL; 73 74 if ((string == NULL) || (strlen(string) == 0)) { 75 return; 76 } 77 78 (VOID)pthread_mutex_lock(&shellCB->historyMutex); 79 if (cmdHistory->count != 0) { 80 cmdNxt = LOS_DL_LIST_ENTRY(cmdHistory->list.pstPrev, CmdKeyLink, list); 81 if (strcmp(string, cmdNxt->cmdString) == 0) { 82 (VOID)LOS_MemFree(m_aucSysMem0, (VOID *)cmdkey); 83 (VOID)pthread_mutex_unlock(&shellCB->historyMutex); 84 return; 85 } 86 } 87 88 if (cmdHistory->count == CMD_HISTORY_LEN) { 89 cmdNxt = LOS_DL_LIST_ENTRY(cmdHistory->list.pstNext, CmdKeyLink, list); 90 LOS_ListDelete(&(cmdNxt->list)); 91 LOS_ListTailInsert(&(cmdHistory->list), &(cmdkey->list)); 92 (VOID)LOS_MemFree(m_aucSysMem0, (VOID *)cmdNxt); 93 (VOID)pthread_mutex_unlock(&shellCB->historyMutex); 94 return; 95 } 96 97 LOS_ListTailInsert(&(cmdHistory->list), &(cmdkey->list)); 98 cmdHistory->count++; 99 100 (VOID)pthread_mutex_unlock(&shellCB->historyMutex); 101 return; 102} 103 104STATIC VOID ShellNotify(ShellCB *shellCB) 105{ 106 (VOID)LOS_EventWrite(&shellCB->shellEvent, SHELL_CMD_PARSE_EVENT); 107} 108 109enum { 110 STAT_NORMAL_KEY, 111 STAT_ESC_KEY, 112 STAT_MULTI_KEY 113}; 114 115STATIC INT32 ShellCmdLineCheckUDRL(const CHAR ch, ShellCB *shellCB) 116{ 117 INT32 ret = LOS_OK; 118 if (ch == 0x1b) { /* 0x1b: ESC */ 119 shellCB->shellKeyType = STAT_ESC_KEY; 120 return ret; 121 } else if (ch == 0x5b) { /* 0x5b: first Key combination */ 122 if (shellCB->shellKeyType == STAT_ESC_KEY) { 123 shellCB->shellKeyType = STAT_MULTI_KEY; 124 return ret; 125 } 126 } else if (ch == 0x41) { /* up */ 127 if (shellCB->shellKeyType == STAT_MULTI_KEY) { 128 OsShellHistoryShow(CMD_KEY_UP, shellCB); 129 shellCB->shellKeyType = STAT_NORMAL_KEY; 130 return ret; 131 } 132 } else if (ch == 0x42) { /* down */ 133 if (shellCB->shellKeyType == STAT_MULTI_KEY) { 134 shellCB->shellKeyType = STAT_NORMAL_KEY; 135 OsShellHistoryShow(CMD_KEY_DOWN, shellCB); 136 return ret; 137 } 138 } else if (ch == 0x43) { /* right */ 139 if (shellCB->shellKeyType == STAT_MULTI_KEY) { 140 shellCB->shellKeyType = STAT_NORMAL_KEY; 141 return ret; 142 } 143 } else if (ch == 0x44) { /* left */ 144 if (shellCB->shellKeyType == STAT_MULTI_KEY) { 145 shellCB->shellKeyType = STAT_NORMAL_KEY; 146 return ret; 147 } 148 } 149 return LOS_NOK; 150} 151 152LITE_OS_SEC_TEXT_MINOR VOID ShellCmdLineParse(CHAR c, pf_OUTPUT outputFunc, ShellCB *shellCB) 153{ 154 const CHAR ch = c; 155 INT32 ret; 156 157 if ((shellCB->shellBufOffset == 0) && (ch != '\n') && (ch != '\0')) { 158 (VOID)memset_s(shellCB->shellBuf, SHOW_MAX_LEN, 0, SHOW_MAX_LEN); 159 } 160 161 if ((ch == '\r') || (ch == '\n')) { 162 if (shellCB->shellBufOffset < (SHOW_MAX_LEN - 1)) { 163 shellCB->shellBuf[shellCB->shellBufOffset] = '\0'; 164 } 165 shellCB->shellBufOffset = 0; 166 (VOID)pthread_mutex_lock(&shellCB->keyMutex); 167 OsShellCmdPush(shellCB->shellBuf, shellCB->cmdKeyLink); 168 (VOID)pthread_mutex_unlock(&shellCB->keyMutex); 169 ShellNotify(shellCB); 170 return; 171 } else if ((ch == '\b') || (ch == 0x7F)) { /* backspace or delete(0x7F) */ 172 if ((shellCB->shellBufOffset > 0) && (shellCB->shellBufOffset < (SHOW_MAX_LEN - 1))) { 173 shellCB->shellBuf[shellCB->shellBufOffset - 1] = '\0'; 174 shellCB->shellBufOffset--; 175 outputFunc("\b \b"); 176 } 177 return; 178 } else if (ch == 0x09) { /* 0x09: tab */ 179 if ((shellCB->shellBufOffset > 0) && (shellCB->shellBufOffset < (SHOW_MAX_LEN - 1))) { 180 ret = OsTabCompletion(shellCB->shellBuf, &shellCB->shellBufOffset); 181 if (ret > 1) { 182 outputFunc("OHOS # %s", shellCB->shellBuf); 183 } 184 } 185 return; 186 } 187 /* parse the up/down/right/left key */ 188 ret = ShellCmdLineCheckUDRL(ch, shellCB); 189 if (ret == LOS_OK) { 190 return; 191 } 192 193 if ((ch != '\n') && (ch != '\0')) { 194 if (shellCB->shellBufOffset < (SHOW_MAX_LEN - 1)) { 195 shellCB->shellBuf[shellCB->shellBufOffset] = ch; 196 } else { 197 shellCB->shellBuf[SHOW_MAX_LEN - 1] = '\0'; 198 } 199 shellCB->shellBufOffset++; 200 outputFunc("%c", ch); 201 } 202 203 shellCB->shellKeyType = STAT_NORMAL_KEY; 204} 205 206LITE_OS_SEC_TEXT_MINOR UINT32 ShellMsgTypeGet(CmdParsed *cmdParsed, const CHAR *cmdType) 207{ 208 CmdItemNode *curCmdItem = (CmdItemNode *)NULL; 209 UINT32 len; 210 UINT32 minLen; 211 CmdModInfo *cmdInfo = OsCmdInfoGet(); 212 213 if ((cmdParsed == NULL) || (cmdType == NULL)) { 214 return OS_INVALID; 215 } 216 217 len = strlen(cmdType); 218 LOS_DL_LIST_FOR_EACH_ENTRY(curCmdItem, &(cmdInfo->cmdList.list), CmdItemNode, list) { 219 if ((len == strlen(curCmdItem->cmd->cmdKey)) && 220 (strncmp((CHAR *)(curCmdItem->cmd->cmdKey), cmdType, len) == 0)) { 221 minLen = (len < CMD_KEY_LEN) ? len : CMD_KEY_LEN; 222 (VOID)memcpy_s((CHAR *)(cmdParsed->cmdKeyword), CMD_KEY_LEN, cmdType, minLen); 223 cmdParsed->cmdType = curCmdItem->cmd->cmdType; 224 return LOS_OK; 225 } 226 } 227 228 return OS_INVALID; 229} 230 231STATIC UINT32 ShellMsgNameGetAndExec(CmdParsed *cmdParsed, const CHAR *output, UINT32 len) 232{ 233 UINT32 loop; 234 UINT32 ret; 235 const CHAR *tmpStr = NULL; 236 BOOL quotes = FALSE; 237 CHAR *msgName = (CHAR *)LOS_MemAlloc(m_aucSysMem0, len + 1); 238 if (msgName == NULL) { 239 PRINTK("malloc failure in %s[%d]\n", __FUNCTION__, __LINE__); 240 return OS_INVALID; 241 } 242 /* Scan the 'output' string for command */ 243 /* Notice: Command string must not have any special name */ 244 for (tmpStr = output, loop = 0; (*tmpStr != '\0') && (loop < len);) { 245 /* If reach a double quotes, switch the quotes matching status */ 246 if (*tmpStr == '\"') { 247 SWITCH_QUOTES_STATUS(quotes); 248 /* Ignore the double quote CHARactor itself */ 249 tmpStr++; 250 continue; 251 } 252 /* If detected a space which the quotes matching status is false */ 253 /* which said has detected the first space for separator, finish this scan operation */ 254 if ((*tmpStr == ' ') && (QUOTES_STATUS_CLOSE(quotes))) { 255 break; 256 } 257 msgName[loop] = *tmpStr++; 258 loop++; 259 } 260 msgName[loop] = '\0'; 261 /* Scan the command list to check whether the command can be found */ 262 ret = ShellMsgTypeGet(cmdParsed, msgName); 263 PRINTK("\n"); 264 if (ret != LOS_OK) { 265 PRINTK("%s:command not found", msgName); 266 } else { 267 (VOID)OsCmdExec(cmdParsed, (CHAR *)output); 268 } 269 (VOID)LOS_MemFree(m_aucSysMem0, msgName); 270 return ret; 271} 272 273LITE_OS_SEC_TEXT_MINOR UINT32 ShellMsgParse(const VOID *msg) 274{ 275 CHAR *output = NULL; 276 UINT32 len, cmdLen, newLen; 277 CmdParsed cmdParsed; 278 UINT32 ret = OS_INVALID; 279 CHAR *buf = (CHAR *)msg; 280 CHAR *newMsg = NULL; 281 CHAR *cmd = "exec"; 282 283 if (msg == NULL) { 284 goto END; 285 } 286 287 len = strlen(msg); 288 /* 2: strlen("./") */ 289 if ((len > 2) && (buf[0] == '.') && (buf[1] == '/')) { 290 cmdLen = strlen(cmd); 291 newLen = len + 1 + cmdLen + 1; 292 newMsg = (CHAR *)LOS_MemAlloc(m_aucSysMem0, newLen); 293 if (newMsg == NULL) { 294 PRINTK("malloc failure in %s[%d]\n", __FUNCTION__, __LINE__); 295 goto END; 296 } 297 (VOID)memcpy_s(newMsg, newLen, cmd, cmdLen); 298 newMsg[cmdLen] = ' '; 299 (VOID)memcpy_s(newMsg + cmdLen + 1, newLen - cmdLen - 1, (CHAR *)msg + 1, len); 300 msg = newMsg; 301 len = newLen - 1; 302 } 303 output = (CHAR *)LOS_MemAlloc(m_aucSysMem0, len + 1); 304 if (output == NULL) { 305 PRINTK("malloc failure in %s[%d]\n", __FUNCTION__, __LINE__); 306 goto END; 307 } 308 /* Call function 'OsCmdKeyShift' to squeeze and clear useless or overmuch space if string buffer */ 309 ret = OsCmdKeyShift((CHAR *)msg, output, len + 1); 310 if ((ret != LOS_OK) || (strlen(output) == 0)) { 311 ret = OS_INVALID; 312 goto END_FREE_OUTPUT; 313 } 314 315 (VOID)memset_s(&cmdParsed, sizeof(CmdParsed), 0, sizeof(CmdParsed)); 316 317 ret = ShellMsgNameGetAndExec(&cmdParsed, output, len); 318 319END_FREE_OUTPUT: 320 (VOID)LOS_MemFree(m_aucSysMem0, output); 321END: 322 if (newMsg != NULL) { 323 (VOID)LOS_MemFree(m_aucSysMem0, newMsg); 324 } 325 return ret; 326} 327 328#ifdef LOSCFG_FS_VFS 329LITE_OS_SEC_TEXT_MINOR UINT32 ShellEntry(UINTPTR param) 330{ 331 CHAR ch; 332 INT32 n; 333 ShellCB *shellCB = (ShellCB *)param; 334 335 CONSOLE_CB *consoleCB = OsGetConsoleByID((INT32)shellCB->consoleID); 336 if (consoleCB == NULL) { 337 PRINT_ERR("Shell task init error!\n"); 338 return 1; 339 } 340 341 (VOID)memset_s(shellCB->shellBuf, SHOW_MAX_LEN, 0, SHOW_MAX_LEN); 342 343 while (1) { 344#ifdef LOSCFG_PLATFORM_CONSOLE 345 if (!IsConsoleOccupied(consoleCB)) { 346#endif 347 /* is console ready for shell ? */ 348 n = read(consoleCB->fd, &ch, 1); 349 if (n == 1) { 350 ShellCmdLineParse(ch, (pf_OUTPUT)dprintf, shellCB); 351 } 352 if (is_nonblock(consoleCB)) { 353 LOS_Msleep(50); /* 50: 50MS for sleep */ 354 } 355#ifdef LOSCFG_PLATFORM_CONSOLE 356 } 357#endif 358 } 359} 360#endif 361 362STATIC VOID ShellCmdProcess(ShellCB *shellCB) 363{ 364 CHAR *buf = NULL; 365 while (1) { 366 buf = ShellGetInputBuf(shellCB); 367 if (buf == NULL) { 368 break; 369 } 370 (VOID)ShellMsgParse(buf); 371 ShellSaveHistoryCmd(buf, shellCB); 372 shellCB->cmdMaskKeyLink = shellCB->cmdHistoryKeyLink; 373 } 374} 375 376LITE_OS_SEC_TEXT_MINOR UINT32 ShellTask(UINTPTR param1, 377 UINTPTR param2, 378 UINTPTR param3, 379 UINTPTR param4) 380{ 381 UINT32 ret; 382 ShellCB *shellCB = (ShellCB *)param1; 383 (VOID)param2; 384 (VOID)param3; 385 (VOID)param4; 386 387 while (1) { 388 PRINTK("\nOHOS # "); 389 ret = LOS_EventRead(&shellCB->shellEvent, 390 0xFFF, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); 391 if (ret == SHELL_CMD_PARSE_EVENT) { 392 ShellCmdProcess(shellCB); 393 } else if (ret == CONSOLE_SHELL_KEY_EVENT) { 394 break; 395 } 396 } 397 OsShellKeyDeInit((CmdKeyLink *)shellCB->cmdKeyLink); 398 OsShellKeyDeInit((CmdKeyLink *)shellCB->cmdHistoryKeyLink); 399 (VOID)LOS_EventDestroy(&shellCB->shellEvent); 400 (VOID)LOS_MemFree((VOID *)m_aucSysMem0, shellCB); 401 return 0; 402} 403 404#define SERIAL_SHELL_TASK_NAME "SerialShellTask" 405#define SERIAL_ENTRY_TASK_NAME "SerialEntryTask" 406#define TELNET_SHELL_TASK_NAME "TelnetShellTask" 407#define TELNET_ENTRY_TASK_NAME "TelnetEntryTask" 408 409LITE_OS_SEC_TEXT_MINOR UINT32 ShellTaskInit(ShellCB *shellCB) 410{ 411 CHAR *name = NULL; 412 TSK_INIT_PARAM_S initParam = {0}; 413 414 if (shellCB->consoleID == CONSOLE_SERIAL) { 415 name = SERIAL_SHELL_TASK_NAME; 416 } else if (shellCB->consoleID == CONSOLE_TELNET) { 417 name = TELNET_SHELL_TASK_NAME; 418 } else { 419 return LOS_NOK; 420 } 421 422 initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ShellTask; 423 initParam.usTaskPrio = 9; /* 9:shell task priority */ 424 initParam.auwArgs[0] = (UINTPTR)shellCB; 425 initParam.uwStackSize = 0x3000; 426 initParam.pcName = name; 427 initParam.uwResved = LOS_TASK_STATUS_DETACHED; 428 429 (VOID)LOS_EventInit(&shellCB->shellEvent); 430 431 return LOS_TaskCreate(&shellCB->shellTaskHandle, &initParam); 432} 433 434LITE_OS_SEC_TEXT_MINOR UINT32 ShellEntryInit(ShellCB *shellCB) 435{ 436 UINT32 ret; 437 CHAR *name = NULL; 438 TSK_INIT_PARAM_S initParam = {0}; 439 440 if (shellCB->consoleID == CONSOLE_SERIAL) { 441 name = SERIAL_ENTRY_TASK_NAME; 442 } else if (shellCB->consoleID == CONSOLE_TELNET) { 443 name = TELNET_ENTRY_TASK_NAME; 444 } else { 445 return LOS_NOK; 446 } 447 448 initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ShellEntry; 449 initParam.usTaskPrio = 9; /* 9:shell task priority */ 450 initParam.auwArgs[0] = (UINTPTR)shellCB; 451 initParam.uwStackSize = 0x1000; 452 initParam.pcName = name; 453 initParam.uwResved = LOS_TASK_STATUS_DETACHED; 454 455 ret = LOS_TaskCreate(&shellCB->shellEntryHandle, &initParam); 456#ifdef LOSCFG_PLATFORM_CONSOLE 457 (VOID)ConsoleTaskReg((INT32)shellCB->consoleID, shellCB->shellEntryHandle); 458#endif 459 460 return ret; 461} 462 463