17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * Copyright 2000 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate /* 67c478bd9Sstevel@tonic-gate * Chat -- a program for automatic session establishment (i.e. dial 77c478bd9Sstevel@tonic-gate * the phone and log in). 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * Standard termination codes: 107c478bd9Sstevel@tonic-gate * 0 - successful completion of the script 117c478bd9Sstevel@tonic-gate * 1 - invalid argument, expect string too large, etc. 127c478bd9Sstevel@tonic-gate * 2 - error on an I/O operation or fatal error condition. 137c478bd9Sstevel@tonic-gate * 3 - timeout waiting for a simple string. 147c478bd9Sstevel@tonic-gate * 4 - the first string declared as "ABORT" 157c478bd9Sstevel@tonic-gate * 5 - the second string declared as "ABORT" 167c478bd9Sstevel@tonic-gate * 6 - ... and so on for successive ABORT strings. 177c478bd9Sstevel@tonic-gate * 187c478bd9Sstevel@tonic-gate * This software is in the public domain. 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * ----------------- 217c478bd9Sstevel@tonic-gate * 22-May-99 added environment substitutuion, enabled with -E switch. 227c478bd9Sstevel@tonic-gate * Andreas Arens <andras@cityweb.de>. 237c478bd9Sstevel@tonic-gate * 247c478bd9Sstevel@tonic-gate * 12-May-99 added a feature to read data to be sent from a file, 257c478bd9Sstevel@tonic-gate * if the send string starts with @. Idea from gpk <gpk@onramp.net>. 267c478bd9Sstevel@tonic-gate * 277c478bd9Sstevel@tonic-gate * added -T and -U option and \T and \U substitution to pass a phone 287c478bd9Sstevel@tonic-gate * number into chat script. Two are needed for some ISDN TA applications. 297c478bd9Sstevel@tonic-gate * Keith Dart <kdart@cisco.com> 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * Added SAY keyword to send output to stderr. 337c478bd9Sstevel@tonic-gate * This allows to turn ECHO OFF and to output specific, user selected, 347c478bd9Sstevel@tonic-gate * text to give progress messages. This best works when stderr 357c478bd9Sstevel@tonic-gate * exists (i.e.: pppd in nodetach mode). 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * Added HANGUP directives to allow for us to be called 387c478bd9Sstevel@tonic-gate * back. When HANGUP is set to NO, chat will not hangup at HUP signal. 397c478bd9Sstevel@tonic-gate * We rely on timeouts in that case. 407c478bd9Sstevel@tonic-gate * 417c478bd9Sstevel@tonic-gate * Added CLR_ABORT to clear previously set ABORT string. This has been 427c478bd9Sstevel@tonic-gate * dictated by the HANGUP above as "NO CARRIER" (for example) must be 437c478bd9Sstevel@tonic-gate * an ABORT condition until we know the other host is going to close 447c478bd9Sstevel@tonic-gate * the connection for call back. As soon as we have completed the 457c478bd9Sstevel@tonic-gate * first stage of the call back sequence, "NO CARRIER" is a valid, non 467c478bd9Sstevel@tonic-gate * fatal string. As soon as we got called back (probably get "CONNECT"), 477c478bd9Sstevel@tonic-gate * we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command. 487c478bd9Sstevel@tonic-gate * Note that CLR_ABORT packs the abort_strings[] array so that we do not 497c478bd9Sstevel@tonic-gate * have unused entries not being reclaimed. 507c478bd9Sstevel@tonic-gate * 517c478bd9Sstevel@tonic-gate * In the same vein as above, added CLR_REPORT keyword. 527c478bd9Sstevel@tonic-gate * 537c478bd9Sstevel@tonic-gate * Allow for comments. Line starting with '#' are comments and are 547c478bd9Sstevel@tonic-gate * ignored. If a '#' is to be expected as the first character, the 557c478bd9Sstevel@tonic-gate * expect string must be quoted. 567c478bd9Sstevel@tonic-gate * 577c478bd9Sstevel@tonic-gate * 587c478bd9Sstevel@tonic-gate * Francis Demierre <Francis@SwissMail.Com> 597c478bd9Sstevel@tonic-gate * Thu May 15 17:15:40 MET DST 1997 607c478bd9Sstevel@tonic-gate * 617c478bd9Sstevel@tonic-gate * 627c478bd9Sstevel@tonic-gate * Added -r "report file" switch & REPORT keyword. 637c478bd9Sstevel@tonic-gate * Robert Geer <bgeer@xmission.com> 647c478bd9Sstevel@tonic-gate * 657c478bd9Sstevel@tonic-gate * Added -s "use stderr" and -S "don't use syslog" switches. 667c478bd9Sstevel@tonic-gate * June 18, 1997 677c478bd9Sstevel@tonic-gate * Karl O. Pinc <kop@meme.com> 687c478bd9Sstevel@tonic-gate * 697c478bd9Sstevel@tonic-gate * 707c478bd9Sstevel@tonic-gate * Added -e "echo" switch & ECHO keyword 717c478bd9Sstevel@tonic-gate * Dick Streefland <dicks@tasking.nl> 727c478bd9Sstevel@tonic-gate * 737c478bd9Sstevel@tonic-gate * 747c478bd9Sstevel@tonic-gate * Considerable updates and modifications by 757c478bd9Sstevel@tonic-gate * Al Longyear <longyear@pobox.com> 767c478bd9Sstevel@tonic-gate * Paul Mackerras <paulus@cs.anu.edu.au> 777c478bd9Sstevel@tonic-gate * 787c478bd9Sstevel@tonic-gate * 797c478bd9Sstevel@tonic-gate * The original author is: 807c478bd9Sstevel@tonic-gate * 817c478bd9Sstevel@tonic-gate * Karl Fox <karl@MorningStar.Com> 827c478bd9Sstevel@tonic-gate * Morning Star Technologies, Inc. 837c478bd9Sstevel@tonic-gate * 1760 Zollinger Road 847c478bd9Sstevel@tonic-gate * Columbus, OH 43221 857c478bd9Sstevel@tonic-gate * (614)451-1883 867c478bd9Sstevel@tonic-gate * 877c478bd9Sstevel@tonic-gate */ 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate #ifndef __STDC__ 907c478bd9Sstevel@tonic-gate #define const 917c478bd9Sstevel@tonic-gate #endif 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate #include <stdio.h> 947c478bd9Sstevel@tonic-gate #include <ctype.h> 957c478bd9Sstevel@tonic-gate #include <time.h> 967c478bd9Sstevel@tonic-gate #include <fcntl.h> 977c478bd9Sstevel@tonic-gate #include <signal.h> 987c478bd9Sstevel@tonic-gate #include <errno.h> 997c478bd9Sstevel@tonic-gate #include <string.h> 1007c478bd9Sstevel@tonic-gate #include <stdlib.h> 1017c478bd9Sstevel@tonic-gate #include <unistd.h> 1027c478bd9Sstevel@tonic-gate #include <sys/types.h> 1037c478bd9Sstevel@tonic-gate #include <sys/stat.h> 1047c478bd9Sstevel@tonic-gate #include <syslog.h> 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate #ifndef TERMIO 1077c478bd9Sstevel@tonic-gate #undef TERMIOS 1087c478bd9Sstevel@tonic-gate #define TERMIOS 1097c478bd9Sstevel@tonic-gate #endif 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate #ifdef TERMIO 1127c478bd9Sstevel@tonic-gate #include <termio.h> 1137c478bd9Sstevel@tonic-gate #endif 1147c478bd9Sstevel@tonic-gate #ifdef TERMIOS 1157c478bd9Sstevel@tonic-gate #include <termios.h> 1167c478bd9Sstevel@tonic-gate #endif 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate #define STR_LEN 1024 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate #ifndef SIGTYPE 1217c478bd9Sstevel@tonic-gate #define SIGTYPE void 1227c478bd9Sstevel@tonic-gate #endif 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate #undef __P 1257c478bd9Sstevel@tonic-gate #undef __V 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate #ifdef __STDC__ 1287c478bd9Sstevel@tonic-gate #include <stdarg.h> 1297c478bd9Sstevel@tonic-gate #define __V(x) x 1307c478bd9Sstevel@tonic-gate #define __P(x) x 1317c478bd9Sstevel@tonic-gate #else 1327c478bd9Sstevel@tonic-gate #include <varargs.h> 1337c478bd9Sstevel@tonic-gate #define __V(x) (va_alist) va_dcl 1347c478bd9Sstevel@tonic-gate #define __P(x) () 1357c478bd9Sstevel@tonic-gate #define const 1367c478bd9Sstevel@tonic-gate #endif 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate #ifndef O_NONBLOCK 1397c478bd9Sstevel@tonic-gate #define O_NONBLOCK O_NDELAY 1407c478bd9Sstevel@tonic-gate #endif 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate #ifdef SUNOS 1437c478bd9Sstevel@tonic-gate extern int sys_nerr; 1447c478bd9Sstevel@tonic-gate extern char *sys_errlist[]; 1457c478bd9Sstevel@tonic-gate #define memmove(to, from, n) bcopy(from, to, n) 1467c478bd9Sstevel@tonic-gate #define strerror(n) ((unsigned)(n) < sys_nerr? sys_errlist[(n)] :\ 1477c478bd9Sstevel@tonic-gate "unknown error") 1487c478bd9Sstevel@tonic-gate #endif 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /*************** Micro getopt() *********************************************/ 1517c478bd9Sstevel@tonic-gate #define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ 1527c478bd9Sstevel@tonic-gate (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ 1537c478bd9Sstevel@tonic-gate &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0)) 1547c478bd9Sstevel@tonic-gate #define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \ 1557c478bd9Sstevel@tonic-gate (_O=4,(char*)0):(char*)0) 1567c478bd9Sstevel@tonic-gate #define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0) 1577c478bd9Sstevel@tonic-gate #define ARG(c,v) (c?(--c,*v++):(char*)0) 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate static int _O = 0; /* Internal state */ 1607c478bd9Sstevel@tonic-gate /*************** Micro getopt() *********************************************/ 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate char *program_name; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate #define MAX_ABORTS 50 1657c478bd9Sstevel@tonic-gate #define MAX_REPORTS 50 1667c478bd9Sstevel@tonic-gate #define DEFAULT_CHAT_TIMEOUT 45 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate int echo = 0; 1697c478bd9Sstevel@tonic-gate int verbose = 0; 1707c478bd9Sstevel@tonic-gate int to_log = 1; 1717c478bd9Sstevel@tonic-gate int to_stderr = 0; 1727c478bd9Sstevel@tonic-gate int Verbose = 0; 1737c478bd9Sstevel@tonic-gate int quiet = 0; 1747c478bd9Sstevel@tonic-gate int report = 0; 1757c478bd9Sstevel@tonic-gate int use_env = 0; 1767c478bd9Sstevel@tonic-gate int exit_code = 0; 1777c478bd9Sstevel@tonic-gate FILE* report_fp = (FILE *) 0; 1787c478bd9Sstevel@tonic-gate char *report_file = (char *) 0; 1797c478bd9Sstevel@tonic-gate char *chat_file = (char *) 0; 1807c478bd9Sstevel@tonic-gate char *phone_num = (char *) 0; 1817c478bd9Sstevel@tonic-gate char *phone_num2 = (char *) 0; 1827c478bd9Sstevel@tonic-gate int timeout = DEFAULT_CHAT_TIMEOUT; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate int have_tty_parameters = 0; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate #ifdef TERMIO 1877c478bd9Sstevel@tonic-gate #define term_parms struct termio 1887c478bd9Sstevel@tonic-gate #define get_term_param(param) ioctl(0, TCGETA, param) 1897c478bd9Sstevel@tonic-gate #define set_term_param(param) ioctl(0, TCSETA, param) 1907c478bd9Sstevel@tonic-gate struct termio saved_tty_parameters; 1917c478bd9Sstevel@tonic-gate #endif 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate #ifdef TERMIOS 1947c478bd9Sstevel@tonic-gate #define term_parms struct termios 1957c478bd9Sstevel@tonic-gate #define get_term_param(param) tcgetattr(0, param) 1967c478bd9Sstevel@tonic-gate #define set_term_param(param) tcsetattr(0, TCSANOW, param) 1977c478bd9Sstevel@tonic-gate struct termios saved_tty_parameters; 1987c478bd9Sstevel@tonic-gate #endif 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate char *abort_string[MAX_ABORTS], *fail_reason = (char *)0, 2017c478bd9Sstevel@tonic-gate fail_buffer[50]; 2027c478bd9Sstevel@tonic-gate int n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0; 2037c478bd9Sstevel@tonic-gate int clear_abort_next = 0; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate char *report_string[MAX_REPORTS] ; 2067c478bd9Sstevel@tonic-gate char report_buffer[50] ; 2077c478bd9Sstevel@tonic-gate int n_reports = 0, report_next = 0, report_gathering = 0 ; 2087c478bd9Sstevel@tonic-gate int clear_report_next = 0; 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate int say_next = 0, hup_next = 0; 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate void *dup_mem __P((void *b, size_t c)); 2137c478bd9Sstevel@tonic-gate void *copy_of __P((char *s)); 2147c478bd9Sstevel@tonic-gate void usage __P((void)); 2157c478bd9Sstevel@tonic-gate void logf __P((const char *fmt, ...)); 2167c478bd9Sstevel@tonic-gate void fatal __P((int code, const char *fmt, ...)); 2177c478bd9Sstevel@tonic-gate SIGTYPE sigalrm __P((int signo)); 2187c478bd9Sstevel@tonic-gate SIGTYPE sigint __P((int signo)); 2197c478bd9Sstevel@tonic-gate SIGTYPE sigterm __P((int signo)); 2207c478bd9Sstevel@tonic-gate SIGTYPE sighup __P((int signo)); 2217c478bd9Sstevel@tonic-gate void unalarm __P((void)); 2227c478bd9Sstevel@tonic-gate void init __P((void)); 2237c478bd9Sstevel@tonic-gate void set_tty_parameters __P((void)); 2247c478bd9Sstevel@tonic-gate void echo_stderr __P((int)); 2257c478bd9Sstevel@tonic-gate void break_sequence __P((void)); 2267c478bd9Sstevel@tonic-gate void terminate __P((int status)); 2277c478bd9Sstevel@tonic-gate void do_file __P((char *chat_file)); 2287c478bd9Sstevel@tonic-gate int get_string __P((register char *string)); 2297c478bd9Sstevel@tonic-gate int put_string __P((register char *s)); 2307c478bd9Sstevel@tonic-gate int write_char __P((int c)); 2317c478bd9Sstevel@tonic-gate int put_char __P((int c)); 2327c478bd9Sstevel@tonic-gate int get_char __P((void)); 2337c478bd9Sstevel@tonic-gate void chat_send __P((register char *s)); 2347c478bd9Sstevel@tonic-gate char *character __P((int c)); 2357c478bd9Sstevel@tonic-gate void chat_expect __P((register char *s)); 2367c478bd9Sstevel@tonic-gate char *clean __P((register char *s, int sending)); 2377c478bd9Sstevel@tonic-gate void break_sequence __P((void)); 2387c478bd9Sstevel@tonic-gate void terminate __P((int status)); 2397c478bd9Sstevel@tonic-gate void pack_array __P((char **array, int end)); 2407c478bd9Sstevel@tonic-gate char *expect_strtok __P((char *, char *)); 2417c478bd9Sstevel@tonic-gate int vfmtmsg __P((char *, int, const char *, va_list)); /* vsprintf++ */ 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate int main __P((int, char *[])); 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate void *dup_mem(b, c) 2467c478bd9Sstevel@tonic-gate void *b; 2477c478bd9Sstevel@tonic-gate size_t c; 2487c478bd9Sstevel@tonic-gate { 2497c478bd9Sstevel@tonic-gate void *ans = malloc (c); 2507c478bd9Sstevel@tonic-gate if (!ans) 2517c478bd9Sstevel@tonic-gate fatal(2, "memory error!"); 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate memcpy (ans, b, c); 2547c478bd9Sstevel@tonic-gate return ans; 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate void *copy_of (s) 2587c478bd9Sstevel@tonic-gate char *s; 2597c478bd9Sstevel@tonic-gate { 2607c478bd9Sstevel@tonic-gate return dup_mem (s, strlen (s) + 1); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate /* 2647c478bd9Sstevel@tonic-gate * chat [ -v ] [ -E ] [ -T number ] [ -U number ] [ -t timeout ] [ -f chat-file ] \ 2657c478bd9Sstevel@tonic-gate * [ -r report-file ] \ 2667c478bd9Sstevel@tonic-gate * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] 2677c478bd9Sstevel@tonic-gate * 2687c478bd9Sstevel@tonic-gate * Perform a UUCP-dialer-like chat script on stdin and stdout. 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate int 2717c478bd9Sstevel@tonic-gate main(argc, argv) 2727c478bd9Sstevel@tonic-gate int argc; 2737c478bd9Sstevel@tonic-gate char **argv; 2747c478bd9Sstevel@tonic-gate { 2757c478bd9Sstevel@tonic-gate int option; 2767c478bd9Sstevel@tonic-gate char *arg; 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate program_name = *argv; 2797c478bd9Sstevel@tonic-gate tzset(); 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate while ((option = OPTION(argc, argv)) != 0) { 2827c478bd9Sstevel@tonic-gate switch (option) { 2837c478bd9Sstevel@tonic-gate case 'e': 2847c478bd9Sstevel@tonic-gate ++echo; 2857c478bd9Sstevel@tonic-gate break; 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate case 'E': 2887c478bd9Sstevel@tonic-gate ++use_env; 2897c478bd9Sstevel@tonic-gate break; 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate case 'v': 2927c478bd9Sstevel@tonic-gate ++verbose; 2937c478bd9Sstevel@tonic-gate break; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate case 'V': 2967c478bd9Sstevel@tonic-gate ++Verbose; 2977c478bd9Sstevel@tonic-gate break; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate case 's': 3007c478bd9Sstevel@tonic-gate ++to_stderr; 3017c478bd9Sstevel@tonic-gate break; 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate case 'S': 3047c478bd9Sstevel@tonic-gate to_log = 0; 3057c478bd9Sstevel@tonic-gate break; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate case 'f': 3087c478bd9Sstevel@tonic-gate if ((arg = OPTARG(argc, argv)) != NULL) 3097c478bd9Sstevel@tonic-gate chat_file = copy_of(arg); 3107c478bd9Sstevel@tonic-gate else 3117c478bd9Sstevel@tonic-gate usage(); 3127c478bd9Sstevel@tonic-gate break; 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate case 't': 3157c478bd9Sstevel@tonic-gate if ((arg = OPTARG(argc, argv)) != NULL) 3167c478bd9Sstevel@tonic-gate timeout = atoi(arg); 3177c478bd9Sstevel@tonic-gate else 3187c478bd9Sstevel@tonic-gate usage(); 3197c478bd9Sstevel@tonic-gate break; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate case 'r': 3227c478bd9Sstevel@tonic-gate arg = OPTARG (argc, argv); 3237c478bd9Sstevel@tonic-gate if (arg) { 3247c478bd9Sstevel@tonic-gate if (report_fp != NULL) 3257c478bd9Sstevel@tonic-gate fclose (report_fp); 3267c478bd9Sstevel@tonic-gate report_file = copy_of (arg); 3277c478bd9Sstevel@tonic-gate report_fp = fopen (report_file, "a"); 3287c478bd9Sstevel@tonic-gate if (report_fp != NULL) { 3297c478bd9Sstevel@tonic-gate if (verbose) 3307c478bd9Sstevel@tonic-gate fprintf (report_fp, "Opening \"%s\"...\n", 3317c478bd9Sstevel@tonic-gate report_file); 3327c478bd9Sstevel@tonic-gate report = 1; 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate break; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate case 'T': 3387c478bd9Sstevel@tonic-gate if ((arg = OPTARG(argc, argv)) != NULL) 3397c478bd9Sstevel@tonic-gate phone_num = copy_of(arg); 3407c478bd9Sstevel@tonic-gate else 3417c478bd9Sstevel@tonic-gate usage(); 3427c478bd9Sstevel@tonic-gate break; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate case 'U': 3457c478bd9Sstevel@tonic-gate if ((arg = OPTARG(argc, argv)) != NULL) 3467c478bd9Sstevel@tonic-gate phone_num2 = copy_of(arg); 3477c478bd9Sstevel@tonic-gate else 3487c478bd9Sstevel@tonic-gate usage(); 3497c478bd9Sstevel@tonic-gate break; 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate default: 3527c478bd9Sstevel@tonic-gate usage(); 3537c478bd9Sstevel@tonic-gate break; 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate /* 3577c478bd9Sstevel@tonic-gate * Default the report file to the stderr location 3587c478bd9Sstevel@tonic-gate */ 3597c478bd9Sstevel@tonic-gate if (report_fp == NULL) 3607c478bd9Sstevel@tonic-gate report_fp = stderr; 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate if (to_log) { 3637c478bd9Sstevel@tonic-gate #ifdef ultrix 3647c478bd9Sstevel@tonic-gate openlog("chat", LOG_PID); 3657c478bd9Sstevel@tonic-gate #else 3667c478bd9Sstevel@tonic-gate openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate if (verbose) 3697c478bd9Sstevel@tonic-gate setlogmask(LOG_UPTO(LOG_INFO)); 3707c478bd9Sstevel@tonic-gate else 3717c478bd9Sstevel@tonic-gate setlogmask(LOG_UPTO(LOG_WARNING)); 3727c478bd9Sstevel@tonic-gate #endif 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate init(); 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate if (chat_file != NULL) { 3787c478bd9Sstevel@tonic-gate arg = ARG(argc, argv); 3797c478bd9Sstevel@tonic-gate if (arg != NULL) 3807c478bd9Sstevel@tonic-gate usage(); 3817c478bd9Sstevel@tonic-gate else 3827c478bd9Sstevel@tonic-gate do_file (chat_file); 3837c478bd9Sstevel@tonic-gate } else { 3847c478bd9Sstevel@tonic-gate while ((arg = ARG(argc, argv)) != NULL) { 3857c478bd9Sstevel@tonic-gate chat_expect(arg); 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate if ((arg = ARG(argc, argv)) != NULL) 3887c478bd9Sstevel@tonic-gate chat_send(arg); 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate terminate(0); 3937c478bd9Sstevel@tonic-gate return 0; 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * Process a chat script when read from a file. 3987c478bd9Sstevel@tonic-gate */ 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate void do_file (chat_file) 4017c478bd9Sstevel@tonic-gate char *chat_file; 4027c478bd9Sstevel@tonic-gate { 4037c478bd9Sstevel@tonic-gate int linect, sendflg; 4047c478bd9Sstevel@tonic-gate char *sp, *arg, quote; 4057c478bd9Sstevel@tonic-gate char buf [STR_LEN]; 4067c478bd9Sstevel@tonic-gate FILE *cfp; 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate cfp = fopen (chat_file, "r"); 4097c478bd9Sstevel@tonic-gate if (cfp == NULL) 4107c478bd9Sstevel@tonic-gate fatal(1, "%s -- open failed: %m", chat_file); 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate linect = 0; 4137c478bd9Sstevel@tonic-gate sendflg = 0; 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate while (fgets(buf, STR_LEN, cfp) != NULL) { 4167c478bd9Sstevel@tonic-gate sp = strchr (buf, '\n'); 4177c478bd9Sstevel@tonic-gate if (sp) 4187c478bd9Sstevel@tonic-gate *sp = '\0'; 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate linect++; 4217c478bd9Sstevel@tonic-gate sp = buf; 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate /* lines starting with '#' are comments. If a real '#' 4247c478bd9Sstevel@tonic-gate is to be expected, it should be quoted .... */ 4257c478bd9Sstevel@tonic-gate if ( *sp == '#' ) 4267c478bd9Sstevel@tonic-gate continue; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate while (*sp != '\0') { 4297c478bd9Sstevel@tonic-gate if (*sp == ' ' || *sp == '\t') { 4307c478bd9Sstevel@tonic-gate ++sp; 4317c478bd9Sstevel@tonic-gate continue; 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate if (*sp == '"' || *sp == '\'') { 4357c478bd9Sstevel@tonic-gate quote = *sp++; 4367c478bd9Sstevel@tonic-gate arg = sp; 4377c478bd9Sstevel@tonic-gate while (*sp != quote) { 4387c478bd9Sstevel@tonic-gate if (*sp == '\0') 4397c478bd9Sstevel@tonic-gate fatal(1, "unterminated quote (line %d)", linect); 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate if (*sp++ == '\\') { 4427c478bd9Sstevel@tonic-gate if (*sp != '\0') 4437c478bd9Sstevel@tonic-gate ++sp; 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate else { 4487c478bd9Sstevel@tonic-gate arg = sp; 4497c478bd9Sstevel@tonic-gate while (*sp != '\0' && *sp != ' ' && *sp != '\t') 4507c478bd9Sstevel@tonic-gate ++sp; 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate if (*sp != '\0') 4547c478bd9Sstevel@tonic-gate *sp++ = '\0'; 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate if (sendflg) 4577c478bd9Sstevel@tonic-gate chat_send (arg); 4587c478bd9Sstevel@tonic-gate else 4597c478bd9Sstevel@tonic-gate chat_expect (arg); 4607c478bd9Sstevel@tonic-gate sendflg = !sendflg; 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate fclose (cfp); 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate /* 4677c478bd9Sstevel@tonic-gate * We got an error parsing the command line. 4687c478bd9Sstevel@tonic-gate */ 4697c478bd9Sstevel@tonic-gate void usage() 4707c478bd9Sstevel@tonic-gate { 4717c478bd9Sstevel@tonic-gate fprintf(stderr, "\ 4727c478bd9Sstevel@tonic-gate Usage: %s [-e] [-E] [-v] [-V] [-t timeout] [-r report-file]\n\ 4737c478bd9Sstevel@tonic-gate [-T phone-number] [-U phone-number2] {-f chat-file | chat-script}\n", program_name); 4747c478bd9Sstevel@tonic-gate exit(1); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate char line[1024]; 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate /* 4807c478bd9Sstevel@tonic-gate * Send a message to syslog and/or stderr. 4817c478bd9Sstevel@tonic-gate */ 4827c478bd9Sstevel@tonic-gate void logf __V((const char *fmt, ...)) 4837c478bd9Sstevel@tonic-gate { 4847c478bd9Sstevel@tonic-gate va_list args; 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate #ifdef __STDC__ 4877c478bd9Sstevel@tonic-gate va_start(args, fmt); 4887c478bd9Sstevel@tonic-gate #else 4897c478bd9Sstevel@tonic-gate char *fmt; 4907c478bd9Sstevel@tonic-gate va_start(args); 4917c478bd9Sstevel@tonic-gate fmt = va_arg(args, char *); 4927c478bd9Sstevel@tonic-gate #endif 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate vfmtmsg(line, sizeof(line), fmt, args); 4957c478bd9Sstevel@tonic-gate if (to_log) 4967c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "%s", line); 4977c478bd9Sstevel@tonic-gate if (to_stderr) 4987c478bd9Sstevel@tonic-gate fprintf(stderr, "%s\n", line); 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * Print an error message and terminate. 5037c478bd9Sstevel@tonic-gate */ 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate void fatal __V((int code, const char *fmt, ...)) 5067c478bd9Sstevel@tonic-gate { 5077c478bd9Sstevel@tonic-gate va_list args; 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate #ifdef __STDC__ 5107c478bd9Sstevel@tonic-gate va_start(args, fmt); 5117c478bd9Sstevel@tonic-gate #else 5127c478bd9Sstevel@tonic-gate int code; 5137c478bd9Sstevel@tonic-gate char *fmt; 5147c478bd9Sstevel@tonic-gate va_start(args); 5157c478bd9Sstevel@tonic-gate code = va_arg(args, int); 5167c478bd9Sstevel@tonic-gate fmt = va_arg(args, char *); 5177c478bd9Sstevel@tonic-gate #endif 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate vfmtmsg(line, sizeof(line), fmt, args); 5207c478bd9Sstevel@tonic-gate if (to_log) 5217c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s", line); 5227c478bd9Sstevel@tonic-gate if (to_stderr) 5237c478bd9Sstevel@tonic-gate fprintf(stderr, "%s\n", line); 5247c478bd9Sstevel@tonic-gate terminate(code); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate int alarmed = 0; 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate SIGTYPE sigalrm(signo) 5307c478bd9Sstevel@tonic-gate int signo; 5317c478bd9Sstevel@tonic-gate { 5327c478bd9Sstevel@tonic-gate int flags; 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate alarm(1); 5357c478bd9Sstevel@tonic-gate alarmed = 1; /* Reset alarm to avoid race window */ 5367c478bd9Sstevel@tonic-gate signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate if ((flags = fcntl(0, F_GETFL, 0)) == -1) 5397c478bd9Sstevel@tonic-gate fatal(2, "Can't get file mode flags on stdin: %m"); 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) 5427c478bd9Sstevel@tonic-gate fatal(2, "Can't set file mode flags on stdin: %m"); 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate if (verbose) 5457c478bd9Sstevel@tonic-gate logf("alarm"); 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate void unalarm() 5497c478bd9Sstevel@tonic-gate { 5507c478bd9Sstevel@tonic-gate int flags; 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate if ((flags = fcntl(0, F_GETFL, 0)) == -1) 5537c478bd9Sstevel@tonic-gate fatal(2, "Can't get file mode flags on stdin: %m"); 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1) 5567c478bd9Sstevel@tonic-gate fatal(2, "Can't set file mode flags on stdin: %m"); 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate SIGTYPE sigint(signo) 5607c478bd9Sstevel@tonic-gate int signo; 5617c478bd9Sstevel@tonic-gate { 5627c478bd9Sstevel@tonic-gate fatal(2, "SIGINT"); 5637c478bd9Sstevel@tonic-gate } 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate SIGTYPE sigterm(signo) 5667c478bd9Sstevel@tonic-gate int signo; 5677c478bd9Sstevel@tonic-gate { 5687c478bd9Sstevel@tonic-gate fatal(2, "SIGTERM"); 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate SIGTYPE sighup(signo) 5727c478bd9Sstevel@tonic-gate int signo; 5737c478bd9Sstevel@tonic-gate { 5747c478bd9Sstevel@tonic-gate fatal(2, "SIGHUP"); 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate void init() 5787c478bd9Sstevel@tonic-gate { 5797c478bd9Sstevel@tonic-gate signal(SIGINT, sigint); 5807c478bd9Sstevel@tonic-gate signal(SIGTERM, sigterm); 5817c478bd9Sstevel@tonic-gate signal(SIGHUP, sighup); 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate set_tty_parameters(); 5847c478bd9Sstevel@tonic-gate signal(SIGALRM, sigalrm); 5857c478bd9Sstevel@tonic-gate alarm(0); 5867c478bd9Sstevel@tonic-gate alarmed = 0; 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate void set_tty_parameters() 5907c478bd9Sstevel@tonic-gate { 5917c478bd9Sstevel@tonic-gate #if defined(get_term_param) 5927c478bd9Sstevel@tonic-gate term_parms t; 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate if (get_term_param (&t) < 0) 5957c478bd9Sstevel@tonic-gate fatal(2, "Can't get terminal parameters: %m"); 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate saved_tty_parameters = t; 5987c478bd9Sstevel@tonic-gate have_tty_parameters = 1; 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 6017c478bd9Sstevel@tonic-gate t.c_oflag = 0; 6027c478bd9Sstevel@tonic-gate t.c_lflag = 0; 6037c478bd9Sstevel@tonic-gate t.c_cc[VERASE] = 6047c478bd9Sstevel@tonic-gate t.c_cc[VKILL] = 0; 6057c478bd9Sstevel@tonic-gate t.c_cc[VMIN] = 1; 6067c478bd9Sstevel@tonic-gate t.c_cc[VTIME] = 0; 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate if (set_term_param (&t) < 0) 6097c478bd9Sstevel@tonic-gate fatal(2, "Can't set terminal parameters: %m"); 6107c478bd9Sstevel@tonic-gate #endif 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate void break_sequence() 6147c478bd9Sstevel@tonic-gate { 6157c478bd9Sstevel@tonic-gate #ifdef TERMIOS 6167c478bd9Sstevel@tonic-gate tcsendbreak (0, 0); 6177c478bd9Sstevel@tonic-gate #endif 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate void terminate(status) 6217c478bd9Sstevel@tonic-gate int status; 6227c478bd9Sstevel@tonic-gate { 6237c478bd9Sstevel@tonic-gate static int terminating = 0; 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate if (terminating) 6267c478bd9Sstevel@tonic-gate exit(status); 6277c478bd9Sstevel@tonic-gate terminating = 1; 6287c478bd9Sstevel@tonic-gate echo_stderr(-1); 6297c478bd9Sstevel@tonic-gate /* 6307c478bd9Sstevel@tonic-gate * Allow the last of the report string to be gathered before we terminate. 6317c478bd9Sstevel@tonic-gate */ 6327c478bd9Sstevel@tonic-gate if (report_gathering) { 6337c478bd9Sstevel@tonic-gate int c, rep_len; 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate rep_len = strlen(report_buffer); 6367c478bd9Sstevel@tonic-gate while (rep_len + 1 <= sizeof(report_buffer)) { 6377c478bd9Sstevel@tonic-gate alarm(1); 6387c478bd9Sstevel@tonic-gate c = get_char(); 6397c478bd9Sstevel@tonic-gate alarm(0); 6407c478bd9Sstevel@tonic-gate if (c < 0 || iscntrl(c)) 6417c478bd9Sstevel@tonic-gate break; 6427c478bd9Sstevel@tonic-gate report_buffer[rep_len] = c; 6437c478bd9Sstevel@tonic-gate ++rep_len; 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate report_buffer[rep_len] = 0; 6467c478bd9Sstevel@tonic-gate fprintf (report_fp, "chat: %s\n", report_buffer); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate if (report_file != (char *) 0 && report_fp != (FILE *) NULL) { 6497c478bd9Sstevel@tonic-gate if (verbose) 6507c478bd9Sstevel@tonic-gate fprintf (report_fp, "Closing \"%s\".\n", report_file); 6517c478bd9Sstevel@tonic-gate fclose (report_fp); 6527c478bd9Sstevel@tonic-gate report_fp = (FILE *) NULL; 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate #if defined(get_term_param) 6567c478bd9Sstevel@tonic-gate if (have_tty_parameters) { 6577c478bd9Sstevel@tonic-gate if (set_term_param (&saved_tty_parameters) < 0) 6587c478bd9Sstevel@tonic-gate fatal(2, "Can't restore terminal parameters: %m"); 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate #endif 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate exit(status); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate /* 6667c478bd9Sstevel@tonic-gate * 'Clean up' this string. 6677c478bd9Sstevel@tonic-gate */ 6687c478bd9Sstevel@tonic-gate char *clean(s, sending) 6697c478bd9Sstevel@tonic-gate register char *s; 6707c478bd9Sstevel@tonic-gate int sending; /* set to 1 when sending (putting) this string. */ 6717c478bd9Sstevel@tonic-gate { 6727c478bd9Sstevel@tonic-gate char temp[STR_LEN], env_str[STR_LEN], cur_chr; 6737c478bd9Sstevel@tonic-gate register char *s1, *phchar; 6747c478bd9Sstevel@tonic-gate int add_return = sending; 6757c478bd9Sstevel@tonic-gate #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 6767c478bd9Sstevel@tonic-gate #define isalnumx(chr) ((((chr) >= '0') && ((chr) <= '9')) \ 6777c478bd9Sstevel@tonic-gate || (((chr) >= 'a') && ((chr) <= 'z')) \ 6787c478bd9Sstevel@tonic-gate || (((chr) >= 'A') && ((chr) <= 'Z')) \ 6797c478bd9Sstevel@tonic-gate || (chr) == '_') 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate s1 = temp; 6827c478bd9Sstevel@tonic-gate while (*s) { 6837c478bd9Sstevel@tonic-gate cur_chr = *s++; 6847c478bd9Sstevel@tonic-gate if (cur_chr == '^') { 6857c478bd9Sstevel@tonic-gate cur_chr = *s++; 6867c478bd9Sstevel@tonic-gate if (cur_chr == '\0') { 6877c478bd9Sstevel@tonic-gate *s1++ = '^'; 6887c478bd9Sstevel@tonic-gate break; 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate cur_chr &= 0x1F; 6917c478bd9Sstevel@tonic-gate if (cur_chr != 0) { 6927c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate continue; 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate if (use_env && cur_chr == '$') { /* ARI */ 6987c478bd9Sstevel@tonic-gate phchar = env_str; 6997c478bd9Sstevel@tonic-gate while (isalnumx(*s)) 7007c478bd9Sstevel@tonic-gate *phchar++ = *s++; 7017c478bd9Sstevel@tonic-gate *phchar = '\0'; 7027c478bd9Sstevel@tonic-gate phchar = getenv(env_str); 7037c478bd9Sstevel@tonic-gate if (phchar) 7047c478bd9Sstevel@tonic-gate while (*phchar) 7057c478bd9Sstevel@tonic-gate *s1++ = *phchar++; 7067c478bd9Sstevel@tonic-gate continue; 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate if (cur_chr != '\\') { 7107c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 7117c478bd9Sstevel@tonic-gate continue; 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate cur_chr = *s++; 7157c478bd9Sstevel@tonic-gate if (cur_chr == '\0') { 7167c478bd9Sstevel@tonic-gate if (sending) { 7177c478bd9Sstevel@tonic-gate *s1++ = '\\'; 7187c478bd9Sstevel@tonic-gate *s1++ = '\\'; 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate break; 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate switch (cur_chr) { 7247c478bd9Sstevel@tonic-gate case 'b': 7257c478bd9Sstevel@tonic-gate *s1++ = '\b'; 7267c478bd9Sstevel@tonic-gate break; 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate case 'c': 7297c478bd9Sstevel@tonic-gate if (sending && *s == '\0') 7307c478bd9Sstevel@tonic-gate add_return = 0; 7317c478bd9Sstevel@tonic-gate else 7327c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 7337c478bd9Sstevel@tonic-gate break; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate case '\\': 7367c478bd9Sstevel@tonic-gate case 'K': 7377c478bd9Sstevel@tonic-gate case 'p': 7387c478bd9Sstevel@tonic-gate case 'd': 7397c478bd9Sstevel@tonic-gate if (sending) 7407c478bd9Sstevel@tonic-gate *s1++ = '\\'; 7417c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 7427c478bd9Sstevel@tonic-gate break; 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate case 'T': 7457c478bd9Sstevel@tonic-gate if (sending && phone_num) { 7467c478bd9Sstevel@tonic-gate for (phchar = phone_num; *phchar != '\0'; phchar++) 7477c478bd9Sstevel@tonic-gate *s1++ = *phchar; 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate else { 7507c478bd9Sstevel@tonic-gate *s1++ = '\\'; 7517c478bd9Sstevel@tonic-gate *s1++ = 'T'; 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate break; 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate case 'U': 7567c478bd9Sstevel@tonic-gate if (sending && phone_num2) { 7577c478bd9Sstevel@tonic-gate for (phchar = phone_num2; *phchar != '\0'; phchar++) 7587c478bd9Sstevel@tonic-gate *s1++ = *phchar; 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate else { 7617c478bd9Sstevel@tonic-gate *s1++ = '\\'; 7627c478bd9Sstevel@tonic-gate *s1++ = 'U'; 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate break; 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate case 'q': 7677c478bd9Sstevel@tonic-gate quiet = 1; 7687c478bd9Sstevel@tonic-gate break; 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate case 'r': 7717c478bd9Sstevel@tonic-gate *s1++ = '\r'; 7727c478bd9Sstevel@tonic-gate break; 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate case 'n': 7757c478bd9Sstevel@tonic-gate *s1++ = '\n'; 7767c478bd9Sstevel@tonic-gate break; 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate case 's': 7797c478bd9Sstevel@tonic-gate *s1++ = ' '; 7807c478bd9Sstevel@tonic-gate break; 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate case 't': 7837c478bd9Sstevel@tonic-gate *s1++ = '\t'; 7847c478bd9Sstevel@tonic-gate break; 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate case 'N': 7877c478bd9Sstevel@tonic-gate if (sending) { 7887c478bd9Sstevel@tonic-gate *s1++ = '\\'; 7897c478bd9Sstevel@tonic-gate *s1++ = '\0'; 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate else 7927c478bd9Sstevel@tonic-gate *s1++ = 'N'; 7937c478bd9Sstevel@tonic-gate break; 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate case '$': /* ARI */ 7967c478bd9Sstevel@tonic-gate if (use_env) { 7977c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 7987c478bd9Sstevel@tonic-gate break; 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate /* FALL THROUGH */ 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate default: 8037c478bd9Sstevel@tonic-gate if (isoctal (cur_chr)) { 8047c478bd9Sstevel@tonic-gate cur_chr &= 0x07; 8057c478bd9Sstevel@tonic-gate if (isoctal (*s)) { 8067c478bd9Sstevel@tonic-gate cur_chr <<= 3; 8077c478bd9Sstevel@tonic-gate cur_chr |= *s++ - '0'; 8087c478bd9Sstevel@tonic-gate if (isoctal (*s)) { 8097c478bd9Sstevel@tonic-gate cur_chr <<= 3; 8107c478bd9Sstevel@tonic-gate cur_chr |= *s++ - '0'; 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate if (cur_chr != 0 || sending) { 8157c478bd9Sstevel@tonic-gate if (sending && (cur_chr == '\\' || cur_chr == 0)) 8167c478bd9Sstevel@tonic-gate *s1++ = '\\'; 8177c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate break; 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate if (sending) 8237c478bd9Sstevel@tonic-gate *s1++ = '\\'; 8247c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 8257c478bd9Sstevel@tonic-gate break; 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate if (add_return) 8307c478bd9Sstevel@tonic-gate *s1++ = '\r'; 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate *s1++ = '\0'; /* guarantee closure */ 8337c478bd9Sstevel@tonic-gate *s1++ = '\0'; /* terminate the string */ 8347c478bd9Sstevel@tonic-gate return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate /* 8387c478bd9Sstevel@tonic-gate * A modified version of 'strtok'. This version skips \ sequences. 8397c478bd9Sstevel@tonic-gate */ 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate char *expect_strtok (s, term) 8427c478bd9Sstevel@tonic-gate char *s, *term; 8437c478bd9Sstevel@tonic-gate { 8447c478bd9Sstevel@tonic-gate static char *str = ""; 8457c478bd9Sstevel@tonic-gate int escape_flag = 0; 8467c478bd9Sstevel@tonic-gate char *result; 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate /* 8497c478bd9Sstevel@tonic-gate * If a string was specified then do initial processing. 8507c478bd9Sstevel@tonic-gate */ 8517c478bd9Sstevel@tonic-gate if (s) 8527c478bd9Sstevel@tonic-gate str = s; 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate /* 8557c478bd9Sstevel@tonic-gate * If this is the escape flag then reset it and ignore the character. 8567c478bd9Sstevel@tonic-gate */ 8577c478bd9Sstevel@tonic-gate if (*str) 8587c478bd9Sstevel@tonic-gate result = str; 8597c478bd9Sstevel@tonic-gate else 8607c478bd9Sstevel@tonic-gate result = (char *) 0; 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate while (*str) { 8637c478bd9Sstevel@tonic-gate if (escape_flag) { 8647c478bd9Sstevel@tonic-gate escape_flag = 0; 8657c478bd9Sstevel@tonic-gate ++str; 8667c478bd9Sstevel@tonic-gate continue; 8677c478bd9Sstevel@tonic-gate } 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate if (*str == '\\') { 8707c478bd9Sstevel@tonic-gate ++str; 8717c478bd9Sstevel@tonic-gate escape_flag = 1; 8727c478bd9Sstevel@tonic-gate continue; 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate /* 8767c478bd9Sstevel@tonic-gate * If this is not in the termination string, continue. 8777c478bd9Sstevel@tonic-gate */ 8787c478bd9Sstevel@tonic-gate if (strchr (term, *str) == (char *) 0) { 8797c478bd9Sstevel@tonic-gate ++str; 8807c478bd9Sstevel@tonic-gate continue; 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate /* 8847c478bd9Sstevel@tonic-gate * This is the terminator. Mark the end of the string and stop. 8857c478bd9Sstevel@tonic-gate */ 8867c478bd9Sstevel@tonic-gate *str++ = '\0'; 8877c478bd9Sstevel@tonic-gate break; 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate return (result); 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate /* 8937c478bd9Sstevel@tonic-gate * Process the expect string 8947c478bd9Sstevel@tonic-gate */ 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate void chat_expect (s) 8977c478bd9Sstevel@tonic-gate char *s; 8987c478bd9Sstevel@tonic-gate { 8997c478bd9Sstevel@tonic-gate char *expect; 9007c478bd9Sstevel@tonic-gate char *reply; 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate if (strcmp(s, "HANGUP") == 0) { 9037c478bd9Sstevel@tonic-gate ++hup_next; 9047c478bd9Sstevel@tonic-gate return; 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate if (strcmp(s, "ABORT") == 0) { 9087c478bd9Sstevel@tonic-gate ++abort_next; 9097c478bd9Sstevel@tonic-gate return; 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate if (strcmp(s, "CLR_ABORT") == 0) { 9137c478bd9Sstevel@tonic-gate ++clear_abort_next; 9147c478bd9Sstevel@tonic-gate return; 9157c478bd9Sstevel@tonic-gate } 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate if (strcmp(s, "REPORT") == 0) { 9187c478bd9Sstevel@tonic-gate ++report_next; 9197c478bd9Sstevel@tonic-gate return; 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate if (strcmp(s, "CLR_REPORT") == 0) { 9237c478bd9Sstevel@tonic-gate ++clear_report_next; 9247c478bd9Sstevel@tonic-gate return; 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate if (strcmp(s, "TIMEOUT") == 0) { 9287c478bd9Sstevel@tonic-gate ++timeout_next; 9297c478bd9Sstevel@tonic-gate return; 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate if (strcmp(s, "ECHO") == 0) { 9337c478bd9Sstevel@tonic-gate ++echo_next; 9347c478bd9Sstevel@tonic-gate return; 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate if (strcmp(s, "SAY") == 0) { 9387c478bd9Sstevel@tonic-gate ++say_next; 9397c478bd9Sstevel@tonic-gate return; 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate /* 9437c478bd9Sstevel@tonic-gate * Fetch the expect and reply string. 9447c478bd9Sstevel@tonic-gate */ 9457c478bd9Sstevel@tonic-gate for (;;) { 9467c478bd9Sstevel@tonic-gate expect = expect_strtok (s, "-"); 9477c478bd9Sstevel@tonic-gate s = (char *) 0; 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate if (expect == (char *) 0) 9507c478bd9Sstevel@tonic-gate return; 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate reply = expect_strtok (s, "-"); 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate /* 9557c478bd9Sstevel@tonic-gate * Handle the expect string. If successful then exit. 9567c478bd9Sstevel@tonic-gate */ 9577c478bd9Sstevel@tonic-gate if (get_string (expect)) 9587c478bd9Sstevel@tonic-gate return; 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate /* 9617c478bd9Sstevel@tonic-gate * If there is a sub-reply string then send it. Otherwise any condition 9627c478bd9Sstevel@tonic-gate * is terminal. 9637c478bd9Sstevel@tonic-gate */ 9647c478bd9Sstevel@tonic-gate if (reply == (char *) 0 || exit_code != 3) 9657c478bd9Sstevel@tonic-gate break; 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate chat_send (reply); 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate /* 9717c478bd9Sstevel@tonic-gate * The expectation did not occur. This is terminal. 9727c478bd9Sstevel@tonic-gate */ 9737c478bd9Sstevel@tonic-gate if (fail_reason) 9747c478bd9Sstevel@tonic-gate logf("Failed (%s)", fail_reason); 9757c478bd9Sstevel@tonic-gate else 9767c478bd9Sstevel@tonic-gate logf("Failed"); 9777c478bd9Sstevel@tonic-gate terminate(exit_code); 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate /* 9817c478bd9Sstevel@tonic-gate * Translate the input character to the appropriate string for printing 9827c478bd9Sstevel@tonic-gate * the data. 9837c478bd9Sstevel@tonic-gate */ 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate char *character(c) 9867c478bd9Sstevel@tonic-gate int c; 9877c478bd9Sstevel@tonic-gate { 9887c478bd9Sstevel@tonic-gate static char string[10]; 9897c478bd9Sstevel@tonic-gate char *meta; 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate meta = (c & 0x80) ? "M-" : ""; 9927c478bd9Sstevel@tonic-gate c &= 0x7F; 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate if (c < 32) 9957c478bd9Sstevel@tonic-gate sprintf(string, "%s^%c", meta, (int)c + '@'); 9967c478bd9Sstevel@tonic-gate else if (c == 127) 9977c478bd9Sstevel@tonic-gate sprintf(string, "%s^?", meta); 9987c478bd9Sstevel@tonic-gate else 9997c478bd9Sstevel@tonic-gate sprintf(string, "%s%c", meta, c); 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate return (string); 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /* 10057c478bd9Sstevel@tonic-gate * process the reply string 10067c478bd9Sstevel@tonic-gate */ 10077c478bd9Sstevel@tonic-gate void chat_send (s) 10087c478bd9Sstevel@tonic-gate register char *s; 10097c478bd9Sstevel@tonic-gate { 10107c478bd9Sstevel@tonic-gate char file_data[STR_LEN]; 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate if (say_next) { 10137c478bd9Sstevel@tonic-gate say_next = 0; 10147c478bd9Sstevel@tonic-gate s = clean(s, 1); 10157c478bd9Sstevel@tonic-gate write(2, s, strlen(s)); 10167c478bd9Sstevel@tonic-gate free(s); 10177c478bd9Sstevel@tonic-gate return; 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate if (hup_next) { 10217c478bd9Sstevel@tonic-gate hup_next = 0; 10227c478bd9Sstevel@tonic-gate if (strcmp(s, "OFF") == 0) 10237c478bd9Sstevel@tonic-gate signal(SIGHUP, SIG_IGN); 10247c478bd9Sstevel@tonic-gate else 10257c478bd9Sstevel@tonic-gate signal(SIGHUP, sighup); 10267c478bd9Sstevel@tonic-gate return; 10277c478bd9Sstevel@tonic-gate } 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate if (echo_next) { 10307c478bd9Sstevel@tonic-gate echo_next = 0; 10317c478bd9Sstevel@tonic-gate echo = (strcmp(s, "ON") == 0); 10327c478bd9Sstevel@tonic-gate return; 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate if (abort_next) { 10367c478bd9Sstevel@tonic-gate char *s1; 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate abort_next = 0; 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate if (n_aborts >= MAX_ABORTS) 10417c478bd9Sstevel@tonic-gate fatal(2, "Too many ABORT strings"); 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate s1 = clean(s, 0); 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate if (strlen(s1) > strlen(s) 10467c478bd9Sstevel@tonic-gate || strlen(s1) + 1 > sizeof(fail_buffer)) 10477c478bd9Sstevel@tonic-gate fatal(1, "Illegal or too-long ABORT string ('%v')", s); 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate abort_string[n_aborts++] = s1; 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate if (verbose) 10527c478bd9Sstevel@tonic-gate logf("abort on (%v)", s); 10537c478bd9Sstevel@tonic-gate return; 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate if (clear_abort_next) { 10577c478bd9Sstevel@tonic-gate char *s1; 10587c478bd9Sstevel@tonic-gate int i; 10597c478bd9Sstevel@tonic-gate int old_max; 10607c478bd9Sstevel@tonic-gate int pack = 0; 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate clear_abort_next = 0; 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate s1 = clean(s, 0); 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate if (strlen(s1) > strlen(s) 10677c478bd9Sstevel@tonic-gate || strlen(s1) + 1 > sizeof(fail_buffer)) 10687c478bd9Sstevel@tonic-gate fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s); 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate old_max = n_aborts; 10717c478bd9Sstevel@tonic-gate for (i=0; i < n_aborts; i++) { 10727c478bd9Sstevel@tonic-gate if ( strcmp(s1,abort_string[i]) == 0 ) { 10737c478bd9Sstevel@tonic-gate free(abort_string[i]); 10747c478bd9Sstevel@tonic-gate abort_string[i] = NULL; 10757c478bd9Sstevel@tonic-gate pack++; 10767c478bd9Sstevel@tonic-gate n_aborts--; 10777c478bd9Sstevel@tonic-gate if (verbose) 10787c478bd9Sstevel@tonic-gate logf("clear abort on (%v)", s); 10797c478bd9Sstevel@tonic-gate } 10807c478bd9Sstevel@tonic-gate } 10817c478bd9Sstevel@tonic-gate free(s1); 10827c478bd9Sstevel@tonic-gate if (pack) 10837c478bd9Sstevel@tonic-gate pack_array(abort_string,old_max); 10847c478bd9Sstevel@tonic-gate return; 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate if (report_next) { 10887c478bd9Sstevel@tonic-gate char *s1; 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate report_next = 0; 10917c478bd9Sstevel@tonic-gate if (n_reports >= MAX_REPORTS) 10927c478bd9Sstevel@tonic-gate fatal(2, "Too many REPORT strings"); 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate s1 = clean(s, 0); 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 10977c478bd9Sstevel@tonic-gate fatal(1, "Illegal or too-long REPORT string ('%v')", s); 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate report_string[n_reports++] = s1; 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate if (verbose) 11027c478bd9Sstevel@tonic-gate logf("report (%v)", s); 11037c478bd9Sstevel@tonic-gate return; 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate if (clear_report_next) { 11077c478bd9Sstevel@tonic-gate char *s1; 11087c478bd9Sstevel@tonic-gate int i; 11097c478bd9Sstevel@tonic-gate int old_max; 11107c478bd9Sstevel@tonic-gate int pack = 0; 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate clear_report_next = 0; 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate s1 = clean(s, 0); 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 11177c478bd9Sstevel@tonic-gate fatal(1, "Illegal or too-long REPORT string ('%v')", s); 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate old_max = n_reports; 11207c478bd9Sstevel@tonic-gate for (i=0; i < n_reports; i++) { 11217c478bd9Sstevel@tonic-gate if ( strcmp(s1,report_string[i]) == 0 ) { 11227c478bd9Sstevel@tonic-gate free(report_string[i]); 11237c478bd9Sstevel@tonic-gate report_string[i] = NULL; 11247c478bd9Sstevel@tonic-gate pack++; 11257c478bd9Sstevel@tonic-gate n_reports--; 11267c478bd9Sstevel@tonic-gate if (verbose) 11277c478bd9Sstevel@tonic-gate logf("clear report (%v)", s); 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate free(s1); 11317c478bd9Sstevel@tonic-gate if (pack) 11327c478bd9Sstevel@tonic-gate pack_array(report_string,old_max); 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate return; 11357c478bd9Sstevel@tonic-gate } 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate if (timeout_next) { 11387c478bd9Sstevel@tonic-gate timeout_next = 0; 11397c478bd9Sstevel@tonic-gate timeout = atoi(s); 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate if (timeout <= 0) 11427c478bd9Sstevel@tonic-gate timeout = DEFAULT_CHAT_TIMEOUT; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate if (verbose) 11457c478bd9Sstevel@tonic-gate logf("timeout set to %d seconds", timeout); 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate return; 11487c478bd9Sstevel@tonic-gate } 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate /* 11517c478bd9Sstevel@tonic-gate * The syntax @filename means read the string to send from the 11527c478bd9Sstevel@tonic-gate * file `filename'. 11537c478bd9Sstevel@tonic-gate */ 11547c478bd9Sstevel@tonic-gate if (s[0] == '@') { 11557c478bd9Sstevel@tonic-gate /* skip the @ and any following white-space */ 11567c478bd9Sstevel@tonic-gate char *fn = s; 11577c478bd9Sstevel@tonic-gate while (*++fn == ' ' || *fn == '\t') 11587c478bd9Sstevel@tonic-gate ; 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate if (*fn != 0) { 11617c478bd9Sstevel@tonic-gate FILE *f; 11627c478bd9Sstevel@tonic-gate int n = 0; 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate /* open the file and read until STR_LEN-1 bytes or end-of-file */ 11657c478bd9Sstevel@tonic-gate f = fopen(fn, "r"); 11667c478bd9Sstevel@tonic-gate if (f == NULL) 11677c478bd9Sstevel@tonic-gate fatal(1, "%s -- open failed: %m", fn); 11687c478bd9Sstevel@tonic-gate while (n < STR_LEN - 1) { 11697c478bd9Sstevel@tonic-gate int nr = fread(&file_data[n], 1, STR_LEN - 1 - n, f); 11707c478bd9Sstevel@tonic-gate if (nr < 0) 11717c478bd9Sstevel@tonic-gate fatal(1, "%s -- read error", fn); 11727c478bd9Sstevel@tonic-gate if (nr == 0) 11737c478bd9Sstevel@tonic-gate break; 11747c478bd9Sstevel@tonic-gate n += nr; 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate fclose(f); 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate /* use the string we got as the string to send, 11797c478bd9Sstevel@tonic-gate but trim off the final newline if any. */ 11807c478bd9Sstevel@tonic-gate if (n > 0 && file_data[n-1] == '\n') 11817c478bd9Sstevel@tonic-gate --n; 11827c478bd9Sstevel@tonic-gate file_data[n] = 0; 11837c478bd9Sstevel@tonic-gate s = file_data; 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate if (strcmp(s, "EOT") == 0) 11887c478bd9Sstevel@tonic-gate s = "^D\\c"; 11897c478bd9Sstevel@tonic-gate else if (strcmp(s, "BREAK") == 0) 11907c478bd9Sstevel@tonic-gate s = "\\K\\c"; 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate if (!put_string(s)) 11937c478bd9Sstevel@tonic-gate fatal(1, "Failed"); 11947c478bd9Sstevel@tonic-gate } 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate int get_char() 11977c478bd9Sstevel@tonic-gate { 11987c478bd9Sstevel@tonic-gate int status; 11997c478bd9Sstevel@tonic-gate char c; 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate status = read(0, &c, 1); 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate switch (status) { 12047c478bd9Sstevel@tonic-gate case 1: 12057c478bd9Sstevel@tonic-gate return ((int)c & 0x7F); 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate default: 12087c478bd9Sstevel@tonic-gate logf("warning: read() on stdin returned %d", status); 1209*b2cf5195SToomas Soome /* FALLTHROUGH */ 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate case -1: 12127c478bd9Sstevel@tonic-gate if ((status = fcntl(0, F_GETFL, 0)) == -1) 12137c478bd9Sstevel@tonic-gate fatal(2, "Can't get file mode flags on stdin: %m"); 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 12167c478bd9Sstevel@tonic-gate fatal(2, "Can't set file mode flags on stdin: %m"); 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate return (-1); 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate } 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate int put_char(c) 12237c478bd9Sstevel@tonic-gate int c; 12247c478bd9Sstevel@tonic-gate { 12257c478bd9Sstevel@tonic-gate int status; 12267c478bd9Sstevel@tonic-gate char ch = c; 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate usleep(10000); /* inter-character typing delay (?) */ 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate status = write(1, &ch, 1); 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate switch (status) { 12337c478bd9Sstevel@tonic-gate case 1: 12347c478bd9Sstevel@tonic-gate return (0); 1235*b2cf5195SToomas Soome 12367c478bd9Sstevel@tonic-gate default: 12377c478bd9Sstevel@tonic-gate logf("warning: write() on stdout returned %d", status); 1238*b2cf5195SToomas Soome /* FALLTHROUGH */ 1239*b2cf5195SToomas Soome 12407c478bd9Sstevel@tonic-gate case -1: 12417c478bd9Sstevel@tonic-gate if ((status = fcntl(0, F_GETFL, 0)) == -1) 12427c478bd9Sstevel@tonic-gate fatal(2, "Can't get file mode flags on stdin, %m"); 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 12457c478bd9Sstevel@tonic-gate fatal(2, "Can't set file mode flags on stdin: %m"); 1246*b2cf5195SToomas Soome 12477c478bd9Sstevel@tonic-gate return (-1); 12487c478bd9Sstevel@tonic-gate } 12497c478bd9Sstevel@tonic-gate } 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate int write_char (c) 12527c478bd9Sstevel@tonic-gate int c; 12537c478bd9Sstevel@tonic-gate { 12547c478bd9Sstevel@tonic-gate if (alarmed || put_char(c) < 0) { 12557c478bd9Sstevel@tonic-gate alarm(0); 12567c478bd9Sstevel@tonic-gate alarmed = 0; 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate if (verbose) { 12597c478bd9Sstevel@tonic-gate if (errno == EINTR || errno == EWOULDBLOCK) 12607c478bd9Sstevel@tonic-gate logf(" -- write timed out"); 12617c478bd9Sstevel@tonic-gate else 12627c478bd9Sstevel@tonic-gate logf(" -- write failed: %m"); 12637c478bd9Sstevel@tonic-gate } 12647c478bd9Sstevel@tonic-gate return (0); 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate return (1); 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate int put_string (s) 12707c478bd9Sstevel@tonic-gate register char *s; 12717c478bd9Sstevel@tonic-gate { 12727c478bd9Sstevel@tonic-gate quiet = 0; 12737c478bd9Sstevel@tonic-gate s = clean(s, 1); 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate if (verbose) { 12767c478bd9Sstevel@tonic-gate if (quiet) 12777c478bd9Sstevel@tonic-gate logf("send (??????)"); 12787c478bd9Sstevel@tonic-gate else 12797c478bd9Sstevel@tonic-gate logf("send (%v)", s); 12807c478bd9Sstevel@tonic-gate } 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate alarm(timeout); alarmed = 0; 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate while (*s) { 12857c478bd9Sstevel@tonic-gate register char c = *s++; 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate if (c != '\\') { 12887c478bd9Sstevel@tonic-gate if (!write_char (c)) 12897c478bd9Sstevel@tonic-gate return 0; 12907c478bd9Sstevel@tonic-gate continue; 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate c = *s++; 12947c478bd9Sstevel@tonic-gate switch (c) { 12957c478bd9Sstevel@tonic-gate case 'd': 12967c478bd9Sstevel@tonic-gate sleep(1); 12977c478bd9Sstevel@tonic-gate break; 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate case 'K': 13007c478bd9Sstevel@tonic-gate break_sequence(); 13017c478bd9Sstevel@tonic-gate break; 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate case 'p': 13047c478bd9Sstevel@tonic-gate usleep(10000); /* 1/100th of a second (arg is microseconds) */ 13057c478bd9Sstevel@tonic-gate break; 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate default: 13087c478bd9Sstevel@tonic-gate if (!write_char (c)) 13097c478bd9Sstevel@tonic-gate return 0; 13107c478bd9Sstevel@tonic-gate break; 13117c478bd9Sstevel@tonic-gate } 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate alarm(0); 13157c478bd9Sstevel@tonic-gate alarmed = 0; 13167c478bd9Sstevel@tonic-gate return (1); 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate /* 13207c478bd9Sstevel@tonic-gate * Echo a character to stderr. 13217c478bd9Sstevel@tonic-gate * When called with -1, a '\n' character is generated when 13227c478bd9Sstevel@tonic-gate * the cursor is not at the beginning of a line. 13237c478bd9Sstevel@tonic-gate */ 13247c478bd9Sstevel@tonic-gate void echo_stderr(n) 13257c478bd9Sstevel@tonic-gate int n; 13267c478bd9Sstevel@tonic-gate { 13277c478bd9Sstevel@tonic-gate static int need_lf; 13287c478bd9Sstevel@tonic-gate char *s; 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate switch (n) { 13317c478bd9Sstevel@tonic-gate case '\r': /* ignore '\r' */ 13327c478bd9Sstevel@tonic-gate break; 13337c478bd9Sstevel@tonic-gate case -1: 13347c478bd9Sstevel@tonic-gate if (need_lf == 0) 13357c478bd9Sstevel@tonic-gate break; 13367c478bd9Sstevel@tonic-gate /* fall through */ 13377c478bd9Sstevel@tonic-gate case '\n': 13387c478bd9Sstevel@tonic-gate write(2, "\n", 1); 13397c478bd9Sstevel@tonic-gate need_lf = 0; 13407c478bd9Sstevel@tonic-gate break; 13417c478bd9Sstevel@tonic-gate default: 13427c478bd9Sstevel@tonic-gate s = character(n); 13437c478bd9Sstevel@tonic-gate write(2, s, strlen(s)); 13447c478bd9Sstevel@tonic-gate need_lf = 1; 13457c478bd9Sstevel@tonic-gate break; 13467c478bd9Sstevel@tonic-gate } 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate /* 13507c478bd9Sstevel@tonic-gate * 'Wait for' this string to appear on this file descriptor. 13517c478bd9Sstevel@tonic-gate */ 13527c478bd9Sstevel@tonic-gate int get_string(string) 13537c478bd9Sstevel@tonic-gate register char *string; 13547c478bd9Sstevel@tonic-gate { 13557c478bd9Sstevel@tonic-gate char temp[STR_LEN]; 13567c478bd9Sstevel@tonic-gate int c, printed = 0, len, minlen; 13577c478bd9Sstevel@tonic-gate register char *s = temp, *end = s + STR_LEN; 13587c478bd9Sstevel@tonic-gate char *logged = temp; 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate fail_reason = (char *)0; 13617c478bd9Sstevel@tonic-gate string = clean(string, 0); 13627c478bd9Sstevel@tonic-gate len = strlen(string); 13637c478bd9Sstevel@tonic-gate minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate if (verbose) 13667c478bd9Sstevel@tonic-gate logf("expect (%v)", string); 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate if (len > STR_LEN) { 13697c478bd9Sstevel@tonic-gate logf("expect string is too long"); 13707c478bd9Sstevel@tonic-gate exit_code = 1; 13717c478bd9Sstevel@tonic-gate return 0; 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate if (len == 0) { 13757c478bd9Sstevel@tonic-gate if (verbose) 13767c478bd9Sstevel@tonic-gate logf("got it"); 13777c478bd9Sstevel@tonic-gate return (1); 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate alarm(timeout); 13817c478bd9Sstevel@tonic-gate alarmed = 0; 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate while ( ! alarmed && (c = get_char()) >= 0) { 13847c478bd9Sstevel@tonic-gate int n, abort_len, report_len; 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate if (echo) 13877c478bd9Sstevel@tonic-gate echo_stderr(c); 13887c478bd9Sstevel@tonic-gate if (verbose && c == '\n') { 13897c478bd9Sstevel@tonic-gate if (s == logged) 13907c478bd9Sstevel@tonic-gate logf(""); /* blank line */ 13917c478bd9Sstevel@tonic-gate else 13927c478bd9Sstevel@tonic-gate logf("%0.*v", s - logged, logged); 13937c478bd9Sstevel@tonic-gate logged = s + 1; 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate *s++ = c; 13977c478bd9Sstevel@tonic-gate 13987c478bd9Sstevel@tonic-gate if (verbose && s >= logged + 80) { 13997c478bd9Sstevel@tonic-gate logf("%0.*v", s - logged, logged); 14007c478bd9Sstevel@tonic-gate logged = s; 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate if (Verbose) { 14047c478bd9Sstevel@tonic-gate if (c == '\n') 14057c478bd9Sstevel@tonic-gate fputc( '\n', stderr ); 14067c478bd9Sstevel@tonic-gate else if (c != '\r') 14077c478bd9Sstevel@tonic-gate fprintf( stderr, "%s", character(c) ); 14087c478bd9Sstevel@tonic-gate } 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate if (!report_gathering) { 14117c478bd9Sstevel@tonic-gate for (n = 0; n < n_reports; ++n) { 14127c478bd9Sstevel@tonic-gate if ((report_string[n] != (char*) NULL) && 14137c478bd9Sstevel@tonic-gate s - temp >= (report_len = strlen(report_string[n])) && 14147c478bd9Sstevel@tonic-gate strncmp(s - report_len, report_string[n], report_len) == 0) { 14157c478bd9Sstevel@tonic-gate time_t time_now = time ((time_t*) NULL); 14167c478bd9Sstevel@tonic-gate struct tm* tm_now = localtime (&time_now); 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 14197c478bd9Sstevel@tonic-gate strcat (report_buffer, report_string[n]); 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate report_string[n] = (char *) NULL; 14227c478bd9Sstevel@tonic-gate report_gathering = 1; 14237c478bd9Sstevel@tonic-gate break; 14247c478bd9Sstevel@tonic-gate } 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate } 14277c478bd9Sstevel@tonic-gate else { 14287c478bd9Sstevel@tonic-gate if (!iscntrl (c)) { 14297c478bd9Sstevel@tonic-gate int rep_len = strlen (report_buffer); 14307c478bd9Sstevel@tonic-gate report_buffer[rep_len] = c; 14317c478bd9Sstevel@tonic-gate report_buffer[rep_len + 1] = '\0'; 14327c478bd9Sstevel@tonic-gate } 14337c478bd9Sstevel@tonic-gate else { 14347c478bd9Sstevel@tonic-gate report_gathering = 0; 14357c478bd9Sstevel@tonic-gate fprintf (report_fp, "chat: %s\n", report_buffer); 14367c478bd9Sstevel@tonic-gate } 14377c478bd9Sstevel@tonic-gate } 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate if (s - temp >= len && 14407c478bd9Sstevel@tonic-gate c == string[len - 1] && 14417c478bd9Sstevel@tonic-gate strncmp(s - len, string, len) == 0) { 14427c478bd9Sstevel@tonic-gate if (verbose) { 14437c478bd9Sstevel@tonic-gate if (s > logged) 14447c478bd9Sstevel@tonic-gate logf("%0.*v", s - logged, logged); 14457c478bd9Sstevel@tonic-gate logf(" -- got it\n"); 14467c478bd9Sstevel@tonic-gate } 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate alarm(0); 14497c478bd9Sstevel@tonic-gate alarmed = 0; 14507c478bd9Sstevel@tonic-gate return (1); 14517c478bd9Sstevel@tonic-gate } 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate for (n = 0; n < n_aborts; ++n) { 14547c478bd9Sstevel@tonic-gate if (s - temp >= (abort_len = strlen(abort_string[n])) && 14557c478bd9Sstevel@tonic-gate strncmp(s - abort_len, abort_string[n], abort_len) == 0) { 14567c478bd9Sstevel@tonic-gate if (verbose) { 14577c478bd9Sstevel@tonic-gate if (s > logged) 14587c478bd9Sstevel@tonic-gate logf("%0.*v", s - logged, logged); 14597c478bd9Sstevel@tonic-gate logf(" -- failed"); 14607c478bd9Sstevel@tonic-gate } 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate alarm(0); 14637c478bd9Sstevel@tonic-gate alarmed = 0; 14647c478bd9Sstevel@tonic-gate exit_code = n + 4; 14657c478bd9Sstevel@tonic-gate strcpy(fail_reason = fail_buffer, abort_string[n]); 14667c478bd9Sstevel@tonic-gate return (0); 14677c478bd9Sstevel@tonic-gate } 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate if (s >= end) { 14717c478bd9Sstevel@tonic-gate if (logged < s - minlen) { 14727c478bd9Sstevel@tonic-gate if (verbose) 14737c478bd9Sstevel@tonic-gate logf("%0.*v", s - logged, logged); 14747c478bd9Sstevel@tonic-gate logged = s; 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate s -= minlen; 14777c478bd9Sstevel@tonic-gate memmove(temp, s, minlen); 14787c478bd9Sstevel@tonic-gate logged = temp + (logged - s); 14797c478bd9Sstevel@tonic-gate s = temp + minlen; 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate if (alarmed && verbose) 14837c478bd9Sstevel@tonic-gate logf("warning: alarm synchronization problem"); 14847c478bd9Sstevel@tonic-gate } 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate alarm(0); 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate if (verbose && printed) { 14897c478bd9Sstevel@tonic-gate if (alarmed) 14907c478bd9Sstevel@tonic-gate logf(" -- read timed out"); 14917c478bd9Sstevel@tonic-gate else 14927c478bd9Sstevel@tonic-gate logf(" -- read failed: %m"); 14937c478bd9Sstevel@tonic-gate } 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate exit_code = 3; 14967c478bd9Sstevel@tonic-gate alarmed = 0; 14977c478bd9Sstevel@tonic-gate return (0); 14987c478bd9Sstevel@tonic-gate } 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate /* 15017c478bd9Sstevel@tonic-gate * Gross kludge to handle Solaris versions >= 2.6 having usleep. 15027c478bd9Sstevel@tonic-gate */ 15037c478bd9Sstevel@tonic-gate #ifdef SOL2 15047c478bd9Sstevel@tonic-gate #include <sys/param.h> 15057c478bd9Sstevel@tonic-gate #if MAXUID > 65536 /* then this is Solaris 2.6 or later */ 15067c478bd9Sstevel@tonic-gate #undef NO_USLEEP 15077c478bd9Sstevel@tonic-gate #endif 15087c478bd9Sstevel@tonic-gate #endif /* SOL2 */ 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate #ifdef NO_USLEEP 15117c478bd9Sstevel@tonic-gate #include <sys/types.h> 15127c478bd9Sstevel@tonic-gate #include <sys/time.h> 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate /* 15157c478bd9Sstevel@tonic-gate usleep -- support routine for 4.2BSD system call emulations 15167c478bd9Sstevel@tonic-gate last edit: 29-Oct-1984 D A Gwyn 15177c478bd9Sstevel@tonic-gate */ 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate extern int select(); 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate int 15227c478bd9Sstevel@tonic-gate usleep( usec ) /* returns 0 if ok, else -1 */ 15237c478bd9Sstevel@tonic-gate long usec; /* delay in microseconds */ 15247c478bd9Sstevel@tonic-gate { 15257c478bd9Sstevel@tonic-gate static struct { /* `timeval' */ 15267c478bd9Sstevel@tonic-gate long tv_sec; /* seconds */ 15277c478bd9Sstevel@tonic-gate long tv_usec; /* microsecs */ 15287c478bd9Sstevel@tonic-gate } delay; /* _select() timeout */ 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate delay.tv_sec = usec / 1000000L; 15317c478bd9Sstevel@tonic-gate delay.tv_usec = usec % 1000000L; 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate return select(0, (long *)0, (long *)0, (long *)0, &delay); 15347c478bd9Sstevel@tonic-gate } 15357c478bd9Sstevel@tonic-gate #endif 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate void 15387c478bd9Sstevel@tonic-gate pack_array (array, end) 15397c478bd9Sstevel@tonic-gate char **array; /* The address of the array of string pointers */ 15407c478bd9Sstevel@tonic-gate int end; /* The index of the next free entry before CLR_ */ 15417c478bd9Sstevel@tonic-gate { 15427c478bd9Sstevel@tonic-gate int i, j; 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate for (i = 0; i < end; i++) { 15457c478bd9Sstevel@tonic-gate if (array[i] == NULL) { 15467c478bd9Sstevel@tonic-gate for (j = i+1; j < end; ++j) 15477c478bd9Sstevel@tonic-gate if (array[j] != NULL) 15487c478bd9Sstevel@tonic-gate array[i++] = array[j]; 15497c478bd9Sstevel@tonic-gate for (; i < end; ++i) 15507c478bd9Sstevel@tonic-gate array[i] = NULL; 15517c478bd9Sstevel@tonic-gate break; 15527c478bd9Sstevel@tonic-gate } 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate /* 15577c478bd9Sstevel@tonic-gate * vfmtmsg - format a message into a buffer. Like vsprintf except we 15587c478bd9Sstevel@tonic-gate * also specify the length of the output buffer, and we handle the 15597c478bd9Sstevel@tonic-gate * %m (error message) format. 15607c478bd9Sstevel@tonic-gate * Doesn't do floating-point formats. 15617c478bd9Sstevel@tonic-gate * Returns the number of chars put into buf. 15627c478bd9Sstevel@tonic-gate */ 15637c478bd9Sstevel@tonic-gate #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate int 15667c478bd9Sstevel@tonic-gate vfmtmsg(buf, buflen, fmt, args) 15677c478bd9Sstevel@tonic-gate char *buf; 15687c478bd9Sstevel@tonic-gate int buflen; 15697c478bd9Sstevel@tonic-gate const char *fmt; 15707c478bd9Sstevel@tonic-gate va_list args; 15717c478bd9Sstevel@tonic-gate { 15727c478bd9Sstevel@tonic-gate int c, i, n; 15737c478bd9Sstevel@tonic-gate int width, prec, fillch; 15747c478bd9Sstevel@tonic-gate int base, len, neg, quoted; 15757c478bd9Sstevel@tonic-gate unsigned long val = 0; 15767c478bd9Sstevel@tonic-gate char *str, *buf0; 15777c478bd9Sstevel@tonic-gate const char *f; 15787c478bd9Sstevel@tonic-gate unsigned char *p; 15797c478bd9Sstevel@tonic-gate char num[32]; 15807c478bd9Sstevel@tonic-gate static char hexchars[] = "0123456789abcdef"; 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate buf0 = buf; 15837c478bd9Sstevel@tonic-gate --buflen; 15847c478bd9Sstevel@tonic-gate while (buflen > 0) { 15857c478bd9Sstevel@tonic-gate for (f = fmt; *f != '%' && *f != 0; ++f) 15867c478bd9Sstevel@tonic-gate ; 15877c478bd9Sstevel@tonic-gate if (f > fmt) { 15887c478bd9Sstevel@tonic-gate len = f - fmt; 15897c478bd9Sstevel@tonic-gate if (len > buflen) 15907c478bd9Sstevel@tonic-gate len = buflen; 15917c478bd9Sstevel@tonic-gate memcpy(buf, fmt, len); 15927c478bd9Sstevel@tonic-gate buf += len; 15937c478bd9Sstevel@tonic-gate buflen -= len; 15947c478bd9Sstevel@tonic-gate fmt = f; 15957c478bd9Sstevel@tonic-gate } 15967c478bd9Sstevel@tonic-gate if (*fmt == 0) 15977c478bd9Sstevel@tonic-gate break; 15987c478bd9Sstevel@tonic-gate c = *++fmt; 15997c478bd9Sstevel@tonic-gate width = prec = 0; 16007c478bd9Sstevel@tonic-gate fillch = ' '; 16017c478bd9Sstevel@tonic-gate if (c == '0') { 16027c478bd9Sstevel@tonic-gate fillch = '0'; 16037c478bd9Sstevel@tonic-gate c = *++fmt; 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate if (c == '*') { 16067c478bd9Sstevel@tonic-gate width = va_arg(args, int); 16077c478bd9Sstevel@tonic-gate c = *++fmt; 16087c478bd9Sstevel@tonic-gate } else { 16097c478bd9Sstevel@tonic-gate while (isdigit(c)) { 16107c478bd9Sstevel@tonic-gate width = width * 10 + c - '0'; 16117c478bd9Sstevel@tonic-gate c = *++fmt; 16127c478bd9Sstevel@tonic-gate } 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate if (c == '.') { 16157c478bd9Sstevel@tonic-gate c = *++fmt; 16167c478bd9Sstevel@tonic-gate if (c == '*') { 16177c478bd9Sstevel@tonic-gate prec = va_arg(args, int); 16187c478bd9Sstevel@tonic-gate c = *++fmt; 16197c478bd9Sstevel@tonic-gate } else { 16207c478bd9Sstevel@tonic-gate while (isdigit(c)) { 16217c478bd9Sstevel@tonic-gate prec = prec * 10 + c - '0'; 16227c478bd9Sstevel@tonic-gate c = *++fmt; 16237c478bd9Sstevel@tonic-gate } 16247c478bd9Sstevel@tonic-gate } 16257c478bd9Sstevel@tonic-gate } 16267c478bd9Sstevel@tonic-gate str = 0; 16277c478bd9Sstevel@tonic-gate base = 0; 16287c478bd9Sstevel@tonic-gate neg = 0; 16297c478bd9Sstevel@tonic-gate ++fmt; 16307c478bd9Sstevel@tonic-gate switch (c) { 16317c478bd9Sstevel@tonic-gate case 'd': 16327c478bd9Sstevel@tonic-gate i = va_arg(args, int); 16337c478bd9Sstevel@tonic-gate if (i < 0) { 16347c478bd9Sstevel@tonic-gate neg = 1; 16357c478bd9Sstevel@tonic-gate val = -i; 16367c478bd9Sstevel@tonic-gate } else 16377c478bd9Sstevel@tonic-gate val = i; 16387c478bd9Sstevel@tonic-gate base = 10; 16397c478bd9Sstevel@tonic-gate break; 16407c478bd9Sstevel@tonic-gate case 'o': 16417c478bd9Sstevel@tonic-gate val = va_arg(args, unsigned int); 16427c478bd9Sstevel@tonic-gate base = 8; 16437c478bd9Sstevel@tonic-gate break; 16447c478bd9Sstevel@tonic-gate case 'x': 16457c478bd9Sstevel@tonic-gate val = va_arg(args, unsigned int); 16467c478bd9Sstevel@tonic-gate base = 16; 16477c478bd9Sstevel@tonic-gate break; 16487c478bd9Sstevel@tonic-gate case 'p': 16497c478bd9Sstevel@tonic-gate val = (unsigned long) va_arg(args, void *); 16507c478bd9Sstevel@tonic-gate base = 16; 16517c478bd9Sstevel@tonic-gate neg = 2; 16527c478bd9Sstevel@tonic-gate break; 16537c478bd9Sstevel@tonic-gate case 's': 16547c478bd9Sstevel@tonic-gate str = va_arg(args, char *); 16557c478bd9Sstevel@tonic-gate break; 16567c478bd9Sstevel@tonic-gate case 'c': 16577c478bd9Sstevel@tonic-gate num[0] = va_arg(args, int); 16587c478bd9Sstevel@tonic-gate num[1] = 0; 16597c478bd9Sstevel@tonic-gate str = num; 16607c478bd9Sstevel@tonic-gate break; 16617c478bd9Sstevel@tonic-gate case 'm': 16627c478bd9Sstevel@tonic-gate str = strerror(errno); 16637c478bd9Sstevel@tonic-gate break; 16647c478bd9Sstevel@tonic-gate case 'v': /* "visible" string */ 16657c478bd9Sstevel@tonic-gate case 'q': /* quoted string */ 16667c478bd9Sstevel@tonic-gate quoted = c == 'q'; 16677c478bd9Sstevel@tonic-gate p = va_arg(args, unsigned char *); 16687c478bd9Sstevel@tonic-gate if (fillch == '0' && prec > 0) { 16697c478bd9Sstevel@tonic-gate n = prec; 16707c478bd9Sstevel@tonic-gate } else { 16717c478bd9Sstevel@tonic-gate n = strlen((char *)p); 16727c478bd9Sstevel@tonic-gate if (prec > 0 && prec < n) 16737c478bd9Sstevel@tonic-gate n = prec; 16747c478bd9Sstevel@tonic-gate } 16757c478bd9Sstevel@tonic-gate while (n > 0 && buflen > 0) { 16767c478bd9Sstevel@tonic-gate c = *p++; 16777c478bd9Sstevel@tonic-gate --n; 16787c478bd9Sstevel@tonic-gate if (!quoted && c >= 0x80) { 16797c478bd9Sstevel@tonic-gate OUTCHAR('M'); 16807c478bd9Sstevel@tonic-gate OUTCHAR('-'); 16817c478bd9Sstevel@tonic-gate c -= 0x80; 16827c478bd9Sstevel@tonic-gate } 16837c478bd9Sstevel@tonic-gate if (quoted && (c == '"' || c == '\\')) 16847c478bd9Sstevel@tonic-gate OUTCHAR('\\'); 16857c478bd9Sstevel@tonic-gate if (c < 0x20 || (0x7f <= c && c < 0xa0)) { 16867c478bd9Sstevel@tonic-gate if (quoted) { 16877c478bd9Sstevel@tonic-gate OUTCHAR('\\'); 16887c478bd9Sstevel@tonic-gate switch (c) { 16897c478bd9Sstevel@tonic-gate case '\t': OUTCHAR('t'); break; 16907c478bd9Sstevel@tonic-gate case '\n': OUTCHAR('n'); break; 16917c478bd9Sstevel@tonic-gate case '\b': OUTCHAR('b'); break; 16927c478bd9Sstevel@tonic-gate case '\f': OUTCHAR('f'); break; 16937c478bd9Sstevel@tonic-gate default: 16947c478bd9Sstevel@tonic-gate OUTCHAR('x'); 16957c478bd9Sstevel@tonic-gate OUTCHAR(hexchars[c >> 4]); 16967c478bd9Sstevel@tonic-gate OUTCHAR(hexchars[c & 0xf]); 16977c478bd9Sstevel@tonic-gate } 16987c478bd9Sstevel@tonic-gate } else { 16997c478bd9Sstevel@tonic-gate if (c == '\t') 17007c478bd9Sstevel@tonic-gate OUTCHAR(c); 17017c478bd9Sstevel@tonic-gate else { 17027c478bd9Sstevel@tonic-gate OUTCHAR('^'); 17037c478bd9Sstevel@tonic-gate OUTCHAR(c ^ 0x40); 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate } 17067c478bd9Sstevel@tonic-gate } else 17077c478bd9Sstevel@tonic-gate OUTCHAR(c); 17087c478bd9Sstevel@tonic-gate } 17097c478bd9Sstevel@tonic-gate continue; 17107c478bd9Sstevel@tonic-gate default: 17117c478bd9Sstevel@tonic-gate *buf++ = '%'; 17127c478bd9Sstevel@tonic-gate if (c != '%') 17137c478bd9Sstevel@tonic-gate --fmt; /* so %z outputs %z etc. */ 17147c478bd9Sstevel@tonic-gate --buflen; 17157c478bd9Sstevel@tonic-gate continue; 17167c478bd9Sstevel@tonic-gate } 17177c478bd9Sstevel@tonic-gate if (base != 0) { 17187c478bd9Sstevel@tonic-gate str = num + sizeof(num); 17197c478bd9Sstevel@tonic-gate *--str = 0; 17207c478bd9Sstevel@tonic-gate while (str > num + neg) { 17217c478bd9Sstevel@tonic-gate *--str = hexchars[val % base]; 17227c478bd9Sstevel@tonic-gate val = val / base; 17237c478bd9Sstevel@tonic-gate if (--prec <= 0 && val == 0) 17247c478bd9Sstevel@tonic-gate break; 17257c478bd9Sstevel@tonic-gate } 17267c478bd9Sstevel@tonic-gate switch (neg) { 17277c478bd9Sstevel@tonic-gate case 1: 17287c478bd9Sstevel@tonic-gate *--str = '-'; 17297c478bd9Sstevel@tonic-gate break; 17307c478bd9Sstevel@tonic-gate case 2: 17317c478bd9Sstevel@tonic-gate *--str = 'x'; 17327c478bd9Sstevel@tonic-gate *--str = '0'; 17337c478bd9Sstevel@tonic-gate break; 17347c478bd9Sstevel@tonic-gate } 17357c478bd9Sstevel@tonic-gate len = num + sizeof(num) - 1 - str; 17367c478bd9Sstevel@tonic-gate } else { 17377c478bd9Sstevel@tonic-gate len = strlen(str); 17387c478bd9Sstevel@tonic-gate if (prec > 0 && len > prec) 17397c478bd9Sstevel@tonic-gate len = prec; 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate if (width > 0) { 17427c478bd9Sstevel@tonic-gate if (width > buflen) 17437c478bd9Sstevel@tonic-gate width = buflen; 17447c478bd9Sstevel@tonic-gate if ((n = width - len) > 0) { 17457c478bd9Sstevel@tonic-gate buflen -= n; 17467c478bd9Sstevel@tonic-gate for (; n > 0; --n) 17477c478bd9Sstevel@tonic-gate *buf++ = fillch; 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate } 17507c478bd9Sstevel@tonic-gate if (len > buflen) 17517c478bd9Sstevel@tonic-gate len = buflen; 17527c478bd9Sstevel@tonic-gate memcpy(buf, str, len); 17537c478bd9Sstevel@tonic-gate buf += len; 17547c478bd9Sstevel@tonic-gate buflen -= len; 17557c478bd9Sstevel@tonic-gate } 17567c478bd9Sstevel@tonic-gate *buf = 0; 17577c478bd9Sstevel@tonic-gate return buf - buf0; 17587c478bd9Sstevel@tonic-gate } 1759