X-Git-Url: https://git.datadissipation.net/ust/blobdiff_plain/fa80b49f9307df5328f05d46b0efec30955c7f26..refs/heads/master:/ust.c diff --git a/ust.c b/ust.c index 9cb4053..4f00a4c 100644 --- a/ust.c +++ b/ust.c @@ -17,7 +17,7 @@ #ifdef __linux__ #include #include -#else /* needed for termios2, which is itself needed for non-standard bauds */ +#else /* including for termios2, which is needed for non-standard bauds */ #include #endif @@ -35,15 +35,15 @@ #endif #ifdef __linux__ - #define TERMIOS_STRUCT termios2 + typedef struct termios2 TermStruct; #else - #define TERMIOS_STRUCT termios + typedef struct termios TermStruct; #endif typedef struct { + int offset; /* can only be a 1 or a -1 */ char find; char input; - int offset; /* can only be a 1 or a -1 */ } Args; typedef struct { @@ -63,48 +63,56 @@ typedef struct { /* including here to access CRLFOpt */ #include "config.h" -static int gettermattr(int dv, struct TERMIOS_STRUCT *optst); -static int settermattr(int dv, const struct TERMIOS_STRUCT *optst); -static void settermspd(unsigned int lispeed, unsigned int lospeed, struct TERMIOS_STRUCT *optst); +static int gettermattr(int dv, TermStruct *optst); +static int settermattr(int dv, const TermStruct *optst); +static void settermspd(unsigned int lispeed, unsigned int lospeed, + TermStruct *optst); static int openport(void); +static int openparent(void); static unsigned int strtoui(const char *str, unsigned int min); -static int troptions(CRLFOpt *options, const char *str); -static int setroptions(void); +static int chcktropts(CRLFOpt *options, const char *str); +static int settropts(void); static inline unsigned int lsbmask(unsigned int n); -static inline int termchck(const struct TERMIOS_STRUCT *term); -static void interchck(void); -static void cechck(void); +static inline int termvalid(const TermStruct *term); +static void eninter(void); +static void enusrecho(void); static void *writeport(void *); static void *readport(void *); static void getcmd(int escape); static inline void replacechar(char *buff, ssize_t size, const Args *args); -static inline ssize_t addchar(char *buff, ssize_t size, int *scratch, const Sizes *msizes, const Args *args); -static inline ssize_t rmchar(char *buff, ssize_t sread, int *scratch, const Args *args); +static inline ssize_t addchar(char *buff, ssize_t size, int *scratch, + const Sizes *msizes, const Args *args); +static inline ssize_t rmchar(char *buff, ssize_t sread, int *scratch, + const Args *args); static void sighandl(int signo); static void die(int code, const char *msg, ...); -static struct TERMIOS_STRUCT cntrl, /* device struct */ - origterm = { 0 }, /* controlling terminal structs */ - newterm = { 0 }; +static TermStruct cntrl, /* device struct */ + /* controlling terminal structs */ + origterm = { 0 }, + newterm = { 0 }; -static Args bsargs = {DEL, DEL, 0}; -static const Args nocrargs = {CR, 0, 0}, - nolfargs = {LF, '\0', 0}, /* null-terminator is for use inside `getcmd()` */ - lfincrargs = {CR, LF, 1}, - crinlfargs = {LF, CR, 0}; +static Args bsargs = {0, DEL, DEL}; +static const Args nocrargs = {0, CR, 0}, + /* null-terminator is for use inside `getcmd()` */ + nolfargs = {0, LF, '\0'}, + lfincrargs = {1, CR, LF}, + crinlfargs = {0, LF, CR}; static struct timespec wts; -static const unsigned int uintmax = ~(unsigned int)0; /* unsigned -1 used to return an error */ +/* unsigned -1 used to return an error */ +static const unsigned int uintmax = ~(unsigned int)0; static int interactive = 0; static char *writebuff = NULL; static char *readbuff = NULL; static int *scratchr = NULL; static int *scratchw = NULL; static int fd = -1; +static int pfd = -1; static long rwc = 0; int -gettermattr(int dv, struct TERMIOS_STRUCT *optst) +gettermattr(int dv, TermStruct *optst) { #ifdef __linux__ return ioctl(dv, TCGETS2, optst); @@ -114,7 +122,7 @@ gettermattr(int dv, struct TERMIOS_STRUCT *optst) } int -settermattr(int dv, const struct TERMIOS_STRUCT *optst) +settermattr(int dv, const TermStruct *optst) { #ifdef __linux__ return ioctl(dv, TCSETS2, optst); @@ -124,16 +132,16 @@ settermattr(int dv, const struct TERMIOS_STRUCT *optst) } void -settermspd(unsigned int lispeed, unsigned int lospeed, struct TERMIOS_STRUCT *optst) +settermspd(unsigned int lispeed, unsigned int lospeed, TermStruct *optst) { #ifdef __linux__ optst->c_cflag &= ~CBAUD; optst->c_cflag |= BOTHER; - optst->c_ispeed = ispeed; - optst->c_ospeed = ospeed; + optst->c_ispeed = lispeed; + optst->c_ospeed = lospeed; #else - cfsetispeed(optst, ispeed); - cfsetospeed(optst, ospeed); + (void)cfsetispeed(optst, lispeed); + (void)cfsetospeed(optst, lospeed); #endif } @@ -142,11 +150,11 @@ openport(void) { int flags; struct flock fl = { 0 }; - + if (verbose) fprintf(stderr, "opening \"%s\"\n", line); - fd = open(line, (O_RDWR | O_NOCTTY | O_NDELAY)); - if (fd == -1) { + fd = open(line, (O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY)); + if (fd < 0) { perror("error opening device"); exit(1); } @@ -158,35 +166,36 @@ openport(void) if (blocking) { flags = fcntl(fd, F_GETFL, 0); - /* opened to check with non-blocking mode, now set to blocking */ flags &= ~(O_NONBLOCK | O_NDELAY); - if (fcntl(fd, F_SETFL, flags) == -1) { - perror("fcntl"); - die(1, "exiting now\n"); + if (fcntl(fd, F_SETFL, flags) < 0) { + perror("fcntl"); + die(1, "exiting now\n"); } } - if (gettermattr(fd, &cntrl) == -1) + if (gettermattr(fd, &cntrl) < 0) die(1, "failed to get device attributes\n"); if (exclusive) { fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; - if (fcntl(fd, F_SETLK, &fl) == -1) { - perror("fcntl"); - die(1, "failed to lock the device, exiting now\n"); + if (fcntl(fd, F_SETLK, &fl) < 0) { + perror("fcntl"); + die(1, "failed to lock the device, exiting now\n"); } } /* * Baud */ - if (verbose) fprintf(stderr, "setting baudrate [RX:%u | TX:%u]\n", ispeed, ospeed); + if (verbose) fprintf(stderr, "setting baudrate [RX:%u | TX:%u]\n", + ispeed, ospeed); settermspd(ispeed, ospeed, &cntrl); - if (settermattr(fd, &cntrl) == -1) - die(2,"failed to set baudrate [RX:%u | TX:%u]\n", ispeed, ospeed); + if (settermattr(fd, &cntrl) < 0) + die(2,"failed to set baudrate [RX:%u | TX:%u]\n", + ispeed, ospeed); /* * Parity @@ -195,17 +204,17 @@ openport(void) cntrl.c_iflag &= ~(ISTRIP | BRKINT); cntrl.c_cflag &= ~(PARENB | PARODD); - if (verbose) fprintf(stderr, "setting parity [even: %d, odd: %d]\n",\ - parity & 1, (parity & 2) >> 1); + if (verbose) fprintf(stderr, "setting parity [even: %d, odd: %d]\n", + parity & 1, (parity & 2) >> 1); if (parity == 1) cntrl.c_cflag |= PARENB; if (parity == 2) cntrl.c_cflag |= PARENB | PARODD; - if (settermattr(fd, &cntrl) == -1) - die(2, "failed to set parity [even: %d, odd: %d]\n",\ - parity & 1, (parity & 2) >> 1); + if (settermattr(fd, &cntrl) < 0) + die(2, "failed to set parity [even: %d, odd: %d]\n", + parity & 1, (parity & 2) >> 1); /* * Flow control @@ -213,8 +222,10 @@ openport(void) if (verbose) { /* it's so ugly and beautiful at the same time */ int t = (((hard & 1) << 1) & (hard & 2)) >> 1; - fprintf(stderr, "setting flow control [XON/XOFF: %d, RTS/CTS: %d, DTR/DSR: %d, DCD: %d]\n",\ - soft, t ^ ((hard & 1) << 1) >> 1, t ^ (hard & 2) >> 1, t); + fprintf(stderr, "setting flow control " + "[XON/XOFF: %d, RTS/CTS: %d, DTR/DSR: %d, DCD: %d]\n", + soft, t ^ ((hard & 1) << 1) >> 1, + t ^ (hard & 2) >> 1, t); } cntrl.c_cflag |= CLOCAL; @@ -227,8 +238,9 @@ openport(void) cntrl.c_cflag |= CRTSCTS; } else if (hard == 2) { #ifndef CDTRDSR - fprintf(stderr, "DTR/DSR flow control is not supported on this platform\n" - "enabling this option does nothing!\n"); + fprintf(stderr, "DTR/DSR " + "flow control is not supported on this platform\n" + "enabling this option does nothing!\n"); #else cntrl.c_lflag |= CDTRDSR; #endif @@ -239,7 +251,7 @@ openport(void) #endif } - if (settermattr(fd, &cntrl) == -1) + if (settermattr(fd, &cntrl) < 0) die(2, "failed to set flow control\n"); /* @@ -248,7 +260,7 @@ openport(void) cntrl.c_iflag &= ~(ICRNL | INLCR); cntrl.c_oflag &= ~(OCRNL | ONLRET | ONLCR); - if (setroptions()) + if (settropts()) die(2, "failed to set cr-lf translation options\n"); /* @@ -270,7 +282,7 @@ openport(void) cntrl.c_cflag &= ~CSIZE; cntrl.c_cflag |= db; - if (settermattr(fd, &cntrl) == -1) + if (settermattr(fd, &cntrl) < 0) die(2, "failed to set data bits [%c]\n", datab); /* @@ -283,10 +295,10 @@ openport(void) else cntrl.c_cflag &= ~CSTOPB; - if (settermattr(fd, &cntrl) == -1) + if (settermattr(fd, &cntrl) < 0) die(1, "failed to set stop bits [%d]\n", stopb+1); - cntrl.c_cc[VMIN] = 1; + cntrl.c_cc[VMIN] = 0; cntrl.c_cc[VTIME] = 0; /* flush both hardware buffers */ @@ -295,7 +307,28 @@ openport(void) #else tcflush(fd, TCIOFLUSH); #endif - return(fd); + /* returning only for readability */ + return fd; +} + +int +openparent(void) +{ + if (verbose) fprintf(stderr, "opening parent terminal\n"); + + pfd = open("/dev/tty", O_RDWR); + if (pfd < 0) { + perror("error opening parent terminal fd"); + die(1, "exiting now\n"); + } + + if (gettermattr(pfd, &origterm) < 0 ) + die(1, "failed to get parent terminal attributes\n"); + + newterm = origterm; + + /* returning only for readability */ + return pfd; } unsigned int @@ -308,40 +341,37 @@ strtoui(const char *str, unsigned int min) if (errno != 0 || *endptr != '\0' || t < min || t > uintmax) { return uintmax; } - /* - * conversion like this results in 'undefined behavior' according to C spec, - * but almost all compilers will just truncate the value so it's OK - */ + return (unsigned int)t; } int -troptions(CRLFOpt *options, const char *str) +chcktropts(CRLFOpt *options, const char *str) { switch (str[0]) { case 'l': if (!strcmp(str, "lf-in-cr")) { - options->lfincr ^= 1; return 0; + options->lfincr ^= 1; return 0; } else if (!strcmp(str, "lf-to-cr")) { - options->lftocr ^= 1; return 0; + options->lftocr ^= 1; return 0; } else { - return 1; + return 1; } case 'c': if (!strcmp(str, "cr-in-lf")) { - options->crinlf ^= 1; return 0; + options->crinlf ^= 1; return 0; } else if (!strcmp(str, "cr-to-lf")) { - options->crtolf ^= 1; return 0; + options->crtolf ^= 1; return 0; } else { - return 1; + return 1; } case 'n': if (!strcmp(str, "no-lf")) { - options->nolf ^= 1; return 0; + options->nolf ^= 1; return 0; } else if (!strcmp(str, "no-cr")) { - options->nocr ^= 1; return 0; + options->nocr ^= 1; return 0; } else { - return 1; + return 1; } default: return 1; @@ -349,7 +379,7 @@ troptions(CRLFOpt *options, const char *str) } int -setroptions(void) +settropts(void) { cntrl.c_iflag ^= (ICRNL & lsbmask(itropts.crtolf)); cntrl.c_iflag ^= (INLCR & lsbmask(itropts.lftocr)); @@ -370,11 +400,11 @@ lsbmask(unsigned int n) } inline int -termchck(const struct TERMIOS_STRUCT *term) +termvalid(const TermStruct *term) { - for (size_t i = 0; i < sizeof(struct TERMIOS_STRUCT); i++) - if (((char*)term)[i] != 0) - return 1; + for (size_t i = 0; i < sizeof(TermStruct); i++) + if (((char*)term)[i] != 0) + return 1; return 0; } @@ -384,6 +414,7 @@ writeport(void *unused) { Sizes msizes; struct timespec ts; + int escape = 0; ts.tv_sec = swritedelay; ts.tv_nsec = nswritedelay; @@ -399,44 +430,45 @@ writeport(void *unused) die(1, "buffer allocation failed\n"); if (scratchw == NULL) die(1, "scratch buffer allocation failed\n"); - - int escape = 0; for (;;) { ssize_t inln = read(STDIN_FILENO, writebuff, wbuffsz - 1); - if (inln > 0) { - if (escape) { - getcmd(escape); - escape = 0; - } - if (writebuff[0] == escapechar) { - if (inln > 1) - getcmd(escape); - else - escape = 1; - } - - if (bsargs.find != bsargs.input) - replacechar(writebuff, inln, &bsargs); - if (tropts.nocr) - inln = rmchar(writebuff, inln, scratchw, &nocrargs); - if (tropts.nolf) - inln = rmchar(writebuff, inln, scratchw, &nolfargs); - if (tropts.lfincr) - inln = addchar(writebuff, inln, scratchw, &msizes, &lfincrargs); - - if (inln > 1) { - for (int i = 0; i <= inln; i++) { - rwc -= write(fd, &writebuff[i], 1); - nanosleep(&wts, NULL); - } - - } else { - rwc -= write(fd, writebuff, 1); - } + if (inln > 0) { + if (escape) { + getcmd(escape); + escape = 0; + inln = 0; + } + if (writebuff[0] == escapechar) { + if (inln > 1) + getcmd(escape); + else + escape = 1; + inln = 0; + } + + if (bsargs.find != bsargs.input) + replacechar(writebuff, inln, &bsargs); + if (tropts.nocr) + inln = rmchar(writebuff, inln, scratchw, &nocrargs); + if (tropts.nolf) + inln = rmchar(writebuff, inln, scratchw, &nolfargs); + if (tropts.lfincr) + inln = addchar(writebuff, inln, scratchw, &msizes, + &lfincrargs); + + if (inln > 1) { + for (int i = 0; i <= inln; i++) { + rwc -= write(fd, &writebuff[i], 1); + nanosleep(&wts, NULL); + } + + } else { + rwc -= write(fd, writebuff, inln); + } } else if (inln == 0 && !interactive) { - break; + break; } nanosleep(&ts, NULL); } @@ -466,7 +498,7 @@ readport(void *unused) if (scratchr == NULL) die(1, "scratch buffer allocation failed\n"); - interchck(); + eninter(); /* disable stdout buffering */ setvbuf(stdout, NULL, _IONBF, 0); @@ -474,16 +506,18 @@ readport(void *unused) for (;;) { ssize_t outln = read(fd, readbuff, rbuffsz - 1); if (outln > 0) { - if (itropts.nocr) - outln = rmchar(readbuff, outln, scratchr, &nocrargs); - if (itropts.nolf) - outln = rmchar(readbuff, outln, scratchr, &nolfargs); - if (itropts.crinlf) - outln = addchar(readbuff, outln, scratchr, &msizes, &crinlfargs); - if (itropts.lfincr) - outln = addchar(readbuff, outln, scratchr, &msizes, &lfincrargs); - - rwc += write(STDOUT_FILENO, readbuff, outln); + if (itropts.nocr) + outln = rmchar(readbuff, outln, scratchr, &nocrargs); + if (itropts.nolf) + outln = rmchar(readbuff, outln, scratchr, &nolfargs); + if (itropts.crinlf) + outln = addchar(readbuff, outln, scratchr, &msizes, + &crinlfargs); + if (itropts.lfincr) + outln = addchar(readbuff, outln, scratchr, &msizes, + &lfincrargs); + + rwc += write(STDOUT_FILENO, readbuff, outln); } nanosleep(&ts, NULL); } @@ -497,11 +531,12 @@ replacechar(char *buff, ssize_t size, const Args *args) { for (int i = 0; i < size; i++) if (buff[i] == args->find) - buff[i] = args->input; + buff[i] = args->input; } inline ssize_t -addchar(char *buff, ssize_t size, int *scratch, const Sizes *sizes, const Args *args) +addchar(char *buff, ssize_t size, int *scratch, const Sizes *sizes, + const Args *args) { int to, c; c = 0; @@ -510,11 +545,11 @@ addchar(char *buff, ssize_t size, int *scratch, const Sizes *sizes, const Args * for (int i = 0; i < size; i++) { if (buff[i] == args->find) { - scratch[c] = i; - c++; + scratch[c] = i; + c++; } if (c >= sizes->sizesm) - break; + break; } if (!c) return(size); @@ -540,8 +575,8 @@ rmchar(char *buff, ssize_t size, int *scratch, const Args *args) int c = 0; for (int i = 0; i < size; i++) { if (buff[i] == args->find) { - scratch[c] = i; - c++; + scratch[c] = i; + c++; } } if (!c) @@ -557,54 +592,50 @@ rmchar(char *buff, ssize_t size, int *scratch, const Args *args) } void -interchck(void) +eninter(void) { if (interactive) { - if (gettermattr(STDIN_FILENO, &origterm) < 0 ) - die(1, "failed to get terminal attributes\n"); - - newterm = origterm; - if (!canonical) - newterm.c_lflag &= ~ECHO; + newterm.c_lflag &= ~ECHO; if (!half) - newterm.c_lflag &= ~ICANON; + newterm.c_lflag &= ~ICANON; if (soft) - newterm.c_iflag |= IXONXOFF; + newterm.c_iflag |= IXONXOFF; newterm.c_iflag |= INLCR; newterm.c_cc[VMIN] = minchars; newterm.c_cc[VTIME] = 0; - newterm.c_cc[VINTR] = newterm.c_cc[VSUSP]\ - = newterm.c_cc[VQUIT] = newterm.c_cc[VLNEXT]\ - = newterm.c_cc[VDISCARD] = _POSIX_VDISABLE; + newterm.c_cc[VINTR] = newterm.c_cc[VSUSP] + = newterm.c_cc[VQUIT] = newterm.c_cc[VLNEXT] + = newterm.c_cc[VDISCARD] = _POSIX_VDISABLE; #ifdef VDSUSP newterm.c_cc[VDSUSP] = _POSIX_VDISABLE; #endif if (backspace) - bsargs.input = BS; + bsargs.input = BS; else - bsargs.input = DEL; + bsargs.input = DEL; bsargs.find = origterm.c_cc[VERASE]; - if (settermattr(STDOUT_FILENO, &newterm) < 0) - die(1, "failed to set terminal attributes\n"); + if (settermattr(pfd, &newterm) < 0) + die(1, "failed to set terminal attributes\n"); } return; } void -cechck(void) +enusrecho(void) { if ((!half || !canonical) && interactive) { newterm.c_lflag |= ECHO; newterm.c_lflag |= ICANON; - if (settermattr(STDIN_FILENO, &newterm) < 0) - fprintf(stderr, "failed to enable echo and/or canonical mode\n"); + if (settermattr(pfd, &newterm) < 0) + fprintf(stderr, + "failed to enable local echo for user input\n"); } return; } @@ -613,6 +644,7 @@ void getcmd(int escape) { Sizes msizes; + CRLFOpt *toptptr; char cmdchar; char ttr[64]; unsigned int tspd; @@ -620,11 +652,6 @@ getcmd(int escape) msizes.sizesm = scratchwsz; msizes.sizebm = wbuffsz; - if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) - interactive = 1; - - interchck(); - if (escape) cmdchar = writebuff[0]; else @@ -636,116 +663,114 @@ getcmd(int escape) die(0,"\n[EOT]\n"); case 'b': if (backspace) - bsargs.input = DEL; + bsargs.input = DEL; else - bsargs.input = BS; + bsargs.input = BS; backspace ^= 1; break; case 'h': if (half) - newterm.c_lflag &= ~ECHO; + newterm.c_lflag &= ~ECHO; else - newterm.c_lflag |= ECHO; - half ^= 1; - if (settermattr(STDOUT_FILENO, &newterm) < 0) - die(1, "failed to set terminal attributes\n"); + newterm.c_lflag |= ECHO; + if (settermattr(pfd, &newterm) < 0) + die(1, "failed to set terminal attributes\n"); + else + half ^= 1; break; case 'c': if (canonical) - newterm.c_lflag &= ~ICANON; + newterm.c_lflag &= ~ICANON; + else + newterm.c_lflag |= ICANON; + if (settermattr(pfd, &newterm) < 0) + die(1, "failed to set terminal attributes\n"); else - newterm.c_lflag |= ICANON; - canonical ^= 1; - if (settermattr(STDOUT_FILENO, &newterm) < 0) - die(1, "failed to set terminal attributes\n"); + canonical ^= 1; break; case 'w': - cechck(); + enusrecho(); if (fgets(ttr, sizeof(ttr), stdin) != NULL) { - ssize_t frln; - int wfd = open(ttr, O_RDONLY); - replacechar(ttr, 63, &nolfargs); - if (wfd == -1) { - perror("error opening file"); - goto finish; - } - while ((frln = read(wfd, writebuff, wbuffsz - 1)) > 0) { - rwc += frln; - for (int i = 0; i <= frln; i++) { - if (tropts.nocr) - frln = rmchar(writebuff, frln, scratchw, &nocrargs); - if (tropts.nolf) - frln = rmchar(writebuff, frln, scratchw, &nolfargs); - if (tropts.lfincr) - frln = addchar(writebuff, frln, scratchw, &msizes, &lfincrargs); + ssize_t frln; + int wfd = open(ttr, O_RDONLY); + replacechar(ttr, 63, &nolfargs); + if (wfd < -1) { + perror("error opening file"); + goto finish; + } + while ((frln = read(wfd, writebuff, wbuffsz - 1)) > 0) { + rwc += frln; + for (int i = 0; i <= frln; i++) { + if (tropts.nocr) + frln = rmchar(writebuff, frln, scratchw, + &nocrargs); + if (tropts.nolf) + frln = rmchar(writebuff, frln, scratchw, + &nolfargs); + if (tropts.lfincr) + frln = addchar(writebuff, frln, scratchw, + &msizes, &lfincrargs); - rwc -= write(fd, &writebuff[i], 1); - nanosleep(&wts, NULL); - } - } + rwc -= write(fd, &writebuff[i], 1); + nanosleep(&wts, NULL); + } + } } goto finish; case 's': - cechck(); + enusrecho(); if (fgets(ttr, sizeof(ttr), stdin) != NULL) { - replacechar(ttr, 63, &nolfargs); - tspd = strtoui(ttr, 0); - if (tspd != uintmax) { - ospeed = ispeed = tspd; - settermspd(ispeed, ospeed, &cntrl); - if (settermattr(fd, &cntrl) != 0) - fprintf(stderr, "failed to set baudrate " - "[RX:%u | TX:%u]\n", ispeed, ospeed); - } else { - fprintf(stderr, "invalid speed: %s\n", ttr); - } + replacechar(ttr, 63, &nolfargs); + tspd = strtoui(ttr, 0); + if (tspd != uintmax) { + ospeed = ispeed = tspd; + settermspd(ispeed, ospeed, &cntrl); + if (settermattr(fd, &cntrl) < 0) + fprintf(stderr, "failed to set baudrate " + "[RX:%u | TX:%u]\n", ispeed, ospeed); + } else { + fprintf(stderr, "invalid speed: %s\n", ttr); + } } goto finish; case 'd': - cechck(); - if (fgets(ttr, sizeof(ttr), stdin) != NULL) { - replacechar(ttr, 63, &nolfargs); - chardelay = strtoui(ttr, 0); - if (chardelay != uintmax) { - wts.tv_sec = 0; - wts.tv_nsec = chardelay; - } else { - fprintf(stderr, "invalid delay: %s\n", ttr); - } - } - goto finish; - case 't': - cechck(); - fprintf(stderr, "additional output translation option: "); + enusrecho(); if (fgets(ttr, sizeof(ttr), stdin) != NULL) { - replacechar(ttr, 63, &nolfargs); - if(troptions(&tropts, ttr)) { - fprintf(stderr, "invalid output translation option: %s\n", optarg); - goto finish; - } - if (setroptions()) - fprintf(stderr, "could not set new options\n"); + replacechar(ttr, 63, &nolfargs); + chardelay = strtoui(ttr, 0); + if (chardelay != uintmax) { + wts.tv_sec = 0; + wts.tv_nsec = chardelay; + } else { + fprintf(stderr, "invalid delay: %s\n", ttr); + } } goto finish; + case 't': /* FALLTHROUGH */ case 'T': - cechck(); - printf("additional input translation option: "); + enusrecho(); + toptptr = (cmdchar == 't') ? &tropts : &itropts; + fprintf(stderr, "additional translation option: "); if (fgets(ttr, sizeof(ttr), stdin) != NULL) { - replacechar(ttr, 63, &nolfargs); - if (troptions(&itropts, ttr)) { - fprintf(stderr, "invalid input translation option: %s\n", optarg); - goto finish; - } - if (setroptions()) - fprintf(stderr, "could not set new options\n"); + replacechar(ttr, 63, &nolfargs); + if (chcktropts(toptptr, ttr)) { + fprintf(stderr, + "invalid translation option: %s\n", + optarg); + + goto finish; + } + if (settropts()) + fprintf(stderr, "could not set new options\n"); } finish: if (!half && interactive) - newterm.c_lflag &= ~ECHO; + newterm.c_lflag &= ~ECHO; if (!canonical && interactive) - newterm.c_lflag &= ~ICANON; - if (settermattr(STDIN_FILENO, &newterm) == -1) - fprintf(stderr, "failed to restore echo and/or canonical mode\n"); + newterm.c_lflag &= ~ICANON; + if (settermattr(pfd, &newterm) < 0) + fprintf(stderr, + "failed to restore echo and/or canonical mode\n"); break; case 'p':; int st; @@ -753,20 +778,20 @@ getcmd(int escape) ts.tv_sec = spulsedelay; ts.tv_nsec = nspulsedelay; - if (ioctl(fd, TIOCMGET, &st) != 0) { - fprintf(stderr, "failed to get port status\n"); - break; + if (ioctl(fd, TIOCMGET, &st) < 0) { + fprintf(stderr, "failed to get port status\n"); + break; } st ^= TIOCM_DTR; - if (ioctl(fd, TIOCMSET, &st) != 0) { - fprintf(stderr, "failed to set DTR [assertion]\n"); - break; + if (ioctl(fd, TIOCMSET, &st) < 0) { + fprintf(stderr, "failed to set DTR [assertion]\n"); + break; } nanosleep(&ts, NULL); st ^= TIOCM_DTR; - if (ioctl(fd, TIOCMSET, &st) != 0) - fprintf(stderr, "failed to set DTR [negation]\n"); + if (ioctl(fd, TIOCMSET, &st) < 0) + fprintf(stderr, "failed to set DTR [negation]\n"); break; case BS: /* FALLTHROUGH */ case DEL: @@ -790,13 +815,18 @@ die(int code, const char *msg, ...) { va_list fpa; + if (termvalid(&origterm)) + settermattr(pfd, &origterm); + while (rwc > 0) { int t = rwc; nanosleep(&wts, NULL); if (t == rwc) break; } - if (fd != -1) + if (pfd < 0) + close(pfd); + if (fd < 0) close(fd); if (writebuff) @@ -808,9 +838,6 @@ die(int code, const char *msg, ...) if (scratchr) free(scratchr); - if (termchck(&newterm)) - settermattr(STDIN_FILENO, &origterm); - va_start(fpa, msg); vfprintf(stderr, msg, fpa); va_end(fpa); @@ -822,20 +849,24 @@ int main(int argc, char *argv[]) { long tl; - char *t; - char *endptr; + char *t = NULL; + char *endptr = NULL; unsigned int tui; int oind, rxspdset, devset, c; oind = rxspdset = devset = 0; for (int i = 1; i < argc; i++) { - if (argv[i][0] == '-' && argv[i][1] >= '0' && argv[i][1] <= '9') { - if (asprintf(&t, "-s%s", argv[i] + 1) == -1) { - fprintf(stderr, "%s: cannot convert -# to -s#\n", argv[0]); - break; - } else { - argv[i] = t; - } + if (argv[i][0] == '-' && argv[i][1] >= '0' && + argv[i][1] <= '9') { + if (asprintf(&t, "-s%s", argv[i] + 1) == -1) { + fprintf(stderr, + "%s: cannot convert -# to -s#\n", + argv[0]); + + break; + } else { + argv[i] = t; + } } } @@ -861,9 +892,10 @@ main(int argc, char *argv[]) {NULL, 0, NULL, 0} }; - while ((c = getopt_long(argc, argv, "D:T:d:i:l:m:s:t:RXbcehorv", longopt, &oind)) != -1) { + while ((c = getopt_long(argc, argv, + "D:T:d:i:l:m:s:t:RXbcehorv", longopt, &oind)) >= 0) { switch (c) { - case 0: + case 0: break; case 'b': backspace ^= 1; break; @@ -877,19 +909,26 @@ main(int argc, char *argv[]) soft ^= 1; break; case 'd': tl = strtol(optarg, &endptr, 10); - if (errno != 0 || *endptr != '\0' || t < 0) { - fprintf(stderr, "%s: invalid character delay: %s\n", argv[0],optarg); - goto ustusage; + if (errno != 0 || *endptr != '\0' || tl < 0) { + fprintf(stderr, + "%s: invalid character delay: %s\n", + argv[0], optarg); + + goto ustusage; } else { - chardelay = tl; + chardelay = tl; } break; case 'D': - if (optarg[1] != '\0' || !(optarg[0] >= '5' && optarg[0] <= '8')) { - fprintf(stderr, "%s: invalid number of data bits: %s\n", argv[0], optarg); - goto ustusage; + if (optarg[1] != '\0' || + !(optarg[0] >= '5' && optarg[0] <= '8')) { + fprintf(stderr, + "%s: invalid number of data bits: %s\n", + argv[0], optarg); + + goto ustusage; } else { - datab = optarg[0]; + datab = optarg[0]; } break; case 'e': @@ -902,84 +941,94 @@ main(int argc, char *argv[]) case 's': tui = strtoui(optarg, 1); if (tui == uintmax) { - fprintf(stderr, "%s: invalid speed: %s\n", argv[0], optarg); - goto ustusage; + fprintf(stderr, + "%s: invalid speed: %s\n", + argv[0], optarg); + + goto ustusage; } if (c == 'i') { - ispeed = tui; rxspdset = 1; + ispeed = tui; rxspdset = 1; } else { - ospeed = tui; - ispeed = rxspdset ? ispeed : ospeed; + ospeed = tui; + ispeed = rxspdset ? ispeed : ospeed; } break; case 'S': stopb ^= 1; break; case 'l': if (devset) { - fprintf(stderr, "%s: cannot specify multiple devices\n", argv[0]); - goto ustusage; + fprintf(stderr, + "%s: cannot specify multiple devices\n", + argv[0]); + + goto ustusage; } if (strlen(optarg) > 58) { - fprintf(stderr, "%s: device name too long\n", argv[0]); - goto ustusage; + fprintf(stderr, "%s: device name too long\n", argv[0]); + goto ustusage; } if (strchr(optarg, '/')) { - strcpy(line, optarg); - devset = 1; + strcpy(line, optarg); + devset = 1; } else { - sprintf(line, "/dev/%s", optarg); - devset = 1; + sprintf(line, "/dev/%s", optarg); + devset = 1; } break; case 'm': tui = strtoui(optarg, 1); if (tui == uintmax) { - fprintf(stderr, "%s: invalid number of characters: %s\n", argv[0], optarg); - goto ustusage; + fprintf(stderr, + "%s: invalid number of characters: %s\n", + argv[0], optarg); + + goto ustusage; } minchars = tui; break; case 't': - if (troptions(&tropts, optarg)) { - fprintf(stderr, "%s: invalid output translation option: %s\n", argv[0], optarg); - goto ustusage; + if (chcktropts(&tropts, optarg)) { + fprintf(stderr, + "%s: invalid output translation option: %s\n", + argv[0], optarg); + + goto ustusage; } break; case 'T': - if (troptions(&itropts, optarg)) { - fprintf(stderr, "%s: invalid input translation option: %s\n", argv[0], optarg); - goto ustusage; + if (chcktropts(&itropts, optarg)) { + fprintf(stderr, + "%s: invalid input translation option: %s\n", + argv[0], optarg); + + goto ustusage; } break; case 'v': verbose ^= 1; break; default: ustusage: - die(2, "usage: %s [--line|-l line] [--speed|-s #|-#] [--rx-speed|-i #]\n" - " [--data-bits|-D #] [--stop-bits|-S]" - " [--even|-e] [--odd|-o]\n" - " [--hardware-rts-cts|-R]" - " [--hardware-dtr-dsr|-r] [--software|-X]\n" - " [--delay|-d #] [--min-chars|-m #]" - " [--canonical|-c] [--echo|-h]\n" - " [--translation|-t option]" - " [--input-translation|-T option]\n" - " [--verbose|-v] [--backspace|-b]\n", - argv[0]); + die(2, "usage: %s [--line | -l line] " + "[--speed | -s # | -#] [--rx-speed | -i #]\n" + " [--data-bits | -D #] " + "[--stop-bits | -S] [--even | -e] [--odd | -o]\n" + " [--hardware-rts-cts | -R] " + "[--hardware-dtr-dsr | -r] [--software | -X]\n" + " [--min-chars | -m #] [--echo | -h] " + "[--canonical | -c] [--delay | -d #]\n" + " [--translation | -t option] " + "[--input-translation | -T option]\n" + " [--verbose | -v] " + "[--backspace | -b]\n", argv[0]); break; } } - /* - * not the best practice, but in order for this `free()` - * to not get executed ust needs to be killed, - * which means the OS *should* free the memory - */ - free(t); - if (!rxspdset) - ispeed = ospeed; + if (t) + free(t); - if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) + if (isatty(STDIN_FILENO)) interactive = 1; signal(SIGHUP, sighandl); @@ -988,7 +1037,15 @@ main(int argc, char *argv[]) signal(SIGTERM, sighandl); fd = openport(); - + if (interactive) pfd = openparent(); + + #ifdef __OpenBSD__ + if (pledge("stdio rpath tty", NULL) < 0) { + perror("pledge"); + die(1, "pledge failed, exiting now\n"); + } + #endif + pthread_t readthread, writethread; pthread_create(&writethread, NULL, writeport, NULL); pthread_create(&readthread, NULL, readport, NULL);