/* ********************************************************************** * Simple shell * * Integrated commands: ls, cd, pwd, ps, kill. * * * * 15/04/02 Lucy B * * ******************************************************************** */ #include "def.h" int main (void) { int i; initcold(); for (;;) { initwarm(); if (getline()) if ((i = parse())) execute(i); } return 1; } void initcold (void) { /* Hides ctrl-c and ctrl-\ */ signal(SIGINT, SIG_IGN); signal (SIGQUIT, SIG_IGN); } void initwarm(void) { int i; backgnd = FALSE; lineptr = line; avptr = avline; infile[0] = '\0'; outfile[0] = '\0'; append = FALSE; for (i = 0; i")) { if (check(">")) append = TRUE; getname(outfile); } /* 5 */ if (check("&")) backgnd = TRUE; /* 6 */ if (check("\n")) return(i); else { fprintf(stderr, "Command line syntax error\n"); return (ERROR); } } void command(int i) /* separates the commands from the line entered */ { int j, flag, inword; for (j = 0; j': case '<': case '|': case '&': case '\n': if (inword==FALSE) cmdlin[i].av[j] = NULL; *avptr++ = '\0'; return; case ' ': case '\t': inword = FALSE; *avptr++ = '\0'; flag = 1; break; default: inword = TRUE; *avptr++ = *lineptr++; break; } } } } void execute(int j) { int i, fd, fds[2]; if(strcmp(cmdlin[0].av[0], "mycd") == 0) mycd(cmdlin[0].av); else { /* 1 */ if (infile[0] !='\0') /* checks for input redirection */ cmdlin[0].infd = open(infile, O_RDONLY); /* 2 */ if (outfile[0] !='\0'){ /* checks for output redirection */ if (append==FALSE) cmdlin[j-1].outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); else cmdlin[j-1].outfd = open(outfile, O_WRONLY | O_CREAT | O_APPEND, 0666); } /* 3 */ if (backgnd==TRUE) /* if cmd is to be run in the background */ signal (SIGCHLD, SIG_IGN); /* creates no zombies so that shell doesnt have to wait() */ else signal (SIGCHLD, SIG_DFL); /* 4 */ for (i = 0; i infd==0 && backgnd==TRUE) ptr->infd = open("/dev/null", O_RDONLY); /* 4 */ if (ptr->infd!=0) { close(0); dup(ptr->infd); } if (ptr->outfd!=1) { close(1); dup(ptr->outfd); } /* 5 */ if (backgnd==FALSE) { signal (SIGINT, SIG_DFL); signal (SIGQUIT, SIG_DFL); } /* 6 */ for (i = 3; iav[0], "duck") == 0){ printf("This shell has super duck powers\n"); printf(" (@_\n"); printf("\\\\\\_\\\n"); printf("<____)\n"); printf("quack\n"); } if(builtin(ptr)==0)/* checks whether cmd is built in before trying to execute */ exit(1); /* 7 */ execvp(ptr->av[0], ptr->av); exit(1); } } int check(char *ptr) { char *tptr; while (*lineptr== ' ' ) lineptr++; tptr = lineptr; while (*ptr!='\0' && *ptr==*tptr) { ptr++; tptr++; } if (*ptr!='\0') return(FALSE); else { lineptr = tptr; return(TRUE); } } int getname(char *name) { int i; for (i = 0; i': case '<': case '|': case '&': case ' ': case '\n': case '\t': *name = '\0'; return 1; default: *name++ = *lineptr++; break; } } *name = '\0'; return 1; } /* ********************** check for builtin in functions ************************* */ int builtin(struct cmd *ptr) { if(strcmp(ptr->av[0], "mypwd") == 0) /* ptr->av - pass as argv[] to function */ return mypwd(ptr->av); else if(strcmp(ptr->av[0], "mykill") == 0) return mykill(ptr->av); else if(strcmp(ptr->av[0], "myps") == 0) return myps(ptr->av); else if(strcmp(ptr->av[0], "myls") == 0) return myls(ptr->av); else return 1; } /* *************************** builtin functions ********************************* */ /* ************************************ mycd ************************************* */ void mycd(char **argv) { char *home; home = "HOME"; /* variable to retrieve from the environment */ if (argv[1] == NULL) argv[1] = getenv(home); /* searches env from shell */ if (chdir(argv[1]) == 0){ printf("New dir: "); fflush(stdout); system("pwd"); /*return 1;*/ } else{ printf("Sorry, directory does not exist\n"); /*return 0;*/ } } /* end mycd*/ /* ******************************** mykill *************************************** */ int mykill(char **argv) { int pid, sig; /* process id and signal id */ char *usage; /* usage message to be printed on user error */ usage = "Usage: kill [SIGNAL]... [process id]..."; /* checks that arguments have been provided, gives usage and exits if not */ if (argv[1] == NULL){ printf("%s\n", usage); return 0; } /*if*/ if (strcmp(argv[1], "-l") == 0){ printf("The signals sent by kill are: \n SIGTERM\t 15\n SIGKILL\t 9\n SIGHUP\t\t 1\n"); return 1; } /*if*/ if (argv[2] == NULL){ /* default option */ sig = 15; if(isdigit(argv[1][0]) == 0){ /* checks that a pid has been provided */ printf("%s\n", usage); return 0; } pid = atoi(argv[1]); } /*if*/ else if (isdigit(argv[2][0]) == 0){ printf("%s\n", usage); return 0; } /* else if*/ else if (strcmp(argv[1], "SIGTERM") == 0){ sig = 15; pid = atoi(argv[2]); } /*if*/ else if (strcmp(argv[1], "SIGKILL") == 0){ sig = 9; pid = atoi(argv[2]); } /*else if*/ else if (strcmp(argv[1], "SIGHUP") == 0){ sig = 1; pid = atoi(argv[2]); } /*else if*/ /* the arguments should be numerical and the first char of the string is tested */ else{ if ((isdigit(argv[1][0])) != 0){ sig = atoi(argv[1]); pid = atoi(argv[2]); } /*if*/ else { printf("%s\n", usage); return 0; } /*else*/ } /*else*/ if ((kill(pid, sig)) == 0){ /* kills process and prints an appropriate message */ printf("The process %i has been killed\n.", pid); } else{ printf("Process has not been killed\n"); return 1; } return 0; } /* end mykill */ /* *********************************** mypwd ************************************** */ int mypwd(char **argv) { char *buf; /* output of getcwd put here */ int size = 200; /* length of buffer */ buf=(char*)malloc(size); /* makes the string array of length size */ getcwd(buf, size); /* gets current working dir and puts result into buf */ printf("%s \n", buf); return 1; } /*end mypwd*/ /* ************************************* myps ************************************* */ int myps(char **argv) { DIR *dp; struct dirent *link; /* struct holding directory information */ struct stat buf; /* struct holding information about each file */ FILE *fp; char current[1025]; /* holds the current absolute path */ int currentpid, tty, uid, test; char name[1025]; /* 1025 is max posix directory size + null char */ char *usage; long unsigned time; /* extras */ char c; int d; unsigned u; usage = "Usage: ps [-A]"; dp = opendir("/proc"); printf("PID\t TTY\tTIME\t CMD\n"); /* print process info */ while ((link =readdir(dp)) != 0){ /* read the contents of the /proc directory */ if(isdigit((link -> d_name)[0])){ /* check that the entry is numerical, i.e represents a process */ uid = getuid(); /* find current user by findng the owner of current process */ sprintf(current, "/proc/%s/stat", link ->d_name); /* print entry to an array */ test= stat(current, &buf); /* retrieve uid of user owning dir and the process */ if (test == -1){ /* error testing */ printf("error when calling stat"); return 0; } fp = fopen(current, "r"); /* retrieve process information from file stat using absolute path */ fscanf(fp, "%d %s %c %d %d %d %d %d %u %u %u %u %u %lu", ¤tpid, name, &c, &d, &d, &d, &tty, &d, &u, &u, &u, &u, &u, &time); fclose(fp); memset(current, '\0', 1025); /* clear contents of array */ if (argv[1] == NULL){ if(buf.st_uid == uid){ /* print only processes that belong to current user */ printf("%d\t %d\t %-8lu %s\n", currentpid, tty, time, name); } } else if (strcmp(argv[1], "-A") == 0){ /* ps -A */ /* print processes belonging to all users */ printf("%d\t %d\t %-8lu %s\n", currentpid, tty, time, name); } else { /* error catching */ printf("%s\n", usage); return 0; } } /*if*/ } /*while*/ return 1; } /*myps*/ /* ************************************ myls *************************************** */ int myls (char **argv) { DIR *dp; struct dirent *link; /* struct holding directory information */ struct stat buf; /* struct holding information about each file */ int success; /* indicates return value of function */ int count; /* counter to store number of files in a directory */ char *list[600]; /* an array of strings */ char *usage; /* holds the command usage message */ char current [1025]; /* holds absolute path */ usage = "Usage: ls [OPTION]... [FILE]...\nmyls takes the arguments -h, -a, -l, -al and an optional directory.\n"; if(argv[1] == NULL){ /* If no arguments are provided the current dir is listed */ argv[1] = "."; } else{ if (argv[2] == NULL) argv[2] = "."; } /* ls -h */ if (strcmp(argv[1], "-h") == 0){ /* prints usage message and exits */ printf("%s\n", usage); return 1; } /*if*/ /* ls -a */ else if (strcmp(argv[1], "-a") == 0){ /* prints all files in the dir */ if((dp = opendir(argv[2])) == NULL){ /* tests for failure to open dir */ printf("%s\n", usage); /* prints usage message and exits */ return 0; } count = 0; /* includes hidden files */ while ((link = readdir (dp)) != 0){ list[count] = link -> d_name; count++; } sortList(list, count); } /*else if*/ /* ls -l */ else if (strcmp(argv[1], "-l") == 0){ /* long format, no hidden files */ if((dp = opendir(argv[2])) == NULL){ printf("%s\n", usage); return 0; } count = 0; while ((link = readdir (dp)) != 0){ if(strncmp(link -> d_name, ".", 1) != 0){ /* ignores files begining with a . */ sprintf(current, "%s//%s", argv[2], link -> d_name);/* creates an absolute path */ success = fullDetails(link, buf, current); /* gets extra file information */ count++; memset(current, '\0', 1025); /* clears the array */ } } } /*else if*/ /* ls -al */ else if (strcmp(argv[1], "-al") == 0){ /* long format, including hidden files */ if((dp = opendir(argv[2])) == NULL){ printf("%s\n", usage); return 0; } count = 0; while ((link = readdir (dp)) != 0){ sprintf(current, "%s//%s", argv[2], link -> d_name); success = fullDetails(link, buf, current); count++; memset(current, '\0', 1025); } } /*else if*/ /* ls */ else { /* normal case, doesnt show hidden files */ if((dp = opendir(argv[1])) == NULL){ printf("%s\n", usage); return 0; } count = 0; while ((link = readdir (dp)) != 0){ /* prints files whose first char is not . */ if(strncmp(link -> d_name, ".", 1) != 0){ list[count] = link -> d_name; count++; } } sortList(list, count); /* orders the output */ } /*else*/ closedir (dp); /* close the directory */ return 1; }/*end main*/ /* prints extra details for each file */ int fullDetails(struct dirent *link, struct stat buf, char current[]) { struct passwd *getuser; struct group *getgroup; stat(current, &buf); getuser = getpwuid(buf.st_uid); /* look up owner name using user id */ getgroup = getgrgid(buf.st_gid); /* look up group name using group id*/ printf("%4o \t", buf.st_mode & 07777);/* file type and permissions- &07777 translates to octal bits */ printf("%i \t", buf.st_nlink); /* number of hard links */ printf("%s \t", getuser -> pw_name); /* owner name */ printf("%s \t", getgroup -> gr_name); /* group name */ printf("%7ld \t", buf.st_size); /* file size in bytes */ printf("%ld \t", buf.st_mtime); /* time of last modification */ printf("%s \n", link -> d_name); /* file name */ fflush(stdout); return 1; } /*full details*/ /* function sorts and sends output to stdout */ void sortList(char *list[], int count) { int i; qsort(list, count, sizeof(char*), cmp); for (i = 0; i < count; i++){ printf("%s\n", list[i]); /*fflush(stdout);*/ } } /*sortList*/ /* function required by qsort */ int cmp(const void *s1, const void *s2) { const char *a = s1; const char *b = s2; return strcmp( a, b ); } /*cmp*/