int main() { int status; // command variable char *args[20]; int i; for (i = 0; i < 20; ++i) { args[i] = NULL; } // background variable int bg; // history variables int historynbr = 1; int *toBeSaved = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); struct cmd **history = mmap(NULL, sizeof(struct cmd), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); int notInitialized = 1; while(notInitialized) { int i; for (i = 0; i < 10; i++) { history[i] = (struct cmd*) malloc(sizeof(struct cmd)); } notInitialized = 0; } // job variable struct job * head = NULL; printf("\n-----------------------------------------\nWelcome!\nThis is a simple shell. \nEnter 'help' for more info.\n-----------------------------------------\n\n"); while (1) { int cnt = getcmd("\n>> ", args, &bg); // int i; // for (i = 0; i < cnt; i++) // printf("\nArg[%d] = %s", i, args[i]); // if (bg) // printf("\nBackground enabled..\n"); // else // printf("\nBackground not enabled \n"); printf("\n"); /**********************************/ /******** INTERNAL COMMAND ********/ /**********************************/ // HISTORY if (cnt != 0 && isnumber(args[0])) { int nbr = stringtoint(args[0]); *toBeSaved = 0; // find the index of the command in the history, if it is there int index = searchhistory(history, nbr); if (index == -1){ printf("***ERROR command ID '%s' does not exist\n\n", args[0]); } else { int j; for (j = 0; j < 20; j++) { args[j] = history[index]->args[j]; } //check is it was in backgorund int bgIndex; if ((bgIndex = isbg(args)) > 0) { bg = 1; args[bgIndex] = NULL; } } } // if nothing is entered if(cnt == 0){ // do nothing } // HELP else if (strcmp(args[0], "help") == 0){ printf("This is a simple shell brought to you by Felix Dube\n\nIt keeps the last 10 commands in HISTORY.\nEnter 'history' to see the list of commands in history.\n\nProcess can be run un BACKGROUND using the '&' argument.\nEnter 'jobs' to see the list of process running in background\nEnter 'fg' and the process job number to bring a process in the forground.\n\n"); } // PRINT HISTORY else if (strcmp(args[0], "history") == 0) { printhistory(history); initargs(args); } // PRESENT WORKING DIRECTORY else if( strcmp(args[0], "pwd") == 0) { char* cwd; char buff[PATH_MAX + 1]; cwd = getcwd( buff, PATH_MAX + 1 ); if( cwd != NULL ) { printf( "My working directory is %s.\n", cwd ); } addhistory(history, args, historynbr); historynbr++; initargs(args); } // CHANGE DIRECTORY else if( strcmp(args[0], "cd") == 0 ){ chdir(args[1]); addhistory(history, args, historynbr); historynbr++; initargs(args); } // JOBS else if( strcmp(args[0], "jobs") == 0) { printjobs(&head); addhistory(history, args, historynbr); historynbr++; initargs(args); } // FOREGROUND else if( strcmp(args[0], "fg") == 0) { addhistory(history, args, historynbr); historynbr++; if (jobexist(head, stringtoint(args[1]))){ waitpid(stringtoint(args[1]), &status, 0); } else{ printf("***ERROR job PID '%s' does not exist\n\n", args[1]); } initargs(args); } // EXIT else if ( strcmp(args[0], "exit") == 0){ exit(0); } /**********************************/ /******** EXTERNAL COMMAND ********/ /**********************************/ else if (cnt != 0) { *toBeSaved = 1; pid_t pid = fork(); /**** PARENT ****/ // the parent process either wait for the child process or not // depending if the command is executed in background or not if ( pid != 0 ) { if (bg) { pushjob(&head, pid, args); // save the cmd if it was valid and not already in the history if(*toBeSaved){ int i = 0; while(args[i] != NULL){ i++; } args[i] = "&"; addhistory(history, args, historynbr); historynbr++; } initargs(args); } else { waitpid(pid, &status, 0); // save the cmd if it was valid and not already in the history if(*toBeSaved){ addhistory(history, args, historynbr); historynbr++; } initargs(args); } } /**** CHILD ****/ // the command is exucuted in the child process else { if (cnt != 0 && isnumber(args[0])){ exit(0); } // change the output of the process when specified (eg. ls > out.txt) int argNbr; if ((argNbr = isredirected(args)) > 0){ freopen(args[argNbr+1], "w", stdout); args[argNbr] = NULL; args[argNbr+1] = NULL; } // execute the command and make sure it is valid if (execvp(args[0], args) == -1) { *toBeSaved = 0; printf("***ERROR invalid command\n"); } } } } }
static void RunBuiltInCmd(commandT* cmd) { if (!strcmp(cmd->argv[0],"fg")) { /* No number passed */ if ((cmd->argv[1]==NULL) && (jobs !=NULL)) { /* Restart the process if it has been stopped */ pid_t temp_pid = tofg_mostrecent(jobs); if(temp_pid != (pid_t)-1) { kill(-temp_pid, SIGCONT); //waitpid(temp_pid, &status, WUNTRACED); waitfg(temp_pid); } /* Job number passed */ } else if((cmd->argv[1] != NULL) && (jobs != NULL)) { // Restart the process if it has been stopped pid_t temp_pid = tofg(atoi(cmd->argv[1])); if(temp_pid != (pid_t)-1) { kill(-temp_pid, SIGCONT); //waitpid(temp_pid, &status, WUNTRACED); waitfg(temp_pid); } } else { printf("fg: current: no such job\n"); } } if (!strcmp(cmd->argv[0],"bg")) { if ((cmd->argv[1]==NULL) && (jobs != NULL)) { pid_t temp_pid = tobg_mostrecent(jobs); if(temp_pid != (pid_t)-1) { kill(temp_pid, SIGCONT); } } else if((cmd->argv[1] != NULL) && (jobs != NULL)) { pid_t temp_pid = tobg(atoi(cmd->argv[1])); if(temp_pid != (pid_t)-1) { kill(temp_pid, SIGCONT); } } else { printf("bg: current: no such job\n"); } } if (!strcmp(cmd->argv[0],"jobs")) { printjobs(); } if (!strcmp(cmd->argv[0],"cd")) { changeDirectory(cmd->argv); } if (!strcmp(cmd->argv[0],"alias")) { if (cmd->argv[1]==NULL) { aliaslist* curr=aliases; while (curr != NULL) { printf("alias %s='%s'\n" , curr->new_name, curr->previous_name); curr=curr->next; } } else { changeAlias(cmd->cmdline); } } if (!strcmp(cmd->argv[0],"unalias")) { if (cmd->argv[1]==NULL) { fprintf(stderr, "Must give an argument to unalias"); } else { int result = remove_from_aliases(cmd->argv[1]); if (result == 0) printf("No such alias %s\n", cmd->argv[1]); } } }
static int mklock(char *file) { int fd, try; Dir *dir; fd = openlock(file); if (fd >= 0) { /* make it a lock file if it wasn't */ dir = dirfstat(fd); if (dir == nil) error("%s vanished: %r", file); dir->mode |= DMEXCL; dir->qid.type |= QTEXCL; dirfwstat(fd, dir); free(dir); /* reopen in case it wasn't a lock file at last open */ close(fd); } for (try = 0; try < 65 && (fd = openlock(file)) < 0; try++) sleep(10*1000); return fd; } void main(int argc, char *argv[]) { Job *j; Tm tm; Time t; ulong now, last; /* in seconds */ int i, lock; debug = 0; ARGBEGIN{ case 'c': createuser(); exits(0); case 'd': debug = 1; break; default: usage(); }ARGEND if(debug){ readalljobs(); printjobs(); exits(0); } initcap(); /* do this early, before cpurc removes it */ switch(fork()){ case -1: fatal("can't fork: %r"); case 0: break; default: exits(0); } /* * it can take a few minutes before the file server notices that * we've rebooted and gives up the lock. */ lock = mklock("/cron/lock"); if (lock < 0) fatal("cron already running: %r"); argv0 = "cron"; srand(getpid()*time(0)); last = time(0); for(;;){ readalljobs(); /* * the system's notion of time may have jumped forward or * backward an arbitrary amount since the last call to time(). */ now = time(0); /* * if time has jumped backward, just note it and adapt. * if time has jumped forward more than a day, * just execute one day's jobs. */ if (now < last) { clog("time went backward"); last = now; } else if (now - last > Day) { clog("time advanced more than a day"); last = now - Day; } now = minute(now); for(last = minute(last); last <= now; last += Minute){ tm = *localtime(last); t.min = 1ULL << tm.min; t.hour = 1 << tm.hour; t.wday = 1 << tm.wday; t.mday = 1 << tm.mday; t.mon = 1 << (tm.mon + 1); for(i = 0; i < nuser; i++) for(j = users[i].jobs; j; j = j->next) if(j->time.min & t.min && j->time.hour & t.hour && j->time.wday & t.wday && j->time.mday & t.mday && j->time.mon & t.mon) rexec(&users[i], j); } seek(lock, 0, 0); write(lock, "x", 1); /* keep the lock alive */ /* * if we're not at next minute yet, sleep until a second past * (to allow for sleep intervals being approximate), * which synchronises with minute roll-over as a side-effect. */ sleepuntil(now + Minute + 1); } /* not reached */ }