varnish-cache/bin/varnishtest/vtc_process.c
1
/*-
2
 * Copyright (c) 2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Dridi Boukelmoune <dridi@varnish-software.com>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 * XXX:
29
 *      -ignore-stderr (otherwise output to stderr is fail)
30
 */
31
32
#include "config.h"
33
34
#include <sys/ioctl.h>          // Linux: struct winsize
35
36
#include <ctype.h>
37
#include <errno.h>
38
#include <fcntl.h>
39
#include <inttypes.h>
40
#include <poll.h>
41
#include <stdio.h>
42
#include <stdlib.h>
43
#include <string.h>
44
#ifdef __sun
45
#  include <stropts.h>
46
#endif
47
#include <termios.h>
48
#include <unistd.h>
49
50
#include "vtc.h"
51
52
#include "vev.h"
53
#include "vlu.h"
54
#include "vsb.h"
55
#include "vsub.h"
56
57
#include "teken.h"
58
59
struct process {
60
        unsigned                magic;
61
#define PROCESS_MAGIC           0x1617b43e
62
        char                    *name;
63
        struct vtclog           *vl;
64
        VTAILQ_ENTRY(process)   list;
65
66
        char                    *spec;
67
        char                    *dir;
68
        char                    *out;
69
        char                    *err;
70
        int                     fd_term;
71
        int                     fd_stderr;
72
        int                     f_stdout;
73
        int                     f_stderr;
74
        struct vlu              *vlu_stdout;
75
        struct vlu              *vlu_stderr;
76
        int                     log;
77
        pid_t                   pid;
78
        int                     expect_exit;
79
        int                     expect_signal;
80
        int                     allow_core;
81
82
        uintmax_t               stdout_bytes;
83
        uintmax_t               stderr_bytes;
84
85
        pthread_mutex_t         mtx;
86
        pthread_t               tp;
87
        unsigned                hasthread;
88
89
        int                     nlin;
90
        int                     ncol;
91
        int                     ansi_response;
92
        char                    **vram;
93
        teken_t                 tek[1];
94
};
95
96
static VTAILQ_HEAD(, process)   processes =
97
    VTAILQ_HEAD_INITIALIZER(processes);
98
99
static void term_resize(struct process *pp, int lin, int col);
100
101
/**********************************************************************
102
 * Terminal emulation
103
 */
104
105
static void
106 404762
term_cursor(void *priv, const teken_pos_t *pos)
107
{
108
        (void)priv;
109
        (void)pos;
110 404762
}
111
112
static void
113 3130530
term_putchar(void *priv, const teken_pos_t *pos, teken_char_t ch,
114
    const teken_attr_t *at)
115
{
116
        struct process *pp;
117
118 3130530
        CAST_OBJ_NOTNULL(pp, priv, PROCESS_MAGIC);
119
        (void)at;
120 3130530
        if (ch > 126 || ch < 32)
121 2248
                ch = '?';
122 3130530
        assert(pos->tp_row < pp->nlin);
123 3130530
        assert(pos->tp_col < pp->ncol);
124 3130530
        pp->vram[pos->tp_row][pos->tp_col] = ch;
125 3130530
}
126
127
static void
128 5874
term_fill(void *priv, const teken_rect_t *r, teken_char_t c,
129
    const teken_attr_t *a)
130
{
131
        teken_pos_t p;
132
133
        /* Braindead implementation of fill() - just call putchar(). */
134 42538
        for (p.tp_row = r->tr_begin.tp_row;
135 30790
            p.tp_row < r->tr_end.tp_row; p.tp_row++)
136 2829292
                for (p.tp_col = r->tr_begin.tp_col;
137 2767712
                    p.tp_col < r->tr_end.tp_col; p.tp_col++)
138 2767712
                        term_putchar(priv, &p, c, a);
139 5874
}
140
141
static void
142 5980
term_copy(void *priv, const teken_rect_t *r, const teken_pos_t *p)
143
{
144
        struct process *pp;
145
        int nrow, ncol, y; /* Has to be signed - >= 0 comparison */
146
147
        /*
148
         * Copying is a little tricky. We must make sure we do it in
149
         * correct order, to make sure we don't overwrite our own data.
150
         */
151 5980
        CAST_OBJ_NOTNULL(pp, priv, PROCESS_MAGIC);
152
153 5980
        nrow = r->tr_end.tp_row - r->tr_begin.tp_row;
154 5980
        ncol = r->tr_end.tp_col - r->tr_begin.tp_col;
155
156 5980
        if (p->tp_row < r->tr_begin.tp_row) {
157
                /* Copy from top to bottom. */
158 25328
                for (y = 0; y < nrow; y++)
159 47184
                        memmove(&pp->vram[p->tp_row + y][p->tp_col],
160 23592
                            &pp->vram[r->tr_begin.tp_row + y][r->tr_begin.tp_col], ncol);
161
        } else {
162
                /* Copy from bottom to top. */
163 23788
                for (y = nrow - 1; y >= 0; y--)
164 39088
                        memmove(&pp->vram[p->tp_row + y][p->tp_col],
165 19544
                            &pp->vram[r->tr_begin.tp_row + y][r->tr_begin.tp_col], ncol);
166
        }
167 5980
}
168
169
static void
170 64
term_respond(void *priv, const void *p, size_t l)
171
{
172
        struct process *pp;
173
        int r;
174
175 64
        CAST_OBJ_NOTNULL(pp, priv, PROCESS_MAGIC);
176
177 64
        vtc_dump(pp->vl, 4, "term_response", p, l);
178 64
        if (pp->ansi_response) {
179 8
                r = write(pp->fd_term, p, l);
180 8
                if (r != l)
181 0
                        vtc_fatal(pp->vl, "Could not write to process: %s",
182 0
                            strerror(errno));
183
        }
184 64
}
185
186
static void
187 436
term_param(void *priv, int p, unsigned int v)
188
{
189
        struct process *pp;
190
191 436
        CAST_OBJ_NOTNULL(pp, priv, PROCESS_MAGIC);
192 436
        if (p == TP_132COLS && v)
193 48
                term_resize(pp, pp->nlin, 132);
194 436
        if (p == TP_132COLS && !v)
195 96
                term_resize(pp, pp->nlin, 80);
196 436
}
197
198
static const teken_funcs_t process_teken_func = {
199
        .tf_cursor      =       term_cursor,
200
        .tf_putchar     =       term_putchar,
201
        .tf_fill        =       term_fill,
202
        .tf_copy        =       term_copy,
203
        .tf_respond     =       term_respond,
204
        .tf_param       =       term_param,
205
};
206
207
static void
208 504
term_screen_dump(const struct process *pp)
209
{
210
        int i;
211
        const teken_pos_t *pos;
212
213 12672
        for (i = 0; i < pp->nlin; i++)
214 12168
                vtc_dump(pp->vl, 3, "screen", pp->vram[i], pp->ncol);
215 504
        pos = teken_get_cursor(pp->tek);
216 1008
        vtc_log(pp->vl, 3, "Cursor at line %d column %d",
217 1008
            pos->tp_row + 1, pos->tp_col + 1);
218 504
}
219
220
static void
221 296
term_resize(struct process *pp, int lin, int col)
222
{
223
        teken_pos_t pos;
224
        char **vram;
225
        int i, j;
226
227 296
        vram = calloc(lin, sizeof *pp->vram);
228 296
        AN(vram);
229 7472
        for (i = 0; i < lin; i++) {
230 7176
                vram[i] = malloc(col + 1L);
231 7176
                AN(vram[i]);
232 7176
                memset(vram[i], ' ', col);
233 7176
                vram[i][col] = '\0';
234
        }
235 296
        if (pp->vram != NULL) {
236 4096
                for (i = 0; i < lin; i++) {
237 3948
                        if (i >= pp->nlin)
238 16
                                break;
239 3932
                        j = col;
240 3932
                        if (j > pp->ncol)
241 1248
                                j = pp->ncol;
242 3932
                        memcpy(vram[i], pp->vram[i], j);
243
                }
244 4100
                for (i = 0; i < pp->nlin; i++)
245 3936
                        free(pp->vram[i]);
246 164
                free(pp->vram);
247
        }
248 296
        pp->vram = vram;
249 296
        pp->nlin = lin;
250 296
        pp->ncol = col;
251
252 296
        pos.tp_row = lin;
253 296
        pos.tp_col = col;
254 296
        teken_set_winsize(pp->tek, &pos);
255 296
}
256
257
static int
258 12157
term_match_textline(const struct process *pp, int *x, int y, const char *pat)
259
{
260
        const char *t;
261
262 12157
        if (*x == 0) {
263 8556
                t = strstr(pp->vram[y], pat);
264 8556
                if (t != NULL) {
265 168
                        *x = 1 + (t - pp->vram[y]);
266 168
                        return (1);
267
                }
268 3601
        } else if (*x <= pp->ncol) {
269 3585
                t = pp->vram[y] + *x - 1;
270 3585
                if (!memcmp(t, pat, strlen(pat)))
271 664
                        return (1);
272
        }
273 11325
        return (0);
274
}
275
276
static int
277 1905
term_match_text(const struct process *pp, int *x, int *y, const char *pat)
278
{
279
        int yy;
280
281 1905
        if (*y == 0) {
282 11144
                for (yy = 0; yy < pp->nlin; yy++) {
283 10788
                        if (term_match_textline(pp, x, yy, pat)) {
284 180
                                *y = yy + 1;
285 180
                                return (1);
286
                        }
287
                }
288 1369
        } else if (*y <= pp->nlin) {
289 1369
                if (term_match_textline(pp, x, *y - 1, pat))
290 652
                        return (1);
291
        }
292 1073
        return (0);
293
}
294
295
static void
296 832
term_expect_text(struct process *pp,
297
    const char *lin, const char *col, const char *pat)
298
{
299 832
        int x, y, l, d = 10000;
300
        char *t;
301
302 832
        y = strtoul(lin, NULL, 0);
303 832
        x = strtoul(col, NULL, 0);
304 832
        l = strlen(pat);
305 832
        AZ(pthread_mutex_lock(&pp->mtx));
306 2737
        while (!term_match_text(pp, &x, &y, pat)) {
307 1073
                if (x != 0 && y != 0) {
308 629
                        t = pp->vram[y - 1] + x - 1;
309 629
                        vtc_log(pp->vl, 4,
310
                            "text at %d,%d: '%.*s'", y, x, l, t);
311
                }
312 1073
                AZ(pthread_mutex_unlock(&pp->mtx));
313 1073
                usleep(d);
314 1073
                AZ(pthread_mutex_lock(&pp->mtx));
315 1073
                if (d < 300000)
316 1009
                        d += d;
317
        }
318 832
        AZ(pthread_mutex_unlock(&pp->mtx));
319 832
        vtc_log(pp->vl, 4, "found expected text at %d,%d: '%s'", y, x, pat);
320 832
}
321
322
static void
323 32
term_expect_cursor(const struct process *pp, const char *lin, const char *col)
324
{
325
        int x, y;
326
        const teken_pos_t *pos;
327
328 32
        pos = teken_get_cursor(pp->tek);
329 32
        y = strtoul(lin, NULL, 0);
330 32
        x = strtoul(col, NULL, 0);
331 32
        if (y != 0 && (y-1) != pos->tp_row)
332 0
                vtc_fatal(pp->vl, "Cursor on line %d (expected %d)",
333 0
                    pos->tp_row + 1, y);
334 32
        if (x != 0 && (x-1) != pos->tp_col)
335 0
                vtc_fatal(pp->vl, "Cursor in column %d (expected %d)",
336 0
                    pos->tp_col + 1, y);
337 32
}
338
339
/**********************************************************************
340
 * Allocate and initialize a process
341
 */
342
343
#define PROCESS_EXPAND(field, format, ...)                              \
344
        do {                                                            \
345
                vsb = macro_expandf(p->vl, format, __VA_ARGS__);        \
346
                AN(vsb);                                                \
347
                p->field = strdup(VSB_data(vsb));                       \
348
                AN(p->field);                                           \
349
                VSB_destroy(&vsb);                                      \
350
        } while (0)
351
352
static void
353 132
process_coverage(struct process *p)
354
{
355
        const teken_attr_t *a;
356
        teken_pos_t pos;
357
        int fg, bg;
358
359
        // Code-Coverage of Teken
360
361 132
        (void)teken_get_sequence(p->tek, TKEY_UP);
362 132
        (void)teken_get_sequence(p->tek, TKEY_F1);
363 132
        (void)teken_256to8(0);
364 132
        (void)teken_256to16(0);
365 132
        a = teken_get_defattr(p->tek);
366 132
        teken_set_defattr(p->tek, a);
367 132
        a = teken_get_curattr(p->tek);
368 132
        teken_set_curattr(p->tek, a);
369 132
        (void)teken_get_winsize(p->tek);
370 132
        pos.tp_row = 0;
371 132
        pos.tp_col = 8;
372 132
        teken_set_cursor(p->tek, &pos);
373 132
        teken_get_defattr_cons25(p->tek, &fg, &bg);
374 132
}
375
376
static struct process *
377 132
process_new(const char *name)
378
{
379
        struct process *p;
380
        struct vsb *vsb;
381
        char buf[1024];
382
383 132
        ALLOC_OBJ(p, PROCESS_MAGIC);
384 132
        AN(p);
385 132
        REPLACE(p->name, name);
386 132
        AZ(pthread_mutex_init(&p->mtx, NULL));
387
388 132
        p->vl = vtc_logopen(name);
389 132
        AN(p->vl);
390
391 132
        PROCESS_EXPAND(dir, "${tmpdir}/%s", name);
392 132
        PROCESS_EXPAND(out, "${tmpdir}/%s/term", name);
393 132
        PROCESS_EXPAND(err, "${tmpdir}/%s/stderr", name);
394
395 132
        bprintf(buf, "rm -rf %s ; mkdir -p %s ; touch %s %s",
396
            p->dir, p->dir, p->out, p->err);
397 132
        AZ(system(buf));
398
399 132
        p->fd_term = -1;
400
401 132
        VTAILQ_INSERT_TAIL(&processes, p, list);
402 132
        teken_init(p->tek, &process_teken_func, p);
403 132
        term_resize(p, 24, 80);
404 132
        process_coverage(p);
405 132
        return (p);
406
}
407
408
#undef PROCESS_EXPAND
409
410
/**********************************************************************
411
 * Clean up process
412
 */
413
414
static void
415 132
process_delete(struct process *p)
416
{
417
        int i;
418
419 132
        CHECK_OBJ_NOTNULL(p, PROCESS_MAGIC);
420 132
        AZ(pthread_mutex_destroy(&p->mtx));
421 132
        vtc_logclose(p->vl);
422 132
        free(p->name);
423 132
        free(p->dir);
424 132
        free(p->out);
425 132
        free(p->err);
426
427 3372
        for (i = 0; i < p->nlin; i++)
428 3240
                free(p->vram[i]);
429 132
        free(p->vram);
430
431
        /*
432
         * We do not delete the directory, it may contain useful stdout
433
         * and stderr files. They will be deleted on account of belonging
434
         * to the test's tmpdir.
435
         */
436
437
        /* XXX: MEMLEAK (?) */
438 132
        FREE_OBJ(p);
439 132
}
440
441
static void
442 132
process_undef(const struct process *p)
443
{
444 132
        CHECK_OBJ_NOTNULL(p, PROCESS_MAGIC);
445
446 132
        macro_undef(p->vl, p->name, "dir");
447 132
        macro_undef(p->vl, p->name, "out");
448 132
        macro_undef(p->vl, p->name, "err");
449 132
}
450
451
/**********************************************************************
452
 * Data stream handling
453
 */
454
455
static int
456 428
process_vlu_func(void *priv, const char *l)
457
{
458
        struct process *p;
459
460 428
        CAST_OBJ_NOTNULL(p, priv, PROCESS_MAGIC);
461 428
        vtc_dump(p->vl, 4, "output", l, -1);
462 428
        return (0);
463
}
464
465
static int v_matchproto_(vev_cb_f)
466 3248
process_stdout(const struct vev *ev, int what)
467
{
468
        struct process *p;
469
        char buf[BUFSIZ];
470
        int i;
471
472 3248
        CAST_OBJ_NOTNULL(p, ev->priv, PROCESS_MAGIC);
473
        (void)what;
474 3248
        i = read(p->fd_term, buf, sizeof buf);
475 3248
        if (i <= 0) {
476 132
                vtc_log(p->vl, 4, "stdout read %d", i);
477 132
                return (1);
478
        }
479 3116
        AZ(pthread_mutex_lock(&p->mtx));
480 3116
        p->stdout_bytes += i;
481 3116
        AZ(pthread_mutex_unlock(&p->mtx));
482 3116
        if (p->log == 1)
483 161
                (void)VLU_Feed(p->vlu_stdout, buf, i);
484 2955
        else if (p->log == 2)
485 261
                vtc_dump(p->vl, 4, "stdout", buf, i);
486 2694
        else if (p->log == 3)
487 175
                vtc_hexdump(p->vl, 4, "stdout", buf, i);
488 3116
        assert(write(p->f_stdout, buf, i) == i);
489 3116
        AZ(pthread_mutex_lock(&p->mtx));
490 3116
        teken_input(p->tek, buf, i);
491 3116
        AZ(pthread_mutex_unlock(&p->mtx));
492 3116
        return (0);
493
}
494
495
static int v_matchproto_(vev_cb_f)
496 180
process_stderr(const struct vev *ev, int what)
497
{
498
        struct process *p;
499
        char buf[BUFSIZ];
500
        int i;
501
502 180
        CAST_OBJ_NOTNULL(p, ev->priv, PROCESS_MAGIC);
503
        (void)what;
504 180
        i = read(p->fd_stderr, buf, sizeof buf);
505 180
        if (i <= 0) {
506 132
                vtc_log(p->vl, 4, "stderr read %d", i);
507 132
                return (1);
508
        }
509 48
        AZ(pthread_mutex_lock(&p->mtx));
510 48
        p->stderr_bytes += i;
511 48
        AZ(pthread_mutex_unlock(&p->mtx));
512 48
        vtc_dump(p->vl, 4, "stderr", buf, i);
513 48
        assert(write(p->f_stderr, buf, i) == i);
514 48
        return (0);
515
}
516
517
static void *
518 132
process_thread(void *priv)
519
{
520
        struct process *p;
521
        struct vev_root *evb;
522
        struct vev *ev;
523
        int r;
524
525 132
        CAST_OBJ_NOTNULL(p, priv, PROCESS_MAGIC);
526
527 132
        p->f_stdout = open(p->out, O_WRONLY|O_APPEND);
528 132
        assert(p->f_stdout >= 0);
529 132
        p->f_stderr = open(p->err, O_WRONLY|O_APPEND);
530 132
        assert(p->f_stderr >= 0);
531
532 132
        evb = VEV_New();
533 132
        AN(evb);
534
535 132
        ev = VEV_Alloc();
536 132
        AN(ev);
537 132
        ev->fd = p->fd_term;
538 132
        ev->fd_flags = VEV__RD | VEV__HUP | VEV__ERR;
539 132
        ev->callback = process_stdout;
540 132
        ev->priv = p;
541 132
        AZ(VEV_Start(evb, ev));
542
543 132
        ev = VEV_Alloc();
544 132
        AN(ev);
545 132
        ev->fd = p->fd_stderr;
546 132
        ev->fd_flags = VEV__RD | VEV__HUP | VEV__ERR;
547 132
        ev->callback = process_stderr;
548 132
        ev->priv = p;
549 132
        AZ(VEV_Start(evb, ev));
550
551 132
        if (p->log == 1) {
552 20
                p->vlu_stdout = VLU_New(process_vlu_func, p, 1024);
553 20
                AN(p->vlu_stdout);
554 20
                p->vlu_stderr = VLU_New(process_vlu_func, p, 1024);
555 20
                AN(p->vlu_stderr);
556
        }
557
558
        do {
559 3451
                r = VEV_Once(evb);
560 3451
        } while (r == 1);
561
562 132
        if (r < 0)
563 0
                vtc_fatal(p->vl, "VEV_Once() = %d, error %s", r,
564 0
                    strerror(errno));
565
566 132
        vtc_wait4(p->vl, p->pid,
567
            p->expect_exit, p->expect_signal, p->allow_core);
568 132
        closefd(&p->f_stdout);
569 132
        closefd(&p->f_stderr);
570
571 132
        AZ(pthread_mutex_lock(&p->mtx));
572
573
        /* NB: We keep the other macros around */
574 132
        macro_undef(p->vl, p->name, "pid");
575 132
        p->pid = -1;
576
577 132
        AZ(pthread_mutex_unlock(&p->mtx));
578
579 132
        VEV_Destroy(&evb);
580 132
        if (p->log == 1) {
581 20
                VLU_Destroy(&p->vlu_stdout);
582 20
                VLU_Destroy(&p->vlu_stderr);
583
        }
584 132
        return (NULL);
585
}
586
587
static void
588 152
process_winsz(struct process *p, int fd)
589
{
590
        struct winsize ws;
591
        int i;
592
593 152
        memset(&ws, 0, sizeof ws);
594 152
        ws.ws_row = (short)p->nlin;
595 152
        ws.ws_col = (short)p->ncol;
596 152
        i = ioctl(fd, TIOCSWINSZ, &ws);
597 152
        if (i)
598 0
                vtc_log(p->vl, 4, "TIOCWINSZ %d %s", i, strerror(errno));
599 152
}
600
601
static void
602 132
process_init_term(struct process *p, int fd)
603
{
604
        struct termios tt;
605
        int i;
606
607 132
        process_winsz(p, fd);
608
609 132
        memset(&tt, 0, sizeof tt);
610 132
        tt.c_cflag = CREAD | CS8 | HUPCL;
611 132
        tt.c_iflag = BRKINT | ICRNL | IMAXBEL | IXON | IXANY;
612 132
        tt.c_lflag = ICANON | ISIG | IEXTEN | ECHO | ECHOE | ECHOKE | ECHOCTL;
613 132
        tt.c_oflag = OPOST | ONLCR;
614 132
        i = cfsetispeed(&tt, B9600);
615 132
        if (i)
616 0
                vtc_log(p->vl, 4, "cfsetispeed %d %s", i, strerror(errno));
617 132
        i = cfsetospeed(&tt, B9600);
618 132
        if (i)
619 0
                vtc_log(p->vl, 4, "cfsetospeed %d %s", i, strerror(errno));
620 132
        tt.c_cc[VEOF] = '\x04';                 // CTRL-D
621 132
        tt.c_cc[VERASE] = '\x08';               // CTRL-H (Backspace)
622 132
        tt.c_cc[VKILL] = '\x15';                // CTRL-U
623 132
        tt.c_cc[VINTR] = '\x03';                // CTRL-C
624 132
        tt.c_cc[VQUIT] = '\x1c';                // CTRL-backslash
625
626 132
        i = tcsetattr(fd, TCSAFLUSH, &tt);
627 132
        if (i)
628 0
                vtc_log(p->vl, 4, "TCSAFLUSH %d %s", i, strerror(errno));
629 132
}
630
631
/**********************************************************************
632
 * Start the process thread
633
 */
634
635
static void
636 132
process_start(struct process *p)
637
{
638
        struct vsb *cl;
639
        int fd2[2];
640
        int master, slave;
641
        const char *slavename;
642
        char c;
643
644 132
        CHECK_OBJ_NOTNULL(p, PROCESS_MAGIC);
645 132
        if (p->hasthread)
646 0
                vtc_fatal(p->vl, "Already running, -wait first");
647
648 132
        vtc_log(p->vl, 4, "CMD: %s", p->spec);
649
650 132
        cl = macro_expand(p->vl, p->spec);
651 132
        AN(cl);
652
653 132
        master = posix_openpt(O_RDWR|O_NOCTTY);
654 132
        assert(master >= 0);
655 132
        AZ(grantpt(master));
656 132
        AZ(unlockpt(master));
657 132
        slavename = ptsname(master);
658 132
        AN(slavename);
659
660 132
        AZ(pipe(fd2));
661
662 132
        p->pid = fork();
663 264
        assert(p->pid >= 0);
664 264
        if (p->pid == 0) {
665 132
                assert(setsid() == getpid());
666 132
                assert(dup2(fd2[1], STDERR_FILENO) == STDERR_FILENO);
667 132
                AZ(close(STDIN_FILENO));
668 132
                slave = open(slavename, O_RDWR);
669 132
                assert(slave == STDIN_FILENO);
670
#ifdef __sun
671
                if (ioctl(slave, I_PUSH, "ptem"))
672
                        vtc_log(p->vl, 4, "PUSH ptem: %s", strerror(errno));
673
                if (ioctl(slave, I_PUSH, "ldterm"))
674
                        vtc_log(p->vl, 4, "PUSH ldterm: %s", strerror(errno));
675
                (void)ioctl(STDIN_FILENO, TIOCSCTTY, NULL);
676
#else
677 132
                AZ(ioctl(STDIN_FILENO, TIOCSCTTY, NULL));
678
#endif
679 132
                AZ(close(STDOUT_FILENO));
680 132
                assert(dup2(slave, STDOUT_FILENO) == STDOUT_FILENO);
681 132
                VSUB_closefrom(STDERR_FILENO + 1);
682 132
                process_init_term(p, slave);
683
684 132
                AZ(setenv("TERM", "xterm", 1));
685 132
                AZ(unsetenv("TERMCAP"));
686
                // Not using NULL because GCC is now even more demented...
687 132
                assert(write(STDERR_FILENO, "+", 1) == 1);
688 132
                AZ(execl("/bin/sh", "/bin/sh", "-c", VSB_data(cl), (char*)0));
689 0
                exit(1);
690
        }
691 132
        vtc_log(p->vl, 3, "PID: %ld", (long)p->pid);
692 132
        VSB_destroy(&cl);
693
694 132
        assert(read(fd2[0], &c, 1) == 1);
695 132
        p->fd_term = master;
696 132
        closefd(&fd2[1]);
697 132
        p->fd_stderr = fd2[0];
698 132
        macro_def(p->vl, p->name, "pid", "%ld", (long)p->pid);
699 132
        macro_def(p->vl, p->name, "dir", "%s", p->dir);
700 132
        macro_def(p->vl, p->name, "out", "%s", p->out);
701 132
        macro_def(p->vl, p->name, "err", "%s", p->err);
702 132
        p->hasthread = 1;
703 132
        AZ(pthread_create(&p->tp, NULL, process_thread, p));
704 132
}
705
706
/**********************************************************************
707
 * Wait for process thread to stop
708
 */
709
710
static void
711 132
process_wait(struct process *p)
712
{
713
        void *v;
714
715 132
        if (p->hasthread) {
716 132
                AZ(pthread_join(p->tp, &v));
717 132
                p->hasthread = 0;
718
        }
719 132
        vtc_log(p->vl, 4, "stdout %ju bytes, stderr %ju bytes",
720
            p->stdout_bytes, p->stderr_bytes);
721 132
}
722
723
/**********************************************************************
724
 * Send a signal to a process
725
 */
726
727
static void
728 52
process_kill(struct process *p, const char *sig)
729
{
730 52
        int j = 0;
731
        pid_t pid;
732
733 52
        CHECK_OBJ_NOTNULL(p, PROCESS_MAGIC);
734 52
        AN(sig);
735
736 52
        AZ(pthread_mutex_lock(&p->mtx));
737 52
        pid = p->pid;
738 52
        AZ(pthread_mutex_unlock(&p->mtx));
739
740 52
        if (pid <= 0)
741 0
                vtc_fatal(p->vl, "Cannot signal a non-running process");
742
743 52
        if (!strcmp(sig, "TERM"))
744 40
                j = SIGTERM;
745 12
        else if (!strcmp(sig, "INT"))
746 0
                j = SIGINT;
747 12
        else if (!strcmp(sig, "KILL"))
748 8
                j = SIGKILL;
749 4
        else if (!strcmp(sig, "HUP"))
750 4
                j = SIGHUP;
751 0
        else if (*sig == '-')
752 0
                j = strtoul(sig + 1, NULL, 10);
753
        else
754 0
                vtc_fatal(p->vl, "Could not grok signal (%s)", sig);
755
756 52
        if (p->expect_signal == 0)
757 52
                p->expect_signal = -j;
758 52
        if (kill(-pid, j) < 0)
759 0
                vtc_fatal(p->vl, "Failed to send signal %d (%s)",
760 0
                    j, strerror(errno));
761
        else
762 52
                vtc_log(p->vl, 4, "Sent signal %d", j);
763 52
}
764
765
/**********************************************************************
766
 * Write to a process' stdin
767
 */
768
769
static void
770 472
process_write(const struct process *p, const char *text)
771
{
772
        int r, len;
773
774 472
        if (!p->hasthread)
775 0
                vtc_fatal(p->vl, "Cannot write to a non-running process");
776
777 472
        len = strlen(text);
778 472
        vtc_log(p->vl, 4, "Writing %d bytes", len);
779 472
        r = write(p->fd_term, text, len);
780 472
        if (r != len)
781 0
                vtc_fatal(p->vl, "Failed to write: len=%d %s (%d)",
782 0
                    len, strerror(errno), errno);
783 472
}
784
785
static void
786 500
process_write_hex(const struct process *p, const char *text)
787
{
788
        struct vsb *vsb;
789
        int j;
790
791 500
        if (!p->hasthread)
792 0
                vtc_fatal(p->vl, "Cannot write to a non-running process");
793
794 500
        vsb = vtc_hex_to_bin(p->vl, text);
795 500
        assert(VSB_len(vsb) >= 0);
796 500
        vtc_hexdump(p->vl, 4, "sendhex", VSB_data(vsb), VSB_len(vsb));
797 500
        j = write(p->fd_term, VSB_data(vsb), VSB_len(vsb));
798 500
        assert(j == VSB_len(vsb));
799 500
        VSB_destroy(&vsb);
800 500
}
801
802
static void
803 0
process_close(struct process *p)
804
{
805
806 0
        if (!p->hasthread)
807 0
                vtc_fatal(p->vl, "Cannot close a non-running process");
808
809 0
        process_kill(p, "HUP");
810 0
}
811
812
/* SECTION: process process
813
 *
814
 * Run a process with stdin+stdout on a pseudo-terminal and stderr on a pipe.
815
 *
816
 * Output from the pseudo-terminal is copied verbatim to ${pNAME_out},
817
 * and the -log/-dump/-hexdump flags will also put it in the vtc-log.
818
 *
819
 * The pseudo-terminal is not in ECHO mode, but if the programs run set
820
 * it to ECHO mode ("stty sane") any input sent to the process will also
821
 * appear in this stream because of the ECHO.
822
 *
823
 * Output from the stderr-pipe is copied verbatim to ${pNAME_err}, and
824
 * is always included in the vtc_log.
825
 *
826
 *      process pNAME SPEC [-log] [-dump] [-hexdump] [-expect-exit N]
827
 *              [-start] [-run]
828
 *              [-write STRING] [-writeln STRING]
829
 *              [-kill STRING] [-stop] [-wait] [-close]
830
 *
831
 * pNAME
832
 *      Name of the process. It must start with 'p'.
833
 *
834
 * SPEC
835
 *      The command(s) to run in this process.
836
 *
837
 * \-hexdump
838
 *      Log output with vtc_hexdump(). Must be before -start/-run.
839
 *
840
 * \-dump
841
 *      Log output with vtc_dump(). Must be before -start/-run.
842
 *
843
 * \-log
844
 *      Log output with VLU/vtc_log(). Must be before -start/-run.
845
 *
846
 * \-start
847
 *      Start the process.
848
 *
849
 * \-expect-exit N
850
 *      Expect exit status N
851
 *
852
 * \-wait
853
 *      Wait for the process to finish.
854
 *
855
 * \-run
856
 *      Shorthand for -start -wait.
857
 *
858
 *      In most cases, if you just want to start a process and wait for it
859
 *      to finish, you can use the ``shell`` command instead.
860
 *      The following commands are equivalent::
861
 *
862
 *          shell "do --something"
863
 *
864
 *          process p1 "do --something" -run
865
 *
866
 *      However, you may use the the ``process`` variant to conveniently
867
 *      collect the standard input and output without dealing with shell
868
 *      redirections yourself. The ``shell`` command can also expect an
869
 *      expression from either output, consider using it if you only need
870
 *      to match one.
871
 *
872
 * \-kill STRING
873
 *      Send a signal to the process. The argument can be either
874
 *      the string "TERM", "INT", or "KILL" for SIGTERM, SIGINT or SIGKILL
875
 *      signals, respectively, or a hyphen (-) followed by the signal
876
 *      number.
877
 *
878
 *      If you need to use other signal names, you can use the ``kill``\(1)
879
 *      command directly::
880
 *
881
 *          shell "kill -USR1 ${pNAME_pid}"
882
 *
883
 *      Note that SIGHUP usage is discouraged in test cases.
884
 *
885
 * \-stop
886
 *      Shorthand for -kill TERM.
887
 *
888
 * \-write STRING
889
 *      Write a string to the process' stdin.
890
 *
891
 * \-writeln STRING
892
 *      Same as -write followed by a newline (\\n).
893
 *
894
 * \-writehex HEXSTRING
895
 *      Same as -write but interpreted as hexadecimal bytes.
896
 *
897
 * \-need-bytes [+]NUMBER
898
 *      Wait until at least NUMBER bytes have been received in total.
899
 *      If '+' is prefixed, NUMBER new bytes must be received.
900
 *
901
 * \-expect-text LIN COL PAT
902
 *      Wait for PAT to appear at LIN,COL on the virtual screen.
903
 *      Lines and columns are numbered 1...N
904
 *      LIN==0 means "on any line"
905
 *      COL==0 means "anywhere on the line"
906
 *
907
 * \-close
908
 *      Alias for "-kill HUP"
909
 *
910
 * \-screen_dump
911
 *      Dump the virtual screen into vtc_log
912
 *
913
 */
914
915
void
916 5544
cmd_process(CMD_ARGS)
917
{
918
        struct process *p, *p2;
919
        uintmax_t u, v, bsnap;
920
        unsigned lin,col;
921 5544
        int spec_set = 0;
922
923
        (void)priv;
924
        (void)cmd;
925
926 5544
        if (av == NULL) {
927
                /* Reset and free */
928 3184
                VTAILQ_FOREACH_SAFE(p, &processes, list, p2) {
929 132
                        if (p->pid > 0) {
930 8
                                process_kill(p, "TERM");
931 8
                                sleep(1);
932 8
                                if (p->pid > 0)
933 0
                                        process_kill(p, "KILL");
934
                        }
935 132
                        if (p->hasthread)
936 12
                                process_wait(p);
937 132
                        VTAILQ_REMOVE(&processes, p, list);
938 132
                        process_undef(p);
939 132
                        process_delete(p);
940
                }
941 3052
                return;
942
        }
943
944 2492
        AZ(strcmp(av[0], "process"));
945 2492
        av++;
946
947 2492
        VTC_CHECK_NAME(vl, av[0], "Process", 'p');
948 6496
        VTAILQ_FOREACH(p, &processes, list)
949 6364
                if (!strcmp(p->name, av[0]))
950 2360
                        break;
951 2492
        if (p == NULL)
952 132
                p = process_new(av[0]);
953 2492
        av++;
954
955 2492
        bsnap = p->stdout_bytes;
956
957 5368
        for (; *av != NULL; av++) {
958 2876
                if (vtc_error)
959 0
                        break;
960
961 2876
                if (!strcmp(*av, "-allow-core")) {
962 0
                        p->allow_core = 1;
963 0
                        continue;
964
                }
965 2876
                if (!strcmp(*av, "-close")) {
966 0
                        process_close(p);
967 0
                        continue;
968
                }
969 2876
                if (!strcmp(*av, "-dump")) {
970 36
                        if (p->hasthread)
971 0
                                vtc_fatal(p->vl,
972
                                    "Cannot dump a running process");
973 36
                        p->log = 2;
974 36
                        continue;
975
                }
976 2840
                if (!strcmp(*av, "-expect-exit")) {
977 12
                        p->expect_exit = strtoul(av[1], NULL, 0);
978 12
                        av++;
979 12
                        continue;
980
                }
981 2828
                if (!strcmp(*av, "-expect-signal")) {
982 0
                        p->expect_signal = strtoul(av[1], NULL, 0);
983 0
                        av++;
984 0
                        continue;
985
                }
986 2828
                if (!strcmp(*av, "-hexdump")) {
987 16
                        if (p->hasthread)
988 0
                                vtc_fatal(p->vl,
989
                                    "Cannot dump a running process");
990 16
                        p->log = 3;
991 16
                        continue;
992
                }
993 2812
                if (!strcmp(*av, "-kill")) {
994 20
                        process_kill(p, av[1]);
995 20
                        av++;
996 20
                        continue;
997
                }
998 2792
                if (!strcmp(*av, "-log")) {
999 20
                        if (p->hasthread)
1000 0
                                vtc_fatal(p->vl,
1001
                                    "Cannot log a running process");
1002 20
                        p->log = 1;
1003 20
                        continue;
1004
                }
1005 2772
                if (!strcmp(*av, "-need-bytes")) {
1006 36
                        u = strtoumax(av[1], NULL, 0);
1007 36
                        if (av[1][0] == '+')
1008 28
                                u += bsnap;
1009 36
                        av++;
1010
                        do {
1011 70
                                AZ(pthread_mutex_lock(&p->mtx));
1012 70
                                v = p->stdout_bytes;
1013 70
                                AZ(pthread_mutex_unlock(&p->mtx));
1014 70
                                vtc_log(p->vl, 4, "Have %ju bytes", v);
1015 70
                                usleep(500000);
1016 70
                        } while(v < u);
1017 36
                        continue;
1018
                }
1019 2736
                if (!strcmp(*av, "-run")) {
1020 8
                        process_start(p);
1021 8
                        process_wait(p);
1022 8
                        continue;
1023
                }
1024 2728
                if (!strcmp(*av, "-ansi-response")) {
1025 8
                        p->ansi_response = 1;
1026 8
                        continue;
1027
                }
1028 2720
                if (!strcmp(*av, "-expect-text")) {
1029 832
                        AN(av[1]);
1030 832
                        AN(av[2]);
1031 832
                        AN(av[3]);
1032 832
                        term_expect_text(p, av[1], av[2], av[3]);
1033 832
                        av += 3;
1034 832
                        continue;
1035
                }
1036 1888
                if (!strcmp(*av, "-expect-cursor")) {
1037 32
                        AN(av[1]);
1038 32
                        AN(av[2]);
1039 32
                        term_expect_cursor(p, av[1], av[2]);
1040 32
                        av += 2;
1041 32
                        continue;
1042
                }
1043 3232
                if (!strcmp(*av, "-screen_dump") ||
1044 1376
                    !strcmp(*av, "-screen-dump")) {
1045 504
                        term_screen_dump(p);
1046 504
                        continue;
1047
                }
1048 1352
                if (!strcmp(*av, "-start")) {
1049 124
                        process_start(p);
1050 124
                        continue;
1051
                }
1052 1228
                if (!strcmp(*av, "-stop")) {
1053 24
                        process_kill(p, "TERM");
1054 24
                        sleep(1);
1055 24
                        continue;
1056
                }
1057 1204
                if (!strcmp(*av, "-wait")) {
1058 112
                        process_wait(p);
1059 112
                        continue;
1060
                }
1061 1092
                if (!strcmp(*av, "-winsz")) {
1062 20
                        lin = atoi(av[1]);
1063 20
                        assert(lin > 1);
1064 20
                        col = atoi(av[2]);
1065 20
                        assert(col > 1);
1066 20
                        av += 2;
1067 20
                        AZ(pthread_mutex_lock(&p->mtx));
1068 20
                        term_resize(p, lin, col);
1069 20
                        AZ(pthread_mutex_unlock(&p->mtx));
1070 20
                        process_winsz(p, p->fd_term);
1071
                }
1072 1092
                if (!strcmp(*av, "-write")) {
1073 408
                        process_write(p, av[1]);
1074 408
                        av++;
1075 408
                        continue;
1076
                }
1077 684
                if (!strcmp(*av, "-writehex")) {
1078 500
                        process_write_hex(p, av[1]);
1079 500
                        av++;
1080 500
                        continue;
1081
                }
1082 184
                if (!strcmp(*av, "-writeln")) {
1083 32
                        process_write(p, av[1]);
1084 32
                        process_write(p, "\n");
1085 32
                        av++;
1086 32
                        continue;
1087
                }
1088 152
                if (**av == '-' || spec_set)
1089 0
                        vtc_fatal(p->vl, "Unknown process argument: %s",
1090
                            *av);
1091 152
                REPLACE(p->spec, *av);
1092 152
                spec_set = 1;
1093
        }
1094
}