Diff

Differences From Artifact [99d07fada6]:

To Artifact [fb4ec99bd9]:


1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
/*
 * Pseudo-tty backend for pterm.
 */

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

#include <fcntl.h>
#include <termios.h>
#include <grp.h>
#include <utmp.h>
#include <pwd.h>
#include <time.h>
#include <sys/types.h>











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 * Pseudo-tty backend for pterm.
 */

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <assert.h>
#include <fcntl.h>
#include <termios.h>
#include <grp.h>
#include <utmp.h>
#include <pwd.h>
#include <time.h>
#include <sys/types.h>
79
80
81
82
83
84
85

86
87
88
89
90
91
92
    int master_fd, slave_fd;
    void *frontend;
    char name[FILENAME_MAX];
    int child_pid;
    int term_width, term_height;
    int child_dead, finished;
    int exit_code;

};

/*
 * We store our pty backends in a tree sorted by master fd, so that
 * when we get an uxsel notification we know which backend instance
 * is the owner of the pty that caused it.
 */







>







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
    int master_fd, slave_fd;
    void *frontend;
    char name[FILENAME_MAX];
    int child_pid;
    int term_width, term_height;
    int child_dead, finished;
    int exit_code;
    bufchain output_data;
};

/*
 * We store our pty backends in a tree sorted by master fd, so that
 * when we get an uxsel notification we know which backend instance
 * is the owner of the pty that caused it.
 */
174
175
176
177
178
179
180

181
182
183
184
185
186
187
 * pty_argv is a grievous hack to allow a proper argv to be passed
 * through from the Unix command line. Again, it doesn't really
 * make sense outside a one-pty-per-process setup.
 */
char **pty_argv;

static void pty_close(Pty pty);


#ifndef OMIT_UTMP
static void setup_utmp(char *ttyname, char *location)
{
#ifdef HAVE_LASTLOG
    struct lastlog lastlog_entry;
    FILE *lastlog;







>







176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
 * pty_argv is a grievous hack to allow a proper argv to be passed
 * through from the Unix command line. Again, it doesn't really
 * make sense outside a one-pty-per-process setup.
 */
char **pty_argv;

static void pty_close(Pty pty);
static void pty_try_write(Pty pty);

#ifndef OMIT_UTMP
static void setup_utmp(char *ttyname, char *location)
{
#ifdef HAVE_LASTLOG
    struct lastlog lastlog_entry;
    FILE *lastlog;
342
343
344
345
346
347
348








349
350
351
352
353
354
355
	perror("unlockpt");
	exit(1);
    }

    pty->name[FILENAME_MAX-1] = '\0';
    strncpy(pty->name, ptsname(pty->master_fd), FILENAME_MAX-1);
#endif









    if (!ptys_by_fd)
	ptys_by_fd = newtree234(pty_compare_by_fd);
    add234(ptys_by_fd, pty);
}

/*







>
>
>
>
>
>
>
>







345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
	perror("unlockpt");
	exit(1);
    }

    pty->name[FILENAME_MAX-1] = '\0';
    strncpy(pty->name, ptsname(pty->master_fd), FILENAME_MAX-1);
#endif

    {
        /*
         * Set the pty master into non-blocking mode.
         */
        int i = 1;
        ioctl(pty->master_fd, FIONBIO, &i);
    }

    if (!ptys_by_fd)
	ptys_by_fd = newtree234(pty_compare_by_fd);
    add234(ptys_by_fd, pty);
}

/*
371
372
373
374
375
376
377

378
379
380
381
382
383
384

#ifndef OMIT_UTMP
    pid_t pid;
    int pipefd[2];
#endif

    pty = single_pty = snew(struct pty_tag);


    /* set the child signal handler straight away; it needs to be set
     * before we ever fork. */
    putty_signal(SIGCHLD, sigchld_handler);
    pty->master_fd = pty->slave_fd = -1;
#ifndef OMIT_UTMP
    pty_stamped_utmp = FALSE;







>







382
383
384
385
386
387
388
389
390
391
392
393
394
395
396

#ifndef OMIT_UTMP
    pid_t pid;
    int pipefd[2];
#endif

    pty = single_pty = snew(struct pty_tag);
    bufchain_init(&pty->output_data);

    /* set the child signal handler straight away; it needs to be set
     * before we ever fork. */
    putty_signal(SIGCHLD, sigchld_handler);
    pty->master_fd = pty->slave_fd = -1;
#ifndef OMIT_UTMP
    pty_stamped_utmp = FALSE;
551
552
553
554
555
556
557





558
559
560
561
562
563
564
565
		    pty->exit_code = 0;
	    } else if (ret < 0) {
		perror("read pty master");
		exit(1);
	    } else if (ret > 0) {
		from_backend(pty->frontend, 0, buf, ret);
	    }





	}
    }

    if (finished && !pty->finished) {
	uxsel_del(pty->master_fd);
	pty_close(pty);
	pty->master_fd = -1;








>
>
>
>
>
|







563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
		    pty->exit_code = 0;
	    } else if (ret < 0) {
		perror("read pty master");
		exit(1);
	    } else if (ret > 0) {
		from_backend(pty->frontend, 0, buf, ret);
	    }
	} else if (event == 2) {
            /*
             * Attempt to send data down the pty.
             */
            pty_try_write(pty);
        }
    }

    if (finished && !pty->finished) {
	uxsel_del(pty->master_fd);
	pty_close(pty);
	pty->master_fd = -1;

625
626
627
628
629
630
631





632
633
634
635
636
637
638
639
    }

    return ret;
}

static void pty_uxsel_setup(Pty pty)
{





    uxsel_set(pty->master_fd, 1, pty_select_result);

    /*
     * In principle this only needs calling once for all pty
     * backend instances, but it's simplest just to call it every
     * time; uxsel won't mind.
     */
    uxsel_set(pty_signal_pipe[0], 1, pty_select_result);







>
>
>
>
>
|







642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
    }

    return ret;
}

static void pty_uxsel_setup(Pty pty)
{
    int rwx;

    rwx = 1;                           /* always want to read from pty */
    if (bufchain_size(&pty->output_data))
        rwx |= 2;                      /* might also want to write to it */
    uxsel_set(pty->master_fd, rwx, pty_select_result);

    /*
     * In principle this only needs calling once for all pty
     * backend instances, but it's simplest just to call it every
     * time; uxsel won't mind.
     */
    uxsel_set(pty_signal_pipe[0], 1, pty_select_result);
866
867
868
869
870
871
872



























873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900

    /* Either of these may fail `not found'. That's fine with us. */
    del234(ptys_by_pid, pty);
    del234(ptys_by_fd, pty);

    sfree(pty);
}




























/*
 * Called to send data down the pty.
 */
static int pty_send(void *handle, char *buf, int len)
{
    Pty pty = (Pty)handle;

    if (pty->master_fd < 0)
	return 0;		       /* ignore all writes if fd closed */

    while (len > 0) {
	int ret = write(pty->master_fd, buf, len);
	if (ret < 0) {
	    perror("write pty master");
	    exit(1);
	}
	buf += ret;
	len -= ret;
    }
    return 0;
}

static void pty_close(Pty pty)
{
    if (pty->master_fd >= 0) {
	close(pty->master_fd);
	pty->master_fd = -1;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>









|

<
|
<
|
<
|
<
<
<
|







888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932

933

934

935



936
937
938
939
940
941
942
943

    /* Either of these may fail `not found'. That's fine with us. */
    del234(ptys_by_pid, pty);
    del234(ptys_by_fd, pty);

    sfree(pty);
}

static void pty_try_write(Pty pty)
{
    void *data;
    int len, ret;

    assert(pty->master_fd >= 0);

    while (bufchain_size(&pty->output_data) > 0) {
        bufchain_prefix(&pty->output_data, &data, &len);
	ret = write(pty->master_fd, data, len);

        if (ret < 0 && (errno == EWOULDBLOCK)) {
            /*
             * We've sent all we can for the moment.
             */
            break;
        }
	if (ret < 0) {
	    perror("write pty master");
	    exit(1);
	}
	bufchain_consume(&pty->output_data, ret);
    }

    pty_uxsel_setup(pty);
}

/*
 * Called to send data down the pty.
 */
static int pty_send(void *handle, char *buf, int len)
{
    Pty pty = (Pty)handle;

    if (pty->master_fd < 0)
	return 0;                      /* ignore all writes if fd closed */


    bufchain_add(&pty->output_data, buf, len);

    pty_try_write(pty);





    return bufchain_size(&pty->output_data);
}

static void pty_close(Pty pty)
{
    if (pty->master_fd >= 0) {
	close(pty->master_fd);
	pty->master_fd = -1;