Created
March 12, 2015 12:52
-
-
Save tai/5d6ce0c28c6b39a9c9df to your computer and use it in GitHub Desktop.
Ad-hoc expect
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /*BINFMTC:-Wall -D_GNU_SOURCE | |
| * | |
| * 簡易expectもどきのテスト。 | |
| * | |
| * 新しくttyのペアを確保して、slave側を子プロセスのcttyにしながら | |
| * 起動する。もう一方のmaster側は親プロセス側でIOして子プロセスを | |
| * 制御する。 | |
| * | |
| * これ、master側をそのまま子プロセスにアタッチしてslave側は | |
| * 別のkermitでもなんでも適当なもので後でアタッチして制御を | |
| * 外部からできるようなセットアップだけできないかな、と思って | |
| * もう一つのコードも書いてみたが、master側をchildのcttyにどうしても | |
| * セットできない。エラーは出ないが起動したbashのcttyが?でアタッチ | |
| * できてない。 | |
| * | |
| * まあSCREEN/screen, TMUX/tmux, detachtty/attachttyのすべてが | |
| * 親プロセスがmaster ttyを握って第三のプロセスと別途通信しながら | |
| * リレーするという構造な訳で、アプリ的なニーズの他に何か実装上の | |
| * 理由でそういう制約が必要になってるのかな。 | |
| * | |
| */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <fcntl.h> | |
| #include <termios.h> | |
| #include <sys/ioctl.h> | |
| #include <sys/types.h> | |
| #include <sys/wait.h> | |
| int | |
| main(void) { | |
| int rc; | |
| pid_t parent, child; | |
| int ctty, mtty, stty; | |
| parent = getpid(); | |
| // allocate master/slave pts | |
| mtty = posix_openpt(O_RDWR|O_NOCTTY); | |
| if (mtty < 0) { | |
| perror("ptmx"); | |
| return -1; | |
| } | |
| printf("open: mtty=%d, %s\n", mtty, ttyname(mtty)); | |
| if ((child = fork()) == 0) { | |
| // Detach from current Controlling TTY (CTTY) | |
| ctty = open(ctermid(NULL), O_RDWR); | |
| printf("ctty=%d, %s\n", ctty, ttyname(ctty)); | |
| if (ioctl(ctty, TIOCNOTTY) < 0) | |
| perror("TIOCNOTTY"); | |
| // allow slave tty to be attached | |
| if (grantpt(mtty) < 0) | |
| perror("grantpt"); | |
| if (unlockpt(mtty) < 0) | |
| perror("unlockpt"); | |
| // obtain slave tty name | |
| char *stty_name = ptsname(mtty); | |
| printf("stty=%s\n", stty_name); | |
| close(mtty); | |
| // open slave tty for use by forking child | |
| stty = open(stty_name, O_RDWR|O_CLOEXEC); | |
| if (stty < 0) { | |
| perror("slave_tty"); | |
| return -1; | |
| } | |
| printf("open: stty=%d, %s\n", stty, ttyname(stty)); | |
| // switch stdio | |
| dup2(stty, 0); | |
| dup2(stty, 1); | |
| dup2(stty, 2); | |
| // Must NOT be a process group leader to call setsid(2) | |
| // So attach to some other PG leader. | |
| if (setpgid(0, parent) < 0) | |
| perror("setpgid"); | |
| // Must be a session leader to have a CTTY | |
| if (setsid() < 0) | |
| perror("setsid"); | |
| // Set CTTY | |
| if (ioctl(stty, TIOCSCTTY, 1) < 0) | |
| perror("TIOCCTTY"); | |
| return execl("/bin/bash", "bash", NULL); | |
| } | |
| printf("child=%d\n", child); | |
| // wait until child is ready | |
| sleep(1); | |
| // | |
| // do IO with mtty, which is now connected with stdio of child process | |
| // | |
| const char *cmd = "/bin/mkdir /tmp/HAHAHA\r\n"; | |
| char buf[1024]; | |
| rc = read(mtty, buf, 1024); | |
| printf("mtty-read: rc=%d\n", rc); | |
| printf("--- got from mtty ---\n"); | |
| write(1, buf, rc); | |
| printf("---\n"); | |
| write(mtty, cmd, strlen(cmd)); | |
| fsync(mtty); | |
| // wait for command to complete | |
| sleep(1); | |
| if (close(mtty) < 0) | |
| perror("close-mtty:"); | |
| wait(&rc); | |
| return rc; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment