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