私は疑似端末ライブラリに取り組んでいます。コードは C コードで実装され、コードは Web ベースの端末で使用されます。sudo またはログインを使用しない限り、コードは機能します。
これは、Mac でサーバーを実行したときに発生するエラーです。
sh-3.2$ sudo ls
Password:
[1]+ Stopped(SIGTTOU)
sh-3.2$
上記は Linux で動作します。
$ sudo ls
readme.txt
ただし、sudo bash を使用すると、Linux で次のようになります。
$ sudo bash
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
]0;root@ubuntu: /tmproot@ubuntu:/tmp#
注: 上記は機能しますが、ジョブ コントロールはありません。
おそらく端末にいくつかの制御ビットを設定するのを忘れたのでしょうが、Google はこれを見つけるのにあまり役に立ちませんでした。また、疑似端末の管理を詳細に説明している良い本をご存知ですか。
setsid 呼び出しがありますが、openpty を使用していません。pty を開くときは、次のコードを使用します。
static int createPty(lua_State* L, char* ttyName, int* pty)
{
*pty = getpt();
if (*pty < 0 || grantpt(*pty) < 0 || unlockpt(*pty) < 0)
return lDoErr(L,"Cannot open PTY: %s",strerror(errno));
if(ptsname_r(*pty, ttyName, PTY_NAME_SIZE-1))
return lDoErr(L,"ptsname_r: %s",strerror(errno));
return 0;
}
以下のコードを編集しましたが、このコードは機能します。最初のバージョンが機能しなかった理由は、2 つの PTY チャネルを作成しようとしたためです。stdout と stderr を区別できるようにしたかったのですが、Linux カーネルでは複数の TIOCSCTTY 呼び出しが許可されていません。
static int
childOpenTTY(const char* ttyName)
{
struct termios termbuf;
int fd=open(ttyName, O_RDWR);
if(fd < 0)
doClientError("open %s: %s",ttyName, strerror(errno));
tcsetpgrp(fd, getpid());
ioctl(fd,TIOCSCTTY,NULL);
tcgetattr(fd, &termbuf);
cfmakeraw(&termbuf); /* turn off NL to CR/NL mapping on output. */
tcsetattr(fd, TCSANOW, &termbuf);
return fd;
}
if( (ret = createPty(L, ttyName, &te->pty)) != 0)
return ret;
if ((te->pid = zzbafork()) < 0)
return lDoErr(L,"fork: %s",strerror(errno));
if(te->pid == 0)
{ /* Child process */
static const char efmt[]={"Cannot set '%s' (dup2 err)"};
int fd;
if(setsid() < 0) /* make new process group */
doClientError("setsid: %s",strerror(errno));
fd=childOpenTTY(ttyName);
if(dup2(fd, STDIN_FILENO) != STDIN_FILENO)
doClientError(efmt,"stdin");
if(dup2(fd, STDOUT_FILENO) != STDOUT_FILENO)
doClientError(efmt,"stdout");
if(dup2(fd, STDERR_FILENO) != STDERR_FILENO)
doClientError(efmt,"stderr");
if(fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
close(fd);
execve(cmd, (char**)cmdArgv, environ);
/* execve should not return, unless error exec cmd */
doClientError("Executing %s failed: %s",cmd,strerror(errno));
}