/* Copyright (c) Lawrence Foard, 1992 This software may be used and distributed under the terms of the gnu public license. M. Andreoli: added support for 57600 and 115200 baud */ /* Version 0.1 */ #include #include #include #include struct alist { int num; char *str; }; /* baud rates */ struct alist bauds[]= { {B0,"0"}, {B50,"50"}, {B75,"75"}, {B110,"110"}, {B134,"134"}, {B150,"150"}, {B200,"200"}, {B300,"300"}, {B600,"600"}, {B1200,"1200"}, {B1800,"1800"}, {B2400,"2400"}, {B4800,"4800"}, {B9600,"9600"}, {B19200,"19200"}, {B38400,"38400"}, {B57600,"57600"}, {B115200,"115200"}, {0,NULL} }; /* character size */ struct alist bits[]= { {CS5,"CS5"}, {CS6,"CS6"}, {CS7,"CS7"}, {CS8,"CS8"}, {0,NULL} }; /* lists of flag bits */ /* input flags */ struct alist iflags[]= { {IGNBRK,"IGNBRK"}, {BRKINT,"BRKINT"}, {IGNPAR,"IGNPAR"}, {PARMRK,"PARMRK"}, {INPCK,"INPCK"}, {ISTRIP,"ISTRIP"}, {INLCR,"INLCR"}, {IGNCR,"IGNCR"}, {ICRNL,"ICRNL"}, {IUCLC,"IUCLC"}, {IXON,"IXON"}, {IXANY,"IXANY"}, {IXOFF,"IXOFF"}, {IMAXBEL,"IMAXBEL"}, {0,NULL} }; struct alist oflags[]= { {OPOST,"OPOST"}, {OLCUC,"OLCUC"}, {ONLCR,"ONLCR"}, {ONOCR,"ONOCR"}, {ONLRET,"ONLRET"}, {OFILL,"OFILL"}, {OFDEL,"OFDEL"}, {0,NULL} }; /* delay modes */ struct alist nldly[]= { {NL0,"NL0"}, {NL1,"NL1"}, {0,NULL} }; struct alist crdly[]= { {CR0,"CR0"}, {CR1,"CR1"}, {CR2,"CR2"}, {CR3,"CR3"}, {0,NULL} }; struct alist tabdly[]= { {TAB0,"TAB0"}, {TAB1,"TAB1"}, {TAB2,"TAB2"}, {TAB3,"TAB3"}, {0,NULL} }; struct alist bsdly[]= { {BS0,"BS0"}, {BS1,"BS1"}, {0,NULL} }; struct alist vtdly[]= { {VT0,"VT0"}, {VT1,"VT1"}, {0,NULL} }; struct alist ffdly[]= { {FF0,"FF0"}, {FF1,"FF1"}, {0,NULL} }; /* composite of all delay modes */ struct alist *delaymodes[]= { nldly, crdly, tabdly, bsdly, vtdly, ffdly, NULL }; /* the mask for each mode */ int delaymasks[]= { NLDLY, CRDLY, TABDLY, BSDLY, VTDLY, FFDLY, 0 }; struct alist cflags[]= { {CSTOPB,"CSTOPB"}, {CREAD,"CREAD"}, {PARENB,"PARENB"}, {PARODD,"PARODD"}, {HUPCL,"HUPCL"}, {CLOCAL,"CLOCAL"}, {CIBAUD,"CIBAUD"}, {CRTSCTS,"CRTSCTS"}, {0,NULL} }; struct alist lflags[]= { {ISIG,"ISIG"}, {ICANON,"ICANON"}, {XCASE,"XCASE"}, {ECHO,"ECHO"}, {ECHOE,"ECHOE"}, {ECHOK,"ECHOK"}, {ECHONL,"ECHONL"}, {NOFLSH,"NOFLSH"}, {TOSTOP,"TOSTOP"}, {ECHOCTL,"ECHOCTL"}, {ECHOPRT,"ECHOPRT"}, {ECHOKE,"ECHOKE"}, {FLUSHO,"FLUSHO"}, {PENDIN,"PENDIN"}, {IEXTEN,"IEXTEN"}, {0,NULL} }; /* special characters */ struct alist special[]= { {VINTR,"INTR"}, {VQUIT,"QUIT"}, {VERASE,"ERASE"}, {VKILL,"KILL"}, {VEOF,"EOF"}, {VTIME,"TIME"}, {VMIN,"MIN"}, {VSWTC,"SWTC"}, {VSTART,"START"}, {VSTOP,"STOP"}, {VSUSP,"SUSP"}, {VEOL,"EOL"}, {VREPRINT,"REPRINT"}, {VDISCARD,"DISCARD"}, {VWERASE,"WERASE"}, {VLNEXT,"LNEXT"}, {VEOL2,"EOL2"}, {0,NULL} }; /* look up a number in a list and return the string */ char *numtostr(struct alist *list,int num) { int a; for(a=0;list[a].str;a++) if (list[a].num==num) return(list[a].str); return("UNKNOWN"); } /* look up a string in a list and return the number */ int strtonum(struct alist *list,char *str) { int a; char buff[100],*s; strcpy(buff,str); for(s=buff;*s;s++) if ((*s>='a') && (*s<='z')) *s=*s-'a'+'A'; for(a=0;list[a].str;a++) if (!strcmp(buff,list[a].str)) return(list[a].num); return(-1); } char *print_ctrl(char c) { static char buff[10]; if (c<32) sprintf(buff," '^%c' ",c+'@'); else if (c==127) sprintf(buff," '^?' "); else sprintf(buff," '%c' ",c); return(buff); } char strtoctrl(char *s) { if (!s[0]) return(0); if (!s[1]) return(s[0]); if (s[0]=='^') { if ((s[1]>'a') && (s[1]<'z')) s[1]=s[1]-'a'+'A'; return((s[1]=='?') ? 127 : s[1]-'@'); } fprintf(stderr,"stty: invalid character %s\n",s); exit(1); } #define TFI(f) ((f & term->c_iflag) ? ' ' : '-') #define TFO(f) ((f & term->c_oflag) ? ' ' : '-') #define TFC(f) ((f & term->c_cflag) ? ' ' : '-') #define TFL(f) ((f & term->c_lflag) ? ' ' : '-') print_settings(struct termios *term,struct winsize *win) { fprintf(stderr,"---------Characters----------\n"); fprintf(stderr,"INTR: %s ",print_ctrl(term->c_cc[VINTR])); fprintf(stderr,"QUIT: %s ",print_ctrl(term->c_cc[VQUIT])); fprintf(stderr,"ERASE: %s ",print_ctrl(term->c_cc[VERASE])); fprintf(stderr,"KILL: %s ",print_ctrl(term->c_cc[VKILL])); fprintf(stderr,"EOF: %s\n",print_ctrl(term->c_cc[VEOF])); fprintf(stderr,"TIME: %3d ",term->c_cc[VTIME]); fprintf(stderr,"MIN: %3d ",term->c_cc[VMIN]); fprintf(stderr,"SWTC: %s ",print_ctrl(term->c_cc[VSWTC])); fprintf(stderr,"START: %s ",print_ctrl(term->c_cc[VSTART])); fprintf(stderr,"STOP: %s\n",print_ctrl(term->c_cc[VSTOP])); fprintf(stderr,"SUSP: %s ",print_ctrl(term->c_cc[VSUSP])); fprintf(stderr,"EOL: %s ",print_ctrl(term->c_cc[VEOL])); fprintf(stderr,"EOL2: %s ",print_ctrl(term->c_cc[VEOL2])); fprintf(stderr,"LNEXT: %s\n",print_ctrl(term->c_cc[VLNEXT])); fprintf(stderr,"DISCARD: %s ",print_ctrl(term->c_cc[VDISCARD])); fprintf(stderr,"REPRINT: %s ",print_ctrl(term->c_cc[VREPRINT])); fprintf(stderr,"RWERASE: %s\n",print_ctrl(term->c_cc[VWERASE])); fprintf(stderr,"----------Control Flags---------\n"); fprintf(stderr, "%cCSTOPB %cCREAD %cPARENB %cPARODD %cHUPCL %cCLOCAL %cCRTSCTS\n", TFC(CSTOPB),TFC(CREAD),TFC(PARENB),TFC(PARODD),TFC(HUPCL),TFC(CLOCAL), TFC(CRTSCTS)); fprintf(stderr,"Baud rate: %s Bits: %s\n", numtostr(bauds,term->c_cflag & CBAUD),numtostr(bits,term->c_cflag & CSIZE)); fprintf(stderr,"----------Input Flags----------\n"); fprintf(stderr, "%cIGNBRK %cBRKINT %cIGNPAR %cPARMRK %cINPCK %cISTRIP %cINLCR %cIGNCR\n", TFI(IGNBRK),TFI(BRKINT),TFI(IGNPAR),TFI(PARMRK),TFI(INPCK),TFI(ISTRIP), TFI(INLCR),TFI(IGNCR)); fprintf(stderr, "%cICRNL %cIUCLC %cIXON %cIXANY %cIXOFF %cIMAXBEL\n", TFI(ICRNL),TFI(IUCLC),TFI(IXON),TFI(IXANY),TFI(IXOFF),TFI(IMAXBEL)); fprintf(stderr,"---------Output Flags---------\n"); fprintf(stderr, "%cOPOST %cOLCUC %cONLCR %cOCRNL %cONOCR %cONLRET %cOFILL %cOFDEL\n", TFO(OPOST),TFO(OLCUC),TFO(ONLCR),TFO(OCRNL),TFO(ONOCR),TFO(ONLRET), TFO(OFILL),TFO(OFDEL)); fprintf(stderr,"Delay modes: CR%d NL%d TAB%d BS%d FF%d VT%d\n", (term->c_oflag & CRDLY)/CR1, (term->c_oflag & NLDLY)/NL1, (term->c_oflag & TABDLY)/TAB1, (term->c_oflag & BSDLY)/BS1, (term->c_oflag & FFDLY)/FF1, (term->c_oflag & VTDLY)/VT1); fprintf(stderr,"-----------Local Flags---------\n"); fprintf(stderr, "%cISIG %cICANON %cXCASE %cECHO %cECHOE %cECHOK %cECHONL %cNOFLSH\n", TFL(ISIG),TFL(ICANON),TFL(XCASE),TFL(ECHO),TFL(ECHOE),TFL(ECHOK), TFL(ECHONL),TFL(NOFLSH)); fprintf(stderr, "%cTOSTOP %cECHOCTL %cECHOPRT %cECHOKE %cFLUSHO %cPENDIN %cIEXTEN\n", TFL(TOSTOP),TFL(ECHOCTL),TFL(ECHOPRT),TFL(ECHOKE),TFL(FLUSHO),TFL(PENDIN), TFL(IEXTEN)); fprintf(stderr,"rows %d cols %d\n",win->ws_row,win->ws_col); } /* This really needs a man page */ void usage() { fprintf(stderr,"Copyright (c), Lawrence Foard, 1992\n"); fprintf(stderr,"May be used under the terms of the gnu public license\n"); fprintf(stderr,"Version 0.1\n"); exit(1); } /* macro to set or clear bit(s) depending on setclr's value */ #define SETIT(flags,bit) \ if (setclr) \ flags&=~(bit);\ else\ flags|=bit; /* parse one option effect passed structure with it */ int parse_opts(char *options[],struct termios *term,struct winsize *winsize) { int a,b,c,d,setclr=0; char *option; for(a=0;options[a];a++) { option=options[a]; /* special cases */ if (!strcmp(option,"rows")) { winsize->ws_row=atoi(options[++a]); continue; } if (!strcmp(option,"cols")) { winsize->ws_col=atoi(options[++a]); continue; } if (!strcmp(option,"sane")) { int c; term->c_cflag=(term->c_cflag & ~CBAUD) | (term->c_cflag & CSIZE) | HUPCL; term->c_iflag=ICRNL | IXON; term->c_oflag=OPOST | ONLCR | ((NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) & term->c_oflag); term->c_lflag=ISIG | ICANON | ECHO | ECHOCTL | ECHOKE; term->c_cc[VINTR]='C'-'@'; term->c_cc[VQUIT]='\\'-'@'; term->c_cc[VERASE]=127; term->c_cc[VEOF]='D'-'@'; term->c_cc[VKILL]='U'-'@'; term->c_cc[VSTART]='Q'-'@'; term->c_cc[VSTOP]='S'-'@'; term->c_cc[VSUSP]='Z'-'@'; term->c_cc[VLNEXT]='V'-'@'; term->c_cc[VDISCARD]='O'-'@'; term->c_cc[VREPRINT]='R'-'@'; term->c_cc[VWERASE]='W'-'@'; continue; } /* is it a baud rate? */ if (-1!=(b=strtonum(bauds,option))) { term->c_cflag=(term->c_cflag & ~CBAUD) | b; continue; } /* is it a character size? */ if (-1!=(b=strtonum(bits,option))) { term->c_cflag=(term->c_cflag & ~CSIZE) | b; continue; } /* is it one of the special characters? */ if (-1!=(b=strtonum(special,option))) { if (!options[a+1]) { fprintf(stderr,"stty: %s must be followed by a character.\n",option); usage(); exit(1); } term->c_cc[b]=strtoctrl(options[++a]); continue; } /* scan delay mode lists */ for(c=d=0;delaymodes[c];c++) if (-1!=(b=strtonum(delaymodes[c],option))) { term->c_oflag=(term->c_oflag & ~delaymasks[c]) | b; d=1; } if (d) continue; /* bit options */ if (*option=='-') { setclr=1; option++; /* skip over single character args already parsed */ if (!option[1]) switch(option[0]) { case 'b': case 'h': continue; case 'r': case 'a': a++; continue; case 'e': return; } } else setclr=0; /* check input flags */ if (-1!=(b=strtonum(iflags,option))) { SETIT(term->c_iflag,b); continue; } /* check output flags */ if (-1!=(b=strtonum(oflags,option))) { SETIT(term->c_oflag,b); continue; } /* check control flags */ if (-1!=(b=strtonum(cflags,option))) { SETIT(term->c_cflag,b); continue; } /* check local flags */ if (-1!=(b=strtonum(lflags,option))) { SETIT(term->c_lflag,b); continue; } fprintf(stderr,"stty: Invalid option %s\n",options[a]); usage(); exit(1); } } /* hangup the line (doesn't work in this version of LINUX) */ dohangup() { struct termios term,oldterm; tcgetattr(1,&term); oldterm=term; term.c_cflag=(term.c_cflag & ~CBAUD) | B0; tcsetattr(1,TCSANOW,&term); /* leave dtr down for 1 second */ sleep(1); tcsetattr(1,TCSANOW,&oldterm); } main(int argc,char *argv[]) { struct termios term; struct termios oldterm; struct winsize win,oldwin; int a,hangupb=0,hangupa=0,execc=-1; char *command=NULL,*tty=NULL; /* if no args just print current state */ if (!argv[1]) { tcgetattr(1,&term); ioctl(1,TIOCGWINSZ,&win); print_settings(&term,&win); exit(0); } /* !!! The getty like features arn't quite working !!! */ /* check for letter options needed before we do this */ for(a=0;argv[a];a++) if ((argv[a][0]=='-') && (argv[a][2]==0)) switch(argv[a][1]) { case 'e': /* exec program */ execc=++a; a=argc; break; case 'r': /* system run program */ command=argv[++a]; break; case 'a': /* attach to tty */ tty=argv[++a]; break; case 'b': /* hangup before command */ hangupb=1; break; case 'h': /* hangup after */ hangupa=1; break; } /* attach to remote tty? */ if (tty) { int tfd; /* POSIX version of setpgrp() */ setsid(); /* open new controlling terminal */ if (-1==(tfd=open(tty,O_RDWR))) { fprintf(stderr,"stty: unable to open %s\n",tty); perror(""); exit(1); } close(0); close(1); close(2); dup(tfd); dup(tfd); dup(tfd); close(tfd); } /* hangup before doing anything? */ if (hangupb) dohangup(); tcgetattr(1,&term); ioctl(1,TIOCGWINSZ,&win); oldterm=term; oldwin=win; parse_opts(argv+1,&term,&win); tcsetattr(1,TCSANOW,&term); ioctl(1,TIOCSWINSZ,&win); /* check for an exec */ if (execc!=-1) { if (-1==execv(argv[execc],argv+execc)) { perror("stty: exec failed"); exit(1); } exit(1); /* just incase */ } /* check for a command to run using system() */ if (command) { /* if this is running on a different tty fork off */ if (tty && fork()) exit(0); system(command); /* restore old terminal attributes */ tcsetattr(1,TCSANOW,&oldterm); ioctl(1,TIOCSWINSZ,&oldwin); } /* handup after */ if (hangupa) dohangup(); }