2013-03-20 42 views
1

我正在使用僞終端庫。代碼以C代碼實現,代碼由基於Web的終端使用。只要我不使用sudo或登錄,代碼就可以工作。僞終端問題(Mac/Linux):SIGTTOU&不適當的ioctl

這是我的錯誤,當我運行在Mac上的服務器:

sh-3.2$ sudo ls 
Password: 
[1]+ Stopped(SIGTTOU) 
sh-3.2$ 

在Linux上面的作品:

$ sudo ls 
    readme.txt 

不過,我得到了在Linux上使用sudo慶典以下:

$ sudo bash 
bash: cannot set terminal process group (-1): Inappropriate ioctl for device 
bash: no job control in this shell 
]0;[email protected]: /[email protected]:/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; 
} 

我編輯了下面的代碼,並且此代碼有效。我的第一個版本不起作用的原因是我試圖創建兩個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)); 
} 

回答

0

很難確定,因爲這裏沒有顯示實際代碼,但我懷疑您正在運行POSIX風格的「會話」管理。您需要執行呼叫setsid,然後打開pty(從站側),使其成爲控制終端。例程openptylogin_tty爲您做低級別的垃圾工作;你在使用這些嗎?

+0

感謝torek,但我有setsid。我已經包含了上面的代碼。 – Will 2013-03-20 20:40:58

+0

啊。嘗試不使用'O_NOCTTY'標誌:這是禁止將新打開的設備設置爲控制終端的標誌。你會認爲這樣可以,因爲'TIOCSCTTY',但是這個ioctl可能現在在OS X上是沒有操作的(我不確定)。 – torek 2013-03-20 21:02:10

+0

各種UNIX發行版並不完全相同,因此在所有UNIX版本中應該兼容的首選方法是使用O_NOCTTY打開PTY,然後設置TIOCSCTTY,因爲ioctl(fd,TIOCSCTTY,NULL)調用在所有版本中都是兼容的。另一種選擇是忽略由ioctl(fd,TIOCSCTTY,NULL)返回的錯誤。 順便說一句,我發現了這個問題,我修改了上面的例子。 – Will 2013-03-27 18:27:45