]> git.ozlabs.org Git - ppp.git/blobdiff - chat/chat.c
pppd man page: Update header to refer to pppd 2.5.x
[ppp.git] / chat / chat.c
index 0015e2bb9fa018be052acd8f2492d92c19d50bda..336c0f4995f4ab3dadd1612673d251ec0d3507d5 100644 (file)
@@ -14,6 +14,9 @@
  *     This software is in the public domain.
  *
  * -----------------
+ *     22-May-99 added environment substitutuion, enabled with -E switch.
+ *     Andreas Arens <andras@cityweb.de>.
+ *
  *     12-May-99 added a feature to read data to be sent from a file,
  *     if the send string starts with @.  Idea from gpk <gpk@onramp.net>.
  *
  *             Columbus, OH  43221
  *             (614)451-1883
  *
- *
  */
 
-#ifndef lint
-static const char rcsid[] = "$Id: chat.c,v 1.23 1999/08/13 01:54:32 paulus Exp $";
-#endif
-
 #include <stdio.h>
 #include <ctype.h>
 #include <time.h>
@@ -96,6 +94,7 @@ static const char rcsid[] = "$Id: chat.c,v 1.23 1999/08/13 01:54:32 paulus Exp $
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <syslog.h>
+#include <stdarg.h>
 
 #ifndef TERMIO
 #undef TERMIOS
@@ -115,20 +114,6 @@ static const char rcsid[] = "$Id: chat.c,v 1.23 1999/08/13 01:54:32 paulus Exp $
 #define SIGTYPE void
 #endif
 
-#undef __P
-#undef __V
-
-#ifdef __STDC__
-#include <stdarg.h>
-#define __V(x) x
-#define __P(x) x
-#else
-#include <varargs.h>
-#define __V(x) (va_alist) va_dcl
-#define __P(x) ()
-#define const
-#endif
-
 #ifndef O_NONBLOCK
 #define O_NONBLOCK     O_NDELAY
 #endif
@@ -166,6 +151,7 @@ int to_stderr     = 0;
 int Verbose       = 0;
 int quiet         = 0;
 int report        = 0;
+int use_env       = 0;
 int exit_code     = 0;
 FILE* report_fp   = (FILE *) 0;
 char *report_file = (char *) 0;
@@ -196,48 +182,46 @@ int n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0;
 int clear_abort_next = 0;
 
 char *report_string[MAX_REPORTS] ;
-char  report_buffer[50] ;
+char  report_buffer[4096] ;
 int n_reports = 0, report_next = 0, report_gathering = 0 ; 
 int clear_report_next = 0;
 
 int say_next = 0, hup_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 *fmt, ...));
-void fatal __P((int code, const char *fmt, ...));
-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 echo_stderr __P((int));
-void break_sequence __P((void));
-void terminate __P((int status));
-void do_file __P((char *chat_file));
-int  get_string __P((register char *string));
-int  put_string __P((register char *s));
-int  write_char __P((int c));
-int  put_char __P((int c));
-int  get_char __P((void));
-void chat_send __P((register char *s));
-char *character __P((int c));
-void chat_expect __P((register char *s));
-char *clean __P((register char *s, int sending));
-void break_sequence __P((void));
-void terminate __P((int status));
-void pack_array __P((char **array, int end));
-char *expect_strtok __P((char *, char *));
-int vfmtmsg __P((char *, int, const char *, va_list)); /* vsprintf++ */
-
-int main __P((int, char *[]));
-
-void *dup_mem(b, c)
-void *b;
-size_t c;
+void *dup_mem (void *b, size_t c);
+void *copy_of (char *s);
+char *grow (char *s, char **p, size_t len);
+void usage (void);
+void msgf (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 checksigs(void);
+void init (void);
+void set_tty_parameters (void);
+int  echo_stderr (int);
+void break_sequence (void);
+void terminate (int status);
+void do_file (char *chat_file);
+int  get_string (register char *string);
+int  put_string (register char *s);
+int  write_char (int c);
+int  put_char (int c);
+int  get_char (void);
+int  chat_send (register char *s);
+char *character (int c);
+void chat_expect (register char *s);
+char *clean (register char *s, int sending);
+void break_sequence (void);
+void pack_array (char **array, int end);
+char *expect_strtok (char *, char *);
+int vfmtmsg (char *, int, const char *, va_list);      /* vsprintf++ */
+
+int main (int, char *[]);
+
+void *dup_mem(void *b, size_t c)
 {
     void *ans = malloc (c);
     if (!ans)
@@ -247,23 +231,32 @@ size_t c;
     return ans;
 }
 
-void *copy_of (s)
-char *s;
+void *copy_of (char *s)
 {
     return dup_mem (s, strlen (s) + 1);
 }
 
+/* grow a char buffer and keep a pointer offset */
+char *grow(char *s, char **p, size_t len)
+{
+    size_t l = *p - s;         /* save p as distance into s */
+
+    s = realloc(s, len);
+    if (!s)
+       fatal(2, "memory error!");
+    *p = s + l;                        /* restore p */
+    return s;
+}
+
 /*
- * chat [ -v ] [-T number] [-U number] [ -t timeout ] [ -f chat-file ] \
+ * chat [ -v ] [ -E ] [ -T number ] [ -U number ] [ -t timeout ] [ -f chat-file ] \
  * [ -r report-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;
+main(int argc, char **argv)
 {
     int option;
     char *arg;
@@ -277,6 +270,10 @@ main(argc, argv)
            ++echo;
            break;
 
+       case 'E':
+           ++use_env;
+           break;
+
        case 'v':
            ++verbose;
            break;
@@ -349,16 +346,12 @@ main(argc, argv)
        report_fp = stderr;
 
     if (to_log) {
-#ifdef ultrix
-       openlog("chat", LOG_PID);
-#else
        openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2);
 
        if (verbose)
            setlogmask(LOG_UPTO(LOG_INFO));
        else
            setlogmask(LOG_UPTO(LOG_WARNING));
-#endif
     }
 
     init();
@@ -375,6 +368,7 @@ main(argc, argv)
 
            if ((arg = ARG(argc, argv)) != NULL)
                chat_send(arg);
+           checksigs();
        }
     }
 
@@ -386,8 +380,7 @@ main(argc, argv)
  *  Process a chat script when read from a file.
  */
 
-void do_file (chat_file)
-char *chat_file;
+void do_file (char *chat_file)
 {
     int linect, sendflg;
     char *sp, *arg, quote;
@@ -447,19 +440,21 @@ char *chat_file;
            else
                chat_expect (arg);
            sendflg = !sendflg;
+           checksigs();
        }
     }
+    checksigs();
     fclose (cfp);
 }
 
 /*
  *     We got an error parsing the command line.
  */
-void usage()
+void usage(void)
 {
     fprintf(stderr, "\
-Usage: %s [-e] [-v] [-t timeout] [-r report-file] [-T phone-number]\n\
-     [-U phone-number2] {-f chat-file | chat-script}\n", program_name);
+Usage: %s [-e] [-E] [-v] [-V] [-t timeout] [-r report-file]\n\
+     [-T phone-number] [-U phone-number2] {-f chat-file | chat-script}\n", program_name);
     exit(1);
 }
 
@@ -468,114 +463,107 @@ char line[1024];
 /*
  * Send a message to syslog and/or stderr.
  */
-void logf __V((const char *fmt, ...))
+void msgf(const char *fmt, ...)
 {
     va_list args;
 
-#ifdef __STDC__
     va_start(args, fmt);
-#else
-    char *fmt;
-    va_start(args);
-    fmt = va_arg(args, char *);
-#endif
 
     vfmtmsg(line, sizeof(line), fmt, args);
     if (to_log)
        syslog(LOG_INFO, "%s", line);
     if (to_stderr)
        fprintf(stderr, "%s\n", line);
+    va_end(args);
 }
 
 /*
  *     Print an error message and terminate.
  */
 
-void fatal __V((int code, const char *fmt, ...))
+void fatal(int code, const char *fmt, ...)
 {
     va_list args;
 
-#ifdef __STDC__
     va_start(args, fmt);
-#else
-    int code;
-    char *fmt;
-    va_start(args);
-    code = va_arg(args, int);
-    fmt = va_arg(args, char *);
-#endif
 
     vfmtmsg(line, sizeof(line), fmt, args);
     if (to_log)
        syslog(LOG_ERR, "%s", line);
     if (to_stderr)
        fprintf(stderr, "%s\n", line);
+    va_end(args);
     terminate(code);
 }
 
 int alarmed = 0;
+int alarmsig = 0;
 
-SIGTYPE sigalrm(signo)
-int signo;
+SIGTYPE sigalrm(int signo)
 {
     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)
-       logf("alarm");
+    alarmed = 1;
+    alarmsig = 1;
 }
 
-void unalarm()
-{
-    int flags;
-
-    if ((flags = fcntl(0, F_GETFL, 0)) == -1)
-       fatal(2, "Can't get file mode flags on stdin: %m");
+const char *fatalsig = NULL;
 
-    if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1)
-       fatal(2, "Can't set file mode flags on stdin: %m");
+SIGTYPE sigint(int signo)
+{
+    fatalsig = "SIGINT";
 }
 
-SIGTYPE sigint(signo)
-int signo;
+SIGTYPE sigterm(int signo)
 {
-    fatal(2, "SIGINT");
+    fatalsig = "SIGTERM";
 }
 
-SIGTYPE sigterm(signo)
-int signo;
+SIGTYPE sighup(int signo)
 {
-    fatal(2, "SIGTERM");
+    fatalsig = "SIGHUP";
 }
 
-SIGTYPE sighup(signo)
-int signo;
+void checksigs(void)
 {
-    fatal(2, "SIGHUP");
+    int err;
+    const char *signame;
+
+    if (fatalsig) {
+       signame = fatalsig;
+       fatalsig = NULL;
+       alarmsig = 0;
+       fatal(2, signame);
+    }
+    if (alarmsig && verbose) {
+       err = errno;
+       msgf("alarm");
+       errno = err;
+       alarmsig = 0;
+    }
 }
 
-void init()
+void init(void)
 {
-    signal(SIGINT, sigint);
-    signal(SIGTERM, sigterm);
-    signal(SIGHUP, sighup);
+    struct sigaction sa;
+
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_handler = sigint;
+    sigaction(SIGINT, &sa, NULL);
+    sa.sa_handler = sigterm;
+    sigaction(SIGTERM, &sa, NULL);
+    sa.sa_handler = sighup;
+    sigaction(SIGHUP, &sa, NULL);
 
     set_tty_parameters();
-    signal(SIGALRM, sigalrm);
+    sa.sa_handler = sigalrm;
+    sigaction(SIGALRM, &sa, NULL);
     alarm(0);
     alarmed = 0;
 }
 
-void set_tty_parameters()
+void set_tty_parameters(void)
 {
 #if defined(get_term_param)
     term_parms t;
@@ -599,15 +587,14 @@ void set_tty_parameters()
 #endif
 }
 
-void break_sequence()
+void break_sequence(void)
 {
 #ifdef TERMIOS
     tcsendbreak (0, 0);
 #endif
 }
 
-void terminate(status)
-int status;
+void terminate(int status)
 {
     static int terminating = 0;
 
@@ -622,7 +609,7 @@ int status;
        int c, rep_len;
 
        rep_len = strlen(report_buffer);
-       while (rep_len + 1 <= sizeof(report_buffer)) {
+       while (rep_len + 1 < sizeof(report_buffer)) {
            alarm(1);
            c = get_char();
            alarm(0);
@@ -654,55 +641,81 @@ int status;
 /*
  *     'Clean up' this string.
  */
-char *clean(s, sending)
-register char *s;
-int sending;  /* set to 1 when sending (putting) this string. */
+char *clean(register char *s,
+           int sending)  /* set to 1 when sending (putting) this string. */
 {
-    char temp[STR_LEN], cur_chr;
-    register char *s1, *phchar;
+    char cur_chr;
+    char *s1, *p, *phchar;
     int add_return = sending;
-#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7'))
+    size_t len = strlen(s) + 3;                /* see len comments below */
+
+#define isoctal(chr)   (((chr) >= '0') && ((chr) <= '7'))
+#define isalnumx(chr)  ((((chr) >= '0') && ((chr) <= '9')) \
+                        || (((chr) >= 'a') && ((chr) <= 'z')) \
+                        || (((chr) >= 'A') && ((chr) <= 'Z')) \
+                        || (chr) == '_')
 
-    s1 = temp;
+    p = s1 = malloc(len);
+    if (!p)
+       fatal(2, "memory error!");
     while (*s) {
        cur_chr = *s++;
        if (cur_chr == '^') {
            cur_chr = *s++;
            if (cur_chr == '\0') {
-               *s1++ = '^';
+               *p++ = '^';
                break;
            }
            cur_chr &= 0x1F;
            if (cur_chr != 0) {
-               *s1++ = cur_chr;
+               *p++ = cur_chr;
+           }
+           continue;
+       }
+
+       if (use_env && cur_chr == '$') {                /* ARI */
+           char c;
+
+           phchar = s;
+           while (isalnumx(*s))
+               s++;
+           c = *s;             /* save */
+           *s = '\0';
+           phchar = getenv(phchar);
+           *s = c;             /* restore */
+           if (phchar) {
+               len += strlen(phchar);
+               s1 = grow(s1, &p, len);
+               while (*phchar)
+                   *p++ = *phchar++;
            }
            continue;
        }
 
        if (cur_chr != '\\') {
-           *s1++ = cur_chr;
+           *p++ = cur_chr;
            continue;
        }
 
        cur_chr = *s++;
        if (cur_chr == '\0') {
            if (sending) {
-               *s1++ = '\\';
-               *s1++ = '\\';
+               *p++ = '\\';
+               *p++ = '\\';    /* +1 for len */
            }
            break;
        }
 
        switch (cur_chr) {
        case 'b':
-           *s1++ = '\b';
+           *p++ = '\b';
            break;
 
        case 'c':
            if (sending && *s == '\0')
                add_return = 0;
            else
-               *s1++ = cur_chr;
+               *p++ = cur_chr;
            break;
 
        case '\\':
@@ -710,30 +723,33 @@ int sending;  /* set to 1 when sending (putting) this string. */
        case 'p':
        case 'd':
            if (sending)
-               *s1++ = '\\';
-
-           *s1++ = cur_chr;
+               *p++ = '\\';
+           *p++ = cur_chr;
            break;
 
        case 'T':
            if (sending && phone_num) {
-               for ( phchar = phone_num; *phchar != '\0'; phchar++) 
-                   *s1++ = *phchar;
+               len += strlen(phone_num);
+               s1 = grow(s1, &p, len);
+               for (phchar = phone_num; *phchar != '\0'; phchar++) 
+                   *p++ = *phchar;
            }
            else {
-               *s1++ = '\\';
-               *s1++ = 'T';
+               *p++ = '\\';
+               *p++ = 'T';
            }
            break;
 
        case 'U':
            if (sending && phone_num2) {
-               for ( phchar = phone_num2; *phchar != '\0'; phchar++) 
-                   *s1++ = *phchar;
+               len += strlen(phone_num2);
+               s1 = grow(s1, &p, len);
+               for (phchar = phone_num2; *phchar != '\0'; phchar++) 
+                   *p++ = *phchar;
            }
            else {
-               *s1++ = '\\';
-               *s1++ = 'U';
+               *p++ = '\\';
+               *p++ = 'U';
            }
            break;
 
@@ -742,30 +758,37 @@ int sending;  /* set to 1 when sending (putting) this string. */
            break;
 
        case 'r':
-           *s1++ = '\r';
+           *p++ = '\r';
            break;
 
        case 'n':
-           *s1++ = '\n';
+           *p++ = '\n';
            break;
 
        case 's':
-           *s1++ = ' ';
+           *p++ = ' ';
            break;
 
        case 't':
-           *s1++ = '\t';
+           *p++ = '\t';
            break;
 
        case 'N':
            if (sending) {
-               *s1++ = '\\';
-               *s1++ = '\0';
+               *p++ = '\\';
+               *p++ = '\0';
            }
            else
-               *s1++ = 'N';
+               *p++ = 'N';
            break;
-           
+
+       case '$':                       /* ARI */
+           if (use_env) {
+               *p++ = cur_chr;
+               break;
+           }
+           /* FALL THROUGH */
+
        default:
            if (isoctal (cur_chr)) {
                cur_chr &= 0x07;
@@ -780,33 +803,31 @@ int sending;  /* set to 1 when sending (putting) this string. */
 
                if (cur_chr != 0 || sending) {
                    if (sending && (cur_chr == '\\' || cur_chr == 0))
-                       *s1++ = '\\';
-                   *s1++ = cur_chr;
+                       *p++ = '\\';
+                   *p++ = cur_chr;
                }
                break;
            }
 
            if (sending)
-               *s1++ = '\\';
-           *s1++ = cur_chr;
+               *p++ = '\\';
+           *p++ = cur_chr;
            break;
        }
     }
 
     if (add_return)
-       *s1++ = '\r';
+       *p++ = '\r';    /* +2 for len */
 
-    *s1++ = '\0'; /* guarantee closure */
-    *s1++ = '\0'; /* terminate the string */
-    return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
+    *p = '\0';         /* +3 for len */
+    return s1;
 }
 
 /*
  * A modified version of 'strtok'. This version skips \ sequences.
  */
 
-char *expect_strtok (s, term)
-     char *s, *term;
+char *expect_strtok (char *s, char *term)
 {
     static  char *str   = "";
     int            escape_flag = 0;
@@ -860,8 +881,7 @@ char *expect_strtok (s, term)
  * Process the expect string
  */
 
-void chat_expect (s)
-char *s;
+void chat_expect (char *s)
 {
     char *expect;
     char *reply;
@@ -932,15 +952,16 @@ char *s;
            break;
 
        chat_send (reply);
+       checksigs();
     }
 
 /*
  * The expectation did not occur. This is terminal.
  */
     if (fail_reason)
-       logf("Failed (%s)", fail_reason);
+       msgf("Failed (%s)", fail_reason);
     else
-       logf("Failed");
+       msgf("Failed");
     terminate(exit_code);
 }
 
@@ -949,8 +970,7 @@ char *s;
  * the data.
  */
 
-char *character(c)
-int c;
+char *character(int c)
 {
     static char string[10];
     char *meta;
@@ -971,32 +991,37 @@ int c;
 /*
  *  process the reply string
  */
-void chat_send (s)
-register char *s;
+int chat_send (register char *s)
 {
     char file_data[STR_LEN];
+    int len, ret = 0;
+    struct sigaction sa;
 
     if (say_next) {
        say_next = 0;
-       s = clean(s,0);
-       write(2, s, strlen(s));
+       s = clean(s, 1);
+       len = strlen(s);
+       ret = write(2, s, len) != len;
         free(s);
-       return;
+       return ret;
     }
 
     if (hup_next) {
         hup_next = 0;
+       memset(&sa, 0, sizeof(sa));
+
        if (strcmp(s, "OFF") == 0)
-           signal(SIGHUP, SIG_IGN);
+           sa.sa_handler = SIG_IGN;
         else
-           signal(SIGHUP, sighup);
-        return;
+           sa.sa_handler = sighup;
+       sigaction(SIGHUP, &sa, NULL);
+        return 0;
     }
 
     if (echo_next) {
        echo_next = 0;
        echo = (strcmp(s, "ON") == 0);
-       return;
+       return 0;
     }
 
     if (abort_next) {
@@ -1009,15 +1034,14 @@ register char *s;
        
        s1 = clean(s, 0);
        
-       if (strlen(s1) > strlen(s)
-           || strlen(s1) + 1 > sizeof(fail_buffer))
+       if (strlen(s1) + 1 > sizeof(fail_buffer))
            fatal(1, "Illegal or too-long ABORT string ('%v')", s);
 
        abort_string[n_aborts++] = s1;
 
        if (verbose)
-           logf("abort on (%v)", s);
-       return;
+           msgf("abort on (%v)", s1);
+       return 0;
     }
 
     if (clear_abort_next) {
@@ -1030,8 +1054,7 @@ register char *s;
        
        s1 = clean(s, 0);
        
-       if (strlen(s1) > strlen(s)
-           || strlen(s1) + 1 > sizeof(fail_buffer))
+       if (strlen(s1) + 1 > sizeof(fail_buffer))
            fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s);
 
         old_max = n_aborts;
@@ -1042,13 +1065,13 @@ register char *s;
                pack++;
                n_aborts--;
                if (verbose)
-                   logf("clear abort on (%v)", s);
+                   msgf("clear abort on (%v)", s1);
            }
        }
         free(s1);
        if (pack)
            pack_array(abort_string,old_max);
-       return;
+       return 0;
     }
 
     if (report_next) {
@@ -1059,15 +1082,14 @@ register char *s;
            fatal(2, "Too many REPORT strings");
        
        s1 = clean(s, 0);
-       
-       if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
+       if (strlen(s1) + 1 > sizeof(fail_buffer))
            fatal(1, "Illegal or too-long REPORT string ('%v')", s);
        
        report_string[n_reports++] = s1;
        
        if (verbose)
-           logf("report (%v)", s);
-       return;
+           msgf("report (%v)", s1);
+       return 0;
     }
 
     if (clear_report_next) {
@@ -1080,7 +1102,7 @@ register char *s;
        
        s1 = clean(s, 0);
        
-       if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
+       if (strlen(s1) + 1 > sizeof(fail_buffer))
            fatal(1, "Illegal or too-long REPORT string ('%v')", s);
 
        old_max = n_reports;
@@ -1091,27 +1113,28 @@ register char *s;
                pack++;
                n_reports--;
                if (verbose)
-                   logf("clear report (%v)", s);
+                   msgf("clear report (%v)", s1);
            }
        }
         free(s1);
         if (pack)
            pack_array(report_string,old_max);
        
-       return;
+       return 0;
     }
 
     if (timeout_next) {
        timeout_next = 0;
+       s = clean(s, 0);
        timeout = atoi(s);
        
        if (timeout <= 0)
            timeout = DEFAULT_CHAT_TIMEOUT;
 
        if (verbose)
-           logf("timeout set to %d seconds", timeout);
-
-       return;
+           msgf("timeout set to %d seconds", timeout);
+       free(s);
+       return 0;
     }
 
     /*
@@ -1158,63 +1181,54 @@ register char *s;
 
     if (!put_string(s))
        fatal(1, "Failed");
+
+    return 0;
 }
 
-int get_char()
+int get_char(void)
 {
     int status;
     char c;
 
     status = read(0, &c, 1);
+    checksigs();
 
     switch (status) {
     case 1:
        return ((int)c & 0x7F);
 
     default:
-       logf("warning: read() on stdin returned %d", status);
+       msgf("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(c)
-int c;
+int put_char(int c)
 {
     int status;
     char ch = c;
 
     usleep(10000);             /* inter-character typing delay (?) */
+    checksigs();
 
     status = write(1, &ch, 1);
+    checksigs();
 
     switch (status) {
     case 1:
        return (0);
        
     default:
-       logf("warning: write() on stdout returned %d", status);
+       msgf("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 (c)
-int c;
+int write_char(int c)
 {
     if (alarmed || put_char(c) < 0) {
        alarm(0);
@@ -1222,26 +1236,28 @@ int c;
 
        if (verbose) {
            if (errno == EINTR || errno == EWOULDBLOCK)
-               logf(" -- write timed out");
+               msgf(" -- write timed out");
            else
-               logf(" -- write failed: %m");
+               msgf(" -- write failed: %m");
        }
        return (0);
     }
     return (1);
 }
 
-int put_string (s)
-register char *s;
+int put_string(register char *s)
 {
+    char *s1;
     quiet = 0;
+
     s = clean(s, 1);
+    s1 = s;
 
     if (verbose) {
        if (quiet)
-           logf("send (??????)");
+           msgf("send (?????\?)");
        else
-           logf("send (%v)", s);
+           msgf("send (%v)", s);
     }
 
     alarm(timeout); alarmed = 0;
@@ -1250,8 +1266,10 @@ register char *s;
        register char c = *s++;
 
        if (c != '\\') {
-           if (!write_char (c))
+           if (!write_char (c)) {
+               free(s1);
                return 0;
+           }
            continue;
        }
 
@@ -1270,14 +1288,18 @@ register char *s;
            break;
 
        default:
-           if (!write_char (c))
+           if (!write_char (c)) {
+               free(s1);
                return 0;
+           }
            break;
        }
+       checksigs();
     }
 
     alarm(0);
     alarmed = 0;
+    free(s1);
     return (1);
 }
 
@@ -1286,11 +1308,11 @@ register char *s;
  *     When called with -1, a '\n' character is generated when
  *     the cursor is not at the beginning of a line.
  */
-void echo_stderr(n)
-int n;
+int echo_stderr(int n)
 {
     static int need_lf;
     char *s;
+    int len, ret = 0;
 
     switch (n) {
     case '\r':         /* ignore '\r' */
@@ -1300,45 +1322,49 @@ int n;
            break;
        /* fall through */
     case '\n':
-       write(2, "\n", 1);
+       ret = write(2, "\n", 1) != 1;
        need_lf = 0;
        break;
     default:
        s = character(n);
-       write(2, s, strlen(s));
+       len = strlen(s);
+       ret = write(2, s, len) != len;
        need_lf = 1;
        break;
     }
+    checksigs();
+    return ret;
 }
 
 /*
  *     'Wait for' this string to appear on this file descriptor.
  */
-int get_string(string)
-register char *string;
+int get_string(register char *string)
 {
     char temp[STR_LEN];
     int c, printed = 0, len, minlen;
     register char *s = temp, *end = s + STR_LEN;
-    char *logged = temp;
+    char *s1, *logged = temp;
 
     fail_reason = (char *)0;
-    string = clean(string, 0);
+    string = s1 = clean(string, 0);
     len = strlen(string);
     minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
 
     if (verbose)
-       logf("expect (%v)", string);
+       msgf("expect (%v)", string);
 
     if (len > STR_LEN) {
-       logf("expect string is too long");
+       msgf("expect string is too long");
        exit_code = 1;
+       free(s1);
        return 0;
     }
 
     if (len == 0) {
        if (verbose)
-           logf("got it");
+           msgf("got it");
+       free(s1);
        return (1);
     }
 
@@ -1348,20 +1374,23 @@ register char *string;
     while ( ! alarmed && (c = get_char()) >= 0) {
        int n, abort_len, report_len;
 
-       if (echo)
-           echo_stderr(c);
+       if (echo) {
+           if (echo_stderr(c) != 0) {
+               fatal(2, "Could not write to stderr, %m");
+           }
+       }
        if (verbose && c == '\n') {
            if (s == logged)
-               logf("");       /* blank line */
+               msgf("");       /* blank line */
            else
-               logf("%0.*v", s - logged, logged);
+               msgf("%0.*v", s - logged, logged);
            logged = s + 1;
        }
 
        *s++ = c;
 
        if (verbose && s >= logged + 80) {
-           logf("%0.*v", s - logged, logged);
+           msgf("%0.*v", s - logged, logged);
            logged = s;
        }
 
@@ -1383,6 +1412,7 @@ register char *string;
                    strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now);
                    strcat (report_buffer, report_string[n]);
 
+                   free(report_string[n]);
                    report_string[n] = (char *) NULL;
                    report_gathering = 1;
                    break;
@@ -1392,8 +1422,10 @@ register char *string;
        else {
            if (!iscntrl (c)) {
                int rep_len = strlen (report_buffer);
-               report_buffer[rep_len]     = c;
-               report_buffer[rep_len + 1] = '\0';
+               if ((rep_len + 1) < sizeof(report_buffer)) {
+                   report_buffer[rep_len]     = c;
+                   report_buffer[rep_len + 1] = '\0';
+               }
            }
            else {
                report_gathering = 0;
@@ -1406,12 +1438,13 @@ register char *string;
            strncmp(s - len, string, len) == 0) {
            if (verbose) {
                if (s > logged)
-                   logf("%0.*v", s - logged, logged);
-               logf(" -- got it\n");
+                   msgf("%0.*v", s - logged, logged);
+               msgf(" -- got it\n");
            }
 
            alarm(0);
            alarmed = 0;
+           free(s1);
            return (1);
        }
 
@@ -1420,21 +1453,23 @@ register char *string;
                strncmp(s - abort_len, abort_string[n], abort_len) == 0) {
                if (verbose) {
                    if (s > logged)
-                       logf("%0.*v", s - logged, logged);
-                   logf(" -- failed");
+                       msgf("%0.*v", s - logged, logged);
+                   msgf(" -- failed");
                }
 
                alarm(0);
                alarmed = 0;
                exit_code = n + 4;
                strcpy(fail_reason = fail_buffer, abort_string[n]);
+               free(s1);
                return (0);
            }
        }
 
        if (s >= end) {
            if (logged < s - minlen) {
-               logf("%0.*v", s - logged, logged);
+               if (verbose)
+                   msgf("%0.*v", s - logged, logged);
                logged = s;
            }
            s -= minlen;
@@ -1444,20 +1479,21 @@ register char *string;
        }
 
        if (alarmed && verbose)
-           logf("warning: alarm synchronization problem");
+           msgf("warning: alarm synchronization problem");
     }
 
     alarm(0);
     
     if (verbose && printed) {
        if (alarmed)
-           logf(" -- read timed out");
+           msgf(" -- read timed out");
        else
-           logf(" -- read failed: %m");
+           msgf(" -- read failed: %m");
     }
 
     exit_code = 3;
     alarmed   = 0;
+    free(s1);
     return (0);
 }
 
@@ -1482,9 +1518,8 @@ register char *string;
 
 extern int       select();
 
-int
-usleep( usec )                           /* returns 0 if ok, else -1 */
-    long               usec;           /* delay in microseconds */
+/* returns 0 if ok, else -1 */
+int usleep(long usec)          /* delay in microseconds */
 {
     static struct {            /* `timeval' */
        long    tv_sec;         /* seconds */
@@ -1498,10 +1533,9 @@ usleep( usec )                             /* returns 0 if ok, else -1 */
 }
 #endif
 
-void
-pack_array (array, end)
-    char **array; /* The address of the array of string pointers */
-    int    end;   /* The index of the next free entry before CLR_ */
+void pack_array (
+    char **array, /* The address of the array of string pointers */
+    int end)      /* The index of the next free entry before CLR_ */
 {
     int i, j;
 
@@ -1527,11 +1561,7 @@ pack_array (array, end)
 #define OUTCHAR(c)     (buflen > 0? (--buflen, *buf++ = (c)): 0)
 
 int
-vfmtmsg(buf, buflen, fmt, args)
-    char *buf;
-    int buflen;
-    const char *fmt;
-    va_list args;
+vfmtmsg(char *buf, int buflen, const char *fmt, va_list args)
 {
     int c, i, n;
     int width, prec, fillch;