示例#1
0
文件: util.c 项目: heapsters/shelldon
/*
 * 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;
}
示例#2
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);
}
示例#3
0
文件: tsh.c 项目: fffxj/csapp
/* 
 * 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;
}
示例#4
0
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);
}
示例#5
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;
}
示例#6
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)
{
    // 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;
}
示例#7
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;

    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;
}
示例#8
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 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;
}
示例#9
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, 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;
}
示例#10
0
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--;
    }
}
示例#12
0
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);


}
示例#13
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);
}
示例#14
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);
}
示例#15
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: 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);
}
示例#16
0
文件: tsh.c 项目: RoseySoft/tsh
/* 
 * 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;
}
示例#17
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, 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;
}
示例#18
0
/*
 * 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);
}
示例#19
0
/*
 * 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);
    }
}
示例#20
0
文件: util.c 项目: heapsters/shelldon
/*
 * 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);
}
示例#21
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];
	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);
}
示例#22
0
文件: csapp.c 项目: jack-lijing/unix
/****************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;
}
示例#23
0
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);
}
示例#24
0
文件: tsh.c 项目: fffxj/csapp
/* 
 * 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;
}
示例#25
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;
    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;
}
示例#26
0
/* 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 */
}
示例#27
0
/* 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;
}
示例#28
0
文件: tsh.c 项目: MyMiracle/Shell-Lab
/*
 * 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;
}
示例#29
0
// 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);
}
示例#30
0
文件: util.c 项目: heapsters/shelldon
/*
 * 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);
    }
}