#define MAX_COMMAND_LENGTH 1024 /* maximum length of each command */
#define MAX_COMMAND_NUM 512 /* maximum number of commands */
#define MAX_COMMAND 64 /* maximum number of characters in each command */
#define MAX_INFONUM_LENGTH 20 /* maximum length of number in each info */
#define MEM_PATH "/proc/meminfo" /* path to info of memory */
#define PROCESS_PATH "/proc/kinfo" /* path to info of process */
#define BG_PATH "/dev/null" /* background process i/o path */
#define CPUTIME(m, i) (m & (1L << (i)))
char command[MAX_COMMAND_NUM][MAX_COMMAND_LENGTH]; /* input command history */
int cnt = 0; /* number of input commands */
const char* cputimenames[] = { "user", "ipc", "kernelcall" };
struct proc* proc = NULL, * prev_proc = NULL;
unsigned int nr_procs, nr_tasks;
#define CPUTIMENAMES (sizeof(cputimenames) / sizeof(cputimenames[0]))
int param_num; /* Number of parameters */
int bg_fg;/* Background or Foreground flag 1 for background while 0
int input_mode; /* Input mode 0 for stdin while 1 for file input */
int output_mode; /* Output mode 0 for stdout , 1 for file output, 2 for
char* input_file; /* Input file */
char* output_file; /* Output file */
int pipe_idx[MAX_COMMAND_LENGTH / MAX_COMMAND];/* If there is a pipe,
this represents the index of each command in the commandline */
int pipe_num; /* Number of pipe */
u_int64_t total_memory; /* Total memory */
u_int64_t free_memory; /* Free memory */
u_int64_t cached_memory; /* Cache memory */
double total_cpu_usage; /* Total CPU usage */
u_int64_t p_cpucycles[CPUTIMENAMES];
void eval(const char* cmd); /* exec command */
int builtin_cmd(const char* buf[MAX_COMMAND]); /* builtin command */
void parse_cmd(char* buf[MAX_COMMAND], const char* cmd, struct
Program_Details* pd); /* split commandline into commands */
void waitfg(pid_t pid); /* wait for foreground process to exit */
void pipeline(char* argv[MAX_COMMAND][MAX_COMMAND], const char*
buf[MAX_COMMAND], struct Program_Details pd); /* a pipeline for running
u_int64_t make64(unsigned long lo, unsigned long hi);
void parse_file(pid_t pid);
u_int64_t cputicks(struct proc* p1, struct proc* p2, int timemode);
double get_usage(struct proc* proc1, struct proc* proc2, int cputimemode);
main(int argc, char** argv) {
char cmdline[MAX_COMMAND_LENGTH]; /* input command */
printf("%s:/# ", getcwd(NULL, NULL));
while (fgets(cmdline, MAX_COMMAND_LENGTH, stdin) == NULL) {
strcpy(command[cnt++], cmdline);
char* buf[MAX_COMMAND] = { NULL };
struct Program_Details pd = {
parse_cmd(buf, cmd, &pd);
signal(SIGCHLD, SIG_IGN);
signal(SIGCHLD, SIG_DFL);
char* argv[MAX_COMMAND][MAX_COMMAND] = { NULL };
if ((pid = fork()) == 0) {
for (int i = 0; i <= pd.pipe_num; i++) {
pipe(p[i]); /* creat a pipe */
if ((pid = fork()) == 0) {
if (pd.input_mode == 1) {
int fd = open(pd.input_file, O_RDONLY);
close(p[i][0]); /* Block input from the parent
else if (i == pd.pipe_num) {
if (pd.output_mode == 1) {
int fd = open(pd.output_file, O_WRONLY |
else if (pd.output_mode == 2) {
int fd = open(pd.output_file, O_WRONLY |
if (execvp(argv[i][0], argv[i]) < 0) {
printf("Error: %s is not a valid command",
if ((pid = fork()) == 0) {
if (pd.input_mode == 1) {
int fd = open(pd.input_file, O_RDONLY);
if (pd.output_mode == 1) {
int fd = open(pd.output_file, O_WRONLY | O_CREAT);
else if (pd.output_mode == 2) {
int fd = open(pd.output_file, O_WRONLY | O_APPEND);
int fd = open(BG_PATH, O_RDWR);
if (execvp(buf[0], buf) < 0) {
printf("Error: %s is not a valid command", cmd);
parse_cmd(char* buf[MAX_COMMAND], const char* cmd, struct Program_Details*
int i = 0, cnt = 0, j = 0;
int input_idx = 0, output_idx = 0;
while (cmd[i] != ' ' && cmd[i] != '\n') {
pd->input_mode = 1, input_idx = cnt;
else if (!strcmp(p, ">"))
pd->output_mode = 1, output_idx = cnt;
else if (!strcmp(p, ">>"))
pd->output_mode = 2, output_idx = cnt;
else if (!strcmp(p, "&"))
else if (!strcmp(p, "|")) {
pd->pipe_idx[cmd_idx++] = cnt;
buf[cnt] = (char*)malloc(sizeof(char) * strlen(p));
if (pd->input_mode == 1) {
pd->input_file = (char*)malloc(sizeof(char) *
strcpy(pd->input_file, buf[input_idx]);
if (pd->output_mode == 1 || pd->output_mode == 2) {
pd->output_file = (char*)malloc(sizeof(char) *
strlen(buf[output_idx]));
strcpy(pd->output_file, buf[output_idx]);
pd->pipe_idx[cmd_idx] = cnt;
builtin_cmd(const char* buf[MAX_COMMAND]) {
if (!strcmp(buf[0], "exit"))
else if (!strcmp(buf[0], "cd")) {
printf("Failed To Open Directory %s\n", buf[1]);
else if (!strcmp(buf[0], "history")) {
int n = buf[1] == NULL ? cnt - 1 : atoi(buf[1]);
if (n > cnt) printf("Error: n is too large\n");
for (int i = cnt - n; i < cnt; i++)
printf("%s", command[i]);
else if (!strcmp(buf[0], "mytop")) {
char* meminfo[MAX_INFONUM_LENGTH];
int fd = open(MEM_PATH, O_RDONLY);
char p[MAX_COMMAND_LENGTH];
while (read(fd, p, MAX_COMMAND_LENGTH) > 0);
char* str = strtok(p, " ");
meminfo[idx] = (char*)malloc(sizeof(char) * strlen(str));
strcpy(meminfo[idx++], str);
u_int64_t pagesize = (u_int64_t)atoi(meminfo[0]);
u_int64_t total = (u_int64_t)atoi(meminfo[1]);
u_int64_t free = (u_int64_t)atoi(meminfo[2]);
u_int64_t cache = (u_int64_t)atoi(meminfo[4]);
tm.total_memory = (pagesize * total) / 1024;
tm.free_memory = (pagesize * free) / 1024;
tm.cached_memory = (pagesize * cache) / 1024;
printf("Memory Usage: main memory:%uK free memory:%uK cache
memory: % uK\n", tm.total_memory, tm.free_memory, tm.cached_memory);
int fd2 = open(PROCESS_PATH, O_RDONLY);
printf("Error: open kinfo failed\n");
bufsize = read(fd2, buf, sizeof(buf));
printf("Error: reading kinfo\n");
nr_procs = (unsigned int)atoi(strtok(buf, " "));
nr_tasks = (unsigned int)atoi(strtok(NULL, " "));
nr_total = (int)(nr_tasks + nr_procs);
tm.total_cpu_usage = get_usage(prev_proc, proc, 1);
printf("CPU Usage: %.2f%%\n", tm.total_cpu_usage);
waitpid(pid, &status, 0);
pipeline(char* argv[MAX_COMMAND][MAX_COMMAND], const char*
buf[MAX_COMMAND], struct Program_Details pd) {
for (int i = 0; i <= pd.pipe_num; i++) {
for (int j = pd.pipe_idx[i]; j < pd.pipe_idx[i + 1]; j++) {
argv[i][j - pd.pipe_idx[i]] = (char*)malloc(sizeof(buf[j]));
strcpy(argv[i][j - pd.pipe_idx[i]], buf[j]);
proc = (struct proc*)malloc(nr_total * sizeof(proc[0]));
printf("Usage: Out of memory\n");
for (i = 0; i < nr_total; i++)
u_int64_t make64(unsigned long lo, unsigned long hi) {
return ((u_int64_t)hi << 32) | (u_int64_t)lo;
void parse_file(pid_t pid) {
char path[MAXBUF], name[256], type, state;
int version, endpt, effuid;
unsigned long cycles_hi, cycles_lo;
sprintf(path, "/proc/%d/psinfo", pid);
if ((fp = fopen(path, "r")) == NULL)
if (fscanf(fp, "%d", &version) != 1) {
if (fscanf(fp, " %c %d", &type, &endpt) != 2) {
if (slot < 0 || slot >= nr_total) {
fprintf(stderr, "top: unreasonable endpoint number %d\n", endpt);
else if (type == TYPE_SYSTEM)
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) {
strncpy(p->p_name, name, sizeof(p->p_name) - 1);
p->p_name[sizeof(p->p_name) - 1] = 0;
p->p_cpucycles[0] = make64(cycles_lo, cycles_hi);
if (!(p->p_flags & IS_TASK)) {
if ((j = fscanf(fp, " %lu %*u %*u %*c %*d %*u %u %*u %d %*c %*d
& p->p_memory, &effuid, &p->p_nice)) != 3) {
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);
if ((p->p_flags & IS_TASK)) {
if (fscanf(fp, " %lu", &p->p_memory) != 1) {
if ((p_dir = opendir("/proc")) == NULL) {
for (p_ent = readdir(p_dir); p_ent != NULL; p_ent = readdir(p_dir)) {
pid = strtol(p_ent->d_name, &end, 10);
u_int64_t cputicks(struct proc* p1, struct proc* p2, int timemode) {
for (i = 0; i < CPUTIMENAMES; i++) {
if (!CPUTIME(timemode, i))
if (p1->p_endpoint == p2->p_endpoint) {
t = t + p2->p_cpucycles[i] - p1->p_cpucycles[i];
t = t + p2->p_cpucycles[i];
double get_usage(struct proc* proc1, struct proc* proc2, int cputimemode) {
static struct tp* tick_procs = NULL;
if (tick_procs == NULL) {
tick_procs = malloc(nr_total * sizeof(tick_procs[0]));
if (tick_procs == NULL) {
fprintf(stderr, "Out of memory!\n");
for (p = nprocs = 0; p < nr_total; p++) {
if (!(proc2[p].p_flags & USED))
tick_procs[nprocs].p = proc2 + p;
tick_procs[nprocs].ticks = cputicks(&proc1[p], &proc2[p],
uticks = cputicks(&proc1[p], &proc2[p], 1);
total_ticks = total_ticks + uticks;
if (!(proc2[p].p_flags & IS_TASK)) {
if (proc2[p].p_flags & IS_SYSTEM)
systemticks = systemticks + tick_procs[nprocs].ticks;
userticks = userticks + tick_procs[nprocs].ticks;
return 100.0 * (userticks + systemticks) / total_ticks;