Ejemplo n.º 1
0
/*========================================================================
** The Main Procedure
** Initialization and FIFO command dispatch routine.
========================================================================*/
static int real_main(int argc, char *argv[])
	{
	const char function[] = "real_main";
	int option_foreground = FALSE;
	int FIFO;					/* First-in-first-out which feeds us requests */
	sigset_t lock_set;
	struct timeval next_tick;

	/* Initialize internation messages library. */
	#ifdef INTERNATIONAL
	setlocale(LC_ALL, "");
	bindtextdomain(PACKAGE_PPRD, LOCALEDIR);
	textdomain(PACKAGE_PPRD);
	#endif

	/*
	** Set some environment variables, (PATH, IFS, and
	** SHELL) for safety and for the convenience of the
	** programs we launch (HOME, and PPR_VERSION).
	** Remove unnecessary and potentially misleading
	** variables.
	*/
	set_ppr_env();
	prune_env();

	parse_command_line(argc, argv, &option_foreground);

	/* Switch all UIDs to USER_PPR, all GIDS to GROUP_PPR. */
	adjust_ids();

	/* If the --forground switch wasn't used, then dropt into background. */
	if(! option_foreground)
		gu_daemon(PPR_PPRD_UMASK);
	else
		umask(PPR_PPRD_UMASK);

	/* Change the home directory to the PPR home directory: */
	chdir(HOMEDIR);

	/* Create /var/spool/ppr/pprd.pid. */
	create_lock_file();

	/* Signal handlers for silly stuff. */
	signal_restarting(SIGPIPE, signal_ignore);
	signal_restarting(SIGHUP, signal_ignore);

	/* Signal handler for shutdown request. */
	signal_interupting(SIGTERM, sigterm_handler);

	/* Arrange for child termination to be noted. */
	signal_restarting(SIGCHLD, sigchld_handler);

	/* Move /var/spool/ppr/logs/pprd to pprd.old before we call debug()
	   for the first time (below). */
	rename_old_log_file();

	/*
	** This code must come after adjust_ids() and gu_daemon().
	** It makes the first log entry and tells queue-display
	** programs that we are starting up.
	*/
	debug("PPRD startup, pid=%ld", (long)getpid());
	state_update("STARTUP");

	/* Make sure the local node gets the node id of 0. */
	if(! nodeid_is_local_node(nodeid_assign(ppr_get_nodename())))
		fatal(1, "%s(): line %d: assertion failed", function, __LINE__);

	/* Initialize other subsystems. */
	question_init();

	/* Load the printers database. */
	DODEBUG_STARTUP(("loading printers database"));
	load_printers();

	/* Load the groups database. */
	DODEBUG_STARTUP(("loading groups database"));
	load_groups();

	/* Set up the FIFO. */
	DODEBUG_STARTUP(("opening FIFO"));
	FIFO = open_fifo();

	/* Initialize the queue.  This is likely to start printers. */
	DODEBUG_STARTUP(("initializing the queue"));
	initialize_queue();

	/* Schedule the first timer tick. */
	gettimeofday(&next_tick, NULL);
	next_tick.tv_sec += TICK_INTERVAL;

	/*
	** Create a signal block set which will be used to block SIGCHLD except
	** when we are calling select().
	*/
	sigemptyset(&lock_set);
	sigaddset(&lock_set, SIGCHLD);
	sigprocmask(SIG_BLOCK, &lock_set, (sigset_t*)NULL);

	/*
	** This is the Main Loop.  It runs until the sigterm_handler
	** sets sigterm_received.
	*/
	while(!sigterm_received)
		{
		int readyfds;					/* return value from select() */
		fd_set rfds;					/* list of file descriptors for select() to watch */
		struct timeval time_now;		/* the current time */

		DODEBUG_MAINLOOP(("top of main loop"));

		gettimeofday(&time_now, NULL);

		/* If it is time for or past time for the next tick, */
		if(gu_timeval_cmp(&time_now, &next_tick) >= 0)
			{
			readyfds = 0;
			}

		/* If it is not time for the next tick yet, */
		else
			{
			/* Set the select() timeout so that it will return in time for the
			   next tick(). */
			gu_timeval_cpy(&select_tv, &next_tick);
			gu_timeval_sub(&select_tv, &time_now);

			/* Create a file descriptor list which contains only the descriptor
			   of the FIFO. */
			FD_ZERO(&rfds);
			FD_SET(FIFO, &rfds);

			/* Call select() with SIGCHLD unblocked. */
			sigprocmask(SIG_UNBLOCK, &lock_set, (sigset_t*)NULL);
			readyfds = select(FIFO + 1, &rfds, NULL, NULL, &select_tv);
			sigprocmask(SIG_BLOCK, &lock_set, (sigset_t*)NULL);
			}

		/* If there is something to read, */
		if(readyfds > 0)
			{
			if(!FD_ISSET(FIFO, &rfds))
				fatal(0, "%s(): assertion failed: select() returned but FIFO not ready", function);
			do_command(FIFO);
			continue;
			}

		/* If the SIGCHLD handler set the flag, handle child termination.  Once
		   we have done that, we must go back to the top of the loop because
		   we don't really know if it is time for a tick() call yet. */
		if(sigchld_caught)
			{
			sigchld_caught = FALSE;
			reapchild();
			continue;
			}

		/* If there was no error and no file descriptors are ready, then the 
		   timeout must have expired.  Call tick(). */
		if(readyfds == 0)
			{
			tick();
			next_tick.tv_sec += TICK_INTERVAL;
			continue;
			}

		/* If interupted by a system call, restart it. */
		if(errno == EINTR)
			continue;

		/* If we get this far, there was an error. */
		fatal(0, "%s(): select() failed, errno=%d (%s)", function, errno, gu_strerror(errno));
		} /* end of endless while() loop */

	state_update("SHUTDOWN");
	fatal(0, "Received SIGTERM, exiting");
	} /* end of real_main() */
Ejemplo n.º 2
0
Archivo: relay.c Proyecto: csmuc/iProxy
int serv_loop()
{
  int    cs, ss = 0;
  struct sockaddr_storage cl;
  fd_set readable;
  int    i, n, len;
  char   cl_addr[NI_MAXHOST];
  char   cl_name[NI_MAXHOST];
  int    error;
  pid_t  pid;

#ifdef USE_THREAD
  if (threading) {
    blocksignal(SIGHUP);
    blocksignal(SIGINT);
    blocksignal(SIGUSR1);
  }
#endif

  for (;;) {
    readable = allsock;

    MUTEX_LOCK(mutex_select);
    n = select(maxsock+1, &readable, 0, 0, 0);
    if (n <= 0) {
      if (n < 0 && errno != EINTR) {
        msg_out(warn, "select: %m");
      }
      MUTEX_UNLOCK(mutex_select);
      continue;
    }

#ifdef USE_THREAD
    if ( ! threading ) {
#endif
      /* handle any queued signal flags */
      if (FD_ISSET(sig_queue[0], &readable)) {
        if (ioctl(sig_queue[0], FIONREAD, &i) != 0) {
          msg_out(crit, "ioctl: %m");
          exit(-1);
        }
        while (--i >= 0) {
          char c;
          if (read(sig_queue[0], &c, 1) != 1) {
            msg_out(crit, "read: %m");
            exit(-1);
          }
          switch(c) {
          case 'H': /* sighup */
            reload();
            break;
          case 'C': /* sigchld */
            reapchild();
            break;
          case 'T': /* sigterm */
            cleanup();
            break;
          default:
            break;
          }
        }
      }
#ifdef USE_THREAD
    }
#endif

    for ( i = 0; i < serv_sock_ind; i++ ) {
      if (FD_ISSET(serv_sock[i], &readable)) {
	n--;
	break;
      }
    }
    if ( n < 0 || i >= serv_sock_ind ) {
      MUTEX_UNLOCK(mutex_select);
      continue;
    }

    len = sizeof(struct sockaddr_storage);
    cs = accept(serv_sock[i], (struct sockaddr *)&cl, (socklen_t *)&len);
    if (cs < 0) {
      if (errno == EINTR
#ifdef SOLARIS
	  || errno == EPROTO
#endif
	  || errno == EWOULDBLOCK
	  || errno == ECONNABORTED) {
	; /* ignore */
      } else {
	/* real accept error */
	msg_out(warn, "accept: %m");
      }
      MUTEX_UNLOCK(mutex_select);
      continue;
    }
    MUTEX_UNLOCK(mutex_select);

#ifdef USE_THREAD
    if ( !threading ) {
#endif
      if (max_child > 0 && cur_child >= max_child) {
	msg_out(warn, "child: cur %d; exeedeing max(%d)",
		          cur_child, max_child);
	close(cs);
	continue;
      }
#ifdef USE_THREAD
    }
#endif

    error = getnameinfo((struct sockaddr *)&cl, len,
			cl_addr, sizeof(cl_addr),
			NULL, 0,
			NI_NUMERICHOST);
    if (resolv_client) {
      error = getnameinfo((struct sockaddr *)&cl, len,
			  cl_name, sizeof(cl_name),
			  NULL, 0, 0);
      msg_out(norm, "%s[%s] connected", cl_name, cl_addr);
    } else {
      msg_out(norm, "%s connected", cl_addr);
      strncpy(cl_name, cl_addr, sizeof(cl_name));
    }

    i = validate_access(cl_addr, cl_name);
    if (i < 1) {
      /* access denied */
      close(cs);
      continue;
    }

    set_blocking(cs);

#ifdef USE_THREAD
    if (!threading ) {
#endif
      blocksignal(SIGHUP);
      blocksignal(SIGCHLD);
      pid = fork();
      switch (pid) {
        case -1:  /* fork child failed */
            printf("\nfork failed\n");
            break;
        case 0:   /* i am child */
            for ( i = 0; i < serv_sock_ind; i++ ) {
              close(serv_sock[i]);
            }
            setsignal(SIGCHLD, SIG_DFL);
                setsignal(SIGHUP, SIG_DFL);
                releasesignal(SIGCHLD);
                releasesignal(SIGHUP);
            ss = proto_socks(cs);
            if ( ss == -1 ) {
              close(cs);  /* may already be closed */
              exit(1);
            }
            printf("\nrelaying\n");
            relay(cs, ss);
            exit(0);
      default: /* may be parent */
            printf("\nadding proc\n");
            proclist_add(pid);
            break;
      }
      close(cs);
      releasesignal(SIGHUP);
      releasesignal(SIGCHLD);
#ifdef USE_THREAD
    } else {
      ss = proto_socks(cs);
      if ( ss == -1 ) {
        close(cs);  /* may already be closed */
        continue;
      }
      relay(cs, ss);
    }
#endif
  }
}
Ejemplo n.º 3
0
int serv_loop()
{

  SOCKS_STATE	state;
  SOCK_INFO	si;
  CL_INFO	client;

  int    cs;
  fd_set readable;
  int    i, n, len;
  int    error;
  pid_t  pid;

  memset(&state, 0, sizeof(state));
  memset(&si, 0, sizeof(si));
  memset(&client, 0, sizeof(client));
  state.si = &si;

#ifdef USE_THREAD
  if (threading) {
    blocksignal(SIGHUP);
    blocksignal(SIGINT);
    blocksignal(SIGUSR1);
  }
#endif

  for (;;) {
    readable = allsock;

    MUTEX_LOCK(mutex_select);
    n = select(maxsock+1, &readable, 0, 0, 0);
    if (n <= 0) {
      if (n < 0 && errno != EINTR) {
        msg_out(warn, "select: %m");
      }
      MUTEX_UNLOCK(mutex_select);
      continue;
    }

#ifdef USE_THREAD
    if ( ! threading ) {
#endif
      /* handle any queued signal flags */
      if (FD_ISSET(sig_queue[0], &readable)) {
        if (ioctl(sig_queue[0], FIONREAD, &i) != 0) {
          msg_out(crit, "ioctl: %m");
          exit(-1);
        }
        while (--i >= 0) {
          char c;
          if (read(sig_queue[0], &c, 1) != 1) {
            msg_out(crit, "read: %m");
            exit(-1);
          }
          switch(c) {
          case 'H': /* sighup */
            reload();
            break;
          case 'C': /* sigchld */
            reapchild();
            break;
          case 'T': /* sigterm */
            cleanup();
            break;
          default:
            break;
          }
        }
      }
#ifdef USE_THREAD
    }
#endif

    for ( i = 0; i < serv_sock_ind; i++ ) {
      if (FD_ISSET(serv_sock[i], &readable)) {
	n--;
	break;
      }
    }
    if ( n < 0 || i >= serv_sock_ind ) {
      MUTEX_UNLOCK(mutex_select);
      continue;
    }

    len = SS_LEN;
    cs = accept(serv_sock[i], &si.prc.addr.sa, (socklen_t *)&len);
    si.prc.len = len;
    if (cs < 0) {
      if (errno == EINTR
#ifdef SOLARIS
	  || errno == EPROTO
#endif
	  || errno == EWOULDBLOCK
	  || errno == ECONNABORTED) {
	; /* ignore */
      } else {
	/* real accept error */
	msg_out(warn, "accept: %m");
      }
      MUTEX_UNLOCK(mutex_select);
      continue;
    }
    MUTEX_UNLOCK(mutex_select);

#ifdef USE_THREAD
    if ( !threading ) {
#endif
      if (max_child > 0 && cur_child >= max_child) {
	msg_out(warn, "child: cur %d; exeedeing max(%d)",
		          cur_child, max_child);
	close(cs);
	continue;
      }
#ifdef USE_THREAD
    }
#endif

    /* get downstream-side socket name */
    len = SS_LEN;
    getsockname(cs, &si.myc.addr.sa, (socklen_t *)&len);
    si.myc.len = len;

    error = getnameinfo(&si.prc.addr.sa, si.prc.len,
			client.addr, sizeof(client.addr),
			NULL, 0,
			NI_NUMERICHOST);
    if (resolv_client) {
      error = getnameinfo(&si.prc.addr.sa, si.prc.len,
			  client.name, sizeof(client.name),
			  NULL, 0, 0);
      msg_out(norm, "%s[%s] connected", client.name, client.addr);
    } else {
      msg_out(norm, "%s connected", client.addr);
      strncpy(client.name, client.addr, sizeof(client.name));
    }

    i = validate_access(&client);
    if (i < 1) {
      /* access denied */
      close(cs);
      continue;
    }

    set_blocking(cs);
    state.s = cs;

#ifdef USE_THREAD
    if (!threading ) {
#endif
      blocksignal(SIGHUP);
      blocksignal(SIGCHLD);
      pid = fork();
      switch (pid) {
      case -1:  /* fork child failed */
	break;
      case 0:   /* i am child */
	for ( i = 0; i < serv_sock_ind; i++ ) {
	  close(serv_sock[i]);
	}
	setsignal(SIGCHLD, SIG_DFL);
        setsignal(SIGHUP, SIG_DFL);
        releasesignal(SIGCHLD);
        releasesignal(SIGHUP);
	error = proto_socks(&state);
	if ( error == -1 ) {
	  close(state.s);  /* may already be closed */
	  exit(1);
	}
	relay(&state);
	exit(0);
      default: /* may be parent */
	proclist_add(pid);
	break;
      }
      close(state.s);
      releasesignal(SIGHUP);
      releasesignal(SIGCHLD);
#ifdef USE_THREAD
    } else {
      error = proto_socks(&state);
      if ( error == -1 ) {
	close(state.s);  /* may already be closed */
	/* udp may be dynamically allocated */
	if (state.sr.udp != NULL)
	  free(state.sr.udp);
	continue;
      }
      relay(&state);
    }
#endif
  }
}
Ejemplo n.º 4
0
int
main(int argc, char **argv, char **ev)
{
    extern char		*optarg;
    extern int		optind;
    char		ch,
			hbuf[BUFSZ],		/* hlogin buffer */
			ptyname[FILENAME_MAX + 1],
			tbuf[BUFSZ],		/* telnet/ssh buffer */
			tbufstr[5] = {ESC, '\x07', '\r', '\n', '\0'};
    int			bytes,			/* bytes read/written */
			devnull,
			rval = EX_OK,
			ptym,			/* master pty */
			ptys;			/* slave pty */
    ssize_t		idx,			/* strcspan span */
			hlen = 0,		/* len of hbuf */
			tlen = 0;		/* len of tbuf */
    struct pollfd	pfds[3];
    struct termios	tios;

    environ = ev;

    /* get just the basename() of our exec() name and strip a .* off the end */
    if ((progname = strrchr(argv[0], '/')) != NULL)
	progname += 1;
    else
	progname = argv[0];
    if (strrchr(progname, '.') != NULL)
	*(strrchr(progname, '.')) = '\0';

    while ((ch = getopt(argc, argv, "dhvt:")) != -1 )
	switch (ch) {
	case 'd':
	    debug++;
	    break;
	case 't':
	    timeo = atoi(optarg);
	    if (timeo < 1)
		timeo = 1;
	    break;
	case 'v':
	    vers();
	    return(EX_OK);
	case 'h':
	default:
	    usage();
	    return(EX_USAGE);
	}

    if (argc - optind < 2) {
	usage();
	return(EX_USAGE);
    }

    unsetenv("DISPLAY");

    for (sigrx = 3; sigrx < 10; sigrx++)
	close(sigrx);

    /* allocate pty for telnet/ssh, then fork and exec */
    if (openpty(&ptym, &ptys, ptyname, NULL, NULL)) {
	fprintf(stderr, "%s: could not allocate pty: %s\n", progname,
		strerror(errno));
	return(EX_TEMPFAIL);
    }
    /* make the pty raw */
    if (tcgetattr(ptys, &tios)) {
	fprintf(stderr, "%s: tcgetattr() failed: %s\n", progname,
		strerror(errno));
	return(EX_OSERR);
    }
    tios.c_lflag &= ~ECHO;
    tios.c_lflag &= ~ICANON;
#ifdef VMIN
    tios.c_cc[VMIN] = 1;
    tios.c_cc[VTIME] = 0;
#endif
    if (tcsetattr(ptys, TCSANOW, &tios)) {
	fprintf(stderr, "%s: tcsetattr() failed: %s\n", progname,
		strerror(errno));
	return(EX_OSERR);
    }

    /*
     * if a tty, make it raw as the hp echos _everything_, including
     * passwords.
     */
    if (isatty(fileno(stdin))) {
	if (tcgetattr(fileno(stdin), &tios)) {
	    fprintf(stderr, "%s: tcgetattr() failed: %s\n", progname,
		strerror(errno));
	    return(EX_OSERR);
	}
	tios.c_lflag &= ~ECHO;
	tios.c_lflag &= ~ICANON;
#ifdef VMIN
	tios.c_cc[VMIN] = 1;
	tios.c_cc[VTIME] = 0;
#endif
	if (tcsetattr(fileno(stdin), TCSANOW, &tios)) {
	    fprintf(stderr, "%s: tcsetattr() failed: %s\n", progname,
		strerror(errno));
	    return(EX_OSERR);
	}
    }

    /* zero the buffers */
    memset(hbuf, 0, BUFSZ);
    memset(tbuf, 0, BUFSZ);

    /* reap our children, must be set-up *after* openpty() */
    signal(SIGCHLD, reapchild);

    if ((child = fork()) == -1) {
	fprintf(stderr, "%s: fork() failed: %s\n", progname, strerror(errno));
	return(EX_TEMPFAIL);
    }

    if (child == 0) {
	struct winsize ws;

	/*
	 * Make sure our terminal length and width are something greater
	 * than 1, for pagers on stupid boxes.
	 */
	ioctl(ptys, TIOCGWINSZ, &ws);
	ws.ws_row = 24;
	ws.ws_col = 132;
	ioctl(ptys, TIOCSWINSZ, &ws);

	signal(SIGCHLD, SIG_DFL);
	/* close the master pty & std* inherited from the parent */
	close(ptym);
	if (ptys != 0)
	    close(0);
	if (ptys != 1)
	    close(1);
	if (ptys != 2)
	    close(2);
#ifdef TIOCSCTTY
	setsid();
	if (ioctl(ptys, TIOCSCTTY, NULL) == -1) {
	    snprintf(ptyname, FILENAME_MAX, "%s: could not set controlling "
		     "tty: %s\n", progname, strerror(errno));
	    write(0, ptyname, strlen(ptyname));
	    return(EX_OSERR);
	}
#endif

	/* close stdin/out/err and attach them to the pipes */
	if (dup2(ptys, 0) == -1 || dup2(ptys, 1) == -1 || dup2(ptys, 2) == -1) {
	    snprintf(ptyname, FILENAME_MAX, "%s: dup2() failed: %s\n", progname,
		     strerror(errno));
	    write(0, ptyname, strlen(ptyname));
	    return(EX_OSERR);
	}
	if (ptys > 2)
	    close(ptys);

	/* exec telnet/ssh */
	execvp(argv[optind], argv + optind);
	snprintf(ptyname, FILENAME_MAX, "%s: execvp() failed: %s\n", progname,
		 strerror(errno));
	write(0, ptyname, strlen(ptyname));
	return(EX_TEMPFAIL);
	/*NOTREACHED*/
    }

    /* parent */
    if (debug)
	fprintf(stderr, "child %d\n", (int)child);

    signal(SIGHUP, sighdlr);

    /* close the slave pty */
    close(ptys);

    devnull = open("/dev/null", O_RDWR);

    /* make FDs non-blocking */
    if (fcntl(ptym, F_SETFL, O_NONBLOCK) ||
	fcntl(fileno(stdin), F_SETFL, O_NONBLOCK) ||
	fcntl(fileno(stdout), F_SETFL, O_NONBLOCK)) {
	fprintf(stderr, "%s: fcntl(NONBLOCK) failed: %s\n", progname,
		strerror(errno));
	exit(EX_OSERR);
    }

    /* loop to read on stdin and ptym */
#define	POLLEXP	(POLLERR | POLLHUP | POLLNVAL)
    pfds[0].fd = fileno(stdin);
    pfds[0].events = POLLIN | POLLEXP;
    pfds[1].fd = fileno(stdout);
    pfds[1].events = POLLEXP;
    pfds[2].fd = ptym;
    pfds[2].events = POLLIN | POLLEXP;

    /* shuffle data across the pipes until we see EOF or a read/write error */
    sigrx = 0;
    while (1) {
	bytes = poll(pfds, 3, (timeo * 1000));
	if (bytes == 0) {
	    if (sigrx)
		break;
	    /* timeout */
	    continue;
	}
	if (bytes == -1) {
	    switch (errno) {
	    case EAGAIN:
	    case EINTR:
		break;
	    default:
		rval = EX_IOERR;
		break;
	    }
	    continue;
	}

	/*
	 * write buffers first
	 * write hbuf (aka hlogin/stdin/pfds[0]) -> telnet (aka ptym/pfds[2])
	 */
	if ((pfds[2].revents & POLLOUT) && hlen) {
	    if ((bytes = write(pfds[2].fd, hbuf, hlen)) < 0 &&
		errno != EINTR && errno != EAGAIN) {
		fprintf(stderr, "%s: write() failed: %s\n", progname,
			strerror(errno));
		hlen = 0;
		hbuf[0] = '\0';
		break;
	    } else if (bytes > 0) {
		strcpy(hbuf, hbuf + bytes);
		hlen -= bytes;
		if (hlen < 1)
		     pfds[2].events &= ~POLLOUT;
	    }
	}
	if (pfds[2].revents & POLLEXP) {
	    hlen = 0;
	    hbuf[0] = '\0';
	    break;
	}

	/* write tbuf (aka telnet/ptym/pfds[2]) -> hlogin (stdout/pfds[1]) */
	if ((pfds[1].revents & POLLOUT) && tlen) {
	    /*
	     * if there is an escape char that didnt get filter()'d,
	     * we need to write only up to that point and wait for
	     * the bits that complete the escape sequence.  if at least
	     * two bytes follow it and it doesn't look like we should expect
	     * more data, write it anyway as filter() didnt match it.
	     */
	    bytes = tlen;
	    idx = strcspn(tbuf, tbufstr);
	    if (idx) {
		if (tbuf[idx] == ESC) {
		    if (tlen - idx < 2 || expectmore(&tbuf[idx], tlen - idx)) {
			bytes = idx;
		    }
		}
		if (tbuf[idx] == '\r' || tbuf[idx] == '\n') {
		    bytes = ++idx;
		    if (tbuf[idx] == '\r' || tbuf[idx] == '\n')
			bytes++;
		}
	    } else {
		if (tbuf[0] == ESC) {
		    if (tlen < 2 || expectmore(tbuf, tlen)) {
			bytes = 0;
		    }
		}
		if (tbuf[0] == '\r' || tbuf[0] == '\n') {
		    bytes = 1;
		    if (tbuf[1] == '\r' || tbuf[1] == '\n')
			bytes++;
		}
	    }

	    if ((bytes = write(pfds[1].fd, tbuf, bytes)) < 0 &&
		errno != EINTR && errno != EAGAIN) {
		fprintf(stderr, "%s: write() failed: %s\n", progname,
			strerror(errno));
		/* dont bother trying to flush tbuf */
		tlen = 0;
		tbuf[0] = '\0';
		break;
	    } else if (bytes > 0) {
		strcpy(tbuf, tbuf + bytes);
		tlen -= bytes;
		if (tlen < 1)
		    pfds[1].events &= ~POLLOUT;
	    }
	}
	if (pfds[1].revents & POLLEXP) {
	    /* dont bother trying to flush tbuf */
	    tlen = 0;
	    tbuf[0] = '\0';
	    break;
	}

	/* read hlogin (aka stdin/pfds[0]) -> hbuf */
	if (pfds[0].revents & POLLIN) {
	    if (BUFSZ - hlen > 1) {
		bytes = read(pfds[0].fd, hbuf + hlen, (BUFSZ - 1) - hlen);
		if (bytes > 0) {
		    hlen += bytes;
		    hbuf[hlen] = '\0';
		    pfds[2].events |= POLLOUT;
		} else if (bytes < 0 && errno != EAGAIN && errno != EINTR) {
		    /* read error */
		    break;
		}
	    }
	}
	if (pfds[0].revents & POLLEXP)
	    break;

	/* read telnet/ssh (aka ptym/pfds[2]) -> tbuf, then filter */
	if (pfds[2].revents & POLLIN) {
	    if (BUFSZ - tlen > 1) {
		bytes = read(pfds[2].fd, tbuf + tlen, (BUFSZ - 1) - tlen);
		if (bytes > 0) {
		    tlen += bytes;
		    tbuf[tlen] = '\0';
		    tlen = filter(tbuf, tlen);
		    if (tlen > 0)
			pfds[1].events |= POLLOUT;
		} else if (bytes < 0 && errno != EAGAIN && errno != EINTR) {
		    /* read error */
		    break;
		}
	    }
	}
	if (pfds[2].revents & POLLEXP)
	    break;
    }
    /* try to flush any remaining data from our buffers */
    if (hlen) {
	(void)write(pfds[2].fd, hbuf, hlen);
	hlen = 0;
    }
    if (tlen) {
	(void)write(pfds[1].fd, tbuf, tlen);
	tlen = 0;
    }
    if ((bytes = read(pfds[2].fd, tbuf, (BUFSZ - 1))) > 0) {
	tbuf[bytes] = '\0';
	tlen = filter(tbuf, bytes);
	(void)write(pfds[1].fd, tbuf, tlen);
    }
    tcdrain(pfds[1].fd);
    if ((hlen = read(pfds[0].fd, hbuf, (BUFSZ - 1))) > 0) {
	(void)write(pfds[2].fd, hbuf, hlen);
    }
    tcdrain(pfds[2].fd);

    if (child && ! kill(child, SIGINT))
	reapchild(SIGCHLD);

    return(rval);
}
Ejemplo n.º 5
0
void reapchildren(void) {
  for(;;) {
    sleep(5);
    reapchild(0);
  }
}