/* * Copyright (c) 2001 Tommy Bohlin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* options.c */ #include #include #include #include #include #include #include #include /********************************************************************** * Constants **********************************************************************/ #define DONGLE_NONE 0 #define DONGLE_TEKRAM 1 #define DONGLE_JETEYE 2 #define DONGLE_ACTISYS 3 #define DONGLE_ACTISYS_PLUS 4 #define DONGLE_LITELINK 5 #define DONGLE_GIRBIL 6 #define DONGLE_REDLINK 7 static const char* defaultPorts[] = { "/dev/tty02", "/dev/tty00", "/dev/ttyS0", 0 }; #define VERBOSITY_INFO 1 #define VERBOSITY_IAS 2 #define VERBOSITY_FRAMES_IN 3 #define VERBOSITY_FRAMES_OUT 4 #define VERBOSITY_TIMERS 5 #define VERBOSITY_LOW_LEVEL_IO 6 #define VERBOSITY_EVENT_SELECT 7 #define VERBOSITY_EVENT_TIMERS 8 /********************************************************************** * State **********************************************************************/ LAP* optLap; IASServer* optIas; void (*optLapConnected)(LAP* lap); void (*optLapDisconnected)(LAP* lap); static int verbosity; static int tries; static int address; /********************************************************************** * Pty handling **********************************************************************/ static int openPty(const char* pty) { if(freopen(pty,"r+",stdin)) { close(fileno(stdout)); dup(fileno(stdin)); setbuf(stdin,0); setbuf(stdout,0); return 1; } return 0; } #ifdef i386 /* PCVT conflicts with ttyv*. */ #define TTY_LETTERS "pqrstuwxyzPQRST" #else #define TTY_LETTERS "pqrstuvwxyzPQRST" #endif /*i386*/ static int getPty(void) { static char dev[]="/dev/ptyXX"; char* c1; char* c2; for(c1=TTY_LETTERS;*c1;c1++) { dev[8]=*c1; for(c2="0123456789abcdef";*c2;c2++) { dev[9]=*c2; if(freopen(dev,"r+",stdin)) { char tty[11]; strcpy(tty,dev); tty[5]='t'; printf("%s\n",tty); fflush(stdout); close(fileno(stdout)); dup(fileno(stdin)); setbuf(stdin,0); setbuf(stdout,0); return 1; } if(errno==ENOENT) return 0; } } return 0; } /********************************************************************** * Forking **********************************************************************/ static void forkDaemon(void) { switch (fork()) { case -1: birda_log("Fork failed\n"); exit(-4); case 0: break; default: _exit(0); } if(setsid()==-1) { birda_log("setsid failed\n"); exit(-5); } chdir("/"); } /********************************************************************** * Pid file **********************************************************************/ static char pidFile[256]; void removePidFile(void) { unlink(pidFile); } static void terminateHandler(int sig) { removePidFile(); exit(0); } static void writePidFile(const char* prog) { FILE* f; struct sigaction sa; const char* p; p=strrchr(prog,'/'); if(p) p++; else p=prog; sprintf(pidFile,"/var/run/%s.pid",p); sa.sa_flags=0; sa.sa_handler=terminateHandler; sigemptyset(&sa.sa_mask); sigaction(SIGINT,&sa,0); sigaction(SIGTERM,&sa,0); atexit(removePidFile); f=fopen(pidFile,"w"); if(f) { fprintf(f,"%d\n",getpid()); fclose(f); } } /********************************************************************** * LAP control **********************************************************************/ static void addHint(char** h, const char* hintbuf, char* name) { char* p=*h; if(p!=hintbuf) { *p++=','; *p++=' '; } strcpy(p,name); p+=strlen(p); *h=p; } static void showDiscovered(int addr, int hints, int charset, const char* name, int len) { int i; char namebuf[32]; char hintbuf[128]; char* p=hintbuf; if(charset==CHARSET_UNICODE) { /* Strip the high byte */ for(i=0;2*i=VERBOSITY_INFO) birda_log("participating in discovery\n"); return TRUE; case LAP_CONNECTING: if(verbosity>=VERBOSITY_INFO) birda_log("accepting connection\n"); return TRUE; case LAP_DISCOVERED: if(verbosity>=VERBOSITY_INFO) showDiscovered(addr,hints,charset,name,len); if(!address) address=addr; break; case LAP_DISCOVERY_END: if(verbosity>=VERBOSITY_INFO) birda_log("query completed\n"); if(address) { if(!lapConnect(lap,address)) { if(optLapDisconnected) optLapDisconnected(lap); } } else if(++tries<10) { lapDiscover(lap); } else { birda_log("No peer station found\n"); if(optLapDisconnected) optLapDisconnected(lap); } break; case LAP_CONNECTED: if(optLapConnected) optLapConnected(lap); break; case LAP_DISCONNECTED: if(optLapDisconnected) optLapDisconnected(lap); break; } return FALSE; } /********************************************************************** * Options processing **********************************************************************/ static void dumpHandler(int sig) { showResources(); } void doOptions(int argc, char* const argv[], int optc, Option* options, int* verbosityp, const char* desc) { int c,i; char optbuf[256]; char* p; int error=0; int usage=0; char* port=0; char* pty=0; char* logFile=0; int daemon=0; int dongle=DONGLE_NONE; #ifdef IRDA_KERNEL_DRIVER int kdevice=1; #else int kdevice=0; #endif int maxspeed=0; struct sigaction sa; char* thisHost=0; char thisHostBuf[128]; SerialPort* serPort; SerialDevice* serDev; FrameDevice* frameDev; /* Standard options */ strcpy(optbuf,"d:hkKl:tjaARpgv:y:Ym:n:"); /* User options */ p=optbuf+strlen(optbuf); for(i=0;iopt; if(o->type!=OPTION_BOOL) *p++=':'; } *p=0; while((c=getopt(argc,argv,optbuf))!=-1) { switch(c) { case 'd': port=optarg; break; case 'h': usage=1; break; case 'K': kdevice=0; break; case 'k': kdevice=1; break; case 'l': logFile=optarg; break; case 't': dongle=DONGLE_TEKRAM; break; case 'j': dongle=DONGLE_JETEYE; break; case 'a': dongle=DONGLE_ACTISYS; break; case 'A': dongle=DONGLE_ACTISYS_PLUS; break; case 'p': dongle=DONGLE_LITELINK; break; case 'g': dongle=DONGLE_GIRBIL; break; case 'R': dongle=DONGLE_REDLINK; break; case 'v': if(sscanf(optarg,"%d",&verbosity)!=1) error=1; break; case 'y': pty=optarg; break; case 'Y': daemon=1; break; case 'm': if(sscanf(optarg,"%d",&maxspeed)!=1) error=1; break; case 'n': thisHost=optarg; break; case '?': error=1; break; default: for(i=0;iopt==c) { switch(o->type) { case OPTION_STRING: o->val.s=optarg; break; case OPTION_INT: sscanf(optarg,"%d",&o->val.i); break; default: /*OPTION_BOOL*/ o->val.b=TRUE; break; } } } break; } } if(usage) { const char** dp; int first; if(desc) fprintf(stderr,"%s\n",desc); fprintf(stderr,"Usage: %s {options}\n",argv[0]); fprintf(stderr," -d dev Device to use\n"); fprintf(stderr," -m speed Limit maximum baud rate\n"); fprintf(stderr," -n name Station name (defaults to host name)\n"); fprintf(stderr," -l file Log to file\n"); fprintf(stderr," -y pty Redirect stdin/stdout\n"); fprintf(stderr," -v level Verbosity\n"); fprintf(stderr," -Y Fork and run as daemon\n"); fprintf(stderr," -t Tekram IR-210B dongle\n"); fprintf(stderr," -j Extended Systems JetEye dongle\n"); fprintf(stderr," -a ACTiSYS IR-220L dongle\n"); fprintf(stderr," -A ACTiSYS IR-220L+ dongle\n"); fprintf(stderr," -p Parallax LiteLink dongle\n"); fprintf(stderr," -g Greenwich GIrBIL dongle\n"); fprintf(stderr," -R Redlink 105 dongle (ACTiSYS IR-200L)\n"); #ifdef IRDA_KERNEL_DRIVER fprintf(stderr," -K Don't use kernel frame device\n"); #endif /* IRDA_KERNEL_DRIVER */ fprintf(stderr," -h Help\n"); for(i=0;itype!=OPTION_BOOL) arg=o->arg ? o->arg : "x"; if(o->desc) desc=o->desc; fprintf(stderr," -%c %-6s %s\n",o->opt,arg,desc); } fprintf(stderr,"Serial port defaults: "); for(first=1,dp=defaultPorts;*dp;dp++) { fprintf(stderr,"%s%s",first ? "" : ", ", *dp); first=0; } fprintf(stderr,"\n"); exit(0); } if(error || optind=VERBOSITY_EVENT_TIMERS) evtDebug|=EVT_DEBUG_TIMERS; if(verbosity>=VERBOSITY_EVENT_SELECT) evtDebug|=EVT_DEBUG_SELECT; if (!kdevice) { if(port) { if(!(serPort=createSerialPort(port,maxspeed))) { birda_log("Bad serial port\n"); exit(-7); } } else { const char** dp; for(dp=defaultPorts;*dp;dp++) if((serPort=createSerialPort(*dp,maxspeed))) break; if(!*dp) { birda_log("Cannot default the port!\n"); exit(-8); } if(verbosity>=VERBOSITY_INFO) birda_log("Using %s\n",*dp); } if(verbosity>=VERBOSITY_LOW_LEVEL_IO) serPort->debug|=SP_DEBUG_INPUT; } #ifdef IRDA_KERNEL_DRIVER if (kdevice) { frameDev = createKernelFrameDevice(port,maxspeed); } else #endif /* IRDA_KERNEL_DRIVER */ { switch(dongle) { case DONGLE_TEKRAM: serDev=createTekram210Device(serPort); break; case DONGLE_JETEYE: serDev=createJetEyeDevice(serPort); break; case DONGLE_ACTISYS: serDev=createACTiSYS220Device(serPort,FALSE); break; case DONGLE_ACTISYS_PLUS: serDev=createACTiSYS220Device(serPort,TRUE); break; case DONGLE_LITELINK: serDev=createLiteLinkDevice(serPort); break; case DONGLE_GIRBIL: serDev=createGIrBILDevice(serPort); break; case DONGLE_REDLINK: serDev=createRedlinkDevice(serPort); break; default: serDev=createRawDevice(serPort); break; } frameDev=createSIRFrameDevice(serDev); } if(verbosity>=VERBOSITY_LOW_LEVEL_IO) frameDev->debug|=FRAME_DEBUG_INPUT; if(!thisHost) { thisHost=thisHostBuf; gethostname(thisHostBuf,sizeof thisHostBuf); thisHostBuf[sizeof thisHostBuf-1]=0; } optLap=createLAP(frameDev,CHARSET_ASCII,thisHost,strlen(thisHost)); optLap->flags|=HINT_COMPUTER; optLap->status=lapStatus; if(verbosity>=VERBOSITY_TIMERS) optLap->debug|=LAP_DEBUG_TIMERS; if(verbosity>=VERBOSITY_FRAMES_OUT) optLap->debug|=LAP_DEBUG_FRAMES_OUT; if(verbosity>=VERBOSITY_FRAMES_IN) optLap->debug|=LAP_DEBUG_FRAMES_IN; if(verbosity>=VERBOSITY_INFO) optLap->debug|=LAP_DEBUG_INFO; optIas=createIASServer(optLap,CHARSET_ASCII,thisHost,strlen(thisHost)); if(verbosity>1) optIas->debug|=IAS_DEBUG_INFO; if(verbosityp) *verbosityp=verbosity; } void doConnect(void) { address=0; lapDiscover(optLap); }