home *** CD-ROM | disk | FTP | other *** search
- /*
- * Routines to get or release a TTY port.
- */
-
- #define MAX_PID 30000
- #define TRUE 1
- #define FALSE 0
-
- #include <stdio.h>
- #include <errno.h>
- #include "config.h"
- #include "dial_dir.h"
- #include "modem.h"
- #include "status.h"
-
- #ifdef BSD
- #include <sys/file.h>
- #else /* BSD */
- #include <fcntl.h>
- #endif /* BSD */
-
- #ifdef UNIXPC
- #include <sys/phone.h>
- #endif /* UNIXPC */
-
- #ifdef XENIX_LOCKS
- #include <ctype.h>
- #endif /* XENIX_LOCKS */
-
- #ifdef SVR4_LOCKS
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/mkdev.h>
- #endif /* SVR4_LOCKS */
-
- static int getty_status = 0;
- static char *lock_path = NULL;
- static int set_getty(), checklock(), ck_speed();
-
- /*
- * Finds a free (or requested) serial port. Creates a lock file to hold
- * for our use. Loads the modem database. A non-zero return code means
- * all ports (or the requested port) are busy.
- */
-
- int
- get_port()
- {
- extern int fd, errno;
- register int i;
- int j, k, lfd, list[NUM_TTY], cmask, aux, progpid, keep_it, trash_it;
- char file[80], buf[80], message[80], *str_rep();
- void error_win(), line_set(), release_port(), send_str(), ipc_update();
- #ifdef XENIX_LOCKS
- char *last_c;
- #endif /* XENIX_LOCKS */
-
- aux = chk_aux(dir->aux[dir->d_cur]);
- /*
- * If you already have a port, see if it is good enough for the
- * current request.
- */
- if (fd != -1) {
- keep_it = 0;
- trash_it = 0;
- /* got the requested TTY ? */
- if (aux == IS_TTY) {
- if (!strcmp(dir->aux[dir->d_cur], modem->tty[modem->t_cur]))
- keep_it++;
- else
- trash_it++;
- }
- /* got the requested Modem? */
- if (aux == IS_MODEM) {
- if (!strcmp(dir->aux[dir->d_cur], modem->tname[modem->t_cur]))
- keep_it++;
- else
- trash_it++;
- }
- /* can it handle the request baud? */
- if (ck_speed(modem->t_cur, dir->baud[dir->d_cur]))
- keep_it++;
-
- if (keep_it && !trash_it) {
- /*
- * Reset the line parameters, because baud rate,
- * etc. may have changed.
- */
- if (dir->d_cur != 0) {
- dir->baud[0] = dir->baud[dir->d_cur];
- dir->parity[0] = dir->parity[dir->d_cur];
- dir->data_bits[0] = dir->data_bits[dir->d_cur];
- dir->stop_bits[0] = dir->stop_bits[dir->d_cur];
- dir->duplex[0] = dir->duplex[dir->d_cur];
- dir->aux[0] = str_rep(dir->aux[0], dir->aux[dir->d_cur]);
- }
- line_set();
- return(0);
- }
- }
-
- /*
- * If we have a script running, we can't swap TTY ports, because
- * we've already forked the child process with "fd" as an open
- * file descriptor. Changing "fd" in the parent won't change the
- * "fd" in the child.
- */
- if (fd != -1 && status->dup_fd != -1) {
- error_win(0, "Can't change TTYs while a script is being played", "dial aborted");
- return(1);
- }
-
- release_port(VERBOSE);
-
- list[0] = -1;
- /*
- * See if you want a specific TTY port. If the auxiliary field in
- * the dialing directory is a valid device name, then use that TTY.
- */
- if (aux == IS_TTY) {
- for (i=0; i<modem->t_entries; i++) {
- /* and it exists in modem database */
- if (!strcmp(dir->aux[dir->d_cur], modem->tty[i])) {
- list[0] = i;
- list[1] = -1;
- break;
- }
- }
- /* oops... we don't know that port */
- if (list[0] == -1) {
- sprintf(message, "Device \"%s\" in the auxiliary field doesn't exist in", dir->aux[dir->d_cur]);
- sprintf(buf, "modem/TTY database \"%s\"", modem->m_path);
- error_win(0, message, buf);
- return(1);
- }
- }
-
- /*
- * If we haven't specified a port, create a list of acceptable TTYs.
- * It searches the modem database for the requested baud rate.
- */
- k = 0;
- if (list[0] == -1) {
- for (i=0; i<modem->t_entries; i++) {
- /* skip ports with no modems */
- if (!strcmp(modem->tname[i], "DIRECT"))
- continue;
-
- /* weed out the modems we don't want */
- if (aux == IS_MODEM) {
- if (strcmp(modem->tname[i], dir->aux[dir->d_cur]))
- continue;
- }
- /* can handle requested baud rate? */
- if (ck_speed(i, dir->baud[dir->d_cur]))
- list[k++] = i;
- }
- /* the end of list marker */
- list[k] = -1;
- }
- /* empty list? */
- if (list[0] == -1) {
- if (aux == IS_MODEM) {
- sprintf(message, "The requested modem \"%s\" does not exists", dir->aux[dir->d_cur]);
- sprintf(buf, "or does not support the requested baud rate %d", dir->baud[dir->d_cur]);
- }
- else {
- sprintf(message, "No modem at a %d baud rating exists in the", dir->baud[dir->d_cur]);
- sprintf(buf, "modem database \"%s\"", modem->m_path);
- }
- error_win(0, message, buf);
- return(1);
- }
- /* check the list for a free port */
- i = 0;
- while (list[i] != -1) {
- /* create a lock file name */
- #ifdef SVR4_LOCKS
- struct stat sbuf;
- sprintf(buf, "/dev/%s", modem->tty[list[i]]);
- stat(buf, &sbuf);
- sprintf(file, "%s/LK.%03d.%03d.%03d", LOCK_DIR, major(sbuf.st_dev), major(sbuf.st_rdev), minor(sbuf.st_rdev));
- #else /* SVR4_LOCKS */
- sprintf(file, "%s/LCK..%s", LOCK_DIR, modem->tty[list[i]]);
- #endif /* SVR4_LOCKS */
-
- #ifdef XENIX_LOCKS
- last_c = file + strlen(file)-1;
- if (isupper(*last_c))
- *last_c = tolower(*last_c);
- #endif /* XENIX_LOCKS */
-
- #ifdef DEBUG
- fprintf(stderr, "get_port: checking '/dev/%s'\n", modem->tty[list[i]]);
- #endif /* DEBUG */
-
- /* no lock exists or it is dead */
- if (checklock(file)) {
- getty_status = set_getty(modem->tty[list[i]], FALSE);
-
- cmask = umask(0);
- if ((lfd = open(file, O_CREAT|O_EXCL|O_WRONLY, 0666)) < 0) {
- if (getty_status)
- set_getty(modem->tty[list[i]], TRUE);
- sprintf(buf, "\"%s\"", file);
- error_win(0, "Can't create the lockfile", buf);
- return(1);
- }
- umask(cmask);
- progpid = getpid();
- #ifdef ASCII_PID
- sprintf(buf, "%10d\n", progpid);
- write(lfd, buf, 11);
- #else /* ASCII_PID */
- write(lfd, (char *) &progpid, sizeof(int));
- #endif /* ASCII_PID */
- close(lfd);
- /* store the new values */
- lock_path = str_rep(lock_path, file);
- modem->t_cur = list[i];
-
- /* load the modem data base */
- modem->m_cur = -1;
- for (j=0; j<modem->m_entries; j++) {
- if (!strcmp(modem->tname[modem->t_cur], modem->mname[j])) {
- modem->m_cur = j;
- break;
- }
- }
- if (modem->m_cur == -1) {
- sprintf(buf, "Modem name \"%s\" in TTY database",
- modem->tname[modem->t_cur]);
- error_win(0, buf, "does not exist in modem database");
- modem->t_cur = -1;
- return(1);
- }
-
- /* open the device (ignore DCD) */
- sprintf(buf, "/dev/%s", modem->tty[modem->t_cur]);
- if ((fd = open(buf, O_RDWR|O_NDELAY)) < 0) {
- if (getty_status)
- set_getty(modem->tty[modem->t_cur], TRUE);
- /*
- * For systems that use flock() instead of
- * UUCP lock files
- */
- if (errno == EBUSY) {
- unlink(lock_path);
- modem->m_cur = -1;
- modem->t_cur = -1;
- i++;
- continue;
- }
- sprintf(file, "Can't open port \"%s\" for read and write", buf);
- error_win(0, file, "");
- modem->m_cur = -1;
- modem->t_cur = -1;
- return(1);
- }
- /* change line settings */
- if (dir->d_cur != 0) {
- dir->baud[0] = dir->baud[dir->d_cur];
- dir->parity[0] = dir->parity[dir->d_cur];
- dir->data_bits[0] = dir->data_bits[dir->d_cur];
- dir->stop_bits[0] = dir->stop_bits[dir->d_cur];
- dir->duplex[0] = dir->duplex[dir->d_cur];
- dir->aux[0] = str_rep(dir->aux[0], dir->aux[dir->d_cur]);
- }
- line_set();
-
- /* turn off the O_NDELAY setting */
- tty_noblock(fd, FALSE);
-
- /*
- * For some reason, the following witchcraft is
- * often required.
- */
- #ifdef O_NDELAY_BROKE
- close(open(buf, O_RDWR));
- #endif /* O_NDELAY_BROKE */
-
- /* initialize the modem */
- send_str(modem->init[modem->m_cur], SLOW);
- /* update the poll()/select() values */
- ipc_update(fd, status->cmd_ipc);
- return(0);
- }
- i++;
- }
- if (aux == IS_TTY) {
- sprintf(buf, "The requested port \"%s\", is busy", modem->tty[modem->t_cur]);
- error_win(0, buf, "Try again later");
- }
- else
- error_win(0, "All ports are busy now, try again later", "");
- return(1);
- }
-
- /*
- * Release the port. Closes the file descriptor and removes the
- * lock file
- */
-
- void
- release_port(verbose)
- int verbose;
- {
- extern int fd;
- extern char *null_ptr;
- char buf[80];
- void free_ptr(), hang_up(), reset_line(), error_win(), ipc_update();
-
- /*
- * The modem structure can't be guaranteed to exist yet. For example,
- * an error in reading one of the other support files would cause
- * this routine to be used before the MODEM structure gets allocated.
- */
- if (modem == NULL)
- return;
- /* close the port */
- if (fd != -1) {
- tty_flush(fd, 2);
- /*
- * Since HUPCL is set, the close() should drop the DTR and
- * hang up the modem (provided you've got the modem to
- * respond to DTR). Since this is not guaranteed, we send
- * the hang_up string first.
- */
- hang_up(verbose);
- reset_line();
- close(fd);
- }
- /* remove the lock */
- if (lock_path != NULL && *lock_path != '\0') {
- if (unlink(lock_path)) {
- sprintf(buf, "\"%s\"", lock_path);
- error_win(0, "Can't remove the lock file", buf);
- }
- free_ptr(lock_path);
- lock_path = null_ptr;
- }
- /* turn the getty back on? */
- if (getty_status && modem->t_cur != -1)
- set_getty(modem->tty[modem->t_cur], TRUE);
- /* clean up the structure */
- fd = -1;
- modem->m_cur = -1;
- modem->t_cur = -1;
- ipc_update(fd, status->cmd_ipc);
- return;
- }
-
- /*
- * Turn the /etc/getty on or off for the specified port. A non-zero return
- * code means that the getty was on. Systems with uugetty() or dedicated
- * dialout ports won't need this routine.
- */
-
- /* ARGSUSED */
- static int
- set_getty(tty, on)
- char *tty;
- int on;
- {
- #ifdef UNIXPC
- int i, ret_code;
- char buf[40];
- unsigned int sleep();
- /* the last three characters */
- i = strlen(tty) -3;
-
- ret_code = 0;
- if (on) {
- sprintf(buf, "setgetty %s 1", tty+i);
- system(buf);
- }
- else {
- sprintf(buf, "setgetty %s 0", tty+i);
- if (system(buf) == 512)
- ret_code++;
- sleep(1);
- }
- return(ret_code);
- #else /* UNIXPC */
- /*
- * If you don't have one of these cute little routines, you
- * might wanna write one. It should check for an existing lock
- * file, edit the /etc/inittab file, and issue an init -q.
- * The return code should tell if there was a getty or not.
- * Obviously the program would be suid to root.
- */
- return(0);
- #endif /* UNIXPC */
- }
-
- /*
- * Check the lock file for a valid pid value. Error conditions such
- * as not being able to open the lock file or not being able to interpret
- * the contents of the lock file cause the code to assume that the lock
- * file is valid. Let the user worry about weird special cases. A
- * non-zero return code means the lock is dead or doesn't exist.
- */
-
- static int
- checklock(lockfile)
- char *lockfile;
- {
- extern int errno;
- int lfd, lckpid;
- unsigned int sleep();
- #ifdef ASCII_PID
- int n;
- char buf[40];
- #endif /* ASCII_PID */
- /* doesn't exist */
- if (access(lockfile, 0))
- return(1);
- /* can't open the lock file */
- if ((lfd = open(lockfile, 0)) < 0)
- return(0);
-
- #ifdef ASCII_PID
- if ((n = read(lfd, buf, 40)) <= 0) {
- close(lfd);
- return(0);
- }
- close(lfd);
- buf[n--] = '\0';
- lckpid = atoi(buf);
- #else /* ASCII_PID */
- if (read(lfd, (char *) &lckpid, sizeof(int)) != sizeof(int)) {
- close(lfd);
- return(0);
- }
- close(lfd);
- #endif /* ASCII_PID */
- /* invalid pid? */
- if (lckpid <= 0 || lckpid > MAX_PID)
- return(0);
-
- if ((kill(lckpid, 0) == -1) && (errno == ESRCH)) {
- /*
- * If the kill was unsuccessful due to an ESRCH error,
- * that means the process is no longer active and the
- * lock file can be safely removed.
- */
- unlink(lockfile);
- sleep(1);
- return(1);
- }
- /*
- * If the kill() was successful, that means the process must
- * still be active.
- */
- return(0);
- }
-
- /*
- * Check to see if the desired baud rate can be handled by the modem.
- * Uses the connect strings to make this determination. The first
- * argument is the index into the TTY database. A non-zero return code
- * means "yes it can".
- */
-
- static int
- ck_speed(tty, baud)
- int tty;
- unsigned int baud;
- {
- int i, mod;
- char buf[60];
- void error_win();
- /* find the modem database */
- mod = -1;
- for (i=0; i<modem->m_entries; i++) {
- if (!strcmp(modem->mname[i], modem->tname[tty])) {
- mod = i;
- break;
- }
- }
- if (mod == -1) {
- sprintf(buf, "Modem name \"%s\" in TTY database", modem->tname[tty]);
- error_win(1, buf, "does not exist in modem database");
- }
-
- #ifdef DEBUG
- fprintf(stderr, "ck_speed: checking modem \"%s\" for %d baud\n", modem->mname[mod], baud);
- #endif /* DEBUG */
-
- switch (baud) {
- case 300:
- if (*modem->con_3[mod] != '\0')
- return(1);
- break;
- case 1200:
- if (*modem->con_12[mod] != '\0')
- return(1);
- break;
- case 2400:
- if (*modem->con_24[mod] != '\0')
- return(1);
- break;
- case 4800:
- if (*modem->con_48[mod] != '\0')
- return(1);
- break;
- case 7200:
- case 9600:
- if (*modem->con_96[mod] != '\0')
- return(1);
- break;
- case 12000:
- case 14400:
- case 19200:
- if (*modem->con_192[mod] != '\0')
- return(1);
- break;
- case 38400:
- if (*modem->con_384[mod] != '\0')
- return(1);
- break;
- }
- return(0);
- }
-
- /*
- * Check to see if the auxiliary field contains a valid TTY or modem name.
- */
-
- chk_aux(aux)
- char *aux;
- {
- int i;
- char buf[80], *strcpy(), *strcat();
-
- if (*aux == '\0')
- return(0);
-
- strcpy(buf, "/dev/");
- strcat(buf, aux);
-
- if (!access(buf, 0))
- return(IS_TTY);
-
- for (i=0; i<modem->m_entries; i++) {
- if (!strcmp(modem->mname[i], aux))
- return(IS_MODEM);
- }
- /* Well, is not a TTY or modem */
- return(IS_SCRIPT);
- }
-