1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2000 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate /* 6*7c478bd9Sstevel@tonic-gate * Chat -- a program for automatic session establishment (i.e. dial 7*7c478bd9Sstevel@tonic-gate * the phone and log in). 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * Standard termination codes: 10*7c478bd9Sstevel@tonic-gate * 0 - successful completion of the script 11*7c478bd9Sstevel@tonic-gate * 1 - invalid argument, expect string too large, etc. 12*7c478bd9Sstevel@tonic-gate * 2 - error on an I/O operation or fatal error condition. 13*7c478bd9Sstevel@tonic-gate * 3 - timeout waiting for a simple string. 14*7c478bd9Sstevel@tonic-gate * 4 - the first string declared as "ABORT" 15*7c478bd9Sstevel@tonic-gate * 5 - the second string declared as "ABORT" 16*7c478bd9Sstevel@tonic-gate * 6 - ... and so on for successive ABORT strings. 17*7c478bd9Sstevel@tonic-gate * 18*7c478bd9Sstevel@tonic-gate * This software is in the public domain. 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * ----------------- 21*7c478bd9Sstevel@tonic-gate * 22-May-99 added environment substitutuion, enabled with -E switch. 22*7c478bd9Sstevel@tonic-gate * Andreas Arens <andras@cityweb.de>. 23*7c478bd9Sstevel@tonic-gate * 24*7c478bd9Sstevel@tonic-gate * 12-May-99 added a feature to read data to be sent from a file, 25*7c478bd9Sstevel@tonic-gate * if the send string starts with @. Idea from gpk <gpk@onramp.net>. 26*7c478bd9Sstevel@tonic-gate * 27*7c478bd9Sstevel@tonic-gate * added -T and -U option and \T and \U substitution to pass a phone 28*7c478bd9Sstevel@tonic-gate * number into chat script. Two are needed for some ISDN TA applications. 29*7c478bd9Sstevel@tonic-gate * Keith Dart <kdart@cisco.com> 30*7c478bd9Sstevel@tonic-gate * 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * Added SAY keyword to send output to stderr. 33*7c478bd9Sstevel@tonic-gate * This allows to turn ECHO OFF and to output specific, user selected, 34*7c478bd9Sstevel@tonic-gate * text to give progress messages. This best works when stderr 35*7c478bd9Sstevel@tonic-gate * exists (i.e.: pppd in nodetach mode). 36*7c478bd9Sstevel@tonic-gate * 37*7c478bd9Sstevel@tonic-gate * Added HANGUP directives to allow for us to be called 38*7c478bd9Sstevel@tonic-gate * back. When HANGUP is set to NO, chat will not hangup at HUP signal. 39*7c478bd9Sstevel@tonic-gate * We rely on timeouts in that case. 40*7c478bd9Sstevel@tonic-gate * 41*7c478bd9Sstevel@tonic-gate * Added CLR_ABORT to clear previously set ABORT string. This has been 42*7c478bd9Sstevel@tonic-gate * dictated by the HANGUP above as "NO CARRIER" (for example) must be 43*7c478bd9Sstevel@tonic-gate * an ABORT condition until we know the other host is going to close 44*7c478bd9Sstevel@tonic-gate * the connection for call back. As soon as we have completed the 45*7c478bd9Sstevel@tonic-gate * first stage of the call back sequence, "NO CARRIER" is a valid, non 46*7c478bd9Sstevel@tonic-gate * fatal string. As soon as we got called back (probably get "CONNECT"), 47*7c478bd9Sstevel@tonic-gate * we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command. 48*7c478bd9Sstevel@tonic-gate * Note that CLR_ABORT packs the abort_strings[] array so that we do not 49*7c478bd9Sstevel@tonic-gate * have unused entries not being reclaimed. 50*7c478bd9Sstevel@tonic-gate * 51*7c478bd9Sstevel@tonic-gate * In the same vein as above, added CLR_REPORT keyword. 52*7c478bd9Sstevel@tonic-gate * 53*7c478bd9Sstevel@tonic-gate * Allow for comments. Line starting with '#' are comments and are 54*7c478bd9Sstevel@tonic-gate * ignored. If a '#' is to be expected as the first character, the 55*7c478bd9Sstevel@tonic-gate * expect string must be quoted. 56*7c478bd9Sstevel@tonic-gate * 57*7c478bd9Sstevel@tonic-gate * 58*7c478bd9Sstevel@tonic-gate * Francis Demierre <Francis@SwissMail.Com> 59*7c478bd9Sstevel@tonic-gate * Thu May 15 17:15:40 MET DST 1997 60*7c478bd9Sstevel@tonic-gate * 61*7c478bd9Sstevel@tonic-gate * 62*7c478bd9Sstevel@tonic-gate * Added -r "report file" switch & REPORT keyword. 63*7c478bd9Sstevel@tonic-gate * Robert Geer <bgeer@xmission.com> 64*7c478bd9Sstevel@tonic-gate * 65*7c478bd9Sstevel@tonic-gate * Added -s "use stderr" and -S "don't use syslog" switches. 66*7c478bd9Sstevel@tonic-gate * June 18, 1997 67*7c478bd9Sstevel@tonic-gate * Karl O. Pinc <kop@meme.com> 68*7c478bd9Sstevel@tonic-gate * 69*7c478bd9Sstevel@tonic-gate * 70*7c478bd9Sstevel@tonic-gate * Added -e "echo" switch & ECHO keyword 71*7c478bd9Sstevel@tonic-gate * Dick Streefland <dicks@tasking.nl> 72*7c478bd9Sstevel@tonic-gate * 73*7c478bd9Sstevel@tonic-gate * 74*7c478bd9Sstevel@tonic-gate * Considerable updates and modifications by 75*7c478bd9Sstevel@tonic-gate * Al Longyear <longyear@pobox.com> 76*7c478bd9Sstevel@tonic-gate * Paul Mackerras <paulus@cs.anu.edu.au> 77*7c478bd9Sstevel@tonic-gate * 78*7c478bd9Sstevel@tonic-gate * 79*7c478bd9Sstevel@tonic-gate * The original author is: 80*7c478bd9Sstevel@tonic-gate * 81*7c478bd9Sstevel@tonic-gate * Karl Fox <karl@MorningStar.Com> 82*7c478bd9Sstevel@tonic-gate * Morning Star Technologies, Inc. 83*7c478bd9Sstevel@tonic-gate * 1760 Zollinger Road 84*7c478bd9Sstevel@tonic-gate * Columbus, OH 43221 85*7c478bd9Sstevel@tonic-gate * (614)451-1883 86*7c478bd9Sstevel@tonic-gate * 87*7c478bd9Sstevel@tonic-gate */ 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate #ifndef __STDC__ 90*7c478bd9Sstevel@tonic-gate #define const 91*7c478bd9Sstevel@tonic-gate #endif 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate #ifndef lint 96*7c478bd9Sstevel@tonic-gate static const char rcsid[] = "$Id: chat.c,v 1.26 1999/12/23 01:39:54 paulus Exp $"; 97*7c478bd9Sstevel@tonic-gate #endif 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate #include <stdio.h> 100*7c478bd9Sstevel@tonic-gate #include <ctype.h> 101*7c478bd9Sstevel@tonic-gate #include <time.h> 102*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 103*7c478bd9Sstevel@tonic-gate #include <signal.h> 104*7c478bd9Sstevel@tonic-gate #include <errno.h> 105*7c478bd9Sstevel@tonic-gate #include <string.h> 106*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 107*7c478bd9Sstevel@tonic-gate #include <unistd.h> 108*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 109*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 110*7c478bd9Sstevel@tonic-gate #include <syslog.h> 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate #ifndef TERMIO 113*7c478bd9Sstevel@tonic-gate #undef TERMIOS 114*7c478bd9Sstevel@tonic-gate #define TERMIOS 115*7c478bd9Sstevel@tonic-gate #endif 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate #ifdef TERMIO 118*7c478bd9Sstevel@tonic-gate #include <termio.h> 119*7c478bd9Sstevel@tonic-gate #endif 120*7c478bd9Sstevel@tonic-gate #ifdef TERMIOS 121*7c478bd9Sstevel@tonic-gate #include <termios.h> 122*7c478bd9Sstevel@tonic-gate #endif 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate #define STR_LEN 1024 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate #ifndef SIGTYPE 127*7c478bd9Sstevel@tonic-gate #define SIGTYPE void 128*7c478bd9Sstevel@tonic-gate #endif 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate #undef __P 131*7c478bd9Sstevel@tonic-gate #undef __V 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 134*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 135*7c478bd9Sstevel@tonic-gate #define __V(x) x 136*7c478bd9Sstevel@tonic-gate #define __P(x) x 137*7c478bd9Sstevel@tonic-gate #else 138*7c478bd9Sstevel@tonic-gate #include <varargs.h> 139*7c478bd9Sstevel@tonic-gate #define __V(x) (va_alist) va_dcl 140*7c478bd9Sstevel@tonic-gate #define __P(x) () 141*7c478bd9Sstevel@tonic-gate #define const 142*7c478bd9Sstevel@tonic-gate #endif 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate #ifndef O_NONBLOCK 145*7c478bd9Sstevel@tonic-gate #define O_NONBLOCK O_NDELAY 146*7c478bd9Sstevel@tonic-gate #endif 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate #ifdef SUNOS 149*7c478bd9Sstevel@tonic-gate extern int sys_nerr; 150*7c478bd9Sstevel@tonic-gate extern char *sys_errlist[]; 151*7c478bd9Sstevel@tonic-gate #define memmove(to, from, n) bcopy(from, to, n) 152*7c478bd9Sstevel@tonic-gate #define strerror(n) ((unsigned)(n) < sys_nerr? sys_errlist[(n)] :\ 153*7c478bd9Sstevel@tonic-gate "unknown error") 154*7c478bd9Sstevel@tonic-gate #endif 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate /*************** Micro getopt() *********************************************/ 157*7c478bd9Sstevel@tonic-gate #define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ 158*7c478bd9Sstevel@tonic-gate (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ 159*7c478bd9Sstevel@tonic-gate &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0)) 160*7c478bd9Sstevel@tonic-gate #define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \ 161*7c478bd9Sstevel@tonic-gate (_O=4,(char*)0):(char*)0) 162*7c478bd9Sstevel@tonic-gate #define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0) 163*7c478bd9Sstevel@tonic-gate #define ARG(c,v) (c?(--c,*v++):(char*)0) 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate static int _O = 0; /* Internal state */ 166*7c478bd9Sstevel@tonic-gate /*************** Micro getopt() *********************************************/ 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate char *program_name; 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate #define MAX_ABORTS 50 171*7c478bd9Sstevel@tonic-gate #define MAX_REPORTS 50 172*7c478bd9Sstevel@tonic-gate #define DEFAULT_CHAT_TIMEOUT 45 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate int echo = 0; 175*7c478bd9Sstevel@tonic-gate int verbose = 0; 176*7c478bd9Sstevel@tonic-gate int to_log = 1; 177*7c478bd9Sstevel@tonic-gate int to_stderr = 0; 178*7c478bd9Sstevel@tonic-gate int Verbose = 0; 179*7c478bd9Sstevel@tonic-gate int quiet = 0; 180*7c478bd9Sstevel@tonic-gate int report = 0; 181*7c478bd9Sstevel@tonic-gate int use_env = 0; 182*7c478bd9Sstevel@tonic-gate int exit_code = 0; 183*7c478bd9Sstevel@tonic-gate FILE* report_fp = (FILE *) 0; 184*7c478bd9Sstevel@tonic-gate char *report_file = (char *) 0; 185*7c478bd9Sstevel@tonic-gate char *chat_file = (char *) 0; 186*7c478bd9Sstevel@tonic-gate char *phone_num = (char *) 0; 187*7c478bd9Sstevel@tonic-gate char *phone_num2 = (char *) 0; 188*7c478bd9Sstevel@tonic-gate int timeout = DEFAULT_CHAT_TIMEOUT; 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate int have_tty_parameters = 0; 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate #ifdef TERMIO 193*7c478bd9Sstevel@tonic-gate #define term_parms struct termio 194*7c478bd9Sstevel@tonic-gate #define get_term_param(param) ioctl(0, TCGETA, param) 195*7c478bd9Sstevel@tonic-gate #define set_term_param(param) ioctl(0, TCSETA, param) 196*7c478bd9Sstevel@tonic-gate struct termio saved_tty_parameters; 197*7c478bd9Sstevel@tonic-gate #endif 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate #ifdef TERMIOS 200*7c478bd9Sstevel@tonic-gate #define term_parms struct termios 201*7c478bd9Sstevel@tonic-gate #define get_term_param(param) tcgetattr(0, param) 202*7c478bd9Sstevel@tonic-gate #define set_term_param(param) tcsetattr(0, TCSANOW, param) 203*7c478bd9Sstevel@tonic-gate struct termios saved_tty_parameters; 204*7c478bd9Sstevel@tonic-gate #endif 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate char *abort_string[MAX_ABORTS], *fail_reason = (char *)0, 207*7c478bd9Sstevel@tonic-gate fail_buffer[50]; 208*7c478bd9Sstevel@tonic-gate int n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0; 209*7c478bd9Sstevel@tonic-gate int clear_abort_next = 0; 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate char *report_string[MAX_REPORTS] ; 212*7c478bd9Sstevel@tonic-gate char report_buffer[50] ; 213*7c478bd9Sstevel@tonic-gate int n_reports = 0, report_next = 0, report_gathering = 0 ; 214*7c478bd9Sstevel@tonic-gate int clear_report_next = 0; 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate int say_next = 0, hup_next = 0; 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate void *dup_mem __P((void *b, size_t c)); 219*7c478bd9Sstevel@tonic-gate void *copy_of __P((char *s)); 220*7c478bd9Sstevel@tonic-gate void usage __P((void)); 221*7c478bd9Sstevel@tonic-gate void logf __P((const char *fmt, ...)); 222*7c478bd9Sstevel@tonic-gate void fatal __P((int code, const char *fmt, ...)); 223*7c478bd9Sstevel@tonic-gate SIGTYPE sigalrm __P((int signo)); 224*7c478bd9Sstevel@tonic-gate SIGTYPE sigint __P((int signo)); 225*7c478bd9Sstevel@tonic-gate SIGTYPE sigterm __P((int signo)); 226*7c478bd9Sstevel@tonic-gate SIGTYPE sighup __P((int signo)); 227*7c478bd9Sstevel@tonic-gate void unalarm __P((void)); 228*7c478bd9Sstevel@tonic-gate void init __P((void)); 229*7c478bd9Sstevel@tonic-gate void set_tty_parameters __P((void)); 230*7c478bd9Sstevel@tonic-gate void echo_stderr __P((int)); 231*7c478bd9Sstevel@tonic-gate void break_sequence __P((void)); 232*7c478bd9Sstevel@tonic-gate void terminate __P((int status)); 233*7c478bd9Sstevel@tonic-gate void do_file __P((char *chat_file)); 234*7c478bd9Sstevel@tonic-gate int get_string __P((register char *string)); 235*7c478bd9Sstevel@tonic-gate int put_string __P((register char *s)); 236*7c478bd9Sstevel@tonic-gate int write_char __P((int c)); 237*7c478bd9Sstevel@tonic-gate int put_char __P((int c)); 238*7c478bd9Sstevel@tonic-gate int get_char __P((void)); 239*7c478bd9Sstevel@tonic-gate void chat_send __P((register char *s)); 240*7c478bd9Sstevel@tonic-gate char *character __P((int c)); 241*7c478bd9Sstevel@tonic-gate void chat_expect __P((register char *s)); 242*7c478bd9Sstevel@tonic-gate char *clean __P((register char *s, int sending)); 243*7c478bd9Sstevel@tonic-gate void break_sequence __P((void)); 244*7c478bd9Sstevel@tonic-gate void terminate __P((int status)); 245*7c478bd9Sstevel@tonic-gate void pack_array __P((char **array, int end)); 246*7c478bd9Sstevel@tonic-gate char *expect_strtok __P((char *, char *)); 247*7c478bd9Sstevel@tonic-gate int vfmtmsg __P((char *, int, const char *, va_list)); /* vsprintf++ */ 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate int main __P((int, char *[])); 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate void *dup_mem(b, c) 252*7c478bd9Sstevel@tonic-gate void *b; 253*7c478bd9Sstevel@tonic-gate size_t c; 254*7c478bd9Sstevel@tonic-gate { 255*7c478bd9Sstevel@tonic-gate void *ans = malloc (c); 256*7c478bd9Sstevel@tonic-gate if (!ans) 257*7c478bd9Sstevel@tonic-gate fatal(2, "memory error!"); 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate memcpy (ans, b, c); 260*7c478bd9Sstevel@tonic-gate return ans; 261*7c478bd9Sstevel@tonic-gate } 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate void *copy_of (s) 264*7c478bd9Sstevel@tonic-gate char *s; 265*7c478bd9Sstevel@tonic-gate { 266*7c478bd9Sstevel@tonic-gate return dup_mem (s, strlen (s) + 1); 267*7c478bd9Sstevel@tonic-gate } 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate /* 270*7c478bd9Sstevel@tonic-gate * chat [ -v ] [ -E ] [ -T number ] [ -U number ] [ -t timeout ] [ -f chat-file ] \ 271*7c478bd9Sstevel@tonic-gate * [ -r report-file ] \ 272*7c478bd9Sstevel@tonic-gate * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] 273*7c478bd9Sstevel@tonic-gate * 274*7c478bd9Sstevel@tonic-gate * Perform a UUCP-dialer-like chat script on stdin and stdout. 275*7c478bd9Sstevel@tonic-gate */ 276*7c478bd9Sstevel@tonic-gate int 277*7c478bd9Sstevel@tonic-gate main(argc, argv) 278*7c478bd9Sstevel@tonic-gate int argc; 279*7c478bd9Sstevel@tonic-gate char **argv; 280*7c478bd9Sstevel@tonic-gate { 281*7c478bd9Sstevel@tonic-gate int option; 282*7c478bd9Sstevel@tonic-gate char *arg; 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate program_name = *argv; 285*7c478bd9Sstevel@tonic-gate tzset(); 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate while ((option = OPTION(argc, argv)) != 0) { 288*7c478bd9Sstevel@tonic-gate switch (option) { 289*7c478bd9Sstevel@tonic-gate case 'e': 290*7c478bd9Sstevel@tonic-gate ++echo; 291*7c478bd9Sstevel@tonic-gate break; 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate case 'E': 294*7c478bd9Sstevel@tonic-gate ++use_env; 295*7c478bd9Sstevel@tonic-gate break; 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate case 'v': 298*7c478bd9Sstevel@tonic-gate ++verbose; 299*7c478bd9Sstevel@tonic-gate break; 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate case 'V': 302*7c478bd9Sstevel@tonic-gate ++Verbose; 303*7c478bd9Sstevel@tonic-gate break; 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate case 's': 306*7c478bd9Sstevel@tonic-gate ++to_stderr; 307*7c478bd9Sstevel@tonic-gate break; 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate case 'S': 310*7c478bd9Sstevel@tonic-gate to_log = 0; 311*7c478bd9Sstevel@tonic-gate break; 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate case 'f': 314*7c478bd9Sstevel@tonic-gate if ((arg = OPTARG(argc, argv)) != NULL) 315*7c478bd9Sstevel@tonic-gate chat_file = copy_of(arg); 316*7c478bd9Sstevel@tonic-gate else 317*7c478bd9Sstevel@tonic-gate usage(); 318*7c478bd9Sstevel@tonic-gate break; 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate case 't': 321*7c478bd9Sstevel@tonic-gate if ((arg = OPTARG(argc, argv)) != NULL) 322*7c478bd9Sstevel@tonic-gate timeout = atoi(arg); 323*7c478bd9Sstevel@tonic-gate else 324*7c478bd9Sstevel@tonic-gate usage(); 325*7c478bd9Sstevel@tonic-gate break; 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate case 'r': 328*7c478bd9Sstevel@tonic-gate arg = OPTARG (argc, argv); 329*7c478bd9Sstevel@tonic-gate if (arg) { 330*7c478bd9Sstevel@tonic-gate if (report_fp != NULL) 331*7c478bd9Sstevel@tonic-gate fclose (report_fp); 332*7c478bd9Sstevel@tonic-gate report_file = copy_of (arg); 333*7c478bd9Sstevel@tonic-gate report_fp = fopen (report_file, "a"); 334*7c478bd9Sstevel@tonic-gate if (report_fp != NULL) { 335*7c478bd9Sstevel@tonic-gate if (verbose) 336*7c478bd9Sstevel@tonic-gate fprintf (report_fp, "Opening \"%s\"...\n", 337*7c478bd9Sstevel@tonic-gate report_file); 338*7c478bd9Sstevel@tonic-gate report = 1; 339*7c478bd9Sstevel@tonic-gate } 340*7c478bd9Sstevel@tonic-gate } 341*7c478bd9Sstevel@tonic-gate break; 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate case 'T': 344*7c478bd9Sstevel@tonic-gate if ((arg = OPTARG(argc, argv)) != NULL) 345*7c478bd9Sstevel@tonic-gate phone_num = copy_of(arg); 346*7c478bd9Sstevel@tonic-gate else 347*7c478bd9Sstevel@tonic-gate usage(); 348*7c478bd9Sstevel@tonic-gate break; 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate case 'U': 351*7c478bd9Sstevel@tonic-gate if ((arg = OPTARG(argc, argv)) != NULL) 352*7c478bd9Sstevel@tonic-gate phone_num2 = copy_of(arg); 353*7c478bd9Sstevel@tonic-gate else 354*7c478bd9Sstevel@tonic-gate usage(); 355*7c478bd9Sstevel@tonic-gate break; 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate default: 358*7c478bd9Sstevel@tonic-gate usage(); 359*7c478bd9Sstevel@tonic-gate break; 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate } 362*7c478bd9Sstevel@tonic-gate /* 363*7c478bd9Sstevel@tonic-gate * Default the report file to the stderr location 364*7c478bd9Sstevel@tonic-gate */ 365*7c478bd9Sstevel@tonic-gate if (report_fp == NULL) 366*7c478bd9Sstevel@tonic-gate report_fp = stderr; 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate if (to_log) { 369*7c478bd9Sstevel@tonic-gate #ifdef ultrix 370*7c478bd9Sstevel@tonic-gate openlog("chat", LOG_PID); 371*7c478bd9Sstevel@tonic-gate #else 372*7c478bd9Sstevel@tonic-gate openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate if (verbose) 375*7c478bd9Sstevel@tonic-gate setlogmask(LOG_UPTO(LOG_INFO)); 376*7c478bd9Sstevel@tonic-gate else 377*7c478bd9Sstevel@tonic-gate setlogmask(LOG_UPTO(LOG_WARNING)); 378*7c478bd9Sstevel@tonic-gate #endif 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate init(); 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate if (chat_file != NULL) { 384*7c478bd9Sstevel@tonic-gate arg = ARG(argc, argv); 385*7c478bd9Sstevel@tonic-gate if (arg != NULL) 386*7c478bd9Sstevel@tonic-gate usage(); 387*7c478bd9Sstevel@tonic-gate else 388*7c478bd9Sstevel@tonic-gate do_file (chat_file); 389*7c478bd9Sstevel@tonic-gate } else { 390*7c478bd9Sstevel@tonic-gate while ((arg = ARG(argc, argv)) != NULL) { 391*7c478bd9Sstevel@tonic-gate chat_expect(arg); 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate if ((arg = ARG(argc, argv)) != NULL) 394*7c478bd9Sstevel@tonic-gate chat_send(arg); 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate } 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate terminate(0); 399*7c478bd9Sstevel@tonic-gate return 0; 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate /* 403*7c478bd9Sstevel@tonic-gate * Process a chat script when read from a file. 404*7c478bd9Sstevel@tonic-gate */ 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate void do_file (chat_file) 407*7c478bd9Sstevel@tonic-gate char *chat_file; 408*7c478bd9Sstevel@tonic-gate { 409*7c478bd9Sstevel@tonic-gate int linect, sendflg; 410*7c478bd9Sstevel@tonic-gate char *sp, *arg, quote; 411*7c478bd9Sstevel@tonic-gate char buf [STR_LEN]; 412*7c478bd9Sstevel@tonic-gate FILE *cfp; 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate cfp = fopen (chat_file, "r"); 415*7c478bd9Sstevel@tonic-gate if (cfp == NULL) 416*7c478bd9Sstevel@tonic-gate fatal(1, "%s -- open failed: %m", chat_file); 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate linect = 0; 419*7c478bd9Sstevel@tonic-gate sendflg = 0; 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate while (fgets(buf, STR_LEN, cfp) != NULL) { 422*7c478bd9Sstevel@tonic-gate sp = strchr (buf, '\n'); 423*7c478bd9Sstevel@tonic-gate if (sp) 424*7c478bd9Sstevel@tonic-gate *sp = '\0'; 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate linect++; 427*7c478bd9Sstevel@tonic-gate sp = buf; 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate /* lines starting with '#' are comments. If a real '#' 430*7c478bd9Sstevel@tonic-gate is to be expected, it should be quoted .... */ 431*7c478bd9Sstevel@tonic-gate if ( *sp == '#' ) 432*7c478bd9Sstevel@tonic-gate continue; 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate while (*sp != '\0') { 435*7c478bd9Sstevel@tonic-gate if (*sp == ' ' || *sp == '\t') { 436*7c478bd9Sstevel@tonic-gate ++sp; 437*7c478bd9Sstevel@tonic-gate continue; 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate if (*sp == '"' || *sp == '\'') { 441*7c478bd9Sstevel@tonic-gate quote = *sp++; 442*7c478bd9Sstevel@tonic-gate arg = sp; 443*7c478bd9Sstevel@tonic-gate while (*sp != quote) { 444*7c478bd9Sstevel@tonic-gate if (*sp == '\0') 445*7c478bd9Sstevel@tonic-gate fatal(1, "unterminated quote (line %d)", linect); 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate if (*sp++ == '\\') { 448*7c478bd9Sstevel@tonic-gate if (*sp != '\0') 449*7c478bd9Sstevel@tonic-gate ++sp; 450*7c478bd9Sstevel@tonic-gate } 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate } 453*7c478bd9Sstevel@tonic-gate else { 454*7c478bd9Sstevel@tonic-gate arg = sp; 455*7c478bd9Sstevel@tonic-gate while (*sp != '\0' && *sp != ' ' && *sp != '\t') 456*7c478bd9Sstevel@tonic-gate ++sp; 457*7c478bd9Sstevel@tonic-gate } 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate if (*sp != '\0') 460*7c478bd9Sstevel@tonic-gate *sp++ = '\0'; 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate if (sendflg) 463*7c478bd9Sstevel@tonic-gate chat_send (arg); 464*7c478bd9Sstevel@tonic-gate else 465*7c478bd9Sstevel@tonic-gate chat_expect (arg); 466*7c478bd9Sstevel@tonic-gate sendflg = !sendflg; 467*7c478bd9Sstevel@tonic-gate } 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate fclose (cfp); 470*7c478bd9Sstevel@tonic-gate } 471*7c478bd9Sstevel@tonic-gate 472*7c478bd9Sstevel@tonic-gate /* 473*7c478bd9Sstevel@tonic-gate * We got an error parsing the command line. 474*7c478bd9Sstevel@tonic-gate */ 475*7c478bd9Sstevel@tonic-gate void usage() 476*7c478bd9Sstevel@tonic-gate { 477*7c478bd9Sstevel@tonic-gate fprintf(stderr, "\ 478*7c478bd9Sstevel@tonic-gate Usage: %s [-e] [-E] [-v] [-V] [-t timeout] [-r report-file]\n\ 479*7c478bd9Sstevel@tonic-gate [-T phone-number] [-U phone-number2] {-f chat-file | chat-script}\n", program_name); 480*7c478bd9Sstevel@tonic-gate exit(1); 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate char line[1024]; 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate /* 486*7c478bd9Sstevel@tonic-gate * Send a message to syslog and/or stderr. 487*7c478bd9Sstevel@tonic-gate */ 488*7c478bd9Sstevel@tonic-gate void logf __V((const char *fmt, ...)) 489*7c478bd9Sstevel@tonic-gate { 490*7c478bd9Sstevel@tonic-gate va_list args; 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 493*7c478bd9Sstevel@tonic-gate va_start(args, fmt); 494*7c478bd9Sstevel@tonic-gate #else 495*7c478bd9Sstevel@tonic-gate char *fmt; 496*7c478bd9Sstevel@tonic-gate va_start(args); 497*7c478bd9Sstevel@tonic-gate fmt = va_arg(args, char *); 498*7c478bd9Sstevel@tonic-gate #endif 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate vfmtmsg(line, sizeof(line), fmt, args); 501*7c478bd9Sstevel@tonic-gate if (to_log) 502*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "%s", line); 503*7c478bd9Sstevel@tonic-gate if (to_stderr) 504*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s\n", line); 505*7c478bd9Sstevel@tonic-gate } 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate /* 508*7c478bd9Sstevel@tonic-gate * Print an error message and terminate. 509*7c478bd9Sstevel@tonic-gate */ 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate void fatal __V((int code, const char *fmt, ...)) 512*7c478bd9Sstevel@tonic-gate { 513*7c478bd9Sstevel@tonic-gate va_list args; 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 516*7c478bd9Sstevel@tonic-gate va_start(args, fmt); 517*7c478bd9Sstevel@tonic-gate #else 518*7c478bd9Sstevel@tonic-gate int code; 519*7c478bd9Sstevel@tonic-gate char *fmt; 520*7c478bd9Sstevel@tonic-gate va_start(args); 521*7c478bd9Sstevel@tonic-gate code = va_arg(args, int); 522*7c478bd9Sstevel@tonic-gate fmt = va_arg(args, char *); 523*7c478bd9Sstevel@tonic-gate #endif 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate vfmtmsg(line, sizeof(line), fmt, args); 526*7c478bd9Sstevel@tonic-gate if (to_log) 527*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s", line); 528*7c478bd9Sstevel@tonic-gate if (to_stderr) 529*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s\n", line); 530*7c478bd9Sstevel@tonic-gate terminate(code); 531*7c478bd9Sstevel@tonic-gate } 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate int alarmed = 0; 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate SIGTYPE sigalrm(signo) 536*7c478bd9Sstevel@tonic-gate int signo; 537*7c478bd9Sstevel@tonic-gate { 538*7c478bd9Sstevel@tonic-gate int flags; 539*7c478bd9Sstevel@tonic-gate 540*7c478bd9Sstevel@tonic-gate alarm(1); 541*7c478bd9Sstevel@tonic-gate alarmed = 1; /* Reset alarm to avoid race window */ 542*7c478bd9Sstevel@tonic-gate signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate if ((flags = fcntl(0, F_GETFL, 0)) == -1) 545*7c478bd9Sstevel@tonic-gate fatal(2, "Can't get file mode flags on stdin: %m"); 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) 548*7c478bd9Sstevel@tonic-gate fatal(2, "Can't set file mode flags on stdin: %m"); 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate if (verbose) 551*7c478bd9Sstevel@tonic-gate logf("alarm"); 552*7c478bd9Sstevel@tonic-gate } 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate void unalarm() 555*7c478bd9Sstevel@tonic-gate { 556*7c478bd9Sstevel@tonic-gate int flags; 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate if ((flags = fcntl(0, F_GETFL, 0)) == -1) 559*7c478bd9Sstevel@tonic-gate fatal(2, "Can't get file mode flags on stdin: %m"); 560*7c478bd9Sstevel@tonic-gate 561*7c478bd9Sstevel@tonic-gate if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1) 562*7c478bd9Sstevel@tonic-gate fatal(2, "Can't set file mode flags on stdin: %m"); 563*7c478bd9Sstevel@tonic-gate } 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate SIGTYPE sigint(signo) 566*7c478bd9Sstevel@tonic-gate int signo; 567*7c478bd9Sstevel@tonic-gate { 568*7c478bd9Sstevel@tonic-gate fatal(2, "SIGINT"); 569*7c478bd9Sstevel@tonic-gate } 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate SIGTYPE sigterm(signo) 572*7c478bd9Sstevel@tonic-gate int signo; 573*7c478bd9Sstevel@tonic-gate { 574*7c478bd9Sstevel@tonic-gate fatal(2, "SIGTERM"); 575*7c478bd9Sstevel@tonic-gate } 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate SIGTYPE sighup(signo) 578*7c478bd9Sstevel@tonic-gate int signo; 579*7c478bd9Sstevel@tonic-gate { 580*7c478bd9Sstevel@tonic-gate fatal(2, "SIGHUP"); 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate void init() 584*7c478bd9Sstevel@tonic-gate { 585*7c478bd9Sstevel@tonic-gate signal(SIGINT, sigint); 586*7c478bd9Sstevel@tonic-gate signal(SIGTERM, sigterm); 587*7c478bd9Sstevel@tonic-gate signal(SIGHUP, sighup); 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate set_tty_parameters(); 590*7c478bd9Sstevel@tonic-gate signal(SIGALRM, sigalrm); 591*7c478bd9Sstevel@tonic-gate alarm(0); 592*7c478bd9Sstevel@tonic-gate alarmed = 0; 593*7c478bd9Sstevel@tonic-gate } 594*7c478bd9Sstevel@tonic-gate 595*7c478bd9Sstevel@tonic-gate void set_tty_parameters() 596*7c478bd9Sstevel@tonic-gate { 597*7c478bd9Sstevel@tonic-gate #if defined(get_term_param) 598*7c478bd9Sstevel@tonic-gate term_parms t; 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate if (get_term_param (&t) < 0) 601*7c478bd9Sstevel@tonic-gate fatal(2, "Can't get terminal parameters: %m"); 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate saved_tty_parameters = t; 604*7c478bd9Sstevel@tonic-gate have_tty_parameters = 1; 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 607*7c478bd9Sstevel@tonic-gate t.c_oflag = 0; 608*7c478bd9Sstevel@tonic-gate t.c_lflag = 0; 609*7c478bd9Sstevel@tonic-gate t.c_cc[VERASE] = 610*7c478bd9Sstevel@tonic-gate t.c_cc[VKILL] = 0; 611*7c478bd9Sstevel@tonic-gate t.c_cc[VMIN] = 1; 612*7c478bd9Sstevel@tonic-gate t.c_cc[VTIME] = 0; 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate if (set_term_param (&t) < 0) 615*7c478bd9Sstevel@tonic-gate fatal(2, "Can't set terminal parameters: %m"); 616*7c478bd9Sstevel@tonic-gate #endif 617*7c478bd9Sstevel@tonic-gate } 618*7c478bd9Sstevel@tonic-gate 619*7c478bd9Sstevel@tonic-gate void break_sequence() 620*7c478bd9Sstevel@tonic-gate { 621*7c478bd9Sstevel@tonic-gate #ifdef TERMIOS 622*7c478bd9Sstevel@tonic-gate tcsendbreak (0, 0); 623*7c478bd9Sstevel@tonic-gate #endif 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate void terminate(status) 627*7c478bd9Sstevel@tonic-gate int status; 628*7c478bd9Sstevel@tonic-gate { 629*7c478bd9Sstevel@tonic-gate static int terminating = 0; 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate if (terminating) 632*7c478bd9Sstevel@tonic-gate exit(status); 633*7c478bd9Sstevel@tonic-gate terminating = 1; 634*7c478bd9Sstevel@tonic-gate echo_stderr(-1); 635*7c478bd9Sstevel@tonic-gate /* 636*7c478bd9Sstevel@tonic-gate * Allow the last of the report string to be gathered before we terminate. 637*7c478bd9Sstevel@tonic-gate */ 638*7c478bd9Sstevel@tonic-gate if (report_gathering) { 639*7c478bd9Sstevel@tonic-gate int c, rep_len; 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate rep_len = strlen(report_buffer); 642*7c478bd9Sstevel@tonic-gate while (rep_len + 1 <= sizeof(report_buffer)) { 643*7c478bd9Sstevel@tonic-gate alarm(1); 644*7c478bd9Sstevel@tonic-gate c = get_char(); 645*7c478bd9Sstevel@tonic-gate alarm(0); 646*7c478bd9Sstevel@tonic-gate if (c < 0 || iscntrl(c)) 647*7c478bd9Sstevel@tonic-gate break; 648*7c478bd9Sstevel@tonic-gate report_buffer[rep_len] = c; 649*7c478bd9Sstevel@tonic-gate ++rep_len; 650*7c478bd9Sstevel@tonic-gate } 651*7c478bd9Sstevel@tonic-gate report_buffer[rep_len] = 0; 652*7c478bd9Sstevel@tonic-gate fprintf (report_fp, "chat: %s\n", report_buffer); 653*7c478bd9Sstevel@tonic-gate } 654*7c478bd9Sstevel@tonic-gate if (report_file != (char *) 0 && report_fp != (FILE *) NULL) { 655*7c478bd9Sstevel@tonic-gate if (verbose) 656*7c478bd9Sstevel@tonic-gate fprintf (report_fp, "Closing \"%s\".\n", report_file); 657*7c478bd9Sstevel@tonic-gate fclose (report_fp); 658*7c478bd9Sstevel@tonic-gate report_fp = (FILE *) NULL; 659*7c478bd9Sstevel@tonic-gate } 660*7c478bd9Sstevel@tonic-gate 661*7c478bd9Sstevel@tonic-gate #if defined(get_term_param) 662*7c478bd9Sstevel@tonic-gate if (have_tty_parameters) { 663*7c478bd9Sstevel@tonic-gate if (set_term_param (&saved_tty_parameters) < 0) 664*7c478bd9Sstevel@tonic-gate fatal(2, "Can't restore terminal parameters: %m"); 665*7c478bd9Sstevel@tonic-gate } 666*7c478bd9Sstevel@tonic-gate #endif 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate exit(status); 669*7c478bd9Sstevel@tonic-gate } 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate /* 672*7c478bd9Sstevel@tonic-gate * 'Clean up' this string. 673*7c478bd9Sstevel@tonic-gate */ 674*7c478bd9Sstevel@tonic-gate char *clean(s, sending) 675*7c478bd9Sstevel@tonic-gate register char *s; 676*7c478bd9Sstevel@tonic-gate int sending; /* set to 1 when sending (putting) this string. */ 677*7c478bd9Sstevel@tonic-gate { 678*7c478bd9Sstevel@tonic-gate char temp[STR_LEN], env_str[STR_LEN], cur_chr; 679*7c478bd9Sstevel@tonic-gate register char *s1, *phchar; 680*7c478bd9Sstevel@tonic-gate int add_return = sending; 681*7c478bd9Sstevel@tonic-gate #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 682*7c478bd9Sstevel@tonic-gate #define isalnumx(chr) ((((chr) >= '0') && ((chr) <= '9')) \ 683*7c478bd9Sstevel@tonic-gate || (((chr) >= 'a') && ((chr) <= 'z')) \ 684*7c478bd9Sstevel@tonic-gate || (((chr) >= 'A') && ((chr) <= 'Z')) \ 685*7c478bd9Sstevel@tonic-gate || (chr) == '_') 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate s1 = temp; 688*7c478bd9Sstevel@tonic-gate while (*s) { 689*7c478bd9Sstevel@tonic-gate cur_chr = *s++; 690*7c478bd9Sstevel@tonic-gate if (cur_chr == '^') { 691*7c478bd9Sstevel@tonic-gate cur_chr = *s++; 692*7c478bd9Sstevel@tonic-gate if (cur_chr == '\0') { 693*7c478bd9Sstevel@tonic-gate *s1++ = '^'; 694*7c478bd9Sstevel@tonic-gate break; 695*7c478bd9Sstevel@tonic-gate } 696*7c478bd9Sstevel@tonic-gate cur_chr &= 0x1F; 697*7c478bd9Sstevel@tonic-gate if (cur_chr != 0) { 698*7c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 699*7c478bd9Sstevel@tonic-gate } 700*7c478bd9Sstevel@tonic-gate continue; 701*7c478bd9Sstevel@tonic-gate } 702*7c478bd9Sstevel@tonic-gate 703*7c478bd9Sstevel@tonic-gate if (use_env && cur_chr == '$') { /* ARI */ 704*7c478bd9Sstevel@tonic-gate phchar = env_str; 705*7c478bd9Sstevel@tonic-gate while (isalnumx(*s)) 706*7c478bd9Sstevel@tonic-gate *phchar++ = *s++; 707*7c478bd9Sstevel@tonic-gate *phchar = '\0'; 708*7c478bd9Sstevel@tonic-gate phchar = getenv(env_str); 709*7c478bd9Sstevel@tonic-gate if (phchar) 710*7c478bd9Sstevel@tonic-gate while (*phchar) 711*7c478bd9Sstevel@tonic-gate *s1++ = *phchar++; 712*7c478bd9Sstevel@tonic-gate continue; 713*7c478bd9Sstevel@tonic-gate } 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate if (cur_chr != '\\') { 716*7c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 717*7c478bd9Sstevel@tonic-gate continue; 718*7c478bd9Sstevel@tonic-gate } 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate cur_chr = *s++; 721*7c478bd9Sstevel@tonic-gate if (cur_chr == '\0') { 722*7c478bd9Sstevel@tonic-gate if (sending) { 723*7c478bd9Sstevel@tonic-gate *s1++ = '\\'; 724*7c478bd9Sstevel@tonic-gate *s1++ = '\\'; 725*7c478bd9Sstevel@tonic-gate } 726*7c478bd9Sstevel@tonic-gate break; 727*7c478bd9Sstevel@tonic-gate } 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate switch (cur_chr) { 730*7c478bd9Sstevel@tonic-gate case 'b': 731*7c478bd9Sstevel@tonic-gate *s1++ = '\b'; 732*7c478bd9Sstevel@tonic-gate break; 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate case 'c': 735*7c478bd9Sstevel@tonic-gate if (sending && *s == '\0') 736*7c478bd9Sstevel@tonic-gate add_return = 0; 737*7c478bd9Sstevel@tonic-gate else 738*7c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 739*7c478bd9Sstevel@tonic-gate break; 740*7c478bd9Sstevel@tonic-gate 741*7c478bd9Sstevel@tonic-gate case '\\': 742*7c478bd9Sstevel@tonic-gate case 'K': 743*7c478bd9Sstevel@tonic-gate case 'p': 744*7c478bd9Sstevel@tonic-gate case 'd': 745*7c478bd9Sstevel@tonic-gate if (sending) 746*7c478bd9Sstevel@tonic-gate *s1++ = '\\'; 747*7c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 748*7c478bd9Sstevel@tonic-gate break; 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate case 'T': 751*7c478bd9Sstevel@tonic-gate if (sending && phone_num) { 752*7c478bd9Sstevel@tonic-gate for (phchar = phone_num; *phchar != '\0'; phchar++) 753*7c478bd9Sstevel@tonic-gate *s1++ = *phchar; 754*7c478bd9Sstevel@tonic-gate } 755*7c478bd9Sstevel@tonic-gate else { 756*7c478bd9Sstevel@tonic-gate *s1++ = '\\'; 757*7c478bd9Sstevel@tonic-gate *s1++ = 'T'; 758*7c478bd9Sstevel@tonic-gate } 759*7c478bd9Sstevel@tonic-gate break; 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate case 'U': 762*7c478bd9Sstevel@tonic-gate if (sending && phone_num2) { 763*7c478bd9Sstevel@tonic-gate for (phchar = phone_num2; *phchar != '\0'; phchar++) 764*7c478bd9Sstevel@tonic-gate *s1++ = *phchar; 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate else { 767*7c478bd9Sstevel@tonic-gate *s1++ = '\\'; 768*7c478bd9Sstevel@tonic-gate *s1++ = 'U'; 769*7c478bd9Sstevel@tonic-gate } 770*7c478bd9Sstevel@tonic-gate break; 771*7c478bd9Sstevel@tonic-gate 772*7c478bd9Sstevel@tonic-gate case 'q': 773*7c478bd9Sstevel@tonic-gate quiet = 1; 774*7c478bd9Sstevel@tonic-gate break; 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate case 'r': 777*7c478bd9Sstevel@tonic-gate *s1++ = '\r'; 778*7c478bd9Sstevel@tonic-gate break; 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate case 'n': 781*7c478bd9Sstevel@tonic-gate *s1++ = '\n'; 782*7c478bd9Sstevel@tonic-gate break; 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate case 's': 785*7c478bd9Sstevel@tonic-gate *s1++ = ' '; 786*7c478bd9Sstevel@tonic-gate break; 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate case 't': 789*7c478bd9Sstevel@tonic-gate *s1++ = '\t'; 790*7c478bd9Sstevel@tonic-gate break; 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate case 'N': 793*7c478bd9Sstevel@tonic-gate if (sending) { 794*7c478bd9Sstevel@tonic-gate *s1++ = '\\'; 795*7c478bd9Sstevel@tonic-gate *s1++ = '\0'; 796*7c478bd9Sstevel@tonic-gate } 797*7c478bd9Sstevel@tonic-gate else 798*7c478bd9Sstevel@tonic-gate *s1++ = 'N'; 799*7c478bd9Sstevel@tonic-gate break; 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate case '$': /* ARI */ 802*7c478bd9Sstevel@tonic-gate if (use_env) { 803*7c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 804*7c478bd9Sstevel@tonic-gate break; 805*7c478bd9Sstevel@tonic-gate } 806*7c478bd9Sstevel@tonic-gate /* FALL THROUGH */ 807*7c478bd9Sstevel@tonic-gate 808*7c478bd9Sstevel@tonic-gate default: 809*7c478bd9Sstevel@tonic-gate if (isoctal (cur_chr)) { 810*7c478bd9Sstevel@tonic-gate cur_chr &= 0x07; 811*7c478bd9Sstevel@tonic-gate if (isoctal (*s)) { 812*7c478bd9Sstevel@tonic-gate cur_chr <<= 3; 813*7c478bd9Sstevel@tonic-gate cur_chr |= *s++ - '0'; 814*7c478bd9Sstevel@tonic-gate if (isoctal (*s)) { 815*7c478bd9Sstevel@tonic-gate cur_chr <<= 3; 816*7c478bd9Sstevel@tonic-gate cur_chr |= *s++ - '0'; 817*7c478bd9Sstevel@tonic-gate } 818*7c478bd9Sstevel@tonic-gate } 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate if (cur_chr != 0 || sending) { 821*7c478bd9Sstevel@tonic-gate if (sending && (cur_chr == '\\' || cur_chr == 0)) 822*7c478bd9Sstevel@tonic-gate *s1++ = '\\'; 823*7c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 824*7c478bd9Sstevel@tonic-gate } 825*7c478bd9Sstevel@tonic-gate break; 826*7c478bd9Sstevel@tonic-gate } 827*7c478bd9Sstevel@tonic-gate 828*7c478bd9Sstevel@tonic-gate if (sending) 829*7c478bd9Sstevel@tonic-gate *s1++ = '\\'; 830*7c478bd9Sstevel@tonic-gate *s1++ = cur_chr; 831*7c478bd9Sstevel@tonic-gate break; 832*7c478bd9Sstevel@tonic-gate } 833*7c478bd9Sstevel@tonic-gate } 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate if (add_return) 836*7c478bd9Sstevel@tonic-gate *s1++ = '\r'; 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate *s1++ = '\0'; /* guarantee closure */ 839*7c478bd9Sstevel@tonic-gate *s1++ = '\0'; /* terminate the string */ 840*7c478bd9Sstevel@tonic-gate return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 841*7c478bd9Sstevel@tonic-gate } 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate /* 844*7c478bd9Sstevel@tonic-gate * A modified version of 'strtok'. This version skips \ sequences. 845*7c478bd9Sstevel@tonic-gate */ 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate char *expect_strtok (s, term) 848*7c478bd9Sstevel@tonic-gate char *s, *term; 849*7c478bd9Sstevel@tonic-gate { 850*7c478bd9Sstevel@tonic-gate static char *str = ""; 851*7c478bd9Sstevel@tonic-gate int escape_flag = 0; 852*7c478bd9Sstevel@tonic-gate char *result; 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate /* 855*7c478bd9Sstevel@tonic-gate * If a string was specified then do initial processing. 856*7c478bd9Sstevel@tonic-gate */ 857*7c478bd9Sstevel@tonic-gate if (s) 858*7c478bd9Sstevel@tonic-gate str = s; 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate /* 861*7c478bd9Sstevel@tonic-gate * If this is the escape flag then reset it and ignore the character. 862*7c478bd9Sstevel@tonic-gate */ 863*7c478bd9Sstevel@tonic-gate if (*str) 864*7c478bd9Sstevel@tonic-gate result = str; 865*7c478bd9Sstevel@tonic-gate else 866*7c478bd9Sstevel@tonic-gate result = (char *) 0; 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate while (*str) { 869*7c478bd9Sstevel@tonic-gate if (escape_flag) { 870*7c478bd9Sstevel@tonic-gate escape_flag = 0; 871*7c478bd9Sstevel@tonic-gate ++str; 872*7c478bd9Sstevel@tonic-gate continue; 873*7c478bd9Sstevel@tonic-gate } 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate if (*str == '\\') { 876*7c478bd9Sstevel@tonic-gate ++str; 877*7c478bd9Sstevel@tonic-gate escape_flag = 1; 878*7c478bd9Sstevel@tonic-gate continue; 879*7c478bd9Sstevel@tonic-gate } 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate /* 882*7c478bd9Sstevel@tonic-gate * If this is not in the termination string, continue. 883*7c478bd9Sstevel@tonic-gate */ 884*7c478bd9Sstevel@tonic-gate if (strchr (term, *str) == (char *) 0) { 885*7c478bd9Sstevel@tonic-gate ++str; 886*7c478bd9Sstevel@tonic-gate continue; 887*7c478bd9Sstevel@tonic-gate } 888*7c478bd9Sstevel@tonic-gate 889*7c478bd9Sstevel@tonic-gate /* 890*7c478bd9Sstevel@tonic-gate * This is the terminator. Mark the end of the string and stop. 891*7c478bd9Sstevel@tonic-gate */ 892*7c478bd9Sstevel@tonic-gate *str++ = '\0'; 893*7c478bd9Sstevel@tonic-gate break; 894*7c478bd9Sstevel@tonic-gate } 895*7c478bd9Sstevel@tonic-gate return (result); 896*7c478bd9Sstevel@tonic-gate } 897*7c478bd9Sstevel@tonic-gate 898*7c478bd9Sstevel@tonic-gate /* 899*7c478bd9Sstevel@tonic-gate * Process the expect string 900*7c478bd9Sstevel@tonic-gate */ 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate void chat_expect (s) 903*7c478bd9Sstevel@tonic-gate char *s; 904*7c478bd9Sstevel@tonic-gate { 905*7c478bd9Sstevel@tonic-gate char *expect; 906*7c478bd9Sstevel@tonic-gate char *reply; 907*7c478bd9Sstevel@tonic-gate 908*7c478bd9Sstevel@tonic-gate if (strcmp(s, "HANGUP") == 0) { 909*7c478bd9Sstevel@tonic-gate ++hup_next; 910*7c478bd9Sstevel@tonic-gate return; 911*7c478bd9Sstevel@tonic-gate } 912*7c478bd9Sstevel@tonic-gate 913*7c478bd9Sstevel@tonic-gate if (strcmp(s, "ABORT") == 0) { 914*7c478bd9Sstevel@tonic-gate ++abort_next; 915*7c478bd9Sstevel@tonic-gate return; 916*7c478bd9Sstevel@tonic-gate } 917*7c478bd9Sstevel@tonic-gate 918*7c478bd9Sstevel@tonic-gate if (strcmp(s, "CLR_ABORT") == 0) { 919*7c478bd9Sstevel@tonic-gate ++clear_abort_next; 920*7c478bd9Sstevel@tonic-gate return; 921*7c478bd9Sstevel@tonic-gate } 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate if (strcmp(s, "REPORT") == 0) { 924*7c478bd9Sstevel@tonic-gate ++report_next; 925*7c478bd9Sstevel@tonic-gate return; 926*7c478bd9Sstevel@tonic-gate } 927*7c478bd9Sstevel@tonic-gate 928*7c478bd9Sstevel@tonic-gate if (strcmp(s, "CLR_REPORT") == 0) { 929*7c478bd9Sstevel@tonic-gate ++clear_report_next; 930*7c478bd9Sstevel@tonic-gate return; 931*7c478bd9Sstevel@tonic-gate } 932*7c478bd9Sstevel@tonic-gate 933*7c478bd9Sstevel@tonic-gate if (strcmp(s, "TIMEOUT") == 0) { 934*7c478bd9Sstevel@tonic-gate ++timeout_next; 935*7c478bd9Sstevel@tonic-gate return; 936*7c478bd9Sstevel@tonic-gate } 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate if (strcmp(s, "ECHO") == 0) { 939*7c478bd9Sstevel@tonic-gate ++echo_next; 940*7c478bd9Sstevel@tonic-gate return; 941*7c478bd9Sstevel@tonic-gate } 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate if (strcmp(s, "SAY") == 0) { 944*7c478bd9Sstevel@tonic-gate ++say_next; 945*7c478bd9Sstevel@tonic-gate return; 946*7c478bd9Sstevel@tonic-gate } 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate /* 949*7c478bd9Sstevel@tonic-gate * Fetch the expect and reply string. 950*7c478bd9Sstevel@tonic-gate */ 951*7c478bd9Sstevel@tonic-gate for (;;) { 952*7c478bd9Sstevel@tonic-gate expect = expect_strtok (s, "-"); 953*7c478bd9Sstevel@tonic-gate s = (char *) 0; 954*7c478bd9Sstevel@tonic-gate 955*7c478bd9Sstevel@tonic-gate if (expect == (char *) 0) 956*7c478bd9Sstevel@tonic-gate return; 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate reply = expect_strtok (s, "-"); 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate /* 961*7c478bd9Sstevel@tonic-gate * Handle the expect string. If successful then exit. 962*7c478bd9Sstevel@tonic-gate */ 963*7c478bd9Sstevel@tonic-gate if (get_string (expect)) 964*7c478bd9Sstevel@tonic-gate return; 965*7c478bd9Sstevel@tonic-gate 966*7c478bd9Sstevel@tonic-gate /* 967*7c478bd9Sstevel@tonic-gate * If there is a sub-reply string then send it. Otherwise any condition 968*7c478bd9Sstevel@tonic-gate * is terminal. 969*7c478bd9Sstevel@tonic-gate */ 970*7c478bd9Sstevel@tonic-gate if (reply == (char *) 0 || exit_code != 3) 971*7c478bd9Sstevel@tonic-gate break; 972*7c478bd9Sstevel@tonic-gate 973*7c478bd9Sstevel@tonic-gate chat_send (reply); 974*7c478bd9Sstevel@tonic-gate } 975*7c478bd9Sstevel@tonic-gate 976*7c478bd9Sstevel@tonic-gate /* 977*7c478bd9Sstevel@tonic-gate * The expectation did not occur. This is terminal. 978*7c478bd9Sstevel@tonic-gate */ 979*7c478bd9Sstevel@tonic-gate if (fail_reason) 980*7c478bd9Sstevel@tonic-gate logf("Failed (%s)", fail_reason); 981*7c478bd9Sstevel@tonic-gate else 982*7c478bd9Sstevel@tonic-gate logf("Failed"); 983*7c478bd9Sstevel@tonic-gate terminate(exit_code); 984*7c478bd9Sstevel@tonic-gate } 985*7c478bd9Sstevel@tonic-gate 986*7c478bd9Sstevel@tonic-gate /* 987*7c478bd9Sstevel@tonic-gate * Translate the input character to the appropriate string for printing 988*7c478bd9Sstevel@tonic-gate * the data. 989*7c478bd9Sstevel@tonic-gate */ 990*7c478bd9Sstevel@tonic-gate 991*7c478bd9Sstevel@tonic-gate char *character(c) 992*7c478bd9Sstevel@tonic-gate int c; 993*7c478bd9Sstevel@tonic-gate { 994*7c478bd9Sstevel@tonic-gate static char string[10]; 995*7c478bd9Sstevel@tonic-gate char *meta; 996*7c478bd9Sstevel@tonic-gate 997*7c478bd9Sstevel@tonic-gate meta = (c & 0x80) ? "M-" : ""; 998*7c478bd9Sstevel@tonic-gate c &= 0x7F; 999*7c478bd9Sstevel@tonic-gate 1000*7c478bd9Sstevel@tonic-gate if (c < 32) 1001*7c478bd9Sstevel@tonic-gate sprintf(string, "%s^%c", meta, (int)c + '@'); 1002*7c478bd9Sstevel@tonic-gate else if (c == 127) 1003*7c478bd9Sstevel@tonic-gate sprintf(string, "%s^?", meta); 1004*7c478bd9Sstevel@tonic-gate else 1005*7c478bd9Sstevel@tonic-gate sprintf(string, "%s%c", meta, c); 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate return (string); 1008*7c478bd9Sstevel@tonic-gate } 1009*7c478bd9Sstevel@tonic-gate 1010*7c478bd9Sstevel@tonic-gate /* 1011*7c478bd9Sstevel@tonic-gate * process the reply string 1012*7c478bd9Sstevel@tonic-gate */ 1013*7c478bd9Sstevel@tonic-gate void chat_send (s) 1014*7c478bd9Sstevel@tonic-gate register char *s; 1015*7c478bd9Sstevel@tonic-gate { 1016*7c478bd9Sstevel@tonic-gate char file_data[STR_LEN]; 1017*7c478bd9Sstevel@tonic-gate 1018*7c478bd9Sstevel@tonic-gate if (say_next) { 1019*7c478bd9Sstevel@tonic-gate say_next = 0; 1020*7c478bd9Sstevel@tonic-gate s = clean(s, 1); 1021*7c478bd9Sstevel@tonic-gate write(2, s, strlen(s)); 1022*7c478bd9Sstevel@tonic-gate free(s); 1023*7c478bd9Sstevel@tonic-gate return; 1024*7c478bd9Sstevel@tonic-gate } 1025*7c478bd9Sstevel@tonic-gate 1026*7c478bd9Sstevel@tonic-gate if (hup_next) { 1027*7c478bd9Sstevel@tonic-gate hup_next = 0; 1028*7c478bd9Sstevel@tonic-gate if (strcmp(s, "OFF") == 0) 1029*7c478bd9Sstevel@tonic-gate signal(SIGHUP, SIG_IGN); 1030*7c478bd9Sstevel@tonic-gate else 1031*7c478bd9Sstevel@tonic-gate signal(SIGHUP, sighup); 1032*7c478bd9Sstevel@tonic-gate return; 1033*7c478bd9Sstevel@tonic-gate } 1034*7c478bd9Sstevel@tonic-gate 1035*7c478bd9Sstevel@tonic-gate if (echo_next) { 1036*7c478bd9Sstevel@tonic-gate echo_next = 0; 1037*7c478bd9Sstevel@tonic-gate echo = (strcmp(s, "ON") == 0); 1038*7c478bd9Sstevel@tonic-gate return; 1039*7c478bd9Sstevel@tonic-gate } 1040*7c478bd9Sstevel@tonic-gate 1041*7c478bd9Sstevel@tonic-gate if (abort_next) { 1042*7c478bd9Sstevel@tonic-gate char *s1; 1043*7c478bd9Sstevel@tonic-gate 1044*7c478bd9Sstevel@tonic-gate abort_next = 0; 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate if (n_aborts >= MAX_ABORTS) 1047*7c478bd9Sstevel@tonic-gate fatal(2, "Too many ABORT strings"); 1048*7c478bd9Sstevel@tonic-gate 1049*7c478bd9Sstevel@tonic-gate s1 = clean(s, 0); 1050*7c478bd9Sstevel@tonic-gate 1051*7c478bd9Sstevel@tonic-gate if (strlen(s1) > strlen(s) 1052*7c478bd9Sstevel@tonic-gate || strlen(s1) + 1 > sizeof(fail_buffer)) 1053*7c478bd9Sstevel@tonic-gate fatal(1, "Illegal or too-long ABORT string ('%v')", s); 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate abort_string[n_aborts++] = s1; 1056*7c478bd9Sstevel@tonic-gate 1057*7c478bd9Sstevel@tonic-gate if (verbose) 1058*7c478bd9Sstevel@tonic-gate logf("abort on (%v)", s); 1059*7c478bd9Sstevel@tonic-gate return; 1060*7c478bd9Sstevel@tonic-gate } 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate if (clear_abort_next) { 1063*7c478bd9Sstevel@tonic-gate char *s1; 1064*7c478bd9Sstevel@tonic-gate int i; 1065*7c478bd9Sstevel@tonic-gate int old_max; 1066*7c478bd9Sstevel@tonic-gate int pack = 0; 1067*7c478bd9Sstevel@tonic-gate 1068*7c478bd9Sstevel@tonic-gate clear_abort_next = 0; 1069*7c478bd9Sstevel@tonic-gate 1070*7c478bd9Sstevel@tonic-gate s1 = clean(s, 0); 1071*7c478bd9Sstevel@tonic-gate 1072*7c478bd9Sstevel@tonic-gate if (strlen(s1) > strlen(s) 1073*7c478bd9Sstevel@tonic-gate || strlen(s1) + 1 > sizeof(fail_buffer)) 1074*7c478bd9Sstevel@tonic-gate fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s); 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate old_max = n_aborts; 1077*7c478bd9Sstevel@tonic-gate for (i=0; i < n_aborts; i++) { 1078*7c478bd9Sstevel@tonic-gate if ( strcmp(s1,abort_string[i]) == 0 ) { 1079*7c478bd9Sstevel@tonic-gate free(abort_string[i]); 1080*7c478bd9Sstevel@tonic-gate abort_string[i] = NULL; 1081*7c478bd9Sstevel@tonic-gate pack++; 1082*7c478bd9Sstevel@tonic-gate n_aborts--; 1083*7c478bd9Sstevel@tonic-gate if (verbose) 1084*7c478bd9Sstevel@tonic-gate logf("clear abort on (%v)", s); 1085*7c478bd9Sstevel@tonic-gate } 1086*7c478bd9Sstevel@tonic-gate } 1087*7c478bd9Sstevel@tonic-gate free(s1); 1088*7c478bd9Sstevel@tonic-gate if (pack) 1089*7c478bd9Sstevel@tonic-gate pack_array(abort_string,old_max); 1090*7c478bd9Sstevel@tonic-gate return; 1091*7c478bd9Sstevel@tonic-gate } 1092*7c478bd9Sstevel@tonic-gate 1093*7c478bd9Sstevel@tonic-gate if (report_next) { 1094*7c478bd9Sstevel@tonic-gate char *s1; 1095*7c478bd9Sstevel@tonic-gate 1096*7c478bd9Sstevel@tonic-gate report_next = 0; 1097*7c478bd9Sstevel@tonic-gate if (n_reports >= MAX_REPORTS) 1098*7c478bd9Sstevel@tonic-gate fatal(2, "Too many REPORT strings"); 1099*7c478bd9Sstevel@tonic-gate 1100*7c478bd9Sstevel@tonic-gate s1 = clean(s, 0); 1101*7c478bd9Sstevel@tonic-gate 1102*7c478bd9Sstevel@tonic-gate if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 1103*7c478bd9Sstevel@tonic-gate fatal(1, "Illegal or too-long REPORT string ('%v')", s); 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate report_string[n_reports++] = s1; 1106*7c478bd9Sstevel@tonic-gate 1107*7c478bd9Sstevel@tonic-gate if (verbose) 1108*7c478bd9Sstevel@tonic-gate logf("report (%v)", s); 1109*7c478bd9Sstevel@tonic-gate return; 1110*7c478bd9Sstevel@tonic-gate } 1111*7c478bd9Sstevel@tonic-gate 1112*7c478bd9Sstevel@tonic-gate if (clear_report_next) { 1113*7c478bd9Sstevel@tonic-gate char *s1; 1114*7c478bd9Sstevel@tonic-gate int i; 1115*7c478bd9Sstevel@tonic-gate int old_max; 1116*7c478bd9Sstevel@tonic-gate int pack = 0; 1117*7c478bd9Sstevel@tonic-gate 1118*7c478bd9Sstevel@tonic-gate clear_report_next = 0; 1119*7c478bd9Sstevel@tonic-gate 1120*7c478bd9Sstevel@tonic-gate s1 = clean(s, 0); 1121*7c478bd9Sstevel@tonic-gate 1122*7c478bd9Sstevel@tonic-gate if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 1123*7c478bd9Sstevel@tonic-gate fatal(1, "Illegal or too-long REPORT string ('%v')", s); 1124*7c478bd9Sstevel@tonic-gate 1125*7c478bd9Sstevel@tonic-gate old_max = n_reports; 1126*7c478bd9Sstevel@tonic-gate for (i=0; i < n_reports; i++) { 1127*7c478bd9Sstevel@tonic-gate if ( strcmp(s1,report_string[i]) == 0 ) { 1128*7c478bd9Sstevel@tonic-gate free(report_string[i]); 1129*7c478bd9Sstevel@tonic-gate report_string[i] = NULL; 1130*7c478bd9Sstevel@tonic-gate pack++; 1131*7c478bd9Sstevel@tonic-gate n_reports--; 1132*7c478bd9Sstevel@tonic-gate if (verbose) 1133*7c478bd9Sstevel@tonic-gate logf("clear report (%v)", s); 1134*7c478bd9Sstevel@tonic-gate } 1135*7c478bd9Sstevel@tonic-gate } 1136*7c478bd9Sstevel@tonic-gate free(s1); 1137*7c478bd9Sstevel@tonic-gate if (pack) 1138*7c478bd9Sstevel@tonic-gate pack_array(report_string,old_max); 1139*7c478bd9Sstevel@tonic-gate 1140*7c478bd9Sstevel@tonic-gate return; 1141*7c478bd9Sstevel@tonic-gate } 1142*7c478bd9Sstevel@tonic-gate 1143*7c478bd9Sstevel@tonic-gate if (timeout_next) { 1144*7c478bd9Sstevel@tonic-gate timeout_next = 0; 1145*7c478bd9Sstevel@tonic-gate timeout = atoi(s); 1146*7c478bd9Sstevel@tonic-gate 1147*7c478bd9Sstevel@tonic-gate if (timeout <= 0) 1148*7c478bd9Sstevel@tonic-gate timeout = DEFAULT_CHAT_TIMEOUT; 1149*7c478bd9Sstevel@tonic-gate 1150*7c478bd9Sstevel@tonic-gate if (verbose) 1151*7c478bd9Sstevel@tonic-gate logf("timeout set to %d seconds", timeout); 1152*7c478bd9Sstevel@tonic-gate 1153*7c478bd9Sstevel@tonic-gate return; 1154*7c478bd9Sstevel@tonic-gate } 1155*7c478bd9Sstevel@tonic-gate 1156*7c478bd9Sstevel@tonic-gate /* 1157*7c478bd9Sstevel@tonic-gate * The syntax @filename means read the string to send from the 1158*7c478bd9Sstevel@tonic-gate * file `filename'. 1159*7c478bd9Sstevel@tonic-gate */ 1160*7c478bd9Sstevel@tonic-gate if (s[0] == '@') { 1161*7c478bd9Sstevel@tonic-gate /* skip the @ and any following white-space */ 1162*7c478bd9Sstevel@tonic-gate char *fn = s; 1163*7c478bd9Sstevel@tonic-gate while (*++fn == ' ' || *fn == '\t') 1164*7c478bd9Sstevel@tonic-gate ; 1165*7c478bd9Sstevel@tonic-gate 1166*7c478bd9Sstevel@tonic-gate if (*fn != 0) { 1167*7c478bd9Sstevel@tonic-gate FILE *f; 1168*7c478bd9Sstevel@tonic-gate int n = 0; 1169*7c478bd9Sstevel@tonic-gate 1170*7c478bd9Sstevel@tonic-gate /* open the file and read until STR_LEN-1 bytes or end-of-file */ 1171*7c478bd9Sstevel@tonic-gate f = fopen(fn, "r"); 1172*7c478bd9Sstevel@tonic-gate if (f == NULL) 1173*7c478bd9Sstevel@tonic-gate fatal(1, "%s -- open failed: %m", fn); 1174*7c478bd9Sstevel@tonic-gate while (n < STR_LEN - 1) { 1175*7c478bd9Sstevel@tonic-gate int nr = fread(&file_data[n], 1, STR_LEN - 1 - n, f); 1176*7c478bd9Sstevel@tonic-gate if (nr < 0) 1177*7c478bd9Sstevel@tonic-gate fatal(1, "%s -- read error", fn); 1178*7c478bd9Sstevel@tonic-gate if (nr == 0) 1179*7c478bd9Sstevel@tonic-gate break; 1180*7c478bd9Sstevel@tonic-gate n += nr; 1181*7c478bd9Sstevel@tonic-gate } 1182*7c478bd9Sstevel@tonic-gate fclose(f); 1183*7c478bd9Sstevel@tonic-gate 1184*7c478bd9Sstevel@tonic-gate /* use the string we got as the string to send, 1185*7c478bd9Sstevel@tonic-gate but trim off the final newline if any. */ 1186*7c478bd9Sstevel@tonic-gate if (n > 0 && file_data[n-1] == '\n') 1187*7c478bd9Sstevel@tonic-gate --n; 1188*7c478bd9Sstevel@tonic-gate file_data[n] = 0; 1189*7c478bd9Sstevel@tonic-gate s = file_data; 1190*7c478bd9Sstevel@tonic-gate } 1191*7c478bd9Sstevel@tonic-gate } 1192*7c478bd9Sstevel@tonic-gate 1193*7c478bd9Sstevel@tonic-gate if (strcmp(s, "EOT") == 0) 1194*7c478bd9Sstevel@tonic-gate s = "^D\\c"; 1195*7c478bd9Sstevel@tonic-gate else if (strcmp(s, "BREAK") == 0) 1196*7c478bd9Sstevel@tonic-gate s = "\\K\\c"; 1197*7c478bd9Sstevel@tonic-gate 1198*7c478bd9Sstevel@tonic-gate if (!put_string(s)) 1199*7c478bd9Sstevel@tonic-gate fatal(1, "Failed"); 1200*7c478bd9Sstevel@tonic-gate } 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate int get_char() 1203*7c478bd9Sstevel@tonic-gate { 1204*7c478bd9Sstevel@tonic-gate int status; 1205*7c478bd9Sstevel@tonic-gate char c; 1206*7c478bd9Sstevel@tonic-gate 1207*7c478bd9Sstevel@tonic-gate status = read(0, &c, 1); 1208*7c478bd9Sstevel@tonic-gate 1209*7c478bd9Sstevel@tonic-gate switch (status) { 1210*7c478bd9Sstevel@tonic-gate case 1: 1211*7c478bd9Sstevel@tonic-gate return ((int)c & 0x7F); 1212*7c478bd9Sstevel@tonic-gate 1213*7c478bd9Sstevel@tonic-gate default: 1214*7c478bd9Sstevel@tonic-gate logf("warning: read() on stdin returned %d", status); 1215*7c478bd9Sstevel@tonic-gate 1216*7c478bd9Sstevel@tonic-gate case -1: 1217*7c478bd9Sstevel@tonic-gate if ((status = fcntl(0, F_GETFL, 0)) == -1) 1218*7c478bd9Sstevel@tonic-gate fatal(2, "Can't get file mode flags on stdin: %m"); 1219*7c478bd9Sstevel@tonic-gate 1220*7c478bd9Sstevel@tonic-gate if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 1221*7c478bd9Sstevel@tonic-gate fatal(2, "Can't set file mode flags on stdin: %m"); 1222*7c478bd9Sstevel@tonic-gate 1223*7c478bd9Sstevel@tonic-gate return (-1); 1224*7c478bd9Sstevel@tonic-gate } 1225*7c478bd9Sstevel@tonic-gate } 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate int put_char(c) 1228*7c478bd9Sstevel@tonic-gate int c; 1229*7c478bd9Sstevel@tonic-gate { 1230*7c478bd9Sstevel@tonic-gate int status; 1231*7c478bd9Sstevel@tonic-gate char ch = c; 1232*7c478bd9Sstevel@tonic-gate 1233*7c478bd9Sstevel@tonic-gate usleep(10000); /* inter-character typing delay (?) */ 1234*7c478bd9Sstevel@tonic-gate 1235*7c478bd9Sstevel@tonic-gate status = write(1, &ch, 1); 1236*7c478bd9Sstevel@tonic-gate 1237*7c478bd9Sstevel@tonic-gate switch (status) { 1238*7c478bd9Sstevel@tonic-gate case 1: 1239*7c478bd9Sstevel@tonic-gate return (0); 1240*7c478bd9Sstevel@tonic-gate 1241*7c478bd9Sstevel@tonic-gate default: 1242*7c478bd9Sstevel@tonic-gate logf("warning: write() on stdout returned %d", status); 1243*7c478bd9Sstevel@tonic-gate 1244*7c478bd9Sstevel@tonic-gate case -1: 1245*7c478bd9Sstevel@tonic-gate if ((status = fcntl(0, F_GETFL, 0)) == -1) 1246*7c478bd9Sstevel@tonic-gate fatal(2, "Can't get file mode flags on stdin, %m"); 1247*7c478bd9Sstevel@tonic-gate 1248*7c478bd9Sstevel@tonic-gate if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 1249*7c478bd9Sstevel@tonic-gate fatal(2, "Can't set file mode flags on stdin: %m"); 1250*7c478bd9Sstevel@tonic-gate 1251*7c478bd9Sstevel@tonic-gate return (-1); 1252*7c478bd9Sstevel@tonic-gate } 1253*7c478bd9Sstevel@tonic-gate } 1254*7c478bd9Sstevel@tonic-gate 1255*7c478bd9Sstevel@tonic-gate int write_char (c) 1256*7c478bd9Sstevel@tonic-gate int c; 1257*7c478bd9Sstevel@tonic-gate { 1258*7c478bd9Sstevel@tonic-gate if (alarmed || put_char(c) < 0) { 1259*7c478bd9Sstevel@tonic-gate alarm(0); 1260*7c478bd9Sstevel@tonic-gate alarmed = 0; 1261*7c478bd9Sstevel@tonic-gate 1262*7c478bd9Sstevel@tonic-gate if (verbose) { 1263*7c478bd9Sstevel@tonic-gate if (errno == EINTR || errno == EWOULDBLOCK) 1264*7c478bd9Sstevel@tonic-gate logf(" -- write timed out"); 1265*7c478bd9Sstevel@tonic-gate else 1266*7c478bd9Sstevel@tonic-gate logf(" -- write failed: %m"); 1267*7c478bd9Sstevel@tonic-gate } 1268*7c478bd9Sstevel@tonic-gate return (0); 1269*7c478bd9Sstevel@tonic-gate } 1270*7c478bd9Sstevel@tonic-gate return (1); 1271*7c478bd9Sstevel@tonic-gate } 1272*7c478bd9Sstevel@tonic-gate 1273*7c478bd9Sstevel@tonic-gate int put_string (s) 1274*7c478bd9Sstevel@tonic-gate register char *s; 1275*7c478bd9Sstevel@tonic-gate { 1276*7c478bd9Sstevel@tonic-gate quiet = 0; 1277*7c478bd9Sstevel@tonic-gate s = clean(s, 1); 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate if (verbose) { 1280*7c478bd9Sstevel@tonic-gate if (quiet) 1281*7c478bd9Sstevel@tonic-gate logf("send (??????)"); 1282*7c478bd9Sstevel@tonic-gate else 1283*7c478bd9Sstevel@tonic-gate logf("send (%v)", s); 1284*7c478bd9Sstevel@tonic-gate } 1285*7c478bd9Sstevel@tonic-gate 1286*7c478bd9Sstevel@tonic-gate alarm(timeout); alarmed = 0; 1287*7c478bd9Sstevel@tonic-gate 1288*7c478bd9Sstevel@tonic-gate while (*s) { 1289*7c478bd9Sstevel@tonic-gate register char c = *s++; 1290*7c478bd9Sstevel@tonic-gate 1291*7c478bd9Sstevel@tonic-gate if (c != '\\') { 1292*7c478bd9Sstevel@tonic-gate if (!write_char (c)) 1293*7c478bd9Sstevel@tonic-gate return 0; 1294*7c478bd9Sstevel@tonic-gate continue; 1295*7c478bd9Sstevel@tonic-gate } 1296*7c478bd9Sstevel@tonic-gate 1297*7c478bd9Sstevel@tonic-gate c = *s++; 1298*7c478bd9Sstevel@tonic-gate switch (c) { 1299*7c478bd9Sstevel@tonic-gate case 'd': 1300*7c478bd9Sstevel@tonic-gate sleep(1); 1301*7c478bd9Sstevel@tonic-gate break; 1302*7c478bd9Sstevel@tonic-gate 1303*7c478bd9Sstevel@tonic-gate case 'K': 1304*7c478bd9Sstevel@tonic-gate break_sequence(); 1305*7c478bd9Sstevel@tonic-gate break; 1306*7c478bd9Sstevel@tonic-gate 1307*7c478bd9Sstevel@tonic-gate case 'p': 1308*7c478bd9Sstevel@tonic-gate usleep(10000); /* 1/100th of a second (arg is microseconds) */ 1309*7c478bd9Sstevel@tonic-gate break; 1310*7c478bd9Sstevel@tonic-gate 1311*7c478bd9Sstevel@tonic-gate default: 1312*7c478bd9Sstevel@tonic-gate if (!write_char (c)) 1313*7c478bd9Sstevel@tonic-gate return 0; 1314*7c478bd9Sstevel@tonic-gate break; 1315*7c478bd9Sstevel@tonic-gate } 1316*7c478bd9Sstevel@tonic-gate } 1317*7c478bd9Sstevel@tonic-gate 1318*7c478bd9Sstevel@tonic-gate alarm(0); 1319*7c478bd9Sstevel@tonic-gate alarmed = 0; 1320*7c478bd9Sstevel@tonic-gate return (1); 1321*7c478bd9Sstevel@tonic-gate } 1322*7c478bd9Sstevel@tonic-gate 1323*7c478bd9Sstevel@tonic-gate /* 1324*7c478bd9Sstevel@tonic-gate * Echo a character to stderr. 1325*7c478bd9Sstevel@tonic-gate * When called with -1, a '\n' character is generated when 1326*7c478bd9Sstevel@tonic-gate * the cursor is not at the beginning of a line. 1327*7c478bd9Sstevel@tonic-gate */ 1328*7c478bd9Sstevel@tonic-gate void echo_stderr(n) 1329*7c478bd9Sstevel@tonic-gate int n; 1330*7c478bd9Sstevel@tonic-gate { 1331*7c478bd9Sstevel@tonic-gate static int need_lf; 1332*7c478bd9Sstevel@tonic-gate char *s; 1333*7c478bd9Sstevel@tonic-gate 1334*7c478bd9Sstevel@tonic-gate switch (n) { 1335*7c478bd9Sstevel@tonic-gate case '\r': /* ignore '\r' */ 1336*7c478bd9Sstevel@tonic-gate break; 1337*7c478bd9Sstevel@tonic-gate case -1: 1338*7c478bd9Sstevel@tonic-gate if (need_lf == 0) 1339*7c478bd9Sstevel@tonic-gate break; 1340*7c478bd9Sstevel@tonic-gate /* fall through */ 1341*7c478bd9Sstevel@tonic-gate case '\n': 1342*7c478bd9Sstevel@tonic-gate write(2, "\n", 1); 1343*7c478bd9Sstevel@tonic-gate need_lf = 0; 1344*7c478bd9Sstevel@tonic-gate break; 1345*7c478bd9Sstevel@tonic-gate default: 1346*7c478bd9Sstevel@tonic-gate s = character(n); 1347*7c478bd9Sstevel@tonic-gate write(2, s, strlen(s)); 1348*7c478bd9Sstevel@tonic-gate need_lf = 1; 1349*7c478bd9Sstevel@tonic-gate break; 1350*7c478bd9Sstevel@tonic-gate } 1351*7c478bd9Sstevel@tonic-gate } 1352*7c478bd9Sstevel@tonic-gate 1353*7c478bd9Sstevel@tonic-gate /* 1354*7c478bd9Sstevel@tonic-gate * 'Wait for' this string to appear on this file descriptor. 1355*7c478bd9Sstevel@tonic-gate */ 1356*7c478bd9Sstevel@tonic-gate int get_string(string) 1357*7c478bd9Sstevel@tonic-gate register char *string; 1358*7c478bd9Sstevel@tonic-gate { 1359*7c478bd9Sstevel@tonic-gate char temp[STR_LEN]; 1360*7c478bd9Sstevel@tonic-gate int c, printed = 0, len, minlen; 1361*7c478bd9Sstevel@tonic-gate register char *s = temp, *end = s + STR_LEN; 1362*7c478bd9Sstevel@tonic-gate char *logged = temp; 1363*7c478bd9Sstevel@tonic-gate 1364*7c478bd9Sstevel@tonic-gate fail_reason = (char *)0; 1365*7c478bd9Sstevel@tonic-gate string = clean(string, 0); 1366*7c478bd9Sstevel@tonic-gate len = strlen(string); 1367*7c478bd9Sstevel@tonic-gate minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 1368*7c478bd9Sstevel@tonic-gate 1369*7c478bd9Sstevel@tonic-gate if (verbose) 1370*7c478bd9Sstevel@tonic-gate logf("expect (%v)", string); 1371*7c478bd9Sstevel@tonic-gate 1372*7c478bd9Sstevel@tonic-gate if (len > STR_LEN) { 1373*7c478bd9Sstevel@tonic-gate logf("expect string is too long"); 1374*7c478bd9Sstevel@tonic-gate exit_code = 1; 1375*7c478bd9Sstevel@tonic-gate return 0; 1376*7c478bd9Sstevel@tonic-gate } 1377*7c478bd9Sstevel@tonic-gate 1378*7c478bd9Sstevel@tonic-gate if (len == 0) { 1379*7c478bd9Sstevel@tonic-gate if (verbose) 1380*7c478bd9Sstevel@tonic-gate logf("got it"); 1381*7c478bd9Sstevel@tonic-gate return (1); 1382*7c478bd9Sstevel@tonic-gate } 1383*7c478bd9Sstevel@tonic-gate 1384*7c478bd9Sstevel@tonic-gate alarm(timeout); 1385*7c478bd9Sstevel@tonic-gate alarmed = 0; 1386*7c478bd9Sstevel@tonic-gate 1387*7c478bd9Sstevel@tonic-gate while ( ! alarmed && (c = get_char()) >= 0) { 1388*7c478bd9Sstevel@tonic-gate int n, abort_len, report_len; 1389*7c478bd9Sstevel@tonic-gate 1390*7c478bd9Sstevel@tonic-gate if (echo) 1391*7c478bd9Sstevel@tonic-gate echo_stderr(c); 1392*7c478bd9Sstevel@tonic-gate if (verbose && c == '\n') { 1393*7c478bd9Sstevel@tonic-gate if (s == logged) 1394*7c478bd9Sstevel@tonic-gate logf(""); /* blank line */ 1395*7c478bd9Sstevel@tonic-gate else 1396*7c478bd9Sstevel@tonic-gate logf("%0.*v", s - logged, logged); 1397*7c478bd9Sstevel@tonic-gate logged = s + 1; 1398*7c478bd9Sstevel@tonic-gate } 1399*7c478bd9Sstevel@tonic-gate 1400*7c478bd9Sstevel@tonic-gate *s++ = c; 1401*7c478bd9Sstevel@tonic-gate 1402*7c478bd9Sstevel@tonic-gate if (verbose && s >= logged + 80) { 1403*7c478bd9Sstevel@tonic-gate logf("%0.*v", s - logged, logged); 1404*7c478bd9Sstevel@tonic-gate logged = s; 1405*7c478bd9Sstevel@tonic-gate } 1406*7c478bd9Sstevel@tonic-gate 1407*7c478bd9Sstevel@tonic-gate if (Verbose) { 1408*7c478bd9Sstevel@tonic-gate if (c == '\n') 1409*7c478bd9Sstevel@tonic-gate fputc( '\n', stderr ); 1410*7c478bd9Sstevel@tonic-gate else if (c != '\r') 1411*7c478bd9Sstevel@tonic-gate fprintf( stderr, "%s", character(c) ); 1412*7c478bd9Sstevel@tonic-gate } 1413*7c478bd9Sstevel@tonic-gate 1414*7c478bd9Sstevel@tonic-gate if (!report_gathering) { 1415*7c478bd9Sstevel@tonic-gate for (n = 0; n < n_reports; ++n) { 1416*7c478bd9Sstevel@tonic-gate if ((report_string[n] != (char*) NULL) && 1417*7c478bd9Sstevel@tonic-gate s - temp >= (report_len = strlen(report_string[n])) && 1418*7c478bd9Sstevel@tonic-gate strncmp(s - report_len, report_string[n], report_len) == 0) { 1419*7c478bd9Sstevel@tonic-gate time_t time_now = time ((time_t*) NULL); 1420*7c478bd9Sstevel@tonic-gate struct tm* tm_now = localtime (&time_now); 1421*7c478bd9Sstevel@tonic-gate 1422*7c478bd9Sstevel@tonic-gate strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 1423*7c478bd9Sstevel@tonic-gate strcat (report_buffer, report_string[n]); 1424*7c478bd9Sstevel@tonic-gate 1425*7c478bd9Sstevel@tonic-gate report_string[n] = (char *) NULL; 1426*7c478bd9Sstevel@tonic-gate report_gathering = 1; 1427*7c478bd9Sstevel@tonic-gate break; 1428*7c478bd9Sstevel@tonic-gate } 1429*7c478bd9Sstevel@tonic-gate } 1430*7c478bd9Sstevel@tonic-gate } 1431*7c478bd9Sstevel@tonic-gate else { 1432*7c478bd9Sstevel@tonic-gate if (!iscntrl (c)) { 1433*7c478bd9Sstevel@tonic-gate int rep_len = strlen (report_buffer); 1434*7c478bd9Sstevel@tonic-gate report_buffer[rep_len] = c; 1435*7c478bd9Sstevel@tonic-gate report_buffer[rep_len + 1] = '\0'; 1436*7c478bd9Sstevel@tonic-gate } 1437*7c478bd9Sstevel@tonic-gate else { 1438*7c478bd9Sstevel@tonic-gate report_gathering = 0; 1439*7c478bd9Sstevel@tonic-gate fprintf (report_fp, "chat: %s\n", report_buffer); 1440*7c478bd9Sstevel@tonic-gate } 1441*7c478bd9Sstevel@tonic-gate } 1442*7c478bd9Sstevel@tonic-gate 1443*7c478bd9Sstevel@tonic-gate if (s - temp >= len && 1444*7c478bd9Sstevel@tonic-gate c == string[len - 1] && 1445*7c478bd9Sstevel@tonic-gate strncmp(s - len, string, len) == 0) { 1446*7c478bd9Sstevel@tonic-gate if (verbose) { 1447*7c478bd9Sstevel@tonic-gate if (s > logged) 1448*7c478bd9Sstevel@tonic-gate logf("%0.*v", s - logged, logged); 1449*7c478bd9Sstevel@tonic-gate logf(" -- got it\n"); 1450*7c478bd9Sstevel@tonic-gate } 1451*7c478bd9Sstevel@tonic-gate 1452*7c478bd9Sstevel@tonic-gate alarm(0); 1453*7c478bd9Sstevel@tonic-gate alarmed = 0; 1454*7c478bd9Sstevel@tonic-gate return (1); 1455*7c478bd9Sstevel@tonic-gate } 1456*7c478bd9Sstevel@tonic-gate 1457*7c478bd9Sstevel@tonic-gate for (n = 0; n < n_aborts; ++n) { 1458*7c478bd9Sstevel@tonic-gate if (s - temp >= (abort_len = strlen(abort_string[n])) && 1459*7c478bd9Sstevel@tonic-gate strncmp(s - abort_len, abort_string[n], abort_len) == 0) { 1460*7c478bd9Sstevel@tonic-gate if (verbose) { 1461*7c478bd9Sstevel@tonic-gate if (s > logged) 1462*7c478bd9Sstevel@tonic-gate logf("%0.*v", s - logged, logged); 1463*7c478bd9Sstevel@tonic-gate logf(" -- failed"); 1464*7c478bd9Sstevel@tonic-gate } 1465*7c478bd9Sstevel@tonic-gate 1466*7c478bd9Sstevel@tonic-gate alarm(0); 1467*7c478bd9Sstevel@tonic-gate alarmed = 0; 1468*7c478bd9Sstevel@tonic-gate exit_code = n + 4; 1469*7c478bd9Sstevel@tonic-gate strcpy(fail_reason = fail_buffer, abort_string[n]); 1470*7c478bd9Sstevel@tonic-gate return (0); 1471*7c478bd9Sstevel@tonic-gate } 1472*7c478bd9Sstevel@tonic-gate } 1473*7c478bd9Sstevel@tonic-gate 1474*7c478bd9Sstevel@tonic-gate if (s >= end) { 1475*7c478bd9Sstevel@tonic-gate if (logged < s - minlen) { 1476*7c478bd9Sstevel@tonic-gate if (verbose) 1477*7c478bd9Sstevel@tonic-gate logf("%0.*v", s - logged, logged); 1478*7c478bd9Sstevel@tonic-gate logged = s; 1479*7c478bd9Sstevel@tonic-gate } 1480*7c478bd9Sstevel@tonic-gate s -= minlen; 1481*7c478bd9Sstevel@tonic-gate memmove(temp, s, minlen); 1482*7c478bd9Sstevel@tonic-gate logged = temp + (logged - s); 1483*7c478bd9Sstevel@tonic-gate s = temp + minlen; 1484*7c478bd9Sstevel@tonic-gate } 1485*7c478bd9Sstevel@tonic-gate 1486*7c478bd9Sstevel@tonic-gate if (alarmed && verbose) 1487*7c478bd9Sstevel@tonic-gate logf("warning: alarm synchronization problem"); 1488*7c478bd9Sstevel@tonic-gate } 1489*7c478bd9Sstevel@tonic-gate 1490*7c478bd9Sstevel@tonic-gate alarm(0); 1491*7c478bd9Sstevel@tonic-gate 1492*7c478bd9Sstevel@tonic-gate if (verbose && printed) { 1493*7c478bd9Sstevel@tonic-gate if (alarmed) 1494*7c478bd9Sstevel@tonic-gate logf(" -- read timed out"); 1495*7c478bd9Sstevel@tonic-gate else 1496*7c478bd9Sstevel@tonic-gate logf(" -- read failed: %m"); 1497*7c478bd9Sstevel@tonic-gate } 1498*7c478bd9Sstevel@tonic-gate 1499*7c478bd9Sstevel@tonic-gate exit_code = 3; 1500*7c478bd9Sstevel@tonic-gate alarmed = 0; 1501*7c478bd9Sstevel@tonic-gate return (0); 1502*7c478bd9Sstevel@tonic-gate } 1503*7c478bd9Sstevel@tonic-gate 1504*7c478bd9Sstevel@tonic-gate /* 1505*7c478bd9Sstevel@tonic-gate * Gross kludge to handle Solaris versions >= 2.6 having usleep. 1506*7c478bd9Sstevel@tonic-gate */ 1507*7c478bd9Sstevel@tonic-gate #ifdef SOL2 1508*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 1509*7c478bd9Sstevel@tonic-gate #if MAXUID > 65536 /* then this is Solaris 2.6 or later */ 1510*7c478bd9Sstevel@tonic-gate #undef NO_USLEEP 1511*7c478bd9Sstevel@tonic-gate #endif 1512*7c478bd9Sstevel@tonic-gate #endif /* SOL2 */ 1513*7c478bd9Sstevel@tonic-gate 1514*7c478bd9Sstevel@tonic-gate #ifdef NO_USLEEP 1515*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 1516*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 1517*7c478bd9Sstevel@tonic-gate 1518*7c478bd9Sstevel@tonic-gate /* 1519*7c478bd9Sstevel@tonic-gate usleep -- support routine for 4.2BSD system call emulations 1520*7c478bd9Sstevel@tonic-gate last edit: 29-Oct-1984 D A Gwyn 1521*7c478bd9Sstevel@tonic-gate */ 1522*7c478bd9Sstevel@tonic-gate 1523*7c478bd9Sstevel@tonic-gate extern int select(); 1524*7c478bd9Sstevel@tonic-gate 1525*7c478bd9Sstevel@tonic-gate int 1526*7c478bd9Sstevel@tonic-gate usleep( usec ) /* returns 0 if ok, else -1 */ 1527*7c478bd9Sstevel@tonic-gate long usec; /* delay in microseconds */ 1528*7c478bd9Sstevel@tonic-gate { 1529*7c478bd9Sstevel@tonic-gate static struct { /* `timeval' */ 1530*7c478bd9Sstevel@tonic-gate long tv_sec; /* seconds */ 1531*7c478bd9Sstevel@tonic-gate long tv_usec; /* microsecs */ 1532*7c478bd9Sstevel@tonic-gate } delay; /* _select() timeout */ 1533*7c478bd9Sstevel@tonic-gate 1534*7c478bd9Sstevel@tonic-gate delay.tv_sec = usec / 1000000L; 1535*7c478bd9Sstevel@tonic-gate delay.tv_usec = usec % 1000000L; 1536*7c478bd9Sstevel@tonic-gate 1537*7c478bd9Sstevel@tonic-gate return select(0, (long *)0, (long *)0, (long *)0, &delay); 1538*7c478bd9Sstevel@tonic-gate } 1539*7c478bd9Sstevel@tonic-gate #endif 1540*7c478bd9Sstevel@tonic-gate 1541*7c478bd9Sstevel@tonic-gate void 1542*7c478bd9Sstevel@tonic-gate pack_array (array, end) 1543*7c478bd9Sstevel@tonic-gate char **array; /* The address of the array of string pointers */ 1544*7c478bd9Sstevel@tonic-gate int end; /* The index of the next free entry before CLR_ */ 1545*7c478bd9Sstevel@tonic-gate { 1546*7c478bd9Sstevel@tonic-gate int i, j; 1547*7c478bd9Sstevel@tonic-gate 1548*7c478bd9Sstevel@tonic-gate for (i = 0; i < end; i++) { 1549*7c478bd9Sstevel@tonic-gate if (array[i] == NULL) { 1550*7c478bd9Sstevel@tonic-gate for (j = i+1; j < end; ++j) 1551*7c478bd9Sstevel@tonic-gate if (array[j] != NULL) 1552*7c478bd9Sstevel@tonic-gate array[i++] = array[j]; 1553*7c478bd9Sstevel@tonic-gate for (; i < end; ++i) 1554*7c478bd9Sstevel@tonic-gate array[i] = NULL; 1555*7c478bd9Sstevel@tonic-gate break; 1556*7c478bd9Sstevel@tonic-gate } 1557*7c478bd9Sstevel@tonic-gate } 1558*7c478bd9Sstevel@tonic-gate } 1559*7c478bd9Sstevel@tonic-gate 1560*7c478bd9Sstevel@tonic-gate /* 1561*7c478bd9Sstevel@tonic-gate * vfmtmsg - format a message into a buffer. Like vsprintf except we 1562*7c478bd9Sstevel@tonic-gate * also specify the length of the output buffer, and we handle the 1563*7c478bd9Sstevel@tonic-gate * %m (error message) format. 1564*7c478bd9Sstevel@tonic-gate * Doesn't do floating-point formats. 1565*7c478bd9Sstevel@tonic-gate * Returns the number of chars put into buf. 1566*7c478bd9Sstevel@tonic-gate */ 1567*7c478bd9Sstevel@tonic-gate #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) 1568*7c478bd9Sstevel@tonic-gate 1569*7c478bd9Sstevel@tonic-gate int 1570*7c478bd9Sstevel@tonic-gate vfmtmsg(buf, buflen, fmt, args) 1571*7c478bd9Sstevel@tonic-gate char *buf; 1572*7c478bd9Sstevel@tonic-gate int buflen; 1573*7c478bd9Sstevel@tonic-gate const char *fmt; 1574*7c478bd9Sstevel@tonic-gate va_list args; 1575*7c478bd9Sstevel@tonic-gate { 1576*7c478bd9Sstevel@tonic-gate int c, i, n; 1577*7c478bd9Sstevel@tonic-gate int width, prec, fillch; 1578*7c478bd9Sstevel@tonic-gate int base, len, neg, quoted; 1579*7c478bd9Sstevel@tonic-gate unsigned long val = 0; 1580*7c478bd9Sstevel@tonic-gate char *str, *buf0; 1581*7c478bd9Sstevel@tonic-gate const char *f; 1582*7c478bd9Sstevel@tonic-gate unsigned char *p; 1583*7c478bd9Sstevel@tonic-gate char num[32]; 1584*7c478bd9Sstevel@tonic-gate static char hexchars[] = "0123456789abcdef"; 1585*7c478bd9Sstevel@tonic-gate 1586*7c478bd9Sstevel@tonic-gate buf0 = buf; 1587*7c478bd9Sstevel@tonic-gate --buflen; 1588*7c478bd9Sstevel@tonic-gate while (buflen > 0) { 1589*7c478bd9Sstevel@tonic-gate for (f = fmt; *f != '%' && *f != 0; ++f) 1590*7c478bd9Sstevel@tonic-gate ; 1591*7c478bd9Sstevel@tonic-gate if (f > fmt) { 1592*7c478bd9Sstevel@tonic-gate len = f - fmt; 1593*7c478bd9Sstevel@tonic-gate if (len > buflen) 1594*7c478bd9Sstevel@tonic-gate len = buflen; 1595*7c478bd9Sstevel@tonic-gate memcpy(buf, fmt, len); 1596*7c478bd9Sstevel@tonic-gate buf += len; 1597*7c478bd9Sstevel@tonic-gate buflen -= len; 1598*7c478bd9Sstevel@tonic-gate fmt = f; 1599*7c478bd9Sstevel@tonic-gate } 1600*7c478bd9Sstevel@tonic-gate if (*fmt == 0) 1601*7c478bd9Sstevel@tonic-gate break; 1602*7c478bd9Sstevel@tonic-gate c = *++fmt; 1603*7c478bd9Sstevel@tonic-gate width = prec = 0; 1604*7c478bd9Sstevel@tonic-gate fillch = ' '; 1605*7c478bd9Sstevel@tonic-gate if (c == '0') { 1606*7c478bd9Sstevel@tonic-gate fillch = '0'; 1607*7c478bd9Sstevel@tonic-gate c = *++fmt; 1608*7c478bd9Sstevel@tonic-gate } 1609*7c478bd9Sstevel@tonic-gate if (c == '*') { 1610*7c478bd9Sstevel@tonic-gate width = va_arg(args, int); 1611*7c478bd9Sstevel@tonic-gate c = *++fmt; 1612*7c478bd9Sstevel@tonic-gate } else { 1613*7c478bd9Sstevel@tonic-gate while (isdigit(c)) { 1614*7c478bd9Sstevel@tonic-gate width = width * 10 + c - '0'; 1615*7c478bd9Sstevel@tonic-gate c = *++fmt; 1616*7c478bd9Sstevel@tonic-gate } 1617*7c478bd9Sstevel@tonic-gate } 1618*7c478bd9Sstevel@tonic-gate if (c == '.') { 1619*7c478bd9Sstevel@tonic-gate c = *++fmt; 1620*7c478bd9Sstevel@tonic-gate if (c == '*') { 1621*7c478bd9Sstevel@tonic-gate prec = va_arg(args, int); 1622*7c478bd9Sstevel@tonic-gate c = *++fmt; 1623*7c478bd9Sstevel@tonic-gate } else { 1624*7c478bd9Sstevel@tonic-gate while (isdigit(c)) { 1625*7c478bd9Sstevel@tonic-gate prec = prec * 10 + c - '0'; 1626*7c478bd9Sstevel@tonic-gate c = *++fmt; 1627*7c478bd9Sstevel@tonic-gate } 1628*7c478bd9Sstevel@tonic-gate } 1629*7c478bd9Sstevel@tonic-gate } 1630*7c478bd9Sstevel@tonic-gate str = 0; 1631*7c478bd9Sstevel@tonic-gate base = 0; 1632*7c478bd9Sstevel@tonic-gate neg = 0; 1633*7c478bd9Sstevel@tonic-gate ++fmt; 1634*7c478bd9Sstevel@tonic-gate switch (c) { 1635*7c478bd9Sstevel@tonic-gate case 'd': 1636*7c478bd9Sstevel@tonic-gate i = va_arg(args, int); 1637*7c478bd9Sstevel@tonic-gate if (i < 0) { 1638*7c478bd9Sstevel@tonic-gate neg = 1; 1639*7c478bd9Sstevel@tonic-gate val = -i; 1640*7c478bd9Sstevel@tonic-gate } else 1641*7c478bd9Sstevel@tonic-gate val = i; 1642*7c478bd9Sstevel@tonic-gate base = 10; 1643*7c478bd9Sstevel@tonic-gate break; 1644*7c478bd9Sstevel@tonic-gate case 'o': 1645*7c478bd9Sstevel@tonic-gate val = va_arg(args, unsigned int); 1646*7c478bd9Sstevel@tonic-gate base = 8; 1647*7c478bd9Sstevel@tonic-gate break; 1648*7c478bd9Sstevel@tonic-gate case 'x': 1649*7c478bd9Sstevel@tonic-gate val = va_arg(args, unsigned int); 1650*7c478bd9Sstevel@tonic-gate base = 16; 1651*7c478bd9Sstevel@tonic-gate break; 1652*7c478bd9Sstevel@tonic-gate case 'p': 1653*7c478bd9Sstevel@tonic-gate val = (unsigned long) va_arg(args, void *); 1654*7c478bd9Sstevel@tonic-gate base = 16; 1655*7c478bd9Sstevel@tonic-gate neg = 2; 1656*7c478bd9Sstevel@tonic-gate break; 1657*7c478bd9Sstevel@tonic-gate case 's': 1658*7c478bd9Sstevel@tonic-gate str = va_arg(args, char *); 1659*7c478bd9Sstevel@tonic-gate break; 1660*7c478bd9Sstevel@tonic-gate case 'c': 1661*7c478bd9Sstevel@tonic-gate num[0] = va_arg(args, int); 1662*7c478bd9Sstevel@tonic-gate num[1] = 0; 1663*7c478bd9Sstevel@tonic-gate str = num; 1664*7c478bd9Sstevel@tonic-gate break; 1665*7c478bd9Sstevel@tonic-gate case 'm': 1666*7c478bd9Sstevel@tonic-gate str = strerror(errno); 1667*7c478bd9Sstevel@tonic-gate break; 1668*7c478bd9Sstevel@tonic-gate case 'v': /* "visible" string */ 1669*7c478bd9Sstevel@tonic-gate case 'q': /* quoted string */ 1670*7c478bd9Sstevel@tonic-gate quoted = c == 'q'; 1671*7c478bd9Sstevel@tonic-gate p = va_arg(args, unsigned char *); 1672*7c478bd9Sstevel@tonic-gate if (fillch == '0' && prec > 0) { 1673*7c478bd9Sstevel@tonic-gate n = prec; 1674*7c478bd9Sstevel@tonic-gate } else { 1675*7c478bd9Sstevel@tonic-gate n = strlen((char *)p); 1676*7c478bd9Sstevel@tonic-gate if (prec > 0 && prec < n) 1677*7c478bd9Sstevel@tonic-gate n = prec; 1678*7c478bd9Sstevel@tonic-gate } 1679*7c478bd9Sstevel@tonic-gate while (n > 0 && buflen > 0) { 1680*7c478bd9Sstevel@tonic-gate c = *p++; 1681*7c478bd9Sstevel@tonic-gate --n; 1682*7c478bd9Sstevel@tonic-gate if (!quoted && c >= 0x80) { 1683*7c478bd9Sstevel@tonic-gate OUTCHAR('M'); 1684*7c478bd9Sstevel@tonic-gate OUTCHAR('-'); 1685*7c478bd9Sstevel@tonic-gate c -= 0x80; 1686*7c478bd9Sstevel@tonic-gate } 1687*7c478bd9Sstevel@tonic-gate if (quoted && (c == '"' || c == '\\')) 1688*7c478bd9Sstevel@tonic-gate OUTCHAR('\\'); 1689*7c478bd9Sstevel@tonic-gate if (c < 0x20 || (0x7f <= c && c < 0xa0)) { 1690*7c478bd9Sstevel@tonic-gate if (quoted) { 1691*7c478bd9Sstevel@tonic-gate OUTCHAR('\\'); 1692*7c478bd9Sstevel@tonic-gate switch (c) { 1693*7c478bd9Sstevel@tonic-gate case '\t': OUTCHAR('t'); break; 1694*7c478bd9Sstevel@tonic-gate case '\n': OUTCHAR('n'); break; 1695*7c478bd9Sstevel@tonic-gate case '\b': OUTCHAR('b'); break; 1696*7c478bd9Sstevel@tonic-gate case '\f': OUTCHAR('f'); break; 1697*7c478bd9Sstevel@tonic-gate default: 1698*7c478bd9Sstevel@tonic-gate OUTCHAR('x'); 1699*7c478bd9Sstevel@tonic-gate OUTCHAR(hexchars[c >> 4]); 1700*7c478bd9Sstevel@tonic-gate OUTCHAR(hexchars[c & 0xf]); 1701*7c478bd9Sstevel@tonic-gate } 1702*7c478bd9Sstevel@tonic-gate } else { 1703*7c478bd9Sstevel@tonic-gate if (c == '\t') 1704*7c478bd9Sstevel@tonic-gate OUTCHAR(c); 1705*7c478bd9Sstevel@tonic-gate else { 1706*7c478bd9Sstevel@tonic-gate OUTCHAR('^'); 1707*7c478bd9Sstevel@tonic-gate OUTCHAR(c ^ 0x40); 1708*7c478bd9Sstevel@tonic-gate } 1709*7c478bd9Sstevel@tonic-gate } 1710*7c478bd9Sstevel@tonic-gate } else 1711*7c478bd9Sstevel@tonic-gate OUTCHAR(c); 1712*7c478bd9Sstevel@tonic-gate } 1713*7c478bd9Sstevel@tonic-gate continue; 1714*7c478bd9Sstevel@tonic-gate default: 1715*7c478bd9Sstevel@tonic-gate *buf++ = '%'; 1716*7c478bd9Sstevel@tonic-gate if (c != '%') 1717*7c478bd9Sstevel@tonic-gate --fmt; /* so %z outputs %z etc. */ 1718*7c478bd9Sstevel@tonic-gate --buflen; 1719*7c478bd9Sstevel@tonic-gate continue; 1720*7c478bd9Sstevel@tonic-gate } 1721*7c478bd9Sstevel@tonic-gate if (base != 0) { 1722*7c478bd9Sstevel@tonic-gate str = num + sizeof(num); 1723*7c478bd9Sstevel@tonic-gate *--str = 0; 1724*7c478bd9Sstevel@tonic-gate while (str > num + neg) { 1725*7c478bd9Sstevel@tonic-gate *--str = hexchars[val % base]; 1726*7c478bd9Sstevel@tonic-gate val = val / base; 1727*7c478bd9Sstevel@tonic-gate if (--prec <= 0 && val == 0) 1728*7c478bd9Sstevel@tonic-gate break; 1729*7c478bd9Sstevel@tonic-gate } 1730*7c478bd9Sstevel@tonic-gate switch (neg) { 1731*7c478bd9Sstevel@tonic-gate case 1: 1732*7c478bd9Sstevel@tonic-gate *--str = '-'; 1733*7c478bd9Sstevel@tonic-gate break; 1734*7c478bd9Sstevel@tonic-gate case 2: 1735*7c478bd9Sstevel@tonic-gate *--str = 'x'; 1736*7c478bd9Sstevel@tonic-gate *--str = '0'; 1737*7c478bd9Sstevel@tonic-gate break; 1738*7c478bd9Sstevel@tonic-gate } 1739*7c478bd9Sstevel@tonic-gate len = num + sizeof(num) - 1 - str; 1740*7c478bd9Sstevel@tonic-gate } else { 1741*7c478bd9Sstevel@tonic-gate len = strlen(str); 1742*7c478bd9Sstevel@tonic-gate if (prec > 0 && len > prec) 1743*7c478bd9Sstevel@tonic-gate len = prec; 1744*7c478bd9Sstevel@tonic-gate } 1745*7c478bd9Sstevel@tonic-gate if (width > 0) { 1746*7c478bd9Sstevel@tonic-gate if (width > buflen) 1747*7c478bd9Sstevel@tonic-gate width = buflen; 1748*7c478bd9Sstevel@tonic-gate if ((n = width - len) > 0) { 1749*7c478bd9Sstevel@tonic-gate buflen -= n; 1750*7c478bd9Sstevel@tonic-gate for (; n > 0; --n) 1751*7c478bd9Sstevel@tonic-gate *buf++ = fillch; 1752*7c478bd9Sstevel@tonic-gate } 1753*7c478bd9Sstevel@tonic-gate } 1754*7c478bd9Sstevel@tonic-gate if (len > buflen) 1755*7c478bd9Sstevel@tonic-gate len = buflen; 1756*7c478bd9Sstevel@tonic-gate memcpy(buf, str, len); 1757*7c478bd9Sstevel@tonic-gate buf += len; 1758*7c478bd9Sstevel@tonic-gate buflen -= len; 1759*7c478bd9Sstevel@tonic-gate } 1760*7c478bd9Sstevel@tonic-gate *buf = 0; 1761*7c478bd9Sstevel@tonic-gate return buf - buf0; 1762*7c478bd9Sstevel@tonic-gate } 1763