1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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
|
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
|
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
|
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
|
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
|
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
|
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, 1, pty_select_result);
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
|
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 */
return 0; /* ignore all writes if fd closed */
while (len > 0) {
int ret = write(pty->master_fd, buf, len);
bufchain_add(&pty->output_data, buf, len);
if (ret < 0) {
perror("write pty master");
pty_try_write(pty);
exit(1);
}
buf += ret;
len -= ret;
}
return 0;
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;
|
| ︙ | | |