diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-08 17:30:39 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-08 17:30:39 +0000 |
commit | dc1c45795b36c232fe781962c5fab1df6b8299d9 (patch) | |
tree | 6ca4edb7f27b9521bd70682eb18c6bbf68f3ce6b /miscutils/microcom.c | |
parent | 97bd0e05ccef27563b4403c24952f0abec8eb6cf (diff) | |
download | busybox-w32-dc1c45795b36c232fe781962c5fab1df6b8299d9.tar.gz busybox-w32-dc1c45795b36c232fe781962c5fab1df6b8299d9.tar.bz2 busybox-w32-dc1c45795b36c232fe781962c5fab1df6b8299d9.zip |
microcom: update from maintainer
Diffstat (limited to 'miscutils/microcom.c')
-rw-r--r-- | miscutils/microcom.c | 153 |
1 files changed, 71 insertions, 82 deletions
diff --git a/miscutils/microcom.c b/miscutils/microcom.c index 00a49837e..fb5e9c868 100644 --- a/miscutils/microcom.c +++ b/miscutils/microcom.c | |||
@@ -17,7 +17,7 @@ static void signal_handler(int signo) | |||
17 | signalled = signo; | 17 | signalled = signo; |
18 | } | 18 | } |
19 | 19 | ||
20 | // set canonical tty mode | 20 | // set raw tty mode |
21 | static void xget1(int fd, struct termios *t, struct termios *oldt) | 21 | static void xget1(int fd, struct termios *t, struct termios *oldt) |
22 | { | 22 | { |
23 | tcgetattr(fd, oldt); | 23 | tcgetattr(fd, oldt); |
@@ -32,7 +32,7 @@ static void xget1(int fd, struct termios *t, struct termios *oldt) | |||
32 | 32 | ||
33 | static int xset1(int fd, struct termios *tio, const char *device) | 33 | static int xset1(int fd, struct termios *tio, const char *device) |
34 | { | 34 | { |
35 | int ret = tcsetattr(fd, TCSANOW, tio); | 35 | int ret = tcsetattr(fd, TCSAFLUSH, tio); |
36 | 36 | ||
37 | if (ret) { | 37 | if (ret) { |
38 | bb_perror_msg("can't tcsetattr for %s", device); | 38 | bb_perror_msg("can't tcsetattr for %s", device); |
@@ -43,41 +43,45 @@ static int xset1(int fd, struct termios *tio, const char *device) | |||
43 | int microcom_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 43 | int microcom_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
44 | int microcom_main(int argc, char **argv) | 44 | int microcom_main(int argc, char **argv) |
45 | { | 45 | { |
46 | struct pollfd pfd[2]; | ||
47 | int nfd; | ||
48 | int sfd; | 46 | int sfd; |
49 | /* #define sfd (pfd[0].fd) - gcc 4.2.1 is still not smart enough */ | 47 | int nfd; |
50 | char *device_lock_file; | 48 | struct pollfd pfd[2]; |
51 | const char *opt_s = "9600"; | ||
52 | speed_t speed; | ||
53 | const char *opt_t = "100"; // 0.1 sec timeout | ||
54 | unsigned timeout; | ||
55 | struct termios tio0, tiosfd, tio; | 49 | struct termios tio0, tiosfd, tio; |
56 | bool istty; | 50 | char *device_lock_file; |
51 | enum { | ||
52 | OPT_X = 1 << 0, // do not respect Ctrl-X, Ctrl-@ | ||
53 | OPT_s = 1 << 1, // baudrate | ||
54 | OPT_t = 1 << 2 // wait for device response, msecs | ||
55 | }; | ||
56 | speed_t speed = 9600; | ||
57 | int timeout = 100; // 0.1 sec timeout | ||
57 | 58 | ||
58 | // fetch options | 59 | // fetch options |
59 | opt_complementary = "-1"; /* at least one arg should be there */ | 60 | char *opt_s; |
60 | getopt32(argv, "s:t:", &opt_s, &opt_t); | 61 | char *opt_t; |
61 | argc -= optind; | 62 | unsigned opts; |
63 | opt_complementary = "=1"; /* exactly one arg should be there */ | ||
64 | opts = getopt32(argv, "Xs:t:", &opt_s, &opt_t); | ||
65 | // apply options | ||
66 | if (opts & OPT_s) | ||
67 | speed = xatoi_u(opt_s); | ||
68 | if (opts & OPT_t) | ||
69 | timeout = xatoi_u(opt_t); | ||
70 | // argc -= optind; | ||
62 | argv += optind; | 71 | argv += optind; |
63 | 72 | ||
64 | // check sanity | ||
65 | speed = xatou(opt_s); | ||
66 | timeout = xatou(opt_t); | ||
67 | device_lock_file = (char *)bb_basename(argv[0]); | ||
68 | |||
69 | // try to create lock file in /var/lock | 73 | // try to create lock file in /var/lock |
74 | device_lock_file = (char *)bb_basename(argv[0]); | ||
70 | device_lock_file = xasprintf("/var/lock/LCK..%s", device_lock_file); | 75 | device_lock_file = xasprintf("/var/lock/LCK..%s", device_lock_file); |
71 | sfd = open(device_lock_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644); | 76 | sfd = open(device_lock_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644); |
72 | if (sfd < 0) { | 77 | if (sfd < 0) { |
73 | if (errno == EEXIST) | 78 | if (errno == EEXIST) |
74 | bb_perror_msg_and_die("can't lock device"); | 79 | bb_perror_msg_and_die("can't create %s", device_lock_file); |
75 | // We don't abort on other errors: /var/lock can be | ||
76 | // non-writable or non-existent | ||
77 | if (ENABLE_FEATURE_CLEAN_UP) | 80 | if (ENABLE_FEATURE_CLEAN_UP) |
78 | free(device_lock_file); | 81 | free(device_lock_file); |
79 | device_lock_file = NULL; | 82 | device_lock_file = NULL; |
80 | } else { | 83 | } |
84 | if (sfd > 0) { | ||
81 | // %4d to make mgetty happy. It treats 4-bytes lock files as binary, | 85 | // %4d to make mgetty happy. It treats 4-bytes lock files as binary, |
82 | // not text, PID. Making 5+ char file. Brrr... | 86 | // not text, PID. Making 5+ char file. Brrr... |
83 | char *s = xasprintf("%4d\n", getpid()); | 87 | char *s = xasprintf("%4d\n", getpid()); |
@@ -99,17 +103,15 @@ int microcom_main(int argc, char **argv) | |||
99 | // open device | 103 | // open device |
100 | sfd = open_or_warn(argv[0], O_RDWR | O_NOCTTY | O_NONBLOCK); | 104 | sfd = open_or_warn(argv[0], O_RDWR | O_NOCTTY | O_NONBLOCK); |
101 | if (sfd < 0) | 105 | if (sfd < 0) |
102 | goto unlock_and_exit; | 106 | goto done; |
103 | fcntl(sfd, F_SETFL, O_RDWR | O_NOCTTY); | 107 | fcntl(sfd, F_SETFL, O_RDWR | O_NOCTTY); |
104 | 108 | ||
105 | /* put stdin to "raw mode" (if stdin is a TTY), | 109 | /* put stdin to "raw mode" (if stdin is a TTY), |
106 | handle one character at a time */ | 110 | handle one character at a time */ |
107 | istty = isatty(STDIN_FILENO); | 111 | if (isatty(STDIN_FILENO)) { |
108 | if (istty) { | ||
109 | xget1(STDIN_FILENO, &tio, &tio0); | 112 | xget1(STDIN_FILENO, &tio, &tio0); |
110 | if (xset1(STDIN_FILENO, &tio, "stdin")) | 113 | if (xset1(STDIN_FILENO, &tio, "stdin")) |
111 | goto close_unlock_and_exit; | 114 | goto done; |
112 | // tcflush(STDIN_FILENO, TCIFLUSH); | ||
113 | timeout = -1; // tty input? -> set infinite timeout for poll() | 115 | timeout = -1; // tty input? -> set infinite timeout for poll() |
114 | } | 116 | } |
115 | 117 | ||
@@ -117,10 +119,12 @@ int microcom_main(int argc, char **argv) | |||
117 | xget1(sfd, &tio, &tiosfd); | 119 | xget1(sfd, &tio, &tiosfd); |
118 | // order device to hang up at exit | 120 | // order device to hang up at exit |
119 | tio.c_cflag |= (CREAD|HUPCL); | 121 | tio.c_cflag |= (CREAD|HUPCL); |
122 | // if (!istty) | ||
123 | // tio.c_iflag |= (IGNCR); | ||
120 | // set device speed | 124 | // set device speed |
121 | cfsetspeed(&tio, tty_value_to_baud(speed)); | 125 | cfsetspeed(&tio, tty_value_to_baud(speed)); |
122 | if (xset1(sfd, &tio, argv[0])) | 126 | if (xset1(sfd, &tio, argv[0])) |
123 | goto restore0_close_unlock_and_exit; | 127 | goto restore0_and_done; |
124 | 128 | ||
125 | // main loop: check with poll(), then read/write bytes across | 129 | // main loop: check with poll(), then read/write bytes across |
126 | pfd[0].fd = sfd; | 130 | pfd[0].fd = sfd; |
@@ -128,69 +132,54 @@ int microcom_main(int argc, char **argv) | |||
128 | pfd[1].fd = STDIN_FILENO; | 132 | pfd[1].fd = STDIN_FILENO; |
129 | pfd[1].events = POLLIN; | 133 | pfd[1].events = POLLIN; |
130 | 134 | ||
131 | // TODO: on piped input should we treat NL as CRNL?! | ||
132 | |||
133 | signalled = 0; | 135 | signalled = 0; |
134 | // initially we have to poll() both stdin and device | ||
135 | nfd = 2; | 136 | nfd = 2; |
136 | while (!signalled && nfd && safe_poll(pfd, nfd, timeout) > 0) { | 137 | while (!signalled && safe_poll(pfd, nfd, timeout) > 0) { |
137 | int i; | 138 | char c; |
138 | 139 | if (pfd[0].revents & POLLIN) { | |
139 | for (i = 0; i < nfd; ++i) { | 140 | // read from device -> write to stdout |
140 | if (pfd[i].revents & (POLLIN | POLLHUP)) { | 141 | if (safe_read(sfd, &c, 1) > 0) |
141 | // int fd; | 142 | write(STDOUT_FILENO, &c, 1); |
142 | char c; | 143 | } |
143 | // read a byte | 144 | if (pfd[1].revents & POLLIN) { |
144 | if (safe_read(pfd[i].fd, &c, 1) < 1) { | 145 | // read from stdin -> write to device |
145 | // this can occur at the end of piped input | 146 | if (safe_read(STDIN_FILENO, &c, 1) < 1) { |
146 | // from now we only poll() for device | 147 | // skip polling stdin if we got EOF/error |
147 | nfd--; | 148 | pfd[1].revents = 0; |
149 | nfd--; | ||
150 | continue; | ||
151 | } | ||
152 | // do we need special processing? | ||
153 | if (!(opts & OPT_X)) { | ||
154 | // ^@ sends Break | ||
155 | if (VINTR == c) { | ||
156 | tcsendbreak(sfd, 0); | ||
148 | continue; | 157 | continue; |
149 | } | 158 | } |
150 | // fd = STDOUT_FILENO; | 159 | // ^X exits |
151 | // stdin requires additional processing | 160 | if (24 == c) |
152 | // (TODO: must be controlled by command line switch) | 161 | break; |
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; | ||
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); | ||
172 | } | 162 | } |
163 | write(sfd, &c, 1); | ||
164 | //// vda: this is suspicious! | ||
165 | // without this we never get POLLIN on sfd | ||
166 | // until piped stdin is drained | ||
167 | if (-1 != timeout) | ||
168 | safe_poll(pfd, 1, 1 /* 1 ms */); | ||
173 | } | 169 | } |
174 | } | 170 | } |
175 | done: | 171 | /* usleep(10000); - let last chars leave serial line */ |
176 | tcsetattr(sfd, TCSANOW, &tiosfd); | ||
177 | 172 | ||
178 | restore0_close_unlock_and_exit: | 173 | tcsetattr(sfd, TCSAFLUSH, &tiosfd); |
179 | if (istty) { | ||
180 | // tcflush(STDIN_FILENO, TCIFLUSH); | ||
181 | tcsetattr(STDIN_FILENO, TCSANOW, &tio0); | ||
182 | } | ||
183 | 174 | ||
184 | close_unlock_and_exit: | 175 | restore0_and_done: |
185 | if (ENABLE_FEATURE_CLEAN_UP) | 176 | // timeout == -1 -- stdin is a tty |
186 | close(sfd); | 177 | if (-1 == timeout) |
178 | tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0); | ||
187 | 179 | ||
188 | unlock_and_exit: | 180 | done: |
189 | // delete lock file | 181 | if (device_lock_file) |
190 | if (device_lock_file) { | ||
191 | unlink(device_lock_file); | 182 | unlink(device_lock_file); |
192 | if (ENABLE_FEATURE_CLEAN_UP) | 183 | |
193 | free(device_lock_file); | ||
194 | } | ||
195 | return signalled; | 184 | return signalled; |
196 | } | 185 | } |