📄 picocom.c
字号:
/* vi: set sw=4 ts=4: * * picocom.c * * simple dumb-terminal program. Helps you manually configure and test * stuff like modems, devices w. serial ports etc. * * by Nick Patavalis (npat@efault.net) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <ctype.h>#include <errno.h>#include <assert.h>#include <stdarg.h>#include <signal.h>#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/wait.h>#include <limits.h>#define _GNU_SOURCE#include <getopt.h>#include "term.h"/**********************************************************************/#define KEY_EXIT '\x18' /* C-x: exit picocom */#define KEY_QUIT '\x11' /* C-q: exit picocom without reseting port */#define KEY_PULSE '\x10' /* C-p: pulse DTR */#define KEY_TOGGLE '\x14' /* C-t: toggle DTR */#define KEY_BAUD_UP '\x15' /* C-u: increase baudrate (up) */#define KEY_BAUD_DN '\x04' /* C-d: decrase baudrate (down) */ #define KEY_FLOW '\x06' /* C-f: change flowcntrl mode */ #define KEY_PARITY '\x19' /* C-y: change parity mode */ #define KEY_BITS '\x02' /* C-b: change number of databits */ #define KEY_STATUS '\x16' /* C-v: show program option */#define KEY_SEND '\x13' /* C-s: send file */#define KEY_RECEIVE '\x12' /* C-r: receive file */#define KEY_BREAK '\x1c' /* C-\: break */#define STO STDOUT_FILENO#define STI STDIN_FILENO/**********************************************************************/struct { char port[128]; int baud; enum flowcntrl_e flow; char *flow_str; enum parity_e parity; char *parity_str; int databits; int noinit; int noreset;#ifdef UUCP_LOCK_DIR int nolock;#endif unsigned char escape; char send_cmd[128]; char receive_cmd[128];} opts = { .port = "", .baud = 9600, .flow = FC_NONE, .flow_str = "none", .parity = P_NONE, .parity_str = "none", .databits = 8, .noinit = 0, .noreset = 0,#ifdef UUCP_LOCK_DIR .nolock = 0,#endif .escape = '\x01', .send_cmd = "ascii_xfr -s -v -l10", .receive_cmd = "rz -vv"};int tty_fd;/**********************************************************************/#ifdef UUCP_LOCK_DIR/* use HDB UUCP locks .. see * <http://www.faqs.org/faqs/uucp-internals> for details */char lockname[_POSIX_PATH_MAX] = "";intuucp_lockname(const char *dir, const char *file){ char *p, *cp; struct stat sb; if ( ! dir || *dir == '\0' || stat(dir, &sb) != 0 ) return -1; /* cut-off initial "/dev/" from file-name */ p = strchr(file + 1, '/'); p = p ? p + 1 : (char *)file; /* replace '/'s with '_'s in what remains (after making a copy) */ p = cp = strdup(p); do { if ( *p == '/' ) *p = '_'; } while(*p++); /* build lockname */ snprintf(lockname, sizeof(lockname), "%s/LCK..%s", dir, cp); /* destroy the copy */ free(cp); return 0;}intuucp_lock(void){ int r, fd, pid; char buf[16]; mode_t m; if ( lockname[0] == '\0' ) return 0; fd = open(lockname, O_RDONLY); if ( fd >= 0 ) { r = read(fd, buf, sizeof(buf)); close(fd); /* if r == 4, lock file is binary (old-style) */ pid = (r == 4) ? *(int *)buf : strtol(buf, NULL, 10); if ( pid > 0 && kill((pid_t)pid, 0) < 0 && errno == ESRCH ) { /* stale lock file */ printf("Removing stale lock: %s\n", lockname); sleep(1); unlink(lockname); } else { lockname[0] = '\0'; errno = EEXIST; return -1; } } /* lock it */ m = umask(022); fd = open(lockname, O_WRONLY|O_CREAT|O_EXCL, 0666); if ( fd < 0 ) { lockname[0] = '\0'; return -1; } umask(m); snprintf(buf, sizeof(buf), "%04d\n", getpid()); write(fd, buf, strlen(buf)); close(fd); return 0;}intuucp_unlock(void){ if ( lockname[0] ) unlink(lockname); return 0;}#endif /* of UUCP_LOCK_DIR *//**********************************************************************/ssize_twriten_ni(int fd, const void *buff, size_t n){ size_t nl; ssize_t nw; const char *p; p = buff; nl = n; while (nl > 0) { do { nw = write(fd, p, nl); } while ( nw < 0 && errno == EINTR ); if ( nw <= 0 ) break; nl -= nw; p += nw; } return n - nl;}intfd_printf (int fd, const char *format, ...){ char buf[256]; va_list args; int len; va_start(args, format); len = vsnprintf(buf, sizeof(buf), format, args); buf[sizeof(buf) - 1] = '\0'; va_end(args); return writen_ni(fd, buf, len);}voidfatal (const char *format, ...){ char *s, buf[256]; va_list args; int len; term_reset(STO); term_reset(STI); va_start(args, format); len = vsnprintf(buf, sizeof(buf), format, args); buf[sizeof(buf) - 1] = '\0'; va_end(args); s = "\r\nFATAL: "; writen_ni(STO, s, strlen(s)); writen_ni(STO, buf, len); s = "\r\n"; writen_ni(STO, s, strlen(s)); /* wait a bit for output to drain */ sleep(1);#ifdef UUCP_LOCK_DIR uucp_unlock();#endif exit(EXIT_FAILURE);}#define cput(fd, c) do { int cl = c; write((fd), &(cl), 1); } while(0)intfd_readline (int fdi, int fdo, char *b, int bsz){ int r; unsigned char c; unsigned char *bp, *bpe; bp = b; bpe = b + bsz - 1; while (1) { r = read(fdi, &c, 1); if ( r <= 0 ) { r--; goto out; } switch (c) { case '\b': if ( bp > (unsigned char *)b ) { bp--; cput(fdo, c); cput(fdo, ' '); cput(fdo, c); } else { cput(fdo, '\x07'); } break; case '\r': *bp = '\0'; r = bp - (unsigned char *)b; goto out; default: if ( bp < bpe ) { *bp++ = c; cput(fdo, c); } else { cput(fdo, '\x07'); } break; } }out: return r;}#undef cput/**********************************************************************/intbaud_up (int baud){ if ( baud < 300 ) baud = 300; else if ( baud == 38400 ) baud = 57600; else baud = baud * 2; if ( baud > 115200 ) baud = 115200; return baud;}intbaud_down (int baud){ if ( baud > 115200 ) baud = 115200; else if ( baud == 57600 ) baud = 38400; else baud = baud / 2; if ( baud < 300) baud = 300; return baud;}intflow_next (int flow, char **flow_str){ switch(flow) { case FC_NONE: flow = FC_RTSCTS; *flow_str = "RTS/CTS"; break; case FC_RTSCTS: flow = FC_XONXOFF; *flow_str = "xon/xoff"; break; case FC_XONXOFF: flow = FC_NONE; *flow_str = "none"; break; default: flow = FC_NONE; *flow_str = "none"; break; } return flow;}intparity_next (int parity, char **parity_str){ switch(parity) { case P_NONE: parity = P_EVEN; *parity_str = "even"; break; case P_EVEN: parity = P_ODD; *parity_str = "odd"; break; case P_ODD: parity = P_NONE; *parity_str = "none"; break; default: parity = P_NONE; *parity_str = "none"; break; } return parity;}intbits_next (int bits){ bits++; if (bits > 8) bits = 5; return bits;}/**********************************************************************/voidchild_empty_handler (int signum){}voidestablish_child_signal_handlers (void){ struct sigaction empty_action; /* Set up the structure to specify the "empty" action. */ empty_action.sa_handler = child_empty_handler; sigemptyset (&empty_action.sa_mask); empty_action.sa_flags = 0; sigaction (SIGINT, &empty_action, NULL); sigaction (SIGTERM, &empty_action, NULL);}intrun_cmd(int fd, ...){ pid_t pid; sigset_t sigm, sigm_old; /* block signals, let child establish its own handlers */ sigemptyset(&sigm); sigaddset(&sigm, SIGTERM); sigprocmask(SIG_BLOCK, &sigm, &sigm_old); pid = fork(); if ( pid < 0 ) { sigprocmask(SIG_SETMASK, &sigm_old, NULL); fd_printf(STO, "*** cannot fork: %s\n", strerror(errno)); return -1; } else if ( pid ) { /* father: picocom */ int r; /* reset the mask */ sigprocmask(SIG_SETMASK, &sigm_old, NULL); /* wait for child to finish */ waitpid(pid, &r, 0); /* reset terminal (back to raw mode) */ term_apply(STI); /* check and report child return status */ if ( WIFEXITED(r) ) { fd_printf(STO, "\r\n*** exit status: %d\r\n", WEXITSTATUS(r)); return WEXITSTATUS(r); } else { fd_printf(STO, "\r\n*** abnormal termination: 0x%x\r\n", r); return -1; } } else { /* child: external program */ int r; long fl; char cmd[512]; establish_child_signal_handlers(); sigprocmask(SIG_SETMASK, &sigm_old, NULL); /* unmanage terminal, and reset it to canonical mode */ term_remove(STI); /* unmanage serial port fd, without reset */ term_erase(fd); /* set serial port fd to blocking mode */ fl = fcntl(fd, F_GETFL); fl &= ~O_NONBLOCK; fcntl(fd, F_SETFL, fl); /* connect stdin and stdout to serial port */ close(STI); close(STO); dup2(fd, STI); dup2(fd, STO); { /* build command-line */ char *c, *ce; const char *s; int n; va_list vls; c = cmd; ce = cmd + sizeof(cmd) - 1; va_start(vls, fd); while ( (s = va_arg(vls, const char *)) ) { n = strlen(s); if ( c + n + 1 >= ce ) break; memcpy(c, s, n); c += n; *c++ = ' '; } va_end(vls); *c = '\0'; } /* run extenral command */ fd_printf(STDERR_FILENO, "%s\n", cmd); r = system(cmd); if ( WIFEXITED(r) ) exit(WEXITSTATUS(r)); else exit(128); }}/**********************************************************************/#define TTY_Q_SZ 256struct tty_q { int len; unsigned char buff[TTY_Q_SZ];} tty_q;/**********************************************************************/voidloop(void){ enum { ST_COMMAND, ST_TRANSPARENT } state; int dtr_up; fd_set rdset, wrset; int newbaud, newflow, newparity, newbits;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -