Почему pty драйвер Linux заменяет VEOF на NUL? - PullRequest
8 голосов
/ 30 апреля 2019

Похоже, что драйвер pty в Linux заменяет символы VEOF (^D, \4) на байты NUL (\0) в данных, уже записанных со стороны мастера, если настройки терминала изменены на tcsetattr(TCSANOW) в неканонический режим перед чтением на ведомой стороне.

Почему это происходит?У него есть какое-то оправдание или это просто ошибка?

Есть ли способ избежать этого?- кроме ожидания ввода от ведомого на ведущей стороне перед записью чего-либо, что нецелесообразно, потому что на ведомой стороне может быть другая программа - процедура установки терминала в режим raw, который я упростил здесьобычно это то, что делает любая оболочка с возможностью редактирования строк.

Хотя можно ожидать, например, заменить \r на \n (поскольку флаг ICRNL уже был применен), я не могу дать какое-либо обоснование дляэти NUL-байты появляются из ниоткуда.

Тестовый пример ниже: он напечатает foo\x00\x00\x00\x00 в Linux, но foo\x04\x04\x04\x04 в * BSD и foo в Solaris.

#define _XOPEN_SOURCE   600
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <termios.h>
#include <err.h>

#ifdef __sun
#include <stropts.h>
#define push_streams(fd)\
        if(ioctl(fd, I_PUSH, "ptem")) err(1, "ioctl(I_PUSH, ptem)");\
        if(ioctl(fd, I_PUSH, "ldterm")) err(1, "ioctl(I_PUSH, ldterm)");
#else
#define push_streams(sd)        /* no need */
#endif

int main(void){
        int mt, st; char *sname;

        /* openpty()-like boilerplate */
        if((mt = posix_openpt(O_RDWR|O_NOCTTY)) == -1) err(1, "posix_openpt");
        if(grantpt(mt)) err(1, "grantpt");
        if(unlockpt(mt)) err(1, "unlockpt");
        if(!(sname = ptsname(mt))) err(1, "ptsname");
        if((st = open(sname, O_RDWR|O_NOCTTY)) == -1) err(1, "open %s", sname);
        push_streams(st);

        /* master */ {
                char test[] = "foo\4\4\4\4";
                if(write(mt, test, sizeof test - 1) < sizeof test - 1)
                        err(1, "write");
        }
        /* slave */ {
                unsigned char buf[512]; int i, r;
                struct termios ts;
                usleep(1000);
                if(tcgetattr(st, &ts)) err(1, "tcgetattr");
                ts.c_lflag &= ~ICANON;
                if(tcsetattr(st, TCSANOW, &ts)) err(1, "tcsetattr");
                if((r = read(st, buf, sizeof buf)) < 0)
                        err(1, "read");
                for(i = 0; i < r; i++)
                        if(isprint(buf[i])) putchar(buf[i]);
                        else printf("\\x%02x", buf[i]);
                putchar('\n');
        }
        return 0;
}
...