sudo rm-rf引发的惨案——Linux硬盘的分区和挂载

2022-10-31 11:52:27 浏览数 (1)

前言

前不久,刚使用组里的一台服务器,这台服务器平时用的人不多, 没有严格的管理机制,大家都使用同一个用户名进行远程连接,人人都有sudo权限。我因为对Linux不是非常熟悉,使用管理员权限下执行了一个删除文件的操作(sudo rm-rf),直接把系统搞崩,差点给全组造成难以估量的损失,从删库到跑路差点在我身上上演。。

最危险的命令

不少人都听说过Linux中最危险的命令就是sudo rm -rf /*

这个命令可以拆解成以下几个部分:

  • sudo:获取管理员权限
  • rm:remove删除
  • -r:递归地删除子目录和子目录中的文件
  • -f:强制删除,不再一一向用户提示确认
  • /*:根目录下所有的内容

因此,执行此命令就意味着把整个系统内容全部删除,是相当危险的,听说过不少误删库导致原地离职的职场案例。

我当然清楚这种命令的危险性,不至于去直接执行,但是却用类似的命令得到了相似的后果,下面就来复盘一下案发经过。

案发经过

案发时,我主要想在服务器上装一个软件。

首先,新建一个空文件夹来存放软件的位置

代码语言:javascript复制
mkdir soft

然后,查询了一下文件系统

代码语言:javascript复制
df -h 

输出:
文件系统        容量  已用  可用 已用% 挂载点
udev             32G     0   32G    0% /dev
tmpfs           6.3G  2.5M  6.3G    1% /run
/dev/nvme0n1p2  457G  163G  272G   38% /
tmpfs            32G     0   32G    0% /dev/shm
tmpfs           5.0M  4.0K  5.0M    1% /run/lock
tmpfs            32G     0   32G    0% /sys/fs/cgroup
......

找到了挂载在根目录下文件系统/dev/nvme0n1p2,然后根据一个安装教程,把该系统挂到新建的文件夹下

代码语言:javascript复制
mount /dev/nvme0n1p2 soft

不知道为什么要这样操作,当时并不清楚mount的作用,就跟着做了,然后捣鼓半天,依然安装失败,于是想把文件夹删了,再重新安装。

代码语言:javascript复制
sudo rm -rf soft

结果系统提示:

代码语言:javascript复制
rm: it is dangerous to operate recursively on '/'
rm: use --no-preserve-root to override this failsafe

我一头雾水,我删一个自己建的文件夹,也没有在里面放很多文件,怎么会被系统提示这操作是危险(dangerous)的呢?

轻蔑一笑,根据系统提示,继续执行:

代码语言:javascript复制
sudo rm -rf soft --no-preserve-root

回车一敲,惨案酿成。 远程连接的ssh终端会话并没有结束,但是新的ssh连接已经无法成功,在会话中输入lscp等基础命令均提示找不到命令,只留下了一个仍然可以用的cd命令以及一脸懵逼和冷汗直冒的我。。

因为当时对Linux的文件系统并不了解,因此我下意识地认为删除了一个挂载在根目录下的文件系统,就等价于执行了上面那条危险命令。删了系统倒是问题不严重,严重的是这台服务器上还有几个T的实验数据和成果,如果误删,那我成了全组的“千古罪人”。

为了给师兄和同门一个交代,我赶紧去补习了一下Linux文件系统的相关知识。于是就有了下面的一些知识笔记。

Linux文件系统知识

Linux目录树结构

在Linux系统中,文件目录树如下图[1]所示。

其中,各目录有着特殊含义:

  • /bin:存放用户经常使用的命令
  • /boot:启动加载程序的静态文件
  • /dev:设备文件目录
  • /etc:系统配置文件目录
  • /home:普通用户的家目录
  • /root:系统管理员的家目录
  • /run:进程的运行数据存放的目录
  • /sbin:存放系统管理员用户使用的命令
  • /tmp:临时文件目录;任何人都可以访问,存放周期10天
  • /usr:存放程序文件,库文件,共享文件,各种文档等
  • /usr/bin:存放用户命令
  • /usr/local:程序安装目录
  • /usr/sbin:类似/sbin;存放管理员用户使用的命令
  • /usr/tmp:被抛弃的临时文件目录
  • /var:动态数据文件目录;日志文件log,数据库,缓存目录等
  • /lib:存放程序的库文件
  • /lib64:存放64位程序库文件
  • /media:移动媒体的挂载点
  • /mnt:临时挂载的文件系统的挂载点
  • /opt:存放第三方软件服务
  • /proc:伪文件系统,内核映射文
  • /srv: 用来存储本机提供的服务或数据
  • /sys:伪文件系统,跟硬件设备相关的属性映射文件

所有的目录文件通常不是放在一整块硬盘之上,就像windows中,基本会单独区分C盘和D盘,盘符就是挂载点。 挂载的含义就是将硬盘和一个文件夹进行绑定连接,这样通过文件夹就可以访问到硬盘的数据。在Linux中,并不会像Windows那样自动生成挂载点,需要手动进行挂载。

如果有两块硬盘,通常的硬盘挂载分布如下,一块硬盘用来挂载根分区和系统相关的文件,另一块硬盘挂载在home文件夹下,即用户信息和数据文件。

看到这里,稍稍松了口气,在之前的惨案中,显然根目录的硬盘挂在了一个空文件夹下,这就导致了空文件夹中包含了系统相关的内容,因此再进行删除会提示危险命令。同时,删除之后,系统报废,但数据之类的内容都挂在了其它盘,不受影响。

硬盘分区

发现问题并没有想象中严重,那么继续往下学习。假设一个新场景,服务器如果新增了一块硬盘,应该如何进行分区?因为硬盘很大,对齐进行分区之后能够更方便进行资源管理,同时也增加了安全性(外一一个和我一样的憨批把整个分区误删了呢,这样其它分区可以不受影响)。

首先要了解一下分区类型,对于一个硬盘来说,通常分为主分区、扩展分区和逻辑分区。 主分区最多存在4个(包含拓展分区),通常用来存储系统相关命令和驱动,类似windows的C盘。 除去主分区之外,剩下的分区被称为拓展分区,在拓展分区中,可以划分成数个逻辑分区(IDE硬盘最多支持59个逻辑分区,SCSI硬盘最多支持11个逻辑分区)

下图[2]中展示了两种不同的分区方式,无论哪种分区,逻辑分区的命名均从sda5开始。

在分区之前,可以使用df命令来查看已挂载磁盘的总容量、使用容量、剩余容量等信息

代码语言:javascript复制
df [选项] [挂载点]

选项:
-a 显示所有的文件系统信息,包括特殊文件系统,如/proc、/sysfs
-h 使用习惯单位显示容量,如KB,MB或GB等
-T 显示文件系统类型
-m 以MB为单位显示容量
-k 以KB为单位显示容量。默认就是以KB为单位

在服务器上输入df -h,输出以下信息:

可以看到,服务器上有这几类文件系统:

  • udev 挂载在/dev目录下,起设备管理器的作用
  • tmpfs tmpfs是一种基于内存的文件系统,无需格式化可以直接使用,读写速度快,重启后丢失
  • /dev/loop loop是一种伪设备,能使用户像块设备一样访问一个文件
  • /dev/nvme0n1 系统硬盘,p1,p2是该硬盘上的分区
  • /dev/sda 系统硬盘

因此可以发现,该系统上只挂载了两块硬盘nvme0n1sda,其中,nvme0n1划分了两个子分区,sda没有划分分区。

使用lsblk命令,可以看得更加清楚一些:

在Linux中,使用du命令可以查看文件夹大小

代码语言:javascript复制
du [选项] [目录或文件名]
选项:
-a 显示每个子文件的磁盘占用量。默认只统计
子目录的磁盘占用量
-h 使用习惯单位显示磁盘占用量,如KB,MB
或GB等
-s 统计总占用量,而不列出子目录和子文件的
占用量

在上面可以看到sda这块硬盘挂在/mnt目录下,已经使用939G的空间。

那用du命令来查看一下该文件夹的大小,神奇的是该文件夹大小只有912G。

主要原因是:

  • df命令是从文件系统考虑的,不光要考虑文件占用的空间,还要统计被命令或程序 占用的空间(最常见的就是文件已经删除,但是程序并没有释放空间)
  • du命令是面向文件的,只会计算文件或目录占用的空间

因此,df命令查出来的所用空间会比du命令查出来的更大。同时,这样启示服务器的管理者需要定期对服务器进行重启,释放那些临时文件空间。

下面学习分区,硬盘分区需要使用fdisk命令。

示例:

代码语言:javascript复制
fdisk /dev/sdb

输入n,新建分区 e:extended 代表新建拓展分区 p:primary partition 主分区 输入p,输入1,新建1号主分区 内存分配输入 2G,给1号主分区分配2G大小 分区完之后,输入p,可以查看到硬盘中的新分区信息

分完一号主分区之后,再分一个2号主分区作为拓展分区,命令类似

拓展分区分完分逻辑分区

硬盘分区分完之后,需要进行格式化。

格式化命令:

代码语言:javascript复制
mkfs -t ext4 /dev/sdb1

硬盘挂载

硬盘分区完之后,需要挂载到空文件夹才能使用。

输入mount,可以查询系统中已经挂载的设备。 mount命令格式:

代码语言:javascript复制
mount [-t 文件系统] [-L 卷标名] [-o 特殊选项] 设备文件名 挂载点
选项:
-t 文件系统:加入文件系统类型来指定挂载的类型,可以ext3、ext4、iso9660等文件系统
-L 卷标名:挂载指定卷标的分区,而不是安装设备文件名挂载
-o 特殊选项:可以指定挂载的额外选项

特殊选项:

通常来说,只需要mount 设备文件名 挂载点即可

如果需要卸载(卸载就类似于Windows中的弹出),输入umount 设备文件名 umount 挂载点

对于外接硬盘,每次挂载完之后,重启之后需要重新挂载,因此对于长期插在机器上使用的硬盘,可以设置其自动挂载

自动挂载需要修改/etc/fstab这个文件,该文件每行有六个字段,含义如下:

  • 第一字段:分区设备文件名或UUID(硬盘通用唯一识别码)
  • 第二字段:挂载点
  • 第三字段:文件系统名称
  • 第四字段:挂载参数
  • 第五字段:指定分区是否被dump备份,0代表不备份,1代表每天备份,2代表不定期备份
  • 第六字段:指定分区是否被fsck检测,0代表不检测,其他数字代表检测的优先级,那么当然1的优先级比2高

如果需要自动挂载,就在该文件中添加信息,示例如下:

注意写完之后务必要执行mount -a,该命令是依据配置文件/etc/fstab的内容,执行自动挂载,相当于进行一次测试,如果该文件出现问题,会导致系统无法正常启动。

意外防止方案

Linux文件系统了解到这里,回到案发现场。学习完这些内容后,我联系到了服务器管理的运维人员,重装系统,重打驱动,顺利解决这个篓子。

那么,为了防止下一次出现这种状况,我总结了一些防止意外的方案。

方案一:大数据备份

该方案在很多企业中被广泛采用,基本是搭建Hadoop集群,实现数据和文件的备份,不过该方案需要依赖较多的资源投入,对于普通实验室来说并不适用。

方案二:严格权限管理

看到不少实验室共用服务器是给每一个学生都新建一个用户,这样大家各自用各自的工作区,互不影响。并且,限制用户的权限,sudo权限仅给予服务器管理员账户中,这样可以直接防止一个用户毁坏整个服务器。而且,管理员可以查看到各用户的历史记录.bash_history,更方便管理。但麻烦之处在于每次需要管理员来单独开辟用户并授权,对于小型实验室来说过于繁琐。

方案三:回收站机制

windows有个回收站,可以防止误删文件。Linux没有这项机制,但是可以新建一个文件作为回收站,每次执行rm命令时,自动将rm替换成mv,将删除的文件移动到回收站,之后定期清理回收站内容即可。 该方案主要参考自:https://blog.csdn.net/geek64581/article/details/101095854

首先创建一个回收站:

代码语言:javascript复制
mkdir -p ~/.trash 

然后编辑:~/.bashrc文件

代码语言:javascript复制
vim ~/.bashrc

文件最后添加:

代码语言:javascript复制
alias rm=del        
del()             
{  
  mv $@ ~/.trash/  
}  
cleartrash()      
{  
    read -p "clear sure?[Input 'y' or 'Y' to confirm. && Input 'n' to cancel.]" confirm   
    [ $confirm == 'y' ] || [ $confirm == 'Y' ]  && /bin/rm -rf ~/.trash/*   
}  

保存修改退出,运行source ~/.bashrc使其立即生效

这样就配置完毕,定期执行cleartrash清空回收站即可

References

[1]《鸟哥的Linux私房菜》(第4版) [2]兄弟连Linux教程:https://www.bilibili.com/video/BV1DA4y1X7ZB [3]教程笔记:https://blog.csdn.net/yy150122/article/details/106146414 [4]https://blog.csdn.net/geek64581/article/details/101095854

0 人点赞