mods & restructuring to support Solaris 2
[ppp.git] / chat / chat.c
1 /*
2  *      Chat -- a program for automatic session establishment (i.e. dial
3  *              the phone and log in).
4  *
5  *      This software is in the public domain.
6  *
7  *      Please send all bug reports, requests for information, etc. to:
8  *
9  *              Al Longyear (longyear@netcom.com)
10  *              (I was the last person to change this code.)
11  *
12  *      The original author is:
13  *
14  *              Karl Fox <karl@MorningStar.Com>
15  *              Morning Star Technologies, Inc.
16  *              1760 Zollinger Road
17  *              Columbus, OH  43221
18  *              (614)451-1883
19  */
20
21 static char rcsid[] = "$Id: chat.c,v 1.8 1995/05/19 04:19:29 paulus Exp $";
22
23 #include <stdio.h>
24 #include <fcntl.h>
25 #include <signal.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <syslog.h>
32
33 #ifndef TERMIO
34 #undef  TERMIOS
35 #define TERMIOS
36 #endif
37
38 #ifdef TERMIO
39 #include <termio.h>
40 #endif
41 #ifdef TERMIOS
42 #include <termios.h>
43 #endif
44
45 #define STR_LEN 1024
46
47 #ifndef SIGTYPE
48 #define SIGTYPE void
49 #endif
50
51 #ifdef __STDC__
52 #undef __P
53 #define __P(x)  x
54 #else
55 #define __P(x)  ()
56 #define const
57 #endif
58
59 #ifndef O_NONBLOCK
60 #define O_NONBLOCK      FNDELAY
61 #endif
62
63 /*************** Micro getopt() *********************************************/
64 #define OPTION(c,v)     (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
65                                 (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
66                                 &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
67 #define OPTARG(c,v)     (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
68                                 (_O=4,(char*)0):(char*)0)
69 #define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0)
70 #define ARG(c,v)        (c?(--c,*v++):(char*)0)
71
72 static int _O = 0;              /* Internal state */
73 /*************** Micro getopt() *********************************************/
74
75 char *program_name;
76
77 #define MAX_ABORTS              50
78 #define DEFAULT_CHAT_TIMEOUT    45
79
80 int verbose = 0;
81 int quiet = 0;
82 char *lock_file = (char *)0;
83 char *chat_file = (char *)0;
84 int timeout = DEFAULT_CHAT_TIMEOUT;
85
86 int have_tty_parameters = 0;
87 #ifdef TERMIO
88 struct termio saved_tty_parameters;
89 #endif
90 #ifdef TERMIOS
91 struct termios saved_tty_parameters;
92 #endif
93
94 char *abort_string[MAX_ABORTS], *fail_reason = (char *)0,
95         fail_buffer[50];
96 int n_aborts = 0, abort_next = 0, timeout_next = 0;
97
98 void *dup_mem __P((void *b, size_t c));
99 void *copy_of __P((char *s));
100 void usage __P((void));
101 void logf __P((const char *str));
102 void logflush __P((void));
103 void fatal __P((const char *msg));
104 void sysfatal __P((const char *msg));
105 SIGTYPE sigalrm __P((int signo));
106 SIGTYPE sigint __P((int signo));
107 SIGTYPE sigterm __P((int signo));
108 SIGTYPE sighup __P((int signo));
109 void unalarm __P((void));
110 void init __P((void));
111 void set_tty_parameters __P((void));
112 void break_sequence __P((void));
113 void terminate __P((int status));
114 void do_file __P((char *chat_file));
115 int  get_string __P((register char *string));
116 int  put_string __P((register char *s));
117 int  write_char __P((int c));
118 int  put_char __P((int c));
119 int  get_char __P((void));
120 void chat_send __P((register char *s));
121 char *character __P((int c));
122 void chat_expect __P((register char *s));
123 char *clean __P((register char *s, int sending));
124 void break_sequence __P((void));
125 void terminate __P((int status));
126 void die __P((void));
127
128 void *dup_mem(b, c)
129 void *b;
130 size_t c;
131     {
132     void *ans = malloc (c);
133     if (!ans)
134         fatal ("memory error!\n");
135     memcpy (ans, b, c);
136     return ans;
137     }
138
139 void *copy_of (s)
140 char *s;
141     {
142     return dup_mem (s, strlen (s) + 1);
143     }
144
145 /*
146  *      chat [ -v ] [ -t timeout ] [ -f chat-file ] \
147  *              [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]]
148  *
149  *      Perform a UUCP-dialer-like chat script on stdin and stdout.
150  */
151 int
152 main(argc, argv)
153 int argc;
154 char **argv;
155     {
156     int option;
157     char *arg;
158
159     program_name = *argv;
160
161     while (option = OPTION(argc, argv))
162         switch (option)
163             {
164             case 'v':
165                 ++verbose;
166                 break;
167
168             case 'f':
169                 if (arg = OPTARG(argc, argv))
170                     chat_file = copy_of(arg);
171                 else
172                     usage();
173
174                 break;
175
176             case 'l':
177                 if (arg = OPTARG(argc, argv))
178                     lock_file = copy_of(arg);
179                 else
180                     usage();
181
182                 break;
183
184             case 't':
185                 if (arg = OPTARG(argc, argv))
186                     timeout = atoi(arg);
187                 else
188                     usage();
189
190                 break;
191
192             default:
193                 usage();
194             }
195
196 #ifdef ultrix
197     openlog("chat", LOG_PID);
198 #else
199     openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2);
200
201     if (verbose) {
202         setlogmask(LOG_UPTO(LOG_INFO));
203     } else {
204         setlogmask(LOG_UPTO(LOG_WARNING));
205     }
206 #endif
207
208     init();
209     
210     if (chat_file != NULL)
211         {
212         arg = ARG(argc, argv);
213         if (arg != NULL)
214             usage();
215         else
216             do_file (chat_file);
217         }
218     else
219         {
220         while (arg = ARG(argc, argv))
221             {
222             chat_expect(arg);
223
224             if (arg = ARG(argc, argv))
225                 chat_send(arg);
226             }
227         }
228
229     terminate(0);
230     }
231
232 /*
233  *  Process a chat script when read from a file.
234  */
235
236 void do_file (chat_file)
237 char *chat_file;
238     {
239     int linect, len, sendflg;
240     char *sp, *arg, quote;
241     char buf [STR_LEN];
242     FILE *cfp;
243
244     if ((cfp = fopen (chat_file, "r")) == NULL)
245         {
246         syslog (LOG_ERR, "%s -- open failed: %m", chat_file);
247         terminate (1);
248         }
249
250     linect = 0;
251     sendflg = 0;
252
253     while (fgets(buf, STR_LEN, cfp) != NULL)
254         {
255         sp = strchr (buf, '\n');
256         if (sp)
257             *sp = '\0';
258
259         linect++;
260         sp = buf;
261         while (*sp != '\0')
262             {
263             if (*sp == ' ' || *sp == '\t')
264                 {
265                 ++sp;
266                 continue;
267                 }
268
269             if (*sp == '"' || *sp == '\'')
270                 {
271                 quote = *sp++;
272                 arg = sp;
273                 while (*sp != quote)
274                     {
275                     if (*sp == '\0')
276                         {
277                         syslog (LOG_ERR, "unterminated quote (line %d)",
278                                 linect);
279                         terminate (1);
280                         }
281                     
282                     if (*sp++ == '\\')
283                         if (*sp != '\0')
284                             ++sp;
285                     }
286                 }
287             else
288                 {
289                 arg = sp;
290                 while (*sp != '\0' && *sp != ' ' && *sp != '\t')
291                     ++sp;
292                 }
293
294             if (*sp != '\0')
295                 *sp++ = '\0';
296
297             if (sendflg)
298                 {
299                 chat_send (arg);
300                 }
301             else
302                 {
303                 chat_expect (arg);
304                 }
305             sendflg = !sendflg;
306             }
307         }
308     fclose (cfp);
309     }
310
311 /*
312  *      We got an error parsing the command line.
313  */
314 void usage()
315     {
316     fprintf(stderr, "\
317 Usage: %s [-v] [-t timeout] {-f chat-file || chat-script}\n",
318             program_name);
319     exit(1);
320     }
321
322 char line[256];
323 char *p;
324
325 void logf (str)
326 const char *str;
327     {
328     p = line + strlen(line);
329     strcat (p, str);
330
331     if (str[strlen(str)-1] == '\n')
332         {
333         syslog (LOG_INFO, "%s", line);
334         line[0] = 0;
335         }
336     }
337
338 void logflush()
339     {
340     if (line[0] != 0)
341         {
342         syslog(LOG_INFO, "%s", line);
343         line[0] = 0;
344         }
345     }
346
347 /*
348  *      Terminate with an error.
349  */
350 void die()
351     {
352     terminate(1);
353     }
354
355 /*
356  *      Print an error message and terminate.
357  */
358
359 void fatal (msg)
360 const char *msg;
361     {
362     syslog(LOG_ERR, "%s", msg);
363     terminate(1);
364     }
365
366 /*
367  *      Print an error message along with the system error message and
368  *      terminate.
369  */
370
371 void sysfatal (msg)
372 const char *msg;
373     {
374     syslog(LOG_ERR, "%s: %m", msg);
375     terminate(1);
376     }
377
378 int alarmed = 0;
379
380 SIGTYPE sigalrm(signo)
381 int signo;
382     {
383     int flags;
384
385     alarm(1);
386     alarmed = 1;                /* Reset alarm to avoid race window */
387     signal(SIGALRM, sigalrm);   /* that can cause hanging in read() */
388
389     logflush();
390     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
391         sysfatal("Can't get file mode flags on stdin");
392     else
393         if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1)
394             sysfatal("Can't set file mode flags on stdin");
395
396     if (verbose)
397         {
398         syslog(LOG_INFO, "alarm");
399         }
400     }
401
402 void unalarm()
403     {
404     int flags;
405
406     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
407         sysfatal("Can't get file mode flags on stdin");
408     else
409         if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1)
410             sysfatal("Can't set file mode flags on stdin");
411     }
412
413 SIGTYPE sigint(signo)
414 int signo;
415     {
416     fatal("SIGINT");
417     }
418
419 SIGTYPE sigterm(signo)
420 int signo;
421     {
422     fatal("SIGTERM");
423     }
424
425 SIGTYPE sighup(signo)
426 int signo;
427     {
428     fatal("SIGHUP");
429     }
430
431 void init()
432     {
433     signal(SIGINT, sigint);
434     signal(SIGTERM, sigterm);
435     signal(SIGHUP, sighup);
436
437     set_tty_parameters();
438     signal(SIGALRM, sigalrm);
439     alarm(0);
440     alarmed = 0;
441     }
442
443 void set_tty_parameters()
444     {
445 #ifdef TERMIO
446     struct termio t;
447
448     if (ioctl(0, TCGETA, &t) < 0)
449         sysfatal("Can't get terminal parameters");
450 #endif
451 #ifdef TERMIOS
452     struct termios t;
453
454     if (tcgetattr(0, &t) < 0)
455         sysfatal("Can't get terminal parameters");
456 #endif
457
458     saved_tty_parameters = t;
459     have_tty_parameters = 1;
460
461     t.c_iflag |= IGNBRK | ISTRIP | IGNPAR;
462     t.c_oflag  = 0;
463     t.c_lflag  = 0;
464     t.c_cc[VERASE] = t.c_cc[VKILL] = 0;
465     t.c_cc[VMIN] = 1;
466     t.c_cc[VTIME] = 0;
467
468 #ifdef TERMIO
469     if (ioctl(0, TCSETA, &t) < 0)
470         sysfatal("Can't set terminal parameters");
471 #endif
472 #ifdef TERMIOS
473     if (tcsetattr(0, TCSANOW, &t) < 0)
474         sysfatal("Can't set terminal parameters");
475 #endif
476     }
477
478 void break_sequence()
479     {
480 #ifdef TERMIOS
481     tcsendbreak (0, 0);
482 #endif
483     }
484
485 void terminate(status)
486 int status;
487     {
488     if (have_tty_parameters &&
489 #ifdef TERMIO
490         ioctl(0, TCSETA, &saved_tty_parameters) < 0
491 #endif
492 #ifdef TERMIOS
493         tcsetattr(0, TCSANOW, &saved_tty_parameters) < 0
494 #endif
495         ) {
496         syslog(LOG_ERR, "Can't restore terminal parameters: %m");
497         exit(1);
498         }
499     exit(status);
500     }
501
502 /*
503  *      'Clean up' this string.
504  */
505 char *clean(s, sending)
506 register char *s;
507 int sending;
508     {
509     char temp[STR_LEN], cur_chr;
510     register char *s1;
511     int add_return = sending;
512 #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7'))
513
514     s1 = temp;
515     while (*s)
516         {
517         cur_chr = *s++;
518         if (cur_chr == '^')
519             {
520             cur_chr = *s++;
521             if (cur_chr == '\0')
522                 {
523                 *s1++ = '^';
524                 break;
525                 }
526             cur_chr &= 0x1F;
527             if (cur_chr != 0)
528                 *s1++ = cur_chr;
529             continue;
530             }
531
532         if (cur_chr != '\\')
533             {
534             *s1++ = cur_chr;
535             continue;
536             }
537
538         cur_chr = *s++;
539         if (cur_chr == '\0')
540             {
541             if (sending)
542                 {
543                 *s1++ = '\\';
544                 *s1++ = '\\';
545                 }
546             break;
547             }
548
549         switch (cur_chr)
550             {
551         case 'b':
552             *s1++ = '\b';
553             break;
554
555         case 'c':
556             if (sending && *s == '\0')
557                 add_return = 0;
558             else
559                 *s1++ = cur_chr;
560             break;
561
562         case '\\':
563         case 'K':
564         case 'p':
565         case 'd':
566             if (sending)
567                 *s1++ = '\\';
568
569             *s1++ = cur_chr;
570             break;
571
572         case 'q':
573             quiet = ! quiet;
574             break;
575
576         case 'r':
577             *s1++ = '\r';
578             break;
579
580         case 'n':
581             *s1++ = '\n';
582             break;
583
584         case 's':
585             *s1++ = ' ';
586             break;
587
588         case 't':
589             *s1++ = '\t';
590             break;
591
592         case 'N':
593             if (sending)
594                 {
595                 *s1++ = '\\';
596                 *s1++ = '\0';
597                 }
598             else
599                 *s1++ = 'N';
600             break;
601             
602         default:
603             if (isoctal (cur_chr))
604                 {
605                 cur_chr &= 0x07;
606                 if (isoctal (*s))
607                     {
608                     cur_chr <<= 3;
609                     cur_chr |= *s++ - '0';
610                     if (isoctal (*s))
611                         {
612                         cur_chr <<= 3;
613                         cur_chr |= *s++ - '0';
614                         }
615                     }
616
617                 if (cur_chr != 0 || sending)
618                     {
619                     if (sending && (cur_chr == '\\' || cur_chr == 0))
620                         *s1++ = '\\';
621                     *s1++ = cur_chr;
622                     }
623                 break;
624                 }
625
626             if (sending)
627                 *s1++ = '\\';
628             *s1++ = cur_chr;
629             break;
630             }
631         }
632
633     if (add_return)
634         *s1++ = '\r';
635
636     *s1++ = '\0'; /* guarantee closure */
637     *s1++ = '\0'; /* terminate the string */
638     return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
639     }
640
641 /*
642  * Process the expect string
643  */
644 void chat_expect(s)
645 register char *s;
646     {
647     if (strcmp(s, "ABORT") == 0)
648         {
649         ++abort_next;
650         return;
651         }
652
653     if (strcmp(s, "TIMEOUT") == 0)
654         {
655         ++timeout_next;
656         return;
657         }
658
659     while (*s)
660         {
661         register char *hyphen;
662
663         for (hyphen = s; *hyphen; ++hyphen)
664             if (*hyphen == '-')
665                 if (hyphen == s || hyphen[-1] != '\\')
666                     break;
667         
668         if (*hyphen == '-')
669             {
670             *hyphen = '\0';
671
672             if (get_string(s))
673                 return;
674             else
675                 {
676                 s = hyphen + 1;
677
678                 for (hyphen = s; *hyphen; ++hyphen)
679                     if (*hyphen == '-')
680                         if (hyphen == s || hyphen[-1] != '\\')
681                             break;
682
683                 if (*hyphen == '-')
684                     {
685                     *hyphen = '\0';
686
687                     chat_send(s);
688                     s = hyphen + 1;
689                     }
690                 else
691                     {
692                     chat_send(s);
693                     return;
694                     }
695                 }
696             }
697         else
698             if (get_string(s))
699                 return;
700             else
701                 {
702                 if (fail_reason)
703                     syslog(LOG_INFO, "Failed (%s)", fail_reason);
704                 else
705                     syslog(LOG_INFO, "Failed");
706
707                 terminate(1);
708                 }
709         }
710     }
711
712 char *character(c)
713 int c;
714     {
715     static char string[10];
716     char *meta;
717
718     meta = (c & 0x80) ? "M-" : "";
719     c &= 0x7F;
720
721     if (c < 32)
722         sprintf(string, "%s^%c", meta, (int)c + '@');
723     else
724         if (c == 127)
725             sprintf(string, "%s^?", meta);
726         else
727             sprintf(string, "%s%c", meta, c);
728
729     return (string);
730     }
731
732 /*
733  *  process the reply string
734  */
735 void chat_send (s)
736 register char *s;
737     {
738     if (abort_next)
739         {
740         char *s1;
741
742         abort_next = 0;
743
744         if (n_aborts >= MAX_ABORTS)
745             fatal("Too many ABORT strings");
746
747         s1 = clean(s, 0);
748
749         if (strlen(s1) > strlen(s)
750             || strlen(s1) + 1 > sizeof(fail_buffer))
751             {
752             syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s);
753             die();
754             }
755
756         abort_string[n_aborts++] = s1;
757
758         if (verbose)
759             {
760             logf("abort on (");
761
762             for (s1 = s; *s1; ++s1)
763                 logf(character(*s1));
764
765             logf(")\n");
766             }
767         }
768     else
769         if (timeout_next)
770             {
771             timeout_next = 0;
772             timeout = atoi(s);
773
774             if (timeout <= 0)
775                 timeout = DEFAULT_CHAT_TIMEOUT;
776
777             if (verbose)
778                 {
779                 syslog(LOG_INFO, "timeout set to %d seconds", timeout);
780                 }
781             }
782         else
783             {
784             if (strcmp(s, "EOT") == 0)
785                 s = "^D\\c";
786             else
787                 if (strcmp(s, "BREAK") == 0)
788                     s = "\\K\\c";
789             if ( ! put_string(s))
790                 {
791                 syslog(LOG_INFO, "Failed");
792                 terminate(1);
793                 }
794             }
795     }
796
797 int get_char()
798     {
799     int status;
800     char c;
801
802     status = read(0, &c, 1);
803
804     switch (status)
805         {
806         case 1:
807             return ((int)c & 0x7F);
808
809         default:
810             syslog(LOG_WARNING, "warning: read() on stdin returned %d",
811                    status);
812
813         case -1:
814             if ((status = fcntl(0, F_GETFL, 0)) == -1)
815                 sysfatal("Can't get file mode flags on stdin");
816             else
817                 if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
818                     sysfatal("Can't set file mode flags on stdin");
819
820             return (-1);
821         }
822     }
823
824 int put_char(c)
825 int c;
826     {
827     int status;
828     char ch = c;
829
830     usleep(10000);              /* inter-character typing delay (?) */
831
832     status = write(1, &ch, 1);
833
834     switch (status)
835         {
836         case 1:
837             return (0);
838
839         default:
840             syslog(LOG_WARNING, "warning: write() on stdout returned %d",
841                    status);
842
843         case -1:
844             if ((status = fcntl(0, F_GETFL, 0)) == -1)
845                 sysfatal("Can't get file mode flags on stdin");
846             else
847                 if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
848                     sysfatal("Can't set file mode flags on stdin");
849
850             return (-1);
851         }
852     }
853
854 int write_char (c)
855 int c;
856     {
857     if (alarmed || put_char(c) < 0)
858         {
859         extern int errno;
860
861         alarm(0); alarmed = 0;
862
863         if (verbose)
864             {
865             if (errno == EINTR || errno == EWOULDBLOCK)
866                 syslog(LOG_INFO, " -- write timed out");
867             else
868                 syslog(LOG_INFO, " -- write failed: %m");
869             }
870         return (0);
871         }
872     return (1);
873     }
874
875 int put_string (s)
876 register char *s;
877     {
878     s = clean(s, 1);
879
880     if (verbose)
881         {
882         logf("send (");
883
884         if (quiet)
885             logf("??????");
886         else
887             {
888             register char *s1 = s;
889
890             for (s1 = s; *s1; ++s1)
891                 logf(character(*s1));
892             }
893
894         logf(")\n");
895         }
896
897     alarm(timeout); alarmed = 0;
898
899     while (*s)
900         {
901         register char c = *s++;
902
903         if (c != '\\')
904             {
905             if (!write_char (c))
906                 return 0;
907             continue;
908             }
909
910         c = *s++;
911         switch (c)
912             {
913         case 'd':
914             sleep(1);
915             break;
916
917         case 'K':
918             break_sequence();
919             break;
920
921         case 'p':
922             usleep(10000); /* 1/100th of a second. */
923             break;
924
925         default:
926             if (!write_char (c))
927                 return 0;
928             break;
929             }
930         }
931
932     alarm(0);
933     alarmed = 0;
934     return (1);
935     }
936
937 /*
938  *      'Wait for' this string to appear on this file descriptor.
939  */
940 int get_string(string)
941 register char *string;
942     {
943     char temp[STR_LEN];
944     int c, printed = 0, len, minlen;
945     register char *s = temp, *end = s + STR_LEN;
946
947     fail_reason = (char *)0;
948     string = clean(string, 0);
949     len = strlen(string);
950     minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
951
952     if (verbose)
953         {
954         register char *s1;
955
956         logf("expect (");
957
958         for (s1 = string; *s1; ++s1)
959             logf(character(*s1));
960
961         logf(")\n");
962         }
963
964     if (len > STR_LEN)
965         {
966         syslog(LOG_INFO, "expect string is too long");
967         return 0;
968         }
969
970     if (len == 0)
971         {
972         if (verbose)
973             {
974             syslog(LOG_INFO, "got it");
975             }
976
977         return (1);
978         }
979
980     alarm(timeout); alarmed = 0;
981
982     while ( ! alarmed && (c = get_char()) >= 0)
983         {
984         int n, abort_len;
985
986         if (verbose)
987             {
988             if (c == '\n')
989                 logf("\n");
990             else
991                 logf(character(c));
992             }
993
994         *s++ = c;
995
996         if (s - temp >= len &&
997             c == string[len - 1] &&
998             strncmp(s - len, string, len) == 0)
999             {
1000             if (verbose)
1001                 {
1002                 logf(" -- got it\n");
1003                 }
1004
1005             alarm(0); alarmed = 0;
1006             return (1);
1007             }
1008
1009         for (n = 0; n < n_aborts; ++n)
1010             if (s - temp >= (abort_len = strlen(abort_string[n])) &&
1011                 strncmp(s - abort_len, abort_string[n], abort_len) == 0)
1012                 {
1013                 if (verbose)
1014                     {
1015                     logf(" -- failed\n");
1016                     }
1017
1018                 alarm(0); alarmed = 0;
1019                 strcpy(fail_reason = fail_buffer, abort_string[n]);
1020                 return (0);
1021                 }
1022
1023         if (s >= end)
1024             {
1025             strncpy(temp, s - minlen, minlen);
1026             s = temp + minlen;
1027             }
1028
1029         if (alarmed && verbose)
1030             syslog(LOG_WARNING, "warning: alarm synchronization problem");
1031         }
1032
1033     alarm(0);
1034     
1035     if (verbose && printed)
1036         {
1037         if (alarmed)
1038             logf(" -- read timed out\n");
1039         else
1040             {
1041             logflush();
1042             syslog(LOG_INFO, " -- read failed: %m");
1043             }
1044         }
1045
1046     alarmed = 0;
1047     return (0);
1048     }
1049
1050 #ifdef NO_USLEEP
1051 #include <sys/types.h>
1052 #include <sys/time.h>
1053
1054 /*
1055   usleep -- support routine for 4.2BSD system call emulations
1056   last edit:  29-Oct-1984     D A Gwyn
1057   */
1058
1059 extern int        select();
1060
1061 int
1062 usleep( usec )                            /* returns 0 if ok, else -1 */
1063     long                usec;           /* delay in microseconds */
1064 {
1065     static struct                       /* `timeval' */
1066         {
1067             long        tv_sec;         /* seconds */
1068             long        tv_usec;        /* microsecs */
1069         }   delay;          /* _select() timeout */
1070
1071     delay.tv_sec = usec / 1000000L;
1072     delay.tv_usec = usec % 1000000L;
1073
1074     return select( 0, (long *)0, (long *)0, (long *)0, &delay );
1075 }
1076 #endif