This is port.c in view mode; [Download] [Up]
/* * 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" #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; /* * 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; register int i; int j, k, lfd, list[NUM_TTY], cmask, is_dev, progpid; static int set_getty(), checklock(), ck_speed(); char file[80], buf[80], message[80], *str_rep(), *last_c; void error_win(), line_set(), release_port(), send_str(); is_dev = chk_script(dir->script[dir->d_cur]); /* * If you already have a port, see if it is good enough for the * current request. */ #ifdef KEEP_PORT if (fd != -1) { if (!strcmp(dir->script[dir->d_cur], modem->tty[modem->t_cur]) || (!is_dev && ck_speed(modem->t_cur, dir->baud[dir->d_cur]))){ /* * Reset the line because the baud rate (or other * parameters) may have changed. */ line_set(); return(0); } } #endif /* KEEP_PORT */ release_port(VERBOSE); list[0] = -1; /* * See if you want a specific TTY port. If the script field in the * dialing directory is a valid device name, then use that TTY. */ if (is_dev) { for (i=0; i<modem->t_entries; i++) { /* and it exists in modem database */ if (!strcmp(dir->script[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 script field doesn't exist in", dir->script[dir->d_cur]); sprintf(buf, "modem/TTY database \"%s\"", modem->m_path); error_win(0, message, buf); return(1); } } /* * 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; /* 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) { 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); #ifdef ASCII_PID sprintf(buf, "%10d\n", getpid()); write(lfd, buf, 11); #else /* ASCII_PID */ progpid = getpid(); 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); 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 */ line_set(); /* ...just to be sure */ close(open(buf, O_RDWR)); /* turn off the O_NDELAY setting */ tty_noblock(fd, FALSE); /* initialize the modem */ send_str(modem->init[modem->m_cur], SLOW); return(0); } i++; } 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(); /* * 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; 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, n; unsigned int sleep(); char buf[40]; /* 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, 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 9600: if (*modem->con_96[mod] != '\0') return(1); break; case 19200: if (*modem->con_192[mod] != '\0') return(1); break; } return(0); } /* * Check to see if the script field is a valid device name. */ chk_script(script) char *script; { char buf[80], *strcpy(), *strcat(); if (*script == '\0') return(0); strcpy(buf, "/dev/"); strcat(buf, script); if (!access(buf, 0)) return(1); return(0); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.