diff --git a/ref.c b/ref.c new file mode 100644 index 0000000..552c8dc --- /dev/null +++ b/ref.c @@ -0,0 +1,924 @@ +#include //标准I/O库 +#include //实用程序库函数 +#include //字符串操作 +#include // 信号 +#include +#include //实现常量 +#include +#include +#include //时间和日期 +#include //出错码 +#include //验证程序断言 + +#include //目录项 +#include //文件控制 +#include //口令文件 +#include //符号常量 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include //文件状态 +#include //基本系统数据类型 +#include //进程控制 +#include //进程时间 +#include +#include //select函数 + +//一般的命令0 +//输出重定向1 +//输入重定向2 +//命令中有管道3 +//#define SELF ((endpoint_t) 0x8ace) /* used to indicate 'own process' */ +//#define _MAX_MAGIC_PROC (SELF) /* used by */ +//#define MAX_NR_TASKS 1023 +//#define _ENDPOINT_GENERATION_SIZE (MAX_NR_TASKS+_MAX_MAGIC_PROC+1) +//#define _ENDPOINT_P(e) +//((((e)+1023) % (1023+((endpoint_t) 0x8ace)+1)) - 1023) +//#define SLOT_NR(e) (_ENDPOINT_P(e) + nr_tasks) + +#define _PATH_PROC "/proc/" +#define PSINFO_VERSION 0 +#define TYPE_TASK 'T' +#define TYPE_SYSTEM 'S' +#define TYPE_USER 'U' +#define STATE_RUN 'R' +#define TIMECYCLEKEY 't' +#define ORDERKEY 'o' + +#define USED 0x1 +#define IS_TASK 0x2 +#define IS_SYSTEM 0x4 +#define BLOCKED 0x8 + +#define ORDER_CPU 0 +#define ORDER_MEMORY 1 +#define ORDER_HIGHEST ORDER_MEMORY + +#define TC_BUFFER 1024 /* Size of termcap(3) buffer */ +#define TC_STRINGS 200 /* Enough room for cm,cl,so,se */ + +/* name of cpu cycle types, in the order they appear in /psinfo. */ +const char *cputimenames[] = {"user", "ipc", "kernelcall"}; +#define CPUTIMENAMES (sizeof(cputimenames) / sizeof(cputimenames[0])) + +#define CPUTIME(m, i) (m & (1L << (i))) + +struct proc +{ + int p_flags; // + endpoint_t p_endpoint; //端点 + pid_t p_pid; //进程号 + u64_t p_cpucycles[CPUTIMENAMES]; //cpu周期 + int p_priority; //动态优先级 + endpoint_t p_blocked; //阻塞状态 + time_t p_user_time; //用户时间 + vir_bytes p_memory; //内存 + uid_t p_effuid; //有效用户ID + int p_nice; //静态优先级 + char p_name[PROC_NAME_LEN + 1]; //名字 +}; + +struct proc *proc = NULL, *prev_proc = NULL; + +struct tp +{ + struct proc *p; + u64_t ticks; +}; + +void getOrder(char *); //得到输入的命令 +void anaOrder(char *, int *, char (*)[256]); //对输入的命令进行解析 +void exeCommand(int, char (*)[256]); //执行命令 +int checkCommand(char *command); //查找命令中的可执行程序 +void getkinfo(); //读取/proc/kinfo得到总的进程和任务数nr_total +int print_memory(); //输出内存信息 +void get_procs(); //记录当前进程,赋值给prev_proc +void parse_dir(); //获取到/proc/下的所有进程pid +void parse_file(pid_t pid); //获取每一个进程信息 +u64_t cputicks(struct proc *p1, struct proc *p2, int timemode); //计算每个进程的滴答 +void print_procs(struct proc *proc1, struct proc *proc2, int cputimemode); //输出CPU使用时间 + +char *message; //用于myshell提示信息的输出 +int whilecnt = 0; +char msg[40][256]; +unsigned int nr_procs, nr_tasks; //进程数和任务数 +int nr_total; //进程和任务总数 +int order = ORDER_CPU; +int blockedverbose = 0; +char *Tclr_all; +int slot = 1; + +/*static inline u64_t make64(unsigned long lo, unsigned long hi) +{ + return ((u64_t)hi << 32) | (u64_t)lo; +} +*/ + +/* +函数名: memset +功 能: 设置s中的所有字节为ch, s数组的大小由n给定 +用 法: void *memset(void *s, char ch, unsigned n); +程序例: + +#include +#include +#include + +int main(void) +{ + char buffer[] = "Hello world\n"; + + printf("Buffer before memset: %s\n", buffer); + memset(buffer, '*', strlen(buffer) - 1); + printf("Buffer after memset: %s\n", buffer); + return 0; +} +*/ +/* +函数名: getcwd +功 能: 取当前工作目录 +用 法: char *getcwd(char *buf, int n); +程序例: +#include +#include +int main(void) +{ + char buffer[MAXPATH]; + + getcwd(buffer, MAXPATH); + printf("The current directory is: %s\n", buffer); + return 0; +} +*/ + +int main(int argc, char **argv) +{ + int i; + int wordcount = 0; + char wordmatrix[100][256]; + char **arg = NULL; + char *buf = NULL; //用户输入 + + if ((buf = (char *)malloc(256)) == NULL) + { + perror("malloc failed"); + exit(-1); + } + + while (1) + { + memset(buf, 0, 256); //将buf所指的空间清零 + message = (char *)malloc(100); + getcwd(message, 100); + printf("myshell:%s# ", message); + free(message); + getOrder(buf); + strcpy(msg[whilecnt], buf); + whilecnt++; + if (strcmp(buf, "exit\n") == 0) + { + break; + } + for (i = 0; i < 100; i++) + { + wordmatrix[i][0] = '\0'; + } + wordcount = 0; + anaOrder(buf, &wordcount, wordmatrix); + exeCommand(wordcount, wordmatrix); + } + + if (buf != NULL) + { + free(buf); + buf = NULL; + } + return 0; +} + +//获取用户输入 +void getOrder(char *buf) +{ + int cnt = 0; + + int c = getchar(); + while (cnt < 256 && c != '\n') + { + buf[cnt++] = c; + c = getchar(); + } + buf[cnt++] = '\n'; + buf[cnt] = '\0'; + if (cnt == 256) + { + exit(-1); + } +} + +//解析buf中的命令,将结果存入wordmatrix中,命令以回车符号\n结束 +void anaOrder(char *buf, int *wordcount, char (*wordmatrix)[256]) +{ + char *p = buf; + char *q = buf; + int number = 0; + int i; + while (1) + { + if (p[0] == '\n') + { + break; + } + if (p[0] == ' ') + { + p++; + } + else + { + q = p; + number = 0; + while ((q[0] != ' ') && (q[0] != '\n')) + { + if (q[0] == 92) + { + q[0] = ' '; + q[1] = q[2]; + for (i = 2;; i++) + { + q[i] = q[i + 1]; + if ((q[i] == ' ') || (q[i] == '\n')) + break; + } + } + number++; + q++; + } + strncpy(wordmatrix[*wordcount], p, number + 1); + wordmatrix[*wordcount][number] = '\0'; + *wordcount = *wordcount + 1; + p = q; + } + } +} +/* +函数名: dup2 +功 能: 复制文件句柄 +用 法: int dup2(int oldhandle, int newhandle); +程序例: + +#include +#include +#include +#include + +int main(void) +{ + #define STDOUT 1 + + int nul, oldstdout; + char msg[] = "This is a test"; + + //create a file + nul = open("DUMMY.FIL", O_CREAT | O_RDWR, + S_IREAD | S_IWRITE); + + //create a duplicate handle for standard output + oldstdout = dup(STDOUT); + redirect standard output to DUMMY.FIL + by duplicating the file handle onto the + file handle for standard output. + dup2(nul, STDOUT); + + close the handle for DUMMY.FIL + close(nul); + + will be redirected into DUMMY.FIL + write(STDOUT, msg, strlen(msg)); + + restore original standard output handle + dup2(oldstdout, STDOUT); + + //close duplicate handle for STDOUT + close(oldstdout); + + return 0; +} +*/ + +void exeCommand(int wordcount, char (*wordmatrix)[256]) +{ + pid_t pid; + char *file; + int correct = 1; + int way = 0; + int status; + int i; + int fd; + char *word[wordcount + 1]; + char *wordnext[wordcount + 1]; + + //将命令取出 + for (i = 0; i < wordcount; i++) + { + word[i] = (char *)wordmatrix[i]; + } + word[wordcount] = NULL; + + //查看命令行是否有后台运行符 + for (i = 0; i < wordcount; i++) + { + if (strncmp(word[i], "&", 1) == 0) + { + way = 4; + word[wordcount - 1] = NULL; + } + } + + for (i = 0; word[i] != NULL; i++) + { + if (strcmp(word[i], ">") == 0) + { + way = 1; + if (word[i + 1] == NULL) + { + correct = 0; + } + } + if (strcmp(word[i], "<") == 0) + { + way = 2; + if (i == 0) + { + correct = 0; + } + } + if (strcmp(word[i], "|") == 0) + { + way = 3; + if (word[i + 1] == NULL) + { + correct = 0; + } + if (i == 0) + { + correct = 0; + } + } + } + //correct=0,说明命令格式不对 + if (correct == 0) + { + printf("wrong format\n"); + return; + } + + if (way == 1) + { + //输出重定向 + for (i = 0; word[i] != NULL; i++) + { + if (strcmp(word[i], ">") == 0) + { + file = word[i + 1]; + word[i] = NULL; + } + } + } + + if (way == 2) + { + //输入重定向 + for (i = 0; word[i] != NULL; i++) + { + if (strcmp(word[i], "<") == 0) + { + file = word[i + 1]; + word[i] = NULL; + } + } + } + + if (way == 3) + { + //把管道符后面的部分存入wordnext中,管道后面的部分是一个可执行的shell命令 + for (i = 0; word[i] != NULL; i++) + { + if (strcmp(word[i], "|") == 0) + { + word[i] = NULL; + int j; + for (j = i + 1; word[j] != NULL; j++) + { + wordnext[j - i - 1] = word[j]; + } + wordnext[j - i - 1] = NULL; + } + } + } + + if (strcmp(word[0], "cd") == 0) + { + if (word[1] == NULL) + { + return; + } + if (chdir(word[1]) == -1) + { + perror("cd"); + } + return; + } + + if ((pid = fork()) < 0) + { //创建子进程 + printf("fork error\n"); + return; + } + + if (strcmp(word[0], "history") == 0) + { //实现history n + if (pid == 0) + { + char cnum = word[1][0]; + int num = cnum - 48; + for (int i = whilecnt - 1; i > whilecnt - num - 1; i--) + { + printf("command %d:", i); + printf("%s", msg[i]); + } + exit(0); + } + } + + if (strcmp(word[0], "mytop") == 0) + { + if (pid == 0) + { + int cputimemode = 1; + getkinfo(); + print_memory(); + get_procs(); + if (prev_proc == NULL) + get_procs(); + print_procs(prev_proc, proc, cputimemode); + exit(0); + } + } + + switch (way) + { + case 0: + //pid为0说明是子进程,在子进程中执行输入的命令 + //输入的命令中不含> < | & + if (pid == 0) + { + if (!(checkCommand(word[0]))) + { + printf("%s : command not found\n", word[0]); + exit(0); + } + execvp(word[0], word); + exit(0); + } + break; + + case 1: + //输入的命令中含有输出重定向符 + if (pid == 0) + { + if (!(checkCommand(word[0]))) + { + printf("%s : command not found\n", word[0]); + exit(0); + } + fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0644); + dup2(fd, 1); + execvp(word[0], word); + exit(0); + } + break; + + case 2: + //输入的命令中含有输入重定向< + if (pid == 0) + { + if (!(checkCommand(word[0]))) + { + printf("%s : command not found\n", word[0]); + exit(0); + } + fd = open(file, O_RDONLY); + dup2(fd, 0); + execvp(word[0], word); + exit(0); + } + break; + + case 3: + //输入的命令中含有管道符| + if (pid == 0) + { + int pid2; + int status2; + int fd[2]; + + if (pipe(fd) < 0) + { + printf("pipe error\n"); + exit(0); + } + + if ((pid2 = fork()) < 0) + { + printf("fork2 error\n"); + return; + } + else if (pid2 == 0) + { + if (!(checkCommand(word[0]))) + { + printf("%s : command not found\n", word[0]); + exit(0); + } + dup2(fd[1], 1); + execvp(word[0], word); + exit(0); + } + if (waitpid(pid2, &status2, 0) == -1) + { + printf("wait for child process error\n"); + } + if (!(checkCommand(wordnext[0]))) + { + printf("%s : command not found\n", wordnext[0]); + exit(0); + } + dup2(fd[0], 0); + execvp(wordnext[0], wordnext); + exit(0); + } + break; + case 4: //若命令中有&,表示后台执行,父进程直接返回,不等待子进程结束 + signal(SIGCHLD, SIG_IGN); + if (pid == 0) + { + //int pidbg; + //pidbg=fork(); + //if(pidbg==0){ + printf("[process id: %d]\n", pid); + int a = open("/dev/null", O_RDONLY); + dup2(a, 0); + dup2(a, 1); + if (!(checkCommand(word[0]))) + { + printf("%s : command not found\n", word[0]); + exit(0); + } + execvp(word[0], word); + exit(0); + //} + } + break; + + default: + break; + } + + //父进程等待子进程结束 + if (waitpid(pid, &status, 0) == -1) + { + printf("wait for child process error\n"); + } +} + +//查找命令中的可执行程序 +int checkCommand(char *command) +{ + DIR *dp; + struct dirent *dirp; + char *path[] = {"./", "/bin", "/usr/bin", NULL}; + + if (strncmp(command, "./", 2) == 0) + { + command = command + 2; + } + + //分别在当前目录,/bin和/usr/bin目录查找要执行的程序 + int i = 0; + while (path[i] != NULL) + { + if ((dp = opendir(path[i])) == NULL) + { + printf("can not open /bin \n"); + } + while ((dirp = readdir(dp)) != NULL) + { + if (strcmp(dirp->d_name, command) == 0) + { + closedir(dp); + return 1; + } + } + closedir(dp); + i++; + } + return 0; +} + +void getkinfo() +{ + FILE *fp; + + if ((fp = fopen("/proc/kinfo", "r")) == NULL) + { + fprintf(stderr, "opening " _PATH_PROC "kinfo failed\n"); + exit(1); + } + + if (fscanf(fp, "%u %u", &nr_procs, &nr_tasks) != 2) + { + fprintf(stderr, "reading from " _PATH_PROC "kinfo failed\n"); + exit(1); + } + + fclose(fp); + + nr_total = (int)(nr_procs + nr_tasks); +} + +int print_memory() +{ + FILE *fp; + unsigned int pagesize; + unsigned long total, free, largest, cached; + + if ((fp = fopen("/proc/meminfo", "r")) == NULL) + return 0; + + if (fscanf(fp, "%u %lu %lu %lu %lu", &pagesize, &total, &free, + &largest, &cached) != 5) + { + fclose(fp); + return 0; + } + + fclose(fp); + + printf("main memory: %ldK total, %ldK free, %ldK contig free, " + "%ldK cached\n", + (pagesize * total) / 1024, (pagesize * free) / 1024, + (pagesize * largest) / 1024, (pagesize * cached) / 1024); + + return 1; +} + +void get_procs() +{ + struct proc *p; + int i; + + p = prev_proc; + prev_proc = proc; + proc = p; + + if (proc == NULL) + { + proc = malloc(nr_total * sizeof(proc[0])); + + if (proc == NULL) + { + fprintf(stderr, "Out of memory!\n"); + exit(1); + } + } + + for (i = 0; i < nr_total; i++) + proc[i].p_flags = 0; + + parse_dir(); +} + +void parse_dir() +{ + DIR *p_dir; + struct dirent *p_ent; + pid_t pid; + char *end; //end是指向第一个不可转换的字符位置的指针 + + if ((p_dir = opendir("/proc")) == NULL) + { + perror("opendir on " _PATH_PROC); + exit(1); + } + + for (p_ent = readdir(p_dir); p_ent != NULL; p_ent = readdir(p_dir)) + { + pid = strtol(p_ent->d_name, &end, 10); //long strtol(char *str, char **endptr, int base)将串转换为长整数,base是基数,表示要转换的是几进制的数 + + if (!end[0] && pid != 0) + parse_file(pid); + } + + closedir(p_dir); +} + +void parse_file(pid_t pid) +{ + char path[PATH_MAX], name[256], type, state; + int version, endpt, effuid; //版本,端点,有效用户ID + unsigned long cycles_hi, cycles_lo; //高周期,低周期 + FILE *fp; + struct proc *p; + //int slot; //插槽? + int i; + //printf("parse_file\n"); + + sprintf(path, "/proc/%d/psinfo", pid); + + if ((fp = fopen(path, "r")) == NULL) + return; + + if (fscanf(fp, "%d", &version) != 1) + { + fclose(fp); + return; + } + + if (version != PSINFO_VERSION) + { //0 + fputs("procfs version mismatch!\n", stderr); + exit(1); + } + + if (fscanf(fp, " %c %d", &type, &endpt) != 2) + { + fclose(fp); + return; + } + + slot++; + //slot = SLOT_NR(endpt); + + if (slot < 0 || slot >= nr_total) + { + fprintf(stderr, "top: unreasonable endpoint number %d\n", endpt); + fclose(fp); + return; + } + + p = &proc[slot]; + + if (type == TYPE_TASK) + p->p_flags |= IS_TASK; + else if (type == TYPE_SYSTEM) + p->p_flags |= IS_SYSTEM; + + p->p_endpoint = endpt; + p->p_pid = pid; + + if (fscanf(fp, " %255s %c %d %d %lu %*u %lu %lu", + name, &state, &p->p_blocked, &p->p_priority, + &p->p_user_time, &cycles_hi, &cycles_lo) != 7) + { + + fclose(fp); + return; + } + + strncpy(p->p_name, name, sizeof(p->p_name) - 1); + p->p_name[sizeof(p->p_name) - 1] = 0; + + if (state != STATE_RUN) + p->p_flags |= BLOCKED; + p->p_cpucycles[0] = make64(cycles_lo, cycles_hi); + p->p_memory = 0L; + + if (!(p->p_flags & IS_TASK)) + { + int j; + if ((j = fscanf(fp, " %lu %*u %*u %*c %*d %*u %u %*u %d %*c %*d %*u", + &p->p_memory, &effuid, &p->p_nice)) != 3) + { + + fclose(fp); + return; + } + + p->p_effuid = effuid; + } + else + p->p_effuid = 0; + + for (i = 1; i < CPUTIMENAMES; i++) + { + if (fscanf(fp, " %lu %lu", + &cycles_hi, &cycles_lo) == 2) + { + p->p_cpucycles[i] = make64(cycles_lo, cycles_hi); + } + else + { + p->p_cpucycles[i] = 0; + } + } + + if ((p->p_flags & IS_TASK)) + { + if (fscanf(fp, " %lu", &p->p_memory) != 1) + { + p->p_memory = 0; + } + } + + p->p_flags |= USED; + + fclose(fp); +} + +u64_t cputicks(struct proc *p1, struct proc *p2, int timemode) +{ + int i; + u64_t t = 0; + for (i = 0; i < CPUTIMENAMES; i++) + { + if (!CPUTIME(timemode, i)) + continue; + if (p1->p_endpoint == p2->p_endpoint) + { + t = t + p2->p_cpucycles[i] - p1->p_cpucycles[i]; + } + else + { + t = t + p2->p_cpucycles[i]; + } + } + + return t; +} + +void print_procs(struct proc *proc1, struct proc *proc2, int cputimemode) +{ + int p, nprocs; + //u64_t idleticks = 0; + //u64_t kernelticks = 0; + u64_t systemticks = 0; + u64_t userticks = 0; + u64_t total_ticks = 0; + int blockedseen = 0; + static struct tp *tick_procs = NULL; //tp结构体的数组tick_procs,对所有的进程和任务(即上面读出来的nr_total)计算ticks + + if (tick_procs == NULL) + { + tick_procs = malloc(nr_total * sizeof(tick_procs[0])); + + if (tick_procs == NULL) + { + fprintf(stderr, "Out of memory!\n"); + exit(1); + } + } + + for (p = nprocs = 0; p < nr_total; p++) + { + u64_t uticks; + if (!(proc2[p].p_flags & USED)) + continue; + tick_procs[nprocs].p = proc2 + p; + tick_procs[nprocs].ticks = cputicks(&proc1[p], &proc2[p], cputimemode); + uticks = cputicks(&proc1[p], &proc2[p], 1); + total_ticks = total_ticks + uticks; + //printf("total_ticks:%llu\n",total_ticks); + /*if(p-NR_TASKS == IDLE) { + idleticks = uticks; + continue; + } + if(p-NR_TASKS == KERNEL) { + kernelticks = uticks; + } + */ + if (!(proc2[p].p_flags & IS_TASK)) + { + if (proc2[p].p_flags & IS_SYSTEM) + systemticks = systemticks + tick_procs[nprocs].ticks; + else + userticks = userticks + tick_procs[nprocs].ticks; + } + + nprocs++; + } + + if (total_ticks == 0) + return; + + printf("CPU states: %6.2f%% user, ", 100.0 * userticks / total_ticks); + printf("%6.2f%% system", 100.0 * systemticks / total_ticks); + printf("%6.2f%% in total\n", 100.0 * (systemticks + userticks) / total_ticks); + //printf("%6.2f%% kernel, ", 100.0 * kernelticks/ total_ticks); + //printf("%6.2f%% idle", 100.0 * idleticks / total_ticks); +} diff --git a/yeeshell.c b/yeeshell.c index 9d46d4e..1dda7c0 100644 --- a/yeeshell.c +++ b/yeeshell.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -25,8 +26,8 @@ #include #include #include -#include #include +#include #include "yeeshell.h" diff --git a/yeeshell.h b/yeeshell.h index ec01430..91140d9 100644 --- a/yeeshell.h +++ b/yeeshell.h @@ -95,4 +95,5 @@ void get_procs(); void parse_dir(); void parse_file(pid_t pid); void getkinfo(); -void print_procs(struct proc *proc1, struct proc *proc2, int cputimemode); \ No newline at end of file +void print_procs(struct proc *proc1, struct proc *proc2, int cputimemode); +u64_t cputicks(struct proc *p1, struct proc *p2, int timemode); \ No newline at end of file