chat.c revision 92920
14374Slars/* 24374Slars * Chat -- a program for automatic session establishment (i.e. dial 34374Slars * the phone and log in). 44374Slars * 511990Speter * Standard termination codes: 611990Speter * 0 - successful completion of the script 711990Speter * 1 - invalid argument, expect string too large, etc. 834766Speter * 2 - error on an I/O operation or fatal error condition. 911990Speter * 3 - timeout waiting for a simple string. 1011990Speter * 4 - the first string declared as "ABORT" 1111990Speter * 5 - the second string declared as "ABORT" 1211990Speter * 6 - ... and so on for successive ABORT strings. 1311990Speter * 144374Slars * This software is in the public domain. 154374Slars * 1628597Speter * ----------------- 1734766Speter * added -T and -U option and \T and \U substitution to pass a phone 1834766Speter * number into chat script. Two are needed for some ISDN TA applications. 1934766Speter * Keith Dart <kdart@cisco.com> 2034766Speter * 214374Slars * 2228597Speter * Added SAY keyword to send output to stderr. 2328597Speter * This allows to turn ECHO OFF and to output specific, user selected, 2428597Speter * text to give progress messages. This best works when stderr 2528597Speter * exists (i.e.: pppd in nodetach mode). 264374Slars * 2728597Speter * Added HANGUP directives to allow for us to be called 2828597Speter * back. When HANGUP is set to NO, chat will not hangup at HUP signal. 2928597Speter * We rely on timeouts in that case. 3028597Speter * 3128597Speter * Added CLR_ABORT to clear previously set ABORT string. This has been 3228597Speter * dictated by the HANGUP above as "NO CARRIER" (for example) must be 3328597Speter * an ABORT condition until we know the other host is going to close 3428597Speter * the connection for call back. As soon as we have completed the 3528597Speter * first stage of the call back sequence, "NO CARRIER" is a valid, non 3628597Speter * fatal string. As soon as we got called back (probably get "CONNECT"), 3728597Speter * we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command. 3828597Speter * Note that CLR_ABORT packs the abort_strings[] array so that we do not 3928597Speter * have unused entries not being reclaimed. 4028597Speter * 4128597Speter * In the same vein as above, added CLR_REPORT keyword. 4228597Speter * 4328597Speter * Allow for comments. Line starting with '#' are comments and are 4428597Speter * ignored. If a '#' is to be expected as the first character, the 4528597Speter * expect string must be quoted. 4628597Speter * 4728597Speter * 4828597Speter * Francis Demierre <Francis@SwissMail.Com> 4928597Speter * Thu May 15 17:15:40 MET DST 1997 5028597Speter * 5128597Speter * 5211990Speter * Added -r "report file" switch & REPORT keyword. 5311990Speter * Robert Geer <bgeer@xmission.com> 5411990Speter * 5534766Speter * Added -s "use stderr" and -S "don't use syslog" switches. 5634766Speter * June 18, 1997 5734766Speter * Karl O. Pinc <kop@meme.com> 5828597Speter * 5934766Speter * 6028597Speter * Added -e "echo" switch & ECHO keyword 6128597Speter * Dick Streefland <dicks@tasking.nl> 6228597Speter * 6328597Speter * 6428597Speter * Considerable updates and modifications by 6528597Speter * Al Longyear <longyear@pobox.com> 6628597Speter * Paul Mackerras <paulus@cs.anu.edu.au> 6728597Speter * 6828597Speter * 694374Slars * The original author is: 704374Slars * 714374Slars * Karl Fox <karl@MorningStar.Com> 724374Slars * Morning Star Technologies, Inc. 734374Slars * 1760 Zollinger Road 744374Slars * Columbus, OH 43221 754374Slars * (614)451-1883 7611990Speter * 7728597Speter * 784374Slars */ 794374Slars 8028597Speter#ifndef lint 8141568Sarchiestatic const char rcsid[] = 8250477Speter "$FreeBSD: head/usr.bin/chat/chat.c 92920 2002-03-22 01:22:50Z imp $"; 8328597Speter#endif 844374Slars 854374Slars#include <stdio.h> 8628597Speter#include <ctype.h> 8711990Speter#include <time.h> 884374Slars#include <fcntl.h> 894374Slars#include <signal.h> 904374Slars#include <errno.h> 914374Slars#include <string.h> 924374Slars#include <stdlib.h> 9328597Speter#include <unistd.h> 944374Slars#include <sys/types.h> 954374Slars#include <sys/stat.h> 964374Slars#include <syslog.h> 974374Slars 984374Slars#ifndef TERMIO 994374Slars#undef TERMIOS 1004374Slars#define TERMIOS 1014374Slars#endif 1024374Slars 1034374Slars#ifdef TERMIO 1044374Slars#include <termio.h> 1054374Slars#endif 1064374Slars#ifdef TERMIOS 1074374Slars#include <termios.h> 1084374Slars#endif 1094374Slars 1104374Slars#define STR_LEN 1024 1114374Slars 1124374Slars#ifndef SIGTYPE 1134374Slars#define SIGTYPE void 1144374Slars#endif 1154374Slars 11634766Speter#include <stdarg.h> 1174374Slars 11811990Speter#ifndef O_NONBLOCK 11911990Speter#define O_NONBLOCK O_NDELAY 12011990Speter#endif 12111990Speter 12234766Speter#ifdef SUNOS 12334766Speterextern int sys_nerr; 12434766Speterextern char *sys_errlist[]; 12534766Speter#define memmove(to, from, n) bcopy(from, to, n) 12634766Speter#define strerror(n) ((unsigned)(n) < sys_nerr? sys_errlist[(n)] :\ 12734766Speter "unknown error") 12834766Speter#endif 12934766Speter 1304374Slars/*************** Micro getopt() *********************************************/ 1314374Slars#define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ 1324374Slars (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ 1334374Slars &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0)) 1344374Slars#define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \ 1354374Slars (_O=4,(char*)0):(char*)0) 1364374Slars#define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0) 1374374Slars#define ARG(c,v) (c?(--c,*v++):(char*)0) 1384374Slars 1394374Slarsstatic int _O = 0; /* Internal state */ 1404374Slars/*************** Micro getopt() *********************************************/ 1414374Slars 1424374Slars#define MAX_ABORTS 50 14311990Speter#define MAX_REPORTS 50 1444374Slars#define DEFAULT_CHAT_TIMEOUT 45 1454374Slars 14628597Speterint echo = 0; 14711990Speterint verbose = 0; 14834766Speterint to_log = 1; 14934766Speterint to_stderr = 0; 15028597Speterint Verbose = 0; 15111990Speterint quiet = 0; 15211990Speterint report = 0; 15311990Speterint exit_code = 0; 15411990SpeterFILE* report_fp = (FILE *) 0; 15511990Speterchar *report_file = (char *) 0; 15611990Speterchar *chat_file = (char *) 0; 15734766Speterchar *phone_num = (char *) 0; 15834766Speterchar *phone_num2 = (char *) 0; 15911990Speterint timeout = DEFAULT_CHAT_TIMEOUT; 1604374Slars 1614374Slarsint have_tty_parameters = 0; 16211990Speter 1634374Slars#ifdef TERMIO 16411990Speter#define term_parms struct termio 16511990Speter#define get_term_param(param) ioctl(0, TCGETA, param) 16611990Speter#define set_term_param(param) ioctl(0, TCSETA, param) 1674374Slarsstruct termio saved_tty_parameters; 1684374Slars#endif 16911990Speter 1704374Slars#ifdef TERMIOS 17111990Speter#define term_parms struct termios 17211990Speter#define get_term_param(param) tcgetattr(0, param) 17311990Speter#define set_term_param(param) tcsetattr(0, TCSANOW, param) 1744374Slarsstruct termios saved_tty_parameters; 1754374Slars#endif 1764374Slars 1774374Slarschar *abort_string[MAX_ABORTS], *fail_reason = (char *)0, 1784374Slars fail_buffer[50]; 17928597Speterint n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0; 18028597Speterint clear_abort_next = 0; 1814374Slars 18211990Speterchar *report_string[MAX_REPORTS] ; 18311990Speterchar report_buffer[50] ; 18411990Speterint n_reports = 0, report_next = 0, report_gathering = 0 ; 18528597Speterint clear_report_next = 0; 18611990Speter 18728597Speterint say_next = 0, hup_next = 0; 18828597Speter 18992920Simpvoid *dup_mem(void *b, size_t c); 19092920Simpvoid *copy_of(char *s); 19192920Simpstatic void usage(void); 19292920Simpvoid logf(const char *fmt, ...); 19392920Simpvoid fatal(int code, const char *fmt, ...); 19492920SimpSIGTYPE sigalrm(int signo); 19592920SimpSIGTYPE sigint(int signo); 19692920SimpSIGTYPE sigterm(int signo); 19792920SimpSIGTYPE sighup(int signo); 19892920Simpvoid unalarm(void); 19992920Simpvoid init(void); 20092920Simpvoid set_tty_parameters(void); 20192920Simpvoid echo_stderr(int); 20292920Simpvoid break_sequence(void); 20392920Simpvoid terminate(int status); 20492920Simpvoid do_file(char *chat_file); 20592920Simpint get_string(register char *string); 20692920Simpint put_string(register char *s); 20792920Simpint write_char(int c); 20892920Simpint put_char(int c); 20992920Simpint get_char(void); 21092920Simpvoid chat_send(register char *s); 21192920Simpchar *character(int c); 21292920Simpvoid chat_expect(register char *s); 21392920Simpchar *clean(register char *s, int sending); 21492920Simpvoid break_sequence(void); 21592920Simpvoid terminate(int status); 21692920Simpvoid pack_array(char **array, int end); 21792920Simpchar *expect_strtok(char *, char *); 21892920Simpint vfmtmsg(char *, int, const char *, va_list); /* vsprintf++ */ 2194374Slars 22092920Simpint main(int, char *[]); 22128597Speter 2224374Slarsvoid *dup_mem(b, c) 2234374Slarsvoid *b; 2244374Slarssize_t c; 22534766Speter{ 2264374Slars void *ans = malloc (c); 2274374Slars if (!ans) 22834766Speter fatal(2, "memory error!"); 22934766Speter 2304374Slars memcpy (ans, b, c); 2314374Slars return ans; 23234766Speter} 2334374Slars 2344374Slarsvoid *copy_of (s) 2354374Slarschar *s; 23634766Speter{ 2374374Slars return dup_mem (s, strlen (s) + 1); 23834766Speter} 2394374Slars 2404374Slars/* 24134766Speter * chat [ -v ] [-T number] [-U number] [ -t timeout ] [ -f chat-file ] \ 24234766Speter * [ -r report-file ] \ 2434374Slars * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] 2444374Slars * 2454374Slars * Perform a UUCP-dialer-like chat script on stdin and stdout. 2464374Slars */ 2474374Slarsint 2484374Slarsmain(argc, argv) 24934766Speter int argc; 25034766Speter char **argv; 25134766Speter{ 2524374Slars int option; 2534374Slars char *arg; 2544374Slars 25511990Speter tzset(); 2564374Slars 25734766Speter while ((option = OPTION(argc, argv)) != 0) { 25834766Speter switch (option) { 25934766Speter case 'e': 26034766Speter ++echo; 26134766Speter break; 26228597Speter 26334766Speter case 'v': 26434766Speter ++verbose; 26534766Speter break; 2664374Slars 26734766Speter case 'V': 26834766Speter ++Verbose; 26934766Speter break; 27028597Speter 27134766Speter case 's': 27234766Speter ++to_stderr; 27334766Speter break; 27434766Speter 27534766Speter case 'S': 27634766Speter to_log = 0; 27734766Speter break; 27834766Speter 27934766Speter case 'f': 28034766Speter if ((arg = OPTARG(argc, argv)) != NULL) 2814374Slars chat_file = copy_of(arg); 28234766Speter else 28334766Speter usage(); 28434766Speter break; 2854374Slars 28634766Speter case 't': 28734766Speter if ((arg = OPTARG(argc, argv)) != NULL) 28834766Speter timeout = atoi(arg); 28934766Speter else 29034766Speter usage(); 29134766Speter break; 2924374Slars 29334766Speter case 'r': 29434766Speter arg = OPTARG (argc, argv); 29534766Speter if (arg) { 29634766Speter if (report_fp != NULL) 29734766Speter fclose (report_fp); 29834766Speter report_file = copy_of (arg); 29934766Speter report_fp = fopen (report_file, "a"); 30034766Speter if (report_fp != NULL) { 30134766Speter if (verbose) 30234766Speter fprintf (report_fp, "Opening \"%s\"...\n", 30334766Speter report_file); 30434766Speter report = 1; 30534766Speter } 30634766Speter } 30734766Speter break; 3084374Slars 30934766Speter case 'T': 31034766Speter if ((arg = OPTARG(argc, argv)) != NULL) 31134766Speter phone_num = copy_of(arg); 31234766Speter else 3134374Slars usage(); 31434766Speter break; 31534766Speter 31634766Speter case 'U': 31734766Speter if ((arg = OPTARG(argc, argv)) != NULL) 31834766Speter phone_num2 = copy_of(arg); 31934766Speter else 32034766Speter usage(); 32134766Speter break; 32234766Speter 32334766Speter default: 32434766Speter usage(); 32534766Speter break; 32634766Speter } 32734766Speter } 32811990Speter/* 32911990Speter * Default the report file to the stderr location 33011990Speter */ 33111990Speter if (report_fp == NULL) 33211990Speter report_fp = stderr; 3334374Slars 33434766Speter if (to_log) { 3354374Slars#ifdef ultrix 33634766Speter openlog("chat", LOG_PID); 3374374Slars#else 33834766Speter openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 3394374Slars 34034766Speter if (verbose) 34134766Speter setlogmask(LOG_UPTO(LOG_INFO)); 34234766Speter else 34334766Speter setlogmask(LOG_UPTO(LOG_WARNING)); 3444374Slars#endif 34534766Speter } 3464374Slars 3474374Slars init(); 34811990Speter 34934766Speter if (chat_file != NULL) { 3504374Slars arg = ARG(argc, argv); 3514374Slars if (arg != NULL) 3524374Slars usage(); 3534374Slars else 3544374Slars do_file (chat_file); 35534766Speter } else { 35634766Speter while ((arg = ARG(argc, argv)) != NULL) { 3574374Slars chat_expect(arg); 3584374Slars 35928597Speter if ((arg = ARG(argc, argv)) != NULL) 3604374Slars chat_send(arg); 3614374Slars } 36234766Speter } 3634374Slars 3644374Slars terminate(0); 36528597Speter return 0; 36634766Speter} 3674374Slars 3684374Slars/* 3694374Slars * Process a chat script when read from a file. 3704374Slars */ 3714374Slars 3724374Slarsvoid do_file (chat_file) 3734374Slarschar *chat_file; 37434766Speter{ 37532069Salex int linect, sendflg; 3764374Slars char *sp, *arg, quote; 3774374Slars char buf [STR_LEN]; 3784374Slars FILE *cfp; 3794374Slars 38011990Speter cfp = fopen (chat_file, "r"); 38111990Speter if (cfp == NULL) 38234766Speter fatal(1, "%s -- open failed: %m", chat_file); 3834374Slars 3844374Slars linect = 0; 3854374Slars sendflg = 0; 3864374Slars 38734766Speter while (fgets(buf, STR_LEN, cfp) != NULL) { 3884374Slars sp = strchr (buf, '\n'); 3894374Slars if (sp) 3904374Slars *sp = '\0'; 3914374Slars 3924374Slars linect++; 3934374Slars sp = buf; 39428597Speter 39528597Speter /* lines starting with '#' are comments. If a real '#' 39628597Speter is to be expected, it should be quoted .... */ 39734766Speter if ( *sp == '#' ) 39834766Speter continue; 39928597Speter 40034766Speter while (*sp != '\0') { 40134766Speter if (*sp == ' ' || *sp == '\t') { 4024374Slars ++sp; 4034374Slars continue; 40434766Speter } 4054374Slars 40634766Speter if (*sp == '"' || *sp == '\'') { 4074374Slars quote = *sp++; 4084374Slars arg = sp; 40934766Speter while (*sp != quote) { 4104374Slars if (*sp == '\0') 41134766Speter fatal(1, "unterminated quote (line %d)", linect); 41234766Speter 41334766Speter if (*sp++ == '\\') { 4144374Slars if (*sp != '\0') 4154374Slars ++sp; 4164374Slars } 4174374Slars } 41834766Speter } 41934766Speter else { 4204374Slars arg = sp; 4214374Slars while (*sp != '\0' && *sp != ' ' && *sp != '\t') 4224374Slars ++sp; 42334766Speter } 4244374Slars 4254374Slars if (*sp != '\0') 4264374Slars *sp++ = '\0'; 4274374Slars 4284374Slars if (sendflg) 4294374Slars chat_send (arg); 4304374Slars else 4314374Slars chat_expect (arg); 4324374Slars sendflg = !sendflg; 4334374Slars } 43434766Speter } 4354374Slars fclose (cfp); 43634766Speter} 4374374Slars 4384374Slars/* 4394374Slars * We got an error parsing the command line. 4404374Slars */ 44126880Scharnierstatic void 44226880Scharnierusage() 44334766Speter{ 44434766Speter fprintf(stderr, "\ 44534766SpeterUsage: chat [-e] [-v] [-V] [-t timeout] [-r report-file] [-T phone-number]\n\ 44634766Speter [-U phone-number2] {-f chat-file | chat-script}\n"); 4474374Slars exit(1); 44834766Speter} 4494374Slars 45034766Speterchar line[1024]; 4514374Slars 45234766Speter/* 45334766Speter * Send a message to syslog and/or stderr. 45434766Speter */ 45592920Simpvoid logf(const char *fmt, ...) 45628597Speter{ 45734766Speter va_list args; 4584374Slars 45934766Speter va_start(args, fmt); 46034766Speter vfmtmsg(line, sizeof(line), fmt, args); 46134766Speter if (to_log) 46228597Speter syslog(LOG_INFO, "%s", line); 46334766Speter if (to_stderr) 46434766Speter fprintf(stderr, "%s\n", line); 46528597Speter} 4664374Slars 4674374Slars/* 4684374Slars * Print an error message and terminate. 4694374Slars */ 4704374Slars 47192920Simpvoid fatal(int code, const char *fmt, ...) 47234766Speter{ 47334766Speter va_list args; 4744374Slars 47534766Speter va_start(args, fmt); 47634766Speter vfmtmsg(line, sizeof(line), fmt, args); 47734766Speter if (to_log) 47834766Speter syslog(LOG_ERR, "%s", line); 47934766Speter if (to_stderr) 48034766Speter fprintf(stderr, "%s\n", line); 48134766Speter terminate(code); 48234766Speter} 4834374Slars 4844374Slarsint alarmed = 0; 4854374Slars 4864374SlarsSIGTYPE sigalrm(signo) 4874374Slarsint signo; 48834766Speter{ 4894374Slars int flags; 4904374Slars 4914374Slars alarm(1); 4924374Slars alarmed = 1; /* Reset alarm to avoid race window */ 4934374Slars signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 4944374Slars 4954374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 49634766Speter fatal(2, "Can't get file mode flags on stdin: %m"); 4974374Slars 49834766Speter if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) 49934766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 50034766Speter 5014374Slars if (verbose) 50234766Speter logf("alarm"); 50334766Speter} 5044374Slars 5054374Slarsvoid unalarm() 50634766Speter{ 5074374Slars int flags; 5084374Slars 5094374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 51034766Speter fatal(2, "Can't get file mode flags on stdin: %m"); 5114374Slars 51234766Speter if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1) 51334766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 51434766Speter} 51534766Speter 5164374SlarsSIGTYPE sigint(signo) 5174374Slarsint signo; 51834766Speter{ 51934766Speter fatal(2, "SIGINT"); 52034766Speter} 5214374Slars 5224374SlarsSIGTYPE sigterm(signo) 5234374Slarsint signo; 52434766Speter{ 52534766Speter fatal(2, "SIGTERM"); 52634766Speter} 5274374Slars 5284374SlarsSIGTYPE sighup(signo) 5294374Slarsint signo; 53034766Speter{ 53134766Speter fatal(2, "SIGHUP"); 53234766Speter} 5334374Slars 5344374Slarsvoid init() 53534766Speter{ 5364374Slars signal(SIGINT, sigint); 5374374Slars signal(SIGTERM, sigterm); 5384374Slars signal(SIGHUP, sighup); 5394374Slars 5404374Slars set_tty_parameters(); 5414374Slars signal(SIGALRM, sigalrm); 5424374Slars alarm(0); 5434374Slars alarmed = 0; 54434766Speter} 5454374Slars 5464374Slarsvoid set_tty_parameters() 54734766Speter{ 54811990Speter#if defined(get_term_param) 54911990Speter term_parms t; 5504374Slars 55111990Speter if (get_term_param (&t) < 0) 55234766Speter fatal(2, "Can't get terminal parameters: %m"); 5534374Slars 5544374Slars saved_tty_parameters = t; 55511990Speter have_tty_parameters = 1; 5564374Slars 55711990Speter t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 55811990Speter t.c_oflag = 0; 55911990Speter t.c_lflag = 0; 56011990Speter t.c_cc[VERASE] = 56111990Speter t.c_cc[VKILL] = 0; 56211990Speter t.c_cc[VMIN] = 1; 56311990Speter t.c_cc[VTIME] = 0; 5644374Slars 56511990Speter if (set_term_param (&t) < 0) 56634766Speter fatal(2, "Can't set terminal parameters: %m"); 5674374Slars#endif 56834766Speter} 5694374Slars 5704374Slarsvoid break_sequence() 57134766Speter{ 5724374Slars#ifdef TERMIOS 5734374Slars tcsendbreak (0, 0); 5744374Slars#endif 57534766Speter} 5764374Slars 5774374Slarsvoid terminate(status) 5784374Slarsint status; 57934766Speter{ 58028597Speter echo_stderr(-1); 58134766Speter if (report_file != (char *) 0 && report_fp != (FILE *) NULL) { 58228597Speter/* 58328597Speter * Allow the last of the report string to be gathered before we terminate. 58428597Speter */ 58528597Speter if (report_gathering) { 58628597Speter int c, rep_len; 58728597Speter 58828597Speter rep_len = strlen(report_buffer); 58928597Speter while (rep_len + 1 <= sizeof(report_buffer)) { 59028597Speter alarm(1); 59128597Speter c = get_char(); 59228597Speter alarm(0); 59328597Speter if (c < 0 || iscntrl(c)) 59428597Speter break; 59528597Speter report_buffer[rep_len] = c; 59628597Speter ++rep_len; 59728597Speter } 59828597Speter report_buffer[rep_len] = 0; 59928597Speter fprintf (report_fp, "chat: %s\n", report_buffer); 60028597Speter } 60111990Speter if (verbose) 60211990Speter fprintf (report_fp, "Closing \"%s\".\n", report_file); 60311990Speter fclose (report_fp); 60428597Speter report_fp = (FILE *) NULL; 60534766Speter } 6064374Slars 60711990Speter#if defined(get_term_param) 60834766Speter if (have_tty_parameters) { 60911990Speter if (set_term_param (&saved_tty_parameters) < 0) 61034766Speter fatal(2, "Can't restore terminal parameters: %m"); 61134766Speter } 61211990Speter#endif 6134374Slars 61411990Speter exit(status); 61534766Speter} 6164374Slars 6174374Slars/* 6184374Slars * 'Clean up' this string. 6194374Slars */ 6204374Slarschar *clean(s, sending) 6214374Slarsregister char *s; 62234766Speterint sending; /* set to 1 when sending (putting) this string. */ 62334766Speter{ 6244374Slars char temp[STR_LEN], cur_chr; 62534766Speter register char *s1, *phchar; 6264374Slars int add_return = sending; 6274374Slars#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 6284374Slars 6294374Slars s1 = temp; 63053686Skris /* Don't overflow buffer, leave room for chars we append later */ 63153686Skris while (*s && s1 - temp < sizeof(temp) - 2 - add_return) { 6324374Slars cur_chr = *s++; 63334766Speter if (cur_chr == '^') { 6344374Slars cur_chr = *s++; 63534766Speter if (cur_chr == '\0') { 6364374Slars *s1++ = '^'; 6374374Slars break; 63834766Speter } 6394374Slars cur_chr &= 0x1F; 64034766Speter if (cur_chr != 0) { 6414374Slars *s1++ = cur_chr; 64234766Speter } 6434374Slars continue; 64434766Speter } 6454374Slars 64634766Speter if (cur_chr != '\\') { 6474374Slars *s1++ = cur_chr; 6484374Slars continue; 64934766Speter } 6504374Slars 6514374Slars cur_chr = *s++; 65234766Speter if (cur_chr == '\0') { 65334766Speter if (sending) { 6544374Slars *s1++ = '\\'; 6554374Slars *s1++ = '\\'; 65634766Speter } 6574374Slars break; 65834766Speter } 6594374Slars 66034766Speter switch (cur_chr) { 6614374Slars case 'b': 6624374Slars *s1++ = '\b'; 6634374Slars break; 6644374Slars 6654374Slars case 'c': 6664374Slars if (sending && *s == '\0') 6674374Slars add_return = 0; 6684374Slars else 6694374Slars *s1++ = cur_chr; 6704374Slars break; 6714374Slars 6724374Slars case '\\': 6734374Slars case 'K': 6744374Slars case 'p': 6754374Slars case 'd': 6764374Slars if (sending) 6774374Slars *s1++ = '\\'; 6784374Slars 6794374Slars *s1++ = cur_chr; 6804374Slars break; 6814374Slars 68234766Speter case 'T': 68334766Speter if (sending && phone_num) { 68434766Speter for ( phchar = phone_num; *phchar != '\0'; phchar++) 68534766Speter *s1++ = *phchar; 68634766Speter } 68734766Speter else { 68834766Speter *s1++ = '\\'; 68934766Speter *s1++ = 'T'; 69034766Speter } 69134766Speter break; 69234766Speter 69334766Speter case 'U': 69434766Speter if (sending && phone_num2) { 69534766Speter for ( phchar = phone_num2; *phchar != '\0'; phchar++) 69634766Speter *s1++ = *phchar; 69734766Speter } 69834766Speter else { 69934766Speter *s1++ = '\\'; 70034766Speter *s1++ = 'U'; 70134766Speter } 70234766Speter break; 70334766Speter 7044374Slars case 'q': 70528597Speter quiet = 1; 7064374Slars break; 7074374Slars 7084374Slars case 'r': 7094374Slars *s1++ = '\r'; 7104374Slars break; 7114374Slars 7124374Slars case 'n': 7134374Slars *s1++ = '\n'; 7144374Slars break; 7154374Slars 7164374Slars case 's': 7174374Slars *s1++ = ' '; 7184374Slars break; 7194374Slars 7204374Slars case 't': 7214374Slars *s1++ = '\t'; 7224374Slars break; 7234374Slars 7244374Slars case 'N': 72534766Speter if (sending) { 7264374Slars *s1++ = '\\'; 7274374Slars *s1++ = '\0'; 72834766Speter } 7294374Slars else 7304374Slars *s1++ = 'N'; 7314374Slars break; 73211990Speter 7334374Slars default: 73434766Speter if (isoctal (cur_chr)) { 7354374Slars cur_chr &= 0x07; 73634766Speter if (isoctal (*s)) { 7374374Slars cur_chr <<= 3; 7384374Slars cur_chr |= *s++ - '0'; 73934766Speter if (isoctal (*s)) { 7404374Slars cur_chr <<= 3; 7414374Slars cur_chr |= *s++ - '0'; 7424374Slars } 74334766Speter } 7444374Slars 74534766Speter if (cur_chr != 0 || sending) { 7464374Slars if (sending && (cur_chr == '\\' || cur_chr == 0)) 7474374Slars *s1++ = '\\'; 7484374Slars *s1++ = cur_chr; 74934766Speter } 7504374Slars break; 75134766Speter } 7524374Slars 7534374Slars if (sending) 7544374Slars *s1++ = '\\'; 7554374Slars *s1++ = cur_chr; 7564374Slars break; 7574374Slars } 75834766Speter } 7594374Slars 7604374Slars if (add_return) 7614374Slars *s1++ = '\r'; 7624374Slars 7634374Slars *s1++ = '\0'; /* guarantee closure */ 7644374Slars *s1++ = '\0'; /* terminate the string */ 7654374Slars return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 76634766Speter} 7674374Slars 7684374Slars/* 76928597Speter * A modified version of 'strtok'. This version skips \ sequences. 77028597Speter */ 77128597Speter 77228597Speterchar *expect_strtok (s, term) 77334766Speter char *s, *term; 77434766Speter{ 77528597Speter static char *str = ""; 77628597Speter int escape_flag = 0; 77728597Speter char *result; 77834766Speter 77928597Speter/* 78028597Speter * If a string was specified then do initial processing. 78128597Speter */ 78228597Speter if (s) 78328597Speter str = s; 78434766Speter 78528597Speter/* 78628597Speter * If this is the escape flag then reset it and ignore the character. 78728597Speter */ 78828597Speter if (*str) 78928597Speter result = str; 79028597Speter else 79128597Speter result = (char *) 0; 79228597Speter 79334766Speter while (*str) { 79434766Speter if (escape_flag) { 79528597Speter escape_flag = 0; 79628597Speter ++str; 79728597Speter continue; 79834766Speter } 79928597Speter 80034766Speter if (*str == '\\') { 80128597Speter ++str; 80228597Speter escape_flag = 1; 80328597Speter continue; 80434766Speter } 80534766Speter 80628597Speter/* 80728597Speter * If this is not in the termination string, continue. 80828597Speter */ 80934766Speter if (strchr (term, *str) == (char *) 0) { 81028597Speter ++str; 81128597Speter continue; 81234766Speter } 81334766Speter 81428597Speter/* 81528597Speter * This is the terminator. Mark the end of the string and stop. 81628597Speter */ 81728597Speter *str++ = '\0'; 81828597Speter break; 81934766Speter } 82028597Speter return (result); 82134766Speter} 82228597Speter 82328597Speter/* 8244374Slars * Process the expect string 8254374Slars */ 82628597Speter 82728597Spetervoid chat_expect (s) 82828597Speterchar *s; 82934766Speter{ 83028597Speter char *expect; 83128597Speter char *reply; 83228597Speter 83334766Speter if (strcmp(s, "HANGUP") == 0) { 83428597Speter ++hup_next; 83528597Speter return; 83634766Speter } 83728597Speter 83834766Speter if (strcmp(s, "ABORT") == 0) { 8394374Slars ++abort_next; 8404374Slars return; 84134766Speter } 8424374Slars 84334766Speter if (strcmp(s, "CLR_ABORT") == 0) { 84428597Speter ++clear_abort_next; 84528597Speter return; 84634766Speter } 84728597Speter 84834766Speter if (strcmp(s, "REPORT") == 0) { 84911990Speter ++report_next; 85011990Speter return; 85134766Speter } 85211990Speter 85334766Speter if (strcmp(s, "CLR_REPORT") == 0) { 85428597Speter ++clear_report_next; 85528597Speter return; 85634766Speter } 85728597Speter 85834766Speter if (strcmp(s, "TIMEOUT") == 0) { 8594374Slars ++timeout_next; 8604374Slars return; 86134766Speter } 8624374Slars 86334766Speter if (strcmp(s, "ECHO") == 0) { 86428597Speter ++echo_next; 86528597Speter return; 86634766Speter } 86734766Speter 86834766Speter if (strcmp(s, "SAY") == 0) { 86928597Speter ++say_next; 87028597Speter return; 87134766Speter } 87234766Speter 87328597Speter/* 87428597Speter * Fetch the expect and reply string. 87528597Speter */ 87634766Speter for (;;) { 87728597Speter expect = expect_strtok (s, "-"); 87828597Speter s = (char *) 0; 8794374Slars 88028597Speter if (expect == (char *) 0) 88128597Speter return; 88228597Speter 88328597Speter reply = expect_strtok (s, "-"); 88434766Speter 88528597Speter/* 88628597Speter * Handle the expect string. If successful then exit. 88728597Speter */ 88828597Speter if (get_string (expect)) 88928597Speter return; 89034766Speter 89128597Speter/* 89228597Speter * If there is a sub-reply string then send it. Otherwise any condition 89328597Speter * is terminal. 89428597Speter */ 89528597Speter if (reply == (char *) 0 || exit_code != 3) 89628597Speter break; 8974374Slars 89828597Speter chat_send (reply); 89934766Speter } 90034766Speter 90128597Speter/* 90228597Speter * The expectation did not occur. This is terminal. 90328597Speter */ 90428597Speter if (fail_reason) 90534766Speter logf("Failed (%s)", fail_reason); 90628597Speter else 90734766Speter logf("Failed"); 90828597Speter terminate(exit_code); 90934766Speter} 9104374Slars 91128597Speter/* 91228597Speter * Translate the input character to the appropriate string for printing 91328597Speter * the data. 91428597Speter */ 91528597Speter 9164374Slarschar *character(c) 91711990Speterint c; 91834766Speter{ 9194374Slars static char string[10]; 9204374Slars char *meta; 9214374Slars 9224374Slars meta = (c & 0x80) ? "M-" : ""; 9234374Slars c &= 0x7F; 9244374Slars 9254374Slars if (c < 32) 9264374Slars sprintf(string, "%s^%c", meta, (int)c + '@'); 92734766Speter else if (c == 127) 92834766Speter sprintf(string, "%s^?", meta); 9294374Slars else 93034766Speter sprintf(string, "%s%c", meta, c); 9314374Slars 9324374Slars return (string); 93334766Speter} 9344374Slars 9354374Slars/* 9364374Slars * process the reply string 9374374Slars */ 9384374Slarsvoid chat_send (s) 9394374Slarsregister char *s; 94034766Speter{ 94134766Speter if (say_next) { 94228597Speter say_next = 0; 94328597Speter s = clean(s,0); 94480381Ssheldonh write(STDERR_FILENO, s, strlen(s)); 94528597Speter free(s); 94628597Speter return; 94734766Speter } 94834766Speter 94934766Speter if (hup_next) { 95028597Speter hup_next = 0; 95128597Speter if (strcmp(s, "OFF") == 0) 95228597Speter signal(SIGHUP, SIG_IGN); 95328597Speter else 95428597Speter signal(SIGHUP, sighup); 95528597Speter return; 95634766Speter } 95734766Speter 95834766Speter if (echo_next) { 95928597Speter echo_next = 0; 96028597Speter echo = (strcmp(s, "ON") == 0); 96128597Speter return; 96234766Speter } 96334766Speter 96434766Speter if (abort_next) { 9654374Slars char *s1; 96611990Speter 9674374Slars abort_next = 0; 96811990Speter 9694374Slars if (n_aborts >= MAX_ABORTS) 97034766Speter fatal(2, "Too many ABORT strings"); 97111990Speter 9724374Slars s1 = clean(s, 0); 97311990Speter 97411990Speter if (strlen(s1) > strlen(s) 97511990Speter || strlen(s1) + 1 > sizeof(fail_buffer)) 97634766Speter fatal(1, "Illegal or too-long ABORT string ('%v')", s); 9774374Slars 9784374Slars abort_string[n_aborts++] = s1; 9794374Slars 9804374Slars if (verbose) 98134766Speter logf("abort on (%v)", s); 98211990Speter return; 98334766Speter } 98411990Speter 98534766Speter if (clear_abort_next) { 98628597Speter char *s1; 98728597Speter int i; 98828597Speter int old_max; 98928597Speter int pack = 0; 99028597Speter 99128597Speter clear_abort_next = 0; 99228597Speter 99328597Speter s1 = clean(s, 0); 99428597Speter 99528597Speter if (strlen(s1) > strlen(s) 99628597Speter || strlen(s1) + 1 > sizeof(fail_buffer)) 99734766Speter fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s); 99828597Speter 99928597Speter old_max = n_aborts; 100034766Speter for (i=0; i < n_aborts; i++) { 100134766Speter if ( strcmp(s1,abort_string[i]) == 0 ) { 100234766Speter free(abort_string[i]); 100334766Speter abort_string[i] = NULL; 100434766Speter pack++; 100534766Speter n_aborts--; 100634766Speter if (verbose) 100734766Speter logf("clear abort on (%v)", s); 100828597Speter } 100934766Speter } 101028597Speter free(s1); 101134766Speter if (pack) 101234766Speter pack_array(abort_string,old_max); 101328597Speter return; 101434766Speter } 101528597Speter 101634766Speter if (report_next) { 101711990Speter char *s1; 101811990Speter 101911990Speter report_next = 0; 102011990Speter if (n_reports >= MAX_REPORTS) 102134766Speter fatal(2, "Too many REPORT strings"); 102211990Speter 102311990Speter s1 = clean(s, 0); 102411990Speter 102511990Speter if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 102634766Speter fatal(1, "Illegal or too-long REPORT string ('%v')", s); 102711990Speter 102811990Speter report_string[n_reports++] = s1; 102911990Speter 103011990Speter if (verbose) 103134766Speter logf("report (%v)", s); 103211990Speter return; 103334766Speter } 10344374Slars 103534766Speter if (clear_report_next) { 103628597Speter char *s1; 103728597Speter int i; 103828597Speter int old_max; 103928597Speter int pack = 0; 104028597Speter 104128597Speter clear_report_next = 0; 104228597Speter 104328597Speter s1 = clean(s, 0); 104428597Speter 104528597Speter if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 104634766Speter fatal(1, "Illegal or too-long REPORT string ('%v')", s); 104728597Speter 104828597Speter old_max = n_reports; 104934766Speter for (i=0; i < n_reports; i++) { 105034766Speter if ( strcmp(s1,report_string[i]) == 0 ) { 105134766Speter free(report_string[i]); 105234766Speter report_string[i] = NULL; 105334766Speter pack++; 105434766Speter n_reports--; 105534766Speter if (verbose) 105634766Speter logf("clear report (%v)", s); 105728597Speter } 105834766Speter } 105928597Speter free(s1); 106034766Speter if (pack) 106134766Speter pack_array(report_string,old_max); 106228597Speter 106328597Speter return; 106434766Speter } 106528597Speter 106634766Speter if (timeout_next) { 106711990Speter timeout_next = 0; 106811990Speter timeout = atoi(s); 106911990Speter 107011990Speter if (timeout <= 0) 107111990Speter timeout = DEFAULT_CHAT_TIMEOUT; 10724374Slars 107311990Speter if (verbose) 107434766Speter logf("timeout set to %d seconds", timeout); 107534766Speter 107611990Speter return; 107734766Speter } 107811990Speter 107911990Speter if (strcmp(s, "EOT") == 0) 108011990Speter s = "^D\\c"; 108134766Speter else if (strcmp(s, "BREAK") == 0) 108234766Speter s = "\\K\\c"; 108311990Speter 108411990Speter if (!put_string(s)) 108534766Speter fatal(1, "Failed"); 108634766Speter} 10874374Slars 10884374Slarsint get_char() 108934766Speter{ 10904374Slars int status; 10914374Slars char c; 10924374Slars 109380381Ssheldonh status = read(STDIN_FILENO, &c, 1); 10944374Slars 109534766Speter switch (status) { 109611990Speter case 1: 109711990Speter return ((int)c & 0x7F); 10984374Slars 109911990Speter default: 110034766Speter logf("warning: read() on stdin returned %d", status); 11014374Slars 110211990Speter case -1: 110311990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 110434766Speter fatal(2, "Can't get file mode flags on stdin: %m"); 110534766Speter 110634766Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 110734766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 110811990Speter 110911990Speter return (-1); 11104374Slars } 111134766Speter} 11124374Slars 11134374Slarsint put_char(c) 111411990Speterint c; 111534766Speter{ 11164374Slars int status; 111711990Speter char ch = c; 11184374Slars 111911990Speter usleep(10000); /* inter-character typing delay (?) */ 11204374Slars 112180381Ssheldonh status = write(STDOUT_FILENO, &ch, 1); 11224374Slars 112334766Speter switch (status) { 112411990Speter case 1: 112511990Speter return (0); 112611990Speter 112711990Speter default: 112834766Speter logf("warning: write() on stdout returned %d", status); 112911990Speter 113011990Speter case -1: 113111990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 113234766Speter fatal(2, "Can't get file mode flags on stdin, %m"); 113334766Speter 113434766Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 113534766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 113611990Speter 113711990Speter return (-1); 11384374Slars } 113934766Speter} 11404374Slars 11414374Slarsint write_char (c) 11424374Slarsint c; 114334766Speter{ 114434766Speter if (alarmed || put_char(c) < 0) { 114511990Speter alarm(0); 114611990Speter alarmed = 0; 11474374Slars 114834766Speter if (verbose) { 11494374Slars if (errno == EINTR || errno == EWOULDBLOCK) 115034766Speter logf(" -- write timed out"); 11514374Slars else 115234766Speter logf(" -- write failed: %m"); 115334766Speter } 11544374Slars return (0); 115534766Speter } 11564374Slars return (1); 115734766Speter} 11584374Slars 11594374Slarsint put_string (s) 11604374Slarsregister char *s; 116134766Speter{ 116228597Speter quiet = 0; 11634374Slars s = clean(s, 1); 11644374Slars 116534766Speter if (verbose) { 11664374Slars if (quiet) 116734766Speter logf("send (??????)"); 11684374Slars else 116934766Speter logf("send (%v)", s); 117034766Speter } 11714374Slars 11724374Slars alarm(timeout); alarmed = 0; 11734374Slars 117434766Speter while (*s) { 11754374Slars register char c = *s++; 11764374Slars 117734766Speter if (c != '\\') { 11784374Slars if (!write_char (c)) 11794374Slars return 0; 11804374Slars continue; 118134766Speter } 11824374Slars 11834374Slars c = *s++; 118434766Speter switch (c) { 11854374Slars case 'd': 11864374Slars sleep(1); 11874374Slars break; 11884374Slars 11894374Slars case 'K': 11904374Slars break_sequence(); 11914374Slars break; 11924374Slars 11934374Slars case 'p': 119411990Speter usleep(10000); /* 1/100th of a second (arg is microseconds) */ 11954374Slars break; 11964374Slars 11974374Slars default: 11984374Slars if (!write_char (c)) 11994374Slars return 0; 12004374Slars break; 12014374Slars } 120234766Speter } 12034374Slars 12044374Slars alarm(0); 12054374Slars alarmed = 0; 12064374Slars return (1); 120734766Speter} 12084374Slars 12094374Slars/* 121028597Speter * Echo a character to stderr. 121128597Speter * When called with -1, a '\n' character is generated when 121228597Speter * the cursor is not at the beginning of a line. 121328597Speter */ 121428597Spetervoid echo_stderr(n) 121528597Speterint n; 121634766Speter{ 121734766Speter static int need_lf; 121834766Speter char *s; 121928597Speter 122034766Speter switch (n) { 122134766Speter case '\r': /* ignore '\r' */ 122234766Speter break; 122334766Speter case -1: 122434766Speter if (need_lf == 0) 122528597Speter break; 122634766Speter /* fall through */ 122734766Speter case '\n': 122880381Ssheldonh write(STDERR_FILENO, "\n", 1); 122934766Speter need_lf = 0; 123034766Speter break; 123134766Speter default: 123234766Speter s = character(n); 123380381Ssheldonh write(STDERR_FILENO, s, strlen(s)); 123434766Speter need_lf = 1; 123534766Speter break; 123628597Speter } 123734766Speter} 123828597Speter 123928597Speter/* 12404374Slars * 'Wait for' this string to appear on this file descriptor. 12414374Slars */ 12424374Slarsint get_string(string) 12434374Slarsregister char *string; 124434766Speter{ 12454374Slars char temp[STR_LEN]; 12464374Slars int c, printed = 0, len, minlen; 12474374Slars register char *s = temp, *end = s + STR_LEN; 124834766Speter char *logged = temp; 12494374Slars 12504374Slars fail_reason = (char *)0; 125153686Skris 125253686Skris if (strlen(string) > STR_LEN) { 125353686Skris logf("expect string is too long"); 125453686Skris exit_code = 1; 125553686Skris return 0; 125653686Skris } 125753686Skris 12584374Slars string = clean(string, 0); 12594374Slars len = strlen(string); 12604374Slars minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 12614374Slars 12624374Slars if (verbose) 126334766Speter logf("expect (%v)", string); 12644374Slars 126534766Speter if (len == 0) { 12664374Slars if (verbose) 126734766Speter logf("got it"); 12684374Slars return (1); 126934766Speter } 12704374Slars 127111990Speter alarm(timeout); 127211990Speter alarmed = 0; 12734374Slars 127434766Speter while ( ! alarmed && (c = get_char()) >= 0) { 127511990Speter int n, abort_len, report_len; 12764374Slars 127728597Speter if (echo) 127828597Speter echo_stderr(c); 127934766Speter if (verbose && c == '\n') { 128034766Speter if (s == logged) 128134766Speter logf(""); /* blank line */ 12824374Slars else 128334766Speter logf("%0.*v", s - logged, logged); 128434766Speter logged = s + 1; 128534766Speter } 12864374Slars 128734766Speter *s++ = c; 128834766Speter 128934766Speter if (verbose && s >= logged + 80) { 129034766Speter logf("%0.*v", s - logged, logged); 129134766Speter logged = s; 129234766Speter } 129334766Speter 129428597Speter if (Verbose) { 129534766Speter if (c == '\n') 129634766Speter fputc( '\n', stderr ); 129734766Speter else if (c != '\r') 129834766Speter fprintf( stderr, "%s", character(c) ); 129928597Speter } 130028597Speter 130134766Speter if (!report_gathering) { 130234766Speter for (n = 0; n < n_reports; ++n) { 130311990Speter if ((report_string[n] != (char*) NULL) && 130411990Speter s - temp >= (report_len = strlen(report_string[n])) && 130534766Speter strncmp(s - report_len, report_string[n], report_len) == 0) { 130611990Speter time_t time_now = time ((time_t*) NULL); 130711990Speter struct tm* tm_now = localtime (&time_now); 130811990Speter 130911990Speter strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 131011990Speter strcat (report_buffer, report_string[n]); 131111990Speter 131211990Speter report_string[n] = (char *) NULL; 131311990Speter report_gathering = 1; 131411990Speter break; 131534766Speter } 131611990Speter } 131734766Speter } 131834766Speter else { 131934766Speter if (!iscntrl (c)) { 132011990Speter int rep_len = strlen (report_buffer); 132111990Speter report_buffer[rep_len] = c; 132211990Speter report_buffer[rep_len + 1] = '\0'; 132334766Speter } 132434766Speter else { 132511990Speter report_gathering = 0; 132611990Speter fprintf (report_fp, "chat: %s\n", report_buffer); 132711990Speter } 132834766Speter } 132911990Speter 133028597Speter if (s - temp >= len && 133128597Speter c == string[len - 1] && 133234766Speter strncmp(s - len, string, len) == 0) { 133334766Speter if (verbose) { 133434766Speter if (s > logged) 133534766Speter logf("%0.*v", s - logged, logged); 133628597Speter logf(" -- got it\n"); 133734766Speter } 133828597Speter 133928597Speter alarm(0); 134028597Speter alarmed = 0; 134128597Speter return (1); 134234766Speter } 134328597Speter 134434766Speter for (n = 0; n < n_aborts; ++n) { 134528597Speter if (s - temp >= (abort_len = strlen(abort_string[n])) && 134634766Speter strncmp(s - abort_len, abort_string[n], abort_len) == 0) { 134734766Speter if (verbose) { 134834766Speter if (s > logged) 134934766Speter logf("%0.*v", s - logged, logged); 135034766Speter logf(" -- failed"); 135134766Speter } 135234766Speter 135328597Speter alarm(0); 135428597Speter alarmed = 0; 135528597Speter exit_code = n + 4; 135628597Speter strcpy(fail_reason = fail_buffer, abort_string[n]); 135728597Speter return (0); 135828597Speter } 135934766Speter } 136028597Speter 136134766Speter if (s >= end) { 136234766Speter if (logged < s - minlen) { 136334766Speter logf("%0.*v", s - logged, logged); 136434766Speter logged = s; 136534766Speter } 136634766Speter s -= minlen; 136734766Speter memmove(temp, s, minlen); 136834766Speter logged = temp + (logged - s); 13694374Slars s = temp + minlen; 137034766Speter } 13714374Slars 13724374Slars if (alarmed && verbose) 137334766Speter logf("warning: alarm synchronization problem"); 137434766Speter } 13754374Slars 13764374Slars alarm(0); 137711990Speter 137834766Speter if (verbose && printed) { 13794374Slars if (alarmed) 138034766Speter logf(" -- read timed out"); 13814374Slars else 138234766Speter logf(" -- read failed: %m"); 138334766Speter } 13844374Slars 138511990Speter exit_code = 3; 138611990Speter alarmed = 0; 13874374Slars return (0); 138834766Speter} 13894374Slars 139037126Speter/* 139137126Speter * Gross kludge to handle Solaris versions >= 2.6 having usleep. 139237126Speter */ 139337126Speter#ifdef SOL2 139437126Speter#include <sys/param.h> 139537126Speter#if MAXUID > 65536 /* then this is Solaris 2.6 or later */ 139637126Speter#undef NO_USLEEP 139737126Speter#endif 139837126Speter#endif /* SOL2 */ 139937126Speter 140011990Speter#ifdef NO_USLEEP 14014374Slars#include <sys/types.h> 14024374Slars#include <sys/time.h> 14034374Slars 14044374Slars/* 14054374Slars usleep -- support routine for 4.2BSD system call emulations 14064374Slars last edit: 29-Oct-1984 D A Gwyn 14074374Slars */ 14084374Slars 14094374Slarsextern int select(); 14104374Slars 14114374Slarsint 14124374Slarsusleep( usec ) /* returns 0 if ok, else -1 */ 14134374Slars long usec; /* delay in microseconds */ 14144374Slars{ 141534766Speter static struct { /* `timeval' */ 141611990Speter long tv_sec; /* seconds */ 141711990Speter long tv_usec; /* microsecs */ 141834766Speter } delay; /* _select() timeout */ 14194374Slars 142011990Speter delay.tv_sec = usec / 1000000L; 14214374Slars delay.tv_usec = usec % 1000000L; 14224374Slars 142334766Speter return select(0, (long *)0, (long *)0, (long *)0, &delay); 14244374Slars} 14254374Slars#endif 142628597Speter 142728597Spetervoid 142828597Speterpack_array (array, end) 142928597Speter char **array; /* The address of the array of string pointers */ 143028597Speter int end; /* The index of the next free entry before CLR_ */ 143128597Speter{ 143228597Speter int i, j; 143328597Speter 143428597Speter for (i = 0; i < end; i++) { 143528597Speter if (array[i] == NULL) { 143628597Speter for (j = i+1; j < end; ++j) 143728597Speter if (array[j] != NULL) 143828597Speter array[i++] = array[j]; 143928597Speter for (; i < end; ++i) 144028597Speter array[i] = NULL; 144128597Speter break; 144228597Speter } 144328597Speter } 144428597Speter} 144534766Speter 144634766Speter/* 144734766Speter * vfmtmsg - format a message into a buffer. Like vsprintf except we 144834766Speter * also specify the length of the output buffer, and we handle the 144934766Speter * %m (error message) format. 145034766Speter * Doesn't do floating-point formats. 145134766Speter * Returns the number of chars put into buf. 145234766Speter */ 145334766Speter#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) 145434766Speter 145534766Speterint 145634766Spetervfmtmsg(buf, buflen, fmt, args) 145734766Speter char *buf; 145834766Speter int buflen; 145934766Speter const char *fmt; 146034766Speter va_list args; 146134766Speter{ 146234766Speter int c, i, n; 146334766Speter int width, prec, fillch; 146434766Speter int base, len, neg, quoted; 146534766Speter unsigned long val = 0; 146634766Speter char *str, *buf0; 146734766Speter const char *f; 146834766Speter unsigned char *p; 146934766Speter char num[32]; 147034766Speter static char hexchars[] = "0123456789abcdef"; 147134766Speter 147234766Speter buf0 = buf; 147334766Speter --buflen; 147434766Speter while (buflen > 0) { 147534766Speter for (f = fmt; *f != '%' && *f != 0; ++f) 147634766Speter ; 147734766Speter if (f > fmt) { 147834766Speter len = f - fmt; 147934766Speter if (len > buflen) 148034766Speter len = buflen; 148134766Speter memcpy(buf, fmt, len); 148234766Speter buf += len; 148334766Speter buflen -= len; 148434766Speter fmt = f; 148534766Speter } 148634766Speter if (*fmt == 0) 148734766Speter break; 148834766Speter c = *++fmt; 148934766Speter width = prec = 0; 149034766Speter fillch = ' '; 149134766Speter if (c == '0') { 149234766Speter fillch = '0'; 149334766Speter c = *++fmt; 149434766Speter } 149534766Speter if (c == '*') { 149634766Speter width = va_arg(args, int); 149734766Speter c = *++fmt; 149834766Speter } else { 149934766Speter while (isdigit(c)) { 150034766Speter width = width * 10 + c - '0'; 150134766Speter c = *++fmt; 150234766Speter } 150334766Speter } 150434766Speter if (c == '.') { 150534766Speter c = *++fmt; 150634766Speter if (c == '*') { 150734766Speter prec = va_arg(args, int); 150834766Speter c = *++fmt; 150934766Speter } else { 151034766Speter while (isdigit(c)) { 151134766Speter prec = prec * 10 + c - '0'; 151234766Speter c = *++fmt; 151334766Speter } 151434766Speter } 151534766Speter } 151634766Speter str = 0; 151734766Speter base = 0; 151834766Speter neg = 0; 151934766Speter ++fmt; 152034766Speter switch (c) { 152134766Speter case 'd': 152234766Speter i = va_arg(args, int); 152334766Speter if (i < 0) { 152434766Speter neg = 1; 152534766Speter val = -i; 152634766Speter } else 152734766Speter val = i; 152834766Speter base = 10; 152934766Speter break; 153034766Speter case 'o': 153134766Speter val = va_arg(args, unsigned int); 153234766Speter base = 8; 153334766Speter break; 153434766Speter case 'x': 153534766Speter val = va_arg(args, unsigned int); 153634766Speter base = 16; 153734766Speter break; 153834766Speter case 'p': 153934766Speter val = (unsigned long) va_arg(args, void *); 154034766Speter base = 16; 154134766Speter neg = 2; 154234766Speter break; 154334766Speter case 's': 154434766Speter str = va_arg(args, char *); 154534766Speter break; 154634766Speter case 'c': 154734766Speter num[0] = va_arg(args, int); 154834766Speter num[1] = 0; 154934766Speter str = num; 155034766Speter break; 155134766Speter case 'm': 155234766Speter str = strerror(errno); 155334766Speter break; 155434766Speter case 'v': /* "visible" string */ 155534766Speter case 'q': /* quoted string */ 155634766Speter quoted = c == 'q'; 155734766Speter p = va_arg(args, unsigned char *); 155834766Speter if (fillch == '0' && prec > 0) { 155934766Speter n = prec; 156034766Speter } else { 156134766Speter n = strlen((char *)p); 156234766Speter if (prec > 0 && prec < n) 156334766Speter n = prec; 156434766Speter } 156534766Speter while (n > 0 && buflen > 0) { 156634766Speter c = *p++; 156734766Speter --n; 156834766Speter if (!quoted && c >= 0x80) { 156934766Speter OUTCHAR('M'); 157034766Speter OUTCHAR('-'); 157134766Speter c -= 0x80; 157234766Speter } 157334766Speter if (quoted && (c == '"' || c == '\\')) 157434766Speter OUTCHAR('\\'); 157534766Speter if (c < 0x20 || (0x7f <= c && c < 0xa0)) { 157634766Speter if (quoted) { 157734766Speter OUTCHAR('\\'); 157834766Speter switch (c) { 157934766Speter case '\t': OUTCHAR('t'); break; 158034766Speter case '\n': OUTCHAR('n'); break; 158134766Speter case '\b': OUTCHAR('b'); break; 158234766Speter case '\f': OUTCHAR('f'); break; 158334766Speter default: 158434766Speter OUTCHAR('x'); 158534766Speter OUTCHAR(hexchars[c >> 4]); 158634766Speter OUTCHAR(hexchars[c & 0xf]); 158734766Speter } 158834766Speter } else { 158934766Speter if (c == '\t') 159034766Speter OUTCHAR(c); 159134766Speter else { 159234766Speter OUTCHAR('^'); 159334766Speter OUTCHAR(c ^ 0x40); 159434766Speter } 159534766Speter } 159634766Speter } else 159734766Speter OUTCHAR(c); 159834766Speter } 159934766Speter continue; 160034766Speter default: 160134766Speter *buf++ = '%'; 160234766Speter if (c != '%') 160334766Speter --fmt; /* so %z outputs %z etc. */ 160434766Speter --buflen; 160534766Speter continue; 160634766Speter } 160734766Speter if (base != 0) { 160834766Speter str = num + sizeof(num); 160934766Speter *--str = 0; 161034766Speter while (str > num + neg) { 161134766Speter *--str = hexchars[val % base]; 161234766Speter val = val / base; 161334766Speter if (--prec <= 0 && val == 0) 161434766Speter break; 161534766Speter } 161634766Speter switch (neg) { 161734766Speter case 1: 161834766Speter *--str = '-'; 161934766Speter break; 162034766Speter case 2: 162134766Speter *--str = 'x'; 162234766Speter *--str = '0'; 162334766Speter break; 162434766Speter } 162534766Speter len = num + sizeof(num) - 1 - str; 162634766Speter } else { 162734766Speter len = strlen(str); 162834766Speter if (prec > 0 && len > prec) 162934766Speter len = prec; 163034766Speter } 163134766Speter if (width > 0) { 163234766Speter if (width > buflen) 163334766Speter width = buflen; 163434766Speter if ((n = width - len) > 0) { 163534766Speter buflen -= n; 163634766Speter for (; n > 0; --n) 163734766Speter *buf++ = fillch; 163834766Speter } 163934766Speter } 164034766Speter if (len > buflen) 164134766Speter len = buflen; 164234766Speter memcpy(buf, str, len); 164334766Speter buf += len; 164434766Speter buflen -= len; 164534766Speter } 164634766Speter *buf = 0; 164734766Speter return buf - buf0; 164834766Speter} 1649