source: MondoRescue/branches/3.3/mindi-busybox/miscutils/microcom.c@ 3865

Last change on this file since 3865 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 4.7 KB
RevLine 
[2725]1/* vi: set sw=4 ts=4: */
2/*
3 * bare bones 'talk to modem' program - similar to 'cu -l $device'
4 * inspired by mgetty's microcom
5 *
6 * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
7 *
8 * Licensed under GPLv2, see file LICENSE in this source tree.
9 */
[3232]10
11//usage:#define microcom_trivial_usage
12//usage: "[-d DELAY] [-t TIMEOUT] [-s SPEED] [-X] TTY"
13//usage:#define microcom_full_usage "\n\n"
14//usage: "Copy bytes for stdin to TTY and from TTY to stdout\n"
15//usage: "\n -d Wait up to DELAY ms for TTY output before sending every"
16//usage: "\n next byte to it"
17//usage: "\n -t Exit if both stdin and TTY are silent for TIMEOUT ms"
18//usage: "\n -s Set serial line to SPEED"
19//usage: "\n -X Disable special meaning of NUL and Ctrl-X from stdin"
20
[2725]21#include "libbb.h"
[3621]22#include "common_bufsiz.h"
[2725]23
24// set raw tty mode
25static void xget1(int fd, struct termios *t, struct termios *oldt)
26{
27 tcgetattr(fd, oldt);
28 *t = *oldt;
29 cfmakeraw(t);
30// t->c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
31// t->c_iflag &= ~(BRKINT|IXON|ICRNL);
32// t->c_oflag &= ~(ONLCR);
33// t->c_cc[VMIN] = 1;
34// t->c_cc[VTIME] = 0;
35}
36
37static int xset1(int fd, struct termios *tio, const char *device)
38{
39 int ret = tcsetattr(fd, TCSAFLUSH, tio);
40
41 if (ret) {
42 bb_perror_msg("can't tcsetattr for %s", device);
43 }
44 return ret;
45}
46
47int microcom_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
48int microcom_main(int argc UNUSED_PARAM, char **argv)
49{
50 int sfd;
51 int nfd;
52 struct pollfd pfd[2];
53 struct termios tio0, tiosfd, tio;
54 char *device_lock_file;
55 enum {
56 OPT_X = 1 << 0, // do not respect Ctrl-X, Ctrl-@
57 OPT_s = 1 << 1, // baudrate
58 OPT_d = 1 << 2, // wait for device response, ms
59 OPT_t = 1 << 3, // timeout, ms
60 };
61 speed_t speed = 9600;
62 int delay = -1;
63 int timeout = -1;
64 unsigned opts;
65
66 // fetch options
67 opt_complementary = "=1:s+:d+:t+"; // exactly one arg, numeric options
68 opts = getopt32(argv, "Xs:d:t:", &speed, &delay, &timeout);
69// argc -= optind;
70 argv += optind;
71
72 // try to create lock file in /var/lock
73 device_lock_file = (char *)bb_basename(argv[0]);
74 device_lock_file = xasprintf("/var/lock/LCK..%s", device_lock_file);
75 sfd = open(device_lock_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644);
76 if (sfd < 0) {
77 // device already locked -> bail out
78 if (errno == EEXIST)
79 bb_perror_msg_and_die("can't create '%s'", device_lock_file);
80 // can't create lock -> don't care
81 if (ENABLE_FEATURE_CLEAN_UP)
82 free(device_lock_file);
83 device_lock_file = NULL;
84 } else {
85 // %4d to make concurrent mgetty (if any) happy.
86 // Mgetty treats 4-bytes lock files as binary,
87 // not text, PID. Making 5+ char file. Brrr...
88 fdprintf(sfd, "%4d\n", getpid());
89 close(sfd);
90 }
91
92 // setup signals
93 bb_signals(0
94 + (1 << SIGHUP)
95 + (1 << SIGINT)
96 + (1 << SIGTERM)
97 + (1 << SIGPIPE)
98 , record_signo);
99
100 // error exit code if we fail to open the device
101 bb_got_signal = 1;
102
103 // open device
104 sfd = open_or_warn(argv[0], O_RDWR | O_NOCTTY | O_NONBLOCK);
105 if (sfd < 0)
106 goto done;
107 fcntl(sfd, F_SETFL, O_RDWR);
108
109 // put device to "raw mode"
110 xget1(sfd, &tio, &tiosfd);
111 // set device speed
112 cfsetspeed(&tio, tty_value_to_baud(speed));
113 if (xset1(sfd, &tio, argv[0]))
114 goto done;
115
116 // put stdin to "raw mode" (if stdin is a TTY),
117 // handle one character at a time
118 if (isatty(STDIN_FILENO)) {
119 xget1(STDIN_FILENO, &tio, &tio0);
120 if (xset1(STDIN_FILENO, &tio, "stdin"))
121 goto done;
122 }
123
124 // main loop: check with poll(), then read/write bytes across
125 pfd[0].fd = sfd;
126 pfd[0].events = POLLIN;
127 pfd[1].fd = STDIN_FILENO;
128 pfd[1].events = POLLIN;
129
130 bb_got_signal = 0;
131 nfd = 2;
132 // Not safe_poll: we want to exit on signal
133 while (!bb_got_signal && poll(pfd, nfd, timeout) > 0) {
134 if (nfd > 1 && pfd[1].revents) {
135 char c;
136 // read from stdin -> write to device
137 if (safe_read(STDIN_FILENO, &c, 1) < 1) {
138 // don't poll stdin anymore if we got EOF/error
139 nfd--;
140 goto skip_write;
141 }
142 // do we need special processing?
143 if (!(opts & OPT_X)) {
144 // ^@ sends Break
145 if (VINTR == c) {
146 tcsendbreak(sfd, 0);
147 goto skip_write;
148 }
149 // ^X exits
150 if (24 == c)
151 break;
152 }
153 write(sfd, &c, 1);
154 if (delay >= 0)
155 safe_poll(pfd, 1, delay);
156skip_write: ;
157 }
158 if (pfd[0].revents) {
[3621]159 ssize_t len;
[2725]160#define iobuf bb_common_bufsiz1
[3621]161 setup_common_bufsiz();
[2725]162 // read from device -> write to stdout
[3621]163 len = safe_read(sfd, iobuf, COMMON_BUFSIZE);
[2725]164 if (len > 0)
165 full_write(STDOUT_FILENO, iobuf, len);
166 else {
167 // EOF/error -> bail out
168 bb_got_signal = SIGHUP;
169 break;
170 }
171 }
172 }
173
174 // restore device mode
175 tcsetattr(sfd, TCSAFLUSH, &tiosfd);
176
177 if (isatty(STDIN_FILENO))
178 tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0);
179
180done:
181 if (device_lock_file)
182 unlink(device_lock_file);
183
184 return bb_got_signal;
185}
Note: See TracBrowser for help on using the repository browser.