Linux用户态编程-伪终端(一)

时间:2022-03-01 15:19:56

最近在看telnet终端登陆的相关程序,了解到了telnet登陆的进程安排。对照UNIX环境高级编程对其中使用伪终端的部分进行了一些学习。


首先,telnet登陆的典型安排如下:

Linux用户态编程-伪终端(一)


1.telnet client通过connect连接telnet server

2.telnet server 调用accept接受连接请求,并fork子进程1处理与client之间的连接。同时打开伪终端主设备

3.子进程1再fork子进程调用login,同时打开伪终端从设备

4.login处理完验证等处理后,exec登陆shell

5.登陆shell利用伪终端从设备和子进程1之间进行通信



下面是打开伪终端的代码:

ptym_open用于打开伪终端主设备,并通过参数输出对应的伪终端从设备名称

ptys_open用伪终端从设备名打开从设备

grantpt用于更改从设备的节点的权限为用户读写,组写。

unlockpt函数用于准予对伪终端从设备的访问,从而允许应用程序打开该设备。阻止其他进程打开从设备后,建立该设备的应用程序有机会在使用主,从设备之间正确地初始化

这些设备。


有一些用编译宏控制打开的函数,这些函数在Linux系统上一般是存在的,如果对应的系统上支持这些函数,可以通过编译宏将这些函数关闭。如果对应的系统上不存在,可以

用编译宏打开这些函数,同时可以了解这些函数的实现机制。

#include "apue.h"
#include <fcntl.h>

#ifndef _HAS_OPENPT
INT posix_openpt(INT iFlag)
{
    INT iFdMaster;

    iFdMaster = open("/dev/ptmx",iFlag);
    return iFdMaster;
}
#endif

#ifndef _HAS_PTSNAME
CHAR *ptsname(int iFd)
{
    int iSlave;
    STATIC CHAR szPtsName[16];

    if(ioctl(iFd,TIOCGPTN,&iSlave) < 0)
    {
        return NULL;
    }

    szPtsName[0] = 0;
    snprintf(szPtsName,sizeof(szPtsName),"/dev/pts/%d",iSlave);
    return szPtsName;
}
#endif

#ifndef _HAS_GRANTPT
INT grantpt(int iMaster)
{
    CHAR *pcPtsName;

    pcPtsName = ptsname(iMaster);
    return (chmod(pcPtsName,S_IRUSR|S_IWUSR|S_IWGRP);
}
#endif

#ifndef _HAS_UNLOCKPT
INT unlockpt(int iMaster)
{
    INT iLock = 0;

    return (ioctl(iMaster,TIOCSPTLCK,&iLock));
}
#endif


INT ptym_open(CHAR *pcPtsName,INT iNameLen)
{
    CHAR *pcName;
    INT iMaster;

    strncpy(pcPtsName,"/dev/ptmx",iNameLen);
    pcPtsName[iNameLen - 1] = 0;

    iMaster = posix_openpt(O_RDWR);
    if(iMaster < 0)
    {
        return -1;
    }

    if(grantpt(iMaster) < 0)
    {
        close(iMaster);
        return -2;
    }

    if(unlockpt(iMaster) < 0)
    {
        close(iMaster);
        return -3;
    }

    if((pcName = ptsname(iMaster)) == NULL)
    {
        close(iMaster);
        return -4;
    }

    strncpy(pcPtsName,pcName,iNameLen);
    pcPtsName[iNameLen - 1] = 0;
    return iMaster;
}

INT ptys_open(const CHAR *pcName)
{
    int iSlave;
    if((iSlave = open(pcName,O_RDWR))<0)
    {
        return -5;
    }

    return iSlave;
}

INT main()
{
    CHAR szPtsName[16];
    INT iMaster,iSlave;
    iMaster = ptym_open(szPtsName,sizeof(szPtsName));

    if(iMaster < 0)
    {
        printf("ptym_open err [%d]\n",iMaster);
        return iMaster;
    }

    printf("ptym_open success %s\n",szPtsName);
    iSlave = ptys_open(szPtsName);
    if(iSlave < 0)
    {
        printf("ptys_open err [%d]\n",iSlave);
        return iSlave;
    }

    sleep(10);

    close(iMaster);
    close(iSlave);
    return 0;
}