/* * Changes for use with the CM11A are * Copyright 1996, 1997, 1998, 1999 by Daniel B. Suthers, * Pleasanton Ca. 94588 USA * E-MAIL dbs@tanj.com * * You may freely copy, use, and distribute this software, * in whole or in part, subject to the following restrictions: * * 1) You may not charge money for it. * 2) You may not remove or alter this copyright notice. * 3) You may not claim you wrote it. * 4) If you make improvements (or other changes), you are requested * to send them to me, so there's a focal point for distributing * improved versions. * */ /* * Copyright 1986 by Larry Campbell, 73 Concord Street, Maynard MA 01754 USA * (maynard!campbell). You may freely copy, use, and distribute this software * subject to the following restrictions: * * 1) You may not charge money for it. * 2) You may not remove or alter this copyright notice. * 3) You may not claim you wrote it. * 4) If you make improvements (or other changes), you are requested * to send them to me, so there's a focal point for distributing * improved versions. * * John Chmielewski (tesla!jlc until 9/1/86, then rogue!jlc) assisted * by doing the System V port and adding some nice features. Thanks! */ #ifdef SCO #define _IBCS2 #endif #include #include "x10.h" #include #include #include #include #include #include #include #include #include #include #ifdef SOLARIS #include #endif #ifdef __GLIBC__ /* msf - added for glibc/rh 5.0 */ #include #endif void exit(); void hangup(); char *make_lock_name(); unsigned long lockpid(char *); char x10_tty[50]; extern int verbose; extern void error(); static char dev_string[PATH_MAX]; int ttylock(); int lock_device(); int tty = -1; /* Real tty */ int sptty = -1; /* Spool */ #ifdef POSIX #ifndef SYSV #define SYSV /* POSIX implies SYSV */ #endif #endif #ifndef SYSV #include struct sgttyb oldsb, newsb; #else #ifndef NCC #define NCC NCCS #endif #ifndef POSIX #include struct termio oldsb, newsb; #else #include struct termios oldsb, newsb; #endif #endif int setup_tty(lockflag) int lockflag; { char RCSID[]= "@(#) $Id: tty.c,v 1.22 2003/03/30 20:25:36 dbs Exp dbs $\n"; int flags; display(RCSID); if (!x10_tty[0]) error("no TTY specified in configfile"); if( lockflag ) if( ttylock(x10_tty) < 0 ) { syslog(LOG_ERR, "Other proccess is using the real tty port."); error("Other process is using tty port."); } #ifdef DEBUG syslog(LOG_ERR, "Opening tty line."); #endif errno = 0 ; /* TESTCODE */ #ifdef O_NONBLOCK /* Open with non-blocking I/O, we'll fix after we set CLOCAL */ tty = open(x10_tty, O_RDWR|O_NONBLOCK); #else tty = open(x10_tty, O_RDWR); #endif if (tty < 0) { perror("Can't open tty line"); syslog(LOG_ERR, "Can't open tty line."); error("Can't open tty line. Check the permissions."); } #ifdef DEBUG else { syslog(LOG_ERR, "Tty line opened."); } #endif #ifndef SYSV /* Old-style BSD/v7 sgtty calls */ (void) ioctl(tty, TIOCFLUSH, (struct sgttyb *) NULL); (void) ioctl(tty, TIOCGETP, &oldsb); newsb = oldsb; newsb.sg_flags |= RAW; newsb.sg_flags &= ~(ECHO | EVENP | ODDP); hangup(); newsb.sg_ispeed = newsb.sg_ospeed = B4800; /* raise DTR & set speed */ (void) ioctl(tty, TIOCSETN, &newsb); #else #ifndef POSIX /* SVr2-style termio */ if (ioctl(tty, TCGETA, &oldsb) < 0) { syslog(LOG_ERR,"ioctl get"); exit(1); } newsb = oldsb; newsb.c_lflag = 0; newsb.c_oflag = 0; newsb.c_iflag = IGNBRK | IGNPAR; newsb.c_cflag = (CLOCAL | B4800 | CS8 | CREAD); newsb.c_cc[VMIN] = 1; newsb.c_cc[VTIME] = 0; newsb.c_cc[VINTR] = 0; newsb.c_cc[VQUIT] = 0; #ifdef VSWTCH newsb.c_cc[VSWTCH] = 0; #endif newsb.c_cc[VTIME] = 0; if (ioctl(tty, TCSETAF, &newsb) < 0) { syslog(LOG_ERR,"ioctl set"); exit(1); } #else { /* POSIX-style termios */ int s; s = tcgetattr(tty, &oldsb); if (s < 0) { char err_str[256]; sprintf(err_str, "ttopen tcgetattr: %s\n", strerror(s) ); syslog(LOG_ERR,"ttopen tcgetattr"); exit(1); } newsb = oldsb; /* newsb.c_iflag = BRKINT|(oldsb.c_iflag & (IXON|IXANY|IXOFF)); */ newsb.c_iflag = IGNPAR; newsb.c_oflag = 0; newsb.c_lflag = 0; newsb.c_cflag = (CLOCAL | CS8 | CREAD); for (s = 0; s < NCC; s++) newsb.c_cc[s] = 0; newsb.c_cc[VMIN] = 1; newsb.c_cc[VTIME] = 0; #ifdef BEFORE #ifdef VSWTCH newsb.c_cc[VSWTCH] = 0; #endif newsb.c_cc[VSUSP] = 0; newsb.c_cc[VSTART] = 0; newsb.c_cc[VSTOP] = 0; #endif /* POSIX sets speed seperately */ cfsetispeed(&newsb, B4800); cfsetospeed(&newsb, B4800); tcsetattr(tty, TCSADRAIN, &newsb); } #endif #endif #ifdef O_NONBLOCK /* Now that we have set CLOCAL on the port, we can use blocking I/O */ flags = fcntl(tty, F_GETFL); fcntl(tty, F_SETFL, flags & ~O_NONBLOCK); #endif return(0); } void restore_tty() { #ifndef SYSV hangup(); (void) ioctl(tty, TIOCSETN, &oldsb); #else #ifndef POSIX (void) ioctl(tty, TCSETAF, &oldsb); #else tcsetattr(tty, TCSADRAIN, &oldsb); #endif #endif } #ifndef SYSV void hangup() { newsb.sg_ispeed = newsb.sg_ospeed = B0; /* drop DTR */ (void) ioctl(tty, TIOCSETN, &newsb); sleep(SMALLPAUSE); } #endif void quit() { if (tty == -1) exit(1); restore_tty(); exit(1); } /* ttylock locks the tty device in a UUCP compatible style. * If the process is not valid, it's ok to remove the lock * The ttydev argument should be the device (tty2) or a fully qualified * path name (/dev/tty2). * It's OK to sleep a moment when we get see a valid lock, just in case it * will go away quickly * */ int ttylock(ttydev) char * ttydev; { char *devstr; int rtn; rtn = 1; devstr = make_lock_name(ttydev); if( verbose ) printf("Trying to lock (%s)\n", devstr); if( lockpid(devstr) == 0 ) rtn = lock_device(devstr); if( (verbose) && ( rtn == 0 ) ) printf("%s is locked\n", devstr); else if( rtn != 0 ) printf("Unable to lock %s\n", devstr); return(rtn); } /* munlock should be called when it's time to close the TTY. * The devstr param should be a fully qualified pathname for the lock file */ int munlock(devstr) char * devstr; { if( lockpid(devstr) == getpid() ) { return( unlink(devstr) ); } return(0); } /* This function writes the pid into the lock file. It uses the ASCII mode. * It will overwrite the existing file. */ int lock_device(ttydev) char * ttydev; { FILE *f; char err_string[128]; if( (f = fopen(ttydev, "w")) != NULL) { fprintf(f, " %d\n", (int)getpid() ); chmod(ttydev, 0777); } else { if ( verbose ) syslog(LOG_ERR,"Unable to create the lock file:"); syslog(LOG_DAEMON | LOG_ERR, "Unable to create the lock file.\n"); /* error quits the program */ sprintf(err_string, "Unable to create the lock file %s.\n", ttydev); error(err_string); } fclose(f); return(0); } /* set up the real and spool psuedo tty file descriptor. */ int setup_sp_tty() { extern char spoolfile[PATH_MAX]; setup_tty(0); if (tty < 0) { error("Can't open tty line"); syslog(LOG_DAEMON | LOG_ERR, "Can't open tty line\n"); } sptty = open(spoolfile, O_RDWR|O_APPEND,0x644);/* open the spool file */ if (sptty < 0) { char tmpbuf[sizeof(spoolfile) + 100]; perror("Can't open spool file"); sprintf(tmpbuf, "Can't open spool file %s", spoolfile); error(tmpbuf); strcat(tmpbuf, "\n"); syslog(LOG_DAEMON | LOG_ERR, tmpbuf); } lseek(sptty, 0, SEEK_END); /* seek to end of file */ return(0); } /* concatenate the lock directory path with the name to be locked. * Start with a device or other string. Example: /dev/tty2 * End result is a string such as "/usr/spool/uucp/LCK..tty2" */ char *make_lock_name(ttydev) char *ttydev; { char *devstr; int x; gid_t grps[30]; char *ptr; struct stat stat_buf; int ngrps; char err_string[200]; /* strip the leading path name */ ptr = rindex(ttydev, '/'); ngrps=30 ; devstr=dev_string; strncpy(dev_string, "", sizeof(dev_string)); if( ptr == (char *) NULL) { ptr = ttydev; } else ptr++; /* move past the slash */ /* Check to see that the Lock Directory is valid */ strcat(devstr, LOCKDIR); if (devstr[strlen(devstr) - 1] != '/') strcat(devstr, "/"); /* check that the lock directory exists */ if( (stat(devstr, &stat_buf) != 0 ) || ((stat_buf.st_mode & S_IFDIR) == 0) ) { sprintf(err_string, "The lock directory %s does not exist.\n", LOCKDIR); syslog(LOG_DAEMON | LOG_ERR, err_string); if(isatty(fileno(stderr))) { fprintf(stderr, err_string); } quit(); } /* check that we can write to the lock directory. Either u+w, g+w or writable by other and different group */ if(!((stat_buf.st_uid == geteuid()) && ((stat_buf.st_mode & S_IWUSR)!=0) ) ) { if( (stat_buf.st_mode & S_IWGRP) != 0) { ngrps = getgroups(30, grps); for(x=0; x < ngrps ; x++ ) { if( stat_buf.st_gid == grps[x] ) break; } } else x=30; /* magic number */ if( (x == 30 || x == ngrps ) && (stat_buf.st_mode & S_IWOTH) ) x--; if( x == 30 || x == ngrps) { sprintf(err_string, "The lock directory %s is not writable.\n", LOCKDIR); syslog(LOG_DAEMON | LOG_ERR, err_string); fprintf(stderr, err_string); quit(); } } strcat(devstr, "LCK.."); strcat(devstr, ptr); return(devstr); } /* lockpid returns 0 if the file is not locked or PID is invalid, * returns the PID if the file is locked * returns -1 on error * * The ttydev should be a full pathname for a lock file as returned by * make_lock_name() */ unsigned long lockpid(devstr) char *devstr; { FILE *input; char bufr[PATH_MAX]; struct stat lockstat; int infd; long pid_no; /* devstr = make_lock_name(devstr); */ if( stat(devstr, &lockstat) >= 0 ) { /* a lock file exists */ input = fopen(devstr, "r"); if( input == NULL ) { syslog(LOG_DAEMON | LOG_ERR, "Problem opening the lock file.\n"); fprintf(stderr, "Problem opening the lock file.\n"); quit(); } fgets(bufr,80,input); /* read the pid info from the file */ if( strncmp(" ", bufr, 4) == 0 ) { /* Oh! ascii info */ sscanf(bufr, " %ld", &pid_no); fclose(input); } else { /* Ahhh. Binary */ fclose(input); infd=open(devstr, O_RDONLY); if( infd < 0 ) { syslog(LOG_DAEMON | LOG_ERR, "Problem opening the lock file.\n"); fprintf(stderr, "Problem opening the lock file.\n"); quit(); } read(infd,&pid_no,4); close(infd); } /* does the process exist? */ errno = 0; getpriority(PRIO_PROCESS, pid_no); /* a harmless check for a pid */ if( errno == ESRCH) return(0); /* no pid exists */ else { /* locked by other process. Please try again. */ return(pid_no); } } else /* could not stat the file. Why? */ { if( errno == ENOENT ) /* Cool! no lock file. */ { return(0); } else { perror("Lock file not accessable:"); syslog(LOG_DAEMON | LOG_ERR, "Lock file not accessable.\n"); quit(); } } return(0); } int lock_for_write() { int max; extern char writelock[PATH_MAX]; max = 0; while( (lockpid(make_lock_name(writelock)) > 1) && (++max < 10) ) sleep(1); if( ttylock(writelock) < 0) { if(isatty(fileno(stderr))) { fprintf(stderr, "Could not set up the heyu.write lock %s\n", writelock); } syslog(LOG_ERR, "Could not set up the heyu.write lock-"); return(-1); } return(0); } int check_lock_for_write() { extern char writelock[PATH_MAX]; return(lockpid(make_lock_name(writelock))); }