程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> C語言實現ps命令的編寫

C語言實現ps命令的編寫

編輯:關於C
在學習Unix/Linux編程實踐教程時,總是感覺學不到東西,過後就沒啥印象了,經過向師兄請教後,還是由於自己動手練習的太少,沒能夠深入理解,於是讓我編寫一個簡單的ps命令。開始很是頭大,經過自己的不斷努力,終於可以實現簡單的ps命令的功能了。下邊就給大家分享一下,有什麼錯誤或者建議,還望大家能夠指出。   先講下自己的思路,明白以下幾個小問題:     1.ps有什麼用?     2.ps的系統調用情況?     3.進程信息在什麼地方存儲?   man ps就可以發現ps是用於顯示進程瞬時信息的,它有好多參數,這裡就不一一介紹; 接下來就是查看ps的系統調用,可以使用strace命令實現,部分輸出如下: wKiom1YWbvPSDEj_AAE07dWqhWs177.jpg 從strace輸出的信息中就可以得到很多有用的信息,從/proc目錄中含有進程信息相關的文件及目錄(/proc/${pid}、/proc/${pid}/stat、/proc/${pid}/status);下來使用ps -e命令輸出所有進程,然後再切換到/proc目錄中查看,發現該目錄中所有的純數字命名的目錄即為進程,再切換入該目錄打開前邊提到的文件,發現文件中存有進程相關信息。   接下來為了實現簡單的ps命令,就需要遍歷/proc目錄以及讀取該目錄中的有關文件信息 wKiom1YWdQGAcXFOAAFpm9P2EpQ118.jpg 實現代碼如下:  
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <pwd.h>

#define MAX_LEN 20
struct ps_info *trav_dir(char dir[]);
int read_info(char d_name[],struct ps_info *p1);
void print_ps(struct ps_info *head);
int is_num(char *);
void uid_to_name();

typedef struct ps_info
{
    char pname[MAX_LEN];
    char user[MAX_LEN];
    int  pid;
    int  ppid;
    char state;
    struct ps_info *next;
}mps;

int main(int ac,char *av[])
{
    mps *head,*link;
     
    head=trav_dir("/proc/");
    if(head==NULL)
        printf("traverse dir error\n");
    print_ps(head);

    while(head!=NULL)        //釋放鏈表
    {
        link=head;
        head=head->next;
        free(link);
    }
    return 0;
}

mps *trav_dir(char dir[])                         
{
    DIR *dir_ptr;
    mps *head,*p1,*p2;
    struct dirent *direntp;
    struct stat infobuf;

    if((dir_ptr=opendir(dir))==NULL)
        fprintf(stderr,"dir error %s\n",dir);
    else
    {
        head=p1=p2=(struct ps_info *)malloc(sizeof(struct ps_info));    //建立鏈表
        while((direntp=readdir(dir_ptr)) != NULL)               //遍歷/proc目錄所有進程目錄
        {
            if((is_num(direntp->d_name))==0)                   //判斷目錄名字是否為純數字
            {
                if(p1==NULL)
                {
                    printf("malloc error!\n");
                    exit(0);
                }

                if(read_info(direntp->d_name,p1)!=0)         //獲取進程信息
                {
                    printf("read_info error\n");
                    exit(0);
                }
                p2->next=p1;                        //插入新節點
                p2=p1;
                p1=(struct ps_info *)malloc(sizeof(struct ps_info));
            }
        }
    }
    p2->next=NULL;
    return head;
}

int read_info(char d_name[],struct ps_info *p1)
{
    FILE *fd;
    char dir[20];
    struct stat infobuf;

    sprintf(dir,"%s/%s","/proc/",d_name);
    chdir("/proc");                        //切換至/proc目錄,不然stat返回-1
    if(stat(d_name,&infobuf)==-1)                     //get process USER
        fprintf(stderr,"stat error %s\n",d_name);
    else
        //p1->user=uid_to_name(infobuf.st_uid);
        uid_to_name(infobuf.st_uid, p1);

    chdir(dir);                         //切換到/proc/pid目錄
    if((fd=fopen("stat","r"))<0)
    {
        printf("open the file is error!\n");
        exit(0);       
    }

 

    while(4==fscanf(fd,"%d %s %c %d\n",&(p1->pid),p1->pname,&(p1->state),&(p1->ppid)))     //讀文件的前四個字段內容,並存放在相關的鏈表成員中
    {
        break;                                    
    }
    fclose(fd);
    return 0;
}

void uid_to_name(uid_t uid, struct ps_info *p1)         //由進程uid得到進程的所有者user
{
    struct passwd *getpwuid(), *pw_ptr;
    static char numstr[10];

    if((pw_ptr=getpwuid(uid)) == NULL)
    {
        sprintf(numstr,"%d",uid);
        strcpy(p1->user, numstr);
    }
    else
        strcpy(p1->user, pw_ptr->pw_name);
}

int is_num(char p_name[])
{
    int i,len;
    len=strlen(p_name);
    if(len==0) return -1;
    for(i=0;i<len;i++)
        if(p_name[i]<'0' || p_name[i]>'9')
            return -1;
    return 0;
}

void print_ps(struct ps_info *head)
{
    mps *list;
    printf("USER\t\tPID\tPPID\tSTATE\tPNAME\n");
    for(list=head;list!=NULL;list=list->next)
    {
        printf("%s\t\t%d\t%d\t%c\t%s\n",list->user,list->pid,list->ppid,list->state,list->pname);
    }
}

 


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved