首页 > 系统相关 >14_Linux 设备树

14_Linux 设备树

时间:2024-04-25 22:48:01浏览次数:24  
标签:node struct Linux 14 device printk 节点 设备

一.什么是设备树?

设备树是一种描述硬件资源的数据结构。它通过bootloader将硬件资源传给内核,使得内核和硬件资源描述相对独立。

有了初步概念之后,我们再来一起探讨设备树的起源。

二.设备树的由来

要想了解为什么会有设备树,设备树是怎么来的,我们就要先来回顾一下在没有设备树之前我们是怎么来写一个驱动程序的。以字符设备驱动代码框架为例,我们一起来回顾下。

任何的设备驱动的编写,Linux已经为我们打好了框架,我们只要像做完形填空一样填写进去就可以了。

字符设备驱动框架:

img

杂项设备驱动框架:

img

通过这些框架,我们可以很容易编写我们的驱动代码,但是,当我们用这个框架非常熟练的时候,我们就会发现虽然这个方法很简单,但是非常不容易扩展,当我们有很多很多相似设备的时候,如果我们都是按照这个框架来完成,那就要写很多遍这个流程,但是多个相似设备之间真正有差异的地方只有框架的第四步,也就是初始化硬件的部分,其他步骤的代码基本都是一样的。这样就会造成大量的重复代码。但是,我们在编写驱动代码的时候,我们要尽量做到代码的复用,也就是一套驱动尽量可以兼任很多设备,如果我们还按照这个来编写就不太符合我们的规则了。

为了实现这个目标,我们就要把通用的代码和有差异的代码分离出来,来增强我们驱动代码的可移植性。所以,设备驱动分离的思想也就应运而生了,在Linux中,我们是在写代码的时候进行分离,分离是把一些不相似的东西放到了dev.c,把相似的东西放在了dri.c,如果我们有很多相似的设备或者平台,我们只要修改dev.c就可以了,这样我们重复性的工作就大大的减少了。这个就是平台总线的由来。

平台总线这个方法有什么弊端呢?

当我们用这个方法用习惯以后就会发现,假如soc不变,我们每换一个平台,都要修改C文件,并且还要重新编译。而且会在arch/arm/plat-xxx和arch/arm/mach-xxx下面留下大量的关于板级细节的代码。并不是说这个方法不好,只是从Linux的发展来看,这些代码相对于Linux内核来说就是“垃圾代码”,而且这些“垃圾代码”非常多,于是就有了Linux Torvalds那句简单粗暴的话:

img

为了改变这个现状,设备树也就被引进到Linux上了,用来剔除相对内核来说的“垃圾代码”,即用设备树文件来描述这些设备信息,也就是代替dev.c文件,虽然拿到了内核外面,但platform匹配上基本不变,并且相比于之前的方法,使用设备树不仅可以去掉大量“垃圾代码”,并且采用文本格式,方便阅读和修改,如果需要修改部分资源,我们也不用在重新编译内核了,只需要把设备树源文件编译成二进制文件,在通过bootloader传递给内核就可以了。内核在对其进行解析和展开得到一个关于硬件的拓扑图。我们通过内核提供的接口获取设备树的节点和属性就可以了。即内核对于同一soc的不同主板,只需更换设备树文件dtb即可实现不同主板的无差异支持,而无需更换内核文件。

img

三.设备树的基本概念

1.为什么叫设备树呢?

因为他的语法结构像树一样,所以管它叫设备树

2. 常用名词解释

<1>DT:Device Tree  //设备树
<2>FDT:Flattened Device Tree  //展开设备树//开放固件,设备树起源于OF,所以我们在设备树中可以看到很多有of字母的函数
<3>device tree source(dts) //设备树代码
<4>device tree source include(dtsi): //更通用的设备树代码,也就是相同芯片但不能平台都可以使用的代码
<5>device tree blob(dtb) //DTS编译后得到的DTB文件
<6>device tree compiler(dtc) //设备树编译器

img

设备树基本框架

​ <1>设备树从根节点开始,每个设备都是一个节点。

​ <2>节点和节点之间可以互相嵌套,形成父子关系。

​ <3>设备的属性用key-value对(键值对)来描述,每个属性用分号结束

设备树语法

2.1节点

​ 什么是节点呢?节点就好比一颗大树,从树的主干开始,然后有一节一节的树枝,这个就叫节点。在代码中的节点是什么样子的呢。我们把上面模板中的根节点摘出来,如下图所示,这个就是根节点。相当于大树的树干。

/{

};//分号

而树枝就相当于设备树的子节点,同样我们把子节点摘出来就是根节点里面的node1和node2,如下图所示:

/{ //根节点
   node1//子节点node1
   { 
   };
   node2//子节点node2
   { 
   };
 };//分号

一个树枝是不是也可以继续分成好几个树枝呢,也就是说子节点里面可以包含子子节点。所以child-node1和child-node2是node1和node1的子节点,如下图所示:

/{ //根节点
   node1//子节点node1
   { 
     child-node1 //子子节点
     { 
     };
   };
   node2//子节点node2
   { 
     child-node2 //子子节点
     { 
     };
   };
 };//分号

2.2节点名称

节点的命名有一个固定的格式。

格式:<名称>[@<设备地址>]

<名称>节点的名称也不是任意起的,一般要体现设备的类型而不是特点的型号,比如网口,应该命名为ethernet,而不是随意起一个,比如111。

<设备地址>就是用来访问该设备的基地址。但并不是说在操作过程中来描述一个地址,他主要用来区分用。

注意事项:

​ <1>同一级的节点只要地址不一样,名字是可以不唯一的。

​ <2>设备地址是一个可选选项,可以不写。但为了容易区分和理解,一般是都写的。

2.3节点别名

​ 当我们找一个节点的时候,我们必须书写完整的节点路径,如果我们的节点名很长,那么我们在引用的时候就十分不方便,所以,设备树允许我们用下面的形式为节点标注引用(起别名)。比如一个动漫人物的名字是蒙其·D·路飞,他的小名是路飞,那是不是小名要比我们的全名更容易记忆了。这个就是别名。

举例:

 uart8: serial@02288000 

其中,uart8就是这个节点名称的别名,serial@02288000就是节点名称。

2,4, 节点的引用

一般我往一个节点里面添加内容的时候,不会直接把添加的内容写到节点里面,而是通过节点的引用来添加。

举例

&uart8 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_uart8>;
    status = "okay";
};

&uart8表示引用节点别名为uart8的节点,并往这个节点里面添加以下内容:

 pinctrl-names = "default";
 pinctrl-0 = <&pinctrl_uart8>;
 status = "okay";

注意事项:

​ 编译设备树的时候,相同的节点的不同属性信息都会被合并,相同节点的相同的属性会被重写,使用引用可以避免移植者四处找节点。如dts和dtsi里面都有根节点,但最终会合并成一个根节点。

2.5属性

(1)reg属性

reg属性用来描述一个设备的地址范围。

格式:

reg=<add1 length1 [add2 length2]......>

举例

serial@02288000 {
      reg = <101F2000 0x1000>;
};

其中101F2000就是起始地址,0x1000就是长度。

(2)#address-cells和#size-cells属性

address-cells用来设置子节点中reg地址的数量

#size-cells用来设置子节点中reg地址长度的数量。

举例

cpu{  
  #address-cells = <1>; 
  #size-cells = <1>;
  serial@101F2000{
      compatible = "serial";
      reg = <101F2000 0x1000>;
  };
};

其中#address-cells和#size-cell均为1,也就是说我们子节点里面的reg属性里这个寄存器组的起始地址只有一个,长度也只有一个。所以101F2000是起始地址,0x1000是长度。

(3)compatible属性

​ compatible是一个字符串列表,可以在代码中进行匹配。

举例:

compatible = "led";

(4)status属性

status属性的值类型是字符串,这里我们只要记住俩个常用的即可,一个是okay,表示设备可以正常使用,一个是disable,表示设备不能正常使用。

在设备树中添加自定义节点

查看设备树节点

ls /proc/device-tree
ls /sys/firmware/devicetree/base/

两个是一样的

在/home/samba/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/boot/dts/imx6ull-14x14-evk.dts中添加自定义节点

test1:test{
	#address-cells = <1>;
	#size-cells = <1>;
	compatible = "test";
	reg = <0x020ac000 0x00000004>;
	status = "okay";
};

image-20240424162935639

编译设备树文件

如果环境没有dtc工具,需要安装dtc工具

安装命令:

apt-get install device-tree-compiler

然后我们输入以下命令设置交叉编译器和编译设备树

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs

image-20240424164042855

但是我们只想编译 imx6ull-14x14-evk.dts 文件, 可以将上述命令的 dtbs 替换为 imx6ull-14x14-evk.dts, 因为我们 imx6ull 烧写的是 topeet_emmc_4_3.dtb 的设备树, 所以编译命令如下图所示, 如果用户烧写的是其他屏幕的设备树文件, 可以修改为对应的命令。

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- topeet_emmc_4_3.dtb

image-20240424164346334

编译烧录到开发板上查看

image-20240424195341241

设备树中常用的of操作函数

设备都是以节点的形式“挂”到设备树上的,因此要想获取这个设备的其他属性信息,必须先获取到这个设备的节点。Linux 内核使用 device_node 结构体来描述一个节点,此结构体定义在文件include/linux/of.h 中,定义如下

struct device_node
{
    const char *name; /* 节点名字 */
    const char *type; /* 设备类型 */
    phandle phandle;
    const char *full_name; /* 节点全名 */
    struct fwnode_handle fwnode;
    struct property *properties; /* 属性 */
    struct property *deadprops; /* removed 属性 */
    struct device_node *parent; /* 父节点 */
    struct device_node *child; /* 子节点 */
    struct device_node *sibling;
    struct kobject kobj;
    unsigned long _flags;
    void *data;
    #if defined(CONFIG_SPARC)
        const char *path_component_name;
        unsigned int unique_id;
        struct of_irq_controller *irq_trans;
    #endif
};

节点的属性信息里面保存了驱动所需要的内容,因此对于属性值的提取非常重要,Linux 内核中使用结构体 property 表示属性,此结构体同样定义在文件 include/linux/of.h 中,内容如下:

struct property
{
    char *name; /* 属性名字 */
    int length; /* 属性长度 */
    void *value; /* 属性值 */
    struct property *next; /* 下一个属性 */
    unsigned long _flags;
    unsigned int unique_id;
    struct bin_attribute attr;
};

或者设备树文件节点里面资源的步骤:

步骤一:查找我们要找的节点。

步骤二:获取我们需要的属性值。

1.查找节点的常用of函数:

<1>of_find_node_by_path函数

image-20240424195946054

<2>of_get_parent函数

image-20240424200003855

<3>of_get_next_child函数

image-20240424200031539

image-20240424200044497

2.查找节点属性的常用of函数:

<1>of_find_property函数

image-20240424200128830

<2>

​ of_property_read_u8函数

​ of_property_read_u16函数

​ of_property_read_u32函数

​ of_property_read_u64函数

image-20240424200153192

<3>

​ of_property_read_u8_array函数

​ of_property_read_u16_array函数

​ of_property_read_u32_array函数

​ of_property_read_u64_array函数

image-20240424200219853 image-20240424200230399

<4>of_property_read_string函数

image-20240424200255307

<5> of_iomap函数 #include <linux/of_address.h>

image-20240424200335967

参数index的值举例:想映射哪段就填哪段

image-20240424221257602

of 函数实验

driver.c

#include <linux/init.h>   //包含宏定义的头文件
#include <linux/module.h> //包含初始化加载模块的头文件
#include <linux/of.h>

struct device_node *test_device_node; //节点
struct property *test_node_property; //节点属性

int size;

u32 out_values[2] = {0};

char *out_string = "";

static int hello_init(void)
{
    int ret = 0;
    /* 内核打印函数不能用printf,因为内核没有办法使用C语言库 */
    printk("hello world\n"); // 内核模块加载的时候打印hello world
    
    test_device_node = of_find_node_by_path("/test"); //查找根节点下的test节点
    if(test_device_node == NULL)
    {
        printk("of_find_node_by_path is error\n");
        return -1;
    }
    printk("test_device_node name is %s\n", test_device_node->name);
    test_node_property = of_find_property(test_device_node, "compatible", &size); //查找节点的compatible属性
    if(test_node_property == NULL)
    {
        printk("of_find_property is error\n");
        return -1;
    }
    printk("test_node_property name is %s\n", test_node_property->name);
    printk("test_node_property value is %s\n", (char *)test_node_property->value);
    
    //读取属性中u32类型的数组数据, 比如大多数的reg属性都是数组数据,可以使用这个函数一次读取出reg属性中的所有数据
    ret = of_property_read_u32_array(test_device_node, "reg", out_values, 2); 
    if(ret < 0)
    {
        printk("of_property_read_u32_array is error\n");
        return -1;
    }
    printk("out_values[0] is 0x%08x\n", out_values[0]);
    printk("out_values[1] is 0x%08x\n", out_values[1]);
    ret = of_property_read_string(test_device_node, "status", &out_string); //获取status属性内容
    if(ret < 0)
    {
        printk("of_property_read_string is error\n");
        return -1;
    }
    printk("status is %s\n", out_string);
    return 0;
}

static void hello_exit(void)
{
    printk("byby\n"); // 内核模块卸载的时候打印"byb byb
}

module_init(hello_init); // 驱动模块的入口
module_exit(hello_exit); // 驱动模块的出口

MODULE_LICENSE("GPL"); // 声明模块拥有开源许可证

Makefile

obj-m +=driver.o
KDIR:=/home/mzx/imx6ull/linux-imx-rel_imx_4.1.15_2.1.0_ga 
PWD?=$(shell pwd)

all:
	make -C $(KDIR) M=$(PWD) modules

在开发板上查看

image-20240424210858796

设备树下的platform驱动

struct platform_driver {
	int (*probe)(struct platform_device *);
	int (*remove)(struct platform_device *);
	void (*shutdown)(struct platform_device *);
	int (*suspend)(struct platform_device *, pm_message_t state);
	int (*resume)(struct platform_device *);
	struct device_driver driver;
	const struct platform_device_id *id_table;
	bool prevent_deferred_probe;
};
struct device_driver {
	const char		*name;
	struct bus_type		*bus;

	struct module		*owner;
	const char		*mod_name;	/* used for built-in modules */

	bool suppress_bind_attrs;	/* disables bind/unbind via sysfs */

	const struct of_device_id	*of_match_table;
	const struct acpi_device_id	*acpi_match_table;

	int (*probe) (struct device *dev);
	int (*remove) (struct device *dev);
	void (*shutdown) (struct device *dev);
	int (*suspend) (struct device *dev, pm_message_t state);
	int (*resume) (struct device *dev);
	const struct attribute_group **groups;

	const struct dev_pm_ops *pm;

	struct driver_private *p;
};
struct platform_device_id {
	char name[PLATFORM_NAME_SIZE];
	kernel_ulong_t driver_data;
};

const struct of_device_id *of_match_table; 用来设置 platform 驱动匹配表

平台总线匹配:

​ 1.struct device_driver中的const struct of_device_id *of_match_table中的compatible

​ 2.struct platform_driver中的const struct platform_device_id *id_table中的name

​ 3.struct device_driver driver中的name

优先级: 1>2>3

Platform 驱动程序

先查看开发板设备数节点中的值是不是正确

image-20240424214305996

driver.c

#include <linux/init.h>   //包含宏定义的头文件
#include <linux/module.h> //包含初始化加载模块的头文件
#include <linux/platform_device.h> //平台设备所需要的头文件
#include <linux/of.h> //of函数
#include <linux/of_address.h> //of_iomap函数
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>

struct device_node *test_device_node; //节点
u32 out_values[2] = {0}; //读取到的数组值
unsigned int *vir_gpio5_dr;

int misc_open(struct inode *inode, struct file *file)
{
    printk("hello misc_open\n");
    return 0;
}

int misc_release(struct inode *inode, struct file *file)
{
    printk("hello mise_release bye bye\n");
    return 0;
}

ssize_t misc_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff_t)
{
    char kbuf[64] = "heheh";
    if (copy_to_user(ubuf, kbuf, strlen(kbuf) + 1) != 0)
    {
        printk("copy_to_user error\n");
        return -1;
    }
    printk("hello misc_read bye bye\n");
    return 0;
}

ssize_t misc_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{
    char kbuf[64] = {0};
    if (copy_from_user(kbuf, ubuf, size) != 0)
    {
        printk("copy_from_user error\n");
        return -1;
    }
    printk("hello misc_write bye bye\n");
    if(kbuf[0] == 1) //打开蜂鸣器
    {
        *vir_gpio5_dr |= 0x02; 
    }else if(kbuf[0] == 0)//关闭蜂鸣器
    {
        *vir_gpio5_dr &= ~0x02; 
    }
    return 0;
}

/* 文件操作集 */
struct file_operations misc_fops = {
    .owner = THIS_MODULE, // 当前模块
    .open = misc_open,
    .release = misc_release,
    .write = misc_write,
    .read = misc_read,
};

/* 杂项设备结构体 */
struct miscdevice misc_dev = {
    .minor = MISC_DYNAMIC_MINOR, // 动态分配次设备号
    .name = "hello_mise",        // 设备节点的名字
    .fops = &misc_fops           // 文件操作集

};

int beep_probe(struct platform_device *pdev)
{
    int ret = 0;
    
    printk("beep_probe\n");
    /* 方法一,直接获取 */
    // printk("node name is %s\n", pdev->dev.of_node->name); 
    
    /* 方法二,of函数获取 */
    test_device_node = of_find_node_by_path("/test"); //查找根节点下的test节点
    if(test_device_node == NULL)
    {
        printk("of_find_node_by_path is error\n");
        return -1;
    }
    printk("test_device_node name is %s\n", test_device_node->name);
    //读取属性中u32类型的数组数据, 比如大多数的reg属性都是数组数据,可以使用这个函数一次读取出reg属性中的所有数据
    ret = of_property_read_u32_array(test_device_node, "reg", out_values, 2); 
    if(ret < 0)
    {
        printk("of_property_read_u32_array is error\n");
        return -1;
    }
    printk("out_values[0] is 0x%08x\n", out_values[0]);
    printk("out_values[1] is 0x%08x\n", out_values[1]);
    ret = misc_register(&misc_dev); // 注册杂项设备
    if (ret < 0)
    {
        printk("misc register is error!\n");
        return -1;
    }
    printk("mise register is ok!\n");
    vir_gpio5_dr = of_iomap(test_device_node, 0); //直接内存映射
    if(vir_gpio5_dr == NULL)
    {
        printk("of_iomap is error\n");
        return -1;
    }
    return 0;
}

int beep_remove(struct platform_device *platform_device)
{
    printk("beep_remove\n");
    return 0;
}

struct platform_device_id beep_id_table = {
    .name = "123"
};

struct of_device_id	of_match_table_test[] = {  //与设备树的 compatible 匹配
    {
        .compatible = "test1234"
    },
    {
        
    }
};

/* platform 驱动结构体 */
struct platform_driver beep_platform_driver = {
    .probe = beep_probe,
    .remove = beep_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = "beep_test", //匹配优先级3
        .of_match_table = of_match_table_test, //中的.compatible匹配优先级1
    },
    .id_table = &beep_id_table //中的.name匹配优先级2
};

static int beep_driver_init(void)
{
    int ret = 0;
    printk("hello world\n");
    ret = platform_driver_register(&beep_platform_driver); //注册平台驱动
    if(ret < 0)
    {
        printk("platform_driver_register is error\n");
        return ret;
    }
    return 0;
}

static void beep_driver_exit(void)
{
    printk("byby\n"); // 内核模块卸载的时候打印"byb byb
    platform_driver_unregister(&beep_platform_driver); //卸载 platform 驱动
    misc_deregister(&misc_dev); // 注销杂项设备
    iounmap(vir_gpio5_dr); //卸载杂项设备
}

module_init(beep_driver_init); // 驱动模块的入口
module_exit(beep_driver_exit); // 驱动模块的出口

MODULE_LICENSE("GPL"); // 声明模块拥有开源许可证

app.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
    int fd;
    char buf[64] = {0};
    
    if(argc < 2)
    {
        printf("Usage: %s <1:beep open / 0:beep close>\n", argv[0]);
        return -1;
    }
    
    fd = open("/dev/hello_mise", O_RDWR);
    if (fd < 0)
    {
        perror("open error\n");
        return fd;
    }
    buf[0] = atoi(argv[1]); //字符串转int
    write(fd, buf, strlen(buf)+1);
    close(fd);
    return 0;
}

Makefile

obj-m +=driver.o
KDIR:=/home/mzx/imx6ull/linux-imx-rel_imx_4.1.15_2.1.0_ga 
PWD?=$(shell pwd)

all:
	make -C $(KDIR) M=$(PWD) modules

标签:node,struct,Linux,14,device,printk,节点,设备
From: https://www.cnblogs.com/mzx233/p/18158793

相关文章

  • 13_Platform 设备驱动
    Platform设备驱动1.什么是平台总线模型?平台总线模型也叫platform总线模型。是Linux内核虚拟出来的一条总线,不是真实的导线。平台总线模型就是把原来的驱动C文件给分成了俩个C文件,一个是device.c,一个是driver.c把稳定不变的放在driver.c里面,需要变得就放在了device.c里面。2......
  • 12_自动创建设备节点
    自动创建设备节点自动创建设备节点简介​ 在嵌入式Linux中使用mdev来实现设备节点文件的自动创建和删除。​ udev是一种工具,它能够根据系统中的硬件设备的状态动态更新设备文件,包括设备文件的创建,删除等。设备文件通常放在/dev目录下。使用udev后,在/dev目录下就......
  • Linux文件系统与日志分析
    目录1.inode与block(1)inode的内容(2)inode的号码(3)inode的大小(4)inode的特殊作用2.硬链接与软连接3.恢复误删的文件(1)恢复EXT类型的文件(2)恢复XFS类型的文件4.分析日志文件(1)日志文件(1)日志的功能:(2)日志文件的分类:(3)日志保存位置(2)内核及系统日志(2)日志消息的级别(3)日志记录的一般格式(3)用户日志......
  • inode(index node)是Unix、Linux和类Unix操作系统中的一个重要概念, 在Windows操作系统中
    inode(indexnode)是Unix、Linux和类Unix操作系统中的一个重要概念,用于描述文件系统中的文件或目录。每个文件或目录都与一个inode相关联。inode包含以下信息:文件或目录的权限(读、写、执行)。文件类型(普通文件、目录、符号链接等)。拥有者和所属组。文件的大小。访问、修......
  • 【vue3入门】-【14】style绑定
    style绑定数据绑定的一个常见需求场景式操作元素的cssstyle列表,因为style是一个Attribute,我们可以和其他Attribute一样使用v-bind,将它们和动态的字符串绑定。但是,在处理比较复杂的绑定时,通过拼接生成字符串是麻烦且容易出错的。因此,vue专门为style的v-bind用法提供了特殊的功能......
  • vim查看linux文件目录,05Linux.浏览目录和文件,VIM文本编辑器
    vim查看linux文件目录,05Linux.浏览目录和文件,VIM文本编辑器一、浏览目录和文件查看目录、查看文件属性1)查看根目录/下有哪些文档或子目录,观察颜色有什么规律ls/2)以长格式显示结果,对比/bin、/usr/bin/目录详细属性ls-ld/bin/usr/bin/【-d只显示目录本身】3)......
  • linux压缩
    市面上有非常多的压缩格式:zip格式:Linux、Windows、MacOS,常用7zip:Windows系统常用rar:Windows系统常用tar:Linux、MacOS常用gzip:Linux、MacOS常用在Linux系统中操作:tar、gzip、zip这三种压缩格式tar命令语法:tar[-z-x-v-f-c-C]参数1参数2选项:-c,创建压缩文件,用于压缩......
  • linux系统管理
    1.用户、用户组创建用户useradd[-g-d]用户名选项:-g指定用户的组,不指定-g,会创建同名组并自动加入,指定-g需要组已经存在,如已存在同名组,必须使用-g选项:-d指定用户HOME路径,不指定,HOME目录默认在:/home/用户名删除用户userdel[-r]用户名选项:-r,删除用户的HOME目录,不使用-r,删......
  • 02、Linux 排查
    Linux分析排查1.敏感文件信息1.1.tmp目录/tmp:临时目录文件,每个用户都可以对它进行读写操作。因此一个普通用户可以对/tmp目录执行读写操作(ls-alt)筛查/tmp目录下是否存在相关的恶意文件等1.2.开机启动:/etc/init.d恶意代码很可能设置在开机自启动的位置查看指定目录下......
  • Linux:VMware切换"仅主机模式"并配置静态IP
    配置网络编辑器点击“编辑”->“虚拟网络编辑器”没有仅主机模式的话,可以通过“添加网络”进行新增网络配置。更改虚拟机网路模式右键“创建的虚拟就”->“设置”登录虚拟机配置静态IP切换目录到“/etc/sysconfig/network-scripts/”修改“if-ens33”文件TYPE=Ethern......