Exemple #1
0
/**
 * The on demand I/O subsystem's ioh handler. Remember this handles both
 * reads and writes.
 *
 * THREADS: MT-SAFE
 *
 *	@param B BAKA thread/global state.
 *	@param opaque My local data.
 *	@param ioh ioh over which the data arrived.
 *	@param state What's going on in the world.
 */
static void
polling_io_ioh_handler(bk_s B, bk_vptr *data, void *args, struct bk_ioh *ioh, bk_ioh_status_e status)
{
  BK_ENTRY(B, __FUNCTION__, __FILE__, "libbk");
  struct bk_polling_io *bpi = args;
  struct polling_io_data *pid = NULL;
  int (*clc_add)(dict_h dll, dict_obj obj) = dll_append; // Can't use #define here...

  if (!bpi || !ioh)
  {
    bk_error_printf(B, BK_ERR_ERR,"Illegal arguments\n");
    BK_VRETURN(B);
  }

  if (!(pid = pid_create(B)))
  {
    bk_error_printf(B, BK_ERR_ERR, "Could not allocate pid: %s\n", strerror(errno));
    goto error;
  }

  bk_debug_printf_and(B, 64, "IOH polling handler: %d (in: %d, out %d)\n", status, ioh->ioh_fdin, ioh->ioh_fdout);
  switch (status)
  {
  case BkIohStatusReadComplete:
  case BkIohStatusIncompleteRead:
    {
      /*
       * NB: We *assume* (safely, we believe) that in the cases of
       * BkIohStatusReadComplete and BkIohStatusIncompleteRead that data[1]
       * exists (ie we can reference data[1].ptr without fear of a core
       * dump). Since we're optimizing here, we thus don't bother checking
       * for data[0].ptr (which might otherwise seem required for "safe"
       * programming)
       */
      if (!data[1].ptr && IOH_DATA_SEIZE_PERMITTED(ioh))
      {
	/*
	 * This checks the most common case where the one buffer has been
	 * passed up. In this case we "seize" the data (which has been
	 * copied at the ioh level) and order the ioh level *not* to free
	 * it (data[0].ptr = NULL). This way we avoid the issue of
	 * coalescion entirely.
	 */
	if (!(BK_MALLOC(pid->pid_data)))
	{
	  bk_error_printf(B, BK_ERR_ERR, "Could not allocate vptr for I/O data: %s\n", strerror(errno));
	  goto error;
	}
	*pid->pid_data = data[0];
	data[0].ptr = NULL;
      }
      else
      {
	// If, OTOH, we 2 or more data bufs, then we coalesce them with copy.
	if (!(pid->pid_data  = bk_ioh_coalesce(B, data, NULL, BK_IOH_COALESCE_FLAG_MUST_COPY, NULL)))
	{
	  bk_error_printf(B, BK_ERR_ERR, "Could not coalesce relay data\n");
	  goto error;
	}
      }
    }

    bk_debug_printf_and(B, 2, "Dequeued %d bytes from descriptor %d\n", pid->pid_data[0].len, ioh->ioh_fdin);
    break;

  case BkIohStatusIohClosing:
    if (BK_FLAG_ISCLEAR(bpi->bpi_flags, BPI_FLAG_DONT_DESTROY))
    {
      // <BUG>There would appear to be a problem here since io_destroy does not notify user, so user will think he can use the bpi</BUG>
      bk_polling_io_destroy(B, bpi);
      if (pid) pid_destroy(B, pid);
      BK_VRETURN(B);
    }

#ifdef BK_USING_PTHREADS
    if (BK_GENERAL_FLAG_ISTHREADON(B) && pthread_mutex_lock(&bpi->bpi_lock) != 0)
      abort();
#endif /* BK_USING_PTHREADS */

    // The ioh is now dead.
    bk_debug_printf_and(B, 128,"Polling IOH is closing\n");

    BK_FLAG_SET(bpi->bpi_flags, BPI_FLAG_IOH_DEAD);

#ifdef BK_USING_PTHREADS
    if (BK_GENERAL_FLAG_ISTHREADON(B) && pthread_mutex_unlock(&bpi->bpi_lock) != 0)
      abort();
#endif /* BK_USING_PTHREADS */
    break;

  case BkIohStatusIohReadError:
#ifdef BK_USING_PTHREADS
    if (BK_GENERAL_FLAG_ISTHREADON(B) && pthread_mutex_lock(&bpi->bpi_lock) != 0)
      abort();
#endif /* BK_USING_PTHREADS */

    BK_FLAG_SET(bpi->bpi_flags, BPI_FLAG_READ_DEAD);

#ifdef BK_USING_PTHREADS
    if (BK_GENERAL_FLAG_ISTHREADON(B) && pthread_mutex_unlock(&bpi->bpi_lock) != 0)
      abort();
#endif /* BK_USING_PTHREADS */

    break;

  case BkIohStatusIohWriteError:
#ifdef BK_USING_PTHREADS
    if (BK_GENERAL_FLAG_ISTHREADON(B) && pthread_mutex_lock(&bpi->bpi_lock) != 0)
      abort();
#endif /* BK_USING_PTHREADS */

    bpi->bpi_wroutstanding--;
    BK_FLAG_SET(bpi->bpi_flags, BPI_FLAG_WRITE_DEAD);

    bk_error_printf(B, BK_ERR_ERR, "Polling write failed at IOH level\n");


#ifdef BK_USING_PTHREADS
    if (BK_GENERAL_FLAG_ISTHREADON(B) && pthread_mutex_unlock(&bpi->bpi_lock) != 0)
      abort();
#endif /* BK_USING_PTHREADS */

    break;

  case BkIohStatusIohReadEOF:
#ifdef BK_USING_PTHREADS
    if (BK_GENERAL_FLAG_ISTHREADON(B) && pthread_mutex_lock(&bpi->bpi_lock) != 0)
      abort();
#endif /* BK_USING_PTHREADS */

    BK_FLAG_SET(bpi->bpi_flags, BPI_FLAG_SAW_EOF);

#ifdef BK_USING_PTHREADS
    if (BK_GENERAL_FLAG_ISTHREADON(B) && pthread_mutex_unlock(&bpi->bpi_lock) != 0)
      abort();
#endif /* BK_USING_PTHREADS */

    break;

  case BkIohStatusWriteComplete:
  case BkIohStatusWriteAborted:
#ifdef BK_USING_PTHREADS
    if (BK_GENERAL_FLAG_ISTHREADON(B) && pthread_mutex_lock(&bpi->bpi_lock) != 0)
      abort();
#endif /* BK_USING_PTHREADS */
    bpi->bpi_wroutstanding--;
    bpi->bpi_wrbytes -= data->len;
    bk_debug_printf_and(B, 2, "Dequeued %d bytes for outstanding total of %d\n", data->len, bpi->bpi_wrbytes);
#ifdef BK_USING_PTHREADS
    bk_debug_printf_and(B, 64, "Broadcasting write timed condition wait\n");
    pthread_cond_broadcast(&bpi->bpi_wrcond);
    if (BK_GENERAL_FLAG_ISTHREADON(B) && pthread_mutex_unlock(&bpi->bpi_lock) != 0)
      abort();
#endif /* BK_USING_PTHREADS */
    free(data->ptr);
    free(data);
    pid_destroy(B, pid);
    data = NULL;
    BK_VRETURN(B);
    break;

  case BkIohStatusIohSeekSuccess:
    polling_io_flush(B, bpi, 0);
    // Intentional fall through.
  case BkIohStatusIohSeekFailed:
    clc_add = dll_insert;			// Put seek messages on front. Can't use #define
    break;

    // No default so gcc can catch missing cases.
  case BkIohStatusNoStatus:
    bk_error_printf(B, BK_ERR_ERR, "Uninitialized status\n");
    goto error;
  }

  pid->pid_status = status;

  if (pid->pid_data)
  {
#ifdef BK_USING_PTHREADS
    if (BK_GENERAL_FLAG_ISTHREADON(B) && pthread_mutex_lock(&bpi->bpi_lock) != 0)
      abort();
#endif /* BK_USING_PTHREADS */

    bpi->bpi_size += pid->pid_data->len;

    /*
     * Pause reading if buffer is full.  <TODO> if file open for only writing
     * mark the case so we don't bother.</TODO>
     */
    if (ioh->ioh_readq.biq_queuemax && bpi->bpi_size >= ioh->ioh_readq.biq_queuemax)
    {
      BK_FLAG_SET(bpi->bpi_flags, BPI_FLAG_SELF_THROTTLE);
      bk_polling_io_throttle(B, bpi, POLLIO_ALREADY_LOCKED);
    }

#ifdef BK_USING_PTHREADS
    if (BK_GENERAL_FLAG_ISTHREADON(B) && pthread_mutex_unlock(&bpi->bpi_lock) != 0)
      abort();
#endif /* BK_USING_PTHREADS */
   }

  if ((*clc_add)(bpi->bpi_data, pid) != DICT_OK)
  {
    bk_error_printf(B, BK_ERR_ERR, "Could not append data to data list: %s\n", pidlist_error_reason(bpi->bpi_data, NULL));
    goto error;
  }

#ifdef BK_USING_PTHREADS
    bk_debug_printf_and(B, 64, "Broadcasting read timed condition wait\n");
    pthread_cond_broadcast(&bpi->bpi_rdcond);
#endif /* BK_USING_PTHREADS */


  BK_VRETURN(B);

 error:
  if (pid) pid_destroy(B, pid);

  BK_VRETURN(B);
}
Exemple #2
0
void main(int argc, char **argv)
{
	char *stop;
	int	opts;
	char *debugstr;
	int	debuglvl;
	int	i;
	int	modemstate;
	int	modeminits;

	breaklist_init();

	progbasename = argv[0];

	if ((stop = rindex(argv[0], '/'))) progbasename = ++stop;

		/* Die Argumente des Programms einlesen und den Debuglevel	*/
		/* setzen.																	*/

	debugstr		= NULL;
	isdnttyname	= NULL;

	while ((opts = getopt_long(argc, argv, "vhx:d:", arguments, (int *)0)) != EOF)
	{
		switch (opts)
		{
			case 'x':
				debugstr = optarg;
				break;

			case 'd':
				isdnttyname = optarg;
				break;

			case 'v':
				show_usage(200, 0);
				break;

			case 'h':
			default:
				show_usage(200, 1);
				break;
		}
	}

	if (debugstr)
	{
		if (strcasecmp(debugstr, "FULL") != 0)
		{
			debuglvl = LOG_E;

			for (i = 0; i < strlen(debugstr); i++)
			{
				switch (debugstr[i])
				{
					case 'W':
					case 'w':
						debuglvl |= LOG_W;
						break;
					
					case 'I':
						debuglvl |= LOG_I;
						break;
					
					case 'A':
						debuglvl |= LOG_A;
						break;
					
					case 'D':
						debuglvl |= LOG_D;
						break;
				}
			}
		}
		else debuglvl = LOG_X;

		log_set_debuglevel(debuglvl);
	}

	umask(xstrtoo(VBOX_ROOT_UMASK, 0));

		/* Pfadangaben vom Devicenamen abschneiden und überprüfen ob	*/
		/* das Device vom Benutzer gelesen und beschrieben werden		*/
		/* kann (eigentlich nicht nötig, da nur unter Rootrechten ge-	*/
		/* startet werden kann.														*/

	if (isdnttyname)
	{
		if ((stop = rindex(isdnttyname, '/'))) isdnttyname = ++stop;

		printstring(savettydname, "%s"     , isdnttyname);
		printstring(temppathname, "/dev/%s", isdnttyname);
		
		if (access(temppathname, F_OK|R_OK|W_OK) != 0)
		{
			fprintf(stderr, "\n%s: error: \"%s\" doesn't exist or is not accessible!\n\n", progbasename, temppathname);

			quit_program(100);
		}
	}
	else
	{
		fprintf(stderr, "\n%s: error: isdn tty name is required!\n", progbasename);

		show_usage(100, 1);
	}

		/* Prüfen ob das Programm unter Rootrechten gestartet wurde. Die	*/
		/* Rechte werden später auf die des jeweiligen Benutzers geän-		*/
		/* dert, zum Start sind aber Rootrechte nötig.							*/

	if (getuid() != 0)
	{
		fprintf(stderr, "\n%s: error: need root privilegs to start!\n\n", progbasename);

		quit_program(100);
	}

		/* Jetzt wird der Log geöffnet. Der Name des aktuellen Devices	*/
		/* wird an das Ende angehängt.											*/

	printstring(temppathname, "%s/vboxgetty-%s.log", LOGDIR, isdnttyname);

	log_open(temppathname);

		/* Tcl-Interpreter starten. Für die momentanen Funktionen wird	*/
		/* Version 8 oder höher benötigt.										*/

	if (scr_create_interpreter() == -1)
	{
		log_line(LOG_E, "Can't create/initialize the tcl interpreter!\n");
		
		quit_program(100);
	}

	log_line(LOG_I, "Running vbox version %s (with tcl version %s).\n", VERSION, scr_tcl_version());

		/* Konfiguration des getty's abarbeiten. Zuerst wird die globale,	*/
		/* dann die des jeweiligen tty's eingelesen.								*/

	if (vboxgettyrc_parse(isdnttyname) == -1)
	{
		log_line(LOG_E, "Unable to read/parse configuration!\n");
	
		quit_program(100);
	}

		/* Modem Device öffnen und die interne Initialisierung	*/
		/* ausführen (nicht der normale Modeminit).					*/

	printstring(temppathname, "/dev/%s", isdnttyname);

	log_line(LOG_D, "Opening modem device \"%s\" (38400, CTS/RTS)...\n", temppathname);

	if (vboxmodem_open(&vboxmodem, temppathname) == -1)
	{
		log_line(LOG_E, "Can't open/setup modem device (%s).\n", vboxmodem_error());

		quit_program(100);
	}

		/* Lock- und PID-Datei für den getty und das entsprechende	*/
		/* Device erzeugen.														*/

	printstring(temppathname, "%s/LCK..%s", LOCKDIR, isdnttyname);
	
	if (lock_create(temppathname) == -1) quit_program(100);

	printstring(temppathname, "%s/vboxgetty-%s.pid", PIDDIR, isdnttyname);

	pid_create(temppathname);

		/* Signalhändler installieren. Alle möglichen Signale werden	*/
		/* auf quit_program() umgelenkt.											*/

	signal(SIGINT , quit_program);
	signal(SIGTERM, quit_program);
	signal(SIGHUP , quit_program);

		/* Hauptloop: Der Loop wird nur verlassen, wenn während der	*/
		/* Abarbeitung ein Fehler aufgetreten ist. Das Programm be-	*/
		/* endet sich danach!													*/
	
	modemstate = VBOXMODEM_STAT_INIT;
	modeminits = 0;
	
	while (modemstate != VBOXMODEM_STAT_EXIT)
	{
		switch (modemstate)
		{
			case VBOXMODEM_STAT_INIT:

				if (run_modem_init() == -1)
				{
					if ((i = (int)xstrtol(rc_get_entry(rc_getty_c, "badinitsexit"), 10)) > 0)
					{
						modeminits++;
						
						if (modeminits >= i)
						{
							modemstate = VBOXMODEM_STAT_EXIT;
							modeminits = 0;
							
							log_line(LOG_E, "Exit program while bad init limit are reached.\n");
						}
						else log_line(LOG_W, "Bad initialization - Program will exist on %d trys!\n", (i - modeminits));
					}
				}
				else
				{
					modemstate = VBOXMODEM_STAT_WAIT;
					modeminits = 0;
				}
				break;

			case VBOXMODEM_STAT_WAIT:
				
				modem_flush(&vboxmodem, 0);

				if (modem_wait(&vboxmodem) == 0)
				{
					modemstate = VBOXMODEM_STAT_RING;
					modeminits = 0;
				}
				else modemstate = VBOXMODEM_STAT_TEST;
				
				break;

			case VBOXMODEM_STAT_TEST:
			
				log_line(LOG_D, "Checking if modem is still alive...\n");
				
				if (modem_command(&vboxmodem, "AT", "OK") > 0)
				{
					modemstate = VBOXMODEM_STAT_WAIT;
					modeminits = 0;
				}
				else modemstate = VBOXMODEM_STAT_INIT;
				
				break;
				
			case VBOXMODEM_STAT_RING:
			
				modem_set_nocarrier(&vboxmodem, 0);
				process_incoming_call();
				modem_hangup(&vboxmodem);

				if (set_process_permissions(0, 0, xstrtoo(VBOX_ROOT_UMASK, 0)) != 0)
					modemstate = VBOXMODEM_STAT_EXIT;
				else
 					modemstate = VBOXMODEM_STAT_INIT;
				
				break;

			default:

				log_line(LOG_E, "Unknown modem status %d!\n", modemstate);
				
				modemstate = VBOXMODEM_STAT_INIT;
				
				break;
		}
	}

	quit_program(0);
}
Exemple #3
0
PRIVATE int daemonize(const char* pidfile) {
  int fd;

  if (getppid() == 1) {
    return -1;
  }

  switch (fork()) {
    case 0:
      break;
    case -1:
      fprintf(stderr, "Error daemonizing (fork)! %d - %s", errno, strerror(
          errno));
      return -1;
    default:
      _exit(0);
  }

  umask(0); /* change the file mode mask */

  if (setsid() < 0) {
    fprintf(stderr, "Error daemonizing (setsid)! %d - %s", errno, strerror(
        errno));
    return -1;
  }

  switch (fork()) {
    case 0:
      break;
    case -1:
      fprintf(stderr, "Error daemonizing (fork2)! %d - %s\n", errno, strerror(
          errno));
      return -1;
    default:
      _exit(0);
  }

  fd = open("/dev/null", O_RDONLY);
  if (fd != 0) {
    dup2(fd, 0);
    close(fd);
  }

  fd = open("/dev/null", O_WRONLY);
  if (fd != 1) {
    dup2(fd, 1);
    close(fd);
  }

  fd = open("/dev/null", O_WRONLY);
  if (fd != 2) {
    dup2(fd, 2);
    close(fd);
  }

  if (pidfile && *pidfile && getpid()) {
    pid_create(pidfile, getpid());
  }

  return 0;
}