提交 2292c0fc 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

开始注解Telnet(远程登录)模块

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    鸿蒙研究站 | http://weharmonyos.com (国内)
              | https://weharmony.github.io (国外)
    oschina | https://my.oschina.net/weharmony
    博客园 | https://www.cnblogs.com/weharmony/
    知乎 | https://www.zhihu.com/people/weharmonyos
    csdn | https://blog.csdn.net/kuangyufei
    51cto | https://harmonyos.51cto.com/column/34
    掘金 | https://juejin.cn/user/756888642000808
    公众号 | 鸿蒙研究站 (weharmonyos)
上级 892cf5a7
/*!
* @file trace.c
* @brief 用户态
* @link section3.2 http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-debug-trace.html#section3.2 @endlink
@verbatim
新增trace字符设备,位于"/dev/trace",通过对设备节点的read\write\ioctl,实现用户态trace的读写和控制:
read: 用户态读取Trace记录数据
write: 用户态事件写入
ioctl: 用户态Trace控制操作,包括
#define TRACE_IOC_MAGIC 'T'
#define TRACE_START _IO(TRACE_IOC_MAGIC, 1)
#define TRACE_STOP _IO(TRACE_IOC_MAGIC, 2)
#define TRACE_RESET _IO(TRACE_IOC_MAGIC, 3)
#define TRACE_DUMP _IO(TRACE_IOC_MAGIC, 4)
#define TRACE_SET_MASK _IO(TRACE_IOC_MAGIC, 5)
分别对应Trace启动(LOS_TraceStart)、停止(LOS_TraceStop)、清除记录(LOS_TraceReset)、
dump记录(LOS_TraceRecordDump)、设置事件过滤掩码(LOS_TraceEventMaskSet)
用户态开发流程
通过在menuconfig配置"Driver->Enable TRACE DRIVER",开启Trace驱动。该配置仅在内核Enable Trace Feature后,
才可在Driver的选项中可见。
打开“/dev/trace”字符文件,进行读写和IOCTL操作;
系统提供用户态的trace命令,该命令位于/bin目录下,cd bin 后可执行如下命令:
./trace reset 清除Trace记录
./trace mask num 设置Trace事件过滤掩码
./trace start 启动Trace
./trace stop 停止Trace
./trace dump 0/1 格式化输出Trace记录
./trace read nBytes 读取Trace记录
./trace write type id params... 写用户态事件 如:./trace write 0x1 0x1001 0x2 0x3 则写入一条用户态事件,
其事件类型为0x1, id为0x1001,参数有2个,分别是0x2和0x3.
用户态命令行的典型使用方法如下:
./trace start
./trace write 0x1 0x1001 0x2 0x3
./trace stop
./trace dump 0
@endverbatim
* @version
* @author weharmonyos.com
* @date 2021-11-22
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -40,6 +95,8 @@
#include <sys/mman.h>
#include <stdint.h>
//分别对应Trace启动(LOS_TraceStart)、停止(LOS_TraceStop)、清除记录(LOS_TraceReset)、
//dump记录(LOS_TraceRecordDump)、设置事件过滤掩码(LOS_TraceEventMaskSet)
#define TRACE_IOC_MAGIC 'T'
#define TRACE_START _IO(TRACE_IOC_MAGIC, 1)
#define TRACE_STOP _IO(TRACE_IOC_MAGIC, 2)
......@@ -98,6 +155,32 @@ static void TraceWrite(int fd, int argc, char **argv)
(void)write(fd, &info, sizeof(UsrEventInfo));
}
/*!
* @brief main 用户态示例代码功能如下:
@verbatim
1. 打开trace字符设备。
2. 设置事件掩码。
3. 启动trace。
4. 写trace事件。
5. 停止trace。
6. 格式化输出trace数据。
7. 输出结果
*******TraceInfo begin*******
clockFreq = 50000000
CurEvtIndex = 2
Index Time(cycles) EventType CurTask Identity params
0 0x366d5e88 0xfffffff1 0x1 0x1 0x1 0x2 0x3
1 0x366d74ae 0xfffffff2 0x1 0x2 0x1 0x2 0x3
*******TraceInfo end*******
示例代码中调用了2次write,对应产生2条Trace记录; 用户层事件的EventType高28位固定均为1(即0xfffffff0),
仅低4位表示具体的事件类型。
@endverbatim
* @param argc
* @param argv
* @return
*
* @see
*/
int main(int argc, char **argv)
{
int fd = open("/dev/trace", O_RDWR);
......
......@@ -87,8 +87,8 @@ struct Mount {
* @brief 挂载操作
*/
struct MountOps {
int (*Mount)(struct Mount *mount, struct Vnode *vnode, const void *data); ///< 挂载
int (*Unmount)(struct Mount *mount, struct Vnode **blkdriver); ///< 卸载
int (*Mount)(struct Mount *mount, struct Vnode *vnode, const void *data); ///< 挂载分区
int (*Unmount)(struct Mount *mount, struct Vnode **blkdriver); ///< 卸载分区
int (*Statfs)(struct Mount *mount, struct statfs *sbp); ///< 统计文件系统的信息,如该文件系统类型、总大小、可用大小等信息
int (*Sync)(struct Mount *mount); ///< 同步挂载
};
......
/*!
* @file vfs_jffs2.c
* @brief
* @link jffs2 http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-bundles-fs-support-jffs2.html @endlink
@verbatim
基本概念
JFFS2是Journalling Flash File System Version 2(日志文件系统)的缩写,是针对MTD设备的日志型文件系统。
OpenHarmony内核的JFFS2主要应用于NOR FLASH闪存,其特点是:可读写、支持数据压缩、提供了崩溃/掉电安全保护、
提供“写平衡”支持等。闪存与磁盘介质有许多差异,直接将磁盘文件系统运行在闪存设备上,会导致性能和安全问题。
为解决这一问题,需要实现一个特别针对闪存的文件系统,JFFS2就是这样一种文件系统。
运行机制
关于JFFS2文件系统的在存储设备上的实际物理布局,及文件系统本身的规格说明,请参考JFFS2的官方规格说明文档。
https://sourceware.org/jffs2/
这里仅列举几个对开发者和使用者会有一定影响的JFFS2的重要机制/特征:
1. Mount机制及速度问题:按照JFFS2的设计,所有的文件会按照一定的规则,切分成大小不等的节点,
依次存储到flash设备上。在mount流程中,需要获取到所有的这些节点信息并缓存到内存里。
因此,mount速度和flash设备的大小和文件数量的多少成线性比例关系。这是JFFS2的原生设计问题,
对于mount速度非常介意的用户,可以在内核编译时开启“Enable JFFS2 SUMMARY”选项,可以极大提升mount的速度。
这个选项的原理是将mount需要的信息提前存储到flash上,在mount时读取并解析这块内容,使得mount的速度变得相对恒定。
这个实际是空间换时间的做法,会消耗8%左右的额外空间。
2. 写平衡的支持:由于flash设备的物理属性,读写都只能基于某个特定大小的“块”进行,为了防止某些特定的块磨损过于严重,
在JFFS2中需要对写入的块进行“平衡”的管理,保证所有的块的写入次数都是相对平均的,进而保证flash设备的整体寿命。
3. GC(garbage collection)机制:在JFFS2里发生删除动作,实际的物理空间并不会立即释放,而是由独立的GC线程来做
空间整理和搬移等GC动作,和所有的GC机制一样,在JFFS2里的GC会对瞬时的读写性能有一定影响。另外,为了有空间能
被用来做空间整理,JFFS2会对每个分区预留3块左右的空间,这个空间是用户不可见的。
4. 压缩机制:当前使用的JFFS2,底层会自动的在每次读/写时进行解压/压缩动作,实际IO的大小和用户请求读写的大小
并不会一样。特别在写入时,不能通过写入大小来和flash剩余空间的大小来预估写入一定会成功或者失败。
5. 硬链接机制:JFFS2支持硬链接,底层实际占用的物理空间是一份,对于同一个文件的多个硬连接,并不会增加空间的占用;
反之,只有当删除了所有的硬链接时,实际物理空间才会被释放。
开发指导
对于基于JFFS2和nor flash的开发,总体而言,与其他文件系统非常相似,因为都有VFS层来屏蔽了具体文件系统的差异,
对外接口体现也都是标准的POSIX接口。
对于整个裸nor flash设备而言,没有集中的地方来管理和记录分区的信息。因此,需要通过其他的配置方式来传递这部分信息
(当前使用的方式是在烧写镜像的时候,使用bootargs参数配置的),然后在代码中调用相应的接口来添加分区,再进行挂载动作。
@endverbatim
* @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-22
*/
/*
* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved.
*
......@@ -54,49 +97,29 @@
#include "os-linux.h"
#include "jffs2/nodelist.h"
/*************************************************************
JFFS2 直接在闪存上提供文件系统,而不是模拟块设备。
JFFS2是Journalling Flash File System Version 2(日志文件系统)的缩写,是MTD设备上实现的日志型文件系统。
JFFS2主要应用于NOR FLASH,其特点是:可读写、支持数据压缩、提供了崩溃/掉电安全保护、提供“写平衡”支持等。
闪存与磁盘介质有许多差异,因此直接将磁盘文件系统运行在闪存上存在性能和安全性上的不足。
为解决这一问题,需要实现一个特别针对闪存的文件系统,JFFS2就是这样一种文件系统。
OpenHarmony内核的JFFS2主要应用于对NOR Flash闪存的文件管理,并且支持多分区。
添加JFFS2分区
调用 add_mtd_partition 函数添加JFFS2分区,该函数会自动为设备节点命名,对于JFFS2,其命名规则是“/dev/spinorblk”加上分区号。
add_mtd_partition函数有四个参数,第一个参数表示介质,有“nand”和“spinor”两种,
JFFS2分区在“spinor”上使用,而“nand”是提供给YAFFS2使用的。
第二个参数表示起始地址,第三个参数表示分区大小,这两个参数都以16进制的形式传入。
最后一个参数表示分区号,有效值为0~19。
*************************************************************/
#ifdef LOSCFG_FS_JFFS
/* forward define */
struct VnodeOps g_jffs2Vops;//vnode操作接口实现
struct file_operations_vfs g_jffs2Fops;//vfs接口实现
struct VnodeOps g_jffs2Vops;///< jffs2 关于vnode操作接口实现
struct file_operations_vfs g_jffs2Fops;///< jffs2 关于vfs接口实现
static LosMux g_jffs2FsLock; /* lock for all jffs2 ops *///操作 jffs2文件系统锁
static LosMux g_jffs2FsLock; /* lock for all jffs2 ops | 操作 jffs2文件系统锁*/
static pthread_mutex_t g_jffs2NodeLock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
struct Vnode *g_jffs2PartList[CONFIG_MTD_PATTITION_NUM];//jffs2 分区列表
//设置vnode节点的文件类型
struct Vnode *g_jffs2PartList[CONFIG_MTD_PATTITION_NUM]; ///< jffs2 分区列表
/// 设置vnode节点的文件类型
static void Jffs2SetVtype(struct jffs2_inode *node, struct Vnode *pVnode)
{
switch (node->i_mode & S_IFMT) {
case S_IFREG:
pVnode->type = VNODE_TYPE_REG;
pVnode->type = VNODE_TYPE_REG; // 普通文件
break;
case S_IFDIR:
pVnode->type = VNODE_TYPE_DIR;
pVnode->type = VNODE_TYPE_DIR; // 目录/文件夹
break;
case S_IFLNK:
pVnode->type = VNODE_TYPE_LNK;
pVnode->type = VNODE_TYPE_LNK; // 软链接
break;
default:
pVnode->type = VNODE_TYPE_UNKNOWN;
......@@ -122,6 +145,23 @@ void Jffs2NodeUnlock(void)
(void)pthread_mutex_unlock(&g_jffs2NodeLock);
}
/*!
* @brief VfsJffs2Bind 挂载JFFS2分区
@verbatim
运行命令:
OHOS # mount /dev/spinorblk1 /jffs1 jffs2
将从串口得到如下回应信息,表明挂载成功。
OHOS # mount /dev/spinorblk1 /jffs1 jffs2
mount OK
挂载成功后,用户就能对norflash进行读写操作。
@endverbatim
* @param blkDriver
* @param data
* @param mnt
* @return
*
* @see
*/
int VfsJffs2Bind(struct Mount *mnt, struct Vnode *blkDriver, const void *data)
{
int ret;
......@@ -132,8 +172,8 @@ int VfsJffs2Bind(struct Mount *mnt, struct Vnode *blkDriver, const void *data)
struct jffs2_inode *rootNode = NULL;
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
p = (mtd_partition *)((struct drv_data *)blkDriver->data)->priv;
mtd = (struct MtdDev *)(p->mtd_info);
p = (mtd_partition *)((struct drv_data *)blkDriver->data)->priv; //分区结构
mtd = (struct MtdDev *)(p->mtd_info);//分区信息
/* find a empty mte in partition table */
if (mtd == NULL || mtd->type != MTD_NORFLASH) {
......@@ -154,7 +194,7 @@ int VfsJffs2Bind(struct Mount *mnt, struct Vnode *blkDriver, const void *data)
LOS_MuxUnlock(&g_jffs2FsLock);
goto ERROR_WITH_VNODE;
}
pv->type = VNODE_TYPE_DIR;
pv->type = VNODE_TYPE_DIR;
pv->data = (void *)rootNode;
pv->originMount = mnt;
pv->fop = &g_jffs2Fops;
......@@ -175,6 +215,22 @@ ERROR_WITH_VNODE:
return ret;
}
/*!
* @brief VfsJffs2Unbind 卸载JFFS2分区
@verbatim
调用int umount(const char *target)函数卸载分区,只需要正确给出挂载点即可。
运行命令:
OHOS # umount /jffs1
将从串口得到如下回应信息,表明卸载成功。
OHOS # umount /jffs1
umount ok
@endverbatim
* @param blkDriver
* @param mnt
* @return
*
* @see
*/
int VfsJffs2Unbind(struct Mount *mnt, struct Vnode **blkDriver)
{
int ret;
......@@ -966,8 +1022,8 @@ void Jffs2MutexDelete(void)
}
const struct MountOps jffs_operations = {//jffs对mount接口实现
.Mount = VfsJffs2Bind, //mount()函数实现设备节点和挂载点的挂载。
.Unmount = VfsJffs2Unbind,
.Mount = VfsJffs2Bind, //挂载JFFS2分区
.Unmount = VfsJffs2Unbind, //卸载JFFS2分区
.Statfs = VfsJffs2Statfs,
};
//jffs2 节点视角的操作实现
......
......@@ -355,7 +355,7 @@ static void VnodeTryFreeAll(struct Mount *mount)
VnodeTryFree(vnode);
}
}
/// 强制卸载挂载点
int ForceUmountDev(struct Vnode *dev)
{
int ret;
......
/*!
* @file vfs_init.c
* @brief
* @link vfs http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-bundles-fs-virtual.html @endlink
@verbatim
VFS是Virtual File System(虚拟文件系统)的缩写,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合层,
为用户提供统一的类Unix文件操作接口。
由于不同类型的文件系统接口不统一,若系统中有多个文件系统类型,访问不同的文件系统就需要使用不同的非标准接口。
而通过在系统中添加VFS层,提供统一的抽象接口,屏蔽了底层异构类型的文件系统的差异,使得访问文件系统的系统调用不用
关心底层的存储介质和文件系统类型,提高开发效率。
OpenHarmony内核中,VFS框架是通过在内存中的树结构来实现的,树的每个结点都是一个inode结构体。
设备注册和文件系统挂载后会根据路径在树中生成相应的结点。VFS最主要是两个功能:
查找节点。
统一调用(标准)。
@endverbatim
* @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-22
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -42,25 +65,7 @@
#include "unistd.h"
#include "vnode.h"
/**
* @file vfs_init.c
* @brief
* @verbatim
VFS是Virtual File System(虚拟文件系统)的缩写,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合层,
为用户提供统一的类Unix文件操作接口。
由于不同类型的文件系统接口不统一,若系统中有多个文件系统类型,访问不同的文件系统就需要使用不同的非标准接口。
而通过在系统中添加VFS层,提供统一的抽象接口,屏蔽了底层异构类型的文件系统的差异,使得访问文件系统的系统调用不用
关心底层的存储介质和文件系统类型,提高开发效率。
OpenHarmony内核中,VFS框架是通过在内存中的树结构来实现的,树的每个结点都是一个inode结构体。
设备注册和文件系统挂载后会根据路径在树中生成相应的结点。VFS最主要是两个功能:
查找节点。
统一调用(标准)。
http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/VFS.html
* @endverbatim
*/
void los_vfs_init(void)//只能调用一次,多次调用将会造成文件系统异常
{
......
......@@ -131,7 +131,7 @@ int osShellCmdDoChdir(const char *path)
return 0;
}
/**
* @brief
* @brief 添加内置命令 ls
* @verbatim
命令功能
ls命令用来显示当前目录的内容。
......@@ -149,8 +149,8 @@ int osShellCmdDoChdir(const char *path)
ls可以显示文件的大小。
proc下ls无法统计文件大小,显示为0。
* @endverbatim
* @param argc
* @param argv
* @param argc Shell命令中,参数个数。
* @param argv 为指针数组,每个元素指向一个字符串,可以根据选择命令类型,决定是否要把命令关键字传入给注册函数。
* @return int
*/
int osShellCmdLs(int argc, const char **argv)
......
......@@ -266,7 +266,7 @@ STATIC VOID LOS_TraceUsrEvent(VOID *buffer, UINT32 len)
LOS_MemFree(m_aucSysMem0, buffer);
#endif
}
///< 为输出日志而注册的钩子函数 ,谁能告诉我 cnv 是啥意思? @note_thinking
///< 将事件的钩子函数注册进HOOK框架 ,但谁能告诉我 cnv 是啥意思? @note_thinking
VOID OsTraceCnvInit(VOID)
{
LOS_HookReg(LOS_HOOK_TYPE_MEM_ALLOC, LOS_TraceMemAlloc);
......@@ -291,19 +291,19 @@ VOID OsTraceCnvInit(VOID)
LOS_HookReg(LOS_HOOK_TYPE_MUX_POST, LOS_TraceMuxPost);
LOS_HookReg(LOS_HOOK_TYPE_MUX_PEND, LOS_TraceMuxPend);
LOS_HookReg(LOS_HOOK_TYPE_MUX_DELETE, LOS_TraceMuxDelete);
LOS_HookReg(LOS_HOOK_TYPE_TASK_PRIMODIFY, LOS_TraceTaskPriModify); ///< 修改任务优先级
LOS_HookReg(LOS_HOOK_TYPE_TASK_DELETE, LOS_TraceTaskDelete); ///< 删除任务
LOS_HookReg(LOS_HOOK_TYPE_TASK_CREATE, LOS_TraceTaskCreate); ///< 创建任务
LOS_HookReg(LOS_HOOK_TYPE_TASK_SWITCHEDIN, LOS_TraceTaskSwitchedIn); ///< 任务切换中
LOS_HookReg(LOS_HOOK_TYPE_MOVEDTASKTOREADYSTATE, LOS_TraceTaskResume); ///< 恢复任务
LOS_HookReg(LOS_HOOK_TYPE_MOVEDTASKTOSUSPENDEDLIST, LOS_TraceTaskSuspend);///< 暂停任务
LOS_HookReg(LOS_HOOK_TYPE_ISR_ENTER, LOS_TraceIsrEnter); ///< 进入中断
LOS_HookReg(LOS_HOOK_TYPE_ISR_EXIT, LOS_TraceIsrExit); ///< 完成中断
LOS_HookReg(LOS_HOOK_TYPE_SWTMR_CREATE, LOS_TraceSwtmrCreate); ///< 创建定时器
LOS_HookReg(LOS_HOOK_TYPE_SWTMR_DELETE, LOS_TraceSwtmrDelete); ///< 删除定时器
LOS_HookReg(LOS_HOOK_TYPE_SWTMR_EXPIRED, LOS_TraceSwtmrExpired); ///< 定时器时间到
LOS_HookReg(LOS_HOOK_TYPE_SWTMR_START, LOS_TraceSwtmrStart); ///< 启动定时器
LOS_HookReg(LOS_HOOK_TYPE_SWTMR_STOP, LOS_TraceSwtmrStop); ///< 停止定时器
LOS_HookReg(LOS_HOOK_TYPE_TASK_PRIMODIFY, LOS_TraceTaskPriModify); // 修改任务优先级
LOS_HookReg(LOS_HOOK_TYPE_TASK_DELETE, LOS_TraceTaskDelete); // 删除任务
LOS_HookReg(LOS_HOOK_TYPE_TASK_CREATE, LOS_TraceTaskCreate); // 创建任务
LOS_HookReg(LOS_HOOK_TYPE_TASK_SWITCHEDIN, LOS_TraceTaskSwitchedIn); // 任务切换中
LOS_HookReg(LOS_HOOK_TYPE_MOVEDTASKTOREADYSTATE, LOS_TraceTaskResume); // 恢复任务
LOS_HookReg(LOS_HOOK_TYPE_MOVEDTASKTOSUSPENDEDLIST, LOS_TraceTaskSuspend);// 暂停任务
LOS_HookReg(LOS_HOOK_TYPE_ISR_ENTER, LOS_TraceIsrEnter); // 进入中断
LOS_HookReg(LOS_HOOK_TYPE_ISR_EXIT, LOS_TraceIsrExit); // 完成中断
LOS_HookReg(LOS_HOOK_TYPE_SWTMR_CREATE, LOS_TraceSwtmrCreate); // 创建定时器
LOS_HookReg(LOS_HOOK_TYPE_SWTMR_DELETE, LOS_TraceSwtmrDelete); // 删除定时器
LOS_HookReg(LOS_HOOK_TYPE_SWTMR_EXPIRED, LOS_TraceSwtmrExpired); // 定时器时间到
LOS_HookReg(LOS_HOOK_TYPE_SWTMR_START, LOS_TraceSwtmrStart); // 启动定时器
LOS_HookReg(LOS_HOOK_TYPE_SWTMR_STOP, LOS_TraceSwtmrStop); // 停止定时器
LOS_HookReg(LOS_HOOK_TYPE_USR_EVENT, LOS_TraceUsrEvent);
LOS_HookReg(LOS_HOOK_TYPE_IPC_WRITE_DROP, LOS_TraceIpcWriteDrop);
LOS_HookReg(LOS_HOOK_TYPE_IPC_WRITE, LOS_TraceIpcWrite);
......
......@@ -331,7 +331,7 @@ STATIC UINT32 OsTraceInit(VOID)
#endif
OsTraceHookInstall();//安装HOOK框架
OsTraceCnvInit();
OsTraceCnvInit();//将事件处理函数注册到HOOK框架
g_traceEventCount = 0;
......
......@@ -59,7 +59,7 @@ extern "C" {
*
* The task is automatically deleted.
*/
#define LOS_TASK_STATUS_DETACHED 0x0U
#define LOS_TASK_STATUS_DETACHED 0x0U //独立模式,自动删除
/**
* @ingroup los_task
......@@ -67,7 +67,7 @@ extern "C" {
*
* The task is joinable.
*/
#define LOS_TASK_ATTR_JOINABLE 0x80000000
#define LOS_TASK_ATTR_JOINABLE 0x80000000 //联合模式,可由其他任务删除
/**
* @ingroup los_task
......
......@@ -41,11 +41,11 @@ extern "C" {
#endif /* __cplusplus */
#ifdef LOSCFG_NET_TELNET
#define TELNETD_PORT 23
#define TELNET_KEEPALIVE 1
#define TELNET_KEEPIDLE 60
#define TELNET_KEEPINTV 2
#define TELNET_KEEPCNT 5
#define TELNETD_PORT 23 ///< telnet 端口,默认 23
#define TELNET_KEEPALIVE 1 ///< 保持链接
#define TELNET_KEEPIDLE 60 ///<
#define TELNET_KEEPINTV 2 ///<
#define TELNET_KEEPCNT 5 ///< 重连次数
extern INT32 TelnetCmd(UINT32 argc, const CHAR **argv);
#endif
......
/*!
* @file telnet_loop.c
* @brief
* @link
@verbatim
telnet命令通常用来远程登录。telnet程序是基于TELNET协议的远程登录客户端程序。Telnet协议是TCP/IP协议族中的一员,
是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的 能力。
在终端使用者的电脑上使用telnet程序,用它连接到服务器。终端使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,
就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。要开始一个 telnet会话,必须输入用户名和密码来登录服务器。
Telnet是常用的远程控制Web服务器的方法。
但是,telnet因为采用明文传送报文,安全性不好,很多Linux服务器都不开放telnet服务,而改用更安全的ssh方式了。
但仍然有很多别的系统可能采用了telnet方式来提供远程登录,因此弄清楚telnet客户端的使用方式仍是很有必要的。
telnet命令还可做别的用途,比如确定远程服务的状态,比如确定远程服务器的某个端口是否能访问。
@endverbatim
* @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-22
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -71,14 +92,14 @@
#define LEN_IAC_CMD_NAWS 9 /* NAWS: |IAC|SB|NAWS|x1|x2|x3|x4|IAC|SE| */
/* server/client settings */
#define TELNET_TASK_STACK_SIZE 0x2000
#define TELNET_TASK_PRIORITY 9
#define TELNET_TASK_STACK_SIZE 0x2000 ///< 内核栈大小 8K
#define TELNET_TASK_PRIORITY 9 ///< telnet 任务优先级
/* server settings */
/* server settings | 服务端设置*/
#define TELNET_LISTEN_BACKLOG 128
#define TELNET_ACCEPT_INTERVAL 200
/* client settings */
/* client settings | 客户端设置*/
#define TELNET_CLIENT_POLL_TIMEOUT 2000
#define TELNET_CLIENT_READ_BUF_SIZE 256
#define TELNET_CLIENT_READ_FILTER_BUF_SIZE (8 * 1024)
......@@ -90,9 +111,9 @@ STATIC volatile INT32 g_telnetClientFd = -1; /* client fd */
STATIC volatile INT32 g_telnetListenFd = -1; /* listen fd of telnetd */
/* each bit for a client connection, although only support 1 connection for now */
STATIC volatile UINT32 g_telnetMask = 0;
STATIC volatile UINT32 g_telnetMask = 0; //掩码
/* taskID of telnetd */
STATIC atomic_t g_telnetTaskId = 0;
STATIC atomic_t g_telnetTaskId = 0; ///< 任务ID
/* protect listenFd, clientFd etc. */
pthread_mutex_t g_telnetMutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
......@@ -289,7 +310,7 @@ ERR_CLOSE_FD:
ERR_OUT:
return -1;
}
/// 远程登录客户端准备阶段
STATIC INT32 TelnetClientPrepare(INT32 clientFd)
{
INT32 keepAlive = TELNET_KEEPALIVE;
......@@ -480,17 +501,26 @@ STATIC VOID TelnetdAcceptLoop(INT32 listenFd)
TelnetUnlock();
}
/*!
* @brief TelnetdMain
* 输入 telnet on
OHOS # telnet on
OHOS # start telnet server successfully, waiting for connection.
* @return
*
* @see
*/
STATIC INT32 TelnetdMain(VOID)
{
INT32 sock;
INT32 ret;
//1.初始化
sock = TelnetdInit(TELNETD_PORT);
if (sock == -1) {
PRINT_ERR("telnet init error.\n");
return -1;
}
//2.注册
TelnetLock();
ret = TelnetedRegister();
TelnetUnlock();
......@@ -500,7 +530,7 @@ STATIC INT32 TelnetdMain(VOID)
(VOID)close(sock);
return -1;
}
//3.接收
PRINTK("start telnet server successfully, waiting for connection.\n");
TelnetdAcceptLoop(sock);
return 0;
......@@ -509,30 +539,39 @@ STATIC INT32 TelnetdMain(VOID)
/*
* Try to create telnetd task.
*/
/*!
* @brief TelnetdTaskInit 创建 telnet 任务
* \n 1. telnet启动要确保网络驱动及网络协议栈已经初始化完成,且板子的网卡是link up状态。
* \n 2. 暂时无法支持多个客户端(telnet + IP)同时连接开发板。
\n 须知: telnet属于调测功能,默认配置为关闭,正式产品中禁止使用该功能。
* @return
*
* @see
*/
STATIC VOID TelnetdTaskInit(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S initParam = {0};
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)TelnetdMain;
initParam.uwStackSize = TELNET_TASK_STACK_SIZE;
initParam.pcName = "TelnetServer";
initParam.usTaskPrio = TELNET_TASK_PRIORITY;
initParam.uwResved = LOS_TASK_STATUS_DETACHED;
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)TelnetdMain; // telnet任务入口函数
initParam.uwStackSize = TELNET_TASK_STACK_SIZE; // 8K
initParam.pcName = "TelnetServer"; //任务名称
initParam.usTaskPrio = TELNET_TASK_PRIORITY; //优先级 9,和 shell 的优先级一样
initParam.uwResved = LOS_TASK_STATUS_DETACHED; //独立模式
if (atomic_read(&g_telnetTaskId) != 0) {
PRINT_ERR("telnet server is already running!\n");
return;
}
ret = LOS_TaskCreate((UINT32 *)&g_telnetTaskId, &initParam);
ret = LOS_TaskCreate((UINT32 *)&g_telnetTaskId, &initParam);//创建远程登录任务并发起调度
if (ret != LOS_OK) {
PRINT_ERR("failed to create telnet server task!\n");
}
}
/*
* Try to destroy telnetd task.
* Try to destroy telnetd task. | 销毁,删除远程登录任务
*/
STATIC VOID TelnetdTaskDeinit(VOID)
{
......@@ -546,7 +585,7 @@ STATIC VOID TelnetdTaskDeinit(VOID)
TelnetdDeinit();
TelnetUnlock();
}
/// 远程登录用法 telnet [on | off]
STATIC VOID TelnetUsage(VOID)
{
PRINTK("Usage: telnet [OPTION]...\n");
......@@ -554,7 +593,7 @@ STATIC VOID TelnetUsage(VOID)
PRINTK(" on Init the telnet server\n");
PRINTK(" off Deinit the telnet server\n");
}
/// 远程登录命令处理
INT32 TelnetCmd(UINT32 argc, const CHAR **argv)
{
if (argc != 1) {
......@@ -578,7 +617,7 @@ INT32 TelnetCmd(UINT32 argc, const CHAR **argv)
}
#ifdef LOSCFG_SHELL_CMD_DEBUG
SHELLCMD_ENTRY(telnet_shellcmd, CMD_TYPE_EX, "telnet", 1, (CmdCallBackFunc)TelnetCmd);
SHELLCMD_ENTRY(telnet_shellcmd, CMD_TYPE_EX, "telnet", 1, (CmdCallBackFunc)TelnetCmd);/// 以静态方式注册shell 命令
#endif /* LOSCFG_SHELL_CMD_DEBUG */
#endif
/*!
* @file shell.h
* @brief Shell命令开发指导
* @link
@verbatim
OpenHarmony内核提供的Shell支持调试常用的基本功能,包含系统、文件、网络和动态加载相关命令。
同时OpenHarmony内核的Shell支持添加新的命令,可以根据需求来进行定制。
系统相关命令:提供查询系统任务、内核信号量、系统软件定时器、CPU占用率、当前中断等相关信息的能力。
文件相关命令:支持基本的ls、cd等功能。
网络相关命令:支持查询接到开发板的其他设备的IP、查询本机IP、测试网络连接、设置开发板的AP和station模式等相关功能。
在使用Shell功能的过程中,需要注意以下几点:
Shell功能支持使用exec命令来运行可执行文件。
Shell功能支持默认模式下英文输入。如果出现用户在UTF-8格式下输入了中文字符的情况,只能通过回退三次来删除。
Shell功能支持shell命令、文件名及目录名的Tab键联想补全。若有多个匹配项,则根据共同字符, 打印多个匹配项。
对于过多的匹配项(打印多于24行),将会进行打印询问(Display all num possibilities?(y/n)),
用户可输入y选择全部打印,或输入n退出打印,选择全部打印并打印超过24行后,会进行--More--提示,
此时按回车键继续打印,按q键退出(支持Ctrl+c退出)。
Shell端工作目录与系统工作目录是分开的,即通过Shell端cd pwd等命令是对Shell端工作目录进行操作,
通过chdir getcwd等命令是对系统工作目录进行操作,两个工作目录相互之间没有联系。当文件系统操作命令入参是相对路径时要格外注意。
在使用网络Shell指令前,需要先调用tcpip_init函数完成网络初始化并完成telnet连接后才能起作用,内核默认不初始化tcpip_init。
不建议使用Shell命令对/dev目录下的设备文件进行操作,这可能会引起不可预知的结果。
输入Shell命令,有两种输入方式:
1. 在串口工具中直接输入Shell命令。
2. 在telnet工具中输入Shell命令(telnet使用方式详见telnet)。
http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-debug-shell-net-telnet.html
@endverbatim
* @attention
Shell功能不符合POSIX标准,仅供调试使用。
Shell功能仅供调试使用,在Debug版本中开启(使用时通过menuconfig在配置项中开启"LOSCFG_DEBUG_VERSION"编译开关进行相关控制),
商用产品中禁止包含该功能。
* @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-22
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -60,17 +106,17 @@ extern "C" {
#define XARGS 0xFFFFFFFF /* default args */
#define CMD_MAX_PARAS 32 //命令参数最大个数
#define CMD_KEY_LEN 16U //关键字长度 例如: 'ls'的长度为2
#define CMD_MAX_PARAS 32 ///< 命令参数最大个数
#define CMD_KEY_LEN 16U ///< 关键字长度 例如: 'ls'的长度为2
#define CMD_MAX_LEN (256U + CMD_KEY_LEN)
#define CMD_KEY_NUM 32 //
#define CMD_HISTORY_LEN 10 //历史记录数量
#define CMD_MAX_PATH 256 //最大路径
#define DEFAULT_SCREEN_WIDTH 80 //屏幕的宽
#define DEFAULT_SCREEN_HEIGHT 24 //屏幕的高
#define CMD_HISTORY_LEN 10 ///< 历史记录数量
#define CMD_MAX_PATH 256 ///< 最大路径
#define DEFAULT_SCREEN_WIDTH 80 ///< 屏幕的宽
#define DEFAULT_SCREEN_HEIGHT 24 ///< 屏幕的高
#define SHELL_MODE 0 //shell模式
#define OTHER_MODE 1 //其他模式
#define SHELL_MODE 0 ///< shell模式
#define OTHER_MODE 1 ///< 其他模式
#define SWITCH_QUOTES_STATUS(qu) do { \
if ((qu) == TRUE) { \
......
......@@ -41,19 +41,19 @@
#include "los_typedef.h"
#define SHELL_INIT_MAGIC_FLAG 0xABABABAB //shell的魔法数字
#define SHELL_INIT_MAGIC_FLAG 0xABABABAB ///< shell的魔法数字
#define CTRL_C 0x03 /* 0x03: ctrl+c ASCII */
STATIC CmdModInfo g_cmdInfo;//shell 命令模块信息,上面挂了所有的命令项(ls,cd ,cp ==)
STATIC CmdModInfo g_cmdInfo; ///< shell 命令模块信息,上面挂了所有的命令项(ls,cd ,cp ==)
LOS_HAL_TABLE_BEGIN(g_shellcmd, shellcmd);
LOS_HAL_TABLE_END(g_shellcmdEnd, shellcmd);
//获取全局变量
/// 获取全局变量
CmdModInfo *OsCmdInfoGet(VOID)
{
return &g_cmdInfo;
}
///释放命令行参数所占内存
/// 释放命令行参数所占内存
STATIC VOID OsFreeCmdPara(CmdParsed *cmdParsed)
{
UINT32 i;
......@@ -151,7 +151,7 @@ STATIC INT32 OsStrSeparate(CHAR *tabStr, CHAR *strPath, CHAR *nameLooking, UINT3
OsFreeCmdPara(&parsed);
return LOS_OK;
}
///输出内容
/// 输出内容
STATIC INT32 OsShowPageInputControl(VOID)
{
CHAR readChar;
......@@ -837,7 +837,22 @@ STATIC UINT32 OsCmdItemCreate(CmdType cmdType, const CHAR *cmdKey, UINT32 paraNu
return LOS_OK;
}
/* open API */ //以动态方式注册命令
/* open API */
/*!
* @brief osCmdReg 以动态方式注册命令
*
* @param cmdKey 命令关键字,函数在Shell中访问的名称。
* @param cmdProc 命令执行函数地址,即命令实际执行函数。
* @param cmdType CMD_TYPE_EX:不支持标准命令参数输入,会把用户填写的命令关键字屏蔽掉,
例如:输入ls /ramfs,传入给注册函数的参数只有/ramfs,而ls命令关键字并不会被传入。
CMD_TYPE_STD:支持的标准命令参数输入,所有输入的字符都会通过命令解析后被传入。
* @param paraNum 调用的执行函数的入参最大个数,暂不支持该参数;当前为默认值XARGS(0xFFFFFFFF)。
* @attention 命令关键字必须是唯一的,也即两个不同的命令项不能拥有相同的命令关键字,否则只会执行其中一个。
Shell在执行用户命令时,如果存在多个命令关键字相同的命令,只会执行其中在"help"命令中排序在最前面的一个。
* @return
*
* @see
*/
LITE_OS_SEC_TEXT_MINOR UINT32 osCmdReg(CmdType cmdType, const CHAR *cmdKey, UINT32 paraNum, CmdCallBackFunc cmdProc)
{
CmdItemNode *cmdItemNode = NULL;
......@@ -876,6 +891,6 @@ LITE_OS_SEC_TEXT_MINOR UINT32 osCmdReg(CmdType cmdType, const CHAR *cmdKey, UINT
}
(VOID)LOS_MuxUnlock(&g_cmdInfo.muxLock);
//5.正式创建命令,挂入链表
return OsCmdItemCreate(cmdType, cmdKey, paraNum, cmdProc);//不存在就注册命令
return OsCmdItemCreate(cmdType, cmdKey, paraNum, cmdProc);
}
git add -A
git commit -m ' trace模块分离线和在线两种模式,详细注解其实现细节
git commit -m ' 开始注解Telnet(远程登录)模块
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
鸿蒙研究站 | http://weharmonyos.com (国内)
| https://weharmony.github.io (国外)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册