⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 port.c

📁 通讯程序源码
💻 C
字号:
/* * 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. */intget_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 */voidrelease_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 intset_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 intchecklock(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 intck_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);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -