This is an automated email from the ASF dual-hosted git repository. ccollins pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git
commit 2622b41bfc82f66e89b5faea8abfb34959c3c86d Author: Christopher Collins <ccoll...@apache.org> AuthorDate: Fri Jan 26 15:52:28 2018 -0800 log_mgmt command handler group. --- cmd/CMakeLists.txt | 1 + cmd/Kconfig | 1 + cmd/log_mgmt/CMakeLists.txt | 9 + cmd/log_mgmt/Kconfig | 53 +++ cmd/log_mgmt/include/log_mgmt/log_mgmt.h | 83 +++++ cmd/log_mgmt/include/log_mgmt/log_mgmt_impl.h | 48 +++ cmd/log_mgmt/port/mynewt/src/mynewt_log_mgmt.c | 206 +++++++++++ cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c | 189 ++++++++++ cmd/log_mgmt/src/log_mgmt.c | 494 +++++++++++++++++++++++++ cmd/log_mgmt/src/log_mgmt_config.h | 45 +++ cmd/log_mgmt/src/stubs.c | 65 ++++ cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c | 2 + 12 files changed, 1196 insertions(+) diff --git a/cmd/CMakeLists.txt b/cmd/CMakeLists.txt index bc91e2f..be26ded 100644 --- a/cmd/CMakeLists.txt +++ b/cmd/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_FS_MGMT fs_mgmt) add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_IMG_MGMT img_mgmt) +add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_LOG_MGMT log_mgmt) add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_OS_MGMT os_mgmt) diff --git a/cmd/Kconfig b/cmd/Kconfig index a0e2031..ea51804 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -19,6 +19,7 @@ menu "Command handlers" source "ext/mcumgr/cmd/fs_mgmt/Kconfig" source "ext/mcumgr/cmd/img_mgmt/Kconfig" +source "ext/mcumgr/cmd/log_mgmt/Kconfig" source "ext/mcumgr/cmd/os_mgmt/Kconfig" endmenu diff --git a/cmd/log_mgmt/CMakeLists.txt b/cmd/log_mgmt/CMakeLists.txt new file mode 100644 index 0000000..7d72dcd --- /dev/null +++ b/cmd/log_mgmt/CMakeLists.txt @@ -0,0 +1,9 @@ +target_include_directories(MCUMGR INTERFACE + include +) + +zephyr_library_sources( + cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c + cmd/log_mgmt/src/log_mgmt.c + cmd/log_mgmt/src/stubs.c +) diff --git a/cmd/log_mgmt/Kconfig b/cmd/log_mgmt/Kconfig new file mode 100644 index 0000000..e949aa6 --- /dev/null +++ b/cmd/log_mgmt/Kconfig @@ -0,0 +1,53 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE log +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this log +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this log except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# Under the License. + +menuconfig MCUMGR_CMD_LOG_MGMT + bool + prompt "Enable mcumgr handlers for log management" + default n + help + Enables mcumgr handlers for log management + +if MCUMGR_CMD_LOG_MGMT +config LOG_MGMT_CHUNK_SIZE + int + prompt "Maximum chunk size for log downloads" + default 512 + help + Limits the maximum chunk size in log downloads. A buffer of this size + gets allocated on the stack during handling of the log show command. + +config LOG_MGMT_NAME_LEN + int + prompt "Maximum log name length" + default 64 + help + Limits the maximum length of log names. If a log's name length exceeds + this number, it gets truncated in management responses. A buffer of this + size gets allocated on the stack during handling of all log management + commands. + +config LOG_MGMT_BODY_LEN + int + prompt "Maximum log body length" + default 128 + help + Limits the maximum length of log entry bodies. If a log entry's body + length exceeds this number, it gets truncated in management responses. A + buffer of this size gets allocated on the stack during handling of the + log show command. +endif diff --git a/cmd/log_mgmt/include/log_mgmt/log_mgmt.h b/cmd/log_mgmt/include/log_mgmt/log_mgmt.h new file mode 100644 index 0000000..01df2e5 --- /dev/null +++ b/cmd/log_mgmt/include/log_mgmt/log_mgmt.h @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_LOG_MGMT_ +#define H_LOG_MGMT_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Command IDs for log management group. + */ +#define LOG_MGMT_ID_SHOW 0 +#define LOG_MGMT_ID_CLEAR 1 +#define LOG_MGMT_ID_APPEND 2 +#define LOG_MGMT_ID_MODULE_LIST 3 +#define LOG_MGMT_ID_LEVEL_LIST 4 +#define LOG_MGMT_ID_LOGS_LIST 5 + +/** @brief Log output is streamed without retention (e.g., console). */ +#define LOG_MGMT_TYPE_STREAM 0 + +/** @brief Log entries are stored in RAM. */ +#define LOG_MGMT_TYPE_MEMORY 1 + +/** @brief Log entries are persisted across reboots. */ +#define LOG_MGMT_TYPE_STORAGE 2 + +/** @brief Generic descriptor for an OS-specific log. */ +struct log_mgmt_log { + const char *name; + int type; +}; + +/** @brief Generic descriptor for an OS-specific log entry. */ +struct log_mgmt_entry { + int64_t ts; + uint32_t index; + const void *data; + size_t len; + uint8_t module; + uint8_t level; +}; + +/** @brief Indicates which log entries to operate on. */ +struct log_mgmt_filter { + /* If min_timestamp == -1: Only access last log entry; + * Elif min_timestamp == 0: Don't filter by timestamp; + * Else: Only access entries whose ts >= min_timestamp. + */ + int64_t min_timestamp; + + /* Only access entries whose index >= min_index. */ + uint32_t min_index; +}; + +/** + * @brief Registers the log management command handler group. + */ +void log_mgmt_register_group(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cmd/log_mgmt/include/log_mgmt/log_mgmt_impl.h b/cmd/log_mgmt/include/log_mgmt/log_mgmt_impl.h new file mode 100644 index 0000000..1890643 --- /dev/null +++ b/cmd/log_mgmt/include/log_mgmt/log_mgmt_impl.h @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_LOG_MGMT_IMPL_ +#define H_LOG_MGMT_IMPL_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct log_mgmt_filter; +struct log_mgmt_entry; +struct log_mgmt_log; + +typedef int log_mgmt_foreach_entry_fn(const struct log_mgmt_entry *entry, + void *arg); + +int log_mgmt_impl_get_log(int idx, struct log_mgmt_log *out_log); +int log_mgmt_impl_get_module(int idx, const char **out_module_name); +int log_mgmt_impl_get_level(int idx, const char **out_level_name); +int log_mgmt_impl_get_next_idx(uint32_t *out_idx); +int log_mgmt_impl_foreach_entry(const char *log_name, + const struct log_mgmt_filter *filter, + log_mgmt_foreach_entry_fn *cb, + void *arg); +int log_mgmt_impl_clear(const char *log_name); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cmd/log_mgmt/port/mynewt/src/mynewt_log_mgmt.c b/cmd/log_mgmt/port/mynewt/src/mynewt_log_mgmt.c new file mode 100644 index 0000000..f81e591 --- /dev/null +++ b/cmd/log_mgmt/port/mynewt/src/mynewt_log_mgmt.c @@ -0,0 +1,206 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "log/log.h" +#include "mgmt/mgmt.h" +#include "log_mgmt/log_mgmt.h" +#include "log_mgmt/log_mgmt_impl.h" +#include "../../../src/log_mgmt_config.h" + +struct mynewt_log_mgmt_walk_arg { + log_mgmt_foreach_entry_fn *cb; + uint8_t body[LOG_MGMT_BODY_LEN]; + void *arg; +}; + +static struct log * +mynewt_log_mgmt_find_log(const char *log_name) +{ + struct log *log; + + log = NULL; + while (1) { + log = log_list_get_next(log); + if (log == NULL) { + return NULL; + } + + if (strcmp(log->l_name, log_name) == 0) { + return log; + } + } +} + +int +log_mgmt_impl_get_log(int idx, struct log_mgmt_log *out_log) +{ + struct log *log; + int i; + + log = NULL; + for (i = 0; i <= idx; i++) { + log = log_list_get_next(log); + if (log == NULL) { + return MGMT_ERR_ENOENT; + } + } + + out_log->name = log->l_name; + out_log->type = log->l_handler->type; + return 0; +} + +int +log_mgmt_impl_get_module(int idx, const char **out_module_name) +{ + const char *name; + + name = LOG_MODULE_STR(idx); + if (name == NULL) { + return MGMT_ERR_ENOENT; + } else { + *out_module_name = name; + return 0; + } +} + +int +log_mgmt_impl_get_level(int idx, const char **out_level_name) +{ + const char *name; + + name = LOG_LEVEL_STR(idx); + if (name == NULL) { + return MGMT_ERR_ENOENT; + } else { + *out_level_name = name; + return 0; + } +} + +int +log_mgmt_impl_get_next_idx(uint32_t *out_idx) +{ + *out_idx = g_log_info.li_next_index; + return 0; +} + +static int +mynewt_log_mgmt_walk_cb(struct log *log, struct log_offset *log_offset, + const void *desciptor, uint16_t len) +{ + struct mynewt_log_mgmt_walk_arg *mynewt_log_mgmt_walk_arg; + struct log_mgmt_entry entry; + struct log_entry_hdr ueh; + int read_len; + int rc; + + mynewt_log_mgmt_walk_arg = log_offset->lo_arg; + + rc = log_read(log, desciptor, &ueh, 0, sizeof ueh); + if (rc != sizeof ueh) { + return MGMT_ERR_EUNKNOWN; + } + + /* If specified timestamp is nonzero, it is the primary criterion, and the + * specified index is the secondary criterion. If specified timetsamp is + * zero, specified index is the only criterion. + * + * If specified timestamp == 0: encode entries whose index >= + * specified index. + * Else: encode entries whose timestamp >= specified timestamp and whose + * index >= specified index + */ + + if (log_offset->lo_ts == 0) { + if (log_offset->lo_index > ueh.ue_index) { + return 0; + } + } else if (ueh.ue_ts < log_offset->lo_ts || + (ueh.ue_ts == log_offset->lo_ts && + ueh.ue_index < log_offset->lo_index)) { + return 0; + } + + read_len = min(len - sizeof ueh, LOG_MGMT_BODY_LEN - sizeof ueh); + rc = log_read(log, desciptor, mynewt_log_mgmt_walk_arg->body, sizeof ueh, + read_len); + if (rc < 0) { + return MGMT_ERR_EUNKNOWN; + } + + entry.ts = ueh.ue_ts; + entry.index = ueh.ue_index; + entry.module = ueh.ue_module; + entry.level = ueh.ue_level; + entry.len = rc; + entry.data = mynewt_log_mgmt_walk_arg->body; + + return mynewt_log_mgmt_walk_arg->cb(&entry, mynewt_log_mgmt_walk_arg->arg); +} + +int +log_mgmt_impl_foreach_entry(const char *log_name, + const struct log_mgmt_filter *filter, + log_mgmt_foreach_entry_fn *cb, void *arg) +{ + struct mynewt_log_mgmt_walk_arg walk_arg; + struct log_offset offset; + struct log *log; + + walk_arg = (struct mynewt_log_mgmt_walk_arg) { + .cb = cb, + .arg = arg, + }; + + log = mynewt_log_mgmt_find_log(log_name); + if (log == NULL) { + return MGMT_ERR_ENOENT; + } + + if (strcmp(log->l_name, log_name) == 0) { + offset.lo_arg = &walk_arg; + offset.lo_ts = filter->min_timestamp; + offset.lo_index = filter->min_index; + offset.lo_data_len = 0; + + return log_walk(log, mynewt_log_mgmt_walk_cb, &offset); + } + + return MGMT_ERR_ENOENT; +} + +int +log_mgmt_impl_clear(const char *log_name) +{ + struct log *log; + int rc; + + log = mynewt_log_mgmt_find_log(log_name); + if (log == NULL) { + return MGMT_ERR_ENOENT; + } + + rc = log_flush(log); + if (rc != 0) { + return MGMT_ERR_EUNKNOWN; + } + + return 0; +} diff --git a/cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c b/cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c new file mode 100644 index 0000000..41cf51e --- /dev/null +++ b/cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c @@ -0,0 +1,189 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <misc/util.h> +#include "logging/mdlog.h" +#include "mgmt/mgmt.h" +#include "log_mgmt/log_mgmt.h" +#include "log_mgmt/log_mgmt_impl.h" +#include "../../../src/log_mgmt_config.h" + +struct zephyr_log_mgmt_walk_arg { + log_mgmt_foreach_entry_fn *cb; + uint8_t body[LOG_MGMT_BODY_LEN]; + void *arg; +}; + +int +log_mgmt_impl_get_log(int idx, struct log_mgmt_log *out_log) +{ + struct mdlog *mdlog; + int i; + + mdlog = NULL; + for (i = 0; i <= idx; i++) { + mdlog = mdlog_get_next(mdlog); + if (mdlog == NULL) { + return MGMT_ERR_ENOENT; + } + } + + out_log->name = mdlog->l_name; + out_log->type = mdlog->l_handler->type; + return 0; +} + +int +log_mgmt_impl_get_module(int idx, const char **out_module_name) +{ + const char *name; + + name = mdlog_module_name(idx); + if (name == NULL) { + return MGMT_ERR_ENOENT; + } else { + *out_module_name = name; + return 0; + } +} + +int +log_mgmt_impl_get_level(int idx, const char **out_level_name) +{ + const char *name; + + name = mdlog_level_name(idx); + if (name == NULL) { + return MGMT_ERR_ENOENT; + } else { + *out_level_name = name; + return 0; + } +} + +int +log_mgmt_impl_get_next_idx(uint32_t *out_idx) +{ + *out_idx = mdlog_get_next_index(); + return 0; +} + +static int +zephyr_log_mgmt_walk_cb(struct mdlog *log, struct mdlog_offset *log_offset, + const void *desciptor, uint16_t len) +{ + struct zephyr_log_mgmt_walk_arg *zephyr_log_mgmt_walk_arg; + struct log_mgmt_entry entry; + struct mdlog_entry_hdr ueh; + int read_len; + int rc; + + zephyr_log_mgmt_walk_arg = log_offset->lo_arg; + + rc = mdlog_read(log, desciptor, &ueh, 0, sizeof ueh); + if (rc != sizeof ueh) { + return MGMT_ERR_EUNKNOWN; + } + + /* If specified timestamp is nonzero, it is the primary criterion, and the + * specified index is the secondary criterion. If specified timetsamp is + * zero, specified index is the only criterion. + * + * If specified timestamp == 0: encode entries whose index >= + * specified index. + * Else: encode entries whose timestamp >= specified timestamp and whose + * index >= specified index + */ + + if (log_offset->lo_ts == 0) { + if (log_offset->lo_index > ueh.ue_index) { + return 0; + } + } else if (ueh.ue_ts < log_offset->lo_ts || + (ueh.ue_ts == log_offset->lo_ts && + ueh.ue_index < log_offset->lo_index)) { + return 0; + } + + read_len = min(len - sizeof ueh, LOG_MGMT_BODY_LEN - sizeof ueh); + rc = mdlog_read(log, desciptor, zephyr_log_mgmt_walk_arg->body, sizeof ueh, + read_len); + if (rc < 0) { + return MGMT_ERR_EUNKNOWN; + } + + entry.ts = ueh.ue_ts; + entry.index = ueh.ue_index; + entry.module = ueh.ue_module; + entry.level = ueh.ue_level; + entry.len = rc; + entry.data = zephyr_log_mgmt_walk_arg->body; + + return zephyr_log_mgmt_walk_arg->cb(&entry, zephyr_log_mgmt_walk_arg->arg); +} + +int +log_mgmt_impl_foreach_entry(const char *log_name, + const struct log_mgmt_filter *filter, + log_mgmt_foreach_entry_fn *cb, void *arg) +{ + struct zephyr_log_mgmt_walk_arg walk_arg; + struct mdlog_offset offset; + struct mdlog *mdlog; + + walk_arg = (struct zephyr_log_mgmt_walk_arg) { + .cb = cb, + .arg = arg, + }; + + mdlog = mdlog_find(log_name); + if (mdlog == NULL) { + return MGMT_ERR_ENOENT; + } + + if (strcmp(mdlog->l_name, log_name) == 0) { + offset.lo_arg = &walk_arg; + offset.lo_ts = filter->min_timestamp; + offset.lo_index = filter->min_index; + offset.lo_data_len = 0; + + return mdlog_walk(mdlog, zephyr_log_mgmt_walk_cb, &offset); + } + + return MGMT_ERR_ENOENT; +} + +int +log_mgmt_impl_clear(const char *log_name) +{ + struct mdlog *mdlog; + int rc; + + mdlog = mdlog_find(log_name); + if (mdlog == NULL) { + return MGMT_ERR_ENOENT; + } + + rc = mdlog_flush(mdlog); + if (rc != 0) { + return MGMT_ERR_EUNKNOWN; + } + + return 0; +} diff --git a/cmd/log_mgmt/src/log_mgmt.c b/cmd/log_mgmt/src/log_mgmt.c new file mode 100644 index 0000000..430f35a --- /dev/null +++ b/cmd/log_mgmt/src/log_mgmt.c @@ -0,0 +1,494 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <string.h> +#include <stdio.h> + +#include "mgmt/mgmt.h" +#include "cborattr/cborattr.h" +#include "cbor_cnt_writer.h" +#include "log_mgmt/log_mgmt.h" +#include "log_mgmt/log_mgmt_impl.h" +#include "log_mgmt_config.h" + +/** Context used during walks. */ +struct log_walk_ctxt { + /* The number of bytes encoded to the response so far. */ + size_t rsp_len; + + /* The encoder to use to write the current log entry. */ + struct CborEncoder *enc; +}; + +static mgmt_handler_fn log_mgmt_show; +static mgmt_handler_fn log_mgmt_clear; +static mgmt_handler_fn log_mgmt_module_list; +static mgmt_handler_fn log_mgmt_level_list; +static mgmt_handler_fn log_mgmt_logs_list; + +static struct mgmt_handler log_mgmt_handlers[] = { + [LOG_MGMT_ID_SHOW] = { log_mgmt_show, NULL }, + [LOG_MGMT_ID_CLEAR] = { NULL, log_mgmt_clear }, + [LOG_MGMT_ID_MODULE_LIST] = { log_mgmt_module_list, NULL }, + [LOG_MGMT_ID_LEVEL_LIST] = { log_mgmt_level_list, NULL }, + [LOG_MGMT_ID_LOGS_LIST] = { log_mgmt_logs_list, NULL }, +}; + +#define LOG_MGMT_HANDLER_CNT \ + sizeof log_mgmt_handlers / sizeof log_mgmt_handlers[0] + +static struct mgmt_group log_mgmt_group = { + .mg_handlers = log_mgmt_handlers, + .mg_handlers_count = LOG_MGMT_HANDLER_CNT, + .mg_group_id = MGMT_GROUP_ID_LOG, +}; + +static int +log_mgmt_encode_entry(CborEncoder *enc, const struct log_mgmt_entry *entry, + size_t *out_len) +{ + CborEncoder entry_enc; + CborError err; + + err = 0; + err |= cbor_encoder_create_map(enc, &entry_enc, 5); + err |= cbor_encode_text_stringz(&entry_enc, "msg"); + err |= cbor_encode_byte_string(&entry_enc, entry->data, entry->len); + err |= cbor_encode_text_stringz(&entry_enc, "ts"); + err |= cbor_encode_int(&entry_enc, entry->ts); + err |= cbor_encode_text_stringz(&entry_enc, "level"); + err |= cbor_encode_uint(&entry_enc, entry->level); + err |= cbor_encode_text_stringz(&entry_enc, "index"); + err |= cbor_encode_uint(&entry_enc, entry->index); + err |= cbor_encode_text_stringz(&entry_enc, "module"); + err |= cbor_encode_uint(&entry_enc, entry->module); + err |= cbor_encoder_close_container(enc, &entry_enc); + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + if (out_len != NULL) { + *out_len = cbor_encode_bytes_written(enc); + } + + return 0; +} + +static int +log_mgmt_walk_cb_encode(const struct log_mgmt_entry *entry, void *arg) +{ + struct CborCntWriter cnt_writer; + struct log_walk_ctxt *ctxt; + CborEncoder cnt_encoder; + size_t entry_len; + int rc; + + ctxt = arg; + + /*** First, determine if this entry would fit. */ + + cbor_cnt_writer_init(&cnt_writer); + cbor_encoder_cust_writer_init(&cnt_encoder, &cnt_writer.enc, 0); + rc = log_mgmt_encode_entry(&cnt_encoder, entry, &entry_len); + if (rc != 0) { + return rc; + } + + /* `+ 1` to account for the CBOR array terminator. */ + if (ctxt->rsp_len + entry_len + 1 > LOG_MGMT_CHUNK_SIZE) { + return MGMT_ERR_EMSGSIZE; + } + ctxt->rsp_len += entry_len; + + /*** The entry fits. Now encode it. */ + + rc = log_mgmt_encode_entry(ctxt->enc, entry, NULL); + if (rc != 0) { + return rc; + } + + return 0; +} + +static int +log_encode_entries(const struct log_mgmt_log *log, CborEncoder *enc, + int64_t timestamp, uint32_t index) +{ + struct log_mgmt_filter filter; + struct log_walk_ctxt ctxt; + CborEncoder entries; + CborError err; + int rc; + + err = 0; + err |= cbor_encode_text_stringz(enc, "entries"); + err |= cbor_encoder_create_array(enc, &entries, CborIndefiniteLength); + + filter = (struct log_mgmt_filter) { + .min_timestamp = timestamp, + .min_index = index, + }; + ctxt = (struct log_walk_ctxt) { + .enc = &entries, + .rsp_len = cbor_encode_bytes_written(enc), + }; + + rc = log_mgmt_impl_foreach_entry(log->name, &filter, + log_mgmt_walk_cb_encode, &ctxt); + if (rc != 0 && rc != MGMT_ERR_EMSGSIZE) { + return rc; + } + + err |= cbor_encoder_close_container(enc, &entries); + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + return 0; +} + +static int +log_encode(const struct log_mgmt_log *log, CborEncoder *ctxt, + int64_t timestamp, uint32_t index) +{ + CborEncoder logs; + CborError err; + int rc; + + err = 0; + err |= cbor_encoder_create_map(ctxt, &logs, CborIndefiniteLength); + err |= cbor_encode_text_stringz(&logs, "name"); + err |= cbor_encode_text_stringz(&logs, log->name); + err |= cbor_encode_text_stringz(&logs, "type"); + err |= cbor_encode_uint(&logs, log->type); + + rc = log_encode_entries(log, &logs, timestamp, index); + if (rc != 0) { + return rc; + } + + err |= cbor_encoder_close_container(ctxt, &logs); + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + return 0; +} + +/** + * Command handler: log show + */ +static int +log_mgmt_show(struct mgmt_ctxt *ctxt) +{ + char name[LOG_MGMT_NAME_LEN]; + struct log_mgmt_log log; + CborEncoder logs; + CborError err; + uint64_t index; + int64_t timestamp; + uint32_t next_idx; + int name_len; + int log_idx; + int rc; + + const struct cbor_attr_t attr[] = { + { + .attribute = "log_name", + .type = CborAttrTextStringType, + .addr.string = name, + .len = sizeof(name), + }, + { + .attribute = "ts", + .type = CborAttrIntegerType, + .addr.integer = ×tamp, + }, + { + .attribute = "index", + .type = CborAttrUnsignedIntegerType, + .addr.uinteger = &index, + }, + { + .attribute = NULL, + }, + }; + + name[0] = '\0'; + rc = cbor_read_object(&ctxt->it, attr); + if (rc != 0) { + return MGMT_ERR_EINVAL; + } + name_len = strlen(name); + + /* Determine the index that the next log entry would use. */ + rc = log_mgmt_impl_get_next_idx(&next_idx); + if (rc != 0) { + return MGMT_ERR_EUNKNOWN; + } + + err = 0; + err |= cbor_encode_text_stringz(&ctxt->encoder, "next_index"); + err |= cbor_encode_uint(&ctxt->encoder, next_idx); + + err |= cbor_encode_text_stringz(&ctxt->encoder, "logs"); + err |= cbor_encoder_create_array(&ctxt->encoder, &logs, + CborIndefiniteLength); + + /* Iterate list of logs, encoding each that matches the client request. */ + for (log_idx = 0; ; log_idx++) { + rc = log_mgmt_impl_get_log(log_idx, &log); + if (rc == MGMT_ERR_ENOENT) { + /* Log list fully iterated. */ + if (name_len != 0) { + /* Client specified log name, but the log wasn't found. */ + return MGMT_ERR_ENOENT; + } else { + break; + } + } else if (rc != 0) { + return rc; + } + + /* Stream logs cannot be read. */ + if (log.type != LOG_MGMT_TYPE_STREAM) { + if (name_len == 0 || strcmp(name, log.name) == 0) { + rc = log_encode(&log, &logs, timestamp, index); + if (rc != 0) { + return rc; + } + + /* If the client specified this log, he isn't interested in the + * remaining ones. + */ + if (name_len != 0) { + break; + } + } + } + } + + err |= cbor_encoder_close_container(&ctxt->encoder, &logs); + err |= cbor_encode_text_stringz(&ctxt->encoder, "rc"); + err |= cbor_encode_int(&ctxt->encoder, rc); + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + return 0; +} + +/** + * Command handler: log module_list + */ +static int +log_mgmt_module_list(struct mgmt_ctxt *ctxt) +{ + const char *module_name; + CborEncoder modules; + CborError err; + int module; + int rc; + + err = 0; + err |= cbor_encode_text_stringz(&ctxt->encoder, "rc"); + err |= cbor_encode_int(&ctxt->encoder, MGMT_ERR_EOK); + err |= cbor_encode_text_stringz(&ctxt->encoder, "module_map"); + err |= cbor_encoder_create_map(&ctxt->encoder, &modules, + CborIndefiniteLength); + + for (module = 0; ; module++) { + rc = log_mgmt_impl_get_module(module, &module_name); + if (rc == MGMT_ERR_ENOENT) { + break; + } + if (rc != 0) { + return rc; + } + + if (module_name != NULL) { + err |= cbor_encode_text_stringz(&modules, module_name); + err |= cbor_encode_uint(&modules, module); + } + } + + err |= cbor_encoder_close_container(&ctxt->encoder, &modules); + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + return 0; +} + +/** + * Command handler: log list + */ +static int +log_mgmt_logs_list(struct mgmt_ctxt *ctxt) +{ + struct log_mgmt_log log; + CborEncoder log_list; + CborError err; + int log_idx; + int rc; + + err = 0; + err |= cbor_encode_text_stringz(&ctxt->encoder, "rc"); + err |= cbor_encode_int(&ctxt->encoder, MGMT_ERR_EOK); + err |= cbor_encode_text_stringz(&ctxt->encoder, "log_list"); + err |= cbor_encoder_create_array(&ctxt->encoder, &log_list, + CborIndefiniteLength); + + for (log_idx = 0; ; log_idx++) { + rc = log_mgmt_impl_get_log(log_idx, &log); + if (rc == MGMT_ERR_ENOENT) { + break; + } + if (rc != 0) { + return rc; + } + + if (log.type != LOG_MGMT_TYPE_STREAM) { + err |= cbor_encode_text_stringz(&log_list, log.name); + } + } + + err |= cbor_encoder_close_container(&ctxt->encoder, &log_list); + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + return 0; +} + +/** + * Command handler: log level_list + */ +static int +log_mgmt_level_list(struct mgmt_ctxt *ctxt) +{ + const char *level_name; + CborEncoder level_map; + CborError err; + int level; + int rc; + + err = 0; + err |= cbor_encode_text_stringz(&ctxt->encoder, "rc"); + err |= cbor_encode_int(&ctxt->encoder, MGMT_ERR_EOK); + err |= cbor_encode_text_stringz(&ctxt->encoder, "level_map"); + err |= cbor_encoder_create_map(&ctxt->encoder, &level_map, + CborIndefiniteLength); + + for (level = 0; ; level++) { + rc = log_mgmt_impl_get_level(level, &level_name); + if (rc == MGMT_ERR_ENOENT) { + break; + } + if (rc != 0) { + return rc; + } + + if (level_name != NULL) { + err |= cbor_encode_text_stringz(&level_map, level_name); + err |= cbor_encode_uint(&level_map, level); + } + } + + err |= cbor_encoder_close_container(&ctxt->encoder, &level_map); + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + return 0; +} + +/** + * Command handler: log clear + */ +static int +log_mgmt_clear(struct mgmt_ctxt *ctxt) +{ + struct log_mgmt_log log; + char name[LOG_MGMT_NAME_LEN] = {0}; + int name_len; + int log_idx; + int rc; + + const struct cbor_attr_t attr[] = { + { + .attribute = "log_name", + .type = CborAttrTextStringType, + .addr.string = name, + .len = sizeof(name) + }, + { + .attribute = NULL + }, + }; + + name[0] = '\0'; + rc = cbor_read_object(&ctxt->it, attr); + if (rc != 0) { + return MGMT_ERR_EINVAL; + } + name_len = strlen(name); + + for (log_idx = 0; ; log_idx++) { + rc = log_mgmt_impl_get_log(log_idx, &log); + if (rc == MGMT_ERR_ENOENT) { + return 0; + } + if (rc != 0) { + return rc; + } + + if (log.type != LOG_MGMT_TYPE_STREAM) { + if (name_len == 0 || strcmp(log.name, name) == 0) { + rc = log_mgmt_impl_clear(log.name); + if (rc != 0) { + return rc; + } + + if (name_len != 0) { + return 0; + } + } + } + } + + if (name_len != 0) { + return MGMT_ERR_ENOENT; + } + + return 0; +} + +void +log_mgmt_register_group(void) +{ + mgmt_register_group(&log_mgmt_group); +} diff --git a/cmd/log_mgmt/src/log_mgmt_config.h b/cmd/log_mgmt/src/log_mgmt_config.h new file mode 100644 index 0000000..572fb00 --- /dev/null +++ b/cmd/log_mgmt/src/log_mgmt_config.h @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_LOG_MGMT_CONFIG_ +#define H_LOG_MGMT_CONFIG_ + +#if defined MYNEWT + +#include "syscfg/syscfg.h" + +#define LOG_MGMT_CHUNK_SIZE MYNEWT_VAL(LOG_MGMT_CHUNK_SIZE) +#define LOG_MGMT_NAME_LEN MYNEWT_VAL(LOG_MGMT_NAME_LEN) +#define LOG_MGMT_BODY_LEN MYNEWT_VAL(LOG_MGMT_BODY_LEN) + +#elif defined __ZEPHYR__ + +#define LOG_MGMT_CHUNK_SIZE CONFIG_LOG_MGMT_CHUNK_SIZE +#define LOG_MGMT_NAME_LEN CONFIG_LOG_MGMT_NAME_LEN +#define LOG_MGMT_BODY_LEN CONFIG_LOG_MGMT_BODY_LEN + +#else + +/* No direct support for this OS. The application needs to define the above + * settings itself. + */ + +#endif + +#endif diff --git a/cmd/log_mgmt/src/stubs.c b/cmd/log_mgmt/src/stubs.c new file mode 100644 index 0000000..7ce61cf --- /dev/null +++ b/cmd/log_mgmt/src/stubs.c @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License") you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * These stubs get linked in when there is no equivalent OS-specific + * implementation. + */ + +#include "mgmt/mgmt.h" +#include "log_mgmt/log_mgmt_impl.h" + +int __attribute__((weak)) +log_mgmt_impl_get_log(int idx, struct log_mgmt_log *out_log) +{ + return MGMT_ERR_ENOTSUP; +} + +int __attribute__((weak)) +log_mgmt_impl_get_module(int idx, const char **out_module_name) +{ + return MGMT_ERR_ENOTSUP; +} + +int __attribute__((weak)) +log_mgmt_impl_get_level(int idx, const char **out_level_name) +{ + return MGMT_ERR_ENOTSUP; +} + +int __attribute__((weak)) +log_mgmt_impl_get_next_idx(uint32_t *out_idx) +{ + return MGMT_ERR_ENOTSUP; +} + +int __attribute__((weak)) +log_mgmt_impl_foreach_entry(const char *log_name, + const struct log_mgmt_filter *filter, + log_mgmt_foreach_entry_fn *cb, + void *arg) +{ + return MGMT_ERR_ENOTSUP; +} + +int __attribute__((weak)) +log_mgmt_impl_clear(const char *log_name) +{ + return MGMT_ERR_ENOTSUP; +} diff --git a/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c b/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c index df996a8..20ee5a6 100644 --- a/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c +++ b/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c @@ -21,6 +21,7 @@ #include <misc/reboot.h> #include <debug/object_tracing.h> #include <kernel_structs.h> +#include "logging/reboot_log.h" #include "mgmt/mgmt.h" #include "os_mgmt/os_mgmt.h" #include "os_mgmt/os_mgmt_impl.h" @@ -77,6 +78,7 @@ os_mgmt_impl_task_info(int idx, struct os_mgmt_task_info *out_info) static void zephyr_os_mgmt_reset_work_handler(struct k_work *work) { + reboot_log_write("mcumgr"); sys_reboot(SYS_REBOOT_WARM); } -- To stop receiving notification emails like this one, please contact ccoll...@apache.org.