/** * 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); }
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); }
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; }