intmain(int argc, char *argv[]) { bool isP = false; // Determine whether there is -p or --show-pids in the command line bool isN = false; // Determine whether there is -n or --numeric-sort in the command line bool isV = false; // Determine whether there is -V or --version in the command line for (int i = 1; i < argc; i++) { /* Output command line parameters assert(argv[i]); printf("argv[%d] = %s\n", i, argv[i]); */
// Judge whether the -p or --show-pids instruction appears if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--show-pids")) { isP = true; } // Judge whether the -n or --numeric-sort instruction appears elseif (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--numeric-sort")) { isN = true; } // Judge whether the -V or --version instruction appears elseif (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version")) { isV = true; } else { /* In case of illegal instructions, the program is forced to end to increase the robustness of the grogram */ printf("Unsupported arg(s):" RED "%s\n" ORI, argv[i]); exit(0); } }
/* Checkpoint one: the correct of isP, isN, isV printf("%d %d %d \n", isP, isN, isV); */
structsubprocessNode { pid_t subprocessNodePid; char fileName[512]; /* A structure dedicated to sorting, which can satisfy the sorting of process number and process name subprocessNodePid: The pid of the child node fileName: The name of the file */ }; structcourseNode { char fileName[512]; pid_t pid; pid_t ppid; int subprocessCount; structsubprocessNodesubprocessNodes[512]; structcourseNode *next; /* Construction of data structure of process node: fileName: The name of the file pid: the pid_t of the process ppid:the father process number of this process subprocessCount: the number of subprocesses subprocessNodes: An array that stores pids and names of the child node next: Linked list structure, pointing to the next independent process */ };
voidgetCourseTree() { structdirent *entry; DIR *dirp; FILE *fp; Assert((dirp = opendir("/proc")), "Can not open /proc\n"); // Get file directory while (true) { entry = readdir(dirp); // If it is empty, the traversal will be ended if (entry == NULL) { break; } /* If it is not empty, judge whether it is a directory and whether the name is a number */ if (entry->d_type == 4 && isAllNumString(entry->d_name)) { /* d_type == 4 means this is a directory isAllNumString(d_name) == true means the name of this directory consists of numbers */ char statPath[512] = "/proc/"; // Complete the acquisition of stat file address strcat(statPath, entry->d_name), strcat(statPath, "/stat"); Assert((fp = fopen(statPath, "r")), "Can not open %s\n", statPath); // Open the stat file structcourseNode *cur; // Conduct classification discussion based on whether the name is 1 if (!strcmp(entry->d_name, "1")) { cur = root; } else { // Avoid stackOverflow Assert((cur = (struct courseNode *)malloc(sizeof(struct courseNode))), "malloc size for process failed"); tail->next = cur, tail = tail->next; } // Write to content fscanf(fp, "%d (%s %*c %d", &cur->pid, cur->fileName, &cur->ppid); cur->fileName[strlen(cur->fileName) - 1] = '\0', fclose(fp); } } // Traverse the linked list and write the pid of the child process // into the child process array of the parent process for (struct courseNode *head = root; head != NULL; head = head->next) { for (struct courseNode *cur = head; cur != NULL; cur = cur->next) { if (cur != head && cur->ppid == head->pid) { bool flag = false; // If it already exists, modify the process name to the same for (int i = 0; i < head->subprocessCount; i++) { if (head->subprocessNodes[i].subprocessNodePid == cur->pid) { strcpy(head->subprocessNodes[i].fileName, cur->fileName); flag = true; break; } } // Otherwise, write it to the array if (!flag) { head->subprocessNodes[head->subprocessCount].subprocessNodePid = cur->pid; strcpy(head->subprocessNodes[head->subprocessCount].fileName, cur->fileName); head->subprocessCount++; } // Prevent overflow and increase robustness Assert((head->subprocessCount <= 512), "Too many processes to fully load\n"); } } } }
voidsort(struct subprocessNode *nums, int len) { /* Because the amount of data is not large, the simplest bubble sorting can be used */ for (int i = 0; i < len - 1; i++) { for (int j = 0; j < len - 1; j++) { if (strcmp(nums[j].fileName, nums[j + 1].fileName) > 0) { pid_t tmp1 = nums[j].subprocessNodePid; nums[j].subprocessNodePid = nums[j + 1].subprocessNodePid; nums[j + 1].subprocessNodePid = tmp1; char tmp2[512]; strcpy(tmp2, nums[j].fileName); strcpy(nums[j].fileName, nums[j + 1].fileName); strcpy(nums[j + 1].fileName, tmp2); } } } } voidsortCourseTree(bool isNModel) { /* Because it is sorted by process number by default, it only needs to be processed when sorting by process name */ if (isNModel == false) { structcourseNode *head = root; while (head != NULL) { sort(head->subprocessNodes, head->subprocessCount), head = head->next; } } }
voidprintCourseTree(bool isPModel, struct courseNode *r, int level) { for (int i = 0; i < level; i++) { printf("\t"); // Indent the relationship of processes } // Select the output mode according to the value of isPModel if (isPModel) { printf("%s(%d)\n", r->fileName, r->pid); // Only output process name } else { // Output both process name and process numbers printf("%s\n", r->fileName); } // Recursive output subprocess for (int i = 0; i < r->subprocessCount; i++) { structcourseNode *node = find(r->subprocessNodes[i].subprocessNodePid); if (node != NULL) { printCourseTree(isPModel, node, level + 1); } } }