const size_t scratchrsz = 256;
/* `nanosleep()` values inside the read and write loops */
-const long swritedelay = 0;
-const long nswritedelay = 1000000;
+const long swritedelay = 0; /* seconds */
+const long nswritedelay = 1000000; /* nanoseconds */
+
+/* other names follow the same logic as above */
const long sreaddelay = 0;
const long nsreaddelay = 1000000;
const long spulsedelay = 0;
const long nspulsedelay = 1000000;
+/* lock the opened device */
+const int exclusive = 1; /*(0|1)*/
+
/* escape character for interactive use */
const char escapechar = '~';
* NetBSD:
* dty* - opening does not block, does not wait for DCD
* tty* - 'dial-in' device, blocks opening until a connection is established
+ * ttyU* - USB variant
*/
char line[16] = "/dev/cuau0";
/*
* CR and LF (NL) translation options
*/
-
-typedef struct{
- int crinlf;
- int crtolf;
- int lfincr;
- int lftocr;
- int nocr;
- int nolf;
-} CRLFOpt;
-
-CRLFOpt tropts = {0};
-CRLFOpt itropts = {0};
+CRLFOpt tropts = { 0 };
+CRLFOpt itropts = { 0 };
/*
* backspace: setting to one makes `^H` the backspace character, `^?` otherwise
*/
int backspace = 0; /*(0|1)*/
-int minchars = 1;
+/*
+ * the minimum of characters input before sending them to the line
+ */
+int minchars = 1; /*(>=1)*/
+
+/*
+ * delay between single characters being sent if the buffer has
+ * more than 1 (redirected stdin, writing a file)
+ * in nanoseconds
+ */
long chardelay = 0;
/*
+#include <sys/ioctl.h>
+
#include <errno.h>
#include <fcntl.h>
-#include <getopt.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+
+#include <getopt.h>
#include <pthread.h>
-#include <sys/ioctl.h>
#ifdef __linux__
#include <asm/termbits.h>
#include <termios.h>
#endif
-#include "config.h"
-
#define CR '\r'
#define LF '\n'
#define BS '\b'
ssize_t sizesm;
} Sizes;
+typedef struct{
+ int crinlf;
+ int crtolf;
+ int lfincr;
+ int lftocr;
+ int nocr;
+ int nolf;
+} CRLFOpt;
+
+/* including here to access CRLFOpt */
+#include "config.h"
+
static int gettermattr(int dv, void *strct);
static int settermattr(int dv, const void *strct);
static void settermspd(unsigned int lispeed, unsigned int lospeed, const void *strct);
static void die(int code, const char *msg, ...);
#ifdef __linux__
- static struct termios2 cntrl, origterm = {0}, newterm = {0};
+ static struct termios2 cntrl, origterm = { 0 }, newterm = { 0 };
#else
- static struct termios cntrl, origterm = {0}, newterm = {0};
+ static struct termios cntrl, origterm = { 0 }, newterm = { 0 };
#endif
static Args bsargs = {DEL, DEL, 0};
int
openport()
{
+ int flags;
+ struct flock fl = { 0 };
+
if (verbose) fprintf(stderr, "opening \"%s\"\n", line);
- fd = open(line, O_RDWR | O_NOCTTY | O_NDELAY);
+ fd = open(line, (O_RDWR | O_NOCTTY | O_NDELAY));
if (fd == -1) {
perror("error opening device");
exit(1);
if (!isatty(fd))
die(2, "device \"%s\" is not a TTY\n", line);
- int flags;
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)
- die(1, "failed to set the device to blocking mode\n");
+
+ if (fcntl(fd, F_SETFL, flags) == -1) {
+ perror("fcntl");
+ die(1, "exiting now\n");
+ }
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) {
+ if (fcntl(fd, F_SETLK, &fl) == -1) {
+ perror("fcntl");
+ die(1, "failed to lock the device, exiting now\n");
+ }
+ }
+
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);
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 (verbose) {
/* it's so ugly and beautiful at the same time */
int t = (((hard & 1) << 1) & (hard & 2)) >> 1;
if (settermattr(fd, &cntrl) == -1)
die(1, "failed to set stop bits [%d]\n", stopb+1);
+ cntrl.c_cc[VMIN] = 1;
+ cntrl.c_cc[VTIME] = 0;
+
#ifdef __linux__
ioctl(fd, TCFLSH, TCIOFLUSH);
#else
char *endptr;
t = strtol(str, &endptr, 10);
- if (errno != 0 || *endptr != '\0' || t < min) {
+ if (errno != 0 || *endptr != '\0' || t < min || t > uintmax) {
fprintf(stderr, msg, str);
return uintmax;
}
{
Sizes msizes;
struct timespec ts;
+
ts.tv_sec = swritedelay;
ts.tv_nsec = nswritedelay;
wts.tv_sec = 0;
newterm.c_iflag |= INLCR;
newterm.c_cc[VMIN] = minchars;
- newterm.c_cc[VINTR] = _POSIX_VDISABLE;
- newterm.c_cc[VSUSP] = _POSIX_VDISABLE;
- newterm.c_cc[VQUIT] = _POSIX_VDISABLE;
+ 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;
+
+ #ifdef VDSUSP
+ newterm.c_cc[VDSUSP] = _POSIX_VDISABLE;
+ #endif
if (backspace)
bsargs.input = BS;
bsargs.input = DEL;
bsargs.find = origterm.c_cc[VERASE];
-
+
if (settermattr(STDOUT_FILENO, &newterm) < 0)
die(1, "failed to set terminal attributes\n");
}
getcmd(int escape)
{
Sizes msizes;
- msizes.sizesm = scratchwsz;
- msizes.sizebm = wbuffsz;
-
char cmdchar;
char ttr[64];
unsigned int tspd;
+ msizes.sizesm = scratchwsz;
+ msizes.sizebm = wbuffsz;
+
if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO))
interactive = 1;
signal(SIGINT, sighandl);
signal(SIGQUIT, sighandl);
signal(SIGTERM, sighandl);
+ signal(SIGCHLD, SIG_DFL);
fd = openport();