Bootstrap

【Linux指令/信号总结】粘滞位 重定向 系统调用 信号产生 信号处理

1.>

echo “hello” > file.txt //没有文件 创建新文件 覆盖式写入

2. cat

cat file.txt

打开file.txt文件,读取其内容,并将这些内容输出到标准输出。
类似于C语言中fopen函数 打开文件后可以使用fread等函数操作

cat < file.txt

将文件file.txt的内容作为cat命令的标准输入(stdin)。
将原来指向键盘输入缓冲区的指针重定向到文件(没有执行打开文件的操作)

3.系统命令

在这里插入图片描述

这条命令 uname -a 的输出提供了您当前Linux系统的详细信息。具体来说,这条输出信息说明了以下几点:

  • 系统名称Linux,表明这是一个Linux系统。
  • 主机名hcss-ecs-79af,服务器名。
  • 内核版本5.4.0-170-generic,内核版本。Linux内核是操作系统的核心,管理着硬件和软件资源。这里的版本号5.4.0是主版本号,-170可能是针对Ubuntu系统进行的特定修订或补丁版本,而generic表明这是一个适用于大多数硬件配置的通用内核版本。
  • 内核编译日期和时间#188-Ubuntu SMP Wed Jan 10 09:51:01 UTC 2024,这部分信息提供了内核编译的日期(2024年1月10日,星期三,UTC时间)和编译编号(#188),以及这是由Ubuntu团队(SMP表示对称多处理,即支持多CPU)编译的版本。
  • 硬件架构x86_64,这表示您的系统是基于x86-64架构的,也就是常说的64位处理器架构。x86_64x86架构的64位扩展,也称为AMD64或Intel 64。
  • GNU/Linux:最后,这表示您的系统遵循GNU项目(GNU’s Not Unix)的开源原则和理念,并运行在Linux内核之上。GNU项目提供了许多核心工具和库,这些工具和库与Linux内核一起构成了现代Linux系统的基础。

总之,这条命令的输出让您了解了您当前Linux系统的基本情况和配置。

bash和shell和kernel

  • Kernel:操作系统的核心,负责管理硬件资源和提供核心服务
  • Shell:命令行解释器,提供了一个用户与操作系统交互的界面。
  • Bash:一种广泛使用的shell,提供了丰富的命令集和编程功能,是Linux系统中默认的shell之一。

权限只被认证一次

“权限只被认证一次”可以理解为每次用户尝试对文件或目录进行访问时,系统都会独立地验证用户的权限。

粘滞位引入

在这里插入图片描述

这个场景涉及到了Linux系统中的文件权限和sudo命令的使用,以及它们如何影响文件和目录的操作。我会尽量用通俗易懂的方式来解释。

前提知识

  1. 文件权限:在Linux中,每个文件或目录都有三组权限,分别对应文件的所有者(owner)、所属组(group)和其他人(others)。每组权限包括读(r)、写(w)和执行(x)。

  2. sudo命令:sudo命令允许普通用户以超级用户(通常是root)的身份执行命令。这意味着,即使一个操作通常需要管理员权限,普通用户也可以通过sudo来执行它。

场景解释

在这个场景中,有一个目录和一个文件,文件的初始权限设置为rw- r-- r--(即所有者可以读写,所属组可以读,其他人可以读)。现在,有一个普通用户和一个root用户(或通过sudo获得root权限的普通用户)在这个目录下。

为什么普通用户(无w权限)可以删除文件?
  • 当普通用户尝试删除文件时,他们实际上是在尝试修改目录(即从中移除一个条目)。这个操作要求用户对目录有写权限(w),而不是对文件本身。
  • 在这个场景中,尽管普通用户对文件没有写权限,但他们可能(如果目录权限允许)对目录有写权限。因此,他们可以删除目录中的文件。
为什么普通用户通过sudo设置文件权限为000后仍能删除文件?
  • 使用sudo命令后,普通用户以root身份执行命令。root用户拥有对系统的完全访问权限,包括对所有文件和目录的读写执行权限。
  • 因此,即使文件权限被设置为000(即所有人都没有读写执行权限),root用户(或通过sudo的普通用户)仍然可以执行任何操作,包括删除文件。

结论

这个场景的关键点在于理解文件权限和目录权限的区别,以及sudo命令如何允许用户以更高的权限执行操作。普通用户能够删除文件,通常是因为他们对包含该文件的目录有写权限,而不是因为他们对文件本身有写权限。而使用sudo命令后,用户可以执行任何操作,因为sudo赋予了他们root权限。

粘滞位是干什么的?粘滞位只能给目录设置

实现这么一个场景

  1. 多个用户共享一个目录 可以在这个目录下rwx
  2. 但是自己只能删自己 不能删除别人的文件

1. 保护文件免受非授权删除或修改

  • 当一个目录被设置了粘滞位后,只有【文件的所有者、目录的所有者或超级用户(root)】才能删除或重命名该目录下的文件。这有效地防止了其他用户(即使他们具有对该目录的写权限)误删除或篡改不属于他们的文件。

2. 应用于公共目录

  • 粘滞位常被应用于如/tmp这样的公共目录。/tmp目录通常用于存储临时文件,这些文件可能由多个用户创建。通过设置粘滞位,可以确保每个用户只能删除或修改自己创建的文件,从而维护了公共目录的秩序和安全性。

3. 提高系统安全性

  • 通过限制非授权用户对文件的操作,粘滞位有助于减少系统因误操作或恶意攻击而遭受的损害。这对于保护敏感数据和系统稳定性至关重要。

4. 适用于网络共享环境

  • 在网络共享环境中,粘滞位同样可以发挥作用。在共享文件服务器上的共享目录中设置粘滞位,可以防止非目录所有者的用户对文件进行修改,从而保护共享资源的安全性和完整性。

5. 使用chmod命令设置

  • 在Linux中,可以使用chmod命令来设置目录的粘滞位。具体命令为chmod +t directory,其中directory表示要设置粘滞位的目录名称或路径。执行该命令后,该目录的权限模式将包含粘滞位标志(通常显示为tT)。

6. 注意事项

  • 粘滞位只对目录起作用,对普通文件没有影响。
  • 粘滞位只能保护目录中的文件和子目录不被删除或重命名,但不能阻止其他用户往该目录中添加新的文件或子目录。
  • 如果一个目录被设置了粘滞位,但是该目录的所有者或超级用户没有相应的权限,那么该目录下的文件和子目录仍然可能被删除或重命名。

vim加注释

批量添加注释: 命令行模式下 进入块可视模式 选中想添加注释语句的首字符 输入大写i 输入// 按esc返回

stat系统调用

struct stat {
    dev_t     st_dev;     /* 设备ID */
    ino_t     st_ino;     /* inode号 */
    mode_t    st_mode;    /* 文件类型和权限 */
    nlink_t   st_nlink;   /* 硬链接数量 */
    uid_t     st_uid;     /* 用户ID */
    gid_t     st_gid;     /* 组ID */
    dev_t     st_rdev;    /* 设备ID(如果是设备文件) */
    off_t     st_size;    /* 文件大小(以字节为单位) */
    blksize_t st_blksize; /* 块大小 */
    blkcnt_t  st_blocks;   /* 分配的块数 */
    time_t    st_atime;    /* 最后访问时间 */
    time_t    stmtime;    /* 最后修改时间 */
    time_t    st_ctime;    /* 最后状态改变时间 */
};
#include <sys/stat.h>
int stat(const char *pathname, struct stat *statbuf);

在使用 stat 系统调用时,可以结合一些宏来解释返回的文件状态信息。以下是一些与 stat 相关的宏:

  1. 文件类型宏(File Type Macros):

    • S_ISREG(mode): 判断文件是否为常规文件。
    • S_ISDIR(mode): 判断文件是否为目录。
    • S_ISCHR(mode): 判断文件是否为字符设备文件。
    • S_ISBLK(mode): 判断文件是否为块设备文件。
    • S_ISFIFO(mode): 判断文件是否为管道(FIFO)文件。
    • S_ISLNK(mode): 判断文件是否为符号链接。
    • S_ISSOCK(mode): 判断文件是否为套接字。
  2. 权限宏(Permission Macros):

    • S_IRUSR, S_IWUSR, S_IXUSR: 用户权限读、写、执行。
    • S_IRGRP, S_IWGRP, S_IXGRP: 用户组权限读、写、执行。
    • S_IROTH, S_IWOTH, S_IXOTH: 其他用户权限读、写、执行。
  3. 文件模式位掩码(File Mode Bit Masks):

    • S_IFMT: 文件类型位掩码(用于从 st_mode 中提取文件类型)。
    • S_IFREG, S_IFDIR, S_IFCHR, S_IFBLK, S_IFIFO, S_IFLNK, S_IFSOCK: 不同文件类型的位掩码。

查看代码行数

在 Ubuntu 中可以使用以下命令查看代码行数:

  1. 单文件行数

    wc -l 文件名
    
  2. 统计目录下所有代码文件的行数

    find 路径 -name "*.cpp" -o -name "*.h" | xargs wc -l
    
  3. 仅输出总行数

    find 路径 -name "*.cpp" -o -name "*.h" | xargs cat | wc -l
    
  4. 结合 cloc 工具
    安装 cloc 后可更详细统计:

    sudo apt install cloc
    cloc 路径
    

    它会显示文件类型、代码行数、注释行数等信息。

信号产生方式

信号的发送是由操作系统负责的,而信号的接收是由进程负责的

信号是一种异步的通信方式,进程无法预测信号何时到达。进程可能正在处理优先级更高,更重要的任务,所以信号的处理工作可能不是立即执行的。进程会临时记录下对应的信号,方便后续进行处理。

当进程崩溃时,操作系统会将进程的内存映像写入到核心转储文件{文件名为core.pid}中。核心转储文件可以用于分析程序崩溃的原因。

  1. 终端按键产生

    • Ctrl+C:发送SIGINT(2)信号,通常用于中断(Interrupt)进程。

    • Ctrl+\:发送SIGQUIT(3)信号,通常用于退出(Quit)进程并生成core文件

    • Ctrl+Z:发送SIGTSTP(20)信号,通常用于挂起暂停(Suspend)进程,可以被忽略或捕捉。

    • Ctrl+S:发送SIGSTOP(19)信号,用于挂起暂停(Stop)进程的执行,无法被忽略、处理或阻塞。

    • Ctrl+Q:发送SIGCONT(18)信号,用于继续(Continue)被19, 20号信号停止的进程。

      Ctrl+D键组合会发送一个特殊的字符(ASCII码为0x04)给正在运行的程序。即EOF(End of File)字符,它表示输入流的结束。EOF是特殊字符,不是信号!

  2. 系统调用发送

    • int kill(pid_t pid, int sig);
    • int raise(int sig);
    • void abort(void);
  3. 软件条件产生

    • 读端fd被关闭,write操作会产生SIGPIPE信号
    • alarm函数用于设置一个定时器,当定时器到期时,会向当前进程发送SIGALRM信号
    • 当一个子进程终止或被暂停时,内核会向其父进程发送 SIGCHLD 信号
  4. 硬件异常产生

    • 进程执行除以0的指令,CPU的状态寄存器(硬件)会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。
    • 进程访问了非法内存地址,在将虚拟地址转化为物理地址的过程中,内存管理单元MMU(硬件)会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。

信号处理

从内核态返回用户态前,进行信号的检测和处理

  1. 信号处理在内核态 因为:管理信号的数据结构都在进程PCB内,而进程PCB属于内核数据。
  2. 信号处理在完成内核态代码后返回用户态前:内核态代码重要度/优先级更高

在这里插入图片描述

信号捕捉与处理

如果信号的处理方法是默认或忽略,则直接在内核态完成相应的处理动作(终止进程、暂停进程、清除pending标志),不需要切换到用户态。

如果信号的处理方法是自定义捕捉,则切换到用户态执行信号处理程序,完成后再次陷入内核,清除对应信号的pending标志,最后返回用户态继续执行用户程序。

为什么要切换到用户态执行信号处理函数呢?因为信号处理函数是用户提供的,如果以内核态执行用户代码的话,由于内核态具有完全的访问权限,用户代码可能会修改系统的重要数据,从而导致系统资源和硬件设备遭到破坏。

在这里插入图片描述

SIGCHILD信号

  • 忽略信号(默认):SIGCHLD信号的默认处理方法就是忽略(ign)。但是子进程会变为僵尸进程一直等待父进程获取其退出状态。

  • 忽略信号(手动):我们还可以通过signal或sigaction函数手动的选择忽略SIGCHLD信号(SIG_IGN),这样的话系统会直接回收子进程资源,释放僵尸进程。不再需要父进程等待子进程了。这通常用于父进程不关心子进程退出状态的情况。

  • 捕捉信号:父进程可以通过注册一个SIGCHLD信号处理函数来捕捉SIGCHLD信号。当子进程终止或停止时,操作系统会调用该信号处理函数。

  • 阻塞信号:父进程可以选择在某些时候阻塞SIGCHLD信号,以延迟对子进程状态改变的处理。这可以通过调用sigprocmask函数来设置信号屏蔽字来实现。

不可重入函数

函数体内使用了静态的数据结构。
函数体内调用了malloc()或free()函数。
函数体内调用了标准I/O函数,因为标准I/O库很多实现都以不可重入的方式使用全局数据结构。
函数体内访问了全局变量。
函数进行了浮点运算,在许多的处理器/编译器中,浮点一般都是不可重入的。
printf()内部包含了semTake操作,在中断服务程序中不能有阻塞操作,因此也被视为不可重入函数。

;