历史沿袭至今,在大多数UNIX系统中,控制终端的名字是/dev/tty. POSIX.1提供了一个运行时函数,可被用来确定控制终端的名字。

#include <stdio.h>

char *ctermid(char *ptr);

返回值:若成功则返回指向控制终端名的指针,若出错则返回指向空字符串的指针

如果ptr非空,则它被认为是一个指针,指向长度至少为L_ctermid字节的数组,进程的控制终端名存放在该数组中。常量L_ctermid定义在<stdio.h>中。若ptr是一个空指针,则该函数为数组(通常作为静态变量)分配空间。同样,进程的控制终端名存放在该数组中。

在这两种情况中,该数组的起始地址被作为函数值返回。因为大多数UNIX系统都使用/dev/tty作为控制终端名,所以此函数的主要作用是帮助提高向其他操作系统的可移植性。

 

实例:ctermid函数

程序清单18-3 POSIX.1 ctermid函数的实现

#include <stdio.h>

#include <string.h>

 

static char ctermid_name[L_ctermid];

 

char *

ctermid(char *str)

{

    if(str == NULL)

        str = ctermid_name;

    return(strcpy(str, "/dev/tty"));    /* strcpy() returns str */

}

 

注意,因为我们无法确定调用者缓冲区的大小,所以也就不能防止过度使用该缓冲区。

 

另外两个与终端标识有关的函数是isatty和ttyname。前者在文件描述符引用一个终端设备时返回真,而后者则返回在该文件描述符上打开的终端设备的路径名。

#include <unisd.h>

int isatty(int filedes);

返回值:若为终端设备则返回1(真),反则返回0(假)

 

char *ttyname(int filedes);

返回值:指向终端路径名的指针,若出错则返回NULL

 

实例:isatty函数

程序清单18-4 POSIX.1 isatty函数的实现

#include <termios.h>

 

int

isatty(int fd)

{

    struct termios    ts;

    

    return(tcgetattr(fd, &ts) != -1);    /* true if no error (is a tty) */

}

 

程序清单18-5测试isatty函数

#include "apue.h"

 

int

main(void)

{

    printf("fd 0: %s\n", isatty(0) ? "tty" : "not a tty");

    printf("fd 1: %s\n", isatty(1) ? "tty" : "not a tty");

    printf("fd 2: %s\n", isatty(2) ? "tty" : "not a tty");

    exit(0);

}

 

运行程序清单18-5中的程序时,我们可以得到下面的结果:

 

实例:ttyname函数

程序清单18-6 POSIX.1 ttyname函数的实现

#include <sys/stat.h>

#include <dirent.h>

#include <limits.h>

#include <string.h>

#include <termios.h>

#include <unistd.h>

#include <stdlib.h>

 

struct devdir {

    struct devdir    *d_next;

    char        *d_name;

};

 

static struct devdir    *head;

static struct devdir    *tail;

static char        pathname[_POSIX_PATH_MAX + 1];

 

static void

add(char *dirname)

{

    struct devdir    *ddp;

    int        len;

    

    len = strlen(dirname);

    /*    

    * Skip ., .., and /dev/fd.

    */

    if((dirname[len - 1] == '.') && (dirname[len - 2] == '/' ||

        (dirname[len - 2] == '.' && dirname[len-3] == '/')))

        return;

    if(strcmp(dirname, "dev/fd") == 0)

        return;

    ddp = malloc(sizeof(struct devdir));

    if(ddp == NULL)

        return;

    

    ddp->d_name = strdup(dirname);

    if(ddp->d_name == NULL)

    {

        free(ddp);

        return;

    }

    ddp->d_next = NULL;

    if(tail == NULL)

    {

        head = ddp;

        tail = ddp;

    }

    else

    {

        tail->d_next = ddp;

        tail = ddp;

    }

}

 

static void

cleanup(void)

{

    struct devdir    *ddp, *nddp;

    

    ddp = head;

    while(ddp != NULL)

    {

        nddp = ddp->d_next;

        free(ddp->d_name);

        free(ddp);

        ddp = nddp;

    }

    head = NULL;

    tail = NULL;

}

 

static char *

searchdir(char *dirname, struct stat *fdstatp)

{

    struct stat    devstat;

    DIR        *dp;

    int        devlen;

    struct dirent    *dirp;

    

    strcpy(pathname, dirname);

    if((dp = opendir(dirname)) == NULL)

        return(NULL);

    strcat(pathname, "/");

    devlen = strlen(pathname);

    while((dirp = readdir(dp)) != NULL)

    {

        strncpy(pathname + devlen, dirp->d_name,

            _POSIX_PATH_MAX - devlen);

        /*

        * Skip aliases.

        */

        if(strcmp(pathname, "/dev/stdin") == 0 ||

            strcmp(pathname, "/dev/stdout") == 0 ||

            strcmp(pathname, "/dev/stderr") == 0)

            continue;

        if(stat(pathname, &devstat) < 0)

            continue;

        if(S_ISDIR(devstat.st_mode))

        {

            add(pathname);

            continue;

        }

        if(devstat.st_ino == fdstatp->st_ino &&

            devstat.st_dev == fdstatp->st_dev)    /* found a match */

        {

            closedir(dp);

            return(pathname);

        }

    }

    closedir(dp);

    return(NULL);

}

 

char *

ttyname(int fd)

{

    struct stat    fdstat;

    struct devdir    *ddp;

    char        *rval;

    

    if(isatty(fd) == 0)

        return(NULL);

    if(fstat(fd, &fdstat) < 0)

        return(NULL);

    if(S_ISCHR(fdstat.st_mode) == 0)

        return(NULL);

 

    rval = searchdir("/dev", &fdstat);

    if(rval == NULL)

    {

        for(ddp = head; ddp != NULL; ddp = ddp->d_next)

            if((rval = searchdir(ddp->d_name, &fdstat)) != NULL)

                break;

    }

    

    cleanup();

    return(rval);

}

此处用到的方法是读/dev目录,寻找具有相同设备号和i节点编号的表项。每个文件系统有一个唯一的设备号(stat结构中的st_dev字段http://www.cnblogs.com/nufangrensheng/p/3501385.html),文件系统中的每个目录项有一个唯一的i节点号(stat结构中的st_ino字段)。在此函数中假定当找到一个匹配的设备号和匹配的i节点号时,就找到了所希望的目录项。

我们的终端名可能在/dev的子目录中。于是,需要搜索在/dev之下的整个文件系统子树。我们跳过了很多产生不正确或奇怪结果的目录,它们是/dev/.,/dev/..和/dev/fd。我么也跳过了一些别名,即/dev/stdin、/dev/stdout以及/dev/stderr,它们是对在/dev/fd目录中文件的符号链接。

 

程序清单18-7 测试ttyname函数

#include "apue.h"

 

int

main(void)

{

    char *name;

 

    if(isatty(0))

    {

        name = ttyname(0);

        if(name == NULL)

            name = "undefined";

    }

    else

    {

        name = "not a tty";

    }

    printf("fd 0: %s\n", name);

 

    if(isatty(1))

    {

        name = ttyname(1);

        if(name == NULL)

            name = "undefined";

    }

    else

    {

        name = "not a tty";

    }

    printf("fd 1: %s\n", name);

 

    if(isatty(2))

    {

        name = ttyname(2);

        if(name == NULL)

            name = "undefined";

    }

    else

    {

        name = "not a tty";

    }

    printf("fd 2: %s\n", name);

    

    exit(0);

}

 

运行该程序得到:

文件描述符0、1和2都指向了同一终端/dev/tty1.

终端I/O之终端标识的更多相关文章

  1. CentOS桌面环境如何打开终端以及如何将终端加入右键

    安装完CentOS的桌面环境后,默认在桌面以及右键是没有打开终端选项的,要想打开终端,可以由以下步骤: 在左上角菜单[Applications]--->[System Tools]---> ...

  2. linux tty终端个 pts伪终端 telnetd伪终端

    转:http://blog.sina.com.cn/s/blog_735da7ae0102v2p7.html 终端tty.虚拟控制台.FrameBuffer的切换过程详解 Framebuffer Dr ...

  3. mac使用终端运行mysql,mysql终端,mysql mac,mysql目录,mysql路径

    首先去官网下载: http://www.mysql.com/downloads/ 我下载了5.6.11的dmg然后安装,安装完成之后..如果要用终端去玩SQL.那么一开始要输入很长的:/usr/loc ...

  4. 终端I/O之终端窗口的大小

    大多数UNIX系统都提供了一种功能,可以对当前终端窗口的大小进行跟踪,在窗口大小发生变化时,使内核通知前台进程组.内核为每个终端和伪终端保存一个winsize结构: Struct winsize { ...

  5. Linux6.X图形界面如何打开终端以及如何将终端加入右键

    今天刚安装了一个centos 6.9图形界面的系统,安装完成后,鼠标右击没有打开终端的按钮,在网上查了一些资料,搞明白了,分享给大家. 在左上角菜单[Applications]--->[Syst ...

  6. [Linux]在终端启动程序关闭终端不退出的方法

    一般情况下关闭终端时,那么在这个终端中启动的后台程序也会终止,要使终端关闭后,后台程序保持执行,使用这个指令: nohup 命令 & 如:nohup test.sh & 回车,然后提示 ...

  7. Linux在终端启动程序关闭终端不退出的方法

    一般情况下关闭终端时,那么在这个终端中启动的后台程序也会终止,要使终端关闭后,后台程序保持执行,使用这个指令: nohup 命令 & 如:nohup ./studio.sh & 网上其 ...

  8. 终端I/O之终端选项标志

    http://www.cnblogs.com/nufangrensheng/p/3575752.html 中的表18-1至表18-4中列出的所有选项标志(除屏蔽标志外)都用一位或几位(设置或清除)表示 ...

  9. tcgetattr函数与tcsetattr函数控制终端

    6.4.4  使用tcgetattr函数与tcsetattr函数控制终端 为了便于通过程序来获得和修改终端参数,Linux还提供了tcgetattr函数和tcsetattr函数.tcgetattr用于 ...

随机推荐

  1. int型长度

    Ø  基本数据类型 C语言中只有4中基本数据类型——整型.浮点型.指针和聚合类型(如数组和结构等):所有其他类型都是从这4种基本类型的某种变化或组合派生而来. 一.整型家族 整型家族包括char.sh ...

  2. x-debug配置简述 - chunyu

    一 x-debug 是什么?在配置之前,先解决一个问题,x-debug 是什么?我也不查标准答案了,就说说个人理解.x-debug是一个PHP调试工具,帮助开发者在IDE里面进行代码的断点调试,效果如 ...

  3. Python基础 条件、循环

    1.条件语句 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. if if语句执行有个特点,它是从上往下判断,如果在某个判断上是True,把该判断对应的 ...

  4. 在VSTO界面中,调用xll中的函数

    最近研究各种有点迷茫了,原来Xll的加载宏直接可以在C#中调用的,我又各种Out了. 先说明一下,在VBA中,如何调用吧 XLLFound = Application.RegisterXLL(This ...

  5. Spring REST实践之客户端和测试

    RestTemplate 可参考spring实战来写这部分. RestTemplate免于编写乏味的样板代码,RestTemplate定义了33个与REST资源交互的方法,涵盖了HTTP动作的各种形式 ...

  6. DIV 布局 左中右

    <style type="text/css">body{ margin:0; padding:0;}.Header{ height:100px; background: ...

  7. 网络虚拟化技术 TUN/TAP MACVLAN MACVTAP

    TUN 设备 TUN 设备是一种虚拟网络设备,通过此设备,程序可以方便得模拟网络行为.先来看看物理设备是如何工作的:

  8. gif动态图片去白边,杂边

    (从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期2014-05-30)

  9. HTML第八天笔记

    第一个知识点是关于伪类的,代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " ...

  10. JS瀑布流布局模式(2)

    这个例子与上一篇类似,唯一的区别是排序的方式有差别.上一篇是在高度最小的列里插入内容,这个案例是按顺序放置内容. 两种方法各有优缺点.第一种需要在图片内容加载完成的情况下有效,各个列的图高度差异不大. ...