/* * battach.c * * Program to attach a tty device to babylon. Once attached, Babylon initiates * communications with the device for ppp, authentication, etc. battach sleeps * until a SIGHUP is recieved. * * Copyright (C) 1997-2000 SpellCaster Telecommunications Inc. * $Id: battach.c,v 1.2 2004/04/08 05:59:00 bcrl Exp $ * Released under the GNU Public License. See LICENSE file for details. */ #include #include #include #include #include #include #include #include "ldisc.h" #include #include #include #include #include #include #include "ttyd.h" #include "version.h" const char CONTROL_PATH[]="/tmp/.bab_control"; /* Options we support (see the man page) */ static char shrt_options[] = "fhvrsc:"; static struct option long_options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "dummy", no_argument, NULL, 'f' }, }; char *arg0; void print_usage() { fprintf(stderr, "Usage: %s [options]\n", arg0); fprintf(stderr, " -h, --help display this info\n"); fprintf(stderr, " -f, --dummy dummy argument useful for hylafax's faxgetty\n"); fprintf(stderr, " -v, --version display version info\n"); exit(1); } /* * Out signal handler */ void handler(int signal) { syslog(LOG_NOTICE,"Caught signal %d!",signal); } /* * Routine to force babylond to rescan the channel list. We do this to allow * the tty driver to work even if btty crashes, the driver is reload, whatever */ int babd_running() { int fd; struct sockaddr_un addr; if ((fd = socket(AF_UNIX, SOCK_STREAM, 0))==-1) { syslog(LOG_NOTICE,"Cannot create socket: %s",strerror(errno)); return(0); } addr.sun_family = AF_UNIX; strcpy(addr.sun_path, CONTROL_PATH); if (connect(fd, (struct sockaddr *)&addr, sizeof(addr.sun_family)+strlen(addr.sun_path))==-1) { syslog(LOG_NOTICE,"Cannot open %s (babylond running?): %s",CONTROL_PATH,strerror(errno)); return(0); } close(fd); return(1); } /* * Routine to check if bttyd is currently running * Returns 1 if yes and 0 if not. */ int check_bttyd() { char pid_str[12]; pid_t pid; int pid_fd,n; memset(pid_str, '\0', 12); /* Check for a stale lock */ if (!(pid_fd = open(PID_FILE, O_RDONLY, 0))) { return(0); } n = read(pid_fd, &pid_str, 11); close(pid_fd); if(n < 0) { return(0); } /* See if the process still exists */ sscanf(pid_str, " %d", &pid); if(pid == 0 || (kill(pid, 0) == -1 && errno == ESRCH)) { /* bttyd not running */ return(0); } else { /* bttyd running */ return(1); } } int main ( int argc, char *argv[] ) { int arg,ctrl_fd,portnum,retval; Req msg; int opt,opt_indx; arg0=argv[0]; /* get out command line options */ while((opt = getopt_long(argc, argv, shrt_options, long_options, &opt_indx)) != EOF) { switch(opt) { case 'v': printf("battach Version %s\n",version); exit(1); case 'f': break; default: print_usage(); } } /* Open syslog */ openlog("battach",LOG_PID|LOG_CONS,LOG_DAEMON); if (!babd_running()) { exit(1); } syslog(LOG_NOTICE,"battach is started"); /* Catch the HUP and TERM signals */ signal(SIGHUP,handler); signal(SIGTERM,handler); /* Check if bttyd is running */ if (!check_bttyd()) { syslog(LOG_NOTICE,"bttyd not running. battach aborted"); exit(2); } /* Open up our control file */ if ((ctrl_fd = open("/proc/bttyctrl", O_WRONLY)) < 0) { syslog(LOG_NOTICE,"Cannot open /proc/bttyctrl: %s",strerror(errno)); exit(2); } /* Get a port number to work with */ if ((portnum=ioctl(ctrl_fd,BIOCF_TTY_FIND_PORT,0))<0) { syslog(LOG_NOTICE,"Can't get port number to use (bttyd running?): %s",strerror(errno)); exit(2); } syslog(LOG_NOTICE,"Requested port from btty ,got back btty[%d]",portnum); /* Tell bttyd the pid we are using */ msg.pid=getpid(); msg.port=portnum; msg.phone_num[0]=(char)0; msg.cmd=REQ_INPORT; write(ctrl_fd,&msg,sizeof(Req)); /* Build our message so we are ready to quit */ msg.pid=0; arg=N_BAB; /* Set the line discipline to Babylon */ if (ioctl(STDIN_FILENO, TIOCSETD, &arg)<0) { syslog(LOG_NOTICE,"Can't set line discpline: %s",strerror(errno)); write(ctrl_fd,&msg,sizeof(Req)); close(ctrl_fd); exit(1); } /* Tell the tty driver to attach babylon to the serial port */ if (ioctl(STDIN_FILENO, BIOC_TTY_ATTACH, portnum) != 0) { syslog(LOG_NOTICE,"Attach to Babylon failed: %s",strerror(errno)); /* Force the line discipline back to normal */ arg=0; ioctl(STDIN_FILENO, TIOCSETD, &arg); /* Tell bttyd that we cleared the line in case a user drops the link */ write(ctrl_fd,&msg,sizeof(Req)); close(ctrl_fd); exit(1); } syslog(LOG_NOTICE,"Connected on port btty%d",portnum); /* Wait around until we get a signal to quit */ pause(); /* Shutdown port gracefully so we can reuse it later */ if ((retval=ioctl(ctrl_fd,BIOCF_TTY_REUSE_PORT, portnum))<0) { syslog(LOG_NOTICE, "Can't shutdown port %d gracefully : %s", portnum, strerror(errno)); exit(2); } else syslog(LOG_NOTICE,"Recycle of port [%d] successful",portnum); /* Report we're done and exit normally */ syslog(LOG_NOTICE,"Disconnected on port btty%d",portnum); /* Set the line discipline to normal */ arg=0; if (ioctl(STDIN_FILENO, TIOCSETD, &arg)<0) { syslog(LOG_NOTICE,"Failed to reset line discipline on btty%d: %s",portnum,strerror(errno)); } /* Tell bttyd that we cleared the line in case a user drops the link */ write(ctrl_fd,&msg,sizeof(Req)); close(ctrl_fd); closelog(); exit(0); }