前言:这是一个操作系统实验罢了……
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <dirent.h>
#define MAXN 10000
typedef struct {
char name[256];
pid_t pid;
pid_t ppid;
} pidinfo;
unsigned pid_cnt = 0, sort_opt;
pidinfo Nodes[MAXN];
typedef struct CTBox CTBox;
typedef struct CTNode {
CTBox* data;
struct CTNode* nxt;
} CTNode;
struct CTBox{
char name[256];
pid_t pid;
struct CTNode *fchild;
};
bool show_PID = false;
void getProcessInfo() {
DIR *pd = opendir("/proc");
if (pd == NULL) {
perror("Opening proc error.");
exit(EXIT_FAILURE);
}
struct dirent* child_dir;
while ((child_dir = readdir(pd))) {
if (!(Nodes[pid_cnt].pid = atoi(child_dir->d_name)))
continue;
char buf[256], status, ps_name[256] = "/proc/";
const char* file_name = "/stat";
strcat(ps_name, child_dir->d_name);
strcat(ps_name, file_name);
FILE *fp = fopen(ps_name, "r");
if (fp == NULL) {
perror("Reading process information error!");
exit(EXIT_FAILURE);
}
int _pid;
fscanf(fp, "%d (%s %c %d", &_pid, buf, &status, &(Nodes[pid_cnt].ppid));
assert(_pid == Nodes[pid_cnt].pid);
buf[strlen(buf) - 1] = 0;
strcpy(Nodes[pid_cnt].name, buf);
++pid_cnt;
fclose(fp);
}
closedir(pd);
}
int cmp(const void *a, const void *b) {
return strcmp(Nodes[*((int*)a)].name, Nodes[*((int*)b)].name);
}
void buildProcTree(CTBox *root) {
int children[500] = {0}, child_cnt = 0;
for (int i = 0; i < pid_cnt; ++i)
if (Nodes[i].ppid == root->pid)
children[child_cnt++] = i;
if (sort_opt == 0)
qsort(children, child_cnt, sizeof(int), cmp);
if (child_cnt == 0) {
root->fchild = NULL;
return;
}
CTNode* prevChild = NULL;
for (int i = 0; i < child_cnt; ++i) {
CTNode* newChild = (CTNode*)malloc(sizeof(CTNode));
if (newChild == NULL) {
perror("Creating child process error");
exit(EXIT_FAILURE);
}
newChild->data = (CTBox*)malloc(sizeof(CTBox));
if (newChild->data == NULL) {
perror("Creating child process error");
exit(EXIT_FAILURE);
}
newChild->data->pid = Nodes[children[i]].pid;
strcpy(newChild->data->name, Nodes[children[i]].name);
newChild->nxt = NULL;
if (prevChild == NULL) {
root->fchild = newChild;
} else {
prevChild->nxt = newChild;
}
buildProcTree(newChild->data);
prevChild = newChild;
}
}
void printProcTree(CTBox *root, int tabLen) {
int eLen = 2;
if (root->fchild == NULL) {
if (show_PID)
printf("%s(%d)", root->name, root->pid);
else printf("%s", root->name);
return;
}
char buf[500] = "";
if (show_PID)
sprintf(buf, "%s(%d)-", root->name, root->pid);
else sprintf(buf, "%s-", root->name);
printf("%s", buf);
if (root->fchild != NULL && root->fchild->nxt != NULL)
printf("+-");
for (CTNode* it = root->fchild->nxt; it != NULL; it = it->nxt) {
int blankcnt = strlen(buf) + tabLen;
printProcTree(it->data, blankcnt + eLen);
if (it->nxt != NULL) {
printf("\n");
for (size_t i = 0; i < blankcnt; ++i)
printf(" ");
if (it->nxt->nxt != NULL)
printf("+-");
else printf("`-");
}
}
}
void cleanupNode(CTNode *node) {
if (node == NULL)
return;
cleanupNode(node->nxt);
free(node->data);
free(node);
}
int main(int argc, char *argv[]) {
struct option long_options[] = {
{"version", no_argument, NULL, 'V'},
{"show-pids", no_argument, NULL, 'p'},
{"numeric-sort", no_argument, NULL, 'n'},
{0,0,0,0}
};
getProcessInfo();
int option_index;
int u = getopt_long(argc, argv, "pnV", long_options, &option_index);
switch (u) {
case 'V':
printf("Process Tree\n");
return EXIT_SUCCESS;
break;
case -1:
sort_opt = 0;
show_PID = false;
break;
case 'p':
sort_opt = 0;
show_PID = true;
break;
case 'n':
sort_opt = 1;
show_PID = true;
break;
default:
printf("Invalid parameters.\n");
return EXIT_FAILURE;
}
CTBox *root = (CTBox*)malloc(sizeof(CTBox));
assert(root);
root->pid = 1;
strcpy(root->name, Nodes[0].name);
buildProcTree(root);
printProcTree(root, 0);
putchar('\n');
cleanupNode(root->fchild);
free(root);
return EXIT_SUCCESS;
}