From: git Date: Mon, 2 Mar 2026 07:43:10 +0000 (-0500) Subject: refine redirected i/o timeout mechanism, remove obsoleted flags X-Git-Url: https://git.datadissipation.net/?a=commitdiff_plain;h=86ec479b40b2e210c4bafae5d94b5c15334bd0cf;p=ust.git refine redirected i/o timeout mechanism, remove obsoleted flags minor formatting changes and version bump --- diff --git a/README.md b/README.md index d60c011..44d3f50 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ ## Installation -Before installing check config.mk - inside, the installation directories can be set. +Before installing check `config.mk` - inside, the installation directories can be set. To install, simply run: ``` -make install +make && make install ``` diff --git a/config.def.h b/config.def.h index e9df038..44583ca 100644 --- a/config.def.h +++ b/config.def.h @@ -10,7 +10,7 @@ const size_t scratchrsz = 256; const long swritedelay = 0; /* seconds */ const long nswritedelay = 1000000; /* nanoseconds */ -/* other names follow the same logic as above */ +/* other time variable names follow the same logic as above */ const long sreaddelay = 0; const long nsreaddelay = 1000000; @@ -36,10 +36,6 @@ const char escapechar = '~'; /* print additional info to stderr */ int verbose = 0; /*(0|1)*/ -/* exit timeout after piped ust reaches EOF */ -long stimeout = 0; -long nstimeout = 10000; - /* * device name * diff --git a/config.mk b/config.mk index 36893ea..31f8619 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,4 @@ -VERSION = 0.2.1 +VERSION = 0.2.3 TARGET = ust @@ -11,8 +11,11 @@ OS != uname -s GNUSRC != if [ "${OS}" = "Linux" ]; then \ printf "%s" "-D_GNU_SOURCE"; \ fi +# some implementations of make do not accept `!=`, +# so if it triggers any errors just remove this block +# and add the flag manually -CFLAGS = -std=c99 -Wall -pthread -O2 ${GNUSRC} +CFLAGS = -std=c99 -Wall -lpthread -O2 ${GNUSRC} LDFLAGS = CC = cc diff --git a/ust.1 b/ust.1 index dd7c132..5e48149 100644 --- a/ust.1 +++ b/ust.1 @@ -17,8 +17,6 @@ .Op Fl \-hardware\-dtr\-dsr|\-R .Op Fl \-software|\-X .Op Fl \-delay|\-d Ar # -.Op Fl \-timeout\-ns|\-f Ar # -.Op Fl \-timeout\-s|\-F Ar # .Op Fl \-min\-chars|\-m Ar # .Op Fl \-canonical|\-c .Op Fl \-echo|\-h @@ -76,17 +74,6 @@ Toggle DTR/DSR flow control (setting both hardware flow control options will ena Toggle XON/XOFF software flow control (can be enabled with hardware flow control simultaneously). .It Fl \-delay|\-d Ar # Delay between sending multiple characters (when redirecting stdin or writing a file) to the line in nanoseconds. -.It Fl \-timeout\-ns|\-f Ar # -With stdin redirected, -.Nm -will exit upon reaching -.Ar EOF , -this option sets a delay (in nanoseconds) after -.Ar EOF -encounter and before program exit. -.It Fl \-timeout\-s|\-F Ar # -.Ar EOF -exit delay (in seconds). .It Fl \-min\-chars|\-m Ar # The minimum of characters to input before they get sent to the line. .It Fl \-canonical|\-c diff --git a/ust.c b/ust.c index e88bdcc..7d4918c 100644 --- a/ust.c +++ b/ust.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -11,6 +10,7 @@ #include #include +#include #include #include @@ -66,16 +66,16 @@ typedef struct { 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 openport(); +static int openport(void); static unsigned int strtoui(const char *str, const char *msg, unsigned int min); static int troptions(CRLFOpt *options, const char *str); -static int setroptions(); +static int setroptions(void); static inline unsigned int lsbmask(unsigned int n); static inline int termchck(const struct TERMIOS_STRUCT *term); -static void interchck(); -static void cechck(); -static void *writeport(void *unused); -static void *readport(void *unused); +static void interchck(void); +static void cechck(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); @@ -101,6 +101,7 @@ static char *readbuff = NULL; static int *scratchr = NULL; static int *scratchw = NULL; static int fd = -1; +static long rwc = 0; int gettermattr(int dv, struct TERMIOS_STRUCT *optst) @@ -137,7 +138,7 @@ settermspd(unsigned int lispeed, unsigned int lospeed, struct TERMIOS_STRUCT *op } int -openport() +openport(void) { int flags; struct flock fl = { 0 }; @@ -169,12 +170,9 @@ openport() if (gettermattr(fd, &cntrl) == -1) die(1, "failed to get device attributes\n"); - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 0; - 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"); @@ -302,7 +300,7 @@ openport() unsigned int strtoui(const char *str, const char *msg, unsigned int min) -{ +{ long t; char *endptr; @@ -357,13 +355,13 @@ troptions(CRLFOpt *options, const char *str) } int -setroptions() +setroptions(void) { - cntrl.c_iflag ^= (ICRNL & lsbmask(itropts.crtolf)); - cntrl.c_iflag ^= (INLCR & lsbmask(itropts.lftocr)); - cntrl.c_oflag ^= (OCRNL & lsbmask(tropts.crtolf)); + cntrl.c_iflag ^= (ICRNL & lsbmask(itropts.crtolf)); + cntrl.c_iflag ^= (INLCR & lsbmask(itropts.lftocr)); + cntrl.c_oflag ^= (OCRNL & lsbmask(tropts.crtolf)); cntrl.c_oflag ^= (ONLRET & lsbmask(tropts.lftocr)); - cntrl.c_oflag ^= (ONLCR & lsbmask(tropts.crinlf)); + cntrl.c_oflag ^= (ONLCR & lsbmask(tropts.crinlf)); return settermattr(fd, &cntrl); } @@ -388,13 +386,11 @@ termchck(const struct TERMIOS_STRUCT *term) } void * -writeport(void *unused) +writeport(void *) { Sizes msizes; - struct timespec timeout, ts; + struct timespec ts; - timeout.tv_sec = stimeout; - timeout.tv_nsec = nstimeout; ts.tv_sec = swritedelay; ts.tv_nsec = nswritedelay; wts.tv_sec = 0; @@ -437,19 +433,18 @@ writeport(void *unused) if (inln > 1) { for (int i = 0; i <= inln; i++) { - write(fd, &writebuff[i], 1); + rwc -= write(fd, &writebuff[i], 1); nanosleep(&wts, NULL); } } else { - write(fd, writebuff, 1); + rwc -= write(fd, writebuff, 1); } } else if (inln == 0 && !interactive) { break; } nanosleep(&ts, NULL); } - /* ust kills itself upon receiving a signal so no fancy `nanosleep()` features needed */ - nanosleep(&timeout, NULL); + die(0, "[EOF]\n"); /* unreachable */ @@ -491,7 +486,7 @@ readport(void *unused) if (itropts.lfincr) outln = addchar(readbuff, outln, scratchr, &msizes, &lfincrargs); - write(STDOUT_FILENO, readbuff, outln); + rwc += write(STDOUT_FILENO, readbuff, outln); } nanosleep(&ts, NULL); } @@ -500,7 +495,7 @@ readport(void *unused) return NULL; } -inline void __attribute__((hot)) +inline void replacechar(char *buff, ssize_t size, const Args *args) { for (int i = 0; i < size; i++) @@ -508,7 +503,7 @@ replacechar(char *buff, ssize_t size, const Args *args) buff[i] = args->input; } -inline ssize_t __attribute__((hot)) +inline ssize_t addchar(char *buff, ssize_t size, int *scratch, const Sizes *sizes, const Args *args) { int to, c; @@ -543,7 +538,7 @@ addchar(char *buff, ssize_t size, int *scratch, const Sizes *sizes, const Args * return (size + c); } -inline ssize_t __attribute__((hot)) +inline ssize_t rmchar(char *buff, ssize_t size, int *scratch, const Args *args) { int c = 0; @@ -671,14 +666,15 @@ getcmd(int escape) case 'w': cechck(); if (fgets(ttr, sizeof(ttr), stdin) != NULL) { - replacechar(ttr, 63, &nolfargs); 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); @@ -687,7 +683,7 @@ getcmd(int escape) if (tropts.lfincr) frln = addchar(writebuff, frln, scratchw, &msizes, &lfincrargs); - write(fd, &writebuff[i], 1); + rwc -= write(fd, &writebuff[i], 1); nanosleep(&wts, NULL); } } @@ -789,6 +785,11 @@ void die(int code, const char *msg, ...) { va_list fpa; + while (rwc > 0) { + int t = rwc; + nanosleep(&wts, NULL); + if (t == rwc) break; + } if (fd != -1) close(fd); @@ -812,14 +813,18 @@ die(int code, const char *msg, ...) } int -main(int argc, char **argv) +main(int argc, char *argv[]) { - char *t = NULL; - /* glibc's `asprintf()` won't set the string to NULL on failure automatically */ + long tl; + char *t; + char *endptr; + 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') { - asprintf(&t, "-s%s", argv[i] + 1); - if (!t) { + if (asprintf(&t, "-s%s", argv[i] + 1) == -1) { fprintf(stderr, "%s: cannot convert -# to -s#\n", argv[0]); break; } @@ -841,8 +846,6 @@ main(int argc, char **argv) {"data", required_argument, NULL, 'D'}, {"delay", required_argument, NULL, 'd'}, {"min-chars", required_argument, NULL, 'm'}, - {"timeout-ns", required_argument, NULL, 'f'}, - {"timeout-s", required_argument, NULL, 'F'}, {"stop-bits", no_argument, NULL, 'S'}, {"backspace", no_argument, NULL, 'b'}, {"translation", required_argument, NULL, 't'}, @@ -851,10 +854,7 @@ main(int argc, char **argv) {NULL, 0, NULL, 0} }; - unsigned int tui; - int oind, rxspdset, devset, c; - oind = rxspdset = devset = 0; - while ((c = getopt_long(argc, argv, "D:F:T:d:f: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)) != -1) { switch (c) { case 0: break; @@ -868,25 +868,17 @@ main(int argc, char **argv) hard ^= 2; break; case 'X': soft ^= 1; break; - case 'd': /* FALLTHROUGH */ - case 'f': - case 'F':; - char* endptr; - long t; - t = strtol(optarg, &endptr, 10); + 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; - } else if (c == 'd') { - chardelay = t; - } else if (c == 'f'){ - nstimeout = t; } else { - stimeout = t; + chardelay = tl; } break; case 'D': - if (strlen(optarg) != 1 || !(optarg[0] >= '5' && optarg[0] <= '8')) { + 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 { @@ -899,18 +891,17 @@ main(int argc, char **argv) parity ^= 2; break; case 'h': half ^= 1; break; - case 'i': - tui = strtoui(optarg, "invalid rx speed: %s\n", 1); - if (tui == uintmax) - goto ustusage; - ispeed = tui; - rxspdset = 1; - break; + case 'i': /* FALLTHROUGH */ case 's': tui = strtoui(optarg, "invalid speed: %s\n", 1); if (tui == uintmax) goto ustusage; - ospeed = tui; + if (c == 'i') { + ispeed = tui; rxspdset = 1; + } else { + ospeed = tui; + ispeed = rxspdset ? ispeed : ospeed; + } break; case 'S': stopb ^= 1; break;