Skip to content

Instantly share code, notes, and snippets.

@tai
Created March 12, 2015 12:52
Show Gist options
  • Select an option

  • Save tai/5d6ce0c28c6b39a9c9df to your computer and use it in GitHub Desktop.

Select an option

Save tai/5d6ce0c28c6b39a9c9df to your computer and use it in GitHub Desktop.
Ad-hoc expect
/*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