/* * builtin_cmd - If the user has typed a built-int * command then execute it immediately. * quit, fg, bg, jobs */ int builtin_cmd(char **argv) { char *cmd = argv[0]; sigset_t mask, prev; /* Blocks all signals while determining * whether command is built in */ Sigfillset(&mask); Sigprocmask(SIG_BLOCK, &mask, &prev); if (!strcmp(cmd, "quit")) { Sigprocmask(SIG_SETMASK, &prev, NULL); exit(0); } if (!strcmp(cmd, "jobs")) { listjobs(jobs); Sigprocmask(SIG_SETMASK, &prev, NULL); return 1; } if (!strcmp(cmd, "bg") || !strcmp(cmd, "fg")) { Sigprocmask(SIG_SETMASK, &prev, NULL); do_bgfg(argv); return 1; } Sigprocmask(SIG_SETMASK, &prev, NULL); return 0; }
int main(int argc, char **argv) { int pid; sigset_t mask; Signal(SIGCHLD, handler); initjobs(); /* Initialize the job list */ while (1) { Sigemptyset(&mask); Sigaddset(&mask, SIGCHLD); Sigprocmask(SIG_BLOCK, &mask, NULL); /* Block SIGCHLD */ /* Child process */ if ((pid = Fork()) == 0) { Sigprocmask(SIG_UNBLOCK, &mask, NULL); /* Unblock SIGCHLD */ Execve("/bin/ls", argv, NULL); } /* Parent process */ addjob(pid); /* Add the child to the job list */ Sigprocmask(SIG_UNBLOCK, &mask, NULL); /* Unblock SIGCHLD */ } exit(0); }
/* * 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) { int olderrno = errno; sigset_t mask_all, prev_all; pid_t pid; int status; Sigfillset(&mask_all); while ((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0) { Sigprocmask(SIG_BLOCK, &mask_all, &prev_all); /* Block Signals*/ if (WIFEXITED(status)) { /* Exit normally */ deletejob(jobs, pid); } if (WIFSIGNALED(status)) { /* C-c SIGINT */ printf("Job [%d] (%d) terminated by signal 2\n", pid2jid(pid), pid); deletejob(jobs, pid); /* Note: printf first, then deletejob */ } if (WIFSTOPPED(status)) { /* C-z SIGTSTP */ printf("Job [%d] (%d) stopped by signal 20\n", pid2jid(pid), pid); getjobpid(jobs, pid)->state = ST; } Sigprocmask(SIG_SETMASK, &prev_all, NULL); /* Unblock Signals*/ } errno = olderrno; return; }
int main(int argc, char **argv) { sigset_t mask, prev; Signal(SIGCHLD, sigchld_handler); Signal(SIGINT, sigint_handler); Sigemptyset(&mask); Sigaddset(&mask, SIGCHLD); while (1) { Sigprocmask(SIG_BLOCK, &mask, &prev); /* Block SIGCHLD */ if (Fork() == 0) /* Child */ exit(0); /* Wait for SIGCHLD to be received */ pid = 0; while (!pid) Sigsuspend(&prev); /* Optionally unblock SIGCHLD */ Sigprocmask(SIG_SETMASK, &prev, NULL); /* Do some work after receiving SIGCHLD */ printf("."); } 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? */ struct cmdline_tokens tok; sigset_t prev, mask_all; int state; pid_t pid; struct job_t *job_ins; /* Parse command line */ bg = parseline(cmdline, &tok); if (bg == -1) /* parsing error */ return; if (tok.argv[0] == NULL) /* ignore empty lines */ return; /* Fig. 8.40 */ if (!builtin_command(&tok)) { Sigemptyset(&mask_all); Sigaddset(&mask_all, SIGCHLD); Sigaddset(&mask_all, SIGINT); Sigaddset(&mask_all, SIGTSTP); Sigprocmask(SIG_BLOCK, &mask_all, &prev); /* Block at beginning */ if ((pid = Fork()) == 0) { /* Child process */ Sigprocmask(SIG_SETMASK, &prev, NULL); /* Unblock inside child */ Setpgid(0, 0); /* one proc and shell in pgrp */ open_dup2_in(tok.infile); open_dup2_out(tok.outfile); if (execve(tok.argv[0], tok.argv, environ) < 0) { printf("%s: Command not found.\n", tok.argv[0]); exit(0); } } /* Parent process */ state = bg ? BG : FG; addjob(job_list, pid, state, cmdline); job_ins = getjobpid(job_list, pid); Sigprocmask(SIG_SETMASK, &prev, NULL); /* Unblock 3 signals */ if (bg) { printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline); } else { wait_fg_job(job_ins -> state); } } return; }
/* * 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) { // Get memory for our parsed input char temp[MAXLINE]; char** argv = (char**)temp; // Return if only newline if (strcmp(cmdline, "\n") == 0) { return; } // Parse the input int background = parseline(cmdline, argv); // Check if built in command if (builtin_cmd(argv) == 0) { // Not a built in command char* programName = argv[0]; // Block sigchild signal sigset_t mask; Sigemptyset(&mask); Sigaddset(&mask, SIGCHLD); Sigprocmask(SIG_BLOCK, &mask, NULL); // Create a child process pid_t pid = Fork(); // Unblock sichild signal Sigprocmask(SIG_UNBLOCK, &mask, NULL); if (pid == 0) { // Child // Assign it a new process group id setpgid(0,0); // Run the external program Execve(programName, argv, environ); } else { // Parent if (background == 0) { // Add it to the list addjob(jobs, pid, FG, cmdline); // Make the shell wait for the process in the fg waitfg(pid); } else { // Add it to the list addjob(jobs, pid, BG, cmdline); // Get the job id int jid = pid2jid(pid); // Print info on background job printf("[%d] (%d) %s", jid, pid, cmdline); } } } return; }
/* * 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]; /* Argument list execve() */ char buf[MAXLINE]; /* Holds modified command line */ int bg; /* Should the job run in bg or fg? */ pid_t pid; /* Process id */ sigset_t mask; strcpy(buf, cmdline); bg = parseline(buf, argv); if (argv[0] == NULL) { return; /* Ignore empty lines */ } if (!builtin_cmd(argv)) { /* Block SIGCHLD, SIGINT, and SIGSTP until the job to be run is on the list */ Sigemptyset(&mask); Sigaddset(&mask, SIGCHLD); Sigaddset(&mask, SIGINT); Sigaddset(&mask, SIGTSTP); Sigprocmask(SIG_BLOCK, &mask, NULL); if ((pid = Fork()) == 0) { /* Child runs user job */ Setpgid(0, 0); // give the child a new group /* unblock signals for child */ Sigprocmask(SIG_UNBLOCK, &mask, NULL); if (execve(argv[0], argv, environ) < 0) { printf("%s: Command not found.\n", argv[0]); exit(0); } } addjob(jobs, pid, bg?BG:FG, cmdline); if (bg) { // Notify user that job is running in the background printf("[%i] (%i) %s", getjobpid(jobs, pid)->jid, pid, cmdline); } Sigprocmask(SIG_UNBLOCK, &mask, NULL); /* Unblock signals */ if (!bg) { /* Parent waits for foreground job to terminate */ waitfg(pid); } } return; }
/* * 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? */ struct cmdline_tokens tok; sigset_t mask_one, prev_one, mask_all; int state; pid_t pid; /* Parse command line */ bg = parseline(cmdline, &tok); if (bg == -1) /* parsing error */ return; if (tok.argv[0] == NULL) /* ignore empty lines */ return; /* Fig. 8.40 */ if (tok.builtins == BUILTIN_NONE) { Sigfillset(&mask_all); Sigemptyset(&mask_one); Sigaddset(&mask_one, SIGCHLD); Sigprocmask(SIG_BLOCK, &mask_one, &prev_one); /* Block SIGCHLD */ if ((pid = Fork()) == 0) { Sigprocmask(SIG_SETMASK, &prev_one, NULL); /* Unblock SIGCHLD */ if (execve(tok.argv[0], tok.argv, environ) < 0) { printf("%s: Command not found.\n", tok.argv[0]); exit(0); } } /* Parent process */ Sigprocmask(SIG_BLOCK, &mask_all, NULL); /* Block all */ state = bg ? BG : FG; addjob(job_list, pid, state, cmdline); Sigprocmask(SIG_SETMASK, &prev_one, NULL); /* Unblock SIGCHLD */ if (state == BG) { printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline); } else { } // Sigprocmask(SIG_SETMASK, &prev_one, NULL); } return; }
/* * 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, SIGTSTP, SIGTTIN or SIGTTOU 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) { pid_t cpid; int status; struct job_t* job; sigset_t mask,prev; //the reason why i dn not use the wrapped function //is that i need the return value while ((cpid = waitpid(-1, &status,WNOHANG|WUNTRACED))>0) { //prepare the mask Sigfillset(&mask); //block the signal because i want to change something Sigprocmask(SIG_BLOCK, &mask, &prev); //get the job by the pid job = getjobpid(job_list, cpid); //STP by any signal //change thet status and print msg if (WIFSTOPPED(status)) { printf("Job [%d] (%d) stopped by signal %d\n",job->jid, cpid, WSTOPSIG(status)); job->state = ST; } //terminate by signal //delete the job and print msg else if (WIFSIGNALED(status)){ printf("Job [%d] (%d) terminated by signal %d\n",job->jid, cpid, WTERMSIG(status)); deletejob(job_list, cpid); } //terminate normally //just delete the job from the job list else deletejob(job_list, cpid); } return; }
int main(int argc, char **argv) { int i, nloop, signo; pid_t childpid, parentpid; sigset_t newmask; if (argc != 2) err_quit("usage: lat_sigwait <#loops>"); nloop = atoi(argv[1]); Sigemptyset(&newmask); Sigaddset(&newmask, SIGUSR1); Sigprocmask(SIG_BLOCK, &newmask, NULL); /* block SIGUSR1 */ parentpid = getpid(); if ( (childpid = Fork()) == 0) { for (i = 0; i < nloop; i++) { /* child */ Sigwait(&newmask, &signo); Kill(parentpid, SIGUSR1); } exit(0); } /* 4parent */ Start_time(); for (i = 0; i < nloop; i++) { Kill(childpid, SIGUSR1); Sigwait(&newmask, &signo); } printf("latency: %.3f usec\n", Stop_time() / nloop); exit(0); }
void sigio_dg_echo(int sockfd_arg, SA *pcliaddr, socklen_t clilen_arg) { int i; const int on = 1; sigset_t zeromask, newmask, oldmask; sockfd = sockfd_arg; clilen = clilen_arg; for (i = 0; i < QSIZE; i++) { /* init queue of buffers */ dg[i].dg_data = Malloc(MAXDG); dg[i].dg_sa = Malloc(clilen); dg[i].dg_salen = clilen; } iget = iput = nqueue = 0; Signal(SIGHUP, sig_hup); Signal(SIGIO, sig_io); Fcntl(sockfd, F_SETOWN, getpid()); if (ioctl(sockfd, FIOASYNC, &on) < 0) err_sys("ioctl error"); if (ioctl(sockfd, FIONBIO, &on) < 0) err_sys("ioctl error"); Sigemptyset(&zeromask); Sigemptyset(&oldmask); Sigemptyset(&newmask); Sigaddset(&newmask, SIGIO); /* signal we want to block */ Sigprocmask(SIG_BLOCK, &newmask, &oldmask); for (;;) { while (nqueue == 0) sigsuspend(&zeromask); Sigprocmask(SIG_SETMASK, &oldmask, NULL); Sendto(sockfd, dg[iget].dg_data, dg[iget].dg_len, 0, dg[iget].dg_sa, dg[iget].dg_salen); if (++iget >= QSIZE) iget = 0; /* Block SIGIO */ Sigprocmask(SIG_BLOCK, &newmask, &oldmask); nqueue--; } }
int main(int argc,char **argv) { int i,j; pid_t pid; sigset_t newset; union sigval val; printf("SIGRTMIN = %d,SIGRTMAX = %d\n",(int) SIGRTMIN,(int )SIGRTMAX ); if((pid=Fork())==0) { Sigemptyset(&newset); Sigaddset(&newset,SIGRTMAX); Sigaddset(&newset,SIGRTMAX-1); Sigaddset(&newset,SIGRTMAX-2); Sigprocmask(SIG_BLOCK,&newset,NULL); Signal_rt(SIGRTMAX,sig_rt); Signal_rt(SIGRTMAX-1,sig_rt); signal_rt(SIGRTMAX-2,sig_rt); sleep(6); Sigprocmask(SIG_UNBLOCK,&newset,NULL); sleep(3); exit(0); } sleep(3); for(i=SIGRTMAX;i>=SIGRTMAX-2;i--) { for(j=0;j<=2;j++) { val.sival_int=j; Sigqueue(pid,i,val); printf("sent signal %d, val= %d\n",i,j); } } exit(0); }
int main(int argc, char **argv) { mqd_t mqd; void *buff; ssize_t n; sigset_t zeromask, newmask, oldmask; struct mq_attr attr; struct sigevent sigev; if (argc != 2) err_quit("Usage: nfs3 <name>"); mqd = Mq_open(argv[1], O_RDONLY | O_NONBLOCK); Mq_getattr(mqd, &attr); buff = (void *)Malloc(attr.mq_msgsize); Sigemptyset(&zeromask); Sigemptyset(&newmask); Sigemptyset(&oldmask); Sigaddset(&newmask, SIGUSR1); Signal(SIGUSR1, sig_usr1); sigev.sigev_notify = SIGEV_SIGNAL; sigev.sigev_signo = SIGUSR1; Mq_notify(mqd, &sigev); for ( ; ; ) { Sigprocmask(SIG_BLOCK, &newmask, &oldmask); while (mqflag == 0) sigsuspend(&zeromask); mqflag = 0; Mq_notify(mqd, &sigev); while ((n = mq_receive(mqd, buff, attr.mq_msgsize, NULL)) >= 0) { printf("read %ld bytes\n", (long)n); } if (errno != EAGAIN) err_sys("mq_receive error"); Sigprocmask(SIG_UNBLOCK, &newmask, NULL); } exit(0); }
void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen) { int n; const int on = 1; char sendline[MAXLINE], recvline[MAXLINE + 1]; sigset_t sigset_alrm; socklen_t len; struct sockaddr *preply_addr; preply_addr = Malloc(servlen); Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); Sigemptyset(&sigset_alrm); Sigaddset(&sigset_alrm, SIGALRM); Signal(SIGALRM, recvfrom_alarm); while (Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); alarm(5); for ( ; ; ) { len = servlen; Sigprocmask(SIG_UNBLOCK, &sigset_alrm, NULL); n = recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len); Sigprocmask(SIG_BLOCK, &sigset_alrm, NULL); if (n < 0) { if (errno == EINTR) break; /* waited long enough for replies */ else err_sys("recvfrom error"); } else { recvline[n] = 0; /* null terminate */ printf("from %s: %s", Sock_ntop_host(preply_addr, len), recvline); } } } free(preply_addr); }
int main(int argc, char **argv) { mqd_t mqd; void *buff; ssize_t n; sigset_t zeromask, newmask, oldmask; struct mq_attr attr; struct sigevent sigev; if (argc != 2) err_quit("usage: mqnotifysig2 <name>"); /* 4open queue, get attributes, allocate read buffer */ mqd = Mq_open(argv[1], O_RDONLY); Mq_getattr(mqd, &attr); buff = Malloc(attr.mq_msgsize); Sigemptyset(&zeromask); /* no signals blocked */ Sigemptyset(&newmask); Sigemptyset(&oldmask); Sigaddset(&newmask, SIGUSR1); /* 4establish signal handler, enable notification */ Signal(SIGUSR1, sig_usr1); sigev.sigev_notify = SIGEV_SIGNAL; sigev.sigev_signo = SIGUSR1; Mq_notify(mqd, &sigev); for ( ; ; ) { Sigprocmask(SIG_BLOCK, &newmask, &oldmask); /* block SIGUSR1 */ while (mqflag == 0) sigsuspend(&zeromask); mqflag = 0; /* reset flag */ Mq_notify(mqd, &sigev); /* reregister first */ n = Mq_receive(mqd, buff, attr.mq_msgsize, NULL); printf("read %ld bytes\n", (long) n); Sigprocmask(SIG_UNBLOCK, &newmask, NULL); /* unblock SIGUSR1 */ } 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) { char *argv[MAXARGS]; //arguments for execve() int bg; //Determines whether the job will run in foreground or background pid_t pid; //Contains the process id struct job_t *jd; sigset_t mask; //The signal set which has to be bloacked before adding the job to jobs bg = parseline(cmdline, argv); //Copies contents of cmdline into argv and returns whether the job should run in background or foreground Sigemptyset(&mask); //Generate an empty signal set in mask Sigaddset(&mask, SIGCHLD); //Add SIGCHLD to the signal set to be blocked Sigaddset(&mask, SIGINT); //Add SIGINT to the signal set to be blocked Sigaddset(&mask, SIGTSTP); //Add SIGTSTP to the signal set to be blocked if(!builtin_cmd(argv)){ //Checks whether command is built-in and executes it if yes, else enters if block Sigprocmask(SIG_BLOCK, &mask, NULL); //Blocked the signal set if((pid = Fork()) == 0){ //Run user process in a child Sigprocmask(SIG_UNBLOCK, &mask, NULL); //Unblock the signal sets in child Setpgid(0,0); //New jobs should have new process ids else signal will kill shell also if(execve(argv[0], argv, environ) < 0){ //executes user command if successful printf("%s: Command not found.\n", argv[0]); //Throw error if execution unsuccessful exit(0); } } if(!bg){ //If process is foreground, parent waits for the job to terminate addjob(jobs, pid, FG, cmdline); //Add the process to jobs Sigprocmask(SIG_UNBLOCK, &mask, NULL); //Unblock the signal set afet adding the job waitfg(pid); //Parent waits for the foreground process to terminate} } else{ //If process is a background addjob(jobs, pid, BG, cmdline); //Add the process to jobs Sigprocmask(SIG_UNBLOCK, &mask, NULL); //Unblock the signal set afet adding the job jd = getjobpid(jobs, pid); //Get the jobpid printf("[%d] (%d) %s", jd->jid, jd->pid, jd->cmdline); //Print the details of background job } } return; }
/* * 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, SIGTSTP, SIGTTIN or SIGTTOU 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) { /* Fig. 8.41 8.18 */ int olderrno = errno; int status; pid_t p_id; struct job_t *job_ins; sigset_t prev, mask_all; Sigemptyset(&mask_all); Sigaddset(&mask_all, SIGCHLD); Sigaddset(&mask_all, SIGINT); Sigaddset(&mask_all, SIGTSTP); while((p_id = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { /* Normally finish/exit */ if (WIFEXITED(status)) { Sigprocmask(SIG_BLOCK, &mask_all, &prev); /* Block */ deletejob(job_list, p_id); Sigprocmask(SIG_SETMASK, &prev, NULL); /* Unblock */ } else if (WIFSIGNALED(status)) { /* Terminated by other signal */ /* Order is fixed, otherwise it cause bugs. */ printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(p_id), p_id, WTERMSIG(status)); Sigprocmask(SIG_BLOCK, &mask_all, &prev); /* Block */ deletejob(job_list, p_id); Sigprocmask(SIG_SETMASK, &prev, NULL); /* Unblock */ } else if (WIFSTOPPED(status)) { /* Stopped by signal, need to modified the state to stopped */ /* Order is fixed, otherwise it cause bugs. */ printf("Job [%d] (%d) stopped by signal %d\n", pid2jid(p_id), p_id, WSTOPSIG(status)); job_ins = getjobpid(job_list, p_id); job_ins -> state = ST; } } errno = olderrno; }
/* * builtin_fg_handler - Change a stopped or running * background job into a running foreground job */ void builtin_fg_handler(struct cmdline_tokens *tok) { /* TODO refactored */ sigset_t prev, mask_all; Sigemptyset(&mask_all); Sigaddset(&mask_all, SIGCHLD); Sigaddset(&mask_all, SIGINT); Sigaddset(&mask_all, SIGTSTP); struct job_t *job_ins = id2job(tok, tok -> argc); /* Modify the status of candidate process, fire the signal */ Sigprocmask(SIG_BLOCK, &mask_all, &prev); /* Block */ job_ins -> state = FG; Sigprocmask(SIG_SETMASK, &prev, NULL); /* Unblock */ Kill(job_ins -> pid, SIGCONT); /* Wait to stop */ wait_fg_job(job_ins -> state); }
/* * builtin_bg_handler - Change a stopped background job * into a running background job */ void builtin_bg_handler(struct cmdline_tokens *tok) { /* TODO */ sigset_t prev, mask_all; Sigemptyset(&mask_all); Sigaddset(&mask_all, SIGCHLD); Sigaddset(&mask_all, SIGINT); Sigaddset(&mask_all, SIGTSTP); struct job_t *job_ins = id2job(tok, tok -> argc); /* Fire the signal */ if (ST == (job_ins -> state)) { Sigprocmask(SIG_BLOCK, &mask_all, &prev); /* Block */ job_ins -> state = BG; Sigprocmask(SIG_SETMASK, &prev, NULL); /* Unblock */ Kill(job_ins -> pid, SIGCONT); printf("[%d] (%d) %s\n", job_ins -> jid, job_ins -> pid, job_ins -> cmdline); } }
/* * waitfg - Block until process pid is no longer the * foreground process */ void waitfg(pid_t pid) { sigset_t mask, prev; Log("WAITFG [0]\n", 11); Sigemptyset(&mask); Sigaddset(&mask, SIGCHLD); Sigprocmask(SIG_BLOCK, &mask, &prev); Log("WAITFG [1]\n", 11); while (atomic_fggpid == pid) { Log("WAITFG [2]\n", 11); Sigsuspend(&prev); } Log("WAITFG [3]\n", 11); Sigprocmask(SIG_SETMASK, &prev, NULL); }
void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen) { int n; const int on = 1; char sendline[MAXLINE], recvline[MAXLINE + 1]; fd_set rset; sigset_t sigset_alrm, sigset_empty; socklen_t len; struct sockaddr *preply_addr; preply_addr = (struct sockaddr *)Malloc(servlen); Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); FD_ZERO(&rset); Sigemptyset(&sigset_empty); sigemptyset(&sigset_alrm); Sigaddset(&sigset_alrm, SIGALRM); Signal(SIGALRM, recvfrom_alarm); while (Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); Sigprocmask(SIG_BLOCK, &sigset_alrm, NULL); alarm(5); for ( ; ; ) { FD_SET(sockfd, &rset); n = pselect(sockfd+1, &rset, NULL, NULL, NULL, &sigset_empty); if (n < 0) { if (errno = EINTR) break; else err_sys("pselect error"); } else if (n != 1) err_sys("pselect error: returned %d", n); len = servlen; n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len); recvline[n] = 0; //null terminate printf("from %s: %s", (char *)Sock_ntop_host(preply_addr, len), recvline); } } free(preply_addr); }
/****************Print Proc Mask Signal*******************/ void pr_mask(const char *str) { sigset_t sigset; int errno_save; errno_save = errno; Sigprocmask(0, NULL, &sigset); printf("%s", str); if(sigismember(&sigset, SIGINT)) printf("SIGINT "); sigaddset(&sigset, SIGQUIT); if(sigismember(&sigset, SIGQUIT)) printf("SIGQUIT "); if(sigismember(&sigset, SIGUSR1)) printf("SIGUSR1 "); if(sigismember(&sigset, SIGALRM)) printf("SIGALRM "); printf("\n"); errno = errno_save; }
int main(int argc, char **argv) { int signo; mqd_t mqd; void *buff; ssize_t n; sigset_t newmask; struct mq_attr attr; struct sigevent sigev; if (argc != 2) err_quit("usage: mqnotifysig4 <name>"); /* 4open queue, get attributes, allocate read buffer */ mqd = Mq_open(argv[1], O_RDONLY | O_NONBLOCK); Mq_getattr(mqd, &attr); buff = Malloc(attr.mq_msgsize); Sigemptyset(&newmask); Sigaddset(&newmask, SIGUSR1); Sigprocmask(SIG_BLOCK, &newmask, NULL); /* block SIGUSR1 */ /* 4establish signal handler, enable notification */ sigev.sigev_notify = SIGEV_SIGNAL; sigev.sigev_signo = SIGUSR1; Mq_notify(mqd, &sigev); for ( ; ; ) { Sigwait(&newmask, &signo); if (signo == SIGUSR1) { Mq_notify(mqd, &sigev); /* reregister first */ while ( (n = mq_receive(mqd, buff, attr.mq_msgsize, NULL)) >= 0) { printf("read %ld bytes\n", (long) n); } if (errno != EAGAIN) err_sys("mq_receive error"); } } 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) { char *argv[MAXARGS]; /* Argument list execve() */ char buf[MAXLINE]; /* Holds modified command line */ int bg; /* Should the job run in bg or fg? */ pid_t pid; /* Process id */ sigset_t mask_all, mask_one, prev_one; /* Signal mask */ Sigfillset(&mask_all); Sigemptyset(&mask_one); Sigaddset(&mask_one, SIGCHLD); strcpy(buf, cmdline); bg = parseline(buf, argv); if (argv[0] == NULL) return; /* Ignore empty lines */ if (!builtin_cmd(argv)) { Sigprocmask(SIG_BLOCK, &mask_one, &prev_one); /* Block SIGCHLD */ if ((pid = Fork()) == 0) { /* Child runs user job */ Sigprocmask(SIG_SETMASK, &prev_one, NULL); /* Unblock SIGCHLD */ setpgid(0, 0); if (execve(argv[0], argv, environ) < 0) { printf("%s: Command not found\n", argv[0]); exit(0); } } if (!bg) { /* Parent waits for foreground job to terminate */ Sigprocmask(SIG_BLOCK, &mask_all, NULL); addjob(jobs, pid, FG, cmdline); Sigprocmask(SIG_SETMASK, &prev_one, NULL); /* Unblock SIGCHLD */ waitfg(pid); } else { /* Background job */ Sigprocmask(SIG_BLOCK, &mask_all, NULL); addjob(jobs, pid, BG, cmdline); printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline); Sigprocmask(SIG_SETMASK, &prev_one, NULL); /* Unblock SIGCHLD */ } } return; }
/* * 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? */ struct cmdline_tokens tok; pid_t cpid ; //child's pid sigset_t mask; sigset_t prev; int parseId; //prepare for the jid or pid in the future int state; struct job_t* job; //use for the fg or bg int infg = 0; //default STDIN int outfg = 1; //default STDOUT /* Create block signal */ Sigemptyset(&mask); /* block int stp child signal with the block signal*/ Sigaddset(&mask, SIGINT); Sigaddset(&mask, SIGTSTP); Sigaddset(&mask, SIGCHLD); /* Parse command line */ bg = parseline(cmdline, &tok); if (bg == -1) /* parsing error */ return; if (tok.argv[0] == NULL) /* ignore empty lines */ return; /* When there is a redirect input or output , change the value infg and out fg to the file */ if (tok.infile != NULL) { infg = Open(tok.infile, O_RDONLY, 0); } if (tok.outfile!=NULL) { outfg = Open(tok.outfile, O_WRONLY,0); } /* There are 5 situations: 1. Not a builtin command 2. Quit 3. list jobs 4. builtin foreground jobs 5. builtin background jobs */ switch (tok.builtins) { case BUILTIN_NONE: //we need to fork and create a child process Sigprocmask(SIG_BLOCK, &mask, &prev); if ((cpid=Fork())==0) { //in the child process //we should unblock all signals Sigprocmask(SIG_UNBLOCK, &mask, NULL); cpid = getpid(); //set child process group to avoid race condition setpgid(cpid,cpid); Sigprocmask(SIG_SETMASK, &prev, NULL); //set the in and out direction if(infg != 0){ Dup2(infg, 0); Close(infg); } if (outfg != 1) { Dup2(outfg, 1); Close(outfg); } //process the outside command Execve(tok.argv[0], tok.argv, environ); }else{ //in the parent process //determin whether it is a bg or fg if (bg==1) { state = BG; } else{ state = FG; } //add the job to job list addjob(job_list, cpid, state, cmdline); //get the job from job list by pid job = getjobpid(job_list, cpid); //unblock all signal Sigprocmask(SIG_UNBLOCK, &mask, NULL); //use while to //set the shell wait until the job is stp or killed if(state == FG){ while (fgpid(job_list)!=0) { Sigsuspend(&prev); } } else{ //if bg, print the background job printf("[%d] (%d) %s\n",job->jid, job->pid,cmdline); } } break; case BUILTIN_QUIT: //use the exit function exit(0); break; case BUILTIN_JOBS: //use the listjobs function listjobs(job_list, outfg); break; case BUILTIN_BG: //get the jid if (tok.argv[1][0]=='%') { parseId = atoi(&tok.argv[1][1]); job = getjobjid(job_list, parseId); } //or get the pid else if ((tok.argv[1][0] >= '0')&&(tok.argv[1][0]<='9')) { parseId = atoi(&tok.argv[1][0]); job = getjobpid(job_list, (pid_t)parseId); } printf("[%d] (%d) %s\n",job->jid, job->pid,job->cmdline); //set the job state to BG job->state = BG; //send SIGCONT Kill(-(job->pid), SIGCONT); break; case BUILTIN_FG: //get jid if (tok.argv[1][0]=='%') { parseId = atoi(&tok.argv[1][1]); job = getjobjid(job_list, parseId); } //get pid else if ((tok.argv[1][0] >= '0')&&(tok.argv[1][0]<='9')) { parseId = atoi(&tok.argv[1][0]); job = getjobpid(job_list, (pid_t)parseId); } //set the job state to FG job->state = FG; //send SIGCONT Kill(-(job->pid), SIGCONT); break; default: break; } return; }
/* fork for exec/system, but return before exec'ing. return=0: is child process return>0: is parent process return<0: error occurred, assume parent process and no child exists !!! function formerly known as _xioopen_foxec() */ int _xioopen_progcall(int xioflags, /* XIO_RDONLY etc. */ struct single *xfd, unsigned groups, struct opt **copts, /* in: opts; out: opts for child */ int *duptostderr, bool inter, /* is interaddr, not endpoint */ int form /* with interaddr: =2: FDs 1,0--4,3 =1: FDs 1--0 */ ) { struct single *fd = xfd; struct opt *popts; /* parent process options */ int numleft; int sv[2], rdpip[2], wrpip[2]; int saverfd = -1, savewfd = -1; /* with inter addr, save assigned right fds */ int rw = (xioflags & XIO_ACCMODE); char *commname; int commtype = XIOCOMM_SOCKETPAIRS; bool usepipes = false; #if HAVE_PTY int ptyfd = -1, ttyfd = -1; bool usebestpty = false; /* use the best available way to open pty */ #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC) bool useptmx = false; /* use /dev/ptmx or equivalent */ #endif #if HAVE_OPENPTY bool useopenpty = false; /* try only openpty */ #endif /* HAVE_OPENPTY */ bool usepty = false; /* any of the pty options is selected */ char ptyname[MAXPTYNAMELEN]; #endif /* HAVE_PTY */ pid_t pid = 0; /* mostly int */ int leftfd[2] = { 0, 1 }; # define fdi (leftfd[0]) # define fdo (leftfd[1]) int rightfd[2] = { 3, 4 }; # define rightin (rightfd[0]) # define rightout (rightfd[1]) short result; bool withstderr = false; bool nofork = false; bool withfork; popts = moveopts(*copts, GROUP_ALL); if (applyopts_single(fd, popts, PH_INIT) < 0) return -1; applyopts2(-1, popts, PH_INIT, PH_EARLY); retropt_bool(popts, OPT_NOFORK, &nofork); withfork = !nofork; if ((retropt_string(popts, OPT_COMMTYPE, &commname)) >= 0) { if ((commtype = getcommtype(commname)) < 0) { Error1("bad communication type \"%s\"", commname); commtype = XIOCOMM_SOCKETPAIRS; } } retropt_bool(popts, OPT_PIPES, &usepipes); #if HAVE_PTY retropt_bool(popts, OPT_PTY, &usebestpty); #if HAVE_OPENPTY retropt_bool(popts, OPT_OPENPTY, &useopenpty); #endif #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC) retropt_bool(popts, OPT_PTMX, &useptmx); #endif usepty = (usebestpty #if HAVE_OPENPTY || useopenpty #endif #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC) || useptmx #endif ); if (usepipes && usepty) { Warn("_xioopen_foxec(): options \"pipes\" and \"pty\" must not be specified together; ignoring \"pipes\""); usepipes = false; } #endif /* HAVE_PTY */ if (usepty) { commtype = XIOCOMM_PTY; } else if (usepipes) { commtype = XIOCOMM_PIPES; } /*------------------------------------------------------------------------*/ /* retrieve options regarding file descriptors */ if (!retropt_int(popts, OPT_LEFTFD, &fdi)) { fdo = fdi; } retropt_int(popts, OPT_LEFTINFD, &fdi); retropt_int(popts, OPT_LEFTOUTFD, &fdo); if (!retropt_int(popts, OPT_RIGHTFD, &rightin)) { rightout = rightin; } retropt_int(popts, OPT_RIGHTINFD, &rightin); retropt_int(popts, OPT_RIGHTOUTFD, &rightout); /* when the superordinate communication type provides two distinct fds we cannot pass just one fd to the program */ if (rw == XIO_RDWR && rightin==rightout) { struct stat rstat, wstat; if (Fstat(xfd->rfd, &rstat) < 0) Error2("fstat(%d, ...): %s", xfd->rfd, strerror(errno)); if (Fstat(xfd->wfd, &wstat) < 0) Error2("fstat(%d, ...): %s", xfd->wfd, strerror(errno)); if (memcmp(&rstat, &wstat, sizeof(rstat))) { Error("exec/system: your rightfd options require the same FD for both directions but the communication environment provides two different FDs"); } } /*------------------------------------------------------------------------*/ if (rw == XIO_WRONLY) { if (fd->howtoclose == XIOCLOSE_UNSPEC) { fd->howtoclose = XIOCLOSE_SLEEP_SIGTERM; } } if (withfork) { const char *typename; if (!(xioflags&XIO_MAYCHILD)) { Error("fork for exec not allowed in this context"); /*!! free something */ return -1; } fd->flags |= XIO_DOESCHILD; switch (commtype) { case XIOCOMM_PIPES: typename = "pipes"; break; #if HAVE_PTY case XIOCOMM_PTY: typename = "pty"; break; case XIOCOMM_PTYS: typename = "two pty's"; break; #endif /* HAVE_PTY */ case XIOCOMM_SOCKETPAIR: typename = "socketpair"; break; case XIOCOMM_SOCKETPAIRS: typename = "two socketpairs"; break; #if _WITH_TCP case XIOCOMM_TCP: typename = "TCP socket pair"; break; case XIOCOMM_TCP4: typename = "TCP4 socket pair"; break; case XIOCOMM_TCP4_LISTEN: typename = "TCP4 listen socket pair"; break; #endif default: typename = NULL; break; } Notice2("forking off child, using %s for %s", typename, ddirection[rw]); } applyopts(-1, popts, PH_PREBIGEN); if (inter) { saverfd = xfd->rfd; savewfd = xfd->wfd; xfd->howtoshut = XIOSHUT_UNSPEC; xfd->howtoclose = XIOCLOSE_UNSPEC; } if (!withfork) { /*0 struct single *stream1, *stream2;*/ free(*copts); *copts = moveopts(popts, GROUP_ALL); /* what if WE are sock1 ? */ #if 1 if (!(xioflags & XIO_MAYEXEC /* means exec+nofork */)) { Error("nofork option is not allowed here"); /*!! free something */ return -1; } fd->flags |= XIO_DOESEXEC; #else /*!! */ if (sock1 == NULL) { Fatal("nofork option must no be applied to first socat address"); } #endif if (fd->howtoclose == XIOCLOSE_UNSPEC) { fd->howtoclose = XIOCLOSE_CLOSE; } #if 0 /*!! */ if (sock1->tag == XIO_TAG_DUAL) { stream1 = &sock1->dual.stream[0]->stream; stream2 = &sock1->dual.stream[1]->stream; } else { stream1 = &sock1->stream; stream2 = &sock1->stream; } if (stream1->dtype == DATA_READLINE || stream2->dtype == DATA_READLINE || stream1->dtype == DATA_OPENSSL || stream2->dtype == DATA_OPENSSL ) { Error("with option nofork, openssl and readline in address1 do not work"); } if (stream1->lineterm != LINETERM_RAW || stream2->lineterm != LINETERM_RAW || stream1->ignoreeof || stream2->ignoreeof) { Warn("due to option nofork, address1 options for lineterm and igoreeof do not apply"); } #endif /*! problem: when fdi==WRFD(sock[0]) or fdo==RDFD(sock[0]) */ if (rw != XIO_WRONLY) { if (XIO_GETRDFD(sock[0]/*!!!*/) == fdi) { if (Fcntl_l(fdi, F_SETFD, 0) < 0) { Warn2("fcntl(%d, F_SETFD, 0): %s", fdi, strerror(errno)); } if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) { Error3("dup2(%d, %d): %s", XIO_GETRDFD(sock[0]), fdi, strerror(errno)); } /*0 Info2("dup2(%d, %d)", XIO_GETRDFD(sock[0]), fdi);*/ } else { if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) { Error3("dup2(%d, %d): %s", XIO_GETRDFD(sock[0]), fdi, strerror(errno)); } /*0 Info2("dup2(%d, %d)", XIO_GETRDFD(sock[0]), fdi);*/ } } if (rw != XIO_RDONLY) { if (XIO_GETWRFD(sock[0]) == fdo) { if (Fcntl_l(fdo, F_SETFD, 0) < 0) { Warn2("fcntl(%d, F_SETFD, 0): %s", fdo, strerror(errno)); } if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) { Error3("dup2(%d, %d): %s)", XIO_GETWRFD(sock[0]), fdo, strerror(errno)); } /*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/ } else { if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) { Error3("dup2(%d, %d): %s)", XIO_GETWRFD(sock[0]), fdo, strerror(errno)); } /*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/ } } } else /* withfork */ /* create fd pair(s), set related xfd parameters, and apply options */ switch (commtype) { #if HAVE_PTY case XIOCOMM_PTY: /*!indent*/ #if defined(HAVE_DEV_PTMX) # define PTMX "/dev/ptmx" /* Linux */ #elif HAVE_DEV_PTC # define PTMX "/dev/ptc" /* AIX 4.3.3 */ #endif fd->dtype = XIODATA_PTY; #if 0 if (fd->howtoshut == XIOSHUT_UNSPEC) { fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP; } if (fd->howtoclose == XIOCLOSE_UNSPEC) { fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM; } #endif if (xiopty(usebestpty||useptmx, &ttyfd, &ptyfd) < 0) { return -1; } free(*copts); if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) { return -1; } applyopts_cloexec(ptyfd, popts);/*!*/ /* exec:...,pty did not kill child process under some circumstances */ if (fd->howtoshut == XIOSHUT_UNSPEC) { fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP; } if (fd->howtoclose == XIOCLOSE_UNSPEC) { fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM; } /* this for parent, was after fork */ applyopts(ptyfd, popts, PH_FD); applyopts(ptyfd, popts, PH_LATE); if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; if (XIOWITHRD(rw)) fd->rfd = ptyfd; if (XIOWITHWR(rw)) fd->wfd = ptyfd; /* this for child, was after fork */ applyopts(ttyfd, *copts, PH_FD); break; #endif /* HAVE_PTY */ case XIOCOMM_PIPES: { /*!indent*/ struct opt *popts2, *copts2; if (rw == XIO_RDWR) { fd->dtype = XIODATA_2PIPE; } if (fd->howtoshut == XIOSHUT_UNSPEC || fd->howtoshut == XIOSHUT_DOWN) { fd->howtoshut = XIOSHUT_CLOSE; } if (fd->howtoclose == XIOCLOSE_UNSPEC) { fd->howtoclose = XIOCLOSE_CLOSE; } if (rw != XIO_WRONLY) { if (Pipe(rdpip) < 0) { Error2("pipe(%p): %s", rdpip, strerror(errno)); return -1; } } /*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/ /* rdpip[0]: read by socat; rdpip[1]: write by child */ free(*copts); if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) { return -1; } popts2 = copyopts(popts, GROUP_ALL); copts2 = copyopts(*copts, GROUP_ALL); if (rw != XIO_WRONLY) { applyopts_cloexec(rdpip[0], popts); applyopts(rdpip[0], popts, PH_FD); applyopts(rdpip[1], *copts, PH_FD); } if (rw != XIO_RDONLY) { if (Pipe(wrpip) < 0) { Error2("pipe(%p): %s", wrpip, strerror(errno)); return -1; } } /*0 Info2("pipe({%d,%d})", wrpip[0], wrpip[1]);*/ /* wrpip[1]: write by socat; wrpip[0]: read by child */ if (rw != XIO_RDONLY) { applyopts_cloexec(wrpip[1], popts2); applyopts(wrpip[1], popts2, PH_FD); applyopts(wrpip[0], copts2, PH_FD); } /* this for parent, was after fork */ if (XIOWITHRD(rw)) fd->rfd = rdpip[0]; if (XIOWITHWR(rw)) fd->wfd = wrpip[1]; applyopts(fd->rfd, popts, PH_FD); applyopts(fd->rfd, popts, PH_LATE); if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; break; } case XIOCOMM_SOCKETPAIR: { /*!indent*/ int pf = AF_UNIX; retropt_int(popts, OPT_PROTOCOL_FAMILY, &pf); result = xiosocketpair(popts, pf, SOCK_STREAM, 0, sv); if (result < 0) { return -1; } if (xfd->howtoshut == XIOSHUT_UNSPEC) { xfd->howtoshut = XIOSHUT_DOWN; } if (xfd->howtoclose == XIOCLOSE_UNSPEC) { xfd->howtoclose = XIOCLOSE_CLOSE; } /*0 Info5("socketpair(%d, %d, %d, {%d,%d})", d, type, protocol, sv[0], sv[1]);*/ free(*copts); if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) { return -1; } applyopts(sv[0], *copts, PH_PASTSOCKET); applyopts(sv[1], popts, PH_PASTSOCKET); applyopts_cloexec(sv[0], *copts); applyopts(sv[0], *copts, PH_FD); applyopts(sv[1], popts, PH_FD); applyopts(sv[0], *copts, PH_PREBIND); applyopts(sv[0], *copts, PH_BIND); applyopts(sv[0], *copts, PH_PASTBIND); applyopts(sv[1], popts, PH_PREBIND); applyopts(sv[1], popts, PH_BIND); applyopts(sv[1], popts, PH_PASTBIND); Warn1("xio-progcall.c: fd->howtoshut == %d", fd->howtoshut); if (inter || fd->howtoshut == XIOSHUT_UNSPEC) { fd->howtoshut = XIOSHUT_DOWN; } if (fd->howtoclose == XIOCLOSE_UNSPEC) { fd->howtoclose = XIOCLOSE_SIGTERM; } /* this for parent, was after fork */ /*!!!*/ Warn2("2: fd->rfd==%d, fd->wfd==%d", fd->rfd, fd->wfd); if (XIOWITHRD(rw)) fd->rfd = sv[0]; if (XIOWITHWR(rw)) fd->wfd = sv[0]; /*!!!*/ Warn2("3: fd->rfd==%d, fd->wfd==%d", fd->rfd, fd->wfd); applyopts(fd->rfd, popts, PH_FD); applyopts(fd->rfd, popts, PH_LATE); if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; } break; case XIOCOMM_TCP: case XIOCOMM_TCP4: { /*!indent*/ int pf = AF_INET; xiofd_t socatfd, execfd; retropt_int(popts, OPT_PROTOCOL_FAMILY, &pf); if (xiocommpair(commtype, XIOWITHWR(rw), XIOWITHRD(rw), 0, &socatfd, &execfd) < 0) { return -1; } free(*copts); if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) { return -1; } sv[0] = socatfd.rfd; /*!!! r/w */ sv[1] = execfd.wfd; applyopts(socatfd.rfd, *copts, PH_PASTSOCKET); applyopts(execfd.rfd, popts, PH_PASTSOCKET); applyopts_cloexec(sv[0], *copts); applyopts(sv[0], *copts, PH_FD); applyopts(sv[1], popts, PH_FD); applyopts(sv[0], *copts, PH_PREBIND); applyopts(sv[0], *copts, PH_BIND); applyopts(sv[0], *copts, PH_PASTBIND); applyopts(sv[1], popts, PH_PREBIND); applyopts(sv[1], popts, PH_BIND); applyopts(sv[1], popts, PH_PASTBIND); Warn1("xio-progcall.c: fd->howtoshut == %d", fd->howtoshut); if (inter || fd->howtoshut == XIOSHUT_UNSPEC) { fd->howtoshut = XIOSHUT_DOWN; } if (fd->howtoclose == XIOCLOSE_UNSPEC) { fd->howtoclose = XIOCLOSE_SIGTERM; } /* this for parent, was after fork */ if (XIOWITHRD(rw)) fd->rfd = sv[0]; if (XIOWITHWR(rw)) fd->wfd = sv[0]; applyopts(fd->rfd, popts, PH_FD); applyopts(fd->rfd, popts, PH_LATE); if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; } break; #if LATER case XIOCOMM_TCP4_LISTEN: { /*!indent*/ int pf = AF_INET; xiofd_t socatfd, execfd; retropt_int(popts, OPT_PROTOCOL_FAMILY, &pf); if (xiocommpair(commtype, XIOWITHWR(rw), XIOWITHRD(rw), 0, &socatfd, &execfd) < 0) { return -1; } free(*copts); if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) { return -1; } applyopts_cloexec(ptyfd, popts);/*!*/ } break; #endif /* LATER */ case XIOCOMM_SOCKETPAIRS: case XIOCOMM_PTYS: { xiofd_t socatfd, execfd; struct termios andmask, ormask; switch (commtype) { case XIOCOMM_SOCKETPAIRS: if (xiocommpair(commtype, XIOWITHWR(rw), XIOWITHRD(rw), 0, &socatfd, &execfd, PF_UNIX, SOCK_STREAM, 0) < 0) return -1; break; case XIOCOMM_PTYS: if (xiocommpair(commtype, XIOWITHWR(rw), XIOWITHRD(rw), 0, &socatfd, &execfd, &andmask, &ormask) < 0) return -1; break; } free(*copts); if ((*copts = copyopts(popts, GROUP_TERMIOS|GROUP_FORK)) == NULL) { return -1; } if (socatfd.rfd >= 0) { applyopts_cloexec(socatfd.rfd, *copts);/*!*/ applyopts(socatfd.rfd, *copts, PH_FD); applyopts(socatfd.rfd, *copts, PH_LATE); } if (applyopts_single(xfd, *copts, PH_LATE) < 0) return -1; free(*copts); if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) { return -1; } if (socatfd.wfd >= 0) { applyopts_cloexec(socatfd.wfd, *copts);/*!*/ applyopts(socatfd.wfd, *copts, PH_FD); applyopts(socatfd.wfd, *copts, PH_LATE); } if (applyopts_single(xfd, *copts, PH_LATE) < 0) return -1; if (XIOWITHRD(rw)) xfd->rfd = socatfd.rfd; if (XIOWITHWR(rw)) xfd->wfd = socatfd.wfd; xfd->dtype = socatfd.dtype; if (xfd->howtoshut == XIOSHUT_UNSPEC) xfd->howtoshut = socatfd.howtoshut; if (fd->howtoclose == XIOCLOSE_UNSPEC) { fd->howtoclose = XIOWITHRD(rw)?XIOCLOSE_CLOSE_SIGTERM:XIOCLOSE_SLEEP_SIGTERM; } wrpip[0] = execfd.rfd; rdpip[1] = execfd.wfd; rdpip[0] = socatfd.rfd; wrpip[1] = socatfd.wfd; } break; default: Error1("_xioopen_progcall() internal: commtype %d not handled", commtype); break; } /*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL) return -1;*/ retropt_bool(*copts, OPT_STDERR, &withstderr); xiosetchilddied(); /* set SIGCHLD handler */ xiosetchilddied(); /* set SIGCHLD handler */ if (withfork) { sigset_t set, oldset; sigemptyset(&set); sigaddset(&set, SIGCHLD); Sigprocmask(SIG_BLOCK, &set, &oldset); /* disable SIGCHLD */ pid = xio_fork(true, E_ERROR); if (pid < 0) { Sigprocmask(SIG_SETMASK, &oldset, NULL); Error1("fork(): %s", strerror(errno)); return -1; } if (pid > 0) { /* for parent (this is our socat process) */ xiosigchld_register(pid, xiosigaction_child, fd); Sigprocmask(SIG_SETMASK, &oldset, NULL); /* enable SIGCHLD */ } if (pid == 0) { /* child */ /* drop parents locks, reset FIPS... */ if (xio_forked_inchild() != 0) { Exit(1); } Sigprocmask(SIG_SETMASK, &oldset, NULL); /* enable SIGCHLD */ } } if (!withfork || pid == 0) { /* child */ uid_t user; gid_t group; if (withfork) { if (Signal(SIGCHLD, SIG_IGN) == SIG_ERR) { Warn1("signal(SIGCHLD, SIG_IGN): %s", strerror(errno)); } /* dup2() the fds to desired values, close old fds, and apply late options */ switch (commtype) { #if HAVE_PTY case XIOCOMM_PTY: if (rw != XIO_RDONLY && fdi != ttyfd) { if (Dup2(ttyfd, fdi) < 0) { Error3("dup2(%d, %d): %s", ttyfd, fdi, strerror(errno)); return -1; } /*0 Info2("dup2(%d, %d)", ttyfd, fdi);*/ } if (rw != XIO_WRONLY && fdo != ttyfd) { if (Dup2(ttyfd, fdo) < 0) { Error3("dup2(%d, %d): %s", ttyfd, fdo, strerror(errno)); return -1; } /*0 Info2("dup2(%d, %d)", ttyfd, fdo);*/ } if ((rw == XIO_RDONLY || fdi != ttyfd) && (rw == XIO_WRONLY || fdo != ttyfd)) { applyopts_cloexec(ttyfd, *copts); } applyopts(ttyfd, *copts, PH_LATE); applyopts(ttyfd, *copts, PH_LATE2); break; #endif /* HAVE_PTY */ case XIOCOMM_PIPES: case XIOCOMM_SOCKETPAIRS: case XIOCOMM_PTYS: { /*!indent*/ /* we might have a temporary conflict between what FDs are currently allocated, and which are to be used. We try to find a graceful solution via temporary descriptors */ int tmpi, tmpo; /* needed with system() (not with exec()) */ if (XIOWITHRD(rw)) Close(rdpip[0]); if (XIOWITHWR(rw)) Close(wrpip[1]); #if 0 /*! might not be needed */ if (XIOWITHRD(rw)) Close(rdpip[0]); if (XIOWITHWR(rw)) Close(wrpip[1]); if (fdi == rdpip[1]) { /* a conflict here */ if ((tmpi = Dup(wrpip[0])) < 0) { Error2("dup(%d): %s", wrpip[0], strerror(errno)); return -1; } /*0 Info2("dup(%d) -> %d", wrpip[0], tmpi);*/ rdpip[1] = tmpi; } if (fdo == wrpip[0]) { /* a conflict here */ if ((tmpo = Dup(rdpip[1])) < 0) { Error2("dup(%d): %s", rdpip[1], strerror(errno)); return -1; } /*0 Info2("dup(%d) -> %d", rdpip[1], tmpo);*/ wrpip[0] = tmpo; } if (rw != XIO_WRONLY && rdpip[1] != fdo) { if (Dup2(rdpip[1], fdo) < 0) { Error3("dup2(%d, %d): %s", rdpip[1], fdo, strerror(errno)); return -1; } Close(rdpip[1]); /*0 Info2("dup2(%d, %d)", rdpip[1], fdo);*/ /*0 applyopts_cloexec(fdo, *copts);*/ } if (rw != XIO_RDONLY && wrpip[0] != fdi) { if (Dup2(wrpip[0], fdi) < 0) { Error3("dup2(%d, %d): %s", wrpip[0], fdi, strerror(errno)); return -1; } Close(wrpip[0]); /*0 Info2("dup2(%d, %d)", wrpip[0], fdi);*/ /*0 applyopts_cloexec(wrpip[0], *copts);*/ /* option is already consumed! */ /* applyopts_cloexec(fdi, *copts);*/ /* option is already consumed! */ } #else result = reassignfds(XIOWITHWR(rw)?wrpip[0]:-1, XIOWITHRD(rw)?rdpip[1]:-1, fdi, fdo); if (result < 0) return result; #endif applyopts(fdi, *copts, PH_LATE); applyopts(fdo, *copts, PH_LATE); applyopts(fdi, *copts, PH_LATE2); applyopts(fdo, *copts, PH_LATE2); break; } case XIOCOMM_SOCKETPAIR: case XIOCOMM_TCP: case XIOCOMM_TCP4: case XIOCOMM_TCP4_LISTEN: /*!indent*/ if (rw != XIO_RDONLY && fdi != sv[1]) { if (Dup2(sv[1], fdi) < 0) { Error3("dup2(%d, %d): %s", sv[1], fdi, strerror(errno)); return -1; } /*0 Info2("dup2(%d, %d)", sv[1], fdi);*/ } if (rw != XIO_WRONLY && fdo != sv[1]) { if (Dup2(sv[1], fdo) < 0) { Error3("dup2(%d, %d): %s", sv[1], fdo, strerror(errno)); return -1; } /*0 Info2("dup2(%d, %d)", sv[1], fdo);*/ } if (fdi != sv[1] && fdo != sv[1]) { applyopts_cloexec(sv[1], *copts); Close(sv[1]); } applyopts(fdi, *copts, PH_LATE); applyopts(fdi, *copts, PH_LATE2); Close(sv[1]); break; default: Error1("_xioopen_progcall() internal: commtype %d not handled", commtype); break; } /* in case of an inter address, assign the right side FDs (e.g. 3 and 4) */ if (inter) { Info2("preparing the right side FDs %d and %d for exec process", rightin, rightout); result = reassignfds(XIOWITHRD(rw)?saverfd:-1, XIOWITHWR(rw)?savewfd:-1, rightin, form==2?rightout:STDOUT_FILENO); if (result < 0) return result; if (form == 2) { Fcntl_l(rightin, F_SETFD, 0); Fcntl_l(rightout, F_SETFD, 0); } } } /* withfork */ else /* !withfork */ { applyopts(-1, *copts, PH_LATE); applyopts(-1, *copts, PH_LATE2); } _xioopen_setdelayeduser(); /* set group before user - maybe you are not permitted afterwards */ if (retropt_gidt(*copts, OPT_SETGID, &group) >= 0) { Setgid(group); } if (retropt_uidt(*copts, OPT_SETUID, &user) >= 0) { Setuid(user); } if (withstderr) { *duptostderr = fdo; } else { *duptostderr = -1; } return 0; /* indicate child process */ } /* for parent (this is our socat process) */ Notice1("forked off child process "F_pid, pid); #if 0 if ((popts = copyopts(*copts, GROUP_FD|GROUP_TERMIOS|GROUP_FORK|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_FIFO)) == NULL) return STAT_RETRYLATER; #endif /* in parent: close fds that are only needed in child */ switch (commtype) { #if HAVE_PTY case XIOCOMM_PTY: if (Close(ttyfd) < 0) { Info2("close(%d): %s", ttyfd, strerror(errno)); } break; #endif /* HAVE_PTY */ case XIOCOMM_SOCKETPAIR: case XIOCOMM_TCP: case XIOCOMM_TCP4: case XIOCOMM_TCP4_LISTEN: Close(sv[1]); break; case XIOCOMM_PIPES: default: if (XIOWITHWR(rw)) Close(wrpip[0]); if (XIOWITHRD(rw)) Close(rdpip[1]); break; } fd->child.pid = pid; if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; applyopts_signal(fd, popts); if ((numleft = leftopts(popts)) > 0) { Error1("%d option(s) could not be used", numleft); showleft(popts); return STAT_NORETRY; } if (inter) { if (XIOWITHRD(rw)) Close(saverfd); if (XIOWITHWR(rw)) Close(savewfd); } return pid; /* indicate parent (main) process */ }
/* creates the listening socket, bind, applies options; waits for incoming connection, checks its source address and port. Depending on fork option, it may fork a subprocess. pf specifies the syntax expected for range option. In the case of generic socket it is 0 (expecting raw binary data), and the real pf can be obtained from us->af_family; for other socket types pf == us->af_family Returns 0 if a connection was accepted; with fork option, this is always in a subprocess! Other return values indicate a problem; this can happen in the master process or in a subprocess. This function does not retry. If you need retries, handle this in a loop in the calling function (and always provide the options...) After fork, we set the forever/retry of the child process to 0 applies and consumes the following option: PH_INIT, PH_PASTSOCKET, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY, PH_PREOPEN, PH_FD, PH_CONNECTED, PH_LATE, PH_LATE2 OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_BACKLOG, OPT_RANGE, tcpwrap, OPT_SOURCEPORT, OPT_LOWPORT, cloexec */ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, socklen_t uslen, struct opt *opts, int pf, int socktype, int proto, int level) { struct sockaddr sa; socklen_t salen; int backlog = 5; /* why? 1 seems to cause problems under some load */ char *rangename; bool dofork = false; int maxchildren = 0; char infobuff[256]; char lisname[256]; union sockaddr_union _peername; union sockaddr_union _sockname; union sockaddr_union *pa = &_peername; /* peer address */ union sockaddr_union *la = &_sockname; /* local address */ socklen_t pas = sizeof(_peername); /* peer address size */ socklen_t las = sizeof(_sockname); /* local address size */ int result; retropt_bool(opts, OPT_FORK, &dofork); if (dofork) { if (!(xioflags & XIO_MAYFORK)) { Error("option fork not allowed here"); return STAT_NORETRY; } xfd->flags |= XIO_DOESFORK; } retropt_int(opts, OPT_MAX_CHILDREN, &maxchildren); if (! dofork && maxchildren) { Error("option max-children not allowed without option fork"); return STAT_NORETRY; } if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (dofork) { xiosetchilddied(); /* set SIGCHLD handler */ } if ((xfd->fd = xiosocket(opts, us->sa_family, socktype, proto, level)) < 0) { return STAT_RETRYLATER; } applyopts_cloexec(xfd->fd, opts); applyopts(xfd->fd, opts, PH_PREBIND); applyopts(xfd->fd, opts, PH_BIND); if (Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, strerror(errno)); Close(xfd->fd); return STAT_RETRYLATER; } #if WITH_UNIX if (us->sa_family == AF_UNIX) { applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD); } #endif /* under some circumstances (e.g., TCP listen on port 0) bind() fills empty fields that we want to know. */ salen = sizeof(sa); if (Getsockname(xfd->fd, us, &uslen) < 0) { Warn4("getsockname(%d, %p, {%d}): %s", xfd->fd, &us, uslen, strerror(errno)); } applyopts(xfd->fd, opts, PH_PASTBIND); #if WITH_UNIX if (us->sa_family == AF_UNIX) { /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY); applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN); } #endif /* WITH_UNIX */ #if WITH_IP4 /*|| WITH_IP6*/ if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { if (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) { free(rangename); return STAT_NORETRY; } free(rangename); xfd->para.socket.dorange = true; } #endif #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP xio_retropt_tcpwrap(xfd, opts); #endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */ #if WITH_TCP || WITH_UDP if (retropt_ushort(opts, OPT_SOURCEPORT, &xfd->para.socket.ip.sourceport) >= 0) { xfd->para.socket.ip.dosourceport = true; } retropt_bool(opts, OPT_LOWPORT, &xfd->para.socket.ip.lowport); #endif /* WITH_TCP || WITH_UDP */ applyopts(xfd->fd, opts, PH_PRELISTEN); retropt_int(opts, OPT_BACKLOG, &backlog); if (Listen(xfd->fd, backlog) < 0) { Error3("listen(%d, %d): %s", xfd->fd, backlog, strerror(errno)); return STAT_RETRYLATER; } if (xioopts.logopt == 'm') { Info("starting accept loop, switching to syslog"); diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y'; } else { Info("starting accept loop"); } while (true) { /* but we only loop if fork option is set */ char peername[256]; char sockname[256]; int ps; /* peer socket */ pa = &_peername; la = &_sockname; salen = sizeof(struct sockaddr); do { /*? int level = E_ERROR;*/ Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname))); ps = Accept(xfd->fd, (struct sockaddr *)&sa, &salen); if (ps >= 0) { /*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", xfd->fd, &sa, salen, ps);*/ break; /* success, break out of loop */ } if (errno == EINTR) { continue; } if (errno == ECONNABORTED) { Notice4("accept(%d, %p, {"F_socklen"}): %s", xfd->fd, &sa, salen, strerror(errno)); continue; } Msg4(level, "accept(%d, %p, {"F_socklen"}): %s", xfd->fd, &sa, salen, strerror(errno)); Close(xfd->fd); return STAT_RETRYLATER; } while (true); applyopts_cloexec(ps, opts); if (Getpeername(ps, &pa->soa, &pas) < 0) { Warn4("getpeername(%d, %p, {"F_socklen"}): %s", ps, pa, pas, strerror(errno)); pa = NULL; } if (Getsockname(ps, &la->soa, &las) < 0) { Warn4("getsockname(%d, %p, {"F_socklen"}): %s", ps, la, las, strerror(errno)); la = NULL; } Notice2("accepting connection from %s on %s", pa? sockaddr_info(&pa->soa, pas, peername, sizeof(peername)):"NULL", la? sockaddr_info(&la->soa, las, sockname, sizeof(sockname)):"NULL"); if (pa != NULL && la != NULL && xiocheckpeer(xfd, pa, la) < 0) { if (Shutdown(ps, 2) < 0) { Info2("shutdown(%d, 2): %s", ps, strerror(errno)); } Close(ps); continue; } if (pa != NULL) Info1("permitting connection from %s", sockaddr_info((struct sockaddr *)pa, pas, infobuff, sizeof(infobuff))); if (dofork) { pid_t pid; /* mostly int; only used with fork */ sigset_t mask_sigchld; /* we must prevent that the current packet triggers another fork; therefore we wait for a signal from the recent child: USR1 indicates that is has consumed the last packet; CHLD means it has terminated */ /* block SIGCHLD and SIGUSR1 until parent is ready to react */ sigemptyset(&mask_sigchld); sigaddset(&mask_sigchld, SIGCHLD); Sigprocmask(SIG_BLOCK, &mask_sigchld, NULL); if ((pid = xio_fork(false, level==E_ERROR?level:E_WARN)) < 0) { Close(xfd->fd); Sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL); return STAT_RETRYLATER; } if (pid == 0) { /* child */ pid_t cpid = Getpid(); Sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL); Info1("just born: child process "F_pid, cpid); xiosetenvulong("PID", cpid, 1); if (Close(xfd->fd) < 0) { Info2("close(%d): %s", xfd->fd, strerror(errno)); } xfd->fd = ps; #if WITH_RETRY /* !? */ xfd->forever = false; xfd->retry = 0; level = E_ERROR; #endif /* WITH_RETRY */ break; } /* server: continue loop with listen */ /* shutdown() closes the socket even for the child process, but close() does what we want */ if (Close(ps) < 0) { Info2("close(%d): %s", ps, strerror(errno)); } /* now we are ready to handle signals */ Sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL); while (maxchildren) { if (num_child < maxchildren) break; Notice("maxchildren are active, waiting"); /* UINT_MAX would even be nicer, but Openindiana works only with 31 bits */ while (!Sleep(INT_MAX)) ; /* any signal lets us continue */ } Info("still listening"); } else { if (Close(xfd->fd) < 0) { Info2("close(%d): %s", xfd->fd, strerror(errno)); } xfd->fd = ps; break; } } applyopts(xfd->fd, opts, PH_FD); applyopts(xfd->fd, opts, PH_PASTSOCKET); applyopts(xfd->fd, opts, PH_CONNECTED); if ((result = _xio_openlate(xfd, opts)) < 0) return result; /* set the env vars describing the local and remote sockets */ if (la != NULL) xiosetsockaddrenv("SOCK", la, las, proto); if (pa != NULL) xiosetsockaddrenv("PEER", pa, pas, proto); return 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? */ struct cmdline_tokens tok; /* Parse command line */ bg = parseline(cmdline, &tok); if (bg == -1) return; /* parsing error */ if (tok.argv[0] == NULL) return; /* ignore empty lines */ /* Built-in Command */ if (tok.builtins!=BUILTIN_NONE){ builtin_command(&tok); return; } /* Common tasks for both foreground and background */ pid_t pid; sigset_t mask; Sigemptyset(&mask); Sigaddset(&mask, SIGCHLD); Sigaddset(&mask, SIGINT); Sigaddset(&mask, SIGTSTP); /* Block signal receving in parent */ Sigprocmask(SIG_BLOCK, &mask, NULL); if ((pid=Fork())==0){ /* Unblock signal receiving in child */ Sigprocmask(SIG_UNBLOCK, &mask, NULL); /* Changes the child's process group from the shell's */ Setpgid(0,0); /* Change the input and output file descriptors */ IOredirection(&tok); Execve(tok.argv[0], tok.argv, environ); /* Command not found */ printf("Executable file not found\n"); exit(0); } /* Foreground job*/ if (!bg){ if (!addjob(job_list, pid, FG, cmdline)) return; Sigprocmask(SIG_UNBLOCK, &mask, NULL); wait_for_fg(pid); return; } /* Background job */ if (bg){ if (!addjob(job_list, pid, BG, cmdline)) return; Sigprocmask(SIG_UNBLOCK, &mask, NULL); printf("[%d] (%d) %s\n", pid2jid(pid), pid, cmdline); } return; }
// Débloque les signaux importants pour le shell s'ils ont // été bloqués au préalable par un appel à `signals_lock` void jobs_signals_unlock (char* desc) { Sigprocmask(SIG_UNBLOCK, &signals_to_block, NULL); }
/* * 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 (SIGSTP) from the kernel * when we type ctrl-c (ctrl-z) at the keyboard. */ void eval(char *cmdline) { char *argv[MAXARGS], buf[MAXLINE]; int bg, status, state; volatile pid_t pid; int jid; sigset_t mask_all, mask_one, prev_one; Log("EVAL [0]\n", 9); strcpy(buf, cmdline); bg = parseline(buf, argv); if (argv[0] == NULL) { return; } Log("EVAL [1]\n", 9); if (builtin_cmd(argv)) { return; } Log("EVAL [2]\n", 9); Sigfillset(&mask_all); Sigemptyset(&mask_one); Sigaddset(&mask_one, SIGCHLD); Sigprocmask(SIG_BLOCK, &mask_one, &prev_one); pid = Fork(); if (pid == CHILD) { Sigprocmask(SIG_SETMASK, &prev_one, NULL); Setpgid(0, 0); Log("EVAL [3]\n", 9); Execve(argv[0], argv, environ); } Sigprocmask(SIG_BLOCK, &mask_all, NULL); state = bg ? BG : FG; Log("EVAL [4]\n", 9); status = addjob(jobs, pid, state, cmdline); Log("EVAL [5]\n", 9); /* Stores jid while process has not been removed */ jid = getjobpid(jobs, pid)->jid; atomic_fggpid = bg ? 0 : pid; Log("EVAL [5a]\n", 10); Sigprocmask(SIG_SETMASK, &prev_one, NULL); Log("EVAL [5b]\n", 10); /* Handle errors when generating a new job */ if (!status) { return; } /* Parent waits for foreground job to terminate */ if (!bg) { Log("EVAL [6]\n", 9); waitfg(pid); } else { Log("EVAL [7]\n", 9); printf("[%d] (%d) %s", jid, pid, cmdline); } }