Introduce old redir program
[lcapit-junk-code.git] / mshell / mshell.c
bloba525c0ebb74ec009cfeefcf730d7fb9faf0306e0
1 /*
2 * mshell.c: A modem shell program.
4 * (yet another small minicom-like program which will become bloat over the
5 * time).
7 * TODO (to make bloat):
9 * 1- Would be cool to have support for internal commands
10 * (eg, to set new memory size);
12 * 2- read_response() sets the timeout using SIGALRM, would be
13 * simpler/better to use select() instead;
15 * 3- Would be good to catch some signals (eg, SIGINT).
17 * 4- The end of input at read_response() is too simple.
19 * Luiz Fernando N. Capitulino
20 * <lcapitulino@gmail.com>
22 #include <stdio.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <signal.h>
29 #include <termios.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <readline/readline.h>
33 #include <readline/history.h>
35 #define MODEM_TIMEOUT 7 /* XXX: Random number */
36 #define DEFAULT_BUFFER 1024
38 static volatile sig_atomic_t timeout;
40 static void handler(int signum)
42 signum = signum;
43 timeout = 1;
44 return;
47 /**
48 * read_response - Reads a modem response
50 * @param fd Modem's file-descriptor
51 * @param buf Buffer to store the response
52 * @param buf_len 'buf' length
54 * @return 0 on success, -1 otherwise
56 static int read_response(int fd, char *buf, size_t buf_len)
58 char *p;
59 size_t len;
60 ssize_t rbytes;
61 int err, ret = -1;
62 struct sigaction new, old;
64 if (fd < 0 || !buf || !buf_len) {
65 errno = EINVAL;
66 return -1;
69 new.sa_handler = handler;
70 sigemptyset(&new.sa_mask);
71 new.sa_flags = 0;
73 timeout = 0;
75 err = sigaction(SIGALRM, &new, &old);
76 if (err)
77 return -1;
79 memset(buf, '\0', buf_len);
80 p = buf;
81 len = buf_len-1; /* Forces '\0' */
83 for (;;) {
84 alarm(MODEM_TIMEOUT);
86 rbytes = read(fd, p, len);
87 if (rbytes < 0) {
88 if (timeout) {
89 errno = ETIMEDOUT;
90 timeout = 0;
92 goto out;
95 alarm(0);
97 if (strstr(buf, "\r\nOK\r\n"))
98 break;
100 if (strstr(buf, "\r\nERROR\r\n"))
101 break;
103 p += rbytes;
104 if (p >= (buf + buf_len -1)) {
105 /* Out of bounds */
106 errno = ENOMEM;
107 goto out;
110 len -= rbytes;
113 ret = 0;
115 out:
116 sigaction(SIGALRM, &old, NULL);
117 return ret;
121 * open_tty - Opens the modem port
123 * Note: All termios settings was taken from 'Advanced programming in the
124 * Unix Environment' book p. 608.
126 * @param tty_port modem's tty port absolute path
128 * @return file decriptor on success, -1 otherwise
130 static int open_tty(const char *tty_port)
132 struct termios term;
133 int berrno, err, fd = -1;
135 if (!tty_port) {
136 errno = EINVAL;
137 goto out;
140 fd = open(tty_port, O_RDWR | O_NOCTTY);
141 if (fd < 0)
142 goto out;
144 err = tcgetattr(fd, &term);
145 if (err)
146 goto out;
149 * Input
151 * Ignore BREAK (XXX: why?).
152 * Enable XON/XOFF flow control.
153 * Strip Input to 7 bits (XXX: why?).
154 * Ignore input parity errors (XXX: why?).
155 * (Note: we are disabling the rest of the options)
157 term.c_iflag = IGNBRK | IXOFF | IXOFF | ISTRIP | IGNPAR;
160 * Output
162 * turn off all output processing.
164 term.c_oflag = 0;
167 * Control
169 * Resets baud rate
171 term.c_cflag &= ~(CSIZE);
174 * Control
176 * Sets 8 bits character.
177 * Enable receiver.
178 * Hang up the modem when last processes closes it.
179 * Ignore modem control lines (it is attached).
181 term.c_cflag |= (CS8 | CREAD | HUPCL | CLOCAL);
184 * Local
186 * Everything off: canonical mode, disables signal
187 * generation, disable ECHO.
189 term.c_lflag = 0;
192 * Local
194 * 1 byte, no timer
196 term.c_cc[VMIN] = 1;
197 term.c_cc[VTIME] = 0;
199 err = cfsetispeed(&term, B115200);
200 if (err)
201 goto out;
203 err = cfsetospeed(&term, B115200);
204 if (err)
205 goto out;
207 err = tcsetattr(fd, TCSANOW, &term);
209 out:
210 if (err && fd >= 0) {
211 berrno = errno;
212 close(fd);
213 fd = -1;
214 errno = berrno;
217 return fd;
221 * __send_command - Sends a command to the modem
223 * @param fd Modem's file-descriptor
224 * @param cmd command to be sent
225 * @param cmd_len 'cmd' length
227 * @return 0 on success, -1 otheriwse
229 static int __send_command(int fd, char *cmd, size_t cmd_len)
231 char *p;
232 size_t len;
233 ssize_t wbytes;
235 if (fd < 0 || !cmd || !cmd_len) {
236 errno = EINVAL;
237 return -1;
240 p = cmd;
241 len = cmd_len;
243 while (len) {
244 wbytes = write(fd, p, len);
245 if (wbytes < 0)
246 return -1;
248 p += wbytes;
249 len -= wbytes;
252 return 0;
256 * send_command - Sends a command to the modem
258 * @param fd Modem's file-descriptor
259 * @param cmd command to be sent
261 * @return 0 on success, -1 otheriwse
263 static int send_command(int fd, char *cmd)
265 int err;
267 if (fd < 0 || !cmd) {
268 errno = EINVAL;
269 return -1;
272 err = __send_command(fd, cmd, strlen(cmd));
273 if (err)
274 return -1;
276 err = __send_command(fd, "\r\n", 2);
277 if (err)
278 return -1;
280 return 0;
283 static void usage(void)
285 printf(
286 "Usage: mshell < port_name > [ -s ] [ < file ]\n"
290 int main(int argc, char *argv[])
292 int err, fd;
293 int silent = 0;
294 char *cmd, buf[DEFAULT_BUFFER];
296 if (argc < 2 || argc > 3) {
297 fprintf(stderr, "Invalid number of parameters!\n");
298 usage();
299 exit(1);
302 if (argc == 3) {
303 if (!strcmp(argv[1], "-s") || !strcmp(argv[2], "-s")) {
304 silent = 1;
305 } else {
306 fprintf(stderr, "Error: option not recognized!\n");
307 usage();
308 exit(1);
312 fd = open_tty(argv[1]);
313 if (fd < 0) {
314 perror("Error: cannot open modem's port");
315 exit(1);
318 if (!silent) {
319 printf("\nDefault settings:\n");
320 printf(" response buffer %d bytes\n", DEFAULT_BUFFER);
321 printf(" modem's timeout in %d seconds\n\n", MODEM_TIMEOUT);
324 for (;;) {
325 cmd = readline("mshell> ");
326 if (!cmd) {
327 /* Probably EOF */
328 break;
331 err = send_command(fd, cmd);
332 if (err) {
333 perror("Error: cannot send command");
334 exit(1);
337 free(cmd);
339 err = read_response(fd, buf, sizeof(buf));
340 if (err)
341 perror("Cannot read response");
342 else
343 printf("%s", buf);
346 printf("\n");
347 exit(0);