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