void freejobs() { struct job *jp; collectjobs(WNOHANG); if (jobnote) { int savefd = setb(2); for (jp = joblst; jp; jp = jp->j_nxtp) { if (jp->j_flag & J_NOTIFY) { if (jp->j_jid) printjob(jp, PR_DFL); else if (jp->j_flag & J_FOREGND) printjob(jp, PR_STAT); else printjob(jp, PR_STAT|PR_PGID); } } (void) setb(savefd); } if (jobdone) { for (jp = joblst; jp; jp = jp->j_nxtp) { if (jp->j_flag & J_DONE) freejob(jp); } } }
recvjob() { struct stat stb; char *bp = pbuf; int status; /* * Perform lookup for printer name or abbreviation */ if ((status = pgetent(line, printer)) < 0) fatal("cannot open printer description file"); else if (status == 0) fatal("unknown printer"); if ((LF = pgetstr("lf", &bp)) == NULL) LF = DEFLOGF; if ((SD = pgetstr("sd", &bp)) == NULL) SD = DEFSPOOL; if ((LO = pgetstr("lo", &bp)) == NULL) LO = DEFLOCK; (void) close(2); (void) open(LF, O_WRONLY|O_APPEND); if (chdir(SD) < 0) fatal("cannot chdir to %s", SD); if (stat(LO, &stb) == 0 && (stb.st_mode & 010)) { /* queue is disabled */ putchar('\1'); /* return error code */ exit(1); } if (readjob()) printjob(); }
/* * eval - Evaluate the command line that the user has just typed in * * If the user has requested a built-in command (quit, jobs, bg or fg) * then execute it immediately. Otherwise, fork a child process and * run the job in the context of the child. If the job is running in * the foreground, wait for it to terminate and then return. Note: * each child process must have a unique process group ID so that our * background children don't receive SIGINT (SIGTSTP) from the kernel * when we type ctrl-c (ctrl-z) at the keyboard. */ void eval(char *cmdline) { char *argv[MAXARGS]; int isBG = parseline(cmdline, argv); if (argv[0] == NULL) return; if (builtin_cmd(argv)) return; sigset_t allset; sigfillset(&allset); sigprocmask(SIG_BLOCK, &allset, NULL); pid_t childpid = fork(); if (childpid == -1) unix_error("fork failed"); if (childpid == 0) { sigprocmask(SIG_UNBLOCK, &allset, NULL); if (setpgid(0, 0) == -1) unix_error("setpgrp failed"); if (execv(argv[0], argv) == -1) unix_error("execv failed"); } if (isBG) { addjob(jobs, childpid, BG, cmdline); printjob(jobs, childpid); sigprocmask(SIG_UNBLOCK, &allset, NULL); } else { addjob(jobs, childpid, FG, cmdline); sigprocmask(SIG_UNBLOCK, &allset, NULL); waitfg(childpid); } return; }
/* listjobs - Print the job list */ void listjobs(struct job_t *jobs) { int i; for (i = 0; i < MAXJOBS; i++) { printjob(jobs, jobs[i].pid); } }
void recvjob(void) { struct stat stb; int status; /* * Perform lookup for printer name or abbreviation */ if ((status = cgetent(&bp, printcapdb, printer)) == -2) frecverr("cannot open printer description file"); else if (status == -1) frecverr("unknown printer %s", printer); else if (status == -3) fatal("potential reference loop detected in printcap file"); if (cgetstr(bp, "lf", &LF) == -1) LF = _PATH_CONSOLE; if (cgetstr(bp, "sd", &SD) == -1) SD = _PATH_DEFSPOOL; if (cgetstr(bp, "lo", &LO) == -1) LO = DEFLOCK; (void)close(2); /* set up log file */ PRIV_START; if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { syslog(LOG_ERR, "%s: %m", LF); (void)open(_PATH_DEVNULL, O_WRONLY); } PRIV_END; if (chdir(SD) < 0) frecverr("%s: %s: %m", printer, SD); if (stat(LO, &stb) == 0) { if (stb.st_mode & 010) { /* queue is disabled */ putchar('\1'); /* return error code */ exit(1); } } else if (stat(SD, &stb) < 0) frecverr("%s: %s: %m", printer, SD); minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ signal(SIGTERM, rcleanup); signal(SIGPIPE, rcleanup); if (readjob()) printjob(); }
recvjob() { struct stat stb; char *bp = pbuf; int status, rcleanup(); /* * Perform lookup for printer name or abbreviation */ if ((status = pgetent(line, printer)) < 0) frecverr("cannot open printer description file"); else if (status == 0) frecverr("unknown printer %s", printer); if ((LF = pgetstr("lf", &bp)) == NULL) LF = DEFLOGF; if ((SD = pgetstr("sd", &bp)) == NULL) SD = DEFSPOOL; if ((LO = pgetstr("lo", &bp)) == NULL) LO = DEFLOCK; (void) close(2); /* set up log file */ if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { syslog(LOG_ERR, "%s: %m", LF); (void) open("/dev/null", O_WRONLY); } if (chdir(SD) < 0) frecverr("%s: %s: %m", printer, SD); if (stat(LO, &stb) == 0) { if (stb.st_mode & 010) { /* queue is disabled */ putchar('\1'); /* return error code */ exit(1); } } else if (stat(SD, &stb) < 0) frecverr("%s: %s: %m", printer, SD); minfree = read_number("minfree"); ddev = find_dev(stb.st_dev, S_IFBLK); if ((dfd = open(ddev, O_RDONLY)) < 0) syslog(LOG_WARNING, "%s: %s: %m", printer, ddev); signal(SIGTERM, rcleanup); signal(SIGPIPE, rcleanup); if (readjob()) printjob(); }
void printallbanks() { printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); int num = 0; jobqueue *j; j = (jobqueue *)malloc(sizeof(jobqueue)); for(num; num<4; num++) { int jnum = row[num].jsize; int a=0; printf("-------------bank %d-----------\n", num); { int k = &row[num]; printf(" current rowbuffer : %s \n", row[num].rowbuffer); printf(" current jobqueue size : %d \n ", row[num].jsize); if(row[num].busy==1) { printf(" Row is busy \n"); } else { printf(" Row is idle \n"); } printf(" current job : \n"); j = row[num].rq; for(a; a<jnum; a++) { printf(" %d job \n", a); printjob(j); printf("\n"); j = j->before; } } } printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n\n\n"); }
/* * sigchld_handler - The kernel sends a SIGCHLD to the shell whenever * a child job terminates (becomes a zombie), or stops because it * received a SIGSTOP or SIGTSTP signal. The handler reaps all * available zombie children, but doesn't wait for any other * currently running children to terminate. */ void sigchld_handler(int sig) { for (;;) { int status; pid_t childpid = waitpid(-1, &status, WNOHANG | WUNTRACED | WCONTINUED); if (childpid == -1) break; //unix_error("waitpid failed"); if (childpid == 0) break; if (WIFEXITED(status)) { deletejob(jobs, childpid); // TODO: print exit code, WEXITSTATUS } else if (WIFSIGNALED(status)){ deletejob(jobs, childpid); printf("Job [1] (%d) terminated by signal %d\n", childpid, WTERMSIG(status)); } else if (WIFSTOPPED(status)) { getjobpid(jobs, childpid)->state = ST; printjob(jobs, childpid); } else if (WIFCONTINUED(status)) { int *state = &getjobpid(jobs, childpid)->state; if (*state == ST) *state = BG; } } return; }
/* * Make a pass through the printcap database and start printing any * files left from the last time the machine went down. */ static void startup(void) { int pid, status, more; struct printer myprinter, *pp = &myprinter; more = firstprinter(pp, &status); if (status) goto errloop; while (more) { if (ckqueue(pp) <= 0) { goto next; } if (lflag) syslog(LOG_INFO, "lpd startup: work for %s", pp->printer); if ((pid = fork()) < 0) { syslog(LOG_WARNING, "lpd startup: cannot fork for %s", pp->printer); mcleanup(0); } if (pid == 0) { lastprinter(); printjob(pp); /* NOTREACHED */ } do { next: more = nextprinter(pp, &status); errloop: if (status) syslog(LOG_WARNING, "lpd startup: printcap entry for %s has errors, skipping", pp->printer ? pp->printer : "<noname?>"); } while (more && status); } }
int main(void) { static char buf[100]; int fd; //int status; // Assumes three file descriptors open. while((fd = open("console", O_RDWR)) >= 0){ if(fd >= 3){ close(fd); break; } } // Read and run input commands. int jobcntr = 0; jlist = malloc(sizeof(*jlist)); jlist->first = 0; jlist->last = 0; jlist->fgJob = 0; int waitStatus; int bPrintDollar = 1; int cmdLen = 0; while((cmdLen = getcmd(buf, sizeof(buf), bPrintDollar)) >= 0){ clearFinishedJobs(jlist); // Check if there's a forground job running. // If so - the shell should not function, but only transfer the data received from the console to the job's pipe if (jlist->fgJob != 0) { bPrintDollar = 0; write(jlist->fgJob->fd, buf, cmdLen); continue; } bPrintDollar = 1; if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' ') { // Clumsy but will have to do for now. // Chdir has no effect on the parent if run in the child. buf[strlen(buf)-1] = 0; // chop \n if(chdir(buf+3) < 0) printf(2, "cannot cd %s\n", buf+3); continue; } if(buf[0] == 'j' && buf[1] == 'o' && buf[2] == 'b' && buf[3] == 's' && (buf[4] == '\n' || buf[4] == ' ')) { struct job* job = jlist->first; while (job != 0) { printjob(job->jid); job = job->next; } if (!jlist->first) printf(1, "There are no jobs.\n"); continue; } if(buf[0] == 'f' && buf[1] == 'g' && (buf[2] == '\n' || buf[2] == ' ')) { char* c = &buf[3]; int jid = atoi(c); struct job* j = jlist->first; while ( j->jid != jid && j != 0) { j = j->next; } jlist->fgJob = j; //fg(jid); continue; } // 0x0A - new line if (buf[0] != 0x0A ) { // create a pipe so the the shell sends the input to jobs_pipe[1] and the new process gets it in jobs_pipe[0] if (pipe(jobs_pipe) == -1) { panic("pipe"); } struct job* job; job = malloc(sizeof(*job)); memset(job, 0, sizeof(*job)); job->jid = ++jobcntr; job->fd = jobs_pipe[1]; //char* s = job->cmd; //char* t = buf; //int i = sizeof(buf); //while(--i > 0 && *t != '\n' && (*s++ = *t++) != 0) ; //*s = 0; struct cmd* command = parsecmd(buf); int childPid = fork1(); if(childPid == 0) { close(0); dup(jobs_pipe[0]); close(jobs_pipe[1]); if(fork1() == 0) runcmd(command); exit(0); } close(jobs_pipe[0]); // The shell doesn't need the READ end. attachjob(childPid, job); // Attach proc to job (Sys call) // shell writes the input to job_buffer ONLY IF the cmd isn't a backgraound job if (command->type != BACK) { jlist->fgJob = job; bPrintDollar = 0; } addJobToList(jlist, job); wait(&waitStatus); } } exit(0); }
/* * eval - Evaluate the command line that the user has just typed in * * If the user has requested a built-in command (quit, jobs, bg or fg) * then execute it immediately. Otherwise, fork a child process and * run the job in the context of the child. If the job is running in * the foreground, wait for it to terminate and then return. Note: * each child process must have a unique process group ID so that our * background children don't receive SIGINT (SIGTSTP) from the kernel * when we type ctrl-c (ctrl-z) at the keyboard. */ void eval(char *cmdline) { int bg; /* should the job run in bg or fg? */ int job_state; /* initial value of job BG or FG based on bg */ int status; int check; struct cmdline_tokens tok; pid_t pid = -255; // Initialzing to int jid = -255; // dummy values sigset_t mask; sigset_t mask2; int flag = 0; //Used while processing "fg" built in command int infile_fd ; //file descriptor to be used for infile if specified in job int outfile_fd ; //file descriptor to be used for outfile if specified in job //Get shell pid tsh_pid = getpid(); //Intialize mask for blocked signal //Block SIGCHLD SIGINT SIGTSTP signals Sigemptyset(&mask); Sigemptyset(&mask2); Sigaddset(&mask,SIGCHLD); Sigaddset(&mask,SIGINT); Sigaddset(&mask2,SIGINT); Sigaddset(&mask,SIGTSTP); Sigaddset(&mask2,SIGTSTP); Sigprocmask(SIG_BLOCK,&mask,NULL); /* Parse command line */ bg = parseline(cmdline, &tok); if (bg == -1) return; /* parsing error */ if (tok.argv[0] == NULL) return; /* ignore empty lines */ /* If tok is a BUILTIN shell command */ if (tok.builtins != BUILTIN_NONE) { switch(tok.builtins) { //Built in command quit : //Send SIGKILL to all processes in shell case BUILTIN_QUIT : tsh_pid = getpid(); kill(-tsh_pid,SIGKILL); break; //List out all jobs when "jobs" called //Also open output file if redirection specified and //redirect jobs output to the new file's descriptor case BUILTIN_JOBS : if (tok.outfile != NULL) { outfile_fd = open(tok.outfile , O_WRONLY); listjobs(job_list,outfile_fd); break; } else listjobs(job_list,STDOUT_FILENO); break; // Parse job id or pid given with bg command // Change state from ST to BG in job_list // Send SIGCONT signal to job case BUILTIN_FG : if(*(char *)(tok.argv[1]) == '%' ) { jid = atoi( (((char *)(tok.argv[1])) + 1) ); pid = jid2pid(jid); } else { pid = atoi(tok.argv[1]); jid = pid2jid(pid); } change_job_state(job_list,pid,FG); flag = 1; //flag set because we want to jump into else clause below // to process resumed job as a foreground job Kill(-pid,SIGCONT); break; //Parse job id or pid given with bg command // Change state from ST to BG in job_list // Send SIGCONT signal to job case BUILTIN_BG : if(*(char *)(tok.argv[1]) == '%' ) { jid = atoi( (((char *)(tok.argv[1])) + 1) ); pid = jid2pid(jid); } else { pid = atoi(tok.argv[1]); jid = pid2jid(pid); } printjob(pid,STDOUT_FILENO); change_job_state(job_list,pid,BG); Kill(-pid,SIGCONT); break; case BUILTIN_NONE : break; default : break; } } //If tok is a external program to be run by shell else if ((tok.builtins == BUILTIN_NONE) || (flag == 1)) { if (flag == 1) bg = 0; if(!bg) job_state = FG; else job_state = BG; //Child process if ((pid = Fork()) == 0) { setpgid(0,0); //Start process in new group Signal(SIGINT, SIG_DFL); /* ctrl-c from child handled by parent's sigchld */ addjob(job_list,getpid(),job_state,cmdline); // If input/output redirection specified open given file and point STDIN/STDOUT descriptor // to new file's file descriptor if (tok.infile != NULL) { infile_fd = open(tok.infile , O_RDONLY); dup2(infile_fd,STDIN_FILENO); } if (tok.outfile != NULL) { outfile_fd = open(tok.outfile , O_WRONLY); dup2(outfile_fd,STDOUT_FILENO); } //Unblock masks inherited from parent process //and execute program using exec Sigprocmask(SIG_UNBLOCK,&mask,NULL); Execve(tok.argv[0],tok.argv,environ); } //Parent process //Add child to job list and unblock signal,also set fg_pid if job is foreground job addjob(job_list,pid,job_state,cmdline); if(!bg) fg_pid = pid; Sigprocmask(SIG_UNBLOCK,&mask2,NULL); //Until foreground process terminates SIGCHLD functionality is done here , SIGINT and SIGTSTP are handled by handlers if(!bg) { check = waitpid(pid,&status,WUNTRACED); if ((check<0) && (errno!=ECHILD)) unix_error("waitfg : wait pid error\n"); if ((check == pid) && WIFSTOPPED(status)){ print_sigtstp_job(job_list,pid,SIGTSTP,STDOUT_FILENO); //Print message that job was stopped by SIGSTP signal //Change stopped job state in list to ST (stopped) change_job_state(job_list,pid,ST); return; } if ((check == pid) && (WIFSIGNALED(status))) print_sigint_job(job_list,pid,WTERMSIG(status),STDOUT_FILENO); //Print message that job/pid was terminated by a signal deletejob(job_list,pid); Sigprocmask(SIG_UNBLOCK,&mask,NULL); } else { Sigprocmask(SIG_UNBLOCK,&mask,NULL); printjob(pid,STDOUT_FILENO); } } return; }