OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [expect/] [exp_clib.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/* exp_clib.c - top-level functions in the expect C library, libexpect.a
2
 
3
Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90
4
 
5
Design and implementation of this program was paid for by U.S. tax
6
dollars.  Therefore it is public domain.  However, the author and NIST
7
would appreciate credit if this program or parts of it are used.
8
*/
9
 
10
#include "expect_cf.h"
11
#include <stdio.h>
12
#include <setjmp.h>
13
#ifdef HAVE_INTTYPES_H
14
#  include <inttypes.h>
15
#endif
16
#include <sys/types.h>
17
#include <sys/ioctl.h>
18
 
19
#ifdef HAVE_UNISTD_H
20
#  include <unistd.h>
21
#endif
22
 
23
#ifdef TIME_WITH_SYS_TIME
24
# include <sys/time.h>
25
# include <time.h>
26
#else
27
# if HAVE_SYS_TIME_H
28
#  include <sys/time.h>
29
# else
30
#  include <time.h>
31
# endif
32
#endif
33
 
34
#ifdef CRAY
35
# ifndef TCSETCTTY
36
#  if defined(HAVE_TERMIOS)
37
#   include <termios.h>
38
#  else
39
#   include <termio.h>
40
#  endif
41
# endif
42
#endif
43
 
44
#ifdef HAVE_SYS_FCNTL_H
45
#  include <sys/fcntl.h>
46
#else
47
#  include <fcntl.h>
48
#endif
49
 
50
#ifdef HAVE_STRREDIR_H
51
#include <sys/strredir.h>
52
# ifdef SRIOCSREDIR
53
#  undef TIOCCONS
54
# endif
55
#endif
56
 
57
#include <signal.h>
58
/*#include <memory.h> - deprecated - ANSI C moves them into string.h */
59
#include "string.h"
60
 
61
#include <errno.h>
62
#include "exp_rename.h"
63
#define EXP_AVOID_INCLUDING_TCL_H
64
#include "expect.h"
65
#include "exp_int.h"
66
 
67
#include "exp_printify.h"
68
 
69
#ifdef NO_STDLIB_H
70
#include "../compat/stdlib.h"
71
#else
72
#include <stdlib.h>             /* for malloc */
73
#endif
74
 
75
#define EXP_MATCH_MAX   2000
76
/* public */
77
char *exp_buffer = 0;
78
char *exp_buffer_end = 0;
79
char *exp_match = 0;
80
char *exp_match_end = 0;
81
int exp_match_max = EXP_MATCH_MAX;      /* bytes */
82
int exp_full_buffer = FALSE;            /* don't return on full buffer */
83
int exp_remove_nulls = TRUE;
84
int exp_timeout = 10;                   /* seconds */
85
int exp_pty_timeout = 5;                /* seconds - see CRAY below */
86
int exp_autoallocpty = TRUE;            /* if TRUE, we do allocation */
87
int exp_pty[2];                         /* master is [0], slave is [1] */
88
int exp_pid;
89
char *exp_stty_init = 0;         /* initial stty args */
90
int exp_ttycopy = TRUE;                 /* copy tty parms from /dev/tty */
91
int exp_ttyinit = TRUE;                 /* set tty parms to sane state */
92
int exp_console = FALSE;                /* redirect console */
93
void (*exp_child_exec_prelude)() = 0;
94
 
95
jmp_buf exp_readenv;            /* for interruptable read() */
96
int exp_reading = FALSE;        /* whether we can longjmp or not */
97
 
98
void debuglog();
99
int getptymaster();
100
int getptyslave();
101
int Exp_StringMatch();
102
 
103
#define sysreturn(x)    return(errno = x, -1)
104
 
105
void exp_init_pty();
106
 
107
/*
108
   The following functions are linked from the Tcl library.  They
109
   don't cause anything else in the library to be dragged in, so it
110
   shouldn't cause any problems (e.g., bloat).
111
 
112
   The functions are relatively small but painful enough that I don't care
113
   to recode them.  You may, if you absolutely want to get rid of any
114
   vestiges of Tcl.
115
*/
116
extern char *TclGetRegError();
117
extern void TclRegError();
118
char *Tcl_ErrnoMsg();
119
 
120
 
121
 
122
static unsigned int bufsiz = 2*EXP_MATCH_MAX;
123
 
124
static struct f {
125
        int valid;
126
 
127
        char *buffer;           /* buffer of matchable chars */
128
        char *buffer_end;       /* one beyond end of matchable chars */
129
        /*char *match;          /* start of matched string */
130
        char *match_end;        /* one beyond end of matched string */
131
        int msize;              /* size of allocate space */
132
                                /* actual size is one larger for null */
133
} *fs = 0;
134
 
135
static int fd_alloc_max = -1;   /* max fd allocated */
136
 
137
/* translate fd or fp to fd */
138
static struct f *
139
fdfp2f(fd,fp)
140
int fd;
141
FILE *fp;
142
{
143
        if (fd == -1) return(fs + fileno(fp));
144
        else return(fs + fd);
145
}
146
 
147
static struct f *
148
fd_new(fd)
149
int fd;
150
{
151
        int i, low;
152
        struct f *fp;
153
        struct f *newfs;        /* temporary, so we don't lose old fs */
154
 
155
        if (fd > fd_alloc_max) {
156
                if (!fs) {      /* no fd's yet allocated */
157
                        newfs = (struct f *)malloc(sizeof(struct f)*(fd+1));
158
                        low = 0;
159
                } else {                /* enlarge fd table */
160
                        newfs = (struct f *)realloc((char *)fs,sizeof(struct f)*(fd+1));
161
                        low = fd_alloc_max+1;
162
                }
163
                fs = newfs;
164
                fd_alloc_max = fd;
165
                for (i = low; i <= fd_alloc_max; i++) { /* init new entries */
166
                        fs[i].valid = FALSE;
167
                }
168
        }
169
 
170
        fp = fs+fd;
171
 
172
        if (!fp->valid) {
173
                /* initialize */
174
                fp->buffer = malloc((unsigned)(bufsiz+1));
175
                if (!fp->buffer) return 0;
176
                fp->msize = bufsiz;
177
                fp->valid = TRUE;
178
        }
179
        fp->buffer_end = fp->buffer;
180
        fp->match_end = fp->buffer;
181
        return fp;
182
 
183
}
184
 
185
/* returns fd of master side of pty */
186
int
187
exp_spawnv(file,argv)
188
char *file;
189
char *argv[];   /* some compiler complains about **argv? */
190
{
191
        int cc;
192
        int errorfd;    /* place to stash fileno(stderr) in child */
193
                        /* while we're setting up new stderr */
194
        int ttyfd;
195
        int sync_fds[2];
196
        int sync2_fds[2];
197
        char sync_byte;
198
#ifdef PTYTRAP_DIES
199
        int slave_write_ioctls = 1;
200
                /* by default, slave will be write-ioctled this many times */
201
#endif
202
 
203
        static int first_time = TRUE;
204
 
205
        if (first_time) {
206
                first_time = FALSE;
207
                exp_init_pty();
208
                exp_init_tty();
209
        }
210
 
211
        if (!file || !argv) sysreturn(EINVAL);
212
        if (!argv[0] || strcmp(file,argv[0])) {
213
                debuglog("expect: warning: file (%s) != argv[0] (%s)\n",
214
                        file,
215
                        argv[0]?argv[0]:"");
216
        }
217
 
218
#ifdef PTYTRAP_DIES
219
/* any extraneous ioctl's that occur in slave must be accounted for
220
when trapping, see below in child half of fork */
221
#if defined(TIOCSCTTY) && !defined(CIBAUD) && !defined(sun) && !defined(hp9000s300)
222
        slave_write_ioctls++;
223
#endif
224
#endif /*PTYTRAP_DIES*/
225
 
226
        if (exp_autoallocpty) {
227
                if (0 > (exp_pty[0] = getptymaster())) sysreturn(ENODEV);
228
        }
229
        fcntl(exp_pty[0],F_SETFD,1);     /* close on exec */
230
#ifdef PTYTRAP_DIES
231
        exp_slave_control(exp_pty[0],1);*/
232
#endif
233
 
234
        if (!fd_new(exp_pty[0])) {
235
                errno = ENOMEM;
236
                return -1;
237
        }
238
 
239
        if (-1 == (pipe(sync_fds))) {
240
                return -1;
241
        }
242
        if (-1 == (pipe(sync2_fds))) {
243
                return -1;
244
        }
245
 
246
        if ((exp_pid = fork()) == -1) return(-1);
247
        if (exp_pid) {
248
                /* parent */
249
                close(sync_fds[1]);
250
                close(sync2_fds[0]);
251
                if (!exp_autoallocpty) close(exp_pty[1]);
252
 
253
#ifdef PTYTRAP_DIES
254
#ifdef HAVE_PTYTRAP
255
                if (exp_autoallocpty) {
256
                        /* trap initial ioctls in a feeble attempt to not */
257
                        /* block the initially.  If the process itself */
258
                        /* ioctls /dev/tty, such blocks will be trapped */
259
                        /* later during normal event processing */
260
 
261
                        while (slave_write_ioctls) {
262
                                int cc;
263
 
264
                                cc = exp_wait_for_slave_open(exp_pty[0]);
265
#if defined(TIOCSCTTY) && !defined(CIBAUD) && !defined(sun) && !defined(hp9000s300)
266
                                if (cc == TIOCSCTTY) slave_write_ioctls = 0;
267
#endif
268
                                if (cc & IOC_IN) slave_write_ioctls--;
269
                                else if (cc == -1) {
270
                                        printf("failed to trap slave pty");
271
                                        return -1;
272
                                }
273
                        }
274
                }
275
#endif
276
#endif /*PTYTRAP_DIES*/
277
 
278
                /*
279
                 * wait for slave to initialize pty before allowing
280
                 * user to send to it
281
                 */
282
 
283
                debuglog("parent: waiting for sync byte\r\n");
284
                cc = read(sync_fds[0],&sync_byte,1);
285
                if (cc == -1) {
286
                        fprintf(stderr,"parent sync byte read: %s\r\n",Tcl_ErrnoMsg(errno));
287
                        exit(-1);
288
                }
289
 
290
                /* turn on detection of eof */
291
                exp_slave_control(exp_pty[0],1);
292
 
293
                /*
294
                 * tell slave to go on now now that we have initialized pty
295
                 */
296
 
297
                debuglog("parent: telling child to go ahead\r\n");
298
                cc = write(sync2_fds[1]," ",1);
299
                if (cc == -1) {
300
                        errorlog("parent sync byte write: %s\r\n",Tcl_ErrnoMsg(errno));
301
                        exit(-1);
302
                }
303
 
304
                debuglog("parent: now unsynchronized from child\r\n");
305
 
306
                close(sync_fds[0]);
307
                close(sync2_fds[1]);
308
 
309
                return(exp_pty[0]);
310
        }
311
 
312
        /* child process - do not return from here!  all errors must exit() */
313
 
314
        close(sync_fds[0]);
315
        close(sync2_fds[1]);
316
 
317
#ifdef CRAY
318
        (void) close(exp_pty[0]);
319
#endif
320
 
321
/* ultrix (at least 4.1-2) fails to obtain controlling tty if setsid */
322
/* is called.  setpgrp works though.  */
323
#if defined(POSIX) && !defined(ultrix)
324
#define DO_SETSID
325
#endif
326
#ifdef __convex__
327
#define DO_SETSID
328
#endif
329
 
330
#ifdef DO_SETSID
331
        setsid();
332
#else
333
#ifdef SYSV3
334
#ifndef CRAY
335
        setpgrp();
336
#endif /* CRAY */
337
#else /* !SYSV3 */
338
#ifdef MIPS_BSD
339
        /* required on BSD side of MIPS OS <jmsellen@watdragon.waterloo.edu> */
340
#       include <sysv/sys.s>
341
        syscall(SYS_setpgrp);
342
#endif
343
        setpgrp(0,0);
344
/*      setpgrp(0,getpid());*/  /* make a new pgrp leader */
345
 
346
#ifdef TIOCNOTTY
347
        ttyfd = open("/dev/tty", O_RDWR);
348
        if (ttyfd >= 0) {
349
                (void) ioctl(ttyfd, TIOCNOTTY, (char *)0);
350
                (void) close(ttyfd);
351
        }
352
#endif /* TIOCNOTTY */
353
 
354
#endif /* SYSV3 */
355
#endif /* DO_SETSID */
356
 
357
        /* save error fd while we're setting up new one */
358
        errorfd = fcntl(2,F_DUPFD,3);
359
        /* and here is the macro to restore it */
360
#define restore_error_fd {close(2);fcntl(errorfd,F_DUPFD,2);}
361
 
362
        if (exp_autoallocpty) {
363
 
364
            close(0);
365
            close(1);
366
            close(2);
367
 
368
            /* since we closed fd 0, open of pty slave must return fd 0 */
369
 
370
            if (0 > (exp_pty[1] = getptyslave(exp_ttycopy,exp_ttyinit,
371
                                                exp_stty_init))) {
372
                restore_error_fd
373
                fprintf(stderr,"open(slave pty): %s\n",Tcl_ErrnoMsg(errno));
374
                exit(-1);
375
            }
376
            /* sanity check */
377
            if (exp_pty[1] != 0) {
378
                restore_error_fd
379
                fprintf(stderr,"getptyslave: slave = %d but expected 0\n",
380
                                                                exp_pty[1]);
381
                exit(-1);
382
            }
383
        } else {
384
                if (exp_pty[1] != 0) {
385
                        close(0);        fcntl(exp_pty[1],F_DUPFD,0);
386
                }
387
                close(1);               fcntl(0,F_DUPFD,1);
388
                close(2);               fcntl(0,F_DUPFD,1);
389
                close(exp_pty[1]);
390
        }
391
 
392
 
393
 
394
/* The test for hpux may have to be more specific.  In particular, the */
395
/* code should be skipped on the hp9000s300 and hp9000s720 (but there */
396
/* is no documented define for the 720!) */
397
 
398
#if defined(TIOCSCTTY) && !defined(sun) && !defined(hpux)
399
        /* 4.3+BSD way to acquire controlling terminal */
400
        /* according to Stevens - Adv. Prog..., p 642 */
401
#ifdef __QNX__ /* posix in general */
402
        if (tcsetct(0, getpid()) == -1) {
403
#else
404
        if (ioctl(0,TIOCSCTTY,(char *)0) < 0) {
405
#endif
406
                restore_error_fd
407
                fprintf(stderr,"failed to get controlling terminal using TIOCSCTTY");
408
                exit(-1);
409
        }
410
#endif
411
 
412
#ifdef CRAY
413
        (void) setsid();
414
        (void) ioctl(0,TCSETCTTY,0);
415
        (void) close(0);
416
        if (open("/dev/tty", O_RDWR) < 0) {
417
                restore_error_fd
418
                fprintf(stderr,"open(/dev/tty): %s\r\n",Tcl_ErrnoMsg(errno));
419
                exit(-1);
420
        }
421
        (void) close(1);
422
        (void) close(2);
423
        (void) dup(0);
424
        (void) dup(0);
425
        setptyutmp();   /* create a utmp entry */
426
 
427
        /* _CRAY2 code from Hal Peterson <hrp@cray.com>, Cray Research, Inc. */
428
#ifdef _CRAY2
429
        /*
430
         * Interpose a process between expect and the spawned child to
431
         * keep the slave side of the pty open to allow time for expect
432
         * to read the last output.  This is a workaround for an apparent
433
         * bug in the Unicos pty driver on Cray-2's under Unicos 6.0 (at
434
         * least).
435
         */
436
        if ((pid = fork()) == -1) {
437
                restore_error_fd
438
                fprintf(stderr,"second fork: %s\r\n",Tcl_ErrnoMsg(errno));
439
                exit(-1);
440
        }
441
 
442
        if (pid) {
443
                /* Intermediate process. */
444
                int status;
445
                int timeout;
446
                char *t;
447
 
448
                /* How long should we wait? */
449
                timeout = exp_pty_timeout;
450
 
451
                /* Let the spawned process run to completion. */
452
                while (wait(&status) < 0 && errno == EINTR)
453
                        /* empty body */;
454
 
455
                /* Wait for the pty to clear. */
456
                sleep(timeout);
457
 
458
                /* Duplicate the spawned process's status. */
459
                if (WIFSIGNALED(status))
460
                        kill(getpid(), WTERMSIG(status));
461
 
462
                /* The kill may not have worked, but this will. */
463
                exit(WEXITSTATUS(status));
464
        }
465
#endif /* _CRAY2 */
466
#endif /* CRAY */
467
 
468
        if (exp_console) {
469
#ifdef SRIOCSREDIR
470
                int fd;
471
 
472
                if ((fd = open("/dev/console", O_RDONLY)) == -1) {
473
                        restore_error_fd
474
                        fprintf(stderr, "spawn %s: cannot open console, check permissions of /dev/console\n",argv[0]);
475
                        exit(-1);
476
                }
477
                if (ioctl(fd, SRIOCSREDIR, 0) == -1) {
478
                        restore_error_fd
479
                        fprintf(stderr, "spawn %s: cannot redirect console, check permissions of /dev/console\n",argv[0]);
480
                }
481
                close(fd);
482
#endif
483
 
484
#ifdef TIOCCONS
485
                int on = 1;
486
                if (ioctl(0,TIOCCONS,(char *)&on) == -1) {
487
                        restore_error_fd
488
                        fprintf(stderr, "spawn %s: cannot open console, check permissions of /dev/console\n",argv[0]);
489
                        exit(-1);
490
                }
491
#endif /* TIOCCONS */
492
        }
493
 
494
        /* tell parent that we are done setting up pty */
495
        /* The actual char sent back is irrelevant. */
496
 
497
        /* debuglog("child: telling parent that pty is initialized\r\n");*/
498
        cc = write(sync_fds[1]," ",1);
499
        if (cc == -1) {
500
                restore_error_fd
501
                fprintf(stderr,"child: sync byte write: %s\r\n",Tcl_ErrnoMsg(errno));
502
                exit(-1);
503
        }
504
        close(sync_fds[1]);
505
 
506
        /* wait for master to let us go on */
507
        /* debuglog("child: waiting for go ahead from parent\r\n"); */
508
 
509
/*      close(master);  /* force master-side close so we can read */
510
        cc = read(sync2_fds[0],&sync_byte,1);
511
        if (cc == -1) {
512
                restore_error_fd
513
                errorlog("child: sync byte read: %s\r\n",Tcl_ErrnoMsg(errno));
514
                exit(-1);
515
        }
516
        close(sync2_fds[0]);
517
 
518
        /* debuglog("child: now unsynchronized from parent\r\n"); */
519
 
520
        /* (possibly multiple) masters are closed automatically due to */
521
        /* earlier fcntl(,,CLOSE_ON_EXEC); */
522
 
523
        /* just in case, allow user to explicitly close other files */
524
        if (exp_close_in_child) (*exp_close_in_child)();
525
 
526
        /* allow user to do anything else to child */
527
        if (exp_child_exec_prelude) (*exp_child_exec_prelude)();
528
 
529
        (void) execvp(file,argv);
530
        /* Unfortunately, by now we've closed fd's to stderr, logfile and
531
                debugfile.
532
           The only reasonable thing to do is to send back the error as
533
           part of the program output.  This will be picked up in an
534
           expect or interact command.
535
        */
536
        fprintf(stderr,"execvp(%s): %s\n",file,Tcl_ErrnoMsg(errno));
537
        exit(-1);
538
        /*NOTREACHED*/
539
}
540
 
541
/* returns fd of master side of pty */
542
/*VARARGS*/
543
int
544
exp_spawnl TCL_VARARGS_DEF(char *,arg1)
545
/*exp_spawnl(va_alist)*/
546
/*va_dcl*/
547
{
548
        va_list args; /* problematic line here */
549
        int i;
550
        char *arg, **argv;
551
 
552
        arg = TCL_VARARGS_START(char *,arg1,args);
553
        /*va_start(args);*/
554
        for (i=1;;i++) {
555
                arg = va_arg(args,char *);
556
                if (!arg) break;
557
        }
558
        va_end(args);
559
        if (i == 0) sysreturn(EINVAL);
560
        if (!(argv = (char **)malloc((i+1)*sizeof(char *)))) sysreturn(ENOMEM);
561
        argv[0] = TCL_VARARGS_START(char *,arg1,args);
562
        /*va_start(args);*/
563
        for (i=1;;i++) {
564
                argv[i] = va_arg(args,char *);
565
                if (!argv[i]) break;
566
        }
567
        i = exp_spawnv(argv[0],argv+1);
568
        free((char *)argv);
569
        return(i);
570
}
571
 
572
/* allow user-provided fd to be passed to expect funcs */
573
int
574
exp_spawnfd(fd)
575
int fd;
576
{
577
        if (!fd_new(fd)) {
578
                errno = ENOMEM;
579
                return -1;
580
        }
581
        return fd;
582
}
583
 
584
/* remove nulls from s.  Initially, the number of chars in s is c, */
585
/* not strlen(s).  This count does not include the trailing null. */
586
/* returns number of nulls removed. */
587
static int
588
rm_nulls(s,c)
589
char *s;
590
int c;
591
{
592
        char *s2 = s;   /* points to place in original string to put */
593
                        /* next non-null character */
594
        int count = 0;
595
        int i;
596
 
597
        for (i=0;i<c;i++,s++) {
598
                if (0 == *s) {
599
                        count++;
600
                        continue;
601
                }
602
                if (count) *s2 = *s;
603
                s2++;
604
        }
605
        return(count);
606
}
607
 
608
static int i_read_errno;/* place to save errno, if i_read() == -1, so it
609
                           doesn't get overwritten before we get to read it */
610
 
611
/*ARGSUSED*/
612
static void
613
sigalarm_handler(n)
614
int n;                  /* signal number, unused by us */
615
{
616
#ifdef REARM_SIG
617
        signal(SIGALRM,sigalarm_handler);
618
#endif
619
 
620
        longjmp(exp_readenv,1);
621
}
622
 
623
/* interruptable read */
624
static int
625
i_read(fd,fp,buffer,length,timeout)
626
int fd;
627
FILE *fp;
628
char *buffer;
629
int length;
630
int timeout;
631
{
632
        int cc = -2;
633
 
634
        /* since setjmp insists on returning 1 upon longjmp(,0), */
635
        /* longjmp(,2 (EXP_RESTART)) instead. */
636
 
637
        /* no need to set alarm if -1 (infinite) or 0 (poll with */
638
        /* guaranteed data) */
639
 
640
        if (timeout > 0) alarm(timeout);
641
 
642
        /* restart read if setjmp returns 0 (first time) or 2 (EXP_RESTART). */
643
        /* abort if setjmp returns 1 (EXP_ABORT). */
644
        if (EXP_ABORT != setjmp(exp_readenv)) {
645
                exp_reading = TRUE;
646
                if (fd == -1) {
647
                        int c;
648
                        c = getc(fp);
649
                        if (c == EOF) {
650
/*fprintf(stderr,"<<EOF>>",c);fflush(stderr);*/
651
                                if (feof(fp)) cc = 0;
652
                                else cc = -1;
653
                        } else {
654
/*fprintf(stderr,"<<%c>>",c);fflush(stderr);*/
655
                                buffer[0] = c;
656
                                cc = 1;
657
                        }
658
                } else {
659
#ifndef HAVE_PTYTRAP
660
                        cc = read(fd,buffer,length);
661
#else
662
#  include <sys/ptyio.h>
663
 
664
                        fd_set rdrs;
665
                        fd_set excep;
666
 
667
                restart:
668
                        FD_ZERO(&rdrs);
669
                        FD_ZERO(&excep);
670
                        FD_SET(fd,&rdrs);
671
                        FD_SET(fd,&excep);
672
                        if (-1 == (cc = select(fd+1,
673
                                         (SELECT_MASK_TYPE *)&rdrs,
674
                                         (SELECT_MASK_TYPE *)0,
675
                                         (SELECT_MASK_TYPE *)&excep,
676
                                         (struct timeval *)0))) {
677
                                /* window refreshes trigger EINTR, ignore */
678
                                if (errno == EINTR) goto restart;
679
                        }
680
                        if (FD_ISSET(fd,&rdrs)) {
681
                                cc = read(fd,buffer,length);
682
                        } else if (FD_ISSET(fd,&excep)) {
683
                                struct request_info ioctl_info;
684
                                ioctl(fd,TIOCREQCHECK,&ioctl_info);
685
                                if (ioctl_info.request == TIOCCLOSE) {
686
                                        cc = 0; /* indicate eof */
687
                                } else {
688
                                        ioctl(fd, TIOCREQSET, &ioctl_info);
689
                                        /* presumably, we trapped an open here */
690
                                        goto restart;
691
                                }
692
                        }
693
#endif /* HAVE_PTYTRAP */
694
                }
695
#if 0
696
                /* can't get fread to return early! */
697
                else {
698
                        if (!(cc = fread(buffer,1,length,fp))) {
699
                                if (ferror(fp)) cc = -1;
700
                        }
701
                }
702
#endif
703
                i_read_errno = errno;   /* errno can be overwritten by the */
704
                                        /* time we return */
705
        }
706
        exp_reading = FALSE;
707
 
708
        if (timeout > 0) alarm(0);
709
        return(cc);
710
}
711
 
712
/* I tried really hard to make the following two functions share the code */
713
/* that makes the ecase array, but I kept running into a brick wall when */
714
/* passing var args into the funcs and then again into a make_cases func */
715
/* I would very much appreciate it if someone showed me how to do it right */
716
 
717
/* takes triplets of args, with a final "exp_last" arg */
718
/* triplets are type, pattern, and then int to return */
719
/* returns negative value if error (or EOF/timeout) occurs */
720
/* some negative values can also have an associated errno */
721
 
722
/* the key internal variables that this function depends on are:
723
        exp_buffer
724
        exp_buffer_end
725
        exp_match_end
726
*/
727
static int
728
expectv(fd,fp,ecases)
729
int fd;
730
FILE *fp;
731
struct exp_case *ecases;
732
{
733
        int cc = 0;              /* number of chars returned in a single read */
734
        int buf_length;         /* numbers of chars in exp_buffer */
735
        int old_length;         /* old buf_length */
736
        int first_time = TRUE;  /* force old buffer to be tested before */
737
                                /* additional reads */
738
        int polled = 0;          /* true if poll has caused read() to occur */
739
 
740
        struct exp_case *ec;    /* points to current ecase */
741
 
742
        time_t current_time;    /* current time (when we last looked)*/
743
        time_t end_time;        /* future time at which to give up */
744
        int remtime;            /* remaining time in timeout */
745
 
746
        struct f *f;
747
        int return_val;
748
        int sys_error = 0;
749
#define return_normally(x)      {return_val = x; goto cleanup;}
750
#define return_errno(x) {sys_error = x; goto cleanup;}
751
 
752
        f = fdfp2f(fd,fp);
753
        if (!f) return_errno(ENOMEM);
754
 
755
        exp_buffer = f->buffer;
756
        exp_buffer_end = f->buffer_end;
757
        exp_match_end = f->match_end;
758
 
759
        buf_length = exp_buffer_end - exp_match_end;
760
        if (buf_length) {
761
                /*
762
                 * take end of previous match to end of buffer
763
                 * and copy to beginning of buffer
764
                 */
765
                memmove(exp_buffer,exp_match_end,buf_length);
766
        }
767
        exp_buffer_end = exp_buffer + buf_length;
768
        *exp_buffer_end = '\0';
769
 
770
        if (!ecases) return_errno(EINVAL);
771
 
772
        /* compile if necessary */
773
        for (ec=ecases;ec->type != exp_end;ec++) {
774
                if ((ec->type == exp_regexp) && !ec->re) {
775
                        TclRegError((char *)0);
776
                        if (!(ec->re = TclRegComp(ec->pattern))) {
777
                                fprintf(stderr,"regular expression %s is bad: %s",ec->pattern,TclGetRegError());
778
                                return_errno(EINVAL);
779
                          }
780
                  }
781
        }
782
 
783
        /* get the latest buffer size.  Double the user input for two */
784
        /* reasons.  1) Need twice the space in case the match */
785
        /* straddles two bufferfuls, 2) easier to hack the division by */
786
        /* two when shifting the buffers later on */
787
 
788
        bufsiz = 2*exp_match_max;
789
        if (f->msize != bufsiz) {
790
                /* if truncated, forget about some data */
791
                if (buf_length > bufsiz) {
792
                        /* copy end of buffer down */
793
 
794
                        /* copy one less than what buffer can hold to avoid */
795
                        /* triggering buffer-full handling code below */
796
                        /* which will immediately dump the first half */
797
                        /* of the buffer */
798
                        memmove(exp_buffer,exp_buffer+(buf_length - bufsiz)+1,
799
                                bufsiz-1);
800
                        buf_length = bufsiz-1;
801
                }
802
                exp_buffer = realloc(exp_buffer,bufsiz+1);
803
                if (!exp_buffer) return_errno(ENOMEM);
804
                exp_buffer[buf_length] = '\0';
805
                exp_buffer_end = exp_buffer + buf_length;
806
                f->msize = bufsiz;
807
        }
808
 
809
        /* some systems (i.e., Solaris) require fp be flushed when switching */
810
        /* directions - do this again afterwards */
811
        if (fd == -1) fflush(fp);
812
 
813
        if (exp_timeout != -1) signal(SIGALRM,sigalarm_handler);
814
 
815
        /* remtime and current_time updated at bottom of loop */
816
        remtime = exp_timeout;
817
 
818
        time(&current_time);
819
        end_time = current_time + remtime;
820
 
821
        for (;;) {
822
                /* when buffer fills, copy second half over first and */
823
                /* continue, so we can do matches over multiple buffers */
824
                if (buf_length == bufsiz) {
825
                        int first_half, second_half;
826
 
827
                        if (exp_full_buffer) {
828
                                debuglog("expect: full buffer\r\n");
829
                                exp_match = exp_buffer;
830
                                exp_match_end = exp_buffer + buf_length;
831
                                exp_buffer_end = exp_match_end;
832
                                return_normally(EXP_FULLBUFFER);
833
                        }
834
                        first_half = bufsiz/2;
835
                        second_half = bufsiz - first_half;
836
 
837
                        memcpy(exp_buffer,exp_buffer+first_half,second_half);
838
                        buf_length = second_half;
839
                        exp_buffer_end = exp_buffer + second_half;
840
                }
841
 
842
                /*
843
                 * always check first if pattern is already in buffer
844
                 */
845
                if (first_time) {
846
                        first_time = FALSE;
847
                        goto after_read;
848
                }
849
 
850
                /*
851
                 * check for timeout
852
                 */
853
                if ((exp_timeout >= 0) && ((remtime < 0) || polled)) {
854
                        debuglog("expect: timeout\r\n");
855
                        exp_match_end = exp_buffer;
856
                        return_normally(EXP_TIMEOUT);
857
                }
858
 
859
                /*
860
                 * if timeout == 0, indicate a poll has
861
                 * occurred so that next time through loop causes timeout
862
                 */
863
                if (exp_timeout == 0) {
864
                        polled = 1;
865
                }
866
 
867
                cc = i_read(fd,fp,
868
                                exp_buffer_end,
869
                                bufsiz - buf_length,
870
                                remtime);
871
 
872
                if (cc == 0) {
873
                        debuglog("expect: eof\r\n");
874
                        return_normally(EXP_EOF);       /* normal EOF */
875
                } else if (cc == -1) {                  /* abnormal EOF */
876
                        /* ptys produce EIO upon EOF - sigh */
877
                        if (i_read_errno == EIO) {
878
                                /* convert to EOF indication */
879
                                debuglog("expect: eof\r\n");
880
                                return_normally(EXP_EOF);
881
                        }
882
                        debuglog("expect: error (errno = %d)\r\n",i_read_errno);
883
                        return_errno(i_read_errno);
884
                } else if (cc == -2) {
885
                        debuglog("expect: timeout\r\n");
886
                        exp_match_end = exp_buffer;
887
                        return_normally(EXP_TIMEOUT);
888
                }
889
 
890
                old_length = buf_length;
891
                buf_length += cc;
892
                exp_buffer_end += buf_length;
893
 
894
                if (logfile_all || (loguser && logfile)) {
895
                        fwrite(exp_buffer + old_length,1,cc,logfile);
896
                }
897
                if (loguser) fwrite(exp_buffer + old_length,1,cc,stdout);
898
                if (debugfile) fwrite(exp_buffer + old_length,1,cc,debugfile);
899
 
900
                /* if we wrote to any logs, flush them */
901
                if (debugfile) fflush(debugfile);
902
                if (loguser) {
903
                        fflush(stdout);
904
                        if (logfile) fflush(logfile);
905
                }
906
 
907
                /* remove nulls from input, so we can use C-style strings */
908
                /* doing it here lets them be sent to the screen, just */
909
                /*  in case they are involved in formatting operations */
910
                if (exp_remove_nulls) {
911
                        buf_length -= rm_nulls(exp_buffer + old_length, cc);
912
                }
913
                /* cc should be decremented as well, but since it will not */
914
                /* be used before being set again, there is no need */
915
                exp_buffer_end = exp_buffer + buf_length;
916
                *exp_buffer_end = '\0';
917
                exp_match_end = exp_buffer;
918
 
919
        after_read:
920
                debuglog("expect: does {%s} match ",exp_printify(exp_buffer));
921
                /* pattern supplied */
922
                for (ec=ecases;ec->type != exp_end;ec++) {
923
                        int matched = -1;
924
 
925
                        debuglog("{%s}? ",exp_printify(ec->pattern));
926
                        if (ec->type == exp_glob) {
927
                                int offset;
928
                                matched = Exp_StringMatch(exp_buffer,ec->pattern,&offset);
929
                                if (matched >= 0) {
930
                                        exp_match = exp_buffer + offset;
931
                                        exp_match_end = exp_match + matched;
932
                                }
933
                        } else if (ec->type == exp_exact) {
934
                                char *p = strstr(exp_buffer,ec->pattern);
935
                                if (p) {
936
                                        matched = 1;
937
                                        exp_match = p;
938
                                        exp_match_end = p + strlen(ec->pattern);
939
                                }
940
                        } else if (ec->type == exp_null) {
941
                                char *p;
942
 
943
                                for (p=exp_buffer;p<exp_buffer_end;p++) {
944
                                        if (*p == 0) {
945
                                                matched = 1;
946
                                                exp_match = p;
947
                                                exp_match_end = p+1;
948
                                        }
949
                                }
950
                        } else {
951
                                TclRegError((char *)0);
952
                                if (TclRegExec(ec->re,exp_buffer,exp_buffer)) {
953
                                        matched = 1;
954
                                        exp_match = ec->re->startp[0];
955
                                        exp_match_end = ec->re->endp[0];
956
                                } else if (TclGetRegError()) {
957
                                        fprintf(stderr,"r.e. match (pattern %s) failed: %s",ec->pattern,TclGetRegError());
958
                                }
959
                        }
960
 
961
                        if (matched != -1) {
962
                                debuglog("yes\nexp_buffer is {%s}\n",
963
                                                exp_printify(exp_buffer));
964
                                return_normally(ec->value);
965
                        } else debuglog("no\n");
966
                }
967
 
968
                /*
969
                 * Update current time and remaining time.
970
                 * Don't bother if we are waiting forever or polling.
971
                 */
972
                if (exp_timeout > 0) {
973
                        time(&current_time);
974
                        remtime = end_time - current_time;
975
                }
976
        }
977
 cleanup:
978
        f->buffer     = exp_buffer;
979
        f->buffer_end = exp_buffer_end;
980
        f->match_end  = exp_match_end;
981
 
982
        /* some systems (i.e., Solaris) require fp be flushed when switching */
983
        /* directions - do this before as well */
984
        if (fd == -1) fflush(fp);
985
 
986
        if (sys_error) {
987
                errno = sys_error;
988
                return -1;
989
        }
990
        return return_val;
991
}
992
 
993
int
994
exp_fexpectv(fp,ecases)
995
FILE *fp;
996
struct exp_case *ecases;
997
{
998
        return(expectv(-1,fp,ecases));
999
}
1000
 
1001
int
1002
exp_expectv(fd,ecases)
1003
int fd;
1004
struct exp_case *ecases;
1005
{
1006
        return(expectv(fd,(FILE *)0,ecases));
1007
}
1008
 
1009
/*VARARGS*/
1010
int
1011
exp_expectl TCL_VARARGS_DEF(int,arg1)
1012
/*exp_expectl(va_alist)*/
1013
/*va_dcl*/
1014
{
1015
        va_list args;
1016
        int fd;
1017
        struct exp_case *ec, *ecases;
1018
        int i;
1019
        enum exp_type type;
1020
 
1021
        fd = TCL_VARARGS_START(int,arg1,args);
1022
        /* va_start(args);*/
1023
        /* fd = va_arg(args,int);*/
1024
        /* first just count the arg sets */
1025
        for (i=0;;i++) {
1026
                type = va_arg(args,enum exp_type);
1027
                if (type == exp_end) break;
1028
 
1029
                /* Ultrix 4.2 compiler refuses enumerations comparison!? */
1030
                if ((int)type < 0 || (int)type >= (int)exp_bogus) {
1031
                        fprintf(stderr,"bad type (set %d) in exp_expectl\n",i);
1032
                        sysreturn(EINVAL);
1033
                }
1034
 
1035
                va_arg(args,char *);            /* COMPUTED BUT NOT USED */
1036
                if (type == exp_compiled) {
1037
                        va_arg(args,regexp *);  /* COMPUTED BUT NOT USED */
1038
                }
1039
                va_arg(args,int);               /* COMPUTED BUT NOT USED*/
1040
        }
1041
        va_end(args);
1042
 
1043
        if (!(ecases = (struct exp_case *)
1044
                                malloc((1+i)*sizeof(struct exp_case))))
1045
                sysreturn(ENOMEM);
1046
 
1047
        /* now set up the actual cases */
1048
        fd = TCL_VARARGS_START(int,arg1,args);
1049
        /*va_start(args);*/
1050
        /*va_arg(args,int);*/           /*COMPUTED BUT NOT USED*/
1051
        for (ec=ecases;;ec++) {
1052
                ec->type = va_arg(args,enum exp_type);
1053
                if (ec->type == exp_end) break;
1054
                ec->pattern = va_arg(args,char *);
1055
                if (ec->type == exp_compiled) {
1056
                        ec->re = va_arg(args,regexp *);
1057
                } else {
1058
                        ec->re = 0;
1059
                }
1060
                ec->value = va_arg(args,int);
1061
        }
1062
        va_end(args);
1063
        i = expectv(fd,(FILE *)0,ecases);
1064
 
1065
        for (ec=ecases;ec->type != exp_end;ec++) {
1066
                /* free only if regexp and we compiled it for user */
1067
                if (ec->type == exp_regexp) {
1068
                        free((char *)ec->re);
1069
                }
1070
        }
1071
        free((char *)ecases);
1072
        return(i);
1073
}
1074
 
1075
int
1076
exp_fexpectl TCL_VARARGS_DEF(FILE *,arg1)
1077
/*exp_fexpectl(va_alist)*/
1078
/*va_dcl*/
1079
{
1080
        va_list args;
1081
        FILE *fp;
1082
        struct exp_case *ec, *ecases;
1083
        int i;
1084
        enum exp_type type;
1085
 
1086
        fp = TCL_VARARGS_START(FILE *,arg1,args);
1087
        /*va_start(args);*/
1088
        /*fp = va_arg(args,FILE *);*/
1089
        /* first just count the arg-pairs */
1090
        for (i=0;;i++) {
1091
                type = va_arg(args,enum exp_type);
1092
                if (type == exp_end) break;
1093
 
1094
                /* Ultrix 4.2 compiler refuses enumerations comparison!? */
1095
                if ((int)type < 0 || (int)type >= (int)exp_bogus) {
1096
                        fprintf(stderr,"bad type (set %d) in exp_expectl\n",i);
1097
                        sysreturn(EINVAL);
1098
                }
1099
 
1100
                va_arg(args,char *);            /* COMPUTED BUT NOT USED */
1101
                if (type == exp_compiled) {
1102
                        va_arg(args,regexp *);  /* COMPUTED BUT NOT USED */
1103
                }
1104
                va_arg(args,int);               /* COMPUTED BUT NOT USED*/
1105
        }
1106
        va_end(args);
1107
 
1108
        if (!(ecases = (struct exp_case *)
1109
                                        malloc((1+i)*sizeof(struct exp_case))))
1110
                sysreturn(ENOMEM);
1111
 
1112
#if 0
1113
        va_start(args);
1114
        va_arg(args,FILE *);            /*COMPUTED, BUT NOT USED*/
1115
#endif
1116
        (void) TCL_VARARGS_START(FILE *,arg1,args);
1117
 
1118
        for (ec=ecases;;ec++) {
1119
                ec->type = va_arg(args,enum exp_type);
1120
                if (ec->type == exp_end) break;
1121
                ec->pattern = va_arg(args,char *);
1122
                if (ec->type == exp_compiled) {
1123
                        ec->re = va_arg(args,regexp *);
1124
                } else {
1125
                        ec->re = 0;
1126
                }
1127
                ec->value = va_arg(args,int);
1128
        }
1129
        va_end(args);
1130
        i = expectv(-1,fp,ecases);
1131
 
1132
        for (ec=ecases;ec->type != exp_end;ec++) {
1133
                /* free only if regexp and we compiled it for user */
1134
                if (ec->type == exp_regexp) {
1135
                        free((char *)ec->re);
1136
                }
1137
        }
1138
        free((char *)ecases);
1139
        return(i);
1140
}
1141
 
1142
/* like popen(3) but works in both directions */
1143
FILE *
1144
exp_popen(program)
1145
char *program;
1146
{
1147
        FILE *fp;
1148
        int ec;
1149
 
1150
        if (0 > (ec = exp_spawnl("sh","sh","-c",program,(char *)0))) return(0);
1151
        if (!(fp = fdopen(ec,"r+"))) return(0);
1152
        setbuf(fp,(char *)0);
1153
        return(fp);
1154
}
1155
 
1156
int
1157
exp_disconnect()
1158
{
1159
        int ttyfd;
1160
 
1161
#ifndef EALREADY
1162
#define EALREADY 37
1163
#endif
1164
 
1165
        /* presumably, no stderr, so don't bother with error message */
1166
        if (exp_disconnected) sysreturn(EALREADY);
1167
        exp_disconnected = TRUE;
1168
 
1169
        freopen("/dev/null","r",stdin);
1170
        freopen("/dev/null","w",stdout);
1171
        freopen("/dev/null","w",stderr);
1172
 
1173
#ifdef POSIX
1174
        setsid();
1175
#else
1176
#ifdef SYSV3
1177
        /* put process in our own pgrp, and lose controlling terminal */
1178
        setpgrp();
1179
        signal(SIGHUP,SIG_IGN);
1180
        if (fork()) exit(0);     /* first child exits (as per Stevens, */
1181
        /* UNIX Network Programming, p. 79-80) */
1182
        /* second child process continues as daemon */
1183
#else /* !SYSV3 */
1184
#ifdef MIPS_BSD
1185
        /* required on BSD side of MIPS OS <jmsellen@watdragon.waterloo.edu> */
1186
#       include <sysv/sys.s>
1187
        syscall(SYS_setpgrp);
1188
#endif
1189
        setpgrp(0,getpid());     /* put process in our own pgrp */
1190
/* Pyramid lacks this defn */
1191
#ifdef TIOCNOTTY
1192
        ttyfd = open("/dev/tty", O_RDWR);
1193
        if (ttyfd >= 0) {
1194
                /* zap controlling terminal if we had one */
1195
                (void) ioctl(ttyfd, TIOCNOTTY, (char *)0);
1196
                (void) close(ttyfd);
1197
        }
1198
#endif /* TIOCNOTTY */
1199
#endif /* SYSV3 */
1200
#endif /* POSIX */
1201
        return(0);
1202
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.