8 typedef struct Termios Termios
;
9 typedef struct Winsize Winsize
;
10 typedef struct Cbuf Cbuf
;
11 typedef struct Tty Tty
;
12 typedef struct Pty Pty
;
13 typedef struct Ptyfile Ptyfile
;
124 int iflag
; /* input modes */
125 int oflag
; /* output modes */
126 int cflag
; /* control modes */
127 int lflag
; /* local modes */
129 uchar cc
[NCCS
]; /* control characters */
187 static Pty
*ptys
[64];
189 int cbput(Cbuf
*b
, char c
)
192 x
= b
->wp
+1&(sizeof(b
->cb
)-1);
206 b
->rp
= (b
->rp
+ 1) & (sizeof(b
->cb
)-1);
212 return (b
->wp
- b
->rp
) & (sizeof(b
->cb
)-1);
217 memset(&t
->t
, 0, sizeof(t
->t
));
220 t
->t
.oflag
= OPOST
|ONLCR
|NL0
|CR0
|TAB0
|BS0
|VT0
|FF0
;
221 t
->t
.lflag
= ICANON
|IEXTEN
|ECHO
|ECHOE
|ECHOK
;
224 t
->pgid
= current
->pgid
;
227 int ttywrite(Tty
*t
, char *buf
, int len
)
231 for(p
=buf
, e
=buf
+len
; p
<e
; p
++){
235 if((t
->t
.oflag
& OPOST
) == 0) {
236 if(cbput(&t
->wb
, c
) < 0)
242 if(t
->t
.oflag
& ONLCR
) {
243 if(cbput(&t
->wb
, '\r') < 0)
246 if(cbput(&t
->wb
, c
) < 0)
251 if((t
->t
.oflag
& TAB3
) == TAB3
) {
261 if(t
->t
.oflag
& OLCUC
)
262 if(c
>= 'a' && c
<= 'z')
264 if(cbput(&t
->wb
, c
) < 0)
272 int ttycanread(Tty
*t
, int *n
)
277 if(t
->t
.lflag
& ICANON
){
289 int ttyread(Tty
*t
, char *buf
, int len
)
293 if((t
->t
.lflag
& ICANON
) && t
->eol
== 0)
296 for(p
=buf
, e
=buf
+len
; p
<e
; p
++){
299 if((c
= cbget(&t
->rb
)) < 0)
304 if(t
->t
.lflag
& ICANON
){
321 if(t
->t
.lflag
& ECHO
) {
324 if(t
->t
.oflag
& OCRNL
) {
331 if(t
->t
.oflag
& ONLCR
)
336 if((t
->t
.oflag
& TAB3
) == TAB3
) {
351 if(c
== '\n' && (t
->t
.lflag
&(ECHONL
|ICANON
)) == (ECHONL
|ICANON
)) {
352 if(t
->t
.oflag
& ONLCR
)
364 if(cbfill(&t
->rb
) == 0)
366 x
= (t
->rb
.wp
-1)&(sizeof(t
->rb
.cb
)-1);
368 if(c
== 0 || c
== '\n')
372 if(t
->t
.lflag
& ECHOE
) {
379 int ttywriteinput(Tty
*t
, char *buf
, int len
)
383 for(p
=buf
, e
=buf
+len
; p
<e
; p
++){
388 if(t
->t
.iflag
& ISTRIP
)
391 if((t
->t
.iflag
& IXON
) && c
== t
->t
.cc
[VSTOP
]) {
398 if(t
->t
.iflag
& IGNCR
)
400 if(t
->t
.iflag
& ICRNL
)
409 if(t
->t
.lflag
& ISIG
) {
410 if(c
== t
->t
.cc
[VINTR
]){
412 sys_kill(-t
->pgid
, SIGINT
);
415 if(c
== t
->t
.cc
[VQUIT
]){
417 sys_kill(-t
->pgid
, SIGQUIT
);
422 if((t
->t
.lflag
& ICANON
) && t
->escaped
== 0) {
423 if(c
== t
->t
.cc
[VERASE
]) {
427 if(c
== t
->t
.cc
[VKILL
]) {
430 if(t
->t
.lflag
& ECHOK
)
436 if(t
->escaped
== 0 && (c
== t
->t
.cc
[VEOF
] || c
== '\n'))
439 if((t
->t
.lflag
& ICANON
) == 0) {
448 if(c
!= t
->t
.cc
[VEOF
])
452 if(c
== t
->t
.cc
[VEOF
])
469 int ttycanreadoutput(Tty
*t
, int *n
)
476 return x
> 0 ? 1 : 0;
479 int ttyreadoutput(Tty
*t
, char *buf
, int len
)
483 for(p
=buf
, e
=buf
+len
; p
<e
; p
++){
486 if((c
= cbget(&t
->wb
)) < 0)
494 pollpty(Ufile
*f
, void *tab
)
496 Ptyfile
*p
= (Ptyfile
*)f
;
505 pollwait(p
, &p
->pty
->q
[1].r
, tab
);
506 n
= ttycanreadoutput(p
->pty
, nil
);
508 pollwait(p
, &p
->pty
->q
[0].r
, tab
);
509 n
= ttycanread(p
->pty
, nil
);
514 } else if(p
->master
==0 && p
->pty
->closed
){
515 err
|= (POLLIN
| POLLHUP
);
523 readpty(Ufile
*f
, void *data
, int len
, vlong
)
526 Ptyfile
*p
= (Ptyfile
*)f
;
533 err
= ttycanreadoutput(p
->pty
, nil
);
535 err
= ttycanread(p
->pty
, nil
);
539 err
= ttyreadoutput(p
->pty
, (char*)data
, len
);
541 err
= ttyread(p
->pty
, (char*)data
, len
);
544 if(p
->master
== 0 && p
->pty
->closed
){
546 } else if(p
->mode
& O_NONBLOCK
){
549 if((err
= sleepq(&p
->pty
->q
[p
->master
].r
, p
->pty
, 1)) == 0)
553 wakeq(&p
->pty
->q
[!p
->master
].w
, MAXPROC
);
562 writepty(Ufile
*f
, void *data
, int len
, vlong
)
564 Ptyfile
*p
= (Ptyfile
*)f
;
579 err
= ttywriteinput(p
->pty
, (char*)data
, len
);
581 err
= ttywrite(p
->pty
, (char*)data
, len
);
584 if((err
= sleepq(&p
->pty
->q
[p
->master
].w
, p
->pty
, 1)) == 0)
587 if(ttycanread(p
->pty
, nil
))
588 wakeq(&p
->pty
->q
[0].r
, MAXPROC
);
589 if(ttycanreadoutput(p
->pty
, nil
))
590 wakeq(&p
->pty
->q
[1].r
, MAXPROC
);
602 Ptyfile
*p
= (Ptyfile
*)f
;
611 ptys
[p
->pty
->id
] = nil
;
615 wakeq(&p
->pty
->q
[0].r
, MAXPROC
);
616 wakeq(&p
->pty
->q
[0].w
, MAXPROC
);
617 wakeq(&p
->pty
->q
[1].r
, MAXPROC
);
618 wakeq(&p
->pty
->q
[1].w
, MAXPROC
);
625 changetty(Ptyfile
*tty
)
631 return (old
== tty
) ? 0 : -EPERM
;
633 tty
->pty
->pgid
= current
->pgid
;
639 ioctlpty(Ufile
*f
, int cmd
, void *arg
)
641 Ptyfile
*p
= (Ptyfile
*)f
;
647 trace("ioctlpty(%s, %lux, %p)", p
->path
, (ulong
)cmd
, arg
);
653 trace("ioctlpty: unknown: 0x%x", cmd
);
657 case 0x5401: /* TCGETS */
658 memmove(arg
, &p
->pty
->t
, sizeof(Termios
));
661 case 0x5402: /* TCSETS */
662 case 0x5403: /* TCSETSW */
663 case 0x5404: /* TCSETSF */
664 memmove(&p
->pty
->t
, arg
, sizeof(Termios
));
667 case 0x5422: // TIOCNOTTY
668 if((f
= gettty()) && (f
!= p
)){
676 case 0x540E: // TIOCSCTTY
680 case 0x540F: // TIOCGPGRP
681 *(int*)arg
= p
->pty
->pgid
;
684 case 0x5410: // TIOCSPGRP
685 p
->pty
->pgid
= *(int*)arg
;
688 case 0x5413: // TIOCGWINSZ
689 memmove(arg
, &p
->pty
->winsize
, sizeof(Winsize
));
692 case 0x5414: // TIOCSWINSZ
693 if(memcmp(&p
->pty
->winsize
, arg
, sizeof(Winsize
)) == 0)
695 memmove(&p
->pty
->winsize
, arg
, sizeof(Winsize
));
696 if((pid
= p
->pty
->pgid
) > 0){
699 sys_kill(-pid
, SIGWINCH
);
703 case 0x40045431: // TIOCSPTLCK
705 p
->pty
->locked
= *(int*)arg
;
709 *(int*)arg
= p
->pty
->id
;
716 ttycanreadoutput(p
->pty
, &err
);
718 ttycanread(p
->pty
, &err
);
734 openpty(char *path
, int mode
, int perm
, Ufile
**pf
)
743 if(strcmp("/dev/tty", path
)==0){
747 } else if(strcmp("/dev/pts", path
)==0){
750 } else if(strcmp("/dev/ptmx", path
)==0){
752 for(id
=0; id
<nelem(ptys
); id
++){
756 if(id
== nelem(ptys
))
759 pty
= kmallocz(sizeof(*pty
), 1);
764 ptys
[pty
->id
= id
] = pty
;
767 if(strncmp("/dev/pts/", path
, 9) != 0)
770 if(id
< 0 || id
>= nelem(ptys
))
772 if((pty
= ptys
[id
]) == nil
)
776 if(pty
->closed
|| pty
->locked
){
784 p
= kmallocz(sizeof(*p
), 1);
789 p
->path
= kstrdup(path
);
793 if(!master
&& !(mode
& O_NOCTTY
))
802 readdirpty(Ufile
*f
, Udirent
**pd
)
804 Ptyfile
*p
= (Ptyfile
*)f
;
811 for(i
=0; i
<nelem(ptys
); i
++){
816 snprint(buf
, sizeof(buf
), "%d", i
);
817 if((*pd
= newdirent(f
->path
, buf
, S_IFCHR
| 0666)) == nil
)
826 fstatpty(Ufile
*f
, Ustat
*s
)
828 Ptyfile
*p
= (Ptyfile
*)f
;
831 s
->mode
= 0666 | S_IFCHR
;
838 s
->mode
= 0777 | S_IFDIR
;
841 s
->ino
= hashpath(p
->path
);
843 s
->uid
= current
->uid
;
844 s
->gid
= current
->gid
;
846 s
->atime
= s
->mtime
= s
->ctime
= boottime
/1000000000LL;
851 statpty(char *path
, int, Ustat
*s
)
853 if(strcmp("/dev/tty", path
)==0){
854 s
->mode
= 0666 | S_IFCHR
;
855 } else if(strcmp("/dev/ptmx", path
)==0){
856 s
->mode
= 0666 | S_IFCHR
;
858 } else if(strcmp("/dev/pts", path
)==0){
859 s
->mode
= 0777 | S_IFDIR
;
860 } else if(strncmp("/dev/pts/", path
, 9)==0){
864 if(id
< 0 || id
>= nelem(ptys
))
869 s
->mode
= 0666 | S_IFCHR
;
874 s
->ino
= hashpath(path
);
875 s
->uid
= current
->uid
;
876 s
->gid
= current
->gid
;
878 s
->atime
= s
->mtime
= s
->ctime
= boottime
/1000000000LL;
883 chmodpty(char *path
, int mode
)
892 chownpty(char *path
, int uid
, int gid
, int link
)
903 fchmodpty(Ufile
*f
, int mode
)
912 fchownpty(Ufile
*f
, int uid
, int gid
)
928 .readdir
= readdirpty
,
938 void ptydevinit(void)
940 devtab
[PTYDEV
] = &ptydev
;
941 fsmount(&ptydev
, "/dev/pts");
942 fsmount(&ptydev
, "/dev/ptmx");
943 fsmount(&ptydev
, "/dev/tty");