模仿pstree 打印进程树

本文介绍了如何使用Linux命令pstree显示系统中的进程树,并探讨了如何通过编写C程序获取并构建进程树。此外,还讨论了inotify工具用于实时监控文件系统变化,以及其在自动化测试和数据同步中的应用。文章还涉及到了进程信息的获取,如PID和PPID,以及如何使用这些信息构建和打印进程树。

Linux pstree(英文全称:display a tree of processes)) 命令将所有进程以树状图显示,树状图将会以 pid (如果有指定) 或是以 init 这个基本进程为根 (root),如果有指定使用者 id,则树状图会只显示该使用者所拥有的进程。
使用权限:所有使用者。
在这里插入图片描述

首先,我们需要问题分解一下:

  1. 得到命令行的参数,根据要求设置标志变量的数值;
  2. 得到系统中所有进程的编号 (每个进程都会有唯一的编号) 保存到列表里;
  3. 对列表里的每个编号,得到它的的父亲是谁;
  4. 在内存中把树建好,按命令行参数要求排序;
  5. 把树打印到终端上。

因为人的脑容量有限,通常解决问题的办法就是把比较复杂的问题分解成小问题,再把小问题继续分解下去。而在学校里所做的训练就是建立问题分解的思路和培养解决问题的能力。

预备工作

由于在实验中会反复编译运行这个程序,所以编译和测试自动化非常重要。
这里我写了一个脚本利用inotufy命令自动化这个过程:
Inotify 一种强大的、细粒度的、异步文件系统监控机制,它满足各种各样的文件监控需要,可以监控文件系统的访问属性、读写属性、权限属性、删除创建、移动等操作,也就是可以监控文件发生的一切变化。

inotify-tools 是一个C库和一组命令行的工作,提供Linux下inotify的简单接口。inotify-tools安装后会得到inotifywaitinotifywatch这两条命令:

下载inotufy:
在Ubuntu系统下使用命令:
sudo apt-get install inotify-tools
其他Linux发行版安装方法可以参见:https://github.com/rvoicilas/inotify-tools/wiki#wiki-getting

inotifywait使用:

语法:inotifywait [-hcmrq] [-e ] [-t ] [–format ] [–timefmt ] []

-m:一直监控指定的目录,接收到一个事情而不退出,无限期地执行。默认的行为是接收到一个事情后立即退出。
@:排除不需要监视的文件,可以是相对路径,也可以是绝对路径。
-o, –outfile :输出事情到一个文件而不是标准输出。
-s, –syslog:输出错误信息到系统日志
-d, –daemon:跟–monitor一样,除了是在后台运行,需要指定–outfile把事情输出到一个文件。也意味着使用了–syslog。
–exclude :正则匹配需要排除的文件,大小写敏感。
–excludei :正则匹配需要排除的文件,忽略大小写。
-t , –timeout :设置超时时间,如果为0,则无限期地执行下去。
-r:递归监控所监控目录的子目录。
-q:指定一次,不会输出详细信息,指定二次,除了致命错误,不会输出任何信息。
–timefmt:指定时间格式。
–format:
%w 表示发生事件的目录
%f 表示发生事件的文件
%e 表示发生的事件
%Xe 事件以“X”分隔
%T 使用由–timefmt定义的时间格式
-e:指定监控事件项
示例1:

实现对 /data/web 目录进行监控,监控文件删除,修改,创建和权限相关事件,并且要求将监控信息写入 /var/log/web_watch.log。要求日志条目要清晰明了,能突显文件路径、事件名和时间。

# cat web_watch.sh
#!/bin/bash
inotifywait -mrq --timefmt '%y/%m/%d %H:%M' --format  '%T %w%f %e' --event delete,modify,create,attrib  /data/web | while read  date time file event
  do
      case $event in
          MODIFY|CREATE|MOVE|MODIFY,ISDIR|CREATE,ISDIR|MODIFY,ISDIR)
                  echo $event'-'$file'-'$date'-'$time >> /var/log/web_watch.log
              ;;

          MOVED_FROM|MOVED_FROM,ISDIR|DELETE|DELETE,ISDIR)
                  echo $event'-'$file'-'$date'-'$time /var/log/web_watch.log
              ;;
      esac
  done

inotify 优点:

1)监控文件系统事件变化,通过同步工具实现实时数据同步。

inotify 缺点

1)并发如果大于200个文件(10-100k),同步就会有延迟
2)我们前面写的脚本,每次都是全部推送一次,但确实是增量的。也可以只同步变化的文件,不变化的不理。
3)监控到事件后,调用rsync同步是单进程的,而sersync为多进程同步。既然有了inotify-tools,为什么还要开发sersync?

serysync功能多:(inotify+rsync命令)

1)支持通过配置文件管理
2)真正的守护进程socket
3)可以对失败文件定时重传(定时任务功能)
4)第三方的HTTP接口(例如:更新cdn缓存)
5)默认多进程rsync同步

在了解inotigy命令相关知识后,就可以利用脚本auto_test.sh每次在文件改动以后自动运行所有测试,代码如下:

#!/bin/bash

projectDir=/home/acs/os_test

while inotifywait $projectDir --timefmt '%d/%m/%y %H:%M' --format "%T %f %e" -e MODIFY --exclude '^.*.swp$'
do
	cd $projectDir && gcc test.c -o test1 && ./test1
done

运行这个脚本就可以了:
./auto_test.sh
在这里插入图片描述

step 1: 得到命令行的参数,根据要求设置标志变量的数值

在c语言主函数中,int argc, char *argv[]就是从命令行获取的参数,这是操作系统与 C 程序之间的约定。其中argc是参数的个数,argv是参数字符串。
这里我们使用getopt()函数来处理命令行参数:
getopt()函数的出处是unistd.h头文件,可以参考这篇博客Linux下getopt()函数的简单使用
代码:

int main(int argc, char *argv[]) {
   
   
    int ch; 
    while((ch = getopt(argc, argv, "pnv")) != -1) 
    {
   
      
        printf("optind: %d\n", optind);
        switch(ch){
   
   
            case 'p':
                printf("HAVE option: -p \n\n");
                break;
            case 'n':
                printf("HAVE option: -n \n\n");
                break;
            case 'v':
                printf("HAVE option: -v \n\n");
                break;
            case '?':
                printf("Unknown option: %c\n",(char)optopt);
                break;
        }
    }
    assert(!argv[argc]);
    return 0;                                                                       
}

step 2: 得到系统中进程的编号

Everything is a file,进程信息当然也可以是 “一切” 的一部分

首先我们要知道的是在Linux中,所有进程的信息都以文件的形式存储在/proc目录中,在/proc中存在由数字命名的文件夹,这些数字就是相应进程的pid,进入各个进程的目录中(如进入1号进程的目录中),有一个stat文件,该文件中第四列即为其父进程的pid。
输入命令:cd /proc && ls可以发现查看这些文件夹
在这里插入图片描述
1号进程的stat文件信息:
在这里插入图片描述

思路:

这里我用一个结构体数组先将每一个进程的ppid和pid存起来,打印出来查看一下效果

代码:
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>

#define PATH "/proc"                                                                                                                                          
#define BUFFSIZE_INFO 50

// pid ppid
struct pinfo{
   
   
    int pid;
    int ppid;
}processInfos[500];

int number_process = 0;// 进程个数


int getPpid(char *filename);
void setPid_Ppid();

int main(int argc, char *argv[]) {
   
   
    setPid_Ppid();

    for(int i = 0;i<number_process;i++){
   
   
       // printf("%d %d \n",processInfos[i].pid,processInfos[i].ppid);
    }
    int ch;
    while((ch = getopt(argc, argv, "pnv")) != -1)
    {
   
   
        printf("optind: %d\n", optind);
        switch(ch){
   
   
            case 'p':
                printf("HAVE option: -p \n\n");
                break;
            case 'n':
                printf("HAVE option: -n \n\n");
                break;
            case 'v':
                printf("HAVE option: -v \n\n");
                break;
            case '?':
                printf("Unknown option: %c\n",(char)optopt);
                break;
        }
    }
    assert(!argv[argc]);
    return 0;
}


int getPpid(char* filename){
   
   
    int ppid = -100;
    char *right
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值