/* * Copyright (c) 2018-2021 mcumgr authors * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include #include #include #include #include LOG_MODULE_REGISTER(mcumgr_shell_grp, CONFIG_MCUMGR_GRP_SHELL_LOG_LEVEL); static int shell_exec(const char *line) { const struct shell *sh = shell_backend_dummy_get_ptr(); shell_backend_dummy_clear_output(sh); return shell_execute_cmd(sh, line); } const char * shell_get_output(size_t *len) { return shell_backend_dummy_get_output( shell_backend_dummy_get_ptr(), len ); } /** * Command handler: shell exec */ static int shell_mgmt_exec(struct smp_streamer *ctxt) { int rc; bool ok; char line[CONFIG_SHELL_CMD_BUFF_SIZE + 1]; size_t len = 0; struct zcbor_string cmd_out; zcbor_state_t *zsd = ctxt->reader->zs; zcbor_state_t *zse = ctxt->writer->zs; if (!zcbor_map_start_decode(zsd)) { return MGMT_ERR_EINVAL; } /* Expecting single array named "argv" */ do { struct zcbor_string key; static const char argv_keyword[] = "argv"; ok = zcbor_tstr_decode(zsd, &key); if (ok) { if (key.len == (ARRAY_SIZE(argv_keyword) - 1) && memcmp(key.value, argv_keyword, ARRAY_SIZE(argv_keyword) - 1) == 0) { break; } ok = zcbor_any_skip(zsd, NULL); } } while (ok); if (!ok || !zcbor_list_start_decode(zsd)) { return MGMT_ERR_EINVAL; } /* Compose command line */ do { struct zcbor_string value; ok = zcbor_tstr_decode(zsd, &value); if (ok) { if ((len + value.len) >= (ARRAY_SIZE(line) - 1)) { ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_SHELL, SHELL_MGMT_ERR_COMMAND_TOO_LONG); goto end; } memcpy(&line[len], value.value, value.len); len += value.len + 1; line[len - 1] = ' '; } else if (len > 0) { line[len - 1] = 0; /* Implicit break by while condition */ } } while (ok); zcbor_list_end_decode(zsd); /* Failed to compose command line? */ if (len == 0) { /* We do not bother to close decoder */ LOG_ERR("Failed to compose command line"); ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_SHELL, SHELL_MGMT_ERR_EMPTY_COMMAND); goto end; } rc = shell_exec(line); cmd_out.value = shell_get_output(&cmd_out.len); /* Key="o"; value= */ /* Key="ret"; value=, or rc if legacy option enabled */ ok = zcbor_tstr_put_lit(zse, "o") && zcbor_tstr_encode(zse, &cmd_out) && #ifdef CONFIG_MCUMGR_GRP_SHELL_LEGACY_RC_RETURN_CODE zcbor_tstr_put_lit(zse, "rc") && #else zcbor_tstr_put_lit(zse, "ret") && #endif zcbor_int32_put(zse, rc); zcbor_map_end_decode(zsd); end: return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE; } #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL /* * @brief Translate shell mgmt group error code into MCUmgr error code * * @param ret #shell_mgmt_err_code_t error code * * @return #mcumgr_err_t error code */ static int shell_mgmt_translate_error_code(uint16_t err) { int rc; switch (err) { case SHELL_MGMT_ERR_COMMAND_TOO_LONG: case SHELL_MGMT_ERR_EMPTY_COMMAND: rc = MGMT_ERR_EINVAL; break; default: rc = MGMT_ERR_EUNKNOWN; } return rc; } #endif static const struct mgmt_handler shell_mgmt_handlers[] = { [SHELL_MGMT_ID_EXEC] = { NULL, shell_mgmt_exec }, }; #define SHELL_MGMT_HANDLER_CNT ARRAY_SIZE(shell_mgmt_handlers) static struct mgmt_group shell_mgmt_group = { .mg_handlers = shell_mgmt_handlers, .mg_handlers_count = SHELL_MGMT_HANDLER_CNT, .mg_group_id = MGMT_GROUP_ID_SHELL, #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL .mg_translate_error = shell_mgmt_translate_error_code, #endif #ifdef CONFIG_MCUMGR_GRP_ENUM_DETAILS_NAME .mg_group_name = "shell mgmt", #endif }; static void shell_mgmt_register_group(void) { mgmt_register_group(&shell_mgmt_group); } MCUMGR_HANDLER_DEFINE(shell_mgmt, shell_mgmt_register_group);