├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── LICENSE ├── README.md └── pstree.c /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | a.out 3 | build/ 4 | CMakeLists.txt -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "(gdb) Launch", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/build/pstree64", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${workspaceFolder}", 15 | "environment": [], 16 | "externalConsole": false, 17 | "MIMode": "gdb", 18 | "setupCommands": [ 19 | { 20 | "description": "Enable pretty-printing for gdb", 21 | "text": "-enable-pretty-printing", 22 | "ignoreFailures": true 23 | }, 24 | { 25 | "description": "Set Disassembly Flavor to Intel", 26 | "text": "-gdb-set disassembly-flavor intel", 27 | "ignoreFailures": true 28 | } 29 | ], 30 | "preLaunchTask": "Build", 31 | "miDebuggerPath": "/usr/bin/gdb" 32 | } 33 | 34 | 35 | ] 36 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "options": { 6 | "cwd": "${workspaceFolder}/build" 7 | }, 8 | "tasks": [ 9 | { 10 | "label": "cmake", 11 | "type": "shell", 12 | "command": "cmake", 13 | "args" :[ 14 | ".." 15 | ] 16 | }, 17 | { 18 | "label": "make", 19 | "group": { 20 | "kind": "build", 21 | "isDefault": true 22 | }, 23 | "command": "make", 24 | "args" :[ 25 | ] 26 | }, 27 | { 28 | "label": "Build", 29 | "dependsOrder": "sequence", 30 | "dependsOn":[ 31 | "cmake", 32 | "make" 33 | ] 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Siyuan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NJUOSLAB M1: 打印进程树 (pstree) 2 | 3 | 这是南京大学JYY讲授的的操作系统课的实验M1的实现 4 | 5 | 实验要求与手册请看:[http://jyywiki.cn/OS/2022/labs/M1](http://jyywiki.cn/OS/2022/labs/M1) 6 | 7 | 实现一个三种选项(-V -n -p )和默认的pstree命令,通过读取Linux中 /proc/ 下的内容打印出进程树 8 | 9 | /proc/pid/stat 文件中有name和ppid 10 | 11 | ### 缺陷列表: 12 | 13 | > 1. 当进程名称出现空格 `“ ”` 时,如:(tmux:sever),存在bug 14 | > 因为读取/proc/1234(对应进程pid)/stat文件出现空格读取错位存在bug需要解决。 15 | > 2. 考虑更贴合实际pstree的输出: 对于叶子节点 /proc/1234/task/ 文件夹下会存在叶子节点开启的子进程( 还会有个该进程的副本文件夹 )文件夹,里面stat文件记录pid和进程名称,且这种进程不会在/proc/ 下出现,pstree中这种进程输出样式为 ``[{ *** }}]`` 16 | > 3. **[已实现]** ~~对错误输入返回非0,对合法输入返回0 如果你的 main 函数返回了非 0 的数值,我们将认为程序报告了错误——在非法的输入上返回 0,以及在合法的输入上返回非 0 都将导致 Wrong Answer。 (实验手册提到的要求)~~ 17 | > 4. **[已实现]** ~~错误检查:open malloc失败时的检查 (实验手册提到的要求)~~ 18 | > 5. 思考:(实验手册提到的) 19 | > 20 | > 1. 万一我得到进程号以后,进去发现文件没了 (进程终止了),怎么办?会不会有这种情况?万一有我的程序会不会 crash……? 21 | > 2. 进程的信息一直在变,文件的内容也一直在变 (两次 `cat` 的结果不同)。那我会不会读到不一致的信息(前一半是旧信息、新一半是新信息)?这两个问题都是 race condition 导致的;我们将会在并发部分回到这个话题。 22 | -------------------------------------------------------------------------------- /pstree.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | typedef struct pidinfo{ 9 | char name[50]; 10 | __pid_t pid; 11 | __pid_t ppid; 12 | }PidInfo; 13 | PidInfo pidinfos[10000]; 14 | int pid_count=0; 15 | char* readcmdops(int argc, char *argv[])//get commandline ops 16 | { 17 | assert(argc>=1); 18 | if(argc==1)//no ops 19 | { 20 | return NULL; 21 | } 22 | char *p=argv[1]; 23 | char ops[10];int j=0; 24 | for(int i=0;id_name))==0) 81 | { 82 | continue; 83 | } 84 | else{// store in pidinfo (name and pid and ppid) 85 | pidinfos[pid_count].pid=pid; 86 | pidinfos[pid_count].ppid=readprocessname_ppid(pid,pidinfos[pid_count].name); 87 | assert(pidinfos[pid_count].ppid>-1); 88 | //printf("%d (%s) %d\n",pidinfos[pid_count].pid,pidinfos[pid_count].name,pidinfos[pid_count].ppid); 89 | pid_count++; 90 | } 91 | } 92 | } 93 | } 94 | 95 | typedef struct processtree{ 96 | pid_t pid; 97 | char name[40]; 98 | struct childprocesses *children; 99 | }Processtree; 100 | struct childprocesses{ 101 | struct childprocesses *next; 102 | Processtree *proc; 103 | }; 104 | 105 | void findallchildrens(int pid ,int index[]) 106 | { 107 | int indexcount=0; 108 | size_t i= 0; 109 | for (; i pid,allchildrensindex); 134 | root->children=(struct childprocesses*)malloc(sizeof(struct childprocesses)); 135 | if(root->children==NULL) 136 | { 137 | printf("malloc failed"); 138 | exit(1); 139 | } 140 | struct childprocesses *child=root->children; 141 | if(allchildrensindex[0]==0)//it's leaf node,no child,return 142 | { 143 | printf("%s(%d)",root->name,root->pid); 144 | return; 145 | } 146 | sprintf(str,"%s(%d)-",root->name,root->pid); 147 | printf("%s",str); 148 | if(allchildrensindex[1]!=0) 149 | { 150 | printf("+-"); 151 | } 152 | else 153 | { 154 | flag=0; 155 | } 156 | for(int i=0;i<500 && allchildrensindex[i]!=0 ;i++)//Traverses all children of the process 157 | { 158 | child->proc=(Processtree *)malloc(sizeof(Processtree)); 159 | if(child->proc==NULL) 160 | { 161 | printf("malloc failed"); 162 | exit(1); 163 | } 164 | child->proc->pid=pidinfos[allchildrensindex[i]].pid; 165 | strcpy(child->proc->name,pidinfos[allchildrensindex[i]].name); 166 | creat_tree(child->proc,strlen(str)+tab_length+flag); // recursive 167 | if(i+1<500 && allchildrensindex[i+1]!=0) 168 | { 169 | child->next=(struct childprocesses*)malloc(sizeof(struct childprocesses)); 170 | if(child->next==NULL) 171 | { 172 | printf("malloc failed"); 173 | exit(1); 174 | } 175 | child=child->next; 176 | char tabs[100]; 177 | printf("\n"); 178 | for (size_t i = 0; i pid,allchildrensindex); 193 | root->children=(struct childprocesses*)malloc(sizeof(struct childprocesses)); 194 | if(root->children==NULL) 195 | { 196 | printf("malloc failed"); 197 | exit(1); 198 | } 199 | struct childprocesses *child=root->children; 200 | if(allchildrensindex[0]==0)//it's leaf node,no child,return 201 | { 202 | printf("%s",root->name); //TODO 缺陷列表2 leafnode task:: /proc/pid/task/.../stat 203 | return; 204 | } 205 | sprintf(str,"%s-",root->name); 206 | printf("%s",str); 207 | if(allchildrensindex[1]!=0) 208 | { 209 | printf("+-"); 210 | } 211 | else 212 | { 213 | flag=0; 214 | } 215 | for(int i=0;i<500 && allchildrensindex[i]!=0 ;i++)//Traverses all children of the process 216 | { 217 | child->proc=(Processtree *)malloc(sizeof(Processtree)); 218 | if(child->proc==NULL) 219 | { 220 | printf("malloc failed"); 221 | exit(1); 222 | } 223 | child->proc->pid=pidinfos[allchildrensindex[i]].pid; 224 | strcpy(child->proc->name,pidinfos[allchildrensindex[i]].name); 225 | creat_tree_nopid(child->proc,strlen(str)+tab_length+flag); // recursive 226 | if(i+1<500 && allchildrensindex[i+1]!=0) 227 | { 228 | child->next=(struct childprocesses*)malloc(sizeof(struct childprocesses)); 229 | if(child->next==NULL) 230 | { 231 | printf("malloc failed"); 232 | exit(1); 233 | } 234 | child=child->next; 235 | char tabs[100]; 236 | printf("\n"); 237 | for (size_t i = 0; i pid=pidinfos[0].pid; 253 | strcpy(root->name,pidinfos[0].name); 254 | creat_tree_nopid(root,0); 255 | } 256 | else 257 | { 258 | if(!strcmp(ops,"p")) //ops = -p 259 | { 260 | //printf("%s",ops); 261 | setProcessInfo(); 262 | Processtree *root=(Processtree *)malloc(sizeof(Processtree)); 263 | root->pid=pidinfos[0].pid; 264 | strcpy(root->name,pidinfos[0].name); 265 | creat_tree(root,0); 266 | } 267 | else if(!strcmp(ops,"n")) // -n 268 | { 269 | //printf("%s",ops); 270 | setProcessInfo(); 271 | Processtree *root=(Processtree *)malloc(sizeof(Processtree)); 272 | root->pid=pidinfos[0].pid; 273 | strcpy(root->name,pidinfos[0].name); 274 | creat_tree_nopid(root,0); 275 | 276 | } 277 | else if(!strcmp(ops,"V")) // -V 278 | { 279 | printf("pstree (PSmisc) UNKNOWN\nCopyright (C) 1993-2019 Werner Almesberger and Craig Small\nPSmisc comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it under\nthe terms of the GNU General Public License.\nFor more information about these matters, see the files named COPYING."); 280 | } 281 | else 282 | { 283 | printf("%s","wrong ops"); 284 | return -1; 285 | } 286 | } 287 | return 0; 288 | } 289 | --------------------------------------------------------------------------------