int tty_setty(int fd, ttydata_t *td) { #ifdef POSIX RETRY(xtcsetattr(fd, TCSADRAIN, &td->d_t)); #else # ifdef TERMIO RETRY(ioctl(fd, TCSETAW, (ioctl_t) &td->d_t)); # else # ifdef TIOCSETN RETRY(ioctl(fd, TIOCSETN, (ioctl_t) &td->d_t)); # endif /* TIOCSETN */ # ifdef TIOCGETC RETRY(ioctl(fd, TIOCSETC, (ioctl_t) &td->d_tc)); # endif /* TIOCGETC */ # ifdef TIOCGPAGE RETRY(ioctl(fd, TIOCSPAGE, (ioctl_t) &td->d_pc)); # endif /* TIOCGPAGE */ # ifdef TIOCLGET RETRY(ioctl(fd, TIOCLSET, (ioctl_t) &td->d_lb)); # endif /* TIOCLGET */ # endif /* TERMIO */ #endif /* POSIX */ #ifdef TIOCGLTC RETRY(ioctl(fd, TIOCSLTC, (ioctl_t) &td->d_ltc)); #endif /* TIOCGLTC */ return 0; }
static void set_window_size(int fd, const struct window_size* ws) { int ret; struct winsize wz = { .ws_row = ws->row, .ws_col = ws->col, .ws_xpixel = ws->xpixel, .ws_ypixel = ws->ypixel, }; do { ret = ioctl(fd, TIOCSWINSZ, &wz); } while (ret == -1 && errno == EINTR); dbg("TIOCSWINSZ(%ux%u): %d", wz.ws_row, wz.ws_col, ret); } struct stub { struct fb_adb_sh sh; struct child* child; }; static void stub_process_msg(struct fb_adb_sh* sh, struct msg mhdr) { if (mhdr.type == MSG_WINDOW_SIZE) { struct msg_window_size m; read_cmdmsg(sh, mhdr, &m, sizeof (m)); dbgmsg(&m.msg, "recv"); struct stub* stub = (struct stub*) sh; if (stub->child->pty_master) set_window_size(stub->child->pty_master->fd, &m.ws); return; } fb_adb_sh_process_msg(sh, mhdr); } static void setup_pty(int master, int slave, void* arg) { struct msg_shex_hello* shex_hello = arg; char* hello_end = (char*) shex_hello + shex_hello->msg.size; struct termios attr = { 0 }; xtcgetattr(slave, &attr); if (shex_hello->ispeed) cfsetispeed(&attr, shex_hello->ispeed); if (shex_hello->ospeed) cfsetospeed(&attr, shex_hello->ospeed); const struct termbit* tb = &termbits[0]; const struct termbit* tb_end = tb + nr_termbits; struct term_control* tc = &shex_hello->tctl[0]; while ((char*)(tc+1) <= hello_end && tb < tb_end) { int cmp = strncmp(tc->name, tb->name, sizeof (tc->name)); if (cmp < 0) { dbg("tc not present: %.*s", (int) sizeof (tc->name), tc->name); tc++; continue; } if (cmp > 0) { dbg("tc not sent: %s", tb->name); tb++; continue; } tcflag_t* flg = NULL; if (tb->thing == TERM_IFLAG) { flg = &attr.c_iflag; } else if (tb->thing == TERM_OFLAG) { flg = &attr.c_oflag; } else if (tb->thing == TERM_LFLAG) { flg = &attr.c_lflag; } else if (tb->thing == TERM_C_CC) { if (tc->value == shex_hello->posix_vdisable_value) attr.c_cc[tb->value] = _POSIX_VDISABLE; else attr.c_cc[tb->value] = tc->value; dbg("c_cc[%s] = %d", tb->name, tc->value); } if (flg) { if (tc->value) { dbg("pty %s: set", tb->name); *flg |= tb->value; } else { dbg("pty %s: reset", tb->name); *flg &= ~tb->value; } } tc++; tb++; } xtcsetattr(slave, &attr); if (shex_hello->have_ws) { dbg("ws %ux%u (%ux%u)", shex_hello->ws.row, shex_hello->ws.col, shex_hello->ws.xpixel, shex_hello->ws.ypixel); set_window_size(master, &shex_hello->ws); } } static char** read_child_arglist(size_t expected) { char** argv; if (expected >= SIZE_MAX / sizeof (*argv)) die(EFBIG, "too many arguments"); argv = xalloc(sizeof (*argv) * (1+expected)); for (size_t argno = 0; argno < expected; ++argno) { SCOPED_RESLIST(rl_read_arg); struct msg_cmdline_argument* m; struct msg* mhdr = read_msg(0, read_all_adb_encoded); reslist_pop_nodestroy(rl_read_arg); const char* argval; size_t arglen; if (mhdr->type == MSG_CMDLINE_ARGUMENT) { m = (struct msg_cmdline_argument*) mhdr; if (mhdr->size < sizeof (*m)) die(ECOMM, "bad handshake: MSG_CMDLINE_ARGUMENT size %u < %u", (unsigned) mhdr->size, (unsigned) sizeof (*m)); argval = m->value; arglen = m->msg.size - sizeof (*m); } else if (mhdr->type == MSG_CMDLINE_DEFAULT_SH || mhdr->type == MSG_CMDLINE_DEFAULT_SH_LOGIN) { argval = getenv("SHELL"); if (argval == NULL) argval = DEFAULT_SHELL; if (mhdr->type == MSG_CMDLINE_DEFAULT_SH_LOGIN) argval = xaprintf("-%s", argval); arglen = strlen(argval); } else { die(ECOMM, "bad handshake: unknown init msg s=%u t=%u", (unsigned) mhdr->size, (unsigned) mhdr->type); } argv[argno] = xalloc(arglen + 1); memcpy(argv[argno], argval, arglen); argv[argno][arglen] = '\0'; } argv[expected] = NULL; return argv; }