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 }
|