├── ubus.h ├── ubus_loop.h ├── .gitignore ├── CMakeLists.txt ├── seriald.h ├── README.md ├── fdio.h ├── ubus.c ├── ubus_loop.c ├── fdio.c ├── seriald.c ├── term.h ├── term.c └── LICENSE /ubus.h: -------------------------------------------------------------------------------- 1 | #ifndef __SERIALD_UBUS_H 2 | #define __SERIALD_UBUS_H 3 | 4 | void seriald_ubus_run(const char *sock); 5 | 6 | #endif /* __SERIALD_UBUS_H */ 7 | -------------------------------------------------------------------------------- /ubus_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef __SERIALD_UBUS_LOOP_H 2 | #define __SERIALD_UBUS_LOOP_H 3 | 4 | int seriald_ubus_loop_init(const char *sock); 5 | void seriald_ubus_loop_done(void); 6 | void *seriald_ubus_loop(void *unused); 7 | void seriald_ubus_loop_stop(void); 8 | 9 | #endif /* __SERIALD_UBUS_LOOP_H */ 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | *.su 34 | 35 | .*.swp 36 | .orig 37 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | PROJECT(seriald C) 4 | ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations) 5 | 6 | SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") 7 | 8 | FIND_LIBRARY(ubox_library NAMES ubox) 9 | FIND_PATH(ubox_include_dir libubox/usock.h) 10 | INCLUDE_DIRECTORIES(${ubox_include_dir}) 11 | 12 | FIND_LIBRARY(blob_library NAMES blobmsg_json) 13 | FIND_LIBRARY(ubus NAMES ubus) 14 | 15 | ADD_EXECUTABLE(seriald seriald.c term.c fdio.c ubus.c ubus_loop.c) 16 | TARGET_LINK_LIBRARIES(seriald ${ubus} ${ubox_library} ${blob_library}) 17 | 18 | INSTALL(TARGETS seriald 19 | RUNTIME DESTINATION sbin 20 | ) 21 | -------------------------------------------------------------------------------- /seriald.h: -------------------------------------------------------------------------------- 1 | #ifndef __SERIALD_H 2 | #define __SERIALD_H 3 | 4 | #include 5 | 6 | #define DPRINTF(format, ...) fprintf(stderr, "%s(%d): " format, __func__, __LINE__, ## __VA_ARGS__) 7 | 8 | #ifndef TTY_Q_SZ 9 | #define TTY_Q_SZ 1024 10 | #endif 11 | 12 | #define TTY_RD_SZ 256 13 | 14 | extern char ubus_path[]; 15 | 16 | struct tty_q { 17 | int len; 18 | char buff[TTY_Q_SZ]; 19 | } tty_q; 20 | 21 | extern struct tty_q tty_q; 22 | extern pthread_mutex_t tty_q_mutex; 23 | void fatal(const char *format, ...); 24 | 25 | extern int sig_exit; 26 | 27 | extern int efd_notify_tty; 28 | extern int efd_signal; 29 | extern int ubus_pipefd[]; 30 | 31 | #endif /* __SERIALD_H */ 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # seriald 2 | 3 | seriald is a high performance deamon which manages a serial port as well as provides the OpenWrt ubus interface for IPC. The binary size is only 21 kB. 4 | 5 | ## Usage 6 | 7 | ### Run daemon 8 | 9 | ``` 10 | seriald /dev/ttyS0 11 | ``` 12 | 13 | Can run multiple daemons on different device nodes. 14 | 15 | #### Options 16 | 17 | See 18 | 19 | ``` 20 | seriald -h 21 | ``` 22 | 23 | ### Read from serial port 24 | 25 | Command: 26 | 27 | ``` 28 | ubus listen serial.ttyS0 29 | ``` 30 | 31 | Result: 32 | 33 | ``` 34 | { "serial.ttyS0": {"data":""} } 35 | ``` 36 | 37 | `` is a line read from the serial port. All the `CR` (`\r`) and `LF` (`\n`) characters will be eliminated from it. 38 | 39 | ### Write to serial port 40 | 41 | ``` 42 | ubus call serial.ttyS0 send '{"data": ""}' 43 | ``` 44 | 45 | `data` is a fixed attribute. To send a message to the serial port, replace `` with the message you want to send. 46 | An `` will be appended an `LF` (`\n`) character at the end before seriald passes it to the serial port. 47 | 48 | ## License 49 | 50 | Except where otherwise noted, all parts of this software is licensed under [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html). 51 | This work is based on [picocom](https://github.com/npat-efault/picocom), which is licensed under [GPLv2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html). 52 | -------------------------------------------------------------------------------- /fdio.h: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: 2 | * 3 | * fdio.h 4 | * 5 | * Functions for doing I/O on file descriptors. 6 | * 7 | * by Nick Patavalis (npat@efault.net) 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as 11 | * published by the Free Software Foundation; either version 2 of the 12 | * License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, but 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 22 | * USA 23 | */ 24 | 25 | #ifndef FDIO_H 26 | 27 | ssize_t writen_ni(int fd, const void *buff, size_t n); 28 | 29 | int fd_printf (int fd, const char *format, ...); 30 | 31 | #ifndef LINENOISE 32 | 33 | int fd_readline (int fdi, int fdo, char *b, int bsz); 34 | 35 | #endif 36 | 37 | #endif /* of FDIO_H */ 38 | 39 | /**********************************************************************/ 40 | 41 | /* 42 | * Local Variables: 43 | * mode:c 44 | * tab-width: 4 45 | * c-basic-offset: 4 46 | * indent-tabs-mode: nil 47 | * End: 48 | */ 49 | -------------------------------------------------------------------------------- /ubus.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "seriald.h" 8 | #include "ubus.h" 9 | 10 | static void seriald_ubus_send_event(const char *json); 11 | static void ubus_send_event_line_splitter(const int n, const char *buff_rd); 12 | 13 | static struct ubus_context *ubus_ctx = NULL; 14 | static struct blob_buf b; 15 | static const char *ubus_sock; 16 | 17 | static void seriald_ubus_send_event(const char *json) 18 | { 19 | blob_buf_init(&b, 0); 20 | 21 | if (!blobmsg_add_json_from_string(&b, json)) { 22 | DPRINTF("cannot parse data for ubus send event\n"); 23 | return; 24 | } 25 | 26 | if (ubus_send_event(ubus_ctx, ubus_path, b.head)) { 27 | ubus_free(ubus_ctx); 28 | ubus_ctx = ubus_connect(ubus_sock); 29 | ubus_send_event(ubus_ctx, ubus_path, b.head); 30 | } 31 | } 32 | 33 | static void ubus_send_event_line_splitter(const int n, const char *buff_rd) 34 | { 35 | static char buff[TTY_RD_SZ*2+1] = ""; 36 | static int buff_len = 0; 37 | const char *p; 38 | 39 | p = buff_rd; 40 | 41 | while (p - buff_rd < n) { 42 | if (buff_len == sizeof(buff) - 1) { 43 | seriald_ubus_send_event(buff); 44 | *buff = '\0'; 45 | buff_len = 0; 46 | } 47 | if (*p && *p != '\r' && *p != '\n') { 48 | buff[buff_len] = *p; 49 | buff[++buff_len] = '\0'; 50 | } else if ((!*p || *p == '\n') && buff_len > 0) { 51 | seriald_ubus_send_event(buff); 52 | *buff = '\0'; 53 | buff_len = 0; 54 | } 55 | p++; 56 | } 57 | } 58 | 59 | void seriald_ubus_run(const char *sock) 60 | { 61 | fd_set rdset; 62 | int r; 63 | int n; 64 | char buff_rd[TTY_RD_SZ*2]; 65 | int max_fd; 66 | eventfd_t efd_value; 67 | 68 | ubus_sock = sock; 69 | max_fd = (efd_signal > ubus_pipefd[0]) ? efd_signal : ubus_pipefd[0]; 70 | 71 | ubus_ctx = ubus_connect(ubus_sock); 72 | if (!ubus_ctx) { 73 | fatal("cannot connect to ubus"); 74 | } 75 | 76 | while (!sig_exit) { 77 | FD_ZERO(&rdset); 78 | FD_SET(efd_signal, &rdset); 79 | FD_SET(ubus_pipefd[0], &rdset); 80 | 81 | r = select(max_fd + 1, &rdset, NULL, NULL, NULL); 82 | if (r < 0) { 83 | if (errno == EINTR) continue; 84 | else fatal("select failed: %d : %s", errno, strerror(errno)); 85 | } 86 | 87 | if (FD_ISSET(ubus_pipefd[0], &rdset)) { 88 | /* read from pipe */ 89 | do { 90 | n = read(ubus_pipefd[0], &buff_rd, sizeof(buff_rd)); 91 | } while (n < 0 && errno == EINTR); 92 | if (n == 0) { 93 | fatal("pipe closed"); 94 | } else if (n < 0) { 95 | if (errno != EAGAIN && errno != EWOULDBLOCK) 96 | fatal("read from pipe failed: %s", strerror(errno)); 97 | } else { 98 | ubus_send_event_line_splitter(n, buff_rd); 99 | } 100 | } 101 | 102 | if (FD_ISSET(efd_signal, &rdset)) { 103 | /* Being self-piped */ 104 | if (eventfd_read(efd_signal, &efd_value)) { 105 | fatal("failed to read efd_signal"); 106 | } 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /ubus_loop.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "seriald.h" 14 | #include "ubus_loop.h" 15 | 16 | static struct ubus_context *ubus_ctx = NULL; 17 | static const char *ubus_sock; 18 | 19 | static void seriald_ubus_add_fd(void); 20 | static void seriald_ubus_connection_lost_cb(struct ubus_context *ctx); 21 | static void seriald_ubus_reconnect_timer(struct uloop_timeout *timeout); 22 | static int seriald_send_data(struct ubus_context *ctx, struct ubus_object *obj, 23 | struct ubus_request_data *req, const char *method, struct blob_attr *msg); 24 | 25 | enum { 26 | DATA_DATA, 27 | __DATA_MAX 28 | }; 29 | 30 | static const struct blobmsg_policy data_policy[__DATA_MAX] = { 31 | [DATA_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING }, 32 | }; 33 | 34 | static struct ubus_method seriald_object_methods[] = { 35 | UBUS_METHOD("send", seriald_send_data, data_policy), 36 | }; 37 | 38 | static struct ubus_object_type seriald_object_type = 39 | UBUS_OBJECT_TYPE(ubus_path, seriald_object_methods); 40 | 41 | static struct ubus_object seriald_object = { 42 | .name = ubus_path, 43 | .type = &seriald_object_type, 44 | .methods = seriald_object_methods, 45 | .n_methods = ARRAY_SIZE(seriald_object_methods), 46 | }; 47 | 48 | static int seriald_send_data( 49 | struct ubus_context *ctx, struct ubus_object *obj, 50 | struct ubus_request_data *req, const char *method, struct blob_attr *msg) 51 | { 52 | struct blob_attr *tb[__DATA_MAX]; 53 | int len; 54 | 55 | blobmsg_parse(data_policy, __DATA_MAX, tb, blob_data(msg), blob_len(msg)); 56 | if (!tb[DATA_DATA]) return UBUS_STATUS_INVALID_ARGUMENT; 57 | 58 | const char *data = blobmsg_get_string(tb[DATA_DATA]); 59 | len = strlen(data); 60 | 61 | pthread_mutex_lock(&tty_q_mutex); 62 | if (tty_q.len + len < TTY_Q_SZ) { 63 | memmove(tty_q.buff + tty_q.len, data, len); 64 | tty_q.len += len; 65 | tty_q.buff[tty_q.len] = '\n'; 66 | ++tty_q.len; 67 | eventfd_write(efd_notify_tty, 1); 68 | } 69 | pthread_mutex_unlock(&tty_q_mutex); 70 | 71 | return UBUS_STATUS_OK; 72 | } 73 | 74 | static void seriald_ubus_reconnect_timer(struct uloop_timeout *timeout) 75 | { 76 | static struct uloop_timeout retry = { 77 | .cb = seriald_ubus_reconnect_timer, 78 | }; 79 | int t = 2; 80 | 81 | if (ubus_reconnect(ubus_ctx, ubus_sock)) { 82 | DPRINTF("failed to reconnect, trying again in %d seconds\n", t); 83 | uloop_timeout_set(&retry, t * 1000); 84 | return; 85 | } 86 | 87 | DPRINTF("reconnected to ubus, new id: %08x\n", ubus_ctx->local_id); 88 | seriald_ubus_add_fd(); 89 | } 90 | 91 | static void seriald_ubus_connection_lost_cb(struct ubus_context *ctx) 92 | { 93 | seriald_ubus_reconnect_timer(NULL); 94 | } 95 | 96 | static void seriald_ubus_add_fd(void) 97 | { 98 | ubus_add_uloop(ubus_ctx); 99 | fcntl(ubus_ctx->sock.fd, F_SETFD, 100 | fcntl(ubus_ctx->sock.fd, F_GETFD) | FD_CLOEXEC); 101 | } 102 | 103 | int seriald_ubus_loop_init(const char *sock) 104 | { 105 | int r; 106 | 107 | uloop_init(); 108 | ubus_sock = sock; 109 | 110 | ubus_ctx = ubus_connect(sock); 111 | if (!ubus_ctx) { 112 | DPRINTF("cannot connect to ubus\n"); 113 | return -EIO; 114 | } 115 | 116 | DPRINTF("connected as %08x\n", ubus_ctx->local_id); 117 | ubus_ctx->connection_lost = seriald_ubus_connection_lost_cb; 118 | seriald_ubus_add_fd(); 119 | 120 | r = ubus_add_object(ubus_ctx, &seriald_object); 121 | if (r) { 122 | DPRINTF("Failed to add object: %s\n", ubus_strerror(r)); 123 | return r; 124 | } 125 | 126 | return 0; 127 | } 128 | 129 | void *seriald_ubus_loop(void *unused) 130 | { 131 | uloop_run(); 132 | return 0; 133 | } 134 | 135 | void seriald_ubus_loop_done(void) 136 | { 137 | ubus_free(ubus_ctx); 138 | } 139 | 140 | void seriald_ubus_loop_stop(void) 141 | { 142 | uloop_end(); 143 | } 144 | -------------------------------------------------------------------------------- /fdio.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: 2 | * 3 | * fdio.c 4 | * 5 | * Functions for doing I/O on file descriptors. 6 | * 7 | * by Nick Patavalis (npat@efault.net) 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as 11 | * published by the Free Software Foundation; either version 2 of the 12 | * License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, but 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 22 | * USA 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "fdio.h" 32 | 33 | /**********************************************************************/ 34 | 35 | ssize_t 36 | writen_ni(int fd, const void *buff, size_t n) 37 | { 38 | size_t nl; 39 | ssize_t nw; 40 | const char *p; 41 | 42 | p = buff; 43 | nl = n; 44 | while (nl > 0) { 45 | do { 46 | nw = write(fd, p, nl); 47 | } while ( nw < 0 && errno == EINTR ); 48 | if ( nw <= 0 ) break; 49 | nl -= nw; 50 | p += nw; 51 | } 52 | 53 | return n - nl; 54 | } 55 | 56 | int 57 | fd_printf (int fd, const char *format, ...) 58 | { 59 | char buf[256]; 60 | va_list args; 61 | int len; 62 | 63 | va_start(args, format); 64 | len = vsnprintf(buf, sizeof(buf), format, args); 65 | buf[sizeof(buf) - 1] = '\0'; 66 | va_end(args); 67 | 68 | return writen_ni(fd, buf, len); 69 | } 70 | 71 | /**********************************************************************/ 72 | 73 | #ifndef LINENOISE 74 | 75 | static int 76 | cput(int fd, char c) 77 | { 78 | return write(fd, &c, 1); 79 | } 80 | 81 | static int 82 | cdel (int fd) 83 | { 84 | const char del[] = "\b \b"; 85 | return write(fd, del, sizeof(del) - 1); 86 | } 87 | 88 | static int 89 | xput (int fd, unsigned char c) 90 | { 91 | const char hex[] = "0123456789abcdef"; 92 | char b[4]; 93 | 94 | b[0] = '\\'; b[1] = 'x'; b[2] = hex[c >> 4]; b[3] = hex[c & 0x0f]; 95 | return write(fd, b, sizeof(b)); 96 | } 97 | 98 | static int 99 | xdel (int fd) 100 | { 101 | const char del[] = "\b\b\b\b \b\b\b\b"; 102 | return write(fd, del, sizeof(del) - 1); 103 | } 104 | 105 | int 106 | fd_readline (int fdi, int fdo, char *b, int bsz) 107 | { 108 | int r; 109 | unsigned char c; 110 | unsigned char *bp, *bpe; 111 | 112 | bp = (unsigned char *)b; 113 | bpe = (unsigned char *)b + bsz - 1; 114 | 115 | while (1) { 116 | r = read(fdi, &c, 1); 117 | if ( r <= 0 ) { r = -1; goto out; } 118 | 119 | switch (c) { 120 | case '\b': 121 | case '\x7f': 122 | if ( bp > (unsigned char *)b ) { 123 | bp--; 124 | if ( isprint(*bp) ) 125 | cdel(fdo); 126 | else 127 | xdel(fdo); 128 | } else { 129 | cput(fdo, '\x07'); 130 | } 131 | break; 132 | case '\x03': /* CTRL-c */ 133 | r = -1; 134 | errno = EINTR; 135 | goto out; 136 | case '\r': 137 | *bp = '\0'; 138 | r = bp - (unsigned char *)b; 139 | goto out; 140 | default: 141 | if ( bp < bpe ) { 142 | *bp++ = c; 143 | if ( isprint(c) ) 144 | cput(fdo, c); 145 | else 146 | xput(fdo, c); 147 | } else { 148 | cput(fdo, '\x07'); 149 | } 150 | break; 151 | } 152 | } 153 | 154 | out: 155 | return r; 156 | } 157 | 158 | #endif /* of LINENOISE */ 159 | 160 | /**********************************************************************/ 161 | 162 | /* 163 | * Local Variables: 164 | * mode:c 165 | * tab-width: 4 166 | * c-basic-offset: 4 167 | * indent-tabs-mode: nil 168 | * End: 169 | */ 170 | -------------------------------------------------------------------------------- /seriald.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "fdio.h" 16 | #include "seriald.h" 17 | #include "term.h" 18 | #include "ubus.h" 19 | #include "ubus_loop.h" 20 | 21 | int efd_notify_tty = -1; 22 | int efd_signal = -1; 23 | int ubus_pipefd[2]; 24 | static int fd_tty; 25 | 26 | #define STO STDOUT_FILENO 27 | #define STI STDIN_FILENO 28 | #define TTY_WRITE_SZ_DIV 10 29 | #define TTY_WRITE_SZ_MIN 8 30 | int tty_write_sz; 31 | #define set_tty_write_sz(baud) \ 32 | do { \ 33 | tty_write_sz = (baud) / TTY_WRITE_SZ_DIV; \ 34 | if (tty_write_sz < TTY_WRITE_SZ_MIN) tty_write_sz = TTY_WRITE_SZ_MIN; \ 35 | } while (0) 36 | struct tty_q tty_q; 37 | pthread_mutex_t tty_q_mutex; 38 | 39 | int sig_exit = 0; 40 | 41 | static struct { 42 | char port[128]; 43 | int baud; 44 | enum flowcntrl_e flow; 45 | enum parity_e parity; 46 | int databits; 47 | int stopbits; 48 | int noreset; 49 | char *socket; 50 | } opts = { 51 | .port = "", 52 | .baud = 115200, 53 | .flow = FC_NONE, 54 | .parity = P_NONE, 55 | .databits = 8, 56 | .stopbits = 1, 57 | .noreset = 0, 58 | .socket = NULL, /* the library fall back to default socket when it is NULL */ 59 | }; 60 | 61 | char ubus_path[sizeof("serial.")+sizeof(opts.port)]; 62 | 63 | static void show_usage(void); 64 | static void parse_args(int argc, char *argv[]); 65 | static void deadly_handler(int signum); 66 | static void register_signal_handlers(void); 67 | static void loop(void); 68 | static void tty_read_line_splitter(const int n, const char *buff_rd); 69 | static void tty_read_line_cb(const char *line); 70 | int main(int argc, char *argv[]); 71 | 72 | static void show_usage() 73 | { 74 | printf("Usage: seriald [options] \n"); 75 | printf("\n"); 76 | printf("Options:\n"); 77 | printf(" -b \n"); 78 | printf(" baudrate should be one of: 0, 50, 75, 110, 134, 150, 200, 300, 600,\n"); 79 | printf(" 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400\n"); 80 | printf(" default to 115200\n"); 81 | printf(" -f s (=soft) | h (=hard) | n (=none)\n"); 82 | printf(" default to n\n"); 83 | printf(" -s \n"); 84 | printf(" no need to give if you use the default one\n"); 85 | printf("\n"); 86 | printf("Examples:\n"); 87 | printf(" Get data:\n"); 88 | printf(" ubus listen serial\n"); 89 | printf(" Send data (replace with the data you want to send):\n"); 90 | printf(" ubus call serial send '{\"data\": \"\"}'\n"); 91 | } 92 | 93 | void fatal(const char *format, ...) 94 | { 95 | char *s, buf[256]; 96 | va_list args; 97 | int len; 98 | 99 | va_start(args, format); 100 | len = vsnprintf(buf, sizeof(buf), format, args); 101 | buf[sizeof(buf)-1] = '\0'; 102 | va_end(args); 103 | 104 | s = "\r\nFATAL: "; 105 | writen_ni(STO, s, strlen(s)); 106 | writen_ni(STO, buf, len); 107 | s = "\r\n"; 108 | writen_ni(STO, s, strlen(s)); 109 | 110 | /* wait a bit for output to drain */ 111 | sleep(1); 112 | 113 | exit(EXIT_FAILURE); 114 | } 115 | 116 | static void parse_args(int argc, char *argv[]) 117 | { 118 | int c; 119 | int r = 0; 120 | 121 | while ((c = getopt(argc, argv, "hf:b:s:")) != -1) { 122 | switch (c) { 123 | case 'f': 124 | switch (optarg[0]) { 125 | case 'X': 126 | case 'x': 127 | opts.flow = FC_XONXOFF; 128 | break; 129 | case 'H': 130 | case 'h': 131 | opts.flow = FC_RTSCTS; 132 | break; 133 | case 'N': 134 | case 'n': 135 | opts.flow = FC_NONE; 136 | break; 137 | default: 138 | DPRINTF("Invalid flow control: %c\n", optarg[0]); 139 | r = -1; 140 | break; 141 | } 142 | break; 143 | case 'b': 144 | opts.baud = atoi(optarg); 145 | if (opts.baud == 0 || !term_baud_ok(opts.baud)) { 146 | DPRINTF("Invalid baud rate: %d\n", opts.baud); 147 | r = -1; 148 | } 149 | break; 150 | case 's': 151 | opts.socket = optarg; 152 | break; 153 | case 'h': 154 | r = 1; 155 | break; 156 | default: 157 | r = -1; 158 | break; 159 | } 160 | } 161 | 162 | if (r) { 163 | show_usage(); 164 | exit((r > 0) ? EXIT_SUCCESS : EXIT_FAILURE); 165 | } 166 | 167 | if ((argc - optind) < 1) { 168 | DPRINTF("No port given\n"); 169 | show_usage(); 170 | exit(EXIT_FAILURE); 171 | } 172 | 173 | strncpy(opts.port, argv[optind], sizeof(opts.port) - 1); 174 | opts.port[sizeof(opts.port)-1] = '\0'; 175 | } 176 | 177 | static void deadly_handler(int signum) 178 | { 179 | DPRINTF("seriald is signaled with TERM\n"); 180 | if (!sig_exit) { 181 | seriald_ubus_loop_stop(); 182 | sig_exit = 1; 183 | if (efd_notify_tty >= 0) eventfd_write(efd_notify_tty, 1); 184 | if (efd_signal >= 0) eventfd_write(efd_signal, 1); 185 | } 186 | } 187 | 188 | static void register_signal_handlers(void) 189 | { 190 | struct sigaction exit_action, ign_action; 191 | 192 | /* Set up the structure to specify the exit action. */ 193 | exit_action.sa_handler = deadly_handler; 194 | sigemptyset (&exit_action.sa_mask); 195 | exit_action.sa_flags = 0; 196 | 197 | /* Set up the structure to specify the ignore action. */ 198 | ign_action.sa_handler = SIG_IGN; 199 | sigemptyset (&ign_action.sa_mask); 200 | ign_action.sa_flags = 0; 201 | 202 | sigaction(SIGTERM, &exit_action, NULL); 203 | 204 | sigaction(SIGALRM, &ign_action, NULL); 205 | sigaction(SIGHUP, &ign_action, NULL); 206 | sigaction(SIGINT, &ign_action, NULL); 207 | sigaction(SIGPIPE, &ign_action, NULL); 208 | sigaction(SIGQUIT, &ign_action, NULL); 209 | sigaction(SIGUSR1, &ign_action, NULL); 210 | sigaction(SIGUSR2, &ign_action, NULL); 211 | } 212 | 213 | static void loop(void) 214 | { 215 | fd_set rdset, wrset; 216 | int r; 217 | int n; 218 | char buff_rd[TTY_RD_SZ]; 219 | int write_sz; 220 | int max_fd; 221 | eventfd_t efd_value; 222 | 223 | max_fd = (fd_tty > efd_notify_tty) ? fd_tty : efd_notify_tty; 224 | tty_q.len = 0; 225 | 226 | while (!sig_exit) { 227 | FD_ZERO(&rdset); 228 | FD_ZERO(&wrset); 229 | FD_SET(fd_tty, &rdset); 230 | FD_SET(efd_notify_tty, &rdset); 231 | 232 | pthread_mutex_lock(&tty_q_mutex); 233 | if (tty_q.len) FD_SET(fd_tty, &wrset); 234 | pthread_mutex_unlock(&tty_q_mutex); 235 | 236 | r = select(max_fd + 1, &rdset, &wrset, NULL, NULL); 237 | if (r < 0) { 238 | if (errno == EINTR) continue; 239 | else fatal("select failed: %d : %s", errno, strerror(errno)); 240 | } 241 | 242 | if (FD_ISSET(fd_tty, &rdset)) { 243 | /* read from port */ 244 | do { 245 | n = read(fd_tty, &buff_rd, sizeof(buff_rd)); 246 | } while (n < 0 && errno == EINTR); 247 | if (n == 0) { 248 | fatal("term closed"); 249 | } else if (n < 0) { 250 | if (errno != EAGAIN && errno != EWOULDBLOCK) 251 | fatal("read from term failed: %s", strerror(errno)); 252 | } else { 253 | tty_read_line_splitter(n, buff_rd); 254 | } 255 | } 256 | 257 | if (FD_ISSET(efd_notify_tty, &rdset)) { 258 | /* Being notified we have something to write to TTY */ 259 | if (eventfd_read(efd_notify_tty, &efd_value)) { 260 | fatal("failed to read efd_notify_tty"); 261 | } 262 | } 263 | 264 | if (FD_ISSET(fd_tty, &wrset)) { 265 | /* write to port */ 266 | pthread_mutex_lock(&tty_q_mutex); 267 | write_sz = (tty_q.len < tty_write_sz) ? tty_q.len : tty_write_sz; 268 | do { 269 | n = write(fd_tty, tty_q.buff, write_sz); 270 | } while (n < 0 && errno == EINTR); 271 | if (n <= 0) fatal("write to term failed: %s", strerror(errno)); 272 | memmove(tty_q.buff, tty_q.buff + n, tty_q.len - n); 273 | tty_q.len -= n; 274 | pthread_mutex_unlock(&tty_q_mutex); 275 | } 276 | } 277 | } 278 | 279 | static void tty_read_line_splitter(const int n, const char *buff_rd) 280 | { 281 | static char buff[TTY_RD_SZ+1] = ""; 282 | static int buff_len = 0; 283 | const char *p; 284 | 285 | p = buff_rd; 286 | 287 | while (p - buff_rd < n) { 288 | if (buff_len == sizeof(buff) - 1) { 289 | tty_read_line_cb(buff); 290 | *buff = '\0'; 291 | buff_len = 0; 292 | } 293 | if (*p && *p != '\r' && *p != '\n') { 294 | buff[buff_len] = *p; 295 | buff[++buff_len] = '\0'; 296 | } else if ((!*p || *p == '\n') && buff_len > 0) { 297 | tty_read_line_cb(buff); 298 | *buff = '\0'; 299 | buff_len = 0; 300 | } 301 | p++; 302 | } 303 | } 304 | 305 | static void tty_read_line_cb(const char *line) 306 | { 307 | char format[] = "{\"data\": \"%s\"}\n"; 308 | char json[sizeof(format)+TTY_RD_SZ]; 309 | char *p; 310 | int n; 311 | int sz; 312 | 313 | sprintf(json, format, line); 314 | p = json; 315 | sz = strlen(json); 316 | 317 | while (sz > 0) { 318 | do { 319 | n = write(ubus_pipefd[1], p, sz); 320 | } while (n < 0 && errno == EINTR); 321 | if (n <= 0) fatal("write to pipe failed: %s", strerror(errno)); 322 | p += n; 323 | sz -= n; 324 | } 325 | } 326 | 327 | int main(int argc, char *argv[]) 328 | { 329 | int r; 330 | pthread_t uloop_tid; 331 | 332 | parse_args(argc, argv); 333 | register_signal_handlers(); 334 | sprintf(ubus_path, "serial.%s", basename(opts.port)); 335 | 336 | r = pipe2(ubus_pipefd, O_CLOEXEC); 337 | if (r < 0) fatal("cannot create pipe to ubus: %s", strerror(errno)); 338 | 339 | /* Seems like you cannot have multiple ubus connections in single process. */ 340 | /* So we fork. */ 341 | switch(fork()) { 342 | case 0: 343 | efd_signal = eventfd(0, EFD_CLOEXEC); 344 | if (efd_signal < 0) { 345 | fatal("cannot create efd_signal: %s", strerror(errno)); 346 | } 347 | close(ubus_pipefd[1]); 348 | seriald_ubus_run(opts.socket); 349 | return EXIT_SUCCESS; 350 | case -1: 351 | fatal("cannot fork ubus_event_loop"); 352 | } 353 | 354 | close(ubus_pipefd[0]); 355 | 356 | efd_notify_tty = eventfd(0, EFD_CLOEXEC); 357 | if (efd_notify_tty < 0) { 358 | fatal("cannot create efd_notify_tty: %s", strerror(errno)); 359 | } 360 | 361 | r = term_lib_init(); 362 | if (r < 0) fatal("term_init failed: %s", term_strerror(term_errno, errno)); 363 | 364 | fd_tty = open(opts.port, O_RDWR | O_NONBLOCK | O_NOCTTY); 365 | if (fd_tty < 0) fatal("cannot open %s: %s", opts.port, strerror(errno)); 366 | 367 | r = term_set(fd_tty, 368 | 1, /* raw mode. */ 369 | opts.baud, /* baud rate. */ 370 | opts.parity, /* parity. */ 371 | opts.databits, /* data bits. */ 372 | opts.stopbits, /* stop bits. */ 373 | opts.flow, /* flow control. */ 374 | 1, /* local or modem */ 375 | !opts.noreset); /* hup-on-close. */ 376 | if (r < 0) { 377 | fatal("failed to add device %s: %s", 378 | opts.port, term_strerror(term_errno, errno)); 379 | } 380 | 381 | r = term_apply(fd_tty, 0); 382 | if (r < 0) { 383 | fatal("failed to config device %s: %s", 384 | opts.port, term_strerror(term_errno, errno)); 385 | } 386 | 387 | set_tty_write_sz(term_get_baudrate(fd_tty, NULL)); 388 | 389 | r = seriald_ubus_loop_init(opts.socket); 390 | if (r) fatal("failed to connect to ubus"); 391 | 392 | r = pthread_create(&uloop_tid, NULL, &seriald_ubus_loop, NULL); 393 | if (r) fatal("can't create thread for uloop: %s", strerror(r)); 394 | 395 | loop(); 396 | 397 | seriald_ubus_loop_done(); 398 | return EXIT_SUCCESS; 399 | } 400 | -------------------------------------------------------------------------------- /term.h: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: 2 | * 3 | * term.h 4 | * 5 | * Simple terminal management library. Wraps termios(3), and 6 | * simplifies the logistics required for the reliable management and 7 | * control of terminals. 8 | * 9 | * Principles of operation: 10 | * 11 | * After the library is initialized, one or more file-descriptors can 12 | * be added to (and latter removed from) the list managed by the 13 | * it. These file descriptors must be opened on terminal devices. For 14 | * every fd, the original settings of the associated terminal device 15 | * are saved by the library. These settings are restored when the fd 16 | * is removed from the framework, or at program termination [by means 17 | * of an atexit(3) handler installed by the library], or at user 18 | * request. The library maintains three structures for every fd in the 19 | * framework: The original settings structure ("origtermios"), keeping 20 | * the settings of the terminal device when the respective filedes was 21 | * added to the framework. The current settings structure 22 | * ("currtermios"), keeping the current settings of the associated 23 | * terminal device; and the next settings structure ("nexttermios") 24 | * which keeps settings to be applied to the associated terminal 25 | * device at a latter time, upon user request. The "term_set_*" 26 | * functions can be used to modify the device settings stored in the 27 | * nexttermios structure. Using functions provided by the library the 28 | * user can: Apply the nexttermios settings to the device. Revert all 29 | * changes made on nexttermios by copying the currtermios structure to 30 | * nexttermios. Reset the device, by configuring it to the original 31 | * settings, and copying origtermios to currtermios and 32 | * nexttermios. Refresh the device by rereading the current settings 33 | * from it and updating currtermios (to catch up with changes made to 34 | * the device by means outside of this framework). 35 | * 36 | * Interface summary: 37 | * 38 | * F term_lib_init - library initialization 39 | * F term_add - add a filedes to the framework 40 | * F term_remove - remove a filedes from the framework 41 | * F term_erase - remove a filedes from the framework without reset 42 | * F term_replace - replace a fd w/o affecting the settings stuctures 43 | * F term_reset - revert a device to the settings in "origtermios" 44 | * F term_apply - configure a device to the settings in "nexttermios" 45 | * F term_revert - discard "nexttermios" by copying-over "currtermios" 46 | * F term_refresh - update "currtermios" from the device 47 | * F term_set_raw - set "nexttermios" to raw mode 48 | * F term_set_baudrate - set the baudrate in "nexttermios" 49 | * F term_set_parity - set the parity mode in "nexttermios" 50 | * F term_set_databits - set the databits in "nexttermios" 51 | * F term_set_stopbits - set the stopbits in "nexttermios" 52 | * F term_set_flowcntrl - set the flowcntl mode in "nexttermios" 53 | * F term_set_hupcl - enable or disable hupcl in "nexttermios" 54 | * F term_set_local - set "nexttermios" to local or non-local mode 55 | * F term_set - set all params of "nexttermios" in a single stroke 56 | * F term_get_baudrate - return the baudrate set in "currtermios" 57 | * F term_get_parity - return the parity setting in "currtermios" 58 | * F term_get_databits - return the data-bits setting in "currtermios" 59 | * F term_get_flowcntrl - return the flow-control setting in "currtermios" 60 | * F term_pulse_dtr - pulse the DTR line a device 61 | * F term_lower_dtr - lower the DTR line of a device 62 | * F term_raise_dtr - raise the DTR line of a device 63 | * F term_get_mctl - Get modem control signals status 64 | * F term_drain - drain the output from the terminal buffer 65 | * F term_flush - discard terminal input and output queue contents 66 | * F term_break - generate a break condition on a device 67 | * F term_baud_up - return next higher baudrate 68 | * F term_baud_down - return next lower baudrate 69 | * F term_baud_ok - check if baudrate is valid 70 | * F term_strerror - return a string describing current error condition 71 | * F term_perror - print a string describing the current error condition 72 | * G term_errno - current error condition of the library 73 | * E term_errno_e - error condition codes 74 | * E parity_t - library supported parity types 75 | * E flocntrl_t - library supported folw-control modes 76 | * M MAX_TERM - maximum number of fds that can be managed 77 | * 78 | * by Nick Patavalis (npat@inaccessnetworks.com) 79 | * 80 | * originaly by Pantelis Antoniou (panto@intranet.gr), Nick Patavalis 81 | * 82 | * This program is free software; you can redistribute it and/or 83 | * modify it under the terms of the GNU General Public License as 84 | * published by the Free Software Foundation; either version 2 of the 85 | * License, or (at your option) any later version. 86 | * 87 | * This program is distributed in the hope that it will be useful, but 88 | * WITHOUT ANY WARRANTY; without even the implied warranty of 89 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 90 | * General Public License for more details. 91 | * 92 | * You should have received a copy of the GNU General Public License 93 | * along with this program; if not, write to the Free Software 94 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 95 | * USA 96 | * 97 | * $Id: term.h,v 1.1 2003/05/07 18:00:05 npat Exp $ 98 | */ 99 | 100 | 101 | #ifndef TERM_H 102 | #define TERM_H 103 | 104 | /* M MAX_TERMS 105 | * 106 | * Maximum nuber of terminals that can be managed by the library. Keep 107 | * relatively low, since linear searches are used. Reasonable values 108 | * would be: 16, 32, 64, etc. 109 | */ 110 | #define MAX_TERMS 16 111 | 112 | /* 113 | * E term_errno_e 114 | * 115 | * Library error-condition codes. These marked with "see errno" 116 | * correspond to system errors, so it makes sense to also check the 117 | * system's error-condition code (errno) in order to fully determine 118 | * what went wrong. 119 | * 120 | * See the error strings in "term.c" for a description of each. 121 | */ 122 | enum term_errno_e { 123 | TERM_EOK = 0, 124 | TERM_ENOINIT, 125 | TERM_EFULL, 126 | TERM_ENOTFOUND, 127 | TERM_EEXISTS, 128 | TERM_EATEXIT, 129 | TERM_EISATTY, 130 | TERM_EFLUSH, /* see errno */ 131 | TERM_EGETATTR, /* see errno */ 132 | TERM_ESETATTR, /* see errno */ 133 | TERM_EBAUD, 134 | TERM_ESETOSPEED, 135 | TERM_ESETISPEED, 136 | TERM_EGETSPEED, 137 | TERM_EPARITY, 138 | TERM_EDATABITS, 139 | TERM_ESTOPBITS, 140 | TERM_EFLOW, 141 | TERM_EDTRDOWN, 142 | TERM_EDTRUP, 143 | TERM_EMCTL, 144 | TERM_EDRAIN, /* see errno */ 145 | TERM_EBREAK 146 | }; 147 | 148 | /* E parity_e 149 | * 150 | * Parity modes supported by the library: 151 | * 152 | * P_NONE - no patiry 153 | * P_EVEN - even parity 154 | * P_ODD - odd parity 155 | * P_MARK - mark parity (parity bit always 1) 156 | * P_SPACE - space parity (parity bit always 0) 157 | */ 158 | enum parity_e { 159 | P_NONE = 0, 160 | P_EVEN, 161 | P_ODD, 162 | P_MARK, 163 | P_SPACE 164 | }; 165 | 166 | /* 167 | * E flowcntrl_e 168 | * 169 | * Flow control modes, supported by the library. 170 | * 171 | * FC_NONE - no flow control 172 | * FC_RTSCTS - RTS/CTS handshaking, also known as hardware 173 | * flow-control. 174 | * FC_XONXOFF - xon/xoff flow control. 175 | */ 176 | enum flowcntrl_e { 177 | FC_NONE = 0, 178 | FC_RTSCTS, 179 | FC_XONXOFF, 180 | FC_OTHER 181 | }; 182 | 183 | /* 184 | * C MCTL_xxx 185 | * 186 | * Modem control line bits. Used against the return value of 187 | * term_get_mctl(). 188 | */ 189 | #define MCTL_DTR (1<<1) /* O: Data Terminal Ready */ 190 | #define MCTL_DSR (1<<2) /* I: Data Set Ready */ 191 | #define MCTL_DCD (1<<3) /* I: Data Carrier Detect */ 192 | #define MCTL_RTS (1<<4) /* O: Request To Send */ 193 | #define MCTL_CTS (1<<5) /* I: Clear To Send */ 194 | #define MCTL_RI (1<<6) /* I: Ring Indicator */ 195 | #define MCTL_UNAVAIL (1<<0) /* MCTL lines (status) not available */ 196 | 197 | /***************************************************************************/ 198 | 199 | /* 200 | * G term_errno 201 | * 202 | * Keeps the current library error-condtion code 203 | */ 204 | extern int term_errno; 205 | 206 | /***************************************************************************/ 207 | 208 | /* 209 | * F term_strerror 210 | * 211 | * Return a string descibing the current library error condition. If 212 | * the error condition reflects a system error, then the respective 213 | * system-error description is appended at the end of the returned 214 | * string. The returned string points to a statically allocated buffer 215 | * that is overwritten with every call to term_strerror() 216 | * 217 | * Returns a string describing the current library (and possibly 218 | * system) error condition. 219 | */ 220 | const char *term_strerror (int terrnum, int errnum); 221 | 222 | /* 223 | * F term_perror 224 | * 225 | * Emit a description of the current library (and possibly system) 226 | * error condition to the standard-error stream. The description is 227 | * prefixed by a user-supplied string. What is actually emmited is: 228 | * 229 | * \n 230 | * 231 | * The description emitted is the string returned by term_strerror(). 232 | * 233 | * Returns the number of characters emmited to the standard-error 234 | * stream or a neagative on failure. 235 | */ 236 | int term_perror (const char *prefix); 237 | 238 | /* F term_lib_init 239 | * 240 | * Initialize the library 241 | * 242 | * Initialize the library. This function must be called before any 243 | * attemt to use the library. If this function is called and the 244 | * library is already initialized, all terminals associated with the 245 | * file-descriptors in the framework will be reset to their original 246 | * settings, and the file-descriptors will be removed from the 247 | * framework. An atexit(3) handler is installed by the library which 248 | * resets and removes all managed terminals. 249 | * 250 | * Returns negative on failure, non-negative on success. This function 251 | * will only fail if the atexit(3) handler cannot be 252 | * installed. Failure to reset a terminal to the original settings is 253 | * not considered an error. 254 | */ 255 | int term_lib_init (void); 256 | 257 | /* F term_add 258 | * 259 | * Add the filedes "fd" to the framework. The filedes must be opened 260 | * on a terminal device or else the addition will fail. The settings 261 | * of the terminal device associated with the filedes are read and 262 | * stored in the origtermios structure. 263 | * 264 | * Returns negative on failure, non-negative on success. 265 | */ 266 | int term_add (int fd); 267 | 268 | /* F term_remove 269 | * 270 | * Remove the filedes "fd" from the framework. The device associated 271 | * with the filedes is reset to its original settings (those it had 272 | * when it was added to the framework) 273 | * 274 | * Return negative on failure, non-negative on success. The filedes is 275 | * always removed form the framework even if this function returns 276 | * failure, indicating that the device reset failed. 277 | */ 278 | int term_remove (int fd); 279 | 280 | /* F term_erase 281 | * 282 | * Remove the filedes "fd" from the framework. The device associated 283 | * with the filedes is *not* reset to its original settings. 284 | * 285 | * Return negative on failure, non-negative on success. The only 286 | * reason for failure is the filedes not to be found. 287 | */ 288 | int term_erase (int fd); 289 | 290 | /* F term_replace 291 | * 292 | * Replace a managed filedes without affecting the associated settings 293 | * structures. The "newfd" takes the place of "oldfd". "oldfd" is 294 | * removed from the framework without the associated device beign 295 | * reset (it is most-likely no longer connected to a device anyway, 296 | * and reset would fail). The device associated with "newfd" is 297 | * configured with "oldfd"s current settings (stored in the 298 | * "currtermios" structure). After applying the settings to "newfd", 299 | * the "currtermios" structure is re-read from the device, so that it 300 | * corresponds to the actual device settings. 301 | * 302 | * Returns negative on failure, non-negative on success. In case of 303 | * failure "oldfd" is not removed from the framework, and no 304 | * replacement takes place. 305 | * 306 | * The usual reason to replace the filedes of a managed terminal is 307 | * because the device was closed and re-opened. This function gives 308 | * you a way to do transparent "open"s and "close"s: Before you close 309 | * a device, it has certain settings managed by the library. When you 310 | * close it and then re-open it many of these settings are lost, since 311 | * the device reverts to system-default settings. By calling 312 | * term_replace, you conceptually _maintain_ the old (pre-close) 313 | * settings to the new (post-open) filedes. 314 | */ 315 | int term_replace (int oldfd, int newfd); 316 | 317 | /* 318 | * F term_apply 319 | * 320 | * Applies the settings stored in the "nexttermios" structure 321 | * associated with the managed filedes "fd", to the respective 322 | * terminal device. It then re-reads the settings form the device and 323 | * stores them in "nexttermios". Finally it copies "nexttermios" to 324 | * "currtermios". If "now" is not zero, settings are applied 325 | * immediatelly, otherwise setting are applied after the output 326 | * buffers are drained and the input buffers are discarder. In this 327 | * sense, term_apply(fd, 0) is equivalent to: term_drain(fd); 328 | * term_flush(fd); term_apply(fd, 1); 329 | * 330 | * Returns negative on failure, non negative on success. In case of 331 | * failure the "nexttermios" and "currtermios" structures are not 332 | * affected. 333 | */ 334 | int term_apply (int fd, int now); 335 | 336 | /* 337 | * F term_revert 338 | * 339 | * Discards all the changes made to the nexttermios structure 340 | * associated with the managed filedes "fd" that have not been applied 341 | * to the device. It does this by copying currtermios to nexttermios. 342 | * 343 | * Returns negative on failure, non negative on success. Returns 344 | * failure only to indicate invalid arguments, so the return value can 345 | * be safely ignored. 346 | */ 347 | int term_revert (int fd); 348 | 349 | /* F term_reset 350 | * 351 | * Reset the terminal device associated with the managed filedes "fd" 352 | * to its "original" settings. This function applies the settings in 353 | * the "origtermios" structure to the actual device. It then reads the 354 | * settings from the device and stores them in both the "currtermios" 355 | * and "nexttermios" stuctures. 356 | * 357 | * Returns negative on failure, non-negative of success. On failure 358 | * the the "origtermios", "currtermios", and "nexttermios" stuctures 359 | * associated with the filedes remain unaffected. 360 | */ 361 | int term_reset (int fd); 362 | 363 | /* 364 | * F term_refresh 365 | * 366 | * Updates the contents of the currtermios structure associated with 367 | * the managed filedes "fd", by reading the settings from the 368 | * respective terminal device. 369 | * 370 | * Returns negative on failure, non negative on success. On failure 371 | * the currtermios structure remains unaffected. 372 | */ 373 | int term_refresh (int fd); 374 | 375 | /* F term_set_raw 376 | * 377 | * Sets the "nexttermios" structure associated with the managed 378 | * filedes "fd" to raw mode. The effective settings of the device are 379 | * not affected by this function. 380 | * 381 | * Returns negative on failure, non-negative on success. Returns 382 | * failure only to indicate invalid arguments, so the return value can 383 | * be safely ignored. 384 | * 385 | * When in raw mode, no characters are processed by the terminal 386 | * driver and there is no line-discipline or buffering. More 387 | * technically setting to raw mode means, affecting the following 388 | * terminal settings as indicated: 389 | * 390 | * -ignbrk -brkint -parmrk -istrip -inlcr -igncr -icrnl -ixon 391 | * -opost -echo -echonl -icannon -isig -iexten -csize -parenb 392 | * cs8 min=1 time=0 393 | */ 394 | int term_set_raw (int fd); 395 | 396 | /* F term_set_baudrate 397 | * 398 | * Sets the baudrate in the "nexttermios" structure associated with 399 | * the managed filedes "fd" to "baudrate". The effective settings of 400 | * the device are not affected by this function. 401 | * 402 | * Supported baudrates: 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 403 | * 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400 404 | * 405 | * Returns negative on failure, non negative on success. Returns 406 | * failure only to indicate invalid arguments, so the return value can 407 | * be safely ignored. 408 | */ 409 | int term_set_baudrate (int fd, int baudrate); 410 | 411 | /* F term_set_parity 412 | * 413 | * Sets the parity mode in the "nexttermios" structure associated with 414 | * the managed filedes "fd" to "parity". The effective settings of the 415 | * device are not affected by this function. 416 | * 417 | * Supported parity modes are: p_even, p_odd, p_none. 418 | * 419 | * Returns negative on failure, non negative on success. Returns 420 | * failure only to indicate invalid arguments, so the return value can 421 | * be safely ignored. 422 | */ 423 | int term_set_parity (int fd, enum parity_e parity); 424 | 425 | /* F term_set_databits 426 | * 427 | * Sets the databits number in the "nexttermios" structure associated 428 | * with the managed filedes "fd" to "databits". The effective settings 429 | * of the device are not affected by this function. 430 | * 431 | * 5, 6, 7, and 8 databits are supported by the library. 432 | * 433 | * Returns negative on failure, non negative on success. Returns 434 | * failure only to indicate invalid arguments, so the return value can 435 | * be safely ignored. 436 | */ 437 | int term_set_databits (int fd, int databits); 438 | 439 | /* F term_set_stopbits 440 | * 441 | * Sets the stopbits number in the "nexttermios" structure associated 442 | * with the managed filedes "fd" to "stopbits". The effective settings 443 | * of the device are not affected by this function. 444 | * 445 | * 1 and 2 stopbits are supported by the library. 446 | * 447 | * Returns negative on failure, non negative on success. Returns 448 | * failure only to indicate invalid arguments, so the return value can 449 | * be safely ignored. 450 | */ 451 | int term_set_stopbits (int fd, int stopbits); 452 | 453 | /* F term_set_flowcntrl 454 | * 455 | * Sets the folwcontrol mode in the "nexttermios" structure associated 456 | * with the managed filedes "fd" to "flowcntl". The effective settings 457 | * of the device are not affected by this function. 458 | * 459 | * The following flow control modes are supportd by the library: 460 | * FC_NONE, FC_RTSCTS, FC_XONXOFF. 461 | * 462 | * Returns negative on failure, non negative on success. Returns 463 | * failure only to indicate invalid arguments, so the return value can 464 | * be safely ignored. 465 | */ 466 | int term_set_flowcntrl (int fd, enum flowcntrl_e flowcntl); 467 | 468 | /* F term_set_hupcl 469 | * 470 | * Enables ("on" = nonzero) or disables ("on" = zero) the 471 | * "HUP-on-close" setting in the "nexttermios" structure associated 472 | * with the managed filedes "fd". The effective settings of the device 473 | * are not affected by this function. 474 | * 475 | * Returns negative on failure, non negative on success. Returns 476 | * failure only to indicate invalid arguments, so the return value can 477 | * be safely ignored. 478 | */ 479 | int term_set_hupcl (int fd, int on); 480 | 481 | /* F term_set_local. 482 | * 483 | * Enables ("local" = nonzero) or disables ("local" = zero) the 484 | * "local-mode" setting in the "nexttermios" structure associated with 485 | * the managed filedes "fd". The effective settings of the device are 486 | * not affected by this function. 487 | * 488 | * Returns negative on failure, non negative on success. Returns 489 | * failure only to indicate invalid arguments, so the return value can 490 | * be safely ignored. 491 | */ 492 | int term_set_local (int fd, int local); 493 | 494 | /* F temr_set 495 | * 496 | * Sets most of the parameters in the "nexttermios" structure 497 | * associated with the managed filedes "fd". Actually sets the 498 | * following: 499 | * 500 | * Raw mode if "raw" is nonzero. 501 | * Baudrate to "baud". 502 | * Parity mode to "parity". 503 | * Flow control mode to "fc". 504 | * Enables local mode if "local" is nonzero, dis. otherwise. 505 | * Enables HUP-on-close if "hupcl" is nonzero, dis. otherwise 506 | * 507 | * The effective settings of the device are not affected by this 508 | * function. Additionally if the filedes "fd" is not managed, it is 509 | * added to the framework. 510 | * 511 | * Returns negative on failure, non negative on success. On failure 512 | * none of the settings of "nexttermios" is affected. *If* the filedes 513 | * "fd" is already in the framework, then the function returns failure 514 | * only to indicate invalid arguments, so, in this case, the return 515 | * value can be safely ignored. If the function successfully adds the 516 | * filedes to the framework, and following this it fails, then it will 517 | * remove the filedes before returning. 518 | */ 519 | int term_set (int fd, 520 | int raw, 521 | int baud, 522 | enum parity_e parity, 523 | int databits, int stopbits, 524 | enum flowcntrl_e fc, 525 | int local, int hupcl); 526 | 527 | /* F term_get_baudrate 528 | * 529 | * Reads and decodes the current baudrate settings in the 530 | * "currtermios" structure of the managed filedes "fd". 531 | * 532 | * Returns the decoded output baudrate (as bits-per-second), or -1 if 533 | * the output baudrate cannot be decoded, or if "fd" does not 534 | * correspond to a managed filedes. If "ispeed" is not NULL, it writes 535 | * the decoded input baudrate to the integer pointed-to by "ispeed"; 536 | * if the input baudrate cannot be decoded in writes -1 instead. 537 | */ 538 | int term_get_baudrate (int fd, int *ispeed); 539 | 540 | /* F term_get_parity 541 | * 542 | * Reads and decodes the current parity settings in the 543 | * "currtermios" structure of the managed filedes "fd". 544 | * 545 | * Returns one of the "enum parity_e" members, or -1 if "fd" does not 546 | * correspond to a managed filedes. 547 | */ 548 | enum parity_e term_get_parity (int fd); 549 | 550 | /* F term_get_databits 551 | * 552 | * Reads and decodes the current databits settings in the 553 | * "currtermios" structure of the managed filedes "fd". 554 | * 555 | * Returns the number of databits (5..8), or -1 if "fd" does not 556 | * correspond to a managed filedes. 557 | */ 558 | int term_get_databits (int fd); 559 | 560 | /* F term_get_stopbits 561 | * 562 | * Reads and decodes the current stopbits settings in the 563 | * "currtermios" structure of the managed filedes "fd". 564 | * 565 | * Returns the number of databits (1 or 2), or -1 if "fd" does not 566 | * correspond to a managed filedes. 567 | */ 568 | int term_get_stopbits (int fd); 569 | 570 | /* F term_get_flowcntrl 571 | * 572 | * Reads and decodes the current flow-control settings in the 573 | * "currtermios" structure of the managed filedes "fd". 574 | * 575 | * Returns one of the "enum flowcntrl_e" members, or -1 if "fd" does 576 | * not correspond to a managed filedes. 577 | */ 578 | enum flowcntrl_e term_get_flowcntrl (int fd); 579 | 580 | /* F term_pulse_dtr 581 | * 582 | * Pulses the DTR line of the device associated with the managed 583 | * filedes "fd". The DTR line is lowered for 1sec and then raised 584 | * again. 585 | * 586 | * Returns negative on failure, non negative on success. 587 | */ 588 | int term_pulse_dtr (int fd); 589 | 590 | /* F term_lower_dtr 591 | * 592 | * Lowers the DTR line of the device associated with the managed 593 | * filedes "fd". 594 | * 595 | * Returns negative on failure, non negative on success. 596 | */ 597 | int term_lower_dtr (int fd); 598 | 599 | /* F term_raise_dtr 600 | * 601 | * Raises the DTR line of the device associated with the managed 602 | * filedes "fd". 603 | * 604 | * Returns negative on failure, non negative on success. 605 | */ 606 | int term_raise_dtr (int fd); 607 | 608 | /* F term_get_mctl 609 | * 610 | * Get the status of the modem control lines of the serial port 611 | * (terminal) associated with the managed filedes "fd". 612 | * 613 | * On error (fd is not managed) return a negative. If the feature is 614 | * not available returns MCTL_UNAVAIL. Otherwise returns a word that 615 | * can be checked against the MCTL_* flags. 616 | */ 617 | int term_get_mctl (int fd); 618 | 619 | /* F term_drain 620 | * 621 | * Drains (flushes) the output queue of the device associated with the 622 | * managed filedes "fd". This functions blocks until all the contents 623 | * of output queue have been transmited. 624 | * 625 | * Returns negative on failure, non negative on success. 626 | */ 627 | int term_drain (int fd); 628 | 629 | /* F term_flush 630 | * 631 | * Discards all the contents of the input AND output queues of the 632 | * device associated with the managed filedes "fd". Although it is 633 | * called flush this functions does NOT FLUSHES the terminal 634 | * queues. It just DISCARDS their contents. The name has stuck from 635 | * the POSIX terminal call: "tcflush". 636 | * 637 | * Returns negative on failure, non negative on success. 638 | */ 639 | int term_flush (int fd); 640 | 641 | /* F term_break 642 | * 643 | * This function generates a break condition on the device associated 644 | * with the managed filedes "fd", by transmiting a stream of 645 | * zero-bits. The stream of zero-bits has a duriation typically 646 | * between 0.25 and 0.5 seconds. 647 | * 648 | * Returns negative on failure, non negative on success. 649 | */ 650 | int term_break(int fd); 651 | 652 | /***************************************************************************/ 653 | 654 | /* F term_baud_up 655 | * 656 | * Returns the next higher valid baudrate. Returns "baud" if there is 657 | * no higher valid baudrate. 658 | */ 659 | int term_baud_up (int baud); 660 | 661 | 662 | /* F term_baud_down 663 | * 664 | * Returns the next lower valid baudrate. Returns "baud" if there is 665 | * no lower valid baudrate. 666 | */ 667 | int term_baud_down (int baud); 668 | 669 | /* F term_baud_ok 670 | * 671 | * Returns non-zero if "baud" is a valid baudrate, zero otherwise. 672 | */ 673 | int term_baud_ok(int baud); 674 | 675 | /***************************************************************************/ 676 | 677 | #endif /* of TERM_H */ 678 | 679 | /***************************************************************************/ 680 | 681 | /* 682 | * Local Variables: 683 | * mode:c 684 | * tab-width: 4 685 | * c-basic-offset: 4 686 | * End: 687 | */ 688 | -------------------------------------------------------------------------------- /term.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: 2 | * 3 | * term.c 4 | * 5 | * General purpose terminal handling library. 6 | * 7 | * Nick Patavalis (npat@inaccessnetworks.com) 8 | * 9 | * originaly by Pantelis Antoniou (panto@intranet.gr), Nick Patavalis 10 | * 11 | * Documentation can be found in the header file "term.h". 12 | * 13 | * This program is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU General Public License as 15 | * published by the Free Software Foundation; either version 2 of the 16 | * License, or (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, but 19 | * WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 26 | * USA 27 | * 28 | * $Id$ 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | /* glibc for MIPS has its own bits/termios.h which does not define 39 | * CMSPAR, so we use the value from the generic bits/termios.h 40 | */ 41 | #ifdef __linux__ 42 | #ifndef CMSPAR 43 | #define CMSPAR 010000000000 44 | #endif 45 | #endif 46 | 47 | /* Some BSDs (and possibly other systems too) have no mark / space 48 | * parity support, and they don't define CMSPAR. Use a zero CMSPAR in 49 | * these cases. If the user tries to set P_MARK or P_SPACE he will get 50 | * P_EVEN or P_ODD instead. */ 51 | #ifndef CMSPAR 52 | #define CMSPAR 0 53 | #endif 54 | 55 | #ifdef __linux__ 56 | #include 57 | #endif 58 | 59 | #ifdef USE_CUSTOM_BAUD 60 | /* only works for linux, recent kernels */ 61 | #include "termios2.h" 62 | #endif 63 | 64 | #include "term.h" 65 | 66 | /***************************************************************************/ 67 | 68 | static struct term_s { 69 | int init; 70 | int fd[MAX_TERMS]; 71 | struct termios origtermios[MAX_TERMS]; 72 | struct termios currtermios[MAX_TERMS]; 73 | struct termios nexttermios[MAX_TERMS]; 74 | } term; 75 | 76 | /***************************************************************************/ 77 | 78 | int term_errno; 79 | 80 | static const char * const term_err_str[] = { 81 | [TERM_EOK] = "No error", 82 | [TERM_ENOINIT] = "Framework is uninitialized", 83 | [TERM_EFULL] = "Framework is full", 84 | [TERM_ENOTFOUND] = "Filedes not in the framework", 85 | [TERM_EEXISTS] = "Filedes already in the framework", 86 | [TERM_EATEXIT] = "Cannot install atexit handler", 87 | [TERM_EISATTY] = "Filedes is not a tty", 88 | [TERM_EFLUSH] = "Cannot flush the device", 89 | [TERM_EGETATTR] = "Cannot get the device attributes", 90 | [TERM_ESETATTR] = "Cannot set the device attributes", 91 | [TERM_EBAUD] = "Invalid baud rate", 92 | [TERM_ESETOSPEED] = "Cannot set the output speed", 93 | [TERM_ESETISPEED] = "Cannot set the input speed", 94 | [TERM_EGETSPEED] = "Cannot decode speed", 95 | [TERM_EPARITY] = "Invalid parity mode", 96 | [TERM_EDATABITS] = "Invalid number of databits", 97 | [TERM_ESTOPBITS] = "Invalid number of stopbits", 98 | [TERM_EFLOW] = "Invalid flowcontrol mode", 99 | [TERM_EDTRDOWN] = "Cannot lower DTR", 100 | [TERM_EDTRUP] = "Cannot raise DTR", 101 | [TERM_EMCTL] = "Cannot get mctl status", 102 | [TERM_EDRAIN] = "Cannot drain the device", 103 | [TERM_EBREAK] = "Cannot send break sequence" 104 | }; 105 | 106 | static char term_err_buff[1024]; 107 | 108 | const char * 109 | term_strerror (int terrnum, int errnum) 110 | { 111 | const char *rval; 112 | 113 | switch(terrnum) { 114 | case TERM_EFLUSH: 115 | case TERM_EGETATTR: 116 | case TERM_ESETATTR: 117 | case TERM_ESETOSPEED: 118 | case TERM_ESETISPEED: 119 | case TERM_EDRAIN: 120 | case TERM_EBREAK: 121 | snprintf(term_err_buff, sizeof(term_err_buff), 122 | "%s: %s", term_err_str[terrnum], strerror(errnum)); 123 | rval = term_err_buff; 124 | break; 125 | case TERM_EOK: 126 | case TERM_ENOINIT: 127 | case TERM_EFULL: 128 | case TERM_ENOTFOUND: 129 | case TERM_EEXISTS: 130 | case TERM_EATEXIT: 131 | case TERM_EISATTY: 132 | case TERM_EBAUD: 133 | case TERM_EPARITY: 134 | case TERM_EDATABITS: 135 | case TERM_ESTOPBITS: 136 | case TERM_EFLOW: 137 | case TERM_EDTRDOWN: 138 | case TERM_EDTRUP: 139 | case TERM_EMCTL: 140 | snprintf(term_err_buff, sizeof(term_err_buff), 141 | "%s", term_err_str[terrnum]); 142 | rval = term_err_buff; 143 | break; 144 | default: 145 | rval = NULL; 146 | break; 147 | } 148 | 149 | return rval; 150 | } 151 | 152 | int 153 | term_perror (const char *prefix) 154 | { 155 | return fprintf(stderr, "%s %s\n", 156 | prefix, term_strerror(term_errno, errno)); 157 | } 158 | 159 | /***************************************************************************/ 160 | 161 | #define BNONE 0xFFFFFFFF 162 | 163 | struct baud_codes { 164 | int speed; 165 | speed_t code; 166 | } baud_table[] = { 167 | { 0, B0 }, 168 | { 50, B50 }, 169 | { 75, B75 }, 170 | { 110, B110 }, 171 | { 134, B134 }, 172 | { 150, B150 }, 173 | { 200, B200 }, 174 | { 300, B300 }, 175 | { 600, B600 }, 176 | { 1200, B1200 }, 177 | { 1800, B1800 }, 178 | { 2400, B2400 }, 179 | { 4800, B4800 }, 180 | { 9600, B9600 }, 181 | { 19200, B19200 }, 182 | { 38400, B38400 }, 183 | { 57600, B57600 }, 184 | { 115200, B115200 }, 185 | #ifdef HIGH_BAUD 186 | #ifdef B230400 187 | { 230400, B230400 }, 188 | #endif 189 | #ifdef B460800 190 | { 460800, B460800 }, 191 | #endif 192 | #ifdef B500000 193 | { 500000, B500000 }, 194 | #endif 195 | #ifdef B576000 196 | { 576000, B576000 }, 197 | #endif 198 | #ifdef B921600 199 | { 921600, B921600 }, 200 | #endif 201 | #ifdef B1000000 202 | { 1000000, B1000000 }, 203 | #endif 204 | #ifdef B1152000 205 | { 1152000, B1152000 }, 206 | #endif 207 | #ifdef B1500000 208 | { 1500000, B1500000 }, 209 | #endif 210 | #ifdef B2000000 211 | { 2000000, B2000000 }, 212 | #endif 213 | #ifdef B2500000 214 | { 2500000, B2500000 }, 215 | #endif 216 | #ifdef B3000000 217 | { 3000000, B3000000 }, 218 | #endif 219 | #ifdef B3500000 220 | { 3500000, B3500000 }, 221 | #endif 222 | #ifdef B4000000 223 | { 4000000, B4000000 }, 224 | #endif 225 | #endif /* of HIGH_BAUD */ 226 | }; 227 | 228 | #define BAUD_TABLE_SZ (sizeof(baud_table) / sizeof(baud_table[0])) 229 | 230 | int 231 | term_baud_up (int baud) 232 | { 233 | int i; 234 | 235 | for (i = 0; i < BAUD_TABLE_SZ; i++) { 236 | if ( baud >= baud_table[i].speed ) 237 | continue; 238 | else { 239 | baud = baud_table[i].speed; 240 | break; 241 | } 242 | } 243 | 244 | return baud; 245 | } 246 | 247 | int 248 | term_baud_down (int baud) 249 | { 250 | int i; 251 | 252 | for (i = BAUD_TABLE_SZ - 1; i >= 0; i--) { 253 | if ( baud <= baud_table[i].speed ) 254 | continue; 255 | else { 256 | baud = baud_table[i].speed; 257 | break; 258 | } 259 | } 260 | 261 | return baud; 262 | } 263 | 264 | static speed_t 265 | Bcode(int speed) 266 | { 267 | speed_t code = BNONE; 268 | int i; 269 | 270 | for (i = 0; i < BAUD_TABLE_SZ; i++) { 271 | if ( baud_table[i].speed == speed ) { 272 | code = baud_table[i].code; 273 | break; 274 | } 275 | } 276 | return code; 277 | } 278 | 279 | static int 280 | Bspeed(speed_t code) 281 | { 282 | int speed = -1, i; 283 | 284 | for (i = 0; i < BAUD_TABLE_SZ; i++) { 285 | if ( baud_table[i].code == code ) { 286 | speed = baud_table[i].speed; 287 | break; 288 | } 289 | } 290 | return speed; 291 | } 292 | 293 | int 294 | term_baud_ok(int baud) 295 | { 296 | #ifndef USE_CUSTOM_BAUD 297 | return (Bcode(baud) != BNONE) ? 1 : 0; 298 | #else 299 | return (baud >= 0); 300 | #endif 301 | } 302 | 303 | /**************************************************************************/ 304 | 305 | static int 306 | term_find_next_free (void) 307 | { 308 | int rval, i; 309 | 310 | do { /* dummy */ 311 | if ( ! term.init ) { 312 | term_errno = TERM_ENOINIT; 313 | rval = -1; 314 | break; 315 | } 316 | 317 | for (i = 0; i < MAX_TERMS; i++) 318 | if ( term.fd[i] == -1 ) break; 319 | 320 | if ( i == MAX_TERMS ) { 321 | term_errno = TERM_EFULL; 322 | rval = -1; 323 | break; 324 | } 325 | 326 | rval = i; 327 | } while (0); 328 | 329 | return rval; 330 | } 331 | 332 | /***************************************************************************/ 333 | 334 | static int 335 | term_find (int fd) 336 | { 337 | int rval, i; 338 | 339 | do { /* dummy */ 340 | if ( ! term.init ) { 341 | term_errno = TERM_ENOINIT; 342 | rval = -1; 343 | break; 344 | } 345 | 346 | for (i = 0; i < MAX_TERMS; i++) 347 | if (term.fd[i] == fd) break; 348 | 349 | if ( i == MAX_TERMS ) { 350 | term_errno = TERM_ENOTFOUND; 351 | rval = -1; 352 | break; 353 | } 354 | 355 | rval = i; 356 | } while (0); 357 | 358 | return rval; 359 | } 360 | 361 | /***************************************************************************/ 362 | 363 | static void 364 | term_exitfunc (void) 365 | { 366 | int r, i; 367 | 368 | do { /* dummy */ 369 | if ( ! term.init ) 370 | break; 371 | 372 | for (i = 0; i < MAX_TERMS; i++) { 373 | if (term.fd[i] == -1) 374 | continue; 375 | tcflush(term.fd[i], TCIOFLUSH); 376 | do { 377 | r = tcsetattr(term.fd[i], TCSANOW, &term.origtermios[i]); 378 | } while ( r < 0 && errno == EINTR ); 379 | if ( r < 0 ) { 380 | char *tname; 381 | 382 | tname = ttyname(term.fd[i]); 383 | if ( ! tname ) tname = "UNKNOWN"; 384 | fprintf(stderr, "%s: reset failed for dev %s: %s\n", 385 | __FUNCTION__, tname, strerror(errno)); 386 | } 387 | term.fd[i] = -1; 388 | } 389 | } while (0); 390 | } 391 | 392 | /***************************************************************************/ 393 | 394 | int 395 | term_lib_init (void) 396 | { 397 | int rval, r, i; 398 | 399 | rval = 0; 400 | 401 | do { /* dummy */ 402 | if ( term.init ) { 403 | /* reset all terms back to their original settings */ 404 | for (i = 0; i < MAX_TERMS; i++) { 405 | if (term.fd[i] == -1) 406 | continue; 407 | tcflush(term.fd[i], TCIOFLUSH); 408 | do { 409 | r = tcsetattr(term.fd[i], TCSANOW, &term.origtermios[i]); 410 | } while ( r < 0 && errno == EINTR ); 411 | if ( r < 0 ) { 412 | char *tname; 413 | 414 | tname = ttyname(term.fd[i]); 415 | if ( ! tname ) tname = "UNKNOWN"; 416 | fprintf(stderr, "%s: reset failed for dev %s: %s\n", 417 | __FUNCTION__, tname, strerror(errno)); 418 | } 419 | term.fd[i] = -1; 420 | } 421 | } else { 422 | /* initialize term structure. */ 423 | for (i = 0; i < MAX_TERMS; i++) 424 | term.fd[i] = -1; 425 | if ( atexit(term_exitfunc) != 0 ) { 426 | term_errno = TERM_EATEXIT; 427 | rval = -1; 428 | break; 429 | } 430 | /* ok. term struct is now initialized. */ 431 | term.init = 1; 432 | } 433 | } while(0); 434 | 435 | return rval; 436 | } 437 | 438 | /***************************************************************************/ 439 | 440 | int 441 | term_add (int fd) 442 | { 443 | int rval, r, i; 444 | 445 | rval = 0; 446 | 447 | do { /* dummy */ 448 | i = term_find(fd); 449 | if ( i >= 0 ) { 450 | term_errno = TERM_EEXISTS; 451 | rval = -1; 452 | break; 453 | } 454 | 455 | if ( ! isatty(fd) ) { 456 | term_errno = TERM_EISATTY; 457 | rval = -1; 458 | break; 459 | } 460 | 461 | i = term_find_next_free(); 462 | if ( i < 0 ) { 463 | rval = -1; 464 | break; 465 | } 466 | 467 | r = tcgetattr(fd, &term.origtermios[i]); 468 | if ( r < 0 ) { 469 | term_errno = TERM_EGETATTR; 470 | rval = -1; 471 | break; 472 | } 473 | 474 | term.currtermios[i] = term.origtermios[i]; 475 | term.nexttermios[i] = term.origtermios[i]; 476 | term.fd[i] = fd; 477 | } while (0); 478 | 479 | return rval; 480 | } 481 | 482 | /***************************************************************************/ 483 | 484 | int 485 | term_remove(int fd) 486 | { 487 | int rval, r, i; 488 | 489 | rval = 0; 490 | 491 | do { /* dummy */ 492 | i = term_find(fd); 493 | if ( i < 0 ) { 494 | rval = -1; 495 | break; 496 | } 497 | 498 | do { /* dummy */ 499 | r = tcflush(term.fd[i], TCIOFLUSH); 500 | if ( r < 0 ) { 501 | term_errno = TERM_EFLUSH; 502 | rval = -1; 503 | break; 504 | } 505 | r = tcsetattr(term.fd[i], TCSANOW, &term.origtermios[i]); 506 | if ( r < 0 ) { 507 | term_errno = TERM_ESETATTR; 508 | rval = -1; 509 | break; 510 | } 511 | } while (0); 512 | 513 | term.fd[i] = -1; 514 | } while (0); 515 | 516 | return rval; 517 | } 518 | 519 | /***************************************************************************/ 520 | 521 | int 522 | term_erase(int fd) 523 | { 524 | int rval, i; 525 | 526 | rval = 0; 527 | 528 | do { /* dummy */ 529 | i = term_find(fd); 530 | if ( i < 0 ) { 531 | rval = -1; 532 | break; 533 | } 534 | 535 | term.fd[i] = -1; 536 | } while (0); 537 | 538 | return rval; 539 | } 540 | 541 | /***************************************************************************/ 542 | 543 | int 544 | term_replace (int oldfd, int newfd) 545 | { 546 | int rval, r, i; 547 | 548 | rval = 0; 549 | 550 | do { /* dummy */ 551 | 552 | i = term_find(oldfd); 553 | if ( i < 0 ) { 554 | rval = -1; 555 | break; 556 | } 557 | 558 | r = tcsetattr(newfd, TCSANOW, &term.currtermios[i]); 559 | if ( r < 0 ) { 560 | term_errno = TERM_ESETATTR; 561 | rval = -1; 562 | break; 563 | } 564 | r = tcgetattr(newfd, &term.currtermios[i]); 565 | if ( r < 0 ) { 566 | term_errno = TERM_EGETATTR; 567 | rval = -1; 568 | break; 569 | } 570 | 571 | term.fd[i] = newfd; 572 | 573 | } while (0); 574 | 575 | return rval; 576 | } 577 | 578 | /***************************************************************************/ 579 | 580 | int 581 | term_reset (int fd) 582 | { 583 | int rval, r, i; 584 | 585 | rval = 0; 586 | 587 | do { /* dummy */ 588 | 589 | i = term_find(fd); 590 | if ( i < 0 ) { 591 | rval = -1; 592 | break; 593 | } 594 | 595 | r = tcflush(term.fd[i], TCIOFLUSH); 596 | if ( r < 0 ) { 597 | term_errno = TERM_EFLUSH; 598 | rval = -1; 599 | break; 600 | } 601 | r = tcsetattr(term.fd[i], TCSANOW, &term.origtermios[i]); 602 | if ( r < 0 ) { 603 | term_errno = TERM_ESETATTR; 604 | rval = -1; 605 | break; 606 | } 607 | r = tcgetattr(term.fd[i], &term.currtermios[i]); 608 | if ( r < 0 ) { 609 | term_errno = TERM_EGETATTR; 610 | rval = -1; 611 | break; 612 | } 613 | 614 | term.nexttermios[i] = term.currtermios[i]; 615 | } while (0); 616 | 617 | return rval; 618 | } 619 | 620 | /***************************************************************************/ 621 | 622 | int 623 | term_revert (int fd) 624 | { 625 | int rval, i; 626 | 627 | rval = 0; 628 | 629 | do { /* dummy */ 630 | 631 | i = term_find(fd); 632 | if ( i < 0 ) { 633 | rval = -1; 634 | break; 635 | } 636 | 637 | term.nexttermios[i] = term.currtermios[i]; 638 | 639 | } while (0); 640 | 641 | return rval; 642 | } 643 | 644 | /***************************************************************************/ 645 | 646 | int 647 | term_refresh (int fd) 648 | { 649 | int rval, r, i; 650 | 651 | rval = 0; 652 | 653 | do { /* dummy */ 654 | 655 | i = term_find(fd); 656 | if ( i < 0 ) { 657 | rval = -1; 658 | break; 659 | } 660 | 661 | r = tcgetattr(fd, &term.currtermios[i]); 662 | if ( r < 0 ) { 663 | term_errno = TERM_EGETATTR; 664 | rval = -1; 665 | break; 666 | } 667 | 668 | } while (0); 669 | 670 | return rval; 671 | } 672 | 673 | /***************************************************************************/ 674 | 675 | int 676 | term_apply (int fd, int now) 677 | { 678 | int when, rval, r, i; 679 | 680 | when = now ? TCSANOW : TCSAFLUSH; 681 | 682 | rval = 0; 683 | 684 | do { /* dummy */ 685 | 686 | i = term_find(fd); 687 | if ( i < 0 ) { 688 | rval = -1; 689 | break; 690 | } 691 | 692 | r = tcsetattr(term.fd[i], when, &term.nexttermios[i]); 693 | if ( r < 0 ) { 694 | term_errno = TERM_ESETATTR; 695 | rval = -1; 696 | break; 697 | } 698 | r = tcgetattr(term.fd[i], &term.nexttermios[i]); 699 | if ( r < 0 ) { 700 | term_errno = TERM_EGETATTR; 701 | rval = -1; 702 | break; 703 | } 704 | 705 | term.currtermios[i] = term.nexttermios[i]; 706 | 707 | } while (0); 708 | 709 | return rval; 710 | } 711 | 712 | /***************************************************************************/ 713 | 714 | int 715 | term_set_raw (int fd) 716 | { 717 | int rval, i; 718 | 719 | rval = 0; 720 | 721 | do { /* dummy */ 722 | 723 | i = term_find(fd); 724 | if ( i < 0 ) { 725 | rval = -1; 726 | break; 727 | } 728 | 729 | /* BSD raw mode */ 730 | cfmakeraw(&term.nexttermios[i]); 731 | /* one byte at a time, no timer */ 732 | term.nexttermios[i].c_cc[VMIN] = 1; 733 | term.nexttermios[i].c_cc[VTIME] = 0; 734 | 735 | } while (0); 736 | 737 | return rval; 738 | } 739 | 740 | /***************************************************************************/ 741 | 742 | int 743 | term_set_baudrate (int fd, int baudrate) 744 | { 745 | int rval, r, i; 746 | speed_t spd; 747 | struct termios tio; 748 | 749 | rval = 0; 750 | 751 | do { /* dummy */ 752 | 753 | i = term_find(fd); 754 | if ( i < 0 ) { 755 | rval = -1; 756 | break; 757 | } 758 | 759 | tio = term.nexttermios[i]; 760 | spd = Bcode(baudrate); 761 | if ( spd != BNONE ) { 762 | r = cfsetospeed(&tio, spd); 763 | if ( r < 0 ) { 764 | term_errno = TERM_ESETOSPEED; 765 | rval = -1; 766 | break; 767 | } 768 | cfsetispeed(&tio, B0); 769 | } else { 770 | #ifdef USE_CUSTOM_BAUD 771 | r = cfsetospeed_custom(&tio, baudrate); 772 | if ( r < 0 ) { 773 | term_errno = TERM_ESETOSPEED; 774 | rval = -1; 775 | break; 776 | } 777 | cfsetispeed(&tio, B0); 778 | #else /* ! defined USE_CUSTOM_BAUD */ 779 | term_errno = TERM_EBAUD; 780 | rval = -1; 781 | break; 782 | #endif /* of USE_CUSTOM_BAUD */ 783 | } 784 | 785 | term.nexttermios[i] = tio; 786 | 787 | } while (0); 788 | 789 | return rval; 790 | } 791 | 792 | int 793 | term_get_baudrate (int fd, int *ispeed) 794 | { 795 | speed_t code; 796 | int i, ospeed; 797 | 798 | do { /* dummy */ 799 | 800 | i = term_find(fd); 801 | if ( i < 0 ) { 802 | ospeed = -1; 803 | break; 804 | } 805 | 806 | if ( ispeed ) { 807 | code = cfgetispeed(&term.currtermios[i]); 808 | *ispeed = Bspeed(code); 809 | #ifdef USE_CUSTOM_BAUD 810 | if ( *ispeed < 0 ) { 811 | *ispeed = cfgetispeed_custom(&term.currtermios[i]); 812 | } 813 | #endif 814 | } 815 | code = cfgetospeed(&term.currtermios[i]); 816 | ospeed = Bspeed(code); 817 | if ( ospeed < 0 ) { 818 | #ifdef USE_CUSTOM_BAUD 819 | ospeed = cfgetospeed_custom(&term.currtermios[i]); 820 | if ( ospeed < 0 ) { 821 | term_errno = TERM_EGETSPEED; 822 | } 823 | #else 824 | term_errno = TERM_EGETSPEED; 825 | #endif 826 | } 827 | 828 | } while (0); 829 | 830 | return ospeed; 831 | } 832 | 833 | /***************************************************************************/ 834 | 835 | int 836 | term_set_parity (int fd, enum parity_e parity) 837 | { 838 | int rval, i; 839 | struct termios *tiop; 840 | 841 | rval = 0; 842 | 843 | do { /* dummy */ 844 | 845 | i = term_find(fd); 846 | if ( i < 0 ) { 847 | rval = -1; 848 | break; 849 | } 850 | 851 | tiop = &term.nexttermios[i]; 852 | 853 | switch (parity) { 854 | case P_EVEN: 855 | tiop->c_cflag &= ~(PARODD | CMSPAR); 856 | tiop->c_cflag |= PARENB; 857 | break; 858 | case P_ODD: 859 | tiop->c_cflag &= ~CMSPAR; 860 | tiop->c_cflag |= PARENB | PARODD; 861 | break; 862 | case P_MARK: 863 | tiop->c_cflag |= PARENB | PARODD | CMSPAR; 864 | break; 865 | case P_SPACE: 866 | tiop->c_cflag &= ~PARODD; 867 | tiop->c_cflag |= PARENB | CMSPAR; 868 | break; 869 | case P_NONE: 870 | tiop->c_cflag &= ~(PARENB | PARODD | CMSPAR); 871 | break; 872 | default: 873 | term_errno = TERM_EPARITY; 874 | rval = -1; 875 | break; 876 | } 877 | if ( rval < 0 ) break; 878 | 879 | } while (0); 880 | 881 | return rval; 882 | } 883 | 884 | enum parity_e 885 | term_get_parity (int fd) 886 | { 887 | tcflag_t flg; 888 | int i, parity; 889 | 890 | do { /* dummy */ 891 | 892 | i = term_find(fd); 893 | if ( i < 0 ) { 894 | parity = -1; 895 | break; 896 | } 897 | 898 | flg = term.currtermios[i].c_cflag; 899 | if ( ! (flg & PARENB) ) { 900 | parity = P_NONE; 901 | } else if ( flg & CMSPAR ) { 902 | parity = (flg & PARODD) ? P_MARK : P_SPACE; 903 | } else { 904 | parity = (flg & PARODD) ? P_ODD : P_EVEN; 905 | } 906 | 907 | } while (0); 908 | 909 | return parity; 910 | } 911 | 912 | /***************************************************************************/ 913 | 914 | int 915 | term_set_databits (int fd, int databits) 916 | { 917 | int rval, i; 918 | struct termios *tiop; 919 | 920 | rval = 0; 921 | 922 | do { /* dummy */ 923 | 924 | i = term_find(fd); 925 | if ( i < 0 ) { 926 | rval = -1; 927 | break; 928 | } 929 | 930 | tiop = &term.nexttermios[i]; 931 | 932 | switch (databits) { 933 | case 5: 934 | tiop->c_cflag = (tiop->c_cflag & ~CSIZE) | CS5; 935 | break; 936 | case 6: 937 | tiop->c_cflag = (tiop->c_cflag & ~CSIZE) | CS6; 938 | break; 939 | case 7: 940 | tiop->c_cflag = (tiop->c_cflag & ~CSIZE) | CS7; 941 | break; 942 | case 8: 943 | tiop->c_cflag = (tiop->c_cflag & ~CSIZE) | CS8; 944 | break; 945 | default: 946 | term_errno = TERM_EDATABITS; 947 | rval = -1; 948 | break; 949 | } 950 | if ( rval < 0 ) break; 951 | 952 | } while (0); 953 | 954 | return rval; 955 | } 956 | 957 | int 958 | term_get_databits (int fd) 959 | { 960 | tcflag_t flg; 961 | int i, bits; 962 | 963 | do { /* dummy */ 964 | 965 | i = term_find(fd); 966 | if ( i < 0 ) { 967 | bits = -1; 968 | break; 969 | } 970 | 971 | flg = term.currtermios[i].c_cflag & CSIZE; 972 | switch (flg) { 973 | case CS5: 974 | bits = 5; 975 | break; 976 | case CS6: 977 | bits = 6; 978 | break; 979 | case CS7: 980 | bits = 7; 981 | break; 982 | case CS8: 983 | default: 984 | bits = 8; 985 | break; 986 | } 987 | 988 | } while (0); 989 | 990 | return bits; 991 | } 992 | 993 | /***************************************************************************/ 994 | 995 | int 996 | term_set_stopbits (int fd, int stopbits) 997 | { 998 | int rval, i; 999 | struct termios *tiop; 1000 | 1001 | rval = 0; 1002 | 1003 | do { /* dummy */ 1004 | 1005 | i = term_find(fd); 1006 | if ( i < 0 ) { 1007 | rval = -1; 1008 | break; 1009 | } 1010 | 1011 | tiop = &term.nexttermios[i]; 1012 | 1013 | switch (stopbits) { 1014 | case 1: 1015 | tiop->c_cflag &= ~CSTOPB; 1016 | break; 1017 | case 2: 1018 | tiop->c_cflag |= CSTOPB; 1019 | break; 1020 | default: 1021 | term_errno = TERM_ESTOPBITS; 1022 | rval = -1; 1023 | break; 1024 | } 1025 | if ( rval < 0 ) break; 1026 | 1027 | } while (0); 1028 | 1029 | return rval; 1030 | } 1031 | 1032 | int 1033 | term_get_stopbits (int fd) 1034 | { 1035 | int i, bits; 1036 | 1037 | do { /* dummy */ 1038 | 1039 | i = term_find(fd); 1040 | if ( i < 0 ) { 1041 | bits = -1; 1042 | break; 1043 | } 1044 | 1045 | bits = (term.currtermios[i].c_cflag & CSTOPB) ? 2 : 1; 1046 | 1047 | } while (0); 1048 | 1049 | return bits; 1050 | } 1051 | 1052 | /***************************************************************************/ 1053 | 1054 | int 1055 | term_set_flowcntrl (int fd, enum flowcntrl_e flowcntl) 1056 | { 1057 | int rval, i; 1058 | struct termios *tiop; 1059 | 1060 | rval = 0; 1061 | 1062 | do { /* dummy */ 1063 | 1064 | i = term_find(fd); 1065 | if ( i < 0 ) { 1066 | rval = -1; 1067 | break; 1068 | } 1069 | 1070 | tiop = &term.nexttermios[i]; 1071 | 1072 | switch (flowcntl) { 1073 | case FC_RTSCTS: 1074 | tiop->c_cflag |= CRTSCTS; 1075 | tiop->c_iflag &= ~(IXON | IXOFF | IXANY); 1076 | break; 1077 | case FC_XONXOFF: 1078 | tiop->c_cflag &= ~(CRTSCTS); 1079 | tiop->c_iflag |= IXON | IXOFF; 1080 | break; 1081 | case FC_NONE: 1082 | tiop->c_cflag &= ~(CRTSCTS); 1083 | tiop->c_iflag &= ~(IXON | IXOFF | IXANY); 1084 | break; 1085 | default: 1086 | term_errno = TERM_EFLOW; 1087 | rval = -1; 1088 | break; 1089 | } 1090 | if ( rval < 0 ) break; 1091 | 1092 | } while (0); 1093 | 1094 | return rval; 1095 | } 1096 | 1097 | enum flowcntrl_e 1098 | term_get_flowcntrl (int fd) 1099 | { 1100 | int i, flow; 1101 | int rtscts, xoff, xon; 1102 | 1103 | do { /* dummy */ 1104 | 1105 | i = term_find(fd); 1106 | if ( i < 0 ) { 1107 | flow = -1; 1108 | break; 1109 | } 1110 | 1111 | rtscts = (term.currtermios[i].c_cflag & CRTSCTS) ? 1 : 0; 1112 | xoff = (term.currtermios[i].c_iflag & IXOFF) ? 1 : 0; 1113 | xon = (term.currtermios[i].c_iflag & (IXON | IXANY)) ? 1 : 0; 1114 | 1115 | if ( rtscts && ! xoff && ! xon ) { 1116 | flow = FC_RTSCTS; 1117 | } else if ( ! rtscts && xoff && xon ) { 1118 | flow = FC_XONXOFF; 1119 | } else if ( ! rtscts && ! xoff && ! xon ) { 1120 | flow = FC_NONE; 1121 | } else { 1122 | flow = FC_OTHER; 1123 | } 1124 | 1125 | } while (0); 1126 | 1127 | return flow; 1128 | } 1129 | 1130 | /***************************************************************************/ 1131 | 1132 | int 1133 | term_set_local(int fd, int local) 1134 | { 1135 | int rval, i; 1136 | struct termios *tiop; 1137 | 1138 | rval = 0; 1139 | 1140 | do { /* dummy */ 1141 | 1142 | i = term_find(fd); 1143 | if ( i < 0 ) { 1144 | rval = -1; 1145 | break; 1146 | } 1147 | 1148 | tiop = &term.nexttermios[i]; 1149 | 1150 | if ( local ) 1151 | tiop->c_cflag |= CLOCAL; 1152 | else 1153 | tiop->c_cflag &= ~CLOCAL; 1154 | 1155 | } while (0); 1156 | 1157 | return rval; 1158 | } 1159 | 1160 | /***************************************************************************/ 1161 | 1162 | int 1163 | term_set_hupcl (int fd, int on) 1164 | { 1165 | int rval, i; 1166 | struct termios *tiop; 1167 | 1168 | rval = 0; 1169 | 1170 | do { /* dummy */ 1171 | 1172 | i = term_find(fd); 1173 | if ( i < 0 ) { 1174 | rval = -1; 1175 | break; 1176 | } 1177 | 1178 | tiop = &term.nexttermios[i]; 1179 | 1180 | if ( on ) 1181 | tiop->c_cflag |= HUPCL; 1182 | else 1183 | tiop->c_cflag &= ~HUPCL; 1184 | 1185 | } while (0); 1186 | 1187 | return rval; 1188 | } 1189 | 1190 | /***************************************************************************/ 1191 | 1192 | int 1193 | term_set(int fd, 1194 | int raw, 1195 | int baud, 1196 | enum parity_e parity, 1197 | int databits, int stopbits, 1198 | enum flowcntrl_e fc, 1199 | int local, int hup_close) 1200 | { 1201 | int rval, r, i, ni; 1202 | struct termios tio; 1203 | 1204 | rval = 0; 1205 | 1206 | do { /* dummy */ 1207 | 1208 | i = term_find(fd); 1209 | if ( i < 0 ) { 1210 | ni = term_add(fd); 1211 | if ( ni < 0 ) { 1212 | rval = -1; 1213 | break; 1214 | } 1215 | } else { 1216 | ni = i; 1217 | } 1218 | 1219 | tio = term.nexttermios[ni]; 1220 | 1221 | do { /* dummy */ 1222 | 1223 | if (raw) { 1224 | r = term_set_raw(fd); 1225 | if ( r < 0 ) { rval = -1; break; } 1226 | } 1227 | 1228 | r = term_set_baudrate(fd, baud); 1229 | if ( r < 0 ) { rval = -1; break; } 1230 | 1231 | r = term_set_parity(fd, parity); 1232 | if ( r < 0 ) { rval = -1; break; } 1233 | 1234 | r = term_set_databits(fd, databits); 1235 | if ( r < 0 ) { rval = -1; break; } 1236 | 1237 | r = term_set_stopbits(fd, stopbits); 1238 | if ( r < 0 ) { rval = -1; break; } 1239 | 1240 | r = term_set_flowcntrl(fd, fc); 1241 | if ( r < 0 ) { rval = -1; break; } 1242 | 1243 | r = term_set_local(fd, local); 1244 | if ( r < 0 ) { rval = -1; break; } 1245 | 1246 | r = term_set_hupcl(fd, hup_close); 1247 | if ( r < 0 ) { rval = -1; break; } 1248 | 1249 | } while (0); 1250 | 1251 | if ( rval < 0 ) { 1252 | if ( i < 0 ) 1253 | /* new addition. must be removed */ 1254 | term.fd[ni] = -1; 1255 | else 1256 | /* just revert to previous settings */ 1257 | term.nexttermios[ni] = tio; 1258 | } 1259 | 1260 | } while (0); 1261 | 1262 | return rval; 1263 | } 1264 | 1265 | /***************************************************************************/ 1266 | 1267 | int 1268 | term_pulse_dtr (int fd) 1269 | { 1270 | int rval, r, i; 1271 | 1272 | rval = 0; 1273 | 1274 | do { /* dummy */ 1275 | 1276 | i = term_find(fd); 1277 | if ( i < 0 ) { 1278 | rval = -1; 1279 | break; 1280 | } 1281 | 1282 | #ifdef __linux__ 1283 | { 1284 | int opins = TIOCM_DTR; 1285 | 1286 | r = ioctl(fd, TIOCMBIC, &opins); 1287 | if ( r < 0 ) { 1288 | term_errno = TERM_EDTRDOWN; 1289 | rval = -1; 1290 | break; 1291 | } 1292 | 1293 | sleep(1); 1294 | 1295 | r = ioctl(fd, TIOCMBIS, &opins); 1296 | if ( r < 0 ) { 1297 | term_errno = TERM_EDTRUP; 1298 | rval = -1; 1299 | break; 1300 | } 1301 | } 1302 | #else 1303 | { 1304 | struct termios tio, tioold; 1305 | 1306 | r = tcgetattr(fd, &tio); 1307 | if ( r < 0 ) { 1308 | term_errno = TERM_ESETATTR; 1309 | rval = -1; 1310 | break; 1311 | } 1312 | 1313 | tioold = tio; 1314 | 1315 | cfsetospeed(&tio, B0); 1316 | cfsetispeed(&tio, B0); 1317 | r = tcsetattr(fd, TCSANOW, &tio); 1318 | if ( r < 0 ) { 1319 | term_errno = TERM_ESETATTR; 1320 | rval = -1; 1321 | break; 1322 | } 1323 | 1324 | sleep(1); 1325 | 1326 | r = tcsetattr(fd, TCSANOW, &tioold); 1327 | if ( r < 0 ) { 1328 | term.currtermios[i] = tio; 1329 | term_errno = TERM_ESETATTR; 1330 | rval = -1; 1331 | break; 1332 | } 1333 | } 1334 | #endif /* of __linux__ */ 1335 | 1336 | } while (0); 1337 | 1338 | return rval; 1339 | } 1340 | 1341 | /***************************************************************************/ 1342 | 1343 | int 1344 | term_raise_dtr(int fd) 1345 | { 1346 | int rval, r, i; 1347 | 1348 | rval = 0; 1349 | 1350 | do { /* dummy */ 1351 | 1352 | i = term_find(fd); 1353 | if ( i < 0 ) { 1354 | rval = -1; 1355 | break; 1356 | } 1357 | 1358 | #ifdef __linux__ 1359 | { 1360 | int opins = TIOCM_DTR; 1361 | 1362 | r = ioctl(fd, TIOCMBIS, &opins); 1363 | if ( r < 0 ) { 1364 | term_errno = TERM_EDTRUP; 1365 | rval = -1; 1366 | break; 1367 | } 1368 | } 1369 | #else 1370 | r = tcsetattr(fd, TCSANOW, &term.currtermios[i]); 1371 | if ( r < 0 ) { 1372 | /* FIXME: perhaps try to update currtermios */ 1373 | term_errno = TERM_ESETATTR; 1374 | rval = -1; 1375 | break; 1376 | } 1377 | #endif /* of __linux__ */ 1378 | } while (0); 1379 | 1380 | return rval; 1381 | } 1382 | 1383 | /***************************************************************************/ 1384 | 1385 | 1386 | int 1387 | term_lower_dtr(int fd) 1388 | { 1389 | int rval, r, i; 1390 | 1391 | rval = 0; 1392 | 1393 | do { /* dummy */ 1394 | 1395 | i = term_find(fd); 1396 | if ( i < 0 ) { 1397 | rval = -1; 1398 | break; 1399 | } 1400 | 1401 | #ifdef __linux__ 1402 | { 1403 | int opins = TIOCM_DTR; 1404 | 1405 | r = ioctl(fd, TIOCMBIC, &opins); 1406 | if ( r < 0 ) { 1407 | term_errno = TERM_EDTRDOWN; 1408 | rval = -1; 1409 | break; 1410 | } 1411 | } 1412 | #else 1413 | { 1414 | struct termios tio; 1415 | 1416 | r = tcgetattr(fd, &tio); 1417 | if ( r < 0 ) { 1418 | term_errno = TERM_EGETATTR; 1419 | rval = -1; 1420 | break; 1421 | } 1422 | term.currtermios[i] = tio; 1423 | 1424 | cfsetospeed(&tio, B0); 1425 | cfsetispeed(&tio, B0); 1426 | 1427 | r = tcsetattr(fd, TCSANOW, &tio); 1428 | if ( r < 0 ) { 1429 | term_errno = TERM_ESETATTR; 1430 | rval = -1; 1431 | break; 1432 | } 1433 | } 1434 | #endif /* of __linux__ */ 1435 | } while (0); 1436 | 1437 | return rval; 1438 | } 1439 | 1440 | /***************************************************************************/ 1441 | 1442 | int 1443 | term_get_mctl (int fd) 1444 | { 1445 | int mctl, i; 1446 | 1447 | do { /* dummy */ 1448 | 1449 | i = term_find(fd); 1450 | if ( i < 0 ) { 1451 | mctl = -1; 1452 | break; 1453 | } 1454 | 1455 | #ifdef __linux__ 1456 | { 1457 | int r, pmctl; 1458 | 1459 | r = ioctl(fd, TIOCMGET, &pmctl); 1460 | if (r < 0) { 1461 | mctl = -1; 1462 | break; 1463 | } 1464 | mctl = 0; 1465 | if (pmctl & TIOCM_DTR) mctl |= MCTL_DTR; 1466 | if (pmctl & TIOCM_DSR) mctl |= MCTL_DSR; 1467 | if (pmctl & TIOCM_CD) mctl |= MCTL_DCD; 1468 | if (pmctl & TIOCM_RTS) mctl |= MCTL_RTS; 1469 | if (pmctl & TIOCM_CTS) mctl |= MCTL_CTS; 1470 | if (pmctl & TIOCM_RI) mctl |= MCTL_RI; 1471 | } 1472 | #else 1473 | mctl = MCTL_UNAVAIL; 1474 | #endif 1475 | } while(0); 1476 | 1477 | return mctl; 1478 | } 1479 | 1480 | int 1481 | term_drain(int fd) 1482 | { 1483 | int rval, r; 1484 | 1485 | rval = 0; 1486 | 1487 | do { /* dummy */ 1488 | 1489 | r = term_find(fd); 1490 | if ( r < 0 ) { 1491 | rval = -1; 1492 | break; 1493 | } 1494 | 1495 | do { 1496 | #ifdef __BIONIC__ 1497 | /* See: http://dan.drown.org/android/src/gdb/no-tcdrain */ 1498 | r = ioctl(fd, TCSBRK, 1); 1499 | #else 1500 | r = tcdrain(fd); 1501 | #endif 1502 | } while ( r < 0 && errno == EINTR); 1503 | if ( r < 0 ) { 1504 | term_errno = TERM_EDRAIN; 1505 | rval = -1; 1506 | break; 1507 | } 1508 | 1509 | } while (0); 1510 | 1511 | return rval; 1512 | } 1513 | 1514 | /***************************************************************************/ 1515 | 1516 | int 1517 | term_flush(int fd) 1518 | { 1519 | int rval, r; 1520 | 1521 | rval = 0; 1522 | 1523 | do { /* dummy */ 1524 | 1525 | r = term_find(fd); 1526 | if ( r < 0 ) { 1527 | rval = -1; 1528 | break; 1529 | } 1530 | 1531 | r = tcflush(fd, TCIOFLUSH); 1532 | if ( r < 0 ) { 1533 | rval = -1; 1534 | break; 1535 | } 1536 | 1537 | } while (0); 1538 | 1539 | return rval; 1540 | } 1541 | 1542 | /***************************************************************************/ 1543 | 1544 | int 1545 | term_break(int fd) 1546 | { 1547 | int rval, r; 1548 | 1549 | rval = 0; 1550 | 1551 | do { /* dummy */ 1552 | 1553 | r = term_find(fd); 1554 | if ( r < 0 ) { 1555 | rval = -1; 1556 | break; 1557 | } 1558 | 1559 | r = tcsendbreak(fd, 0); 1560 | if ( r < 0 ) { 1561 | term_errno = TERM_EBREAK; 1562 | rval = -1; 1563 | break; 1564 | } 1565 | 1566 | } while (0); 1567 | 1568 | return rval; 1569 | } 1570 | 1571 | /**************************************************************************/ 1572 | 1573 | /* 1574 | * Local Variables: 1575 | * mode:c 1576 | * tab-width: 4 1577 | * c-basic-offset: 4 1578 | * End: 1579 | */ 1580 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------