|
1. A Makefile that compiles the shell |
CC = gcc CCFLAGS = -g LD = gcc LDFLAGS = CLEAN = rm -f *.o cse451sh %.o: %.c $(CC) $(CCFLAGS) -c $< -o $@ all: 451sh clobber: clean all 451sh: shell.o ${LD} ${LDFLAGS} $^ -o $@ clean: $(CLEAN)
|
2. Source for the shell |
/*********************************************************** * A skeletal Linux shell that handles the execution of user * programs and three system calls: exit, physusage, clear_physusage **********************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <linux/kernel.h> #include <linux/sys.h> #include <sys/syscall.h> #include <errno.h> #include <sys/types.h> #include <sys/wait.h> #define __NR_physusage 223 #define __NR_clearphysusage 224 #define MAX_INPUT 1024 #define DELIMITER " \t\n" /* parses user input by whitespace and returns an array of words */ char **parse_input(char *instr); /* frees any dynamic memory we use in the token buffer */ void freeinput(char **input); int main(int argc, char *argv[]) { /* forked process id */ int procid; /* variables for calculating page requests */ int total; int usageArray[MAX_ORDER]; /* input buffer to hold user input */ char inputbuffer[MAX_INPUT]; /* Just one character for flushing stdin*/ char ch; /* this will be the array of the file path and arguments */ char **tok_input = NULL; /* this structure holds various information about the system */ struct sysinfo ansr; int count = -1; int errtrap = 0; /* A loop variable */ int i; /* loop until we get the exit command */ while(1) { printf("CSE451shell%% "); /* grab a line of user input */ if (!(fgets(inputbuffer, MAX_INPUT, stdin))) { fprintf(stderr, "\nINPUT ERROR: error with fgets\n"); continue; } /* Did we exceed the input buffer? */ if (strlen(inputbuffer)==MAX_INPUT-1 && inputbuffer[MAX_INPUT-2]!='\n') { fprintf(stderr,"\nSorry, but the input is limited to %d chars. \n\"%s\" not accepted.\nTry again.\n",MAX_INPUT,inputbuffer); /* Discard rest of input line */ while ((ch = getchar()) != '\n' && ch != EOF); continue; } /* our input should be split by ' ', '\t' and '\n' after this call */ tok_input = parse_input(inputbuffer); /* If empty input start over */ if (tok_input == NULL) continue; /* "exit" syscall just ends this program */ if (strcmp("exit", tok_input[0]) == 0) { exit(0); } else if (strcmp("chdir", tok_input[0]) == 0) { if (tok_input[1] == NULL) { fprintf(stderr, "\nchdir: Not enough arguments\n"); } else if (!chdir(tok_input[1])) { fprintf(stderr, "\nchdir: errno %d\n",errno); } } else if (strcmp("physusage", tok_input[0]) == 0) { if (syscall(__NR_physusage, usageArray)) { fprintf(stderr, "\nSyscall %d returned errno: %d\n",__NR_physusage,errno); } else { /* get total */ for (i = 0, total = 0; i < MAX_ORDER; i++) { total += usageArray[i]; } /* print statistics */ printf("\nTotal requests to page_alloc: %d\n\n", total); for (i = 0; i < MAX_ORDER; i++) { if (usageArray[i]) { printf("Requests for order %d pages: %d (%f)\n", i, usageArray[i], usageArray[i]/(float)total); } } } } else if (strcmp("clear_physusage", tok_input[0]) == 0) { if (syscall(__NR_clearphysusage)) { fprintf(stderr, "\nSyscall %d returned errno: %d\n",__NR_physusage,errno); } } else { /* the user is running a user program */ procid = fork(); if (procid < 0) { fprintf(stderr, "\nERROR: Could not fork child, Errno: %d\n",errno); } else if (procid == 0) { /* if execvp returns then something went wrong */ errtrap = execvp(tok_input[0], tok_input); if (errtrap) { /* this is a switch in case I want to add more error handling */ switch (errno) { case ENOENT: fprintf(stderr, "\n%s: command not found\n", tok_input[0]); break; case ENOMEM: fprintf(stderr, "\nInsufficient memory for process\n"); break; default: fprintf(stderr, "\nERROR: execvp not successful. Errno: %d\n",errno); } exit(errno); } } else { wait(NULL); } } freeinput(tok_input); } printf("Exited loop for some reason\n"); freeinput(tok_input); return 0; } /* takes in a string of user input and places each word into an array * returns a pointer to the array of string tokens * the array returned will have a NULL pointer in its last index */ char **parse_input(char *instr) { char **token_list; char *token = NULL; char *instrCopy; int token_count = 0; int i = 0; /* first we need to know how many tokens exist so we can allocate the correct number of pointers */ instrCopy = strdup(instr); if (instrCopy == NULL) { fprintf(stderr, "Insufficient memory\n"); exit(errno); } token = strtok(instrCopy, DELIMITER); while (token) { token = strtok(NULL, DELIMITER); token_count++; } free(instrCopy); /* Do we have an empty input, then return and do not parse */ if (token_count <= 0) return NULL; token_list = (char **)malloc((token_count+1) * sizeof(char *)); if (token_list == NULL) { fprintf(stderr, "Insufficient memory\n"); exit(errno); } /* tokenize the string and place each token in the array */ token_count=0; token = strtok(instr, DELIMITER); while (token) { token_list[token_count] = strdup(token); if (token_list[token_count] == NULL) { fprintf(stderr, "Insufficient memory\n"); exit(errno); } token = strtok(NULL, DELIMITER); token_count++; } token_list[token_count] = NULL; return token_list; } /* free the token buffer */ void freeinput(char **input) { int i; for (i = 0; input[i]; i++) { free(input[i]); } free(input); }
|
3. List of all kernel file changes |
Added the system call table entries for the two system calls at entries 294 and 295:
.long sys_physusage .long sys_clearphysusage /* 295 */You should add the /* 295 */ comment, since these comments give a rough guide to where we are in the table. Respect coding conventions!
#define __NR_physusage 294 #define __NR_clearphysusage 295to name the new system call entries. This is only done for completeness. It would be mandatory if we were creating a libc stub for these system calls. Instead we just repeat these definitions in our shell.
|
4. Changes to page_alloc.c |
At the top of page_alloc.c:
static int pageUsage[MAX_ORDER+1];In __alloc_pages():
struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order) { /* variable declarations */ if (order >= 0 && order <= MAX_ORDER) { pageUsage[order]++; } /* rest of function */ }At the end of the file:
asmlinkage int sys_physusage(int *usageArray) { if (!access_ok(VERIFY_WRITE, usageArray, sizeof(int) * MAX_ORDER)) { return -EFAULT; } else if (!copy_to_user(usageArray, pageUsage, sizeof(int) * MAX_ORDER)) { return -EFAULT; } else { return 0; } } asmlinkage int sys_clearphysusage() { int i; for (i = 0; i < MAX_ORDER; i++) { pageUsage[i] = 0; } }