chat.c revision 102412
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 102412 2002-08-25 13:23:09Z charnier $"; 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 2204374Slarsvoid *dup_mem(b, c) 2214374Slarsvoid *b; 2224374Slarssize_t c; 22334766Speter{ 2244374Slars void *ans = malloc (c); 2254374Slars if (!ans) 22634766Speter fatal(2, "memory error!"); 22734766Speter 2284374Slars memcpy (ans, b, c); 2294374Slars return ans; 23034766Speter} 2314374Slars 2324374Slarsvoid *copy_of (s) 2334374Slarschar *s; 23434766Speter{ 2354374Slars return dup_mem (s, strlen (s) + 1); 23634766Speter} 2374374Slars 2384374Slars/* 23934766Speter * chat [ -v ] [-T number] [-U number] [ -t timeout ] [ -f chat-file ] \ 24034766Speter * [ -r report-file ] \ 2414374Slars * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] 2424374Slars * 2434374Slars * Perform a UUCP-dialer-like chat script on stdin and stdout. 2444374Slars */ 2454374Slarsint 2464374Slarsmain(argc, argv) 24734766Speter int argc; 24834766Speter char **argv; 24934766Speter{ 2504374Slars int option; 2514374Slars char *arg; 2524374Slars 25311990Speter tzset(); 2544374Slars 25534766Speter while ((option = OPTION(argc, argv)) != 0) { 25634766Speter switch (option) { 25734766Speter case 'e': 25834766Speter ++echo; 25934766Speter break; 26028597Speter 26134766Speter case 'v': 26234766Speter ++verbose; 26334766Speter break; 2644374Slars 26534766Speter case 'V': 26634766Speter ++Verbose; 26734766Speter break; 26828597Speter 26934766Speter case 's': 27034766Speter ++to_stderr; 27134766Speter break; 27234766Speter 27334766Speter case 'S': 27434766Speter to_log = 0; 27534766Speter break; 27634766Speter 27734766Speter case 'f': 27834766Speter if ((arg = OPTARG(argc, argv)) != NULL) 2794374Slars chat_file = copy_of(arg); 28034766Speter else 28134766Speter usage(); 28234766Speter break; 2834374Slars 28434766Speter case 't': 28534766Speter if ((arg = OPTARG(argc, argv)) != NULL) 28634766Speter timeout = atoi(arg); 28734766Speter else 28834766Speter usage(); 28934766Speter break; 2904374Slars 29134766Speter case 'r': 29234766Speter arg = OPTARG (argc, argv); 29334766Speter if (arg) { 29434766Speter if (report_fp != NULL) 29534766Speter fclose (report_fp); 29634766Speter report_file = copy_of (arg); 29734766Speter report_fp = fopen (report_file, "a"); 29834766Speter if (report_fp != NULL) { 29934766Speter if (verbose) 30034766Speter fprintf (report_fp, "Opening \"%s\"...\n", 30134766Speter report_file); 30234766Speter report = 1; 30334766Speter } 30434766Speter } 30534766Speter break; 3064374Slars 30734766Speter case 'T': 30834766Speter if ((arg = OPTARG(argc, argv)) != NULL) 30934766Speter phone_num = copy_of(arg); 31034766Speter else 3114374Slars usage(); 31234766Speter break; 31334766Speter 31434766Speter case 'U': 31534766Speter if ((arg = OPTARG(argc, argv)) != NULL) 31634766Speter phone_num2 = copy_of(arg); 31734766Speter else 31834766Speter usage(); 31934766Speter break; 32034766Speter 32134766Speter default: 32234766Speter usage(); 32334766Speter break; 32434766Speter } 32534766Speter } 32611990Speter/* 32711990Speter * Default the report file to the stderr location 32811990Speter */ 32911990Speter if (report_fp == NULL) 33011990Speter report_fp = stderr; 3314374Slars 33234766Speter if (to_log) { 3334374Slars#ifdef ultrix 33434766Speter openlog("chat", LOG_PID); 3354374Slars#else 33634766Speter openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 3374374Slars 33834766Speter if (verbose) 33934766Speter setlogmask(LOG_UPTO(LOG_INFO)); 34034766Speter else 34134766Speter setlogmask(LOG_UPTO(LOG_WARNING)); 3424374Slars#endif 34334766Speter } 3444374Slars 3454374Slars init(); 34611990Speter 34734766Speter if (chat_file != NULL) { 3484374Slars arg = ARG(argc, argv); 3494374Slars if (arg != NULL) 3504374Slars usage(); 3514374Slars else 3524374Slars do_file (chat_file); 35334766Speter } else { 35434766Speter while ((arg = ARG(argc, argv)) != NULL) { 3554374Slars chat_expect(arg); 3564374Slars 35728597Speter if ((arg = ARG(argc, argv)) != NULL) 3584374Slars chat_send(arg); 3594374Slars } 36034766Speter } 3614374Slars 3624374Slars terminate(0); 36328597Speter return 0; 36434766Speter} 3654374Slars 3664374Slars/* 3674374Slars * Process a chat script when read from a file. 3684374Slars */ 3694374Slars 3704374Slarsvoid do_file (chat_file) 3714374Slarschar *chat_file; 37234766Speter{ 37332069Salex int linect, sendflg; 3744374Slars char *sp, *arg, quote; 3754374Slars char buf [STR_LEN]; 3764374Slars FILE *cfp; 3774374Slars 37811990Speter cfp = fopen (chat_file, "r"); 37911990Speter if (cfp == NULL) 38034766Speter fatal(1, "%s -- open failed: %m", chat_file); 3814374Slars 3824374Slars linect = 0; 3834374Slars sendflg = 0; 3844374Slars 38534766Speter while (fgets(buf, STR_LEN, cfp) != NULL) { 3864374Slars sp = strchr (buf, '\n'); 3874374Slars if (sp) 3884374Slars *sp = '\0'; 3894374Slars 3904374Slars linect++; 3914374Slars sp = buf; 39228597Speter 39328597Speter /* lines starting with '#' are comments. If a real '#' 39428597Speter is to be expected, it should be quoted .... */ 39534766Speter if ( *sp == '#' ) 39634766Speter continue; 39728597Speter 39834766Speter while (*sp != '\0') { 39934766Speter if (*sp == ' ' || *sp == '\t') { 4004374Slars ++sp; 4014374Slars continue; 40234766Speter } 4034374Slars 40434766Speter if (*sp == '"' || *sp == '\'') { 4054374Slars quote = *sp++; 4064374Slars arg = sp; 40734766Speter while (*sp != quote) { 4084374Slars if (*sp == '\0') 40934766Speter fatal(1, "unterminated quote (line %d)", linect); 41034766Speter 41134766Speter if (*sp++ == '\\') { 4124374Slars if (*sp != '\0') 4134374Slars ++sp; 4144374Slars } 4154374Slars } 41634766Speter } 41734766Speter else { 4184374Slars arg = sp; 4194374Slars while (*sp != '\0' && *sp != ' ' && *sp != '\t') 4204374Slars ++sp; 42134766Speter } 4224374Slars 4234374Slars if (*sp != '\0') 4244374Slars *sp++ = '\0'; 4254374Slars 4264374Slars if (sendflg) 4274374Slars chat_send (arg); 4284374Slars else 4294374Slars chat_expect (arg); 4304374Slars sendflg = !sendflg; 4314374Slars } 43234766Speter } 4334374Slars fclose (cfp); 43434766Speter} 4354374Slars 4364374Slars/* 4374374Slars * We got an error parsing the command line. 4384374Slars */ 43926880Scharnierstatic void 44026880Scharnierusage() 44134766Speter{ 44234766Speter fprintf(stderr, "\ 44334766SpeterUsage: chat [-e] [-v] [-V] [-t timeout] [-r report-file] [-T phone-number]\n\ 44434766Speter [-U phone-number2] {-f chat-file | chat-script}\n"); 4454374Slars exit(1); 44634766Speter} 4474374Slars 44834766Speterchar line[1024]; 4494374Slars 45034766Speter/* 45134766Speter * Send a message to syslog and/or stderr. 45234766Speter */ 45392920Simpvoid logf(const char *fmt, ...) 45428597Speter{ 45534766Speter va_list args; 4564374Slars 45734766Speter va_start(args, fmt); 45834766Speter vfmtmsg(line, sizeof(line), fmt, args); 45934766Speter if (to_log) 46028597Speter syslog(LOG_INFO, "%s", line); 46134766Speter if (to_stderr) 46234766Speter fprintf(stderr, "%s\n", line); 46328597Speter} 4644374Slars 4654374Slars/* 4664374Slars * Print an error message and terminate. 4674374Slars */ 4684374Slars 46992920Simpvoid fatal(int code, const char *fmt, ...) 47034766Speter{ 47134766Speter va_list args; 4724374Slars 47334766Speter va_start(args, fmt); 47434766Speter vfmtmsg(line, sizeof(line), fmt, args); 47534766Speter if (to_log) 47634766Speter syslog(LOG_ERR, "%s", line); 47734766Speter if (to_stderr) 47834766Speter fprintf(stderr, "%s\n", line); 47934766Speter terminate(code); 48034766Speter} 4814374Slars 4824374Slarsint alarmed = 0; 4834374Slars 4844374SlarsSIGTYPE sigalrm(signo) 4854374Slarsint signo; 48634766Speter{ 4874374Slars int flags; 4884374Slars 4894374Slars alarm(1); 4904374Slars alarmed = 1; /* Reset alarm to avoid race window */ 4914374Slars signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 4924374Slars 4934374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 49434766Speter fatal(2, "Can't get file mode flags on stdin: %m"); 4954374Slars 49634766Speter if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) 49734766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 49834766Speter 4994374Slars if (verbose) 50034766Speter logf("alarm"); 50134766Speter} 5024374Slars 5034374Slarsvoid unalarm() 50434766Speter{ 5054374Slars int flags; 5064374Slars 5074374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 50834766Speter fatal(2, "Can't get file mode flags on stdin: %m"); 5094374Slars 51034766Speter if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1) 51134766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 51234766Speter} 51334766Speter 5144374SlarsSIGTYPE sigint(signo) 5154374Slarsint signo; 51634766Speter{ 51734766Speter fatal(2, "SIGINT"); 51834766Speter} 5194374Slars 5204374SlarsSIGTYPE sigterm(signo) 5214374Slarsint signo; 52234766Speter{ 52334766Speter fatal(2, "SIGTERM"); 52434766Speter} 5254374Slars 5264374SlarsSIGTYPE sighup(signo) 5274374Slarsint signo; 52834766Speter{ 52934766Speter fatal(2, "SIGHUP"); 53034766Speter} 5314374Slars 5324374Slarsvoid init() 53334766Speter{ 5344374Slars signal(SIGINT, sigint); 5354374Slars signal(SIGTERM, sigterm); 5364374Slars signal(SIGHUP, sighup); 5374374Slars 5384374Slars set_tty_parameters(); 5394374Slars signal(SIGALRM, sigalrm); 5404374Slars alarm(0); 5414374Slars alarmed = 0; 54234766Speter} 5434374Slars 5444374Slarsvoid set_tty_parameters() 54534766Speter{ 54611990Speter#if defined(get_term_param) 54711990Speter term_parms t; 5484374Slars 54911990Speter if (get_term_param (&t) < 0) 55034766Speter fatal(2, "Can't get terminal parameters: %m"); 5514374Slars 5524374Slars saved_tty_parameters = t; 55311990Speter have_tty_parameters = 1; 5544374Slars 55511990Speter t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 55611990Speter t.c_oflag = 0; 55711990Speter t.c_lflag = 0; 55811990Speter t.c_cc[VERASE] = 55911990Speter t.c_cc[VKILL] = 0; 56011990Speter t.c_cc[VMIN] = 1; 56111990Speter t.c_cc[VTIME] = 0; 5624374Slars 56311990Speter if (set_term_param (&t) < 0) 56434766Speter fatal(2, "Can't set terminal parameters: %m"); 5654374Slars#endif 56634766Speter} 5674374Slars 5684374Slarsvoid break_sequence() 56934766Speter{ 5704374Slars#ifdef TERMIOS 5714374Slars tcsendbreak (0, 0); 5724374Slars#endif 57334766Speter} 5744374Slars 5754374Slarsvoid terminate(status) 5764374Slarsint status; 57734766Speter{ 57828597Speter echo_stderr(-1); 57934766Speter if (report_file != (char *) 0 && report_fp != (FILE *) NULL) { 58028597Speter/* 58128597Speter * Allow the last of the report string to be gathered before we terminate. 58228597Speter */ 58328597Speter if (report_gathering) { 58428597Speter int c, rep_len; 58528597Speter 58628597Speter rep_len = strlen(report_buffer); 58728597Speter while (rep_len + 1 <= sizeof(report_buffer)) { 58828597Speter alarm(1); 58928597Speter c = get_char(); 59028597Speter alarm(0); 59128597Speter if (c < 0 || iscntrl(c)) 59228597Speter break; 59328597Speter report_buffer[rep_len] = c; 59428597Speter ++rep_len; 59528597Speter } 59628597Speter report_buffer[rep_len] = 0; 59728597Speter fprintf (report_fp, "chat: %s\n", report_buffer); 59828597Speter } 59911990Speter if (verbose) 60011990Speter fprintf (report_fp, "Closing \"%s\".\n", report_file); 60111990Speter fclose (report_fp); 60228597Speter report_fp = (FILE *) NULL; 60334766Speter } 6044374Slars 60511990Speter#if defined(get_term_param) 60634766Speter if (have_tty_parameters) { 60711990Speter if (set_term_param (&saved_tty_parameters) < 0) 60834766Speter fatal(2, "Can't restore terminal parameters: %m"); 60934766Speter } 61011990Speter#endif 6114374Slars 61211990Speter exit(status); 61334766Speter} 6144374Slars 6154374Slars/* 6164374Slars * 'Clean up' this string. 6174374Slars */ 6184374Slarschar *clean(s, sending) 6194374Slarsregister char *s; 62034766Speterint sending; /* set to 1 when sending (putting) this string. */ 62134766Speter{ 6224374Slars char temp[STR_LEN], cur_chr; 62334766Speter register char *s1, *phchar; 6244374Slars int add_return = sending; 6254374Slars#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 6264374Slars 6274374Slars s1 = temp; 62853686Skris /* Don't overflow buffer, leave room for chars we append later */ 62953686Skris while (*s && s1 - temp < sizeof(temp) - 2 - add_return) { 6304374Slars cur_chr = *s++; 63134766Speter if (cur_chr == '^') { 6324374Slars cur_chr = *s++; 63334766Speter if (cur_chr == '\0') { 6344374Slars *s1++ = '^'; 6354374Slars break; 63634766Speter } 6374374Slars cur_chr &= 0x1F; 63834766Speter if (cur_chr != 0) { 6394374Slars *s1++ = cur_chr; 64034766Speter } 6414374Slars continue; 64234766Speter } 6434374Slars 64434766Speter if (cur_chr != '\\') { 6454374Slars *s1++ = cur_chr; 6464374Slars continue; 64734766Speter } 6484374Slars 6494374Slars cur_chr = *s++; 65034766Speter if (cur_chr == '\0') { 65134766Speter if (sending) { 6524374Slars *s1++ = '\\'; 6534374Slars *s1++ = '\\'; 65434766Speter } 6554374Slars break; 65634766Speter } 6574374Slars 65834766Speter switch (cur_chr) { 6594374Slars case 'b': 6604374Slars *s1++ = '\b'; 6614374Slars break; 6624374Slars 6634374Slars case 'c': 6644374Slars if (sending && *s == '\0') 6654374Slars add_return = 0; 6664374Slars else 6674374Slars *s1++ = cur_chr; 6684374Slars break; 6694374Slars 6704374Slars case '\\': 6714374Slars case 'K': 6724374Slars case 'p': 6734374Slars case 'd': 6744374Slars if (sending) 6754374Slars *s1++ = '\\'; 6764374Slars 6774374Slars *s1++ = cur_chr; 6784374Slars break; 6794374Slars 68034766Speter case 'T': 68134766Speter if (sending && phone_num) { 68234766Speter for ( phchar = phone_num; *phchar != '\0'; phchar++) 68334766Speter *s1++ = *phchar; 68434766Speter } 68534766Speter else { 68634766Speter *s1++ = '\\'; 68734766Speter *s1++ = 'T'; 68834766Speter } 68934766Speter break; 69034766Speter 69134766Speter case 'U': 69234766Speter if (sending && phone_num2) { 69334766Speter for ( phchar = phone_num2; *phchar != '\0'; phchar++) 69434766Speter *s1++ = *phchar; 69534766Speter } 69634766Speter else { 69734766Speter *s1++ = '\\'; 69834766Speter *s1++ = 'U'; 69934766Speter } 70034766Speter break; 70134766Speter 7024374Slars case 'q': 70328597Speter quiet = 1; 7044374Slars break; 7054374Slars 7064374Slars case 'r': 7074374Slars *s1++ = '\r'; 7084374Slars break; 7094374Slars 7104374Slars case 'n': 7114374Slars *s1++ = '\n'; 7124374Slars break; 7134374Slars 7144374Slars case 's': 7154374Slars *s1++ = ' '; 7164374Slars break; 7174374Slars 7184374Slars case 't': 7194374Slars *s1++ = '\t'; 7204374Slars break; 7214374Slars 7224374Slars case 'N': 72334766Speter if (sending) { 7244374Slars *s1++ = '\\'; 7254374Slars *s1++ = '\0'; 72634766Speter } 7274374Slars else 7284374Slars *s1++ = 'N'; 7294374Slars break; 73011990Speter 7314374Slars default: 73234766Speter if (isoctal (cur_chr)) { 7334374Slars cur_chr &= 0x07; 73434766Speter if (isoctal (*s)) { 7354374Slars cur_chr <<= 3; 7364374Slars cur_chr |= *s++ - '0'; 73734766Speter if (isoctal (*s)) { 7384374Slars cur_chr <<= 3; 7394374Slars cur_chr |= *s++ - '0'; 7404374Slars } 74134766Speter } 7424374Slars 74334766Speter if (cur_chr != 0 || sending) { 7444374Slars if (sending && (cur_chr == '\\' || cur_chr == 0)) 7454374Slars *s1++ = '\\'; 7464374Slars *s1++ = cur_chr; 74734766Speter } 7484374Slars break; 74934766Speter } 7504374Slars 7514374Slars if (sending) 7524374Slars *s1++ = '\\'; 7534374Slars *s1++ = cur_chr; 7544374Slars break; 7554374Slars } 75634766Speter } 7574374Slars 7584374Slars if (add_return) 7594374Slars *s1++ = '\r'; 7604374Slars 7614374Slars *s1++ = '\0'; /* guarantee closure */ 7624374Slars *s1++ = '\0'; /* terminate the string */ 7634374Slars return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 76434766Speter} 7654374Slars 7664374Slars/* 76728597Speter * A modified version of 'strtok'. This version skips \ sequences. 76828597Speter */ 76928597Speter 77028597Speterchar *expect_strtok (s, term) 77134766Speter char *s, *term; 77234766Speter{ 77328597Speter static char *str = ""; 77428597Speter int escape_flag = 0; 77528597Speter char *result; 77634766Speter 77728597Speter/* 77828597Speter * If a string was specified then do initial processing. 77928597Speter */ 78028597Speter if (s) 78128597Speter str = s; 78234766Speter 78328597Speter/* 78428597Speter * If this is the escape flag then reset it and ignore the character. 78528597Speter */ 78628597Speter if (*str) 78728597Speter result = str; 78828597Speter else 78928597Speter result = (char *) 0; 79028597Speter 79134766Speter while (*str) { 79234766Speter if (escape_flag) { 79328597Speter escape_flag = 0; 79428597Speter ++str; 79528597Speter continue; 79634766Speter } 79728597Speter 79834766Speter if (*str == '\\') { 79928597Speter ++str; 80028597Speter escape_flag = 1; 80128597Speter continue; 80234766Speter } 80334766Speter 80428597Speter/* 80528597Speter * If this is not in the termination string, continue. 80628597Speter */ 80734766Speter if (strchr (term, *str) == (char *) 0) { 80828597Speter ++str; 80928597Speter continue; 81034766Speter } 81134766Speter 81228597Speter/* 81328597Speter * This is the terminator. Mark the end of the string and stop. 81428597Speter */ 81528597Speter *str++ = '\0'; 81628597Speter break; 81734766Speter } 81828597Speter return (result); 81934766Speter} 82028597Speter 82128597Speter/* 8224374Slars * Process the expect string 8234374Slars */ 82428597Speter 82528597Spetervoid chat_expect (s) 82628597Speterchar *s; 82734766Speter{ 82828597Speter char *expect; 82928597Speter char *reply; 83028597Speter 83134766Speter if (strcmp(s, "HANGUP") == 0) { 83228597Speter ++hup_next; 83328597Speter return; 83434766Speter } 83528597Speter 83634766Speter if (strcmp(s, "ABORT") == 0) { 8374374Slars ++abort_next; 8384374Slars return; 83934766Speter } 8404374Slars 84134766Speter if (strcmp(s, "CLR_ABORT") == 0) { 84228597Speter ++clear_abort_next; 84328597Speter return; 84434766Speter } 84528597Speter 84634766Speter if (strcmp(s, "REPORT") == 0) { 84711990Speter ++report_next; 84811990Speter return; 84934766Speter } 85011990Speter 85134766Speter if (strcmp(s, "CLR_REPORT") == 0) { 85228597Speter ++clear_report_next; 85328597Speter return; 85434766Speter } 85528597Speter 85634766Speter if (strcmp(s, "TIMEOUT") == 0) { 8574374Slars ++timeout_next; 8584374Slars return; 85934766Speter } 8604374Slars 86134766Speter if (strcmp(s, "ECHO") == 0) { 86228597Speter ++echo_next; 86328597Speter return; 86434766Speter } 86534766Speter 86634766Speter if (strcmp(s, "SAY") == 0) { 86728597Speter ++say_next; 86828597Speter return; 86934766Speter } 87034766Speter 87128597Speter/* 87228597Speter * Fetch the expect and reply string. 87328597Speter */ 87434766Speter for (;;) { 87528597Speter expect = expect_strtok (s, "-"); 87628597Speter s = (char *) 0; 8774374Slars 87828597Speter if (expect == (char *) 0) 87928597Speter return; 88028597Speter 88128597Speter reply = expect_strtok (s, "-"); 88234766Speter 88328597Speter/* 88428597Speter * Handle the expect string. If successful then exit. 88528597Speter */ 88628597Speter if (get_string (expect)) 88728597Speter return; 88834766Speter 88928597Speter/* 89028597Speter * If there is a sub-reply string then send it. Otherwise any condition 89128597Speter * is terminal. 89228597Speter */ 89328597Speter if (reply == (char *) 0 || exit_code != 3) 89428597Speter break; 8954374Slars 89628597Speter chat_send (reply); 89734766Speter } 89834766Speter 89928597Speter/* 90028597Speter * The expectation did not occur. This is terminal. 90128597Speter */ 90228597Speter if (fail_reason) 90334766Speter logf("Failed (%s)", fail_reason); 90428597Speter else 90534766Speter logf("Failed"); 90628597Speter terminate(exit_code); 90734766Speter} 9084374Slars 90928597Speter/* 91028597Speter * Translate the input character to the appropriate string for printing 91128597Speter * the data. 91228597Speter */ 91328597Speter 9144374Slarschar *character(c) 91511990Speterint c; 91634766Speter{ 9174374Slars static char string[10]; 9184374Slars char *meta; 9194374Slars 9204374Slars meta = (c & 0x80) ? "M-" : ""; 9214374Slars c &= 0x7F; 9224374Slars 9234374Slars if (c < 32) 9244374Slars sprintf(string, "%s^%c", meta, (int)c + '@'); 92534766Speter else if (c == 127) 92634766Speter sprintf(string, "%s^?", meta); 9274374Slars else 92834766Speter sprintf(string, "%s%c", meta, c); 9294374Slars 9304374Slars return (string); 93134766Speter} 9324374Slars 9334374Slars/* 9344374Slars * process the reply string 9354374Slars */ 9364374Slarsvoid chat_send (s) 9374374Slarsregister char *s; 93834766Speter{ 93934766Speter if (say_next) { 94028597Speter say_next = 0; 94128597Speter s = clean(s,0); 94280381Ssheldonh write(STDERR_FILENO, s, strlen(s)); 94328597Speter free(s); 94428597Speter return; 94534766Speter } 94634766Speter 94734766Speter if (hup_next) { 94828597Speter hup_next = 0; 94928597Speter if (strcmp(s, "OFF") == 0) 95028597Speter signal(SIGHUP, SIG_IGN); 95128597Speter else 95228597Speter signal(SIGHUP, sighup); 95328597Speter return; 95434766Speter } 95534766Speter 95634766Speter if (echo_next) { 95728597Speter echo_next = 0; 95828597Speter echo = (strcmp(s, "ON") == 0); 95928597Speter return; 96034766Speter } 96134766Speter 96234766Speter if (abort_next) { 9634374Slars char *s1; 96411990Speter 9654374Slars abort_next = 0; 96611990Speter 9674374Slars if (n_aborts >= MAX_ABORTS) 96834766Speter fatal(2, "Too many ABORT strings"); 96911990Speter 9704374Slars s1 = clean(s, 0); 97111990Speter 97211990Speter if (strlen(s1) > strlen(s) 97311990Speter || strlen(s1) + 1 > sizeof(fail_buffer)) 97434766Speter fatal(1, "Illegal or too-long ABORT string ('%v')", s); 9754374Slars 9764374Slars abort_string[n_aborts++] = s1; 9774374Slars 9784374Slars if (verbose) 97934766Speter logf("abort on (%v)", s); 98011990Speter return; 98134766Speter } 98211990Speter 98334766Speter if (clear_abort_next) { 98428597Speter char *s1; 98528597Speter int i; 98628597Speter int old_max; 98728597Speter int pack = 0; 98828597Speter 98928597Speter clear_abort_next = 0; 99028597Speter 99128597Speter s1 = clean(s, 0); 99228597Speter 99328597Speter if (strlen(s1) > strlen(s) 99428597Speter || strlen(s1) + 1 > sizeof(fail_buffer)) 99534766Speter fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s); 99628597Speter 99728597Speter old_max = n_aborts; 99834766Speter for (i=0; i < n_aborts; i++) { 99934766Speter if ( strcmp(s1,abort_string[i]) == 0 ) { 100034766Speter free(abort_string[i]); 100134766Speter abort_string[i] = NULL; 100234766Speter pack++; 100334766Speter n_aborts--; 100434766Speter if (verbose) 100534766Speter logf("clear abort on (%v)", s); 100628597Speter } 100734766Speter } 100828597Speter free(s1); 100934766Speter if (pack) 101034766Speter pack_array(abort_string,old_max); 101128597Speter return; 101234766Speter } 101328597Speter 101434766Speter if (report_next) { 101511990Speter char *s1; 101611990Speter 101711990Speter report_next = 0; 101811990Speter if (n_reports >= MAX_REPORTS) 101934766Speter fatal(2, "Too many REPORT strings"); 102011990Speter 102111990Speter s1 = clean(s, 0); 102211990Speter 102311990Speter if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 102434766Speter fatal(1, "Illegal or too-long REPORT string ('%v')", s); 102511990Speter 102611990Speter report_string[n_reports++] = s1; 102711990Speter 102811990Speter if (verbose) 102934766Speter logf("report (%v)", s); 103011990Speter return; 103134766Speter } 10324374Slars 103334766Speter if (clear_report_next) { 103428597Speter char *s1; 103528597Speter int i; 103628597Speter int old_max; 103728597Speter int pack = 0; 103828597Speter 103928597Speter clear_report_next = 0; 104028597Speter 104128597Speter s1 = clean(s, 0); 104228597Speter 104328597Speter if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 104434766Speter fatal(1, "Illegal or too-long REPORT string ('%v')", s); 104528597Speter 104628597Speter old_max = n_reports; 104734766Speter for (i=0; i < n_reports; i++) { 104834766Speter if ( strcmp(s1,report_string[i]) == 0 ) { 104934766Speter free(report_string[i]); 105034766Speter report_string[i] = NULL; 105134766Speter pack++; 105234766Speter n_reports--; 105334766Speter if (verbose) 105434766Speter logf("clear report (%v)", s); 105528597Speter } 105634766Speter } 105728597Speter free(s1); 105834766Speter if (pack) 105934766Speter pack_array(report_string,old_max); 106028597Speter 106128597Speter return; 106234766Speter } 106328597Speter 106434766Speter if (timeout_next) { 106511990Speter timeout_next = 0; 106611990Speter timeout = atoi(s); 106711990Speter 106811990Speter if (timeout <= 0) 106911990Speter timeout = DEFAULT_CHAT_TIMEOUT; 10704374Slars 107111990Speter if (verbose) 107234766Speter logf("timeout set to %d seconds", timeout); 107334766Speter 107411990Speter return; 107534766Speter } 107611990Speter 107711990Speter if (strcmp(s, "EOT") == 0) 107811990Speter s = "^D\\c"; 107934766Speter else if (strcmp(s, "BREAK") == 0) 108034766Speter s = "\\K\\c"; 108111990Speter 108211990Speter if (!put_string(s)) 108334766Speter fatal(1, "Failed"); 108434766Speter} 10854374Slars 10864374Slarsint get_char() 108734766Speter{ 10884374Slars int status; 10894374Slars char c; 10904374Slars 109180381Ssheldonh status = read(STDIN_FILENO, &c, 1); 10924374Slars 109334766Speter switch (status) { 109411990Speter case 1: 109511990Speter return ((int)c & 0x7F); 10964374Slars 109711990Speter default: 109834766Speter logf("warning: read() on stdin returned %d", status); 10994374Slars 110011990Speter case -1: 110111990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 110234766Speter fatal(2, "Can't get file mode flags on stdin: %m"); 110334766Speter 110434766Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 110534766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 110611990Speter 110711990Speter return (-1); 11084374Slars } 110934766Speter} 11104374Slars 11114374Slarsint put_char(c) 111211990Speterint c; 111334766Speter{ 11144374Slars int status; 111511990Speter char ch = c; 11164374Slars 111711990Speter usleep(10000); /* inter-character typing delay (?) */ 11184374Slars 111980381Ssheldonh status = write(STDOUT_FILENO, &ch, 1); 11204374Slars 112134766Speter switch (status) { 112211990Speter case 1: 112311990Speter return (0); 112411990Speter 112511990Speter default: 112634766Speter logf("warning: write() on stdout returned %d", status); 112711990Speter 112811990Speter case -1: 112911990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 113034766Speter fatal(2, "Can't get file mode flags on stdin, %m"); 113134766Speter 113234766Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 113334766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 113411990Speter 113511990Speter return (-1); 11364374Slars } 113734766Speter} 11384374Slars 11394374Slarsint write_char (c) 11404374Slarsint c; 114134766Speter{ 114234766Speter if (alarmed || put_char(c) < 0) { 114311990Speter alarm(0); 114411990Speter alarmed = 0; 11454374Slars 114634766Speter if (verbose) { 11474374Slars if (errno == EINTR || errno == EWOULDBLOCK) 114834766Speter logf(" -- write timed out"); 11494374Slars else 115034766Speter logf(" -- write failed: %m"); 115134766Speter } 11524374Slars return (0); 115334766Speter } 11544374Slars return (1); 115534766Speter} 11564374Slars 11574374Slarsint put_string (s) 11584374Slarsregister char *s; 115934766Speter{ 116028597Speter quiet = 0; 11614374Slars s = clean(s, 1); 11624374Slars 116334766Speter if (verbose) { 11644374Slars if (quiet) 116534766Speter logf("send (??????)"); 11664374Slars else 116734766Speter logf("send (%v)", s); 116834766Speter } 11694374Slars 11704374Slars alarm(timeout); alarmed = 0; 11714374Slars 117234766Speter while (*s) { 11734374Slars register char c = *s++; 11744374Slars 117534766Speter if (c != '\\') { 11764374Slars if (!write_char (c)) 11774374Slars return 0; 11784374Slars continue; 117934766Speter } 11804374Slars 11814374Slars c = *s++; 118234766Speter switch (c) { 11834374Slars case 'd': 11844374Slars sleep(1); 11854374Slars break; 11864374Slars 11874374Slars case 'K': 11884374Slars break_sequence(); 11894374Slars break; 11904374Slars 11914374Slars case 'p': 119211990Speter usleep(10000); /* 1/100th of a second (arg is microseconds) */ 11934374Slars break; 11944374Slars 11954374Slars default: 11964374Slars if (!write_char (c)) 11974374Slars return 0; 11984374Slars break; 11994374Slars } 120034766Speter } 12014374Slars 12024374Slars alarm(0); 12034374Slars alarmed = 0; 12044374Slars return (1); 120534766Speter} 12064374Slars 12074374Slars/* 120828597Speter * Echo a character to stderr. 120928597Speter * When called with -1, a '\n' character is generated when 121028597Speter * the cursor is not at the beginning of a line. 121128597Speter */ 121228597Spetervoid echo_stderr(n) 121328597Speterint n; 121434766Speter{ 121534766Speter static int need_lf; 121634766Speter char *s; 121728597Speter 121834766Speter switch (n) { 121934766Speter case '\r': /* ignore '\r' */ 122034766Speter break; 122134766Speter case -1: 122234766Speter if (need_lf == 0) 122328597Speter break; 1224102412Scharnier /* FALLTHROUGH */ 122534766Speter case '\n': 122680381Ssheldonh write(STDERR_FILENO, "\n", 1); 122734766Speter need_lf = 0; 122834766Speter break; 122934766Speter default: 123034766Speter s = character(n); 123180381Ssheldonh write(STDERR_FILENO, s, strlen(s)); 123234766Speter need_lf = 1; 123334766Speter break; 123428597Speter } 123534766Speter} 123628597Speter 123728597Speter/* 12384374Slars * 'Wait for' this string to appear on this file descriptor. 12394374Slars */ 12404374Slarsint get_string(string) 12414374Slarsregister char *string; 124234766Speter{ 12434374Slars char temp[STR_LEN]; 12444374Slars int c, printed = 0, len, minlen; 12454374Slars register char *s = temp, *end = s + STR_LEN; 124634766Speter char *logged = temp; 12474374Slars 12484374Slars fail_reason = (char *)0; 124953686Skris 125053686Skris if (strlen(string) > STR_LEN) { 125153686Skris logf("expect string is too long"); 125253686Skris exit_code = 1; 125353686Skris return 0; 125453686Skris } 125553686Skris 12564374Slars string = clean(string, 0); 12574374Slars len = strlen(string); 12584374Slars minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 12594374Slars 12604374Slars if (verbose) 126134766Speter logf("expect (%v)", string); 12624374Slars 126334766Speter if (len == 0) { 12644374Slars if (verbose) 126534766Speter logf("got it"); 12664374Slars return (1); 126734766Speter } 12684374Slars 126911990Speter alarm(timeout); 127011990Speter alarmed = 0; 12714374Slars 127234766Speter while ( ! alarmed && (c = get_char()) >= 0) { 127311990Speter int n, abort_len, report_len; 12744374Slars 127528597Speter if (echo) 127628597Speter echo_stderr(c); 127734766Speter if (verbose && c == '\n') { 127834766Speter if (s == logged) 127934766Speter logf(""); /* blank line */ 12804374Slars else 128134766Speter logf("%0.*v", s - logged, logged); 128234766Speter logged = s + 1; 128334766Speter } 12844374Slars 128534766Speter *s++ = c; 128634766Speter 128734766Speter if (verbose && s >= logged + 80) { 128834766Speter logf("%0.*v", s - logged, logged); 128934766Speter logged = s; 129034766Speter } 129134766Speter 129228597Speter if (Verbose) { 129334766Speter if (c == '\n') 129434766Speter fputc( '\n', stderr ); 129534766Speter else if (c != '\r') 129634766Speter fprintf( stderr, "%s", character(c) ); 129728597Speter } 129828597Speter 129934766Speter if (!report_gathering) { 130034766Speter for (n = 0; n < n_reports; ++n) { 130111990Speter if ((report_string[n] != (char*) NULL) && 130211990Speter s - temp >= (report_len = strlen(report_string[n])) && 130334766Speter strncmp(s - report_len, report_string[n], report_len) == 0) { 130411990Speter time_t time_now = time ((time_t*) NULL); 130511990Speter struct tm* tm_now = localtime (&time_now); 130611990Speter 130711990Speter strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 130811990Speter strcat (report_buffer, report_string[n]); 130911990Speter 131011990Speter report_string[n] = (char *) NULL; 131111990Speter report_gathering = 1; 131211990Speter break; 131334766Speter } 131411990Speter } 131534766Speter } 131634766Speter else { 131734766Speter if (!iscntrl (c)) { 131811990Speter int rep_len = strlen (report_buffer); 131911990Speter report_buffer[rep_len] = c; 132011990Speter report_buffer[rep_len + 1] = '\0'; 132134766Speter } 132234766Speter else { 132311990Speter report_gathering = 0; 132411990Speter fprintf (report_fp, "chat: %s\n", report_buffer); 132511990Speter } 132634766Speter } 132711990Speter 132828597Speter if (s - temp >= len && 132928597Speter c == string[len - 1] && 133034766Speter strncmp(s - len, string, len) == 0) { 133134766Speter if (verbose) { 133234766Speter if (s > logged) 133334766Speter logf("%0.*v", s - logged, logged); 133428597Speter logf(" -- got it\n"); 133534766Speter } 133628597Speter 133728597Speter alarm(0); 133828597Speter alarmed = 0; 133928597Speter return (1); 134034766Speter } 134128597Speter 134234766Speter for (n = 0; n < n_aborts; ++n) { 134328597Speter if (s - temp >= (abort_len = strlen(abort_string[n])) && 134434766Speter strncmp(s - abort_len, abort_string[n], abort_len) == 0) { 134534766Speter if (verbose) { 134634766Speter if (s > logged) 134734766Speter logf("%0.*v", s - logged, logged); 134834766Speter logf(" -- failed"); 134934766Speter } 135034766Speter 135128597Speter alarm(0); 135228597Speter alarmed = 0; 135328597Speter exit_code = n + 4; 135428597Speter strcpy(fail_reason = fail_buffer, abort_string[n]); 135528597Speter return (0); 135628597Speter } 135734766Speter } 135828597Speter 135934766Speter if (s >= end) { 136034766Speter if (logged < s - minlen) { 136134766Speter logf("%0.*v", s - logged, logged); 136234766Speter logged = s; 136334766Speter } 136434766Speter s -= minlen; 136534766Speter memmove(temp, s, minlen); 136634766Speter logged = temp + (logged - s); 13674374Slars s = temp + minlen; 136834766Speter } 13694374Slars 13704374Slars if (alarmed && verbose) 137134766Speter logf("warning: alarm synchronization problem"); 137234766Speter } 13734374Slars 13744374Slars alarm(0); 137511990Speter 137634766Speter if (verbose && printed) { 13774374Slars if (alarmed) 137834766Speter logf(" -- read timed out"); 13794374Slars else 138034766Speter logf(" -- read failed: %m"); 138134766Speter } 13824374Slars 138311990Speter exit_code = 3; 138411990Speter alarmed = 0; 13854374Slars return (0); 138634766Speter} 13874374Slars 138837126Speter/* 138937126Speter * Gross kludge to handle Solaris versions >= 2.6 having usleep. 139037126Speter */ 139137126Speter#ifdef SOL2 139237126Speter#include <sys/param.h> 139337126Speter#if MAXUID > 65536 /* then this is Solaris 2.6 or later */ 139437126Speter#undef NO_USLEEP 139537126Speter#endif 139637126Speter#endif /* SOL2 */ 139737126Speter 139811990Speter#ifdef NO_USLEEP 13994374Slars#include <sys/types.h> 14004374Slars#include <sys/time.h> 14014374Slars 14024374Slars/* 14034374Slars usleep -- support routine for 4.2BSD system call emulations 14044374Slars last edit: 29-Oct-1984 D A Gwyn 14054374Slars */ 14064374Slars 14074374Slarsextern int select(); 14084374Slars 14094374Slarsint 14104374Slarsusleep( usec ) /* returns 0 if ok, else -1 */ 14114374Slars long usec; /* delay in microseconds */ 14124374Slars{ 141334766Speter static struct { /* `timeval' */ 141411990Speter long tv_sec; /* seconds */ 141511990Speter long tv_usec; /* microsecs */ 141634766Speter } delay; /* _select() timeout */ 14174374Slars 141811990Speter delay.tv_sec = usec / 1000000L; 14194374Slars delay.tv_usec = usec % 1000000L; 14204374Slars 142134766Speter return select(0, (long *)0, (long *)0, (long *)0, &delay); 14224374Slars} 14234374Slars#endif 142428597Speter 142528597Spetervoid 142628597Speterpack_array (array, end) 142728597Speter char **array; /* The address of the array of string pointers */ 142828597Speter int end; /* The index of the next free entry before CLR_ */ 142928597Speter{ 143028597Speter int i, j; 143128597Speter 143228597Speter for (i = 0; i < end; i++) { 143328597Speter if (array[i] == NULL) { 143428597Speter for (j = i+1; j < end; ++j) 143528597Speter if (array[j] != NULL) 143628597Speter array[i++] = array[j]; 143728597Speter for (; i < end; ++i) 143828597Speter array[i] = NULL; 143928597Speter break; 144028597Speter } 144128597Speter } 144228597Speter} 144334766Speter 144434766Speter/* 144534766Speter * vfmtmsg - format a message into a buffer. Like vsprintf except we 144634766Speter * also specify the length of the output buffer, and we handle the 144734766Speter * %m (error message) format. 144834766Speter * Doesn't do floating-point formats. 144934766Speter * Returns the number of chars put into buf. 145034766Speter */ 145134766Speter#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) 145234766Speter 145334766Speterint 145434766Spetervfmtmsg(buf, buflen, fmt, args) 145534766Speter char *buf; 145634766Speter int buflen; 145734766Speter const char *fmt; 145834766Speter va_list args; 145934766Speter{ 146034766Speter int c, i, n; 146134766Speter int width, prec, fillch; 146234766Speter int base, len, neg, quoted; 146334766Speter unsigned long val = 0; 146434766Speter char *str, *buf0; 146534766Speter const char *f; 146634766Speter unsigned char *p; 146734766Speter char num[32]; 146834766Speter static char hexchars[] = "0123456789abcdef"; 146934766Speter 147034766Speter buf0 = buf; 147134766Speter --buflen; 147234766Speter while (buflen > 0) { 147334766Speter for (f = fmt; *f != '%' && *f != 0; ++f) 147434766Speter ; 147534766Speter if (f > fmt) { 147634766Speter len = f - fmt; 147734766Speter if (len > buflen) 147834766Speter len = buflen; 147934766Speter memcpy(buf, fmt, len); 148034766Speter buf += len; 148134766Speter buflen -= len; 148234766Speter fmt = f; 148334766Speter } 148434766Speter if (*fmt == 0) 148534766Speter break; 148634766Speter c = *++fmt; 148734766Speter width = prec = 0; 148834766Speter fillch = ' '; 148934766Speter if (c == '0') { 149034766Speter fillch = '0'; 149134766Speter c = *++fmt; 149234766Speter } 149334766Speter if (c == '*') { 149434766Speter width = va_arg(args, int); 149534766Speter c = *++fmt; 149634766Speter } else { 149734766Speter while (isdigit(c)) { 149834766Speter width = width * 10 + c - '0'; 149934766Speter c = *++fmt; 150034766Speter } 150134766Speter } 150234766Speter if (c == '.') { 150334766Speter c = *++fmt; 150434766Speter if (c == '*') { 150534766Speter prec = va_arg(args, int); 150634766Speter c = *++fmt; 150734766Speter } else { 150834766Speter while (isdigit(c)) { 150934766Speter prec = prec * 10 + c - '0'; 151034766Speter c = *++fmt; 151134766Speter } 151234766Speter } 151334766Speter } 151434766Speter str = 0; 151534766Speter base = 0; 151634766Speter neg = 0; 151734766Speter ++fmt; 151834766Speter switch (c) { 151934766Speter case 'd': 152034766Speter i = va_arg(args, int); 152134766Speter if (i < 0) { 152234766Speter neg = 1; 152334766Speter val = -i; 152434766Speter } else 152534766Speter val = i; 152634766Speter base = 10; 152734766Speter break; 152834766Speter case 'o': 152934766Speter val = va_arg(args, unsigned int); 153034766Speter base = 8; 153134766Speter break; 153234766Speter case 'x': 153334766Speter val = va_arg(args, unsigned int); 153434766Speter base = 16; 153534766Speter break; 153634766Speter case 'p': 153734766Speter val = (unsigned long) va_arg(args, void *); 153834766Speter base = 16; 153934766Speter neg = 2; 154034766Speter break; 154134766Speter case 's': 154234766Speter str = va_arg(args, char *); 154334766Speter break; 154434766Speter case 'c': 154534766Speter num[0] = va_arg(args, int); 154634766Speter num[1] = 0; 154734766Speter str = num; 154834766Speter break; 154934766Speter case 'm': 155034766Speter str = strerror(errno); 155134766Speter break; 155234766Speter case 'v': /* "visible" string */ 155334766Speter case 'q': /* quoted string */ 155434766Speter quoted = c == 'q'; 155534766Speter p = va_arg(args, unsigned char *); 155634766Speter if (fillch == '0' && prec > 0) { 155734766Speter n = prec; 155834766Speter } else { 155934766Speter n = strlen((char *)p); 156034766Speter if (prec > 0 && prec < n) 156134766Speter n = prec; 156234766Speter } 156334766Speter while (n > 0 && buflen > 0) { 156434766Speter c = *p++; 156534766Speter --n; 156634766Speter if (!quoted && c >= 0x80) { 156734766Speter OUTCHAR('M'); 156834766Speter OUTCHAR('-'); 156934766Speter c -= 0x80; 157034766Speter } 157134766Speter if (quoted && (c == '"' || c == '\\')) 157234766Speter OUTCHAR('\\'); 157334766Speter if (c < 0x20 || (0x7f <= c && c < 0xa0)) { 157434766Speter if (quoted) { 157534766Speter OUTCHAR('\\'); 157634766Speter switch (c) { 157734766Speter case '\t': OUTCHAR('t'); break; 157834766Speter case '\n': OUTCHAR('n'); break; 157934766Speter case '\b': OUTCHAR('b'); break; 158034766Speter case '\f': OUTCHAR('f'); break; 158134766Speter default: 158234766Speter OUTCHAR('x'); 158334766Speter OUTCHAR(hexchars[c >> 4]); 158434766Speter OUTCHAR(hexchars[c & 0xf]); 158534766Speter } 158634766Speter } else { 158734766Speter if (c == '\t') 158834766Speter OUTCHAR(c); 158934766Speter else { 159034766Speter OUTCHAR('^'); 159134766Speter OUTCHAR(c ^ 0x40); 159234766Speter } 159334766Speter } 159434766Speter } else 159534766Speter OUTCHAR(c); 159634766Speter } 159734766Speter continue; 159834766Speter default: 159934766Speter *buf++ = '%'; 160034766Speter if (c != '%') 160134766Speter --fmt; /* so %z outputs %z etc. */ 160234766Speter --buflen; 160334766Speter continue; 160434766Speter } 160534766Speter if (base != 0) { 160634766Speter str = num + sizeof(num); 160734766Speter *--str = 0; 160834766Speter while (str > num + neg) { 160934766Speter *--str = hexchars[val % base]; 161034766Speter val = val / base; 161134766Speter if (--prec <= 0 && val == 0) 161234766Speter break; 161334766Speter } 161434766Speter switch (neg) { 161534766Speter case 1: 161634766Speter *--str = '-'; 161734766Speter break; 161834766Speter case 2: 161934766Speter *--str = 'x'; 162034766Speter *--str = '0'; 162134766Speter break; 162234766Speter } 162334766Speter len = num + sizeof(num) - 1 - str; 162434766Speter } else { 162534766Speter len = strlen(str); 162634766Speter if (prec > 0 && len > prec) 162734766Speter len = prec; 162834766Speter } 162934766Speter if (width > 0) { 163034766Speter if (width > buflen) 163134766Speter width = buflen; 163234766Speter if ((n = width - len) > 0) { 163334766Speter buflen -= n; 163434766Speter for (; n > 0; --n) 163534766Speter *buf++ = fillch; 163634766Speter } 163734766Speter } 163834766Speter if (len > buflen) 163934766Speter len = buflen; 164034766Speter memcpy(buf, str, len); 164134766Speter buf += len; 164234766Speter buflen -= len; 164334766Speter } 164434766Speter *buf = 0; 164534766Speter return buf - buf0; 164634766Speter} 1647