Index: usr.bin/Makefile =================================================================== --- usr.bin/Makefile +++ usr.bin/Makefile @@ -15,7 +15,6 @@ bzip2 \ bzip2recover \ cap_mkdb \ - chat \ chpass \ cksum \ cmp \ Index: usr.bin/chat/Makefile =================================================================== --- usr.bin/chat/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# $FreeBSD$ - -# I once used this extensively, but no longer have a modem. Feel free -# to ask me questions about it, but I disclaim ownership now. -Peter - -PROG= chat -MAN= chat.8 - -.include Index: usr.bin/chat/Makefile.depend =================================================================== --- usr.bin/chat/Makefile.depend +++ /dev/null @@ -1,17 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: usr.bin/chat/chat.8 =================================================================== --- usr.bin/chat/chat.8 +++ /dev/null @@ -1,644 +0,0 @@ -.\" $FreeBSD$ -.Dd September 10, 2012 -.Dt CHAT 8 -.Os -.Sh NAME -.Nm chat -.Nd Automated conversational script with a modem -.Sh SYNOPSIS -.Nm -.Op Fl eSsVv -.Op Fl f Ar chat-file -.Op Fl r Ar report-file -.Op Fl T Ar phone-number -.Op Fl t Ar timeout -.Op Fl U Ar phone-number2 -.Op Ar script -.Sh DESCRIPTION -The -.Nm -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 -.Pq pppd -and the remote's pppd process. -.Sh OPTIONS -.Bl -tag -width indent -.It Fl e -Start with the echo option turned on. -Echoing may also be turned on -or off at specific points in the chat script by using the ECHO -keyword. -When echoing is enabled, all output from the modem is echoed -to -.Em stderr . -.It Fl f Ar chat-file -Read the chat script from the chat file. -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. -.It Fl r Ar report-file -Set the file for output of the report strings. -If you use the keyword -.Dv REPORT , -the resulting strings are written to this file. -If this -option is not used and you still use -.Dv REPORT -keywords, the -.Pa stderr -file is used for the report strings. -.It Fl S -Do not use -.Xr syslog 3 . -By default, error messages are sent to -.Xr syslog 3 . -The use of -.Fl S -will prevent both log messages from -.Fl v -and error messages from being sent to -.Xr syslog 3 . -.It Fl s -Use -.Em stderr . -All log messages from -.Fl v -and all error messages will be -sent to -.Em stderr . -.It Fl T Ar phone-number -Pass in an arbitrary string, usually a phone number, that will be -substituted for the \\T substitution metacharacter in a send string. -.It Fl t Ar timeout -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 -.Nm -program to terminate with a non-zero error code. -.It Fl U Ar phone-number2 -Pass in a second string, usually a phone number, that will be -substituted for the \\U substitution metacharacter in a send string. -This is useful when dialing an ISDN terminal adapter that requires two -numbers. -.It Fl V -Request that the -.Nm -script be executed in a -.Em stderr -verbose mode. -The -.Nm -program will then log all text received from the -modem and the output strings sent to the modem to the stderr device. -This -device is usually the local console at the station running the chat or -pppd program. -.It Fl v -Request that the -.Nm -script be executed in a verbose mode. -The -.Nm -program will then log the execution state of the chat -script as well as all text received from the modem and the output -strings sent to the modem. -The default is to log through -.Xr syslog 3 ; -the logging method may be altered with the -.Fl S -and -.Fl s -flags. -Logging is done to the -.Em local2 -facility at level -.Em info -for verbose tracing and level -.Em err -for some errors. -.El -.Sh CHAT SCRIPT -The -.Nm -script defines the communications. -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: -.Pp -.D1 ogin:-BREAK-ogin: ppp ssword: hello2u2 -.Pp -This line indicates that the -.Nm -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. -.Pp -Once it received the login prompt the -.Nm -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. -.Pp -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. -.Pp -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. -.Pp -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:". -.Pp -A very simple script might look like this: -.Pp -.D1 ogin: ppp ssword: hello2u2 -.Pp -In other words, expect ....ogin:, send ppp, expect ...ssword:, send hello2u2. -.Pp -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: -.Pp -.D1 ogin:--ogin: ppp ssword: hello2u2 -.Pp -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 COMMENTS -Comments can be embedded in the chat script. -A comment is a line which -starts with the # (hash) character in column 1. -Such comment -lines are just ignored by the chat program. -If a '#' character is to -be expected as the first character of the expect sequence, you should -quote the expect string. -If you want to wait for a prompt that starts with a # (hash) -character, you would have to write something like this: -.Bd -literal -offset indent -# Now wait for the prompt and send logout string -\&'# ' logout -.Ed -.Sh ABORT STRINGS -Many modems will report the status of the call as a string. -These strings may be -.Dv CONNECTED -or -.Dv NO CARRIER -or -.Dv BUSY . -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 -.Dv BUSY -while the next time it may receive -.Dv NO CARRIER . -.Pp -These "abort" strings may be specified in the script using the ABORT -sequence. -It is written in the script as in the following example: -.Pp -.D1 ABORT BUSY ABORT 'NO CARRIER' '' ATZ OK ATDT5551212 CONNECT -.Pp -This sequence will expect nothing; and then send the string ATZ. -The expected response to this is the string -.Dv OK . -When it receives -.Dv OK , -the string ATDT5551212 to dial the telephone. -The expected string is -.Dv CONNECT . -If the string -.Dv CONNECT -is received the remainder of the -script is executed. -However, should the modem find a busy telephone, it will -send the string -.Dv BUSY . -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 -.Dv NO CARRIER , -it will abort -for the same reason. -Either string may be received. -Either string will -terminate the -.Nm -script. -.Sh CLR_ABORT STRINGS -This sequence allows for clearing previously set -.Dv ABORT -strings. -.Dv ABORT -strings are kept in an array of a pre-determined size (at -compilation time); CLR_ABORT will reclaim the space for cleared -entries so that new strings can use that space. -.Sh SAY STRINGS -The -.Dv SAY -directive allows the script to send strings to the user -at the terminal via standard error. -If -.Nm -is being run by -pppd, and pppd is running as a daemon (detached from its controlling -terminal), standard error will normally be redirected to the file -.Pa /etc/ppp/connect-errors . -.Pp -.Dv SAY -strings must be enclosed in single or double quotes. -If carriage return and line feed are needed in the string to be output, -you must explicitly add them to your string. -.Pp -The -.Dv SAY -strings could be used to give progress messages in sections of -the script where you want to have 'ECHO OFF' but still let the user -know what is happening. An example is: -.Bd -literal -offset indent -ABORT BUSY -ECHO OFF -SAY "Dialling your ISP...\\n" -\&'' ATDT5551212 -TIMEOUT 120 -SAY "Waiting up to 2 minutes for connection ... " -CONNECT '' -SAY "Connected, now logging in ...\\n" -ogin: account -ssword: pass -$ SAY "Logged in OK ...\\n" \fIetc ...\fR -.Ed -.Pp -This sequence will only present the -.Dv SAY -strings to the user and all -the details of the script will remain hidden. -For example, if the -above script works, the user will see: -.Bd -literal -offset indent -Dialling your ISP... -Waiting up to 2 minutes for connection ... Connected, now logging in ... -Logged in OK ... -.Ed -.Sh REPORT STRINGS -A report string is similar to the -.Dv ABORT -string. -The difference -is that the strings, and all characters to the next control character -such as a carriage return, are written to the report file. -.Pp -The report strings may be used to isolate the transmission rate of the -modem's connect string and return the value to the chat user. -The -analysis of the report string logic occurs in conjunction with the -other string processing such as looking for the expect string. -The use -of the same string for a report and abort sequence is probably not -very useful, however, it is possible. -.Pp -The report strings to no change the completion code of the program. -.Pp -These "report" strings may be specified in the script using the -.Dv REPORT -sequence. -It is written in the script as in the following example: -.Pp -.D1 REPORT CONNECT ABORT BUSY '' ATDT5551212 CONNECT '' ogin: account -.Pp -This sequence will expect nothing; and then send the string -ATDT5551212 to dial the telephone. -The expected string is -.Dv CONNECT . -If the string -.Dv CONNECT -is received the remainder -of the script is executed. -In addition the program will write to the -expect-file the string "CONNECT" plus any characters which follow it -such as the connection rate. -.Sh CLR_REPORT STRINGS -This sequence allows for clearing previously set -.Dv REPORT -strings. -.Dv REPORT -strings are kept in an array of a pre-determined size (at -compilation time); CLR_REPORT will reclaim the space for cleared -entries so that new strings can use that space. -.Sh ECHO -The echo options controls whether the output from the modem is echoed -to -.Em stderr . -This option may be set with the -.Fl e -option, but -it can also be controlled by the -.Dv ECHO -keyword. -The "expect-send" -pair -.Dv ECHO ON -enables echoing, and -.Dv ECHO OFF -disables it. -With this keyword you can select which parts of the -conversation should be visible. -For instance, with the following -script: -.Bd -literal -offset indent -ABORT 'BUSY' -ABORT 'NO CARRIER' -\&'' ATZ -OK\\r\\n ATD1234567 -\\r\\n \\c -ECHO ON -CONNECT \\c -ogin: account -.Ed -.Pp -all output resulting from modem configuration and dialing is not visible, -but starting with the -.Dv CONNECT -or -.Dv BUSY -message, everything -will be echoed. -.Sh HANGUP -The -.Dv HANGUP -options control whether a modem hangup should be considered -as an error or not. -This option is useful in scripts for dialling -systems which will hang up and call your system back. -The -.Dv HANGUP -options can be -.Dv ON -or -.Dv OFF . -.Pp -When -.Dv HANGUP -is set -.Dv OFF -and the modem hangs up (e.g., after the first -stage of logging in to a callback system), -.Nm -will continue -running the script (e.g., waiting for the incoming call and second -stage login prompt). -As soon as the incoming call is connected, you -should use the -.Dv HANGUP ON -directive to reinstall normal hang up -signal behavior. -Here is a (simple) example script: -.Bd -literal -offset indent -ABORT 'BUSY' -\&'' ATZ -OK\\r\\n ATD1234567 -\\r\\n \\c -CONNECT \\c -\&'Callback login:' call_back_ID -HANGUP OFF -ABORT "Bad Login" -\&'Callback Password:' Call_back_password -TIMEOUT 120 -CONNECT \\c -HANGUP ON -ABORT "NO CARRIER" -ogin:--BREAK--ogin: real_account -\fIetc ...\fR -.Ed -.Sh TIMEOUT -The initial timeout value is 45 seconds. -This may be changed using the -.Fl t -parameter. -.Pp -To change the timeout value for the next expect string, the following -example may be used: -.Bd -literal -offset indent -ATZ OK ATDT5551212 CONNECT TIMEOUT 10 ogin:--ogin: TIMEOUT 5 assword: hello2u2 -.Ed -.Pp -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. -.Pp -The timeout, once changed, remains in effect until it is changed again. -.Sh SENDING EOT -The special reply string of -.Dv EOT -indicates that the chat program -should send an -.Dv EOT -character to the remote. -This is normally the -End-of-file character sequence. -A return character is not sent -following the -.Dv EOT . -.Pp -The -.Dv EOT -sequence may be embedded into the send string using the -sequence ^D. -.Sh GENERATING BREAK -The special reply string of -.Dv BREAK -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. -.Pp -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. -.Bl -tag -width indent -.It '' -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. -.It \eb -represents a backspace character. -.It \ec -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 -.Pq Em not valid in expect . -.It \ed -Delay for one second. -The program uses sleep(1) which will delay to a -maximum of one second -.Pq Em not valid in expect . -.It \eK -Insert a -.Dv BREAK -.Pq Em not valid in expect . -.It \en -Send a newline or linefeed character. -.It \eN -Send a null character. -The same sequence may be represented by \\0 -.Pq Em not valid in expect . -.It \ep -Pause for a fraction of a second. -The delay is 1/10th of a second -.Pq Em not valid in expect . -.It \eq -Suppress writing the string to -.Xr syslogd 8 . -The string ?????? is -written to the log in its place -.Pq Em not valid in expect . -.It \er -Send or expect a carriage return. -.It \es -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. -.It \et -Send or expect a tab character. -.It \e -Send or expect a backslash character. -.It \eddd -Collapse the octal digits (ddd) into a single ASCII character and send that -character -.Pq Em some characters are not valid in expect . -.It \^^C -Substitute the sequence with the control character represented by C. -For example, the character DC1 (17) is shown as \^^Q -.Pq Em some characters are not valid in expect . -.El -.Sh TERMINATION CODES -The -.Nm -program will terminate with the following completion -codes. -.Bl -tag -width indent -.It 0 -The normal termination of the program. -This indicates that the script -was executed without error to the normal conclusion. -.It 1 -One or more of the parameters are invalid or an expect string was too -large for the internal buffers. -This indicates that the program as not -properly executed. -.It 2 -An error occurred during the execution of the program. -This may be due -to a read or write operation failing for some reason or chat receiving -a signal such as -.Dv SIGINT . -.It 3 -A timeout event occurred when there was an -.Em expect -string without -having a "-subsend" string. -This may mean that you did not program the -script correctly for the condition or that some unexpected event has -occurred and the expected string could not be found. -.It 4 -The first string marked as an -.Dv ABORT -condition occurred. -.It 5 -The second string marked as an -.Dv ABORT -condition occurred. -.It 6 -The third string marked as an -.Dv ABORT -condition occurred. -.It 7 -The fourth string marked as an -.Dv ABORT -condition occurred. -.It ... -The other termination codes are also strings marked as an -.Dv ABORT -condition. -.El -.Pp -Using the termination code, it is possible to determine which event -terminated the script. -It is possible to decide if the string "BUSY" -was received from the modem as opposed to "NO DIAL TONE". -While the -first event may be retried, the second will probably have little -chance of succeeding during a retry. -.Sh SEE ALSO -Additional information about -.Nm -scripts may be found with UUCP -documentation. -The -.Nm -script was taken from the ideas proposed -by the scripts used by the uucico program. -.Pp -.Xr syslog 3 , -.Xr syslogd 8 -.Sh COPYRIGHT -The -.Nm -program is in public domain. -This is not the GNU public -license. -If it breaks then you get to keep both pieces. Index: usr.bin/chat/chat.c =================================================================== --- usr.bin/chat/chat.c +++ /dev/null @@ -1,1529 +0,0 @@ -/* - * Chat -- a program for automatic session establishment (i.e. dial - * the phone and log in). - * - * Standard termination codes: - * 0 - successful completion of the script - * 1 - invalid argument, expect string too large, etc. - * 2 - error on an I/O operation or fatal error condition. - * 3 - timeout waiting for a simple string. - * 4 - the first string declared as "ABORT" - * 5 - the second string declared as "ABORT" - * 6 - ... and so on for successive ABORT strings. - * - * This software is in the public domain. - * - * ----------------- - * added -T and -U option and \T and \U substitution to pass a phone - * number into chat script. Two are needed for some ISDN TA applications. - * Keith Dart - * - * - * Added SAY keyword to send output to stderr. - * This allows to turn ECHO OFF and to output specific, user selected, - * text to give progress messages. This best works when stderr - * exists (i.e.: pppd in nodetach mode). - * - * Added HANGUP directives to allow for us to be called - * back. When HANGUP is set to NO, chat will not hangup at HUP signal. - * We rely on timeouts in that case. - * - * Added CLR_ABORT to clear previously set ABORT string. This has been - * dictated by the HANGUP above as "NO CARRIER" (for example) must be - * an ABORT condition until we know the other host is going to close - * the connection for call back. As soon as we have completed the - * first stage of the call back sequence, "NO CARRIER" is a valid, non - * fatal string. As soon as we got called back (probably get "CONNECT"), - * we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command. - * Note that CLR_ABORT packs the abort_strings[] array so that we do not - * have unused entries not being reclaimed. - * - * In the same vein as above, added CLR_REPORT keyword. - * - * Allow for comments. Line starting with '#' are comments and are - * ignored. If a '#' is to be expected as the first character, the - * expect string must be quoted. - * - * - * Francis Demierre - * Thu May 15 17:15:40 MET DST 1997 - * - * - * Added -r "report file" switch & REPORT keyword. - * Robert Geer - * - * Added -s "use stderr" and -S "don't use syslog" switches. - * June 18, 1997 - * Karl O. Pinc - * - * - * Added -e "echo" switch & ECHO keyword - * Dick Streefland - * - * - * Considerable updates and modifications by - * Al Longyear - * Paul Mackerras - * - * - * The original author is: - * - * Karl Fox - * Morning Star Technologies, Inc. - * 1760 Zollinger Road - * Columbus, OH 43221 - * (614)451-1883 - * - * - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define STR_LEN 1024 - -#ifndef SIGTYPE -#define SIGTYPE void -#endif - -#ifndef O_NONBLOCK -#define O_NONBLOCK O_NDELAY -#endif - -#define MAX_ABORTS 50 -#define MAX_REPORTS 50 -#define DEFAULT_CHAT_TIMEOUT 45 - -static int echo; -static int verbose; -static int to_log; -static int to_stderr; -static int Verbose; -static int quiet; -static int exit_code; -static FILE* report_fp; -static char *report_file; -static char *chat_file; -static char *phone_num; -static char *phone_num2; -static int timeout = DEFAULT_CHAT_TIMEOUT; - -static char blank[] = ""; - -static int have_tty_parameters; - -#define term_parms struct termios -#define get_term_param(param) tcgetattr(0, param) -#define set_term_param(param) tcsetattr(0, TCSANOW, param) -static struct termios saved_tty_parameters; - -static char *abort_string[MAX_ABORTS], *fail_reason, fail_buffer[50]; -static int n_aborts, abort_next, timeout_next, echo_next; -static int clear_abort_next; - -static char *report_string[MAX_REPORTS]; -static char report_buffer[50]; -static int n_reports, report_next, report_gathering; -static int clear_report_next; - -static int say_next, hup_next; - -void *dup_mem(void *b, size_t c); -void *copy_of(char *s); -static void usage(void); -void chat_logf(const char *fmt, ...); -void fatal(int code, const char *fmt, ...); -SIGTYPE sigalrm(int signo); -SIGTYPE sigint(int signo); -SIGTYPE sigterm(int signo); -SIGTYPE sighup(int signo); -void init(void); -void set_tty_parameters(void); -void echo_stderr(int); -void break_sequence(void); -void terminate(int status); -void do_file(char *chatfile); -int get_string(char *string); -int put_string(char *s); -int write_char(int c); -int put_char(int c); -int get_char(void); -void chat_send(char *s); -char *character(int c); -void chat_expect(char *s); -char *clean(char *s, int sending); -void pack_array(char **array, int end); -char *expect_strtok(char *, const char *); -int vfmtmsg(char *, int, const char *, va_list); /* vsprintf++ */ - -void * -dup_mem(void *b, size_t c) -{ - void *ans = malloc (c); - if (!ans) - fatal(2, "memory error!"); - - memcpy (ans, b, c); - return ans; -} - -void * -copy_of(char *s) -{ - return dup_mem (s, strlen (s) + 1); -} - -/* - * chat [-esSvV] [-f chat-file] [-r report-file] [-t timeout] - * [-T phone-number] [-U phone-number2] [chat-script] - * where chat-script has the form: - * [...[[expect[-send[-expect...]] send expect[-send[-expect]] ...]]] - * - * Perform a UUCP-dialer-like chat script on stdin and stdout. - */ -int -main(int argc, char *argv[]) -{ - int option; - - tzset(); - - while ((option = getopt(argc, argv, "ef:r:sSt:T:U:vV")) != -1) { - switch (option) { - case 'e': - ++echo; - break; - - case 'f': - if (chat_file != NULL) - free(chat_file); - chat_file = copy_of(optarg); - break; - - case 'r': - if (report_fp != NULL) - fclose(report_fp); - if (report_file != NULL) - free(report_file); - report_file = copy_of(optarg); - report_fp = fopen(report_file, "a"); - if (report_fp != NULL) { - if (verbose) - fprintf(report_fp, "Opening \"%s\"...\n", report_file); - } else - fatal(2, "cannot open \"%s\" for appending", report_file); - break; - - case 's': - ++to_stderr; - break; - - case 'S': - to_log = 0; - break; - - case 't': - timeout = atoi(optarg); - break; - - case 'T': - if (phone_num != NULL) - free(phone_num); - phone_num = copy_of(optarg); - break; - - case 'U': - if (phone_num2 != NULL) - free(phone_num2); - phone_num2 = copy_of(optarg); - break; - - case 'v': - ++verbose; - break; - - case 'V': - ++Verbose; - break; - - default: - usage(); - break; - } - } - - argc -= optind; - argv += optind; - -/* - * Default the report file to the stderr location - */ - if (report_fp == NULL) - report_fp = stderr; - - if (to_log) { - openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); - - if (verbose) - setlogmask(LOG_UPTO(LOG_INFO)); - else - setlogmask(LOG_UPTO(LOG_WARNING)); - } - - if (chat_file != NULL) { - if (*argv != NULL) - usage(); - else { - init(); - do_file(chat_file); - } - } else { - init(); - while (*argv != NULL && argc > 0) { - chat_expect(*argv); - argv++; - argc--; - - if (*argv != NULL && argc > 0) { - chat_send(*argv); - argv++; - argc--; - } - } - } - - terminate(0); - return 0; -} - -/* - * Process a chat script when read from a file. - */ - -void -do_file(char *chatfile) -{ - int linect, sendflg; - char *sp, *arg, quote; - char buf [STR_LEN]; - FILE *cfp; - - cfp = fopen (chatfile, "r"); - if (cfp == NULL) - fatal(1, "%s -- open failed: %m", chatfile); - - linect = 0; - sendflg = 0; - - while (fgets(buf, STR_LEN, cfp) != NULL) { - sp = strchr (buf, '\n'); - if (sp) - *sp = '\0'; - - linect++; - sp = buf; - - /* lines starting with '#' are comments. If a real '#' - is to be expected, it should be quoted .... */ - if ( *sp == '#' ) - continue; - - while (*sp != '\0') { - if (*sp == ' ' || *sp == '\t') { - ++sp; - continue; - } - - if (*sp == '"' || *sp == '\'') { - quote = *sp++; - arg = sp; - while (*sp != quote) { - if (*sp == '\0') - fatal(1, "unterminated quote (line %d)", linect); - - 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. - */ -static void -usage(void) -{ - fprintf(stderr, - "Usage: chat [-esSvV] [-f chat-file] [-r report-file] [-t timeout]\n" - " [-T phone-number] [-U phone-number2] [chat-script]\n" - "where chat-script has the form:\n" - " [...[[expect[-send[-expect...]] send expect[-send[-expect]] ...]]]\n"); - exit(1); -} - -/* - * Send a message to syslog and/or stderr. - */ -void -chat_logf(const char *fmt, ...) -{ - char line[1024]; - va_list args; - - va_start(args, fmt); - vfmtmsg(line, sizeof(line), fmt, args); - va_end(args); - if (to_log) - syslog(LOG_INFO, "%s", line); - if (to_stderr) - fprintf(stderr, "%s\n", line); -} - -/* - * Print an error message and terminate. - */ - -void -fatal(int code, const char *fmt, ...) -{ - char line[1024]; - va_list args; - - va_start(args, fmt); - vfmtmsg(line, sizeof(line), fmt, args); - va_end(args); - if (to_log) - syslog(LOG_ERR, "%s", line); - if (to_stderr) - fprintf(stderr, "%s\n", line); - terminate(code); -} - -static int alarmed; - -SIGTYPE sigalrm(int signo __unused) -{ - int flags; - - alarm(1); - alarmed = 1; /* Reset alarm to avoid race window */ - signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ - - if ((flags = fcntl(0, F_GETFL, 0)) == -1) - fatal(2, "Can't get file mode flags on stdin: %m"); - - if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) - fatal(2, "Can't set file mode flags on stdin: %m"); - - if (verbose) - chat_logf("alarm"); -} - -SIGTYPE sigint(int signo __unused) -{ - fatal(2, "SIGINT"); -} - -SIGTYPE sigterm(int signo __unused) -{ - fatal(2, "SIGTERM"); -} - -SIGTYPE sighup(int signo __unused) -{ - fatal(2, "SIGHUP"); -} - -void init(void) -{ - signal(SIGINT, sigint); - signal(SIGTERM, sigterm); - signal(SIGHUP, sighup); - - set_tty_parameters(); - signal(SIGALRM, sigalrm); - alarm(0); - alarmed = 0; -} - -void set_tty_parameters(void) -{ -#if defined(get_term_param) - term_parms t; - - if (get_term_param (&t) < 0) - fatal(2, "Can't get terminal parameters: %m"); - - saved_tty_parameters = t; - have_tty_parameters = 1; - - 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; - - if (set_term_param (&t) < 0) - fatal(2, "Can't set terminal parameters: %m"); -#endif -} - -void break_sequence(void) -{ - tcsendbreak (0, 0); -} - -void terminate(int status) -{ - echo_stderr(-1); - if (report_file != (char *) 0 && report_fp != (FILE *) NULL) { -/* - * Allow the last of the report string to be gathered before we terminate. - */ - if (report_gathering) { - int c; - size_t rep_len; - - rep_len = strlen(report_buffer); - while (rep_len + 1 < sizeof(report_buffer)) { - alarm(1); - c = get_char(); - alarm(0); - if (c < 0 || iscntrl(c)) - break; - report_buffer[rep_len] = c; - ++rep_len; - } - report_buffer[rep_len] = 0; - fprintf (report_fp, "chat: %s\n", report_buffer); - } - if (verbose) - fprintf (report_fp, "Closing \"%s\".\n", report_file); - fclose (report_fp); - report_fp = (FILE *) NULL; - } - -#if defined(get_term_param) - if (have_tty_parameters) { - if (set_term_param (&saved_tty_parameters) < 0) - fatal(2, "Can't restore terminal parameters: %m"); - } -#endif - - exit(status); -} - -/* - * 'Clean up' this string. - */ -char * -clean(char *s, int sending) -{ - char temp[STR_LEN], cur_chr; - char *s1, *phchar; - int add_return = sending; -#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) - - s1 = temp; - /* Don't overflow buffer, leave room for chars we append later */ - while (*s && s1 - temp < (off_t)(sizeof(temp) - 2 - add_return)) { - 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; - } - - if (cur_chr != '\\') { - *s1++ = cur_chr; - continue; - } - - cur_chr = *s++; - if (cur_chr == '\0') { - if (sending) { - *s1++ = '\\'; - *s1++ = '\\'; - } - break; - } - - switch (cur_chr) { - case 'b': - *s1++ = '\b'; - break; - - case 'c': - if (sending && *s == '\0') - add_return = 0; - else - *s1++ = cur_chr; - break; - - case '\\': - case 'K': - case 'p': - case 'd': - if (sending) - *s1++ = '\\'; - - *s1++ = cur_chr; - break; - - case 'T': - if (sending && phone_num) { - for ( phchar = phone_num; *phchar != '\0'; phchar++) - *s1++ = *phchar; - } - else { - *s1++ = '\\'; - *s1++ = 'T'; - } - break; - - case 'U': - if (sending && phone_num2) { - for ( phchar = phone_num2; *phchar != '\0'; phchar++) - *s1++ = *phchar; - } - else { - *s1++ = '\\'; - *s1++ = 'U'; - } - break; - - case 'q': - quiet = 1; - 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; - } - } - - if (add_return) - *s1++ = '\r'; - - *s1++ = '\0'; /* guarantee closure */ - *s1++ = '\0'; /* terminate the string */ - return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ -} - -/* - * A modified version of 'strtok'. This version skips \ sequences. - */ - -char * -expect_strtok (char *s, const char *term) -{ - static char *str = blank; - int escape_flag = 0; - char *result; - -/* - * If a string was specified then do initial processing. - */ - if (s) - str = s; - -/* - * If this is the escape flag then reset it and ignore the character. - */ - if (*str) - result = str; - else - result = (char *) 0; - - while (*str) { - if (escape_flag) { - escape_flag = 0; - ++str; - continue; - } - - if (*str == '\\') { - ++str; - escape_flag = 1; - continue; - } - -/* - * If this is not in the termination string, continue. - */ - if (strchr (term, *str) == (char *) 0) { - ++str; - continue; - } - -/* - * This is the terminator. Mark the end of the string and stop. - */ - *str++ = '\0'; - break; - } - return (result); -} - -/* - * Process the expect string - */ - -void -chat_expect(char *s) -{ - char *expect; - char *reply; - - if (strcmp(s, "HANGUP") == 0) { - ++hup_next; - return; - } - - if (strcmp(s, "ABORT") == 0) { - ++abort_next; - return; - } - - if (strcmp(s, "CLR_ABORT") == 0) { - ++clear_abort_next; - return; - } - - if (strcmp(s, "REPORT") == 0) { - ++report_next; - return; - } - - if (strcmp(s, "CLR_REPORT") == 0) { - ++clear_report_next; - return; - } - - if (strcmp(s, "TIMEOUT") == 0) { - ++timeout_next; - return; - } - - if (strcmp(s, "ECHO") == 0) { - ++echo_next; - return; - } - - if (strcmp(s, "SAY") == 0) { - ++say_next; - return; - } - -/* - * Fetch the expect and reply string. - */ - for (;;) { - expect = expect_strtok (s, "-"); - s = (char *) 0; - - if (expect == (char *) 0) - return; - - reply = expect_strtok (s, "-"); - -/* - * Handle the expect string. If successful then exit. - */ - if (get_string (expect)) - return; - -/* - * If there is a sub-reply string then send it. Otherwise any condition - * is terminal. - */ - if (reply == (char *) 0 || exit_code != 3) - break; - - chat_send (reply); - } - -/* - * The expectation did not occur. This is terminal. - */ - if (fail_reason) - chat_logf("Failed (%s)", fail_reason); - else - chat_logf("Failed"); - terminate(exit_code); -} - -/* - * Translate the input character to the appropriate string for printing - * the data. - */ - -char * -character(int c) -{ - static char string[10]; - const char *meta; - - meta = (c & 0x80) ? "M-" : ""; - c &= 0x7F; - - if (c < 32) - sprintf(string, "%s^%c", meta, (int)c + '@'); - else if (c == 127) - sprintf(string, "%s^?", meta); - else - sprintf(string, "%s%c", meta, c); - - return (string); -} - -/* - * process the reply string - */ -void -chat_send(char *s) -{ - if (say_next) { - say_next = 0; - s = clean(s,0); - write(STDERR_FILENO, s, strlen(s)); - free(s); - return; - } - - if (hup_next) { - hup_next = 0; - if (strcmp(s, "OFF") == 0) - signal(SIGHUP, SIG_IGN); - else - signal(SIGHUP, sighup); - return; - } - - if (echo_next) { - echo_next = 0; - echo = (strcmp(s, "ON") == 0); - return; - } - - if (abort_next) { - char *s1; - - abort_next = 0; - - if (n_aborts >= MAX_ABORTS) - fatal(2, "Too many ABORT strings"); - - s1 = clean(s, 0); - - if (strlen(s1) > strlen(s) - || strlen(s1) + 1 > sizeof(fail_buffer)) - fatal(1, "Illegal or too-long ABORT string ('%v')", s); - - abort_string[n_aborts++] = s1; - - if (verbose) - chat_logf("abort on (%v)", s); - return; - } - - if (clear_abort_next) { - char *s1; - int i; - int old_max; - int pack = 0; - - clear_abort_next = 0; - - s1 = clean(s, 0); - - if (strlen(s1) > strlen(s) - || strlen(s1) + 1 > sizeof(fail_buffer)) - fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s); - - old_max = n_aborts; - for (i=0; i < n_aborts; i++) { - if ( strcmp(s1,abort_string[i]) == 0 ) { - free(abort_string[i]); - abort_string[i] = NULL; - pack++; - n_aborts--; - if (verbose) - chat_logf("clear abort on (%v)", s); - } - } - free(s1); - if (pack) - pack_array(abort_string,old_max); - return; - } - - if (report_next) { - char *s1; - - report_next = 0; - if (n_reports >= MAX_REPORTS) - fatal(2, "Too many REPORT strings"); - - s1 = clean(s, 0); - - if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) - fatal(1, "Illegal or too-long REPORT string ('%v')", s); - - report_string[n_reports++] = s1; - - if (verbose) - chat_logf("report (%v)", s); - return; - } - - if (clear_report_next) { - char *s1; - int i; - int old_max; - int pack = 0; - - clear_report_next = 0; - - s1 = clean(s, 0); - - if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) - fatal(1, "Illegal or too-long REPORT string ('%v')", s); - - old_max = n_reports; - for (i=0; i < n_reports; i++) { - if ( strcmp(s1,report_string[i]) == 0 ) { - free(report_string[i]); - report_string[i] = NULL; - pack++; - n_reports--; - if (verbose) - chat_logf("clear report (%v)", s); - } - } - free(s1); - if (pack) - pack_array(report_string,old_max); - - return; - } - - if (timeout_next) { - timeout_next = 0; - timeout = atoi(s); - - if (timeout <= 0) - timeout = DEFAULT_CHAT_TIMEOUT; - - if (verbose) - chat_logf("timeout set to %d seconds", timeout); - - return; - } - - if (strcmp(s, "EOT") == 0) - s = strdup("^D\\c"); - else if (strcmp(s, "BREAK") == 0) - s = strdup("\\K\\c"); - - if (!put_string(s)) - fatal(1, "Failed"); -} - -int -get_char(void) -{ - int status; - char c; - - status = read(STDIN_FILENO, &c, 1); - - switch (status) { - case 1: - return ((int)c & 0x7F); - - default: - chat_logf("warning: read() on stdin returned %d", status); - - case -1: - if ((status = fcntl(0, F_GETFL, 0)) == -1) - fatal(2, "Can't get file mode flags on stdin: %m"); - - if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) - fatal(2, "Can't set file mode flags on stdin: %m"); - - return (-1); - } -} - -int put_char(int c) -{ - int status; - char ch = c; - - usleep(10000); /* inter-character typing delay (?) */ - - status = write(STDOUT_FILENO, &ch, 1); - - switch (status) { - case 1: - return (0); - - default: - chat_logf("warning: write() on stdout returned %d", status); - - case -1: - if ((status = fcntl(0, F_GETFL, 0)) == -1) - fatal(2, "Can't get file mode flags on stdin, %m"); - - if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) - fatal(2, "Can't set file mode flags on stdin: %m"); - - return (-1); - } -} - -int -write_char(int c) -{ - if (alarmed || put_char(c) < 0) { - alarm(0); - alarmed = 0; - - if (verbose) { - if (errno == EINTR || errno == EWOULDBLOCK) - chat_logf(" -- write timed out"); - else - chat_logf(" -- write failed: %m"); - } - return (0); - } - return (1); -} - -int -put_string(char *s) -{ - quiet = 0; - s = clean(s, 1); - - if (verbose) - chat_logf("send (%v)", quiet ? "??????" : s); - - alarm(timeout); alarmed = 0; - - while (*s) { - char c = *s++; - - if (c != '\\') { - if (!write_char (c)) - return 0; - continue; - } - - c = *s++; - switch (c) { - case 'd': - sleep(1); - break; - - case 'K': - break_sequence(); - break; - - case 'p': - usleep(10000); /* 1/100th of a second (arg is microseconds) */ - break; - - default: - if (!write_char (c)) - return 0; - break; - } - } - - alarm(0); - alarmed = 0; - return (1); -} - -/* - * Echo a character to stderr. - * When called with -1, a '\n' character is generated when - * the cursor is not at the beginning of a line. - */ -void -echo_stderr(int n) -{ - static int need_lf; - char *s; - - switch (n) { - case '\r': /* ignore '\r' */ - break; - case -1: - if (need_lf == 0) - break; - /* FALLTHROUGH */ - case '\n': - write(STDERR_FILENO, "\n", 1); - need_lf = 0; - break; - default: - s = character(n); - write(STDERR_FILENO, s, strlen(s)); - need_lf = 1; - break; - } -} - -/* - * 'Wait for' this string to appear on this file descriptor. - */ -int -get_string(char *string) -{ - char temp[STR_LEN]; - int c; - size_t len, minlen; - char *s = temp, *end = s + STR_LEN; - char *logged = temp; - - fail_reason = (char *)0; - - if (strlen(string) > STR_LEN) { - chat_logf("expect string is too long"); - exit_code = 1; - return 0; - } - - string = clean(string, 0); - len = strlen(string); - minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; - - if (verbose) - chat_logf("expect (%v)", string); - - if (len == 0) { - if (verbose) - chat_logf("got it"); - return (1); - } - - alarm(timeout); - alarmed = 0; - - while ( ! alarmed && (c = get_char()) >= 0) { - int n, abort_len, report_len; - - if (echo) - echo_stderr(c); - if (verbose && c == '\n') { - if (s == logged) - chat_logf(""); /* blank line */ - else - chat_logf("%0.*v", s - logged, logged); - logged = s + 1; - } - - *s++ = c; - - if (verbose && s >= logged + 80) { - chat_logf("%0.*v", s - logged, logged); - logged = s; - } - - if (Verbose) { - if (c == '\n') - fputc( '\n', stderr ); - else if (c != '\r') - fprintf( stderr, "%s", character(c) ); - } - - if (!report_gathering) { - for (n = 0; n < n_reports; ++n) { - if ((report_string[n] != (char*) NULL) && - s - temp >= (report_len = strlen(report_string[n])) && - strncmp(s - report_len, report_string[n], report_len) == 0) { - time_t time_now = time ((time_t*) NULL); - struct tm* tm_now = localtime (&time_now); - - strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); - strcat (report_buffer, report_string[n]); - - report_string[n] = (char *) NULL; - report_gathering = 1; - break; - } - } - } - else { - if (!iscntrl (c)) { - int rep_len = strlen (report_buffer); - report_buffer[rep_len] = c; - report_buffer[rep_len + 1] = '\0'; - } - else { - report_gathering = 0; - fprintf (report_fp, "chat: %s\n", report_buffer); - } - } - - if ((size_t)(s - temp) >= len && - c == string[len - 1] && - strncmp(s - len, string, len) == 0) { - if (verbose) { - if (s > logged) - chat_logf("%0.*v", s - logged, logged); - chat_logf(" -- got it\n"); - } - - alarm(0); - alarmed = 0; - return (1); - } - - for (n = 0; n < n_aborts; ++n) { - if (s - temp >= (abort_len = strlen(abort_string[n])) && - strncmp(s - abort_len, abort_string[n], abort_len) == 0) { - if (verbose) { - if (s > logged) - chat_logf("%0.*v", s - logged, logged); - chat_logf(" -- failed"); - } - - alarm(0); - alarmed = 0; - exit_code = n + 4; - strcpy(fail_reason = fail_buffer, abort_string[n]); - return (0); - } - } - - if (s >= end) { - if (logged < s - minlen) { - chat_logf("%0.*v", s - logged, logged); - logged = s; - } - s -= minlen; - memmove(temp, s, minlen); - logged = temp + (logged - s); - s = temp + minlen; - } - - if (alarmed && verbose) - chat_logf("warning: alarm synchronization problem"); - } - - alarm(0); - - exit_code = 3; - alarmed = 0; - return (0); -} - -void -pack_array(char **array, int end) -{ - int i, j; - - for (i = 0; i < end; i++) { - if (array[i] == NULL) { - for (j = i+1; j < end; ++j) - if (array[j] != NULL) - array[i++] = array[j]; - for (; i < end; ++i) - array[i] = NULL; - break; - } - } -} - -/* - * vfmtmsg - format a message into a buffer. Like vsprintf except we - * also specify the length of the output buffer, and we handle the - * %m (error message) format. - * Doesn't do floating-point formats. - * Returns the number of chars put into buf. - */ -#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) - -int -vfmtmsg(char *buf, int buflen, const char *fmt, va_list args) -{ - int c, i, n; - int width, prec, fillch; - int base, len, neg, quoted; - unsigned long val = 0; - char *str, *buf0; - const char *f; - unsigned char *p; - char num[32]; - static char hexchars[] = "0123456789abcdef"; - - buf0 = buf; - --buflen; - while (buflen > 0) { - for (f = fmt; *f != '%' && *f != 0; ++f) - ; - if (f > fmt) { - len = f - fmt; - if (len > buflen) - len = buflen; - memcpy(buf, fmt, len); - buf += len; - buflen -= len; - fmt = f; - } - if (*fmt == 0) - break; - c = *++fmt; - width = prec = 0; - fillch = ' '; - if (c == '0') { - fillch = '0'; - c = *++fmt; - } - if (c == '*') { - width = va_arg(args, int); - c = *++fmt; - } else { - while (isdigit(c)) { - width = width * 10 + c - '0'; - c = *++fmt; - } - } - if (c == '.') { - c = *++fmt; - if (c == '*') { - prec = va_arg(args, int); - c = *++fmt; - } else { - while (isdigit(c)) { - prec = prec * 10 + c - '0'; - c = *++fmt; - } - } - } - str = NULL; - base = 0; - neg = 0; - ++fmt; - switch (c) { - case 'd': - i = va_arg(args, int); - if (i < 0) { - neg = 1; - val = -i; - } else - val = i; - base = 10; - break; - case 'o': - val = va_arg(args, unsigned int); - base = 8; - break; - case 'x': - val = va_arg(args, unsigned int); - base = 16; - break; - case 'p': - val = (unsigned long) va_arg(args, void *); - base = 16; - neg = 2; - break; - case 's': - str = va_arg(args, char *); - break; - case 'c': - num[0] = va_arg(args, int); - num[1] = 0; - str = num; - break; - case 'm': - str = strerror(errno); - break; - case 'v': /* "visible" string */ - case 'q': /* quoted string */ - quoted = c == 'q'; - p = va_arg(args, unsigned char *); - if (fillch == '0' && prec > 0) { - n = prec; - } else { - n = strlen((char *)p); - if (prec > 0 && prec < n) - n = prec; - } - while (n > 0 && buflen > 0) { - c = *p++; - --n; - if (!quoted && c >= 0x80) { - OUTCHAR('M'); - OUTCHAR('-'); - c -= 0x80; - } - if (quoted && (c == '"' || c == '\\')) - OUTCHAR('\\'); - if (c < 0x20 || (0x7f <= c && c < 0xa0)) { - if (quoted) { - OUTCHAR('\\'); - switch (c) { - case '\t': OUTCHAR('t'); break; - case '\n': OUTCHAR('n'); break; - case '\b': OUTCHAR('b'); break; - case '\f': OUTCHAR('f'); break; - default: - OUTCHAR('x'); - OUTCHAR(hexchars[c >> 4]); - OUTCHAR(hexchars[c & 0xf]); - } - } else { - if (c == '\t') - OUTCHAR(c); - else { - OUTCHAR('^'); - OUTCHAR(c ^ 0x40); - } - } - } else - OUTCHAR(c); - } - continue; - default: - *buf++ = '%'; - if (c != '%') - --fmt; /* so %z outputs %z etc. */ - --buflen; - continue; - } - if (base != 0) { - str = num + sizeof(num); - *--str = 0; - while (str > num + neg) { - *--str = hexchars[val % base]; - val = val / base; - if (--prec <= 0 && val == 0) - break; - } - switch (neg) { - case 1: - *--str = '-'; - break; - case 2: - *--str = 'x'; - *--str = '0'; - break; - } - len = num + sizeof(num) - 1 - str; - } else { - len = strlen(str); - if (prec > 0 && len > prec) - len = prec; - } - if (width > 0) { - if (width > buflen) - width = buflen; - if ((n = width - len) > 0) { - buflen -= n; - for (; n > 0; --n) - *buf++ = fillch; - } - } - if (len > buflen) - len = buflen; - memcpy(buf, str, len); - buf += len; - buflen -= len; - } - *buf = 0; - return buf - buf0; -} Index: usr.sbin/ppp/ppp.8 =================================================================== --- usr.sbin/ppp/ppp.8 +++ usr.sbin/ppp/ppp.8 @@ -4662,9 +4662,7 @@ See also the .Dq set login command below. -Refer to -.Xr chat 8 -and to the example configuration files for details of the chat script +Refer to the example configuration files for details of the chat script format. It is possible to specify some special .Sq values @@ -4791,9 +4789,6 @@ This, of course means that it is possible to execute an entirely external .Dq chat command rather than using the internal one. -See -.Xr chat 8 -for a good alternative. .Pp The external command that is executed is subjected to the same special word expansions as the @@ -6053,7 +6048,6 @@ .Xr resolv.conf 5 , .Xr syslog.conf 5 , .Xr adduser 8 , -.Xr chat 8 , .Xr getty 8 , .Xr inetd 8 , .Xr init 8 ,