dterm-nuc

annotate dterm.c @ 0:ad098a33fd34

initial commit of my fork of dterm
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 07 Apr 2017 23:43:06 +0300
parents
children 68e6bdd9c9df
rev   line source
nuclear@0 1 /* dterm.c Dumb terminal program 19/11/2004/dcs
nuclear@0 2 */
nuclear@0 3
nuclear@0 4 /*
nuclear@0 5 * Copyright 2007 Knossos Networks Ltd.
nuclear@0 6 * Copyright 2017 John Tsiombikas <nuclear@member.fsf.org>
nuclear@0 7 *
nuclear@0 8 * This program is free software; you can redistribute it and/or
nuclear@0 9 * modify it under the terms of the GNU General Public License version 2
nuclear@0 10 * as published by the Free Software Foundation.
nuclear@0 11 *
nuclear@0 12 * This program is distributed in the hope that it will be useful,
nuclear@0 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nuclear@0 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
nuclear@0 15 * GNU General Public License
nuclear@0 16 *
nuclear@0 17 * You should have received a copy of the GNU General Public License
nuclear@0 18 * along with this program; if not, write to the Free Software
nuclear@0 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
nuclear@0 20 * 02110-1301, USA.
nuclear@0 21 */
nuclear@0 22
nuclear@0 23 #ifndef VERSION
nuclear@0 24 #define VERSION "unknown"
nuclear@0 25 #endif
nuclear@0 26 #define COPYRIGHT \
nuclear@0 27 "dterm version " VERSION " Copyright 2007 Knossos Networks Ltd.\n" \
nuclear@0 28 " Copyright 2017 John Tsiombikas <nuclear@member.fsf.org>\n" \
nuclear@0 29 "\n" \
nuclear@0 30 "This program is free software; you can redistribute it and/or\n" \
nuclear@0 31 "modify it under the terms of the GNU General Public License version 2\n" \
nuclear@0 32 "as published by the Free Software Foundation.\n" \
nuclear@0 33 "\n" \
nuclear@0 34 "This program is distributed in the hope that it will be useful,\n" \
nuclear@0 35 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
nuclear@0 36 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" \
nuclear@0 37 "GNU General Public License for more details.\n" \
nuclear@0 38 "\n" \
nuclear@0 39 "You should have received a copy of the GNU General Public License\n" \
nuclear@0 40 "along with this program; if not, write to the Free Software\n" \
nuclear@0 41 "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\n" \
nuclear@0 42 "02110-1301, USA.\n"
nuclear@0 43
nuclear@0 44
nuclear@0 45 #include <stdio.h>
nuclear@0 46 #include <ctype.h>
nuclear@0 47 #include <sys/types.h>
nuclear@0 48 #include <sys/signal.h>
nuclear@0 49 #include <sys/stat.h>
nuclear@0 50 #include <sys/wait.h>
nuclear@0 51 #include <fcntl.h>
nuclear@0 52 #include <termios.h>
nuclear@0 53 #include <string.h>
nuclear@0 54 #include <unistd.h>
nuclear@0 55 #include <stdlib.h>
nuclear@0 56 #include <time.h>
nuclear@0 57 #include <signal.h>
nuclear@0 58 #include <sys/select.h>
nuclear@0 59 #include <sys/stat.h>
nuclear@0 60 #include <sys/ioctl.h>
nuclear@0 61 #include <errno.h>
nuclear@0 62
nuclear@0 63 #define FIXTTY if(istty) tcsetattr(0, TCSADRAIN, &savetio)
nuclear@0 64 #define DIEP(s) { FIXTTY; perror(s); exit(1); }
nuclear@0 65 #define DIE(s,m) { FIXTTY; fprintf(stderr, "%s: %s\n", s, m); exit(1); }
nuclear@0 66
nuclear@0 67 /*
nuclear@0 68 Sigh
nuclear@0 69 */
nuclear@0 70 #ifndef CCTS_OFLOW
nuclear@0 71 #ifdef CRTSCTS
nuclear@0 72 #define CCTS_OFLOW CRTSCTS
nuclear@0 73 #endif /* CRTSCTS */
nuclear@0 74 #endif /* ! CCTS_OFLOW */
nuclear@0 75
nuclear@0 76
nuclear@0 77 /*
nuclear@0 78 Valid speed settings.
nuclear@0 79 */
nuclear@0 80 static struct { int s, c; } speeds[] = {
nuclear@0 81 { 50, B50 },
nuclear@0 82 { 75, B75 },
nuclear@0 83 { 110, B110 },
nuclear@0 84 { 134, B134 },
nuclear@0 85 { 150, B150 },
nuclear@0 86 { 200, B200 },
nuclear@0 87 { 300, B300 },
nuclear@0 88 { 600, B600 },
nuclear@0 89 { 1200, B1200 },
nuclear@0 90 { 1800, B1800 },
nuclear@0 91 { 2400, B2400 },
nuclear@0 92 { 4800, B4800 },
nuclear@0 93 { 9600, B9600 },
nuclear@0 94 { 19200, B19200 },
nuclear@0 95 { 38400, B38400 },
nuclear@0 96 #ifdef B7200
nuclear@0 97 { 7200, B7200 },
nuclear@0 98 #endif
nuclear@0 99 #ifdef B14400
nuclear@0 100 { 14400, B14400 },
nuclear@0 101 #endif
nuclear@0 102 #ifdef B28800
nuclear@0 103 { 28800, B28800 },
nuclear@0 104 #endif
nuclear@0 105 #ifdef B57600
nuclear@0 106 { 57600, B57600 },
nuclear@0 107 #endif
nuclear@0 108 #ifdef B76800
nuclear@0 109 { 76800, B76800 },
nuclear@0 110 #endif
nuclear@0 111 #ifdef B115200
nuclear@0 112 { 115200, B115200 },
nuclear@0 113 #endif
nuclear@0 114 #ifdef B230400
nuclear@0 115 { 230400, B230400 },
nuclear@0 116 #endif
nuclear@0 117 #ifdef B460800
nuclear@0 118 { 460800, B460800 },
nuclear@0 119 #endif
nuclear@0 120 #ifdef B921600
nuclear@0 121 { 921600, B921600 },
nuclear@0 122 #endif
nuclear@0 123 { 0, 0 }};
nuclear@0 124
nuclear@0 125
nuclear@0 126 /*
nuclear@0 127 Save the terminal settings here
nuclear@0 128 */
nuclear@0 129 static struct termios intio, savetio;
nuclear@0 130
nuclear@0 131 static int fd = -1; /* Channel to port */
nuclear@0 132 static int cmdchar = 035; /* Command character, default ^] */
nuclear@0 133 static char *device = 0; /* Device, no default */
nuclear@0 134 static int ispeed = B9600; /* Input speed, default 9600 bps */
nuclear@0 135 static int ospeed = B9600; /* Output speed, default 9600 bps */
nuclear@0 136 static int twostop = 0; /* Stop bits, if set to CSTOPB, use two */
nuclear@0 137 static int parity = 0; /* Parity, -1 = mark, -2 = space 0=none */
nuclear@0 138 /* PARENB enables parity, PARODD = odd */
nuclear@0 139 static int bits = CS8; /* CS5-CS8 for 5-8 bits per character */
nuclear@0 140 static int ctsflow = 0; /* CCTS_OFLOW enables CTS flow control */
nuclear@0 141 static int xonflow = 0; /* IXON | IXOFF for in & out soft F/c */
nuclear@0 142 static int modemcontrol = 0; /* Set to HUPCLto enable modem control */
nuclear@0 143 static int markparity = 0; /* Mark parity -- set high bit on out */
nuclear@0 144 static int backspace = 0; /* Backspace char, send on BS or DEL */
nuclear@0 145 static int maplf = 0; /* If set, map LF to CR */
nuclear@0 146 static int ignorecr = 0; /* Ignore carriage returns */
nuclear@0 147 static int crlf = 0; /* Send CRLF on CR */
nuclear@0 148 static int istty; /* Result of isatty() */
nuclear@0 149 static char *connname = 0; /* Connection name found in config */
nuclear@0 150 static int sendbreak = 0; /* Break requested */
nuclear@0 151 static int modem = 0; /* Current modem status */
nuclear@0 152 static int setmodem = 0; /* Set modem status to this */
nuclear@0 153 static int delay = 0; /* Millisecond delay after each key */
nuclear@0 154 static int linedelay = 0; /* Millisecond delay after each CR */
nuclear@0 155 static int showspecial = 0; /* Show special chars as [xx] */
nuclear@0 156
nuclear@0 157 static void
nuclear@0 158 help() {
nuclear@0 159 fprintf(stderr,
nuclear@0 160 "dterm commands:\n"
nuclear@0 161 "^%c Enter command mode quit, q Exit\n"
nuclear@0 162 "show Display configuration help, h, ? Display this message\n"
nuclear@0 163 "!<command> Execute shell command version Display version\n"
nuclear@0 164 "@<filename> Get configuration from <filename>\n"
nuclear@0 165 "<device> Connect to <device> 300,1200,9600 Set speed\n"
nuclear@0 166 "5, 6, 7, 8 Set bits per character 1, 2 Set stop bits\n"
nuclear@0 167 "e, o, n, m, s Set parity"
nuclear@0 168 #ifdef CCTS_OFLOW
nuclear@0 169 " cts,nocts Enable / disable CTS\n"
nuclear@0 170 #else
nuclear@0 171 "\n"
nuclear@0 172 #endif
nuclear@0 173 "dtr, nodtr Raise / lower DTR b Send a 500ms break\n"
nuclear@0 174 "rts, norts Raise / lower RTS d, r Toggle DTR, RTS\n"
nuclear@0 175 "rx <filename> Receive file (XMODEM) sx <filename> Send file (XMODEM)\n"
nuclear@0 176 "rz Receive file (ZMODEM) sz <filename> Send file (ZMODEM)\n"
nuclear@0 177 "xon,noxon Enable / disable XON/XOFF flow control\n"
nuclear@0 178 "modem Hang up modem on exit, exit if modem hangs up\n"
nuclear@0 179 "nomodem Do not do modem control\n"
nuclear@0 180 "bs, nobs Enable / disable mapping of Delete to Backspace\n"
nuclear@0 181 "del, nodel Enable / disable mapping of Backspace to Delete\n"
nuclear@0 182 "maplf, nomaplf Enable / disable mapping of LF to CR\n"
nuclear@0 183 "igncr, noigncr Ignore / output carriage returns\n"
nuclear@0 184 "crlf, nocrlf Enable / disable sending LF after each CR\n"
nuclear@0 185 "delay=<n> Add delay of <n> ms after each charachter sent\n"
nuclear@0 186 "crwait=<n> Add delay of <n> ms after each line sent\n"
nuclear@0 187 "esc=<c> Set command mode character to Ctrl/<c>\n"
nuclear@0 188 "ctrl,hex,noctrl Show control characters as ^n (except tab, CR, LF)\n"
nuclear@0 189
nuclear@0 190
nuclear@0 191
nuclear@0 192 , cmdchar + '@');
nuclear@0 193 }
nuclear@0 194
nuclear@0 195
nuclear@0 196
nuclear@0 197
nuclear@0 198 /*
nuclear@0 199 Show current setup
nuclear@0 200 */
nuclear@0 201 static void
nuclear@0 202 showsetup() {
nuclear@0 203 int i;
nuclear@0 204 fprintf(stderr, "Port: %s\n", device);
nuclear@0 205 fprintf(stderr, "Communications parameters: ");
nuclear@0 206 for(i = 0; speeds[i].s && speeds[i].c != ispeed; )
nuclear@0 207 i++;
nuclear@0 208 fprintf(stderr, "%d", speeds[i].s);
nuclear@0 209 if(ospeed != ispeed) {
nuclear@0 210 for(i = 0; speeds[i].s && speeds[i].c != ospeed; )
nuclear@0 211 i++;
nuclear@0 212 fprintf(stderr, "/%d", speeds[i].s);
nuclear@0 213 }
nuclear@0 214 if(bits == CS5) fprintf(stderr, " 5");
nuclear@0 215 if(bits == CS6) fprintf(stderr, " 6");
nuclear@0 216 if(bits == CS7) fprintf(stderr, " 7");
nuclear@0 217 if(bits == CS8) fprintf(stderr, " 8");
nuclear@0 218 if(parity == 0) fprintf(stderr, " n");
nuclear@0 219 if(parity == PARENB) fprintf(stderr, " e");
nuclear@0 220 if(parity == (PARENB|PARODD)) fprintf(stderr, " o");
nuclear@0 221 if(parity == -1) fprintf(stderr, " m");
nuclear@0 222 if(parity == -2) fprintf(stderr, " s");
nuclear@0 223 if(twostop) fprintf(stderr, " 2\n");
nuclear@0 224 else fprintf(stderr, " 1\n");
nuclear@0 225 fprintf(stderr, "Flow/modem control:");
nuclear@0 226 if(xonflow) fprintf(stderr, " xon");
nuclear@0 227 if(ctsflow) fprintf(stderr, " cts");
nuclear@0 228 if(modemcontrol)fprintf(stderr, " modem");
nuclear@0 229 putc('\n', stderr);
nuclear@0 230 fprintf(stderr, "Character mappings:");
nuclear@0 231 if(backspace == 8) fprintf(stderr, " bs");
nuclear@0 232 if(backspace == 127) fprintf(stderr, " del");
nuclear@0 233 if(maplf) fprintf(stderr, " maplf");
nuclear@0 234 if(ignorecr) fprintf(stderr, " igncr");
nuclear@0 235 if(crlf) fprintf(stderr, " crlf");
nuclear@0 236 if(showspecial == 1) fprintf(stderr, " ctrl");
nuclear@0 237 if(showspecial == 2) fprintf(stderr, " hex");
nuclear@0 238 putc('\n', stderr);
nuclear@0 239 printf("Modem control: DTR: %s RTS: %s CTS: %s DSR: %s DCD: %s\n",
nuclear@0 240 setmodem & TIOCM_DTR ? "on" : "off",
nuclear@0 241 setmodem & TIOCM_RTS ? "on" : "off",
nuclear@0 242 modem & TIOCM_CTS ? "on" : "off",
nuclear@0 243 modem & TIOCM_DSR ? "on" : "off",
nuclear@0 244 modem & TIOCM_CD ? "on" : "off");
nuclear@0 245 fprintf(stderr, "Escape character: ^%c\n", cmdchar + '@');
nuclear@0 246 fflush(stderr);
nuclear@0 247 }
nuclear@0 248
nuclear@0 249
nuclear@0 250 /*
nuclear@0 251 Use the rzsz or lrzsz package to do file transfer
nuclear@0 252 Mode should be "rx", "rb" or "rz" to receive a file, "sx", "sb" or "sz"
nuclear@0 253 to send. "rz" & "rb" don't require a file name; the others do.
nuclear@0 254 */
nuclear@0 255 static int
nuclear@0 256 rzsz(char *mode, char *file) {
nuclear@0 257 static char *loc[] = { "/usr/bin/", "/usr/local/bin/l",
nuclear@0 258 "/usr/bin/l", "/usr/local/bin/", 0 };
nuclear@0 259 char path[128];
nuclear@0 260 char *cmd;
nuclear@0 261 int i;
nuclear@0 262 struct stat sb;
nuclear@0 263 pid_t pid;
nuclear@0 264
nuclear@0 265 /*
nuclear@0 266 Check file name
nuclear@0 267 */
nuclear@0 268 if(*file == 0 && (mode[0] != 'r' || mode[1] == 'x')) {
nuclear@0 269 fprintf(stderr, "File name required for %c%c\n",
nuclear@0 270 mode[0], mode[1]);
nuclear@0 271 return -1;
nuclear@0 272 }
nuclear@0 273
nuclear@0 274 /*
nuclear@0 275 Find the appropriate command
nuclear@0 276 */
nuclear@0 277 for(i = 0; loc[i]; i++) {
nuclear@0 278 if(mode[1] == 'a') {
nuclear@0 279 sprintf(path, "%sascii-xfr", loc[i]);
nuclear@0 280 } else {
nuclear@0 281 sprintf(path, "%s%c%c", loc[i], mode[0], mode[1]);
nuclear@0 282 }
nuclear@0 283 if(!stat(path, &sb) && (sb.st_mode & S_IXUSR))
nuclear@0 284 break;
nuclear@0 285 }
nuclear@0 286 if(!loc[i]) {
nuclear@0 287 fprintf(stderr, "RZ/SZ/ascii-xfr not installed\n");
nuclear@0 288 return -1;
nuclear@0 289 }
nuclear@0 290
nuclear@0 291 /*
nuclear@0 292 Get the command name
nuclear@0 293 */
nuclear@0 294 cmd = strrchr(path, '/');
nuclear@0 295 if(cmd) cmd++;
nuclear@0 296 else cmd = path;
nuclear@0 297
nuclear@0 298 /*
nuclear@0 299 Fork subprocess. Set stdin & stdout to the serial line
nuclear@0 300 stderr remains on the console for progress messages
nuclear@0 301 */
nuclear@0 302 pid = fork();
nuclear@0 303 if(pid == 0) {
nuclear@0 304 dup2(fd, 0);
nuclear@0 305 dup2(fd, 1);
nuclear@0 306 if(mode[1] == 'a') {
nuclear@0 307 char delay_str[64];
nuclear@0 308 sprintf(delay_str, "%d", linedelay);
nuclear@0 309 if(*file) execl(path, cmd, "-s", "-l", delay_str, file, NULL);
nuclear@0 310 else execl(path, cmd, "-r", NULL);
nuclear@0 311 } else {
nuclear@0 312 if(*file) execl(path, cmd, file, NULL);
nuclear@0 313 else execl(path, cmd, NULL);
nuclear@0 314 }
nuclear@0 315 _exit(127);
nuclear@0 316 }
nuclear@0 317 else if(pid == -1) {
nuclear@0 318 perror("fork");
nuclear@0 319 return -1;
nuclear@0 320 }
nuclear@0 321
nuclear@0 322 /*
nuclear@0 323 Wait for the process to complete and give a meaningful
nuclear@0 324 response
nuclear@0 325 */
nuclear@0 326 signal(SIGINT, SIG_IGN);
nuclear@0 327 signal(SIGQUIT, SIG_IGN);
nuclear@0 328 signal(SIGTERM, SIG_IGN);
nuclear@0 329 while(waitpid(pid, &i, 0) != pid) {}
nuclear@0 330 signal(SIGINT, SIG_DFL);
nuclear@0 331 signal(SIGQUIT, SIG_DFL);
nuclear@0 332 signal(SIGTERM, SIG_DFL);
nuclear@0 333
nuclear@0 334 if(WIFSIGNALED(i)) {
nuclear@0 335 fprintf(stderr, "Terminated on signal %d%s\n", WTERMSIG(i),
nuclear@0 336 WCOREDUMP(i) ? " (core dumped)" : "");
nuclear@0 337 return -1;
nuclear@0 338 }
nuclear@0 339 if(WTERMSIG(i))
nuclear@0 340 return -1;
nuclear@0 341 return 0;
nuclear@0 342 }
nuclear@0 343
nuclear@0 344
nuclear@0 345
nuclear@0 346 static int readconfig(char *, char *);
nuclear@0 347
nuclear@0 348 /*
nuclear@0 349 Process commands passed as strings, may be several commands on a line
nuclear@0 350 Allow ugliness like 8n1 -- treat as 8, n, 1
nuclear@0 351 */
nuclear@0 352 static int
nuclear@0 353 setup(char *s, char *cffile, int cfline) {
nuclear@0 354 char *t, *d;
nuclear@0 355 int j,k;
nuclear@0 356 int ret = 0;
nuclear@0 357 struct stat sb;
nuclear@0 358 char ttybuf[128];
nuclear@0 359 int justospeed = 0;
nuclear@0 360
nuclear@0 361 while(*s) {
nuclear@0 362 /*
nuclear@0 363 Skip whitespace, commas
nuclear@0 364 */
nuclear@0 365 while(isspace(*s) || *s == ',')
nuclear@0 366 s++;
nuclear@0 367 if(!*s) break;
nuclear@0 368
nuclear@0 369 /*
nuclear@0 370 '?' = help
nuclear@0 371 */
nuclear@0 372 if(*s == '?') {
nuclear@0 373 help();
nuclear@0 374 return -4;
nuclear@0 375 }
nuclear@0 376
nuclear@0 377 /*
nuclear@0 378 '!' = shell command
nuclear@0 379 */
nuclear@0 380 if(*s == '!') {
nuclear@0 381 if((t = strchr(s, '\n')))
nuclear@0 382 *t = 0;
nuclear@0 383 system(++s);
nuclear@0 384 break;
nuclear@0 385 }
nuclear@0 386
nuclear@0 387 /*
nuclear@0 388 File transfer (sx, sz, rx, rz, sa, ra)
nuclear@0 389 Run rzsz or ascii-xfr to perform the actual file transfer
nuclear@0 390 Allow "sxfilename", "sx filename" or just "rz"
nuclear@0 391 */
nuclear@0 392 if((s[0] == 's' || s[0] == 'r') &&
nuclear@0 393 (s[1] == 'x' || s[1] == 'z' || s[1] == 'a')) {
nuclear@0 394 if((t = strchr(s, '\n')))
nuclear@0 395 *t = 0;
nuclear@0 396 for(t = s + 2; isspace(*t); ) t++;
nuclear@0 397 return rzsz(s, t);
nuclear@0 398 }
nuclear@0 399
nuclear@0 400 /*
nuclear@0 401 If a number, process it.
nuclear@0 402 If it's a valid speed, use that -- if nnn/mmm, set both to nnn
nuclear@0 403 for the first time, and flag things so mmm just sets ospeed
nuclear@0 404 5-8 = data bits, 1,2 sets stops
nuclear@0 405 Anything else is error
nuclear@0 406 */
nuclear@0 407 if(isdigit(*s)) {
nuclear@0 408 j = strtol(s, &s, 10);
nuclear@0 409 for(k = 1; speeds[k].s; k++)
nuclear@0 410 if(speeds[k].s == j)
nuclear@0 411 break;
nuclear@0 412 if(speeds[k].s) {
nuclear@0 413 ospeed = speeds[k].c;
nuclear@0 414 if(!justospeed)
nuclear@0 415 ispeed = ospeed;
nuclear@0 416 if(*s == '/') {
nuclear@0 417 s++;
nuclear@0 418 justospeed = 1;
nuclear@0 419 }
nuclear@0 420 else justospeed = 0;
nuclear@0 421 }
nuclear@0 422 else if(j == 5) bits = CS5;
nuclear@0 423 else if(j == 6) bits = CS6;
nuclear@0 424 else if(j == 7) bits = CS7;
nuclear@0 425 else if(j == 8) bits = CS8;
nuclear@0 426 else if(j == 1) twostop = 0;
nuclear@0 427 else if(j == 2) twostop = CSTOPB;
nuclear@0 428 else {
nuclear@0 429 if(cffile)
nuclear@0 430 fprintf(stderr, "in %s:%d: ",
nuclear@0 431 cffile, cfline);
nuclear@0 432 fprintf(stderr, "%d: invalid speed/bits\n", j);
nuclear@0 433 ret = -1;
nuclear@0 434 }
nuclear@0 435 }
nuclear@0 436
nuclear@0 437 /*
nuclear@0 438 Otherwise, get the alpha-only keyword, see if it matches anything
nuclear@0 439 useful.
nuclear@0 440 */
nuclear@0 441 else {
nuclear@0 442 t = s;
nuclear@0 443 while(isalpha(*t)) t++;
nuclear@0 444 j = *t;
nuclear@0 445 *t = 0;
nuclear@0 446 if( !strcasecmp(s, "xon"))
nuclear@0 447 xonflow = IXON | IXOFF;
nuclear@0 448 else if(!strcasecmp(s, "noxon"))
nuclear@0 449 xonflow = 0;
nuclear@0 450
nuclear@0 451 #ifdef CCTS_OFLOW
nuclear@0 452 else if(!strcasecmp(s, "cts"))
nuclear@0 453 ctsflow = CCTS_OFLOW;
nuclear@0 454 else if(!strcasecmp(s, "nocts"))
nuclear@0 455 ctsflow = 0;
nuclear@0 456 #endif
nuclear@0 457 else if(!strcasecmp(s, "modem"))
nuclear@0 458 modemcontrol = HUPCL;
nuclear@0 459 else if(!strcasecmp(s, "nomodem"))
nuclear@0 460 modemcontrol = 0;
nuclear@0 461 else if(!strcasecmp(s, "E"))
nuclear@0 462 parity = PARENB;
nuclear@0 463 else if(!strcasecmp(s, "O"))
nuclear@0 464 parity = PARENB | PARODD;
nuclear@0 465 else if(!strcasecmp(s, "M"))
nuclear@0 466 parity = -1;
nuclear@0 467 else if(!strcasecmp(s, "S"))
nuclear@0 468 parity = -2;
nuclear@0 469 else if(!strcasecmp(s, "N"))
nuclear@0 470 parity = 0;
nuclear@0 471 else if(!strcasecmp(s, "q") || !strcasecmp(s, "quit"))
nuclear@0 472 ret = -3;
nuclear@0 473 else if(!strcasecmp(s, "h") || !strcasecmp(s, "help"))
nuclear@0 474 help();
nuclear@0 475 else if(!strcasecmp(s, "del"))
nuclear@0 476 backspace = 127;
nuclear@0 477 else if(!strcasecmp(s, "bs"))
nuclear@0 478 backspace = 8;
nuclear@0 479 else if(!strcasecmp(s,"nobs") || !strcasecmp(s,"nodel"))
nuclear@0 480 backspace = 0;
nuclear@0 481 else if(!strcasecmp(s, "noesc"))
nuclear@0 482 cmdchar = 0;
nuclear@0 483 else if(!strcasecmp(s, "maplf"))
nuclear@0 484 maplf = 1;
nuclear@0 485 else if(!strcasecmp(s, "nomaplf"))
nuclear@0 486 maplf = 0;
nuclear@0 487 else if(!strcasecmp(s, "igncr"))
nuclear@0 488 ignorecr = 1;
nuclear@0 489 else if(!strcasecmp(s, "noigncr"))
nuclear@0 490 ignorecr = 0;
nuclear@0 491 else if(!strcasecmp(s, "crlf"))
nuclear@0 492 crlf = 1;
nuclear@0 493 else if(!strcasecmp(s, "nocrlf"))
nuclear@0 494 crlf = 0;
nuclear@0 495 else if(!strcasecmp(s, "b"))
nuclear@0 496 sendbreak = 1;
nuclear@0 497 else if(!strcasecmp(s, "d"))
nuclear@0 498 setmodem ^= TIOCM_DTR;
nuclear@0 499 else if(!strcasecmp(s, "r"))
nuclear@0 500 setmodem ^= TIOCM_RTS;
nuclear@0 501 else if(!strcasecmp(s, "dtr"))
nuclear@0 502 setmodem |= TIOCM_DTR;
nuclear@0 503 else if(!strcasecmp(s, "rts"))
nuclear@0 504 setmodem |= TIOCM_RTS;
nuclear@0 505 else if(!strcasecmp(s, "nodtr"))
nuclear@0 506 setmodem &= ~TIOCM_DTR;
nuclear@0 507 else if(!strcasecmp(s, "norts"))
nuclear@0 508 setmodem &= ~TIOCM_RTS;
nuclear@0 509 else if(!strcasecmp(s, "show"))
nuclear@0 510 showsetup();
nuclear@0 511 else if(!strcasecmp(s, "version"))
nuclear@0 512 fputs(COPYRIGHT, stderr);
nuclear@0 513 else if(!strcasecmp(s, "ctrl"))
nuclear@0 514 showspecial = 1;
nuclear@0 515 else if(!strcasecmp(s, "hex"))
nuclear@0 516 showspecial = 2;
nuclear@0 517 else if(!strcasecmp(s, "noctrl") ||
nuclear@0 518 !strcasecmp(s, "noctrl"))
nuclear@0 519 showspecial = 0;
nuclear@0 520
nuclear@0 521 /*
nuclear@0 522 No?
nuclear@0 523 @<filename> includes a file
nuclear@0 524 !cmd Run a command
nuclear@0 525 esc=c sets escape char
nuclear@0 526 <device> select device
nuclear@0 527 */
nuclear@0 528 else {
nuclear@0 529 *t = j;
nuclear@0 530 while(*t && !isspace(*t) && *t != ',')
nuclear@0 531 t++;
nuclear@0 532 j = *t;
nuclear@0 533 *t = 0;
nuclear@0 534 if(*s == '@') {
nuclear@0 535 k = readconfig(++s, 0);
nuclear@0 536 if(k == -2) {
nuclear@0 537 if(cffile)
nuclear@0 538 fprintf(stderr,
nuclear@0 539 "in %s:%d: ",
nuclear@0 540 cffile, cfline);
nuclear@0 541 fprintf(stderr, "%s: %s\n",
nuclear@0 542 s, strerror(errno));
nuclear@0 543 ret = -1;
nuclear@0 544 }
nuclear@0 545 goto next;
nuclear@0 546 }
nuclear@0 547 if(!strncasecmp(s, "esc=", 4)) {
nuclear@0 548 cmdchar = s[4] & 0x1f;
nuclear@0 549 goto next;
nuclear@0 550 }
nuclear@0 551 else if(!strncasecmp(s, "delay=", 6)) {
nuclear@0 552 delay = atoi(s+6);
nuclear@0 553 goto next;
nuclear@0 554 }
nuclear@0 555 else if(!strncasecmp(s, "crwait=", 7)) {
nuclear@0 556 linedelay = atoi(s+7);
nuclear@0 557 goto next;
nuclear@0 558 }
nuclear@0 559 d = s;
nuclear@0 560 k = stat(d, &sb);
nuclear@0 561 if(k && *d != '/') {
nuclear@0 562 sprintf(ttybuf, "/dev/%.100s", d);
nuclear@0 563 d = ttybuf;
nuclear@0 564 k = stat(d, &sb);
nuclear@0 565 }
nuclear@0 566 if(!k) {
nuclear@0 567 if((sb.st_mode & S_IFMT) == S_IFCHR) {
nuclear@0 568 ret = 1;
nuclear@0 569 device = strdup(d);
nuclear@0 570 goto next;
nuclear@0 571 }
nuclear@0 572 }
nuclear@0 573 if(cffile)
nuclear@0 574 fprintf(stderr, "in %s:%d: ",
nuclear@0 575 cffile, cfline);
nuclear@0 576 fprintf(stderr,
nuclear@0 577 "%s: unrecognised keyword/device\n", s);
nuclear@0 578 ret = -1;
nuclear@0 579 }
nuclear@0 580 next: *t = j;
nuclear@0 581 s = t;
nuclear@0 582 }
nuclear@0 583 }
nuclear@0 584 return ret;
nuclear@0 585 }
nuclear@0 586
nuclear@0 587
nuclear@0 588 /*
nuclear@0 589 Read a config file
nuclear@0 590 Input lines can be lists of config words, or in the form
nuclear@0 591 name: words
nuclear@0 592 If name: form, only lines matching passed name are used
nuclear@0 593 */
nuclear@0 594 static int
nuclear@0 595 readconfig(char *file, char *name) {
nuclear@0 596 char buf[1024];
nuclear@0 597 FILE *f;
nuclear@0 598 char *s, *t;
nuclear@0 599 int lineno = 0;
nuclear@0 600 int ret = 0, r;
nuclear@0 601
nuclear@0 602 /*
nuclear@0 603 ~/file = get file from $HOME/file
nuclear@0 604 */
nuclear@0 605 if(*file == '~' && file[1] == '/' && (s = getenv("HOME"))) {
nuclear@0 606 snprintf(buf, sizeof(buf), "%s/%s", s, file+2);
nuclear@0 607 file = buf;
nuclear@0 608 }
nuclear@0 609
nuclear@0 610 /*
nuclear@0 611 Return -2 if can't open
nuclear@0 612 */
nuclear@0 613 f = fopen(file, "r");
nuclear@0 614 if(!f) return -2;
nuclear@0 615
nuclear@0 616 /*
nuclear@0 617 Read input, strip # commends
nuclear@0 618 Count lines
nuclear@0 619 Keep track of return code
nuclear@0 620 */
nuclear@0 621 while(fgets(buf, sizeof(buf), f)) {
nuclear@0 622 lineno++;
nuclear@0 623 if((s = strchr(buf, '#')))
nuclear@0 624 *s = 0;
nuclear@0 625 for(s = buf; isspace(*s);)
nuclear@0 626 s++;
nuclear@0 627 if(!*s) continue;
nuclear@0 628 for(t = s; *t && *t != ':' && *t != ',' && !isspace(*t); )
nuclear@0 629 t++;
nuclear@0 630 if(*t == ':') {
nuclear@0 631 *t++ = 0;
nuclear@0 632 if(!name)
nuclear@0 633 continue;
nuclear@0 634 if(strcmp(name, s))
nuclear@0 635 continue;
nuclear@0 636 s = t;
nuclear@0 637 connname = name;
nuclear@0 638 }
nuclear@0 639
nuclear@0 640 r = setup(s, file, lineno);
nuclear@0 641 if(r < 0)
nuclear@0 642 ret = r;
nuclear@0 643 if(r > 0 && !ret)
nuclear@0 644 ret = 1;
nuclear@0 645 }
nuclear@0 646
nuclear@0 647 fclose(f);
nuclear@0 648 return ret;
nuclear@0 649 }
nuclear@0 650
nuclear@0 651
nuclear@0 652 /*
nuclear@0 653 Sleep n milliseconds
nuclear@0 654 */
nuclear@0 655 static void
nuclear@0 656 millisleep(int n) {
nuclear@0 657 struct timespec t;
nuclear@0 658 t.tv_sec = n / 1000;
nuclear@0 659 t.tv_nsec = (n % 1000) * 1000000;
nuclear@0 660 nanosleep(&t, 0);
nuclear@0 661 }
nuclear@0 662
nuclear@0 663
nuclear@0 664 /*
nuclear@0 665 Set up the port
nuclear@0 666 */
nuclear@0 667 static int
nuclear@0 668 setupport(int fd) {
nuclear@0 669 int parityflags;
nuclear@0 670 int modemflags;
nuclear@0 671 int spaceparity = 0;
nuclear@0 672 struct termios tio;
nuclear@0 673 int m;
nuclear@0 674
nuclear@0 675 /*
nuclear@0 676 See what to do with parity
nuclear@0 677 */
nuclear@0 678 markparity = 0;
nuclear@0 679 parityflags = parity;
nuclear@0 680 if(parity == -1) {
nuclear@0 681 parityflags = 0;
nuclear@0 682 markparity = ISTRIP;
nuclear@0 683 }
nuclear@0 684 else if(parity == -2) {
nuclear@0 685 parityflags = 0;
nuclear@0 686 spaceparity = ISTRIP;
nuclear@0 687 }
nuclear@0 688
nuclear@0 689 /*
nuclear@0 690 If no modem control, use local mode
nuclear@0 691 */
nuclear@0 692 modemflags = ctsflow | modemcontrol;
nuclear@0 693 if(!modemflags)
nuclear@0 694 modemflags = CLOCAL;
nuclear@0 695
nuclear@0 696 /*
nuclear@0 697 Set the speed and params
nuclear@0 698 */
nuclear@0 699 tcgetattr(fd, &tio);
nuclear@0 700 tio.c_iflag = IGNBRK | IGNPAR | xonflow | spaceparity | markparity;
nuclear@0 701 tio.c_cflag = CREAD | HUPCL | modemflags | bits | parityflags;
nuclear@0 702 tio.c_oflag = 0;
nuclear@0 703 tio.c_lflag = 0;
nuclear@0 704 cfsetispeed(&tio, ispeed);
nuclear@0 705 cfsetospeed(&tio, ospeed);
nuclear@0 706 if(tcsetattr(fd, TCSAFLUSH, &tio) == -1)
nuclear@0 707 return -1;
nuclear@0 708
nuclear@0 709 /*
nuclear@0 710 Set up the modem lines
nuclear@0 711 */
nuclear@0 712 ioctl(fd, TIOCMGET, &modem);
nuclear@0 713 if((modem & (TIOCM_RTS | TIOCM_DTR)) != (setmodem & (TIOCM_RTS |
nuclear@0 714 TIOCM_DTR))) {
nuclear@0 715 m = setmodem & (TIOCM_RTS | TIOCM_DTR);
nuclear@0 716 ioctl(fd, TIOCMBIS, &m);
nuclear@0 717 m = (~setmodem) & (TIOCM_RTS | TIOCM_DTR);
nuclear@0 718 ioctl(fd, TIOCMBIC, &m);
nuclear@0 719 }
nuclear@0 720
nuclear@0 721 /*
nuclear@0 722 Send a break if requested
nuclear@0 723 */
nuclear@0 724 if(sendbreak) {
nuclear@0 725 ioctl(fd, TIOCSBRK, 0);
nuclear@0 726 millisleep(500);
nuclear@0 727 ioctl(fd, TIOCCBRK, 0);
nuclear@0 728 sendbreak = 0;
nuclear@0 729 }
nuclear@0 730
nuclear@0 731 /*
nuclear@0 732 Get the current modem status
nuclear@0 733 */
nuclear@0 734 ioctl(fd, TIOCMGET, &modem);
nuclear@0 735 setmodem = modem;
nuclear@0 736
nuclear@0 737 return 0;
nuclear@0 738 }
nuclear@0 739
nuclear@0 740
nuclear@0 741 /*
nuclear@0 742 Set up the modem. This is a little tricky due to the need to
nuclear@0 743 ensure the modem does not block before we set it up.
nuclear@0 744 */
nuclear@0 745 static int
nuclear@0 746 openport(char *device) {
nuclear@0 747 int fd;
nuclear@0 748
nuclear@0 749 if((fd = open(device, O_RDWR|O_NONBLOCK, 0)) < 0)
nuclear@0 750 DIEP(device)
nuclear@0 751 if(setupport(fd) < 0)
nuclear@0 752 DIEP(device)
nuclear@0 753 millisleep(10);
nuclear@0 754 fcntl(fd, F_SETFL, 0);
nuclear@0 755
nuclear@0 756 ioctl(fd, TIOCMGET, &modem);
nuclear@0 757 setmodem = modem;
nuclear@0 758
nuclear@0 759 setenv("DTERM_PORT", device, 1);
nuclear@0 760 return fd;
nuclear@0 761 }
nuclear@0 762
nuclear@0 763
nuclear@0 764 /*
nuclear@0 765 Usage
nuclear@0 766 */
nuclear@0 767 static void
nuclear@0 768 usage(char *this) {
nuclear@0 769 fprintf(stderr, "Usage: %s port/setup\n"
nuclear@0 770 " '%s help' for help\n", this, this);
nuclear@0 771 exit(1);
nuclear@0 772 }
nuclear@0 773
nuclear@0 774
nuclear@0 775 int
nuclear@0 776 main(int argc, char **argv) {
nuclear@0 777 int nfd;
nuclear@0 778 int i, j, c;
nuclear@0 779 unsigned char inbuf;
nuclear@0 780 char buf[256];
nuclear@0 781 char cbuf[8];
nuclear@0 782 char *s;
nuclear@0 783 int done;
nuclear@0 784 fd_set fds;
nuclear@0 785 struct timeval delay_tv, *readdelay;
nuclear@0 786 struct stat sb;
nuclear@0 787
nuclear@0 788 /*
nuclear@0 789 Do the right things depending on whether stdin & stdout are TTYs
nuclear@0 790 If the input is a TTY, we need to put it into non-canonical mode
nuclear@0 791 (which we'll actually do later); otherwise, default to turning
nuclear@0 792 LFs from a file into CRs. (See [no]maplf setup command.)
nuclear@0 793 If the output is a TTY, default to passing CR transparently;
nuclear@0 794 otherwise default to ignoring CR so that output is logged to a
nuclear@0 795 files etc nicely. (See [no]igncr.)
nuclear@0 796 */
nuclear@0 797 istty = isatty(0);
nuclear@0 798 if(istty) {
nuclear@0 799 tcgetattr(0, &savetio);
nuclear@0 800 maplf = 0;
nuclear@0 801 }
nuclear@0 802 else maplf = 1;
nuclear@0 803 if(isatty(1))
nuclear@0 804 ignorecr = 0;
nuclear@0 805 else ignorecr = 1;
nuclear@0 806
nuclear@0 807 /*
nuclear@0 808 Read default config, if no private .dtermrc, use /etc/dtermrc
nuclear@0 809 */
nuclear@0 810 setmodem = modem = TIOCM_DTR | TIOCM_RTS;
nuclear@0 811 if(readconfig("~/.dtermrc", argv[1]) == -2)
nuclear@0 812 readconfig("/etc/dtermrc", argv[1]);
nuclear@0 813
nuclear@0 814 /*
nuclear@0 815 Parse args
nuclear@0 816 If only arg is "help", exit
nuclear@0 817 */
nuclear@0 818 i = 1;
nuclear@0 819 if(connname) i = 2;
nuclear@0 820 for(; i < argc; i++)
nuclear@0 821 if(setup(argv[i], 0, 0) < 0)
nuclear@0 822 usage(argv[0]);
nuclear@0 823 if(argc == 2 && !strcasecmp(argv[1], "help"))
nuclear@0 824 exit(0);
nuclear@0 825
nuclear@0 826 /*
nuclear@0 827 If no device specified, have a crack at finding a default device
nuclear@0 828 Look for the first on-board device first; failing that look for
nuclear@0 829 the first USB device. For Linux & BSD these are:
nuclear@0 830 OS Onboard USB
nuclear@0 831 Linux ttyS0 ttyUSB0
nuclear@0 832 BSD ttyd0 ttyU0
nuclear@0 833 Note that this rather assumes that the existence of a device
nuclear@0 834 name in /dev indicates the actual existence of a device. Mostly
nuclear@0 835 this is the case on modern systems. Mostly.
nuclear@0 836 */
nuclear@0 837 if(!device) {
nuclear@0 838 if( !stat("/dev/ttyS0", &sb)) device = "/dev/ttyS0";
nuclear@0 839 else if(!stat("/dev/ttyd0", &sb)) device = "/dev/ttyd0";
nuclear@0 840 else if(!stat("/dev/ttyUSB0", &sb)) device = "/dev/ttyUSB0";
nuclear@0 841 else if(!stat("/dev/ttyU0", &sb)) device = "/dev/ttyU0";
nuclear@0 842 else {
nuclear@0 843 fprintf(stderr, "Could not find default device\n");
nuclear@0 844 usage(argv[0]);
nuclear@0 845 }
nuclear@0 846 }
nuclear@0 847
nuclear@0 848 /*
nuclear@0 849 If the controlling TTY is in fact a TTY, set it up
nuclear@0 850 */
nuclear@0 851 if(istty) {
nuclear@0 852 intio = savetio;
nuclear@0 853 intio.c_oflag = 0;
nuclear@0 854 intio.c_lflag = 0;
nuclear@0 855 intio.c_iflag = savetio.c_iflag & ~(INLCR|IGNCR|ICRNL);
nuclear@0 856
nuclear@0 857 intio.c_cc[VEOF] = _POSIX_VDISABLE;
nuclear@0 858 intio.c_cc[VEOL] = _POSIX_VDISABLE;
nuclear@0 859 intio.c_cc[VEOL2] = _POSIX_VDISABLE;
nuclear@0 860 intio.c_cc[VERASE] = _POSIX_VDISABLE;
nuclear@0 861 intio.c_cc[VWERASE] = _POSIX_VDISABLE;
nuclear@0 862 intio.c_cc[VKILL] = _POSIX_VDISABLE;
nuclear@0 863 intio.c_cc[VREPRINT] = _POSIX_VDISABLE;
nuclear@0 864 intio.c_cc[VINTR] = _POSIX_VDISABLE;
nuclear@0 865 intio.c_cc[VQUIT] = _POSIX_VDISABLE;
nuclear@0 866 intio.c_cc[VSUSP] = _POSIX_VDISABLE;
nuclear@0 867 #ifdef VDSUSP
nuclear@0 868 intio.c_cc[VDSUSP] = _POSIX_VDISABLE;
nuclear@0 869 #endif
nuclear@0 870 intio.c_cc[VLNEXT] = _POSIX_VDISABLE;
nuclear@0 871 intio.c_cc[VDISCARD] = _POSIX_VDISABLE;
nuclear@0 872 #ifdef VSTATUS
nuclear@0 873 intio.c_cc[VSTATUS] = _POSIX_VDISABLE;
nuclear@0 874 #endif
nuclear@0 875 tcsetattr(0, TCSADRAIN, &intio);
nuclear@0 876 }
nuclear@0 877
nuclear@0 878 /*
nuclear@0 879 Connect to serial port
nuclear@0 880 */
nuclear@0 881 fd = openport(device);
nuclear@0 882 if(fd < 0) exit(1);
nuclear@0 883
nuclear@0 884 /*
nuclear@0 885 Main loop
nuclear@0 886 */
nuclear@0 887 readdelay = 0;
nuclear@0 888 done = 0;
nuclear@0 889 while(!done) {
nuclear@0 890
nuclear@0 891 /*
nuclear@0 892 Set up the select() call
nuclear@0 893 If readdelay is not 0, we're waiting for things to go quiet so we
nuclear@0 894 can exit.
nuclear@0 895 Errors kill us, execpt for interrupted calls
nuclear@0 896 0 return only happens if readdelay is set, so we exit then
nuclear@0 897 */
nuclear@0 898 FD_ZERO(&fds);
nuclear@0 899 if(!readdelay)
nuclear@0 900 FD_SET(0, &fds);
nuclear@0 901 FD_SET(fd, &fds);
nuclear@0 902 i = select(fd + 1, &fds, 0,0, readdelay);
nuclear@0 903 if(i == -1 && errno != EINTR)
nuclear@0 904 DIEP("select");
nuclear@0 905 if(i == 0 && readdelay)
nuclear@0 906 break;
nuclear@0 907
nuclear@0 908 /*
nuclear@0 909 If input from line, read a full buffer in
nuclear@0 910 IgnoreCR means sucking CRs out of the buffer (yuck)
nuclear@0 911 If EOF (e.g. hangup), exit nicely.
nuclear@0 912 */
nuclear@0 913 if(FD_ISSET(fd, &fds)) {
nuclear@0 914 i = read(fd, buf, sizeof(buf));
nuclear@0 915 if(i < 0)
nuclear@0 916 DIEP(device);
nuclear@0 917 if(!i) break;
nuclear@0 918 if(showspecial) {
nuclear@0 919 s = buf;
nuclear@0 920 do {
nuclear@0 921 c = 0;
nuclear@0 922 for(j = 0; j < i; j++) {
nuclear@0 923 c = (unsigned char) s[j];
nuclear@0 924 if(showspecial == 2 && (
nuclear@0 925 c == '\t' || c > '~'))
nuclear@0 926 break;
nuclear@0 927 if(c == '\r' && ignorecr)
nuclear@0 928 break;
nuclear@0 929 if(( c < ' ' && c != '\t'
nuclear@0 930 && c != '\r' && c != '\n')
nuclear@0 931 || (c > '~' && c < 160))
nuclear@0 932 break;
nuclear@0 933 }
nuclear@0 934 if(j) write(1, s, j);
nuclear@0 935 if(j >= i)
nuclear@0 936 break;
nuclear@0 937 if(c == '\r' && ignorecr) {
nuclear@0 938 /* Do nothing */
nuclear@0 939 }
nuclear@0 940 else if(c < 32 && showspecial != 2) {
nuclear@0 941 cbuf[0] = '^';
nuclear@0 942 cbuf[1] = c + '@';
nuclear@0 943 write(1, cbuf, 2);
nuclear@0 944 }
nuclear@0 945 else if(c == 127 && showspecial != 2)
nuclear@0 946 write(1, "[DEL]", 5);
nuclear@0 947 else {
nuclear@0 948 sprintf(cbuf, "[%02x]", c);
nuclear@0 949 write(1, cbuf, 4);
nuclear@0 950 }
nuclear@0 951 j++;
nuclear@0 952 s += j;
nuclear@0 953 i -= j;
nuclear@0 954 } while(i > 0);
nuclear@0 955 }
nuclear@0 956 else {
nuclear@0 957 if(ignorecr) {
nuclear@0 958 j = 0;
nuclear@0 959 for(s = buf; s < buf + i; s++)
nuclear@0 960 if(*s != '\r')
nuclear@0 961 buf[j++] = *s;
nuclear@0 962 i = j;
nuclear@0 963 }
nuclear@0 964 write(1, buf, i);
nuclear@0 965 }
nuclear@0 966 }
nuclear@0 967
nuclear@0 968 /*
nuclear@0 969 Input on stdin
nuclear@0 970 Read a character
nuclear@0 971 If EOF, set readdelay to 1 second
nuclear@0 972 */
nuclear@0 973 if(FD_ISSET(0, &fds)) {
nuclear@0 974 if(read(0, &inbuf, 1) < 1) {
nuclear@0 975 delay_tv.tv_sec = 1;
nuclear@0 976 delay_tv.tv_usec = 0;
nuclear@0 977 readdelay = &delay_tv;
nuclear@0 978 continue;
nuclear@0 979 }
nuclear@0 980 /*
nuclear@0 981 If command character received, read commands
nuclear@0 982 */
nuclear@0 983 if(inbuf == cmdchar && istty) {
nuclear@0 984 FIXTTY;
nuclear@0 985 putchar('\n');
nuclear@0 986 for(;;) {
nuclear@0 987 fprintf(stderr, "dterm> ");
nuclear@0 988 if(!fgets(buf, sizeof(buf), stdin))
nuclear@0 989 return 0;
nuclear@0 990 if((s = strchr(buf, '#')))
nuclear@0 991 *s = 0;
nuclear@0 992 for(s = buf; *s; s++)
nuclear@0 993 if(!isspace(*s)) break;
nuclear@0 994 if(!*s) break;
nuclear@0 995 ioctl(fd, TIOCMGET, &modem);
nuclear@0 996 i = setup(buf, 0, 0);
nuclear@0 997 if(i == -3)
nuclear@0 998 return 0;
nuclear@0 999 if(i == 1) {
nuclear@0 1000 nfd = openport(device);
nuclear@0 1001 if(nfd >= 0) {
nuclear@0 1002 close(fd);
nuclear@0 1003 fd = nfd;
nuclear@0 1004 }
nuclear@0 1005 }
nuclear@0 1006 else if(setupport(fd))
nuclear@0 1007 fprintf(stderr,
nuclear@0 1008 "invalid parameters\n");
nuclear@0 1009 }
nuclear@0 1010 if(istty) tcsetattr(0, TCSADRAIN, &intio);
nuclear@0 1011 }
nuclear@0 1012 /*
nuclear@0 1013 Otherwise do any processing on the character
nuclear@0 1014 Add dread high bit disease if mark parity
nuclear@0 1015 BS <-> DEL mapping
nuclear@0 1016 LF -> CR mapping for files
nuclear@0 1017 CR -> CRLF mapping for TTYs
nuclear@0 1018 */
nuclear@0 1019 else {
nuclear@0 1020 if(markparity)
nuclear@0 1021 inbuf |= 0x80;
nuclear@0 1022 if(backspace && (inbuf == 8 || inbuf == 127))
nuclear@0 1023 inbuf = backspace;
nuclear@0 1024 if(maplf && inbuf == '\n')
nuclear@0 1025 inbuf = '\r';
nuclear@0 1026 write(fd, &inbuf, 1);
nuclear@0 1027 if(crlf && inbuf == '\r') {
nuclear@0 1028 inbuf = '\n';
nuclear@0 1029 write(fd, &inbuf, 1);
nuclear@0 1030 }
nuclear@0 1031 if(linedelay && inbuf == '\r')
nuclear@0 1032 millisleep(linedelay);
nuclear@0 1033 else if(delay)
nuclear@0 1034 millisleep(delay);
nuclear@0 1035 }
nuclear@0 1036 }
nuclear@0 1037
nuclear@0 1038 }
nuclear@0 1039
nuclear@0 1040 /*
nuclear@0 1041 Fall out the bottom, cleaning up
nuclear@0 1042 */
nuclear@0 1043 FIXTTY;
nuclear@0 1044 return 0;
nuclear@0 1045 }