diff --git a/usr.sbin/pppd/chat/Makefile b/usr.sbin/pppd/chat/Makefile index 33544e2261ad..61ff127724ea 100644 --- a/usr.sbin/pppd/chat/Makefile +++ b/usr.sbin/pppd/chat/Makefile @@ -1,8 +1,8 @@ -# $Id: Makefile,v 1.1 1993/08/14 06:30:44 deraadt Exp $ +# $Id: Makefile,v 1.2 1994/05/30 01:38:57 paulus Exp $ PROG= chat SRCS= chat.c -NOMAN= noman +MAN8= chat.0 BINDIR= /usr/sbin .include diff --git a/usr.sbin/pppd/chat/chat.8 b/usr.sbin/pppd/chat/chat.8 new file mode 100644 index 000000000000..e5d82bfb0530 --- /dev/null +++ b/usr.sbin/pppd/chat/chat.8 @@ -0,0 +1,251 @@ +.\" -*- nroff -*- +.\" manual page [] for chat 1.8 +.\" $Id: chat.8,v 1.1 1994/05/30 01:38:58 paulus Exp $ +.\" SH section heading +.\" SS subsection heading +.\" LP paragraph +.\" IP indented paragraph +.\" TP hanging label +.TH CHAT 8 "17 April 1994" "Chat Version 1.8" +.SH NAME +chat \- Automated conversational script with a modem +.SH SYNOPSIS +.B chat +[ +.I options +] +.I script +.SH DESCRIPTION +.LP +The \fIchat\fR program defines a conversational exchange between the +computer and the modem. Its primary purpose is to establish the +connection between the Point-to-Point Protocol Daemon (\fIpppd\fR) and +the remote's \fIpppd\fR process. +.SH OPTIONS +.TP +.B -f \fI +Read the chat script from the chat \fIfile\fR. The use of this option +is mutually exclusive with the chat script parameters. The user must +have read access to the file. Multiple lines are permitted in the +file. Space or horizontal tab characters should be used to separate +the strings. +.TP +.B -l \fI +Perform the UUCP style locking using the indicated lock file. +.IP +If the file could not be created then the \fIchat\fR program will +fail. The lock file will be deleted only if the \fIchat\fR program +fails to perform the script for any reason. If the script is +successful the lock file will be left on the disk. It is expected that +the lock file will be deleted when the \fIpppd\fR process no longer +wishes to use the serial device. +.IP +The use of a lock file with +.I chat +and +\fIpppd\fR\'s +.I lock +option should not be used at the same time. They are mutually +exclusive options and will cause one or the other program to fail to +achieve the required lock if you use both. +.TP +.B -t \fI +Set the timeout for the expected string to be received. If the string +is not received within the time limit then the reply string is not +sent. An alternate reply may be sent or the script will fail if there +is no alternate reply string. A failed script will cause the +\fIchat\fR program to terminate with a non-zero error code. +.TP +.B -v +Request that the \fIchat\fR script be executed in a verbose mode. The +\fIchat\fR program will then log all text received from the modem and +the output strings which it sends to the SYSLOG. +.TP +.B script +If the script is not specified in a file with the \fI-f\fR option then +the script is included as parameters to the \fIchat\fR program. +.SH CHAT SCRIPT +.LP +The \fIchat\fR script defines the communications. +.LP +A script consists of one or more "expect-send" pairs of strings, +separated by spaces, with an optional "subexpect-subsend" string pair, +separated by a dash as in the following example: +.IP +ogin:-BREAK-ogin: ppp ssword: hello2u2 +.LP +This line indicates that the \fIchat\fR program should expect the string +"ogin:". If it fails to receive a login prompt within the time interval +allotted, it is to send a break sequence to the remote and then expect the +string "ogin:". If the first "ogin:" is received then the break sequence is +not generated. +.LP +Once it received the login prompt the \fIchat\fR program will send the string ppp +and then expect the prompt "ssword:". When it receives the prompt for the +password, it will send the password hello2u2. +.LP +A carriage return is normally sent following the reply string. It is not +expected in the "expect" string unless it is specifically requested by using +the \\r character sequence. +.LP +The expect sequence should contain only what is needed to identify the +string. Since it is normally stored on a disk file, it should not contain +variable information. It is generally not acceptable to look for time +strings, network identification strings, or other variable pieces of data as +an expect string. +.LP +To help correct for characters which may be corrupted during the initial +sequence, look for the string "ogin:" rather than "login:". It is possible +that the leading "l" character may be received in error and you may never +find the string even though it was sent by the system. For this reason, +scripts look for "ogin:" rather than "login:" and "ssword:" rather than +"password:". +.LP +A very simple script might look like this: +.IP +ogin: ppp ssword: hello2u2 +.LP +In other words, expect ....ogin:, send ppp, expect ...ssword:, send hello2u2. +.LP +In actual practice, simple scripts are rare. At the vary least, you +should include sub-expect sequences should the original string not be +received. For example, consider the following script: +.IP +ogin:--ogin: ppp ssowrd: hello2u2 +.LP +This would be a better script than the simple one used earlier. This would look +for the same login: prompt, however, if one was not received, a single +return sequence is sent and then it will look for login: again. Should line +noise obscure the first login prompt then sending the empty line will +usually generate a login prompt again. +.SH ABORT STRINGS +Many modems will report the status of the call as a string. These +strings may be \fBCONNECTED\fR or \fBNO CARRIER\fR or \fBBUSY\fR. It +is often desirable to terminate the script should the modem fail to +connect to the remote. The difficulty is that a script would not know +exactly which modem string it may receive. On one attempt, it may +receive \fBBUSY\fR while the next time it may receive \fBNO CARRIER\fR. +.LP +These "abort" strings may be specified in the script using the \fIABORT\fR +sequence. It is written in the script as in the following example: +.IP +ABORT BUSY ABORT 'NO CARRIER' '' ATZ OK ATDT5551212 CONNECT +.LP +This sequence will expect nothing; and then send the string ATZ. The +expected response to this is the string \fIOK\fR. When it receives \fIOK\fR, +the string ATDT5551212 to dial the telephone. The expected string is +\fICONNECT\fR. If the string \fICONNECT\fR is received the remainder of the +script is executed. However, should the modem find a busy telephone, it will +send the string \fIBUSY\fR. This will cause the string to match the abort +character sequence. The script will then fail because it found a match to +the abort string. If it received the string \fINO CARRIER\fR, it will abort +for the same reason. Either string may be received. Either string will +terminate the \fIchat\fR script. +.SH TIMEOUT +The initial timeout value is 45 seconds. This may be changed using the \fB-t\fR +parameter. +.LP +To change the timeout value for the next expect string, the following +example may be used: +.IP +ATZ OK ATDT5551212 CONNECT TIMEOUT 10 ogin:--ogin: TIMEOUT 5 assowrd: hello2u2 +.LP +This will change the timeout to 10 seconds when it expects the login: +prompt. The timeout is then changed to 5 seconds when it looks for the +password prompt. +.LP +The timeout, once changed, remains in effect until it is changed again. +.SH SENDING EOT +The special reply string of \fIEOT\fR indicates that the chat program +should send an EOT character to the remote. This is normally the +End-of-file character sequence. A return character is not sent +following the EOT. +.PR +The EOT sequence may be embedded into the send string using the +sequence \fI^D\fR. +.SH GENERATING BREAK +The special reply string of \fIBREAK\fR will cause a break condition +to be sent. The break is a special signal on the transmitter. The +normal processing on the receiver is to change the transmission rate. +It may be used to cycle through the available transmission rates on +the remote until you are able to receive a valid login prompt. +.PR +The break sequence may be embedded into the send string using the +\fI\\K\fR sequence. +.SH ESCAPE SEQUENCES +The expect and reply strings may contain escape sequences. All of the +sequences are legal in the reply string. Many are legal in the expect. +Those which are not valid in the expect sequence are so indicated. +.TP +.B '' +Expects or sends a null string. If you send a null string then it will still +send the return character. This sequence may either be a pair of apostrophe +or quote characters. +.TP +.B \\\\b +represents a backspace character. +.TP +.B \\\\c +Suppresses the newline at the end of the reply string. This is the only +method to send a string without a trailing return character. It must +be at the end of the send string. For example, +the sequence hello\\c will simply send the characters h, e, l, l, o. +.I (not valid in expect.) +.TP +.B \\\\d +Delay for one second. The program uses sleep(1) which will delay to a +maximum of one second. +.I (not valid in expect.) +.TP +.B \\\\K +Insert a BREAK +.I (not valid in expect.) +.TP +.B \\\\n +Send a newline or linefeed character. +.TP +.B \\\\N +Send a null character. The same sequence may be represented by \\0. +.I (not valid in expect.) +.TP +.B \\\\p +Pause for a fraction of a second. The delay is 1/10th of a second. +.I (not valid in expect.) +.TP +.B \\\\q +Suppress writing the string to the SYSLOG file. The string ?????? is +written to the log in its place. +.I (not valid in expect.) +.TP +.B \\\\r +Send or expect a carriage return. +.TP +.B \\\\s +Represents a space character in the string. This may be used when it +is not desirable to quote the strings which contains spaces. The +sequence 'HI TIM' and HI\\sTIM are the same. +.TP +.B \\\\t +Send or expect a tab character. +.TP +.B \\\\\\\\ +Send or expect a backslash character. +.TP +.B \\\\ddd +Collapse the octal digits (ddd) into a single ASCII character and send that +character. +.I (some characters are not valid in expect.) +.TP +.B \^^C +Substitute the sequence with the control character represented by C. +For example, the character DC1 (17) is shown as \^^Q. +.I (some characters are not valid in expect.) +.SH SEE ALSO +Additional information about \fIchat\fR scripts may be found with UUCP +documentation. The \fIchat\fR script was taken from the ideas proposed by the +scripts used by the \fIuucico\fR program. +.LP +uucico(1), uucp(1) +.SH COPYRIGHT +The \fIchat\fR program is in public domain. This is not the GNU public +license. If it breaks then you get to keep both pieces. diff --git a/usr.sbin/pppd/chat/chat.c b/usr.sbin/pppd/chat/chat.c index 892e2d445014..1fbbb2385eba 100644 --- a/usr.sbin/pppd/chat/chat.c +++ b/usr.sbin/pppd/chat/chat.c @@ -6,6 +6,11 @@ * * Please send all bug reports, requests for information, etc. to: * + * Al Longyear (longyear@netcom.com) + * (I was the last person to change this code.) + * + * The original author is: + * * Karl Fox * Morning Star Technologies, Inc. * 1760 Zollinger Road @@ -13,19 +18,20 @@ * (614)451-1883 */ -/*static char sccs_id[] = "@(#)chat.c 1.7";*/ -static char rcsid[] = "$Id: chat.c,v 1.4 1993/11/09 04:57:19 paulus Exp $"; +static char rcsid[] = "$Id: chat.c,v 1.5 1994/05/30 01:39:00 paulus Exp $"; #include #include #include #include +#include +#include #include #include -#include #include #ifndef TERMIO +#undef TERMIOS #define TERMIOS #endif @@ -50,6 +56,14 @@ static char rcsid[] = "$Id: chat.c,v 1.4 1993/11/09 04:57:19 paulus Exp $"; #define SIGTYPE void #endif +#ifdef __STDC__ +#undef __P +#define __P(x) x +#else +#define __P(x) () +#define const +#endif + /*************** Micro getopt() *********************************************/ #define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ @@ -64,10 +78,6 @@ static int _O = 0; /* Internal state */ char *program_name; -extern char *strcpy(), *strcat(), *malloc(); -extern int strlen(); -#define copyof(s) ((s) ? strcpy(malloc(strlen(s) + 1), s) : (s)) - #ifndef LOCK_DIR # ifdef __NetBSD__ # define PIDSTRING @@ -88,6 +98,7 @@ extern int strlen(); int verbose = 0; int quiet = 0; char *lock_file = (char *)0; +char *chat_file = (char *)0; int timeout = DEFAULT_CHAT_TIMEOUT; int have_tty_parameters = 0; @@ -102,17 +113,69 @@ char *abort_string[MAX_ABORTS], *fail_reason = (char *)0, fail_buffer[50]; int n_aborts = 0, abort_next = 0, timeout_next = 0; +void *dup_mem __P((void *b, size_t c)); +void *copy_of __P((char *s)); +void usage __P((void)); +void logf __P((const char *str)); +void logflush __P((void)); +void fatal __P((const char *msg)); +void sysfatal __P((const char *msg)); +SIGTYPE sigalrm __P((int signo)); +SIGTYPE sigint __P((int signo)); +SIGTYPE sigterm __P((int signo)); +SIGTYPE sighup __P((int signo)); +void unalarm __P((void)); +void init __P((void)); +void set_tty_parameters __P((void)); +void break_sequence __P((void)); +void terminate __P((int status)); +void do_file __P((char *chat_file)); +void lock __P((void)); +void delay __P((void)); +int get_string __P((register char *string)); +int put_string __P((register char *s)); +int write_char __P((int c)); +int put_char __P((char c)); +int get_char __P((void)); +void chat_send __P((register char *s)); +char *character __P((char c)); +void chat_expect __P((register char *s)); +char *clean __P((register char *s, int sending)); +void unlock __P((void)); +void lock __P((void)); +void break_sequence __P((void)); +void terminate __P((int status)); +void die __P((void)); + +void *dup_mem(b, c) +void *b; +size_t c; + { + void *ans = malloc (c); + if (!ans) + fatal ("memory error!\n"); + memcpy (ans, b, c); + return ans; + } + +void *copy_of (s) +char *s; + { + return dup_mem (s, strlen (s) + 1); + } + /* - * chat [ -v ] [ -t timeout ] [ -l lock-file ] \ + * chat [ -v ] [ -t timeout ] [ -l lock-file ] [ -f chat-file ] \ * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] * * Perform a UUCP-dialer-like chat script on stdin and stdout. */ +int main(argc, argv) int argc; char **argv; { - int option, n; + int option; char *arg; program_name = *argv; @@ -124,9 +187,17 @@ char **argv; ++verbose; break; + case 'f': + if (arg = OPTARG(argc, argv)) + chat_file = copy_of(arg); + else + usage(); + + break; + case 'l': if (arg = OPTARG(argc, argv)) - lock_file = copyof(arg); + lock_file = copy_of(arg); else usage(); @@ -144,6 +215,9 @@ char **argv; usage(); } +#ifdef ultrix + openlog("chat", LOG_PID); +#else openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); if (verbose) { @@ -151,55 +225,164 @@ char **argv; } else { setlogmask(LOG_UPTO(LOG_WARNING)); } +#endif init(); - while (arg = ARG(argc, argv)) + if (chat_file != NULL) { - chat_expect(arg); + arg = ARG(argc, argv); + if (arg != NULL) + usage(); + else + do_file (chat_file); + } + else + { + while (arg = ARG(argc, argv)) + { + chat_expect(arg); - if (arg = ARG(argc, argv)) - chat_send(arg); + if (arg = ARG(argc, argv)) + chat_send(arg); + } } terminate(0); } +/* + * Process a chat script when read from a file. + */ + +void do_file (chat_file) +char *chat_file; + { + int linect, len, sendflg; + char *sp, *arg, quote; + char buf [STR_LEN]; + FILE *cfp; + + if ((cfp = fopen (chat_file, "r")) == NULL) + { + syslog (LOG_ERR, "%s -- open failed: %m", chat_file); + terminate (1); + } + + linect = 0; + sendflg = 0; + + while (fgets(buf, STR_LEN, cfp) != NULL) + { + sp = strchr (buf, '\n'); + if (sp) + *sp = '\0'; + + linect++; + sp = buf; + while (*sp != '\0') + { + if (*sp == ' ' || *sp == '\t') + { + ++sp; + continue; + } + + if (*sp == '"' || *sp == '\'') + { + quote = *sp++; + arg = sp; + while (*sp != quote) + { + if (*sp == '\0') + { + syslog (LOG_ERR, "unterminated quote (line %d)", + linect); + terminate (1); + } + + if (*sp++ == '\\') + if (*sp != '\0') + ++sp; + } + } + else + { + arg = sp; + while (*sp != '\0' && *sp != ' ' && *sp != '\t') + ++sp; + } + + if (*sp != '\0') + *sp++ = '\0'; + + if (sendflg) + { + chat_send (arg); + } + else + { + chat_expect (arg); + } + sendflg = !sendflg; + } + } + fclose (cfp); + } + /* * We got an error parsing the command line. */ -usage() +void usage() { - fprintf(stderr, - "Usage: %s [ -v ] [ -l lock-file ] [ -t timeout ] chat-script\n", + fprintf(stderr, "\ +Usage: %s [-v] [-l lock-file] [-t timeout] {-f chat-file || chat-script}\n", program_name); exit(1); } -/* - * Print a warning message. - */ -/*VARARGS1*/ -warn(format, arg1, arg2, arg3, arg4) -char *format; -int arg1, arg2, arg3, arg4; +char line[256]; +char *p; + +void logf (str) +const char *str; { - logf("%s: Warning: ", program_name); - logf(format, arg1, arg2, arg3, arg4); - logf("\n"); + p = line + strlen(line); + strcat (p, str); + + if (str[strlen(str)-1] == '\n') + { + syslog (LOG_INFO, "%s", line); + line[0] = 0; + } + } + +void logflush() + { + if (line[0] != 0) + { + syslog(LOG_INFO, "%s", line); + line[0] = 0; + } + } + +/* + * Unlock and terminate with an error. + */ +void die() + { + unlock(); + terminate(1); } /* * Print an error message and terminate. */ -/*VARARGS1*/ -fatal(format, arg1, arg2, arg3, arg4) -char *format; -int arg1, arg2, arg3, arg4; + +void fatal (msg) +const char *msg; { - logf("%s: ", program_name); - logf(format, arg1, arg2, arg3, arg4); - logf("\n"); + syslog(LOG_ERR, "%s", msg); unlock(); terminate(1); } @@ -208,30 +391,27 @@ int arg1, arg2, arg3, arg4; * Print an error message along with the system error message and * terminate. */ -/*VARARGS1*/ -sysfatal(format, arg1, arg2, arg3, arg4) -char *format; -int arg1, arg2, arg3, arg4; - { - char message[STR_LEN]; - sprintf(message, "%s: ", program_name); - sprintf(message + strlen(message), format, arg1, arg2, arg3, arg4); - perror(message); +void sysfatal (msg) +const char *msg; + { + syslog(LOG_ERR, "%s: %m", msg); unlock(); terminate(1); } int alarmed = 0; -SIGTYPE - sigalrm() -{ +SIGTYPE sigalrm(signo) +int signo; + { int flags; - alarm(1); alarmed = 1; /* Reset alarm to avoid race window */ + alarm(1); + alarmed = 1; /* Reset alarm to avoid race window */ signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ + logflush(); if ((flags = fcntl(0, F_GETFL, 0)) == -1) sysfatal("Can't get file mode flags on stdin"); else @@ -240,11 +420,11 @@ SIGTYPE if (verbose) { - logf("alarm\n"); + syslog(LOG_INFO, "alarm"); } } -unalarm() +void unalarm() { int flags; @@ -255,25 +435,25 @@ unalarm() sysfatal("Can't set file mode flags on stdin"); } -SIGTYPE - sigint() -{ - fatal("SIGINT"); -} +SIGTYPE sigint(signo) +int signo; + { + fatal("SIGINT"); + } -SIGTYPE - sigterm() -{ - fatal("SIGTERM"); -} +SIGTYPE sigterm(signo) +int signo; + { + fatal("SIGTERM"); + } -SIGTYPE - sighup() -{ - fatal("SIGHUP"); -} +SIGTYPE sighup(signo) +int signo; + { + fatal("SIGHUP"); + } -init() +void init() { signal(SIGINT, sigint); signal(SIGTERM, sigterm); @@ -284,11 +464,11 @@ init() set_tty_parameters(); signal(SIGALRM, sigalrm); - alarm(0); alarmed = 0; + alarm(0); + alarmed = 0; } - -set_tty_parameters() +void set_tty_parameters() { #ifdef TERMIO struct termio t; @@ -306,9 +486,9 @@ set_tty_parameters() saved_tty_parameters = t; have_tty_parameters = 1; - t.c_iflag = IGNBRK | ISTRIP | IGNPAR; - t.c_oflag = 0; - t.c_lflag = 0; + t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; + t.c_oflag = 0; + t.c_lflag = 0; t.c_cc[VERASE] = t.c_cc[VKILL] = 0; t.c_cc[VMIN] = 1; t.c_cc[VTIME] = 0; @@ -323,31 +503,40 @@ set_tty_parameters() #endif } +void break_sequence() + { +#ifdef TERMIOS + tcsendbreak (0, 0); +#endif + } -terminate(status) -{ - if (have_tty_parameters && +void terminate(status) +int status; + { + if (have_tty_parameters && #ifdef TERMIO - ioctl(0, TCSETA, &saved_tty_parameters) < 0 + ioctl(0, TCSETA, &saved_tty_parameters) < 0 #endif #ifdef TERMIOS - tcsetattr(0, TCSANOW, &saved_tty_parameters) < 0 + tcsetattr(0, TCSANOW, &saved_tty_parameters) < 0 #endif - ) { - perror("Can't restore terminal parameters"); - unlock(); - exit(1); - } - exit(status); -} + ) { + syslog(LOG_ERR, "Can't restore terminal parameters: %m"); + unlock(); + exit(1); + } + exit(status); + } /* * Create a lock file for the named lock device */ -lock() +void lock() { - char hdb_lock_buffer[12]; int fd, pid; +# ifdef PIDSTRING + char hdb_lock_buffer[12]; +# endif lock_file = strcat(strcat(strcpy(malloc(strlen(LOCK_DIR) + 1 + strlen(lock_file) + 1), @@ -356,9 +545,9 @@ lock() if ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { char *s = lock_file; - lock_file = (char *)0; /* Don't remove someone else's lock file! */ - sysfatal("Can't get lock file '%s'", s); + syslog(LOG_ERR, "Can't get lock file '%s': %m", s); + die(); } # ifdef PIDSTRING @@ -375,7 +564,7 @@ lock() /* * Remove our lockfile */ -unlock() +void unlock() { if (lock_file) { @@ -391,59 +580,142 @@ char *clean(s, sending) register char *s; int sending; { - char temp[STR_LEN]; + char temp[STR_LEN], cur_chr; register char *s1; int add_return = sending; +#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) - for (s1 = temp; *s; ++s) - switch (*s) - { - case '\\': - switch (*++s) - { - case '\\': - case 'd': if (sending) - *s1++ = '\\'; + s1 = temp; + while (*s) + { + cur_chr = *s++; + if (cur_chr == '^') + { + cur_chr = *s++; + if (cur_chr == '\0') + { + *s1++ = '^'; + break; + } + cur_chr &= 0x1F; + if (cur_chr != 0) + *s1++ = cur_chr; + continue; + } - *s1++ = *s; - break; + if (cur_chr != '\\') + { + *s1++ = cur_chr; + continue; + } - case 'q': quiet = ! quiet; break; - case 'r': *s1++ = '\r'; break; - case 'n': *s1++ = '\n'; break; - case 's': *s1++ = ' '; break; + cur_chr = *s++; + if (cur_chr == '\0') + { + if (sending) + { + *s1++ = '\\'; + *s1++ = '\\'; + } + break; + } - case 'c': if (sending && s[1] == '\0') - add_return = 0; - else - *s1++ = *s; + switch (cur_chr) + { + case 'b': + *s1++ = '\b'; + break; - break; + case 'c': + if (sending && *s == '\0') + add_return = 0; + else + *s1++ = cur_chr; + break; - default: *s1++ = *s; - } + case '\\': + case 'K': + case 'p': + case 'd': + if (sending) + *s1++ = '\\'; - break; + *s1++ = cur_chr; + break; - case '^': - *s1++ = (int)(*++s) & 0x1F; - break; + case 'q': + quiet = ! quiet; + break; + + case 'r': + *s1++ = '\r'; + break; + + case 'n': + *s1++ = '\n'; + break; + + case 's': + *s1++ = ' '; + break; + + case 't': + *s1++ = '\t'; + break; + + case 'N': + if (sending) + { + *s1++ = '\\'; + *s1++ = '\0'; + } + else + *s1++ = 'N'; + break; + + default: + if (isoctal (cur_chr)) + { + cur_chr &= 0x07; + if (isoctal (*s)) + { + cur_chr <<= 3; + cur_chr |= *s++ - '0'; + if (isoctal (*s)) + { + cur_chr <<= 3; + cur_chr |= *s++ - '0'; + } + } + + if (cur_chr != 0 || sending) + { + if (sending && (cur_chr == '\\' || cur_chr == 0)) + *s1++ = '\\'; + *s1++ = cur_chr; + } + break; + } + + if (sending) + *s1++ = '\\'; + *s1++ = cur_chr; + break; + } + } - default: - *s1++ = *s; - } - if (add_return) *s1++ = '\r'; - *s1 = '\0'; - return (copyof(temp)); + *s1++ = '\0'; /* guarantee closure */ + *s1++ = '\0'; /* terminate the string */ + return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ } /* - * + * Process the expect string */ -chat_expect(s) +void chat_expect(s) register char *s; { if (strcmp(s, "ABORT") == 0) @@ -502,9 +774,9 @@ register char *s; else { if (fail_reason) - logf("Failed(%s)\n", fail_reason); + syslog(LOG_INFO, "Failed (%s)", fail_reason); else - logf("Failed\n"); + syslog(LOG_INFO, "Failed"); unlock(); terminate(1); @@ -533,9 +805,9 @@ char c; } /* - * + * process the reply string */ -chat_send(s) +void chat_send (s) register char *s; { if (abort_next) @@ -549,23 +821,20 @@ register char *s; s1 = clean(s, 0); - if (strlen(s1) > strlen(s)) - fatal("Illegal ABORT string ('%s')\n", s); + if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) + { + syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s); + die(); + } - if (strlen(s1) > sizeof fail_buffer - 1) - fatal("Too long ABORT string ('%s')\n", s); - - strcpy(s, s1); - abort_string[n_aborts++] = s; + abort_string[n_aborts++] = s1; if (verbose) { - register char *s1 = s; - logf("abort on ("); for (s1 = s; *s1; ++s1) - logf("%s", character(*s1)); + logf(character(*s1)); logf(")\n"); } @@ -581,16 +850,23 @@ register char *s; if (verbose) { - logf("timeout set to %d seconds\n", timeout); + syslog(LOG_INFO, "timeout set to %d seconds", timeout); } } else + { + if (strcmp(s, "EOT") == 0) + s = "^D\\c"; + else + if (strcmp(s, "BREAK") == 0) + s = "\\K\\c"; if ( ! put_string(s)) { - logf("Failed\n"); + syslog(LOG_INFO, "Failed"); unlock(); terminate(1); } + } } int get_char() @@ -606,7 +882,8 @@ int get_char() return ((int)c & 0x7F); default: - warn("read() on stdin returned %d", status); + syslog(LOG_WARNING, "warning: read() on stdin returned %d", + status); case -1: if ((status = fcntl(0, F_GETFL, 0)) == -1) @@ -634,7 +911,8 @@ char c; return (0); default: - warn("write() on stdout returned %d", status); + syslog(LOG_WARNING, "warning: write() on stdout returned %d", + status); case -1: if ((status = fcntl(0, F_GETFL, 0)) == -1) @@ -647,7 +925,28 @@ char c; } } -int put_string(s) +int write_char (c) +int c; + { + if (alarmed || put_char(c) < 0) + { + extern int errno; + + alarm(0); alarmed = 0; + + if (verbose) + { + if (errno == EINTR || errno == EWOULDBLOCK) + syslog(LOG_INFO, " -- write timed out"); + else + syslog(LOG_INFO, " -- write failed: %m"); + } + return (0); + } + return (1); + } + +int put_string (s) register char *s; { s = clean(s, 1); @@ -663,7 +962,7 @@ register char *s; register char *s1 = s; for (s1 = s; *s1; ++s1) - logf("%s", character(*s1)); + logf(character(*s1)); } logf(")\n"); @@ -671,39 +970,41 @@ register char *s; alarm(timeout); alarmed = 0; - for ( ; *s; ++s) + while (*s) { - register char c = *s; + register char c = *s++; - if (c == '\\') - if ((c = *++s) == '\0') - break; - else - if (c == 'd') /* \d -- Delay */ - { - sleep(2); - continue; - } - - if (alarmed || put_char(*s) < 0) + if (c != '\\') { - extern int errno; + if (!write_char (c)) + return 0; + continue; + } - alarm(0); alarmed = 0; + c = *s++; + switch (c) + { + case 'd': + sleep(1); + break; - if (verbose) - { - if (errno == EINTR || errno == EWOULDBLOCK) - logf(" -- write timed out\n"); - else - syslog(LOG_INFO, " -- write failed: %m"); - } + case 'K': + break_sequence(); + break; - return (0); + case 'p': + usleep(10000); /* 1/100th of a second. */ + break; + + default: + if (!write_char (c)) + return 0; + break; } } - alarm(0); alarmed = 0; + alarm(0); + alarmed = 0; return (1); } @@ -729,22 +1030,22 @@ register char *string; logf("expect ("); for (s1 = string; *s1; ++s1) - logf("%s", character(*s1)); + logf(character(*s1)); logf(")\n"); } if (len > STR_LEN) { - logf("expect string is too long\n"); - return; + syslog(LOG_INFO, "expect string is too long"); + return 0; } if (len == 0) { if (verbose) { - logf("got it\n"); + syslog(LOG_INFO, "got it"); } return (1); @@ -761,7 +1062,7 @@ register char *string; if (c == '\n') logf("\n"); else - logf("%s", character(c)); + logf(character(c)); } *s++ = c; @@ -772,7 +1073,7 @@ register char *string; { if (verbose) { - logf("got it\n"); + logf(" -- got it\n"); } alarm(0); alarmed = 0; @@ -800,59 +1101,66 @@ register char *string; } if (alarmed && verbose) - warn("Alarm synchronization problem"); + syslog(LOG_WARNING, "warning: alarm synchronization problem"); } alarm(0); if (verbose && printed) { - extern int errno; - if (alarmed) logf(" -- read timed out\n"); else + { + logflush(); syslog(LOG_INFO, " -- read failed: %m"); + } } alarmed = 0; return (0); } +#ifdef ultrix +#undef NO_USLEEP +#include +#include + +/* + usleep -- support routine for 4.2BSD system call emulations + last edit: 29-Oct-1984 D A Gwyn + */ + +extern int select(); + +int +usleep( usec ) /* returns 0 if ok, else -1 */ + long usec; /* delay in microseconds */ +{ + static struct /* `timeval' */ + { + long tv_sec; /* seconds */ + long tv_usec; /* microsecs */ + } delay; /* _select() timeout */ + + delay.tv_sec = usec / 1000000L; + delay.tv_usec = usec % 1000000L; + + return select( 0, (long *)0, (long *)0, (long *)0, &delay ); +} +#endif + /* * Delay an amount appropriate for between typed characters. */ -delay() +void delay() { +# ifdef NO_USLEEP register int i; -# ifdef NO_USLEEP for (i = 0; i < 30000; ++i) /* ... did we just say appropriate? */ ; # else /* NO_USLEEP */ usleep(100); # endif /* NO_USLEEP */ } - -char line[256]; -char *p; - -logf(fmt, va_alist) -char *fmt; -va_dcl -{ - va_list pvar; - char buf[256]; - - va_start(pvar); - vsprintf(buf, fmt, pvar); - va_end(pvar); - - p = line + strlen(line); - strcat(p, buf); - - if (buf[strlen(buf)-1] == '\n') { - syslog(LOG_INFO, "%s", line); - line[0] = 0; - } -}