aboutsummaryrefslogtreecommitdiff
path: root/miscutils/microcom.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-01-27 22:40:39 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-01-27 22:40:39 +0000
commitef67c5758a3eeeac2a4cf57559ff967210f7feab (patch)
tree2581b72d9f01234274a0b5c07278d2146c903023 /miscutils/microcom.c
parentc4e4be9414f8c7318c0f87b0838d88bb9ef75732 (diff)
downloadbusybox-w32-ef67c5758a3eeeac2a4cf57559ff967210f7feab.tar.gz
busybox-w32-ef67c5758a3eeeac2a4cf57559ff967210f7feab.tar.bz2
busybox-w32-ef67c5758a3eeeac2a4cf57559ff967210f7feab.zip
microcom: update from the author
Diffstat (limited to 'miscutils/microcom.c')
-rw-r--r--miscutils/microcom.c206
1 files changed, 133 insertions, 73 deletions
diff --git a/miscutils/microcom.c b/miscutils/microcom.c
index 1235f0634..160bff19b 100644
--- a/miscutils/microcom.c
+++ b/miscutils/microcom.c
@@ -9,128 +9,188 @@
9 */ 9 */
10#include "libbb.h" 10#include "libbb.h"
11 11
12/* All known arches use small ints for signals */
13static volatile smallint signalled;
14
15static void signal_handler(int signo)
16{
17 signalled = signo;
18}
19
20// set canonical tty mode
21static void xget1(int fd, struct termios *t, struct termios *oldt)
22{
23 tcgetattr(fd, oldt);
24 *t = *oldt;
25 cfmakeraw(t);
26// t->c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
27// t->c_iflag &= ~(BRKINT|IXON|ICRNL);
28// t->c_oflag &= ~(ONLCR);
29// t->c_cc[VMIN] = 1;
30// t->c_cc[VTIME] = 0;
31}
32
33static int xset1(int fd, struct termios *tio, const char *device)
34{
35 int ret = tcsetattr(fd, TCSANOW, tio);
36
37 if (ret) {
38 bb_perror_msg("can't tcsetattr for %s", device);
39 }
40 return ret;
41}
42
12int microcom_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 43int microcom_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13int microcom_main(int argc, char **argv) 44int microcom_main(int argc, char **argv)
14{ 45{
15 struct pollfd pfd[2]; 46 struct pollfd pfd[2];
16#define sfd (pfd[1].fd) 47 int nfd;
17 char *device_lock_file = NULL; 48 //int sfd;
18 const char *s; 49#define sfd (pfd[0].fd)
50 char *device_lock_file;
19 const char *opt_s = "9600"; 51 const char *opt_s = "9600";
20 unsigned speed; 52 speed_t speed;
21 int len; 53 const char *opt_t = "100"; // 0.1 sec timeout
22 int exitcode = 1; 54 unsigned timeout;
23 struct termios tio0, tiosfd, tio; 55 struct termios tio0, tiosfd, tio;
56 bool istty;
24 57
25 getopt32(argv, "s:", &opt_s); 58 // fetch options
59 opt_complementary = "-1"; /* at least one arg should be there */
60 getopt32(argv, "s:t:", &opt_s, &opt_t);
26 argc -= optind; 61 argc -= optind;
27 argv += optind; 62 argv += optind;
28 if (!argv[0]) 63
29 bb_show_usage(); 64 // check sanity
30 speed = xatou(opt_s); 65 speed = xatou(opt_s);
66 timeout = xatou(opt_t);
67 device_lock_file = (char *)bb_basename(argv[0]);
31 68
32 // try to create lock file in /var/lock 69 // try to create lock file in /var/lock
33 s = bb_basename(argv[0]); 70 device_lock_file = xasprintf("/var/lock/LCK..%s", device_lock_file);
34 if (!s[0]) {
35 errno = ENODEV;
36 bb_perror_msg_and_die("can't lock device");
37 }
38 device_lock_file = xasprintf("/var/lock/LCK..%s", s);
39 sfd = open(device_lock_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644); 71 sfd = open(device_lock_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644);
40 if (sfd < 0) { 72 if (sfd < 0) {
41 if (ENABLE_FEATURE_CLEAN_UP)
42 free(device_lock_file);
43 device_lock_file = NULL;
44 if (errno == EEXIST) 73 if (errno == EEXIST)
45 bb_perror_msg_and_die("can't lock device"); 74 bb_perror_msg_and_die("can't lock device");
46 // We don't abort on other errors: /var/lock can be 75 // We don't abort on other errors: /var/lock can be
47 // non-writable or non-existent 76 // non-writable or non-existent
77 if (ENABLE_FEATURE_CLEAN_UP)
78 free(device_lock_file);
79 device_lock_file = NULL;
48 } else { 80 } else {
49 // %4d to make mgetty happy. It treats 4-bytes lock files as binary, 81 // %4d to make mgetty happy. It treats 4-bytes lock files as binary,
50 // not text, PID. Making 5+ char file. Brrr... 82 // not text, PID. Making 5+ char file. Brrr...
51 s = xasprintf("%4d\n", getpid()); 83 char *s = xasprintf("%4d\n", getpid());
52 write(sfd, s, strlen(s)); 84 write(sfd, s, strlen(s));
53 if (ENABLE_FEATURE_CLEAN_UP) 85 if (ENABLE_FEATURE_CLEAN_UP)
54 free((char*)s); 86 free(s);
55 close(sfd); 87 close(sfd);
56 } 88 }
57 89
58 // open device 90 // setup signals
59 sfd = open(argv[0], O_RDWR); 91 sig_catch(SIGHUP, signal_handler);
60 if (sfd < 0) { 92 sig_catch(SIGINT, signal_handler);
61 bb_perror_msg("can't open device"); 93 sig_catch(SIGTERM, signal_handler);
62 goto unlock_and_exit; 94 sig_catch(SIGPIPE, signal_handler);
63 }
64 95
65 // put stdin to "raw mode", handle one character at a time 96 // error exit code if we fail to open the device
66 tcgetattr(STDIN_FILENO, &tio0); 97 signalled = 1;
67 tio = tio0;
68 tio.c_lflag &= ~(ICANON|ECHO);
69 tio.c_iflag &= ~(IXON|ICRNL);
70 tio.c_oflag &= ~(ONLCR);
71 tio.c_cc[VMIN] = 1;
72 tio.c_cc[VTIME] = 0;
73 if (tcsetattr(STDIN_FILENO, TCSANOW, &tio)) {
74 bb_perror_msg("can't tcsetattr for %s", "stdin");
75 goto unlock_and_exit;
76 }
77 98
78 /* same thing for modem (plus: set baud rate) - TODO: make CLI option */ 99 // open device
79 tcgetattr(sfd, &tiosfd); 100 sfd = open_or_warn(argv[0], O_RDWR | O_NOCTTY | O_NONBLOCK);
80 tio = tiosfd; 101 if (sfd < 0)
81 tio.c_lflag &= ~(ICANON|ECHO);
82 tio.c_iflag &= ~(IXON|ICRNL);
83 tio.c_oflag &= ~(ONLCR);
84 tio.c_cc[VMIN] = 1;
85 tio.c_cc[VTIME] = 0;
86 cfsetispeed(&tio, tty_value_to_baud(speed));
87 cfsetospeed(&tio, tty_value_to_baud(speed));
88 if (tcsetattr(sfd, TCSANOW, &tio)) {
89 bb_perror_msg("can't tcsetattr for %s", "device");
90 goto unlock_and_exit; 102 goto unlock_and_exit;
91 } 103 fcntl(sfd, F_SETFL, O_RDWR | O_NOCTTY);
92 104
93 // disable SIGINT 105 /* put stdin to "raw mode" (if stdin is a TTY),
94 signal(SIGINT, SIG_IGN); 106 handle one character at a time */
107 istty = isatty(STDIN_FILENO);
108 if (istty) {
109 xget1(STDIN_FILENO, &tio, &tio0);
110 if (xset1(STDIN_FILENO, &tio, "stdin"))
111 goto close_unlock_and_exit;
112// tcflush(STDIN_FILENO, TCIFLUSH);
113 timeout = -1; // tty input? -> set infinite timeout for poll()
114 }
95 115
96 // drain stdin 116 // same thing for modem
97 tcflush(STDIN_FILENO, TCIFLUSH); 117 xget1(sfd, &tio, &tiosfd);
98 printf("connected to '%s' (%d bps), exit with ctrl-X...\r\n", argv[0], speed); 118 // order device to hang up at exit
119 tio.c_cflag |= (CREAD|HUPCL);
120 // set device speed
121 cfsetspeed(&tio, tty_value_to_baud(speed));
122 if (xset1(sfd, &tio, argv[0]))
123 goto restore0_close_unlock_and_exit;
99 124
100 // main loop: check with poll(), then read/write bytes across 125 // main loop: check with poll(), then read/write bytes across
101 pfd[0].fd = STDIN_FILENO; 126 /* pfd[0].fd = sfd; - they are the same */
102 pfd[0].events = POLLIN; 127 pfd[0].events = POLLIN;
103 /*pfd[1].fd = sfd;*/ 128 pfd[1].fd = STDIN_FILENO;
104 pfd[1].events = POLLIN; 129 pfd[1].events = POLLIN;
105 while (1) { 130
131 // TODO: on piped input should we treat NL as CRNL?!
132
133 signalled = 0;
134 // initially we have to poll() both stdin and device
135 nfd = 2;
136 while (!signalled && nfd && safe_poll(pfd, nfd, timeout) > 0) {
106 int i; 137 int i;
107 safe_poll(pfd, 2, -1); 138
108 for (i = 0; i < 2; ++i) { 139 for (i = 0; i < nfd; ++i) {
109 if (pfd[i].revents & POLLIN) { 140 if (pfd[i].revents & (POLLIN | POLLHUP)) {
110 len = read(pfd[i].fd, bb_common_bufsiz1, COMMON_BUFSIZE); 141// int fd;
111 if (len > 0) { 142 char c;
112 if (!i && 24 == bb_common_bufsiz1[0]) 143 // read a byte
113 goto done; // ^X exits 144 if (safe_read(pfd[i].fd, &c, 1) < 1) {
114 write(pfd[1-i].fd, bb_common_bufsiz1, len); 145 // this can occur at the end of piped input
146 // from now we only poll() for device
147 nfd--;
148 continue;
149 }
150// fd = STDOUT_FILENO;
151 // stdin requires additional processing
152 // (TODO: must be controlled by command line switch)
153 if (i) {
154 // ^@ sends Break
155 if (0 == c) {
156 tcsendbreak(sfd, 0);
157 continue;
158 }
159 // ^X exits
160 if (24 == c)
161 goto done;
162// fd = sfd;
115 } 163 }
164 // write the byte
165 write(i ? sfd : STDOUT_FILENO, &c, 1);
166// write(fd, &c, 1);
167 // give device a chance to get data
168 // wait 0.01 msec
169 // (TODO: seems to be arbitrary to me)
170 if (i)
171 usleep(10);
116 } 172 }
117 } 173 }
118 } 174 }
119 done: 175done:
120 tcsetattr(sfd, TCSANOW, &tiosfd); 176 tcsetattr(sfd, TCSANOW, &tiosfd);
121 tcsetattr(STDIN_FILENO, TCSANOW, &tio0);
122 tcflush(STDIN_FILENO, TCIFLUSH);
123 177
178restore0_close_unlock_and_exit:
179 if (istty) {
180// tcflush(STDIN_FILENO, TCIFLUSH);
181 tcsetattr(STDIN_FILENO, TCSANOW, &tio0);
182 }
183
184close_unlock_and_exit:
124 if (ENABLE_FEATURE_CLEAN_UP) 185 if (ENABLE_FEATURE_CLEAN_UP)
125 close(sfd); 186 close(sfd);
126 exitcode = 0;
127 187
128 unlock_and_exit: 188unlock_and_exit:
129 // delete lock file 189 // delete lock file
130 if (device_lock_file) { 190 if (device_lock_file) {
131 unlink(device_lock_file); 191 unlink(device_lock_file);
132 if (ENABLE_FEATURE_CLEAN_UP) 192 if (ENABLE_FEATURE_CLEAN_UP)
133 free(device_lock_file); 193 free(device_lock_file);
134 } 194 }
135 return exitcode; 195 return signalled;
136} 196}