HOME | Links | About | Read

《Unix/Linux编程实践教程》笔记(4)──连接控制stty

Table of Contents

内容

设备和文件有相似之处也有不同之处,文中介绍了磁盘连接和终端连接的属性,磁盘连接具有缓冲,自动添加模式的属性,通过fcntl函数可以通过文件描述符来控制驱动器。自动添加模式,对每个write都自动调用lseek将内容添加到文件的末尾,内核将这两个操作合成一个原子操作。

终端文件的属性可以查看stty的man手册。相关的系统调用如下:

控制文件描述符 fcntl
读取tty驱动程序的属性 tcgetattr
设置tty驱动程序的属性 tcsetattr
控制一个设备 ioctl

p141 有termios结构每个标志集的独立位的含义

习题

5.22 使write能处理用户不在线和用户登录多个终端的情况

修改了write1,从utmp文件中读取在线用户列表,如果用户不在线,就不发送消息并且提示。如果用户登录多个终端,向每个终端发送消息。代码如下:

#include	<stdio.h>
#include	<fcntl.h>
#include	<utmp.h>

/*
 * write2.c
 *
 *	purpose: send messages to another terminal
 *	 method: open the other terminal for output then
 *	 	 copy from stdin to that terminal
 *        usage: write1 username
 */

main( int ac, char *av[] )
{
	int	fd, utfd;
	char	buf[BUFSIZ];
	char	*get_tty(), *tty_for_user;
	int flag = 0;

	/* check args */
	if ( ac != 2 ){
		fprintf(stderr,"usage: write0 logname\n");
		exit(1);
	}

	if ( (utfd = open( UTMP_FILE, O_RDONLY )) == -1 )
		return NULL;
	/* find user */
	while ((tty_for_user = get_tty( utfd, av[1] )) != NULL )
	{
		flag ++;
		printf ("tty_for_user is %s\n", tty_for_user);
		/* open device */
		sprintf(buf, "/dev/%s", tty_for_user);
		fd = open( buf, O_WRONLY );
		if ( fd == -1 ){
			perror(buf); exit(1);
		}

		/* loop until EOF on input */
		while( fgets(buf, BUFSIZ, stdin) != NULL )
			if ( write(fd, buf, strlen(buf)) == -1 )
				break;
		close( fd );
	}
	if ( flag == 0 )
		printf ("%s is not on or %s is not existed\n", av[1], av[1]);
	close(utfd);
}

char *
get_tty( int utfd, char *logname )
/*
 * purpose: find the tty at which 'logname' is logged in
 * returns: a string or NULL if not logged in
 *  errors: does not handle multiple logins 
 */
{
	static struct utmp utrec;
	int		namelen = sizeof( utrec.ut_name );
	char	*retval = NULL ;

	/* look for a line where the user is logged in */
	while( read( utfd, &utrec, sizeof(utrec)) == sizeof(utrec) )
		if ( strncmp(logname, utrec.ut_name, namelen ) == 0 )
		{
			retval = utrec.ut_line ;
			break;
		}

	/* close file and return result */
	return retval;
}

5.23 实现mesg命令

通过使用mesg命令,发现mesg通过接收n,y参数,来置位终端文件的w权限。代码如下:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>

int main (int ac, char *av[])
{
	struct stat sb;
	int nmask = 0777755;
	int ymask = 0000020;
	char *ttydevice = ttyname(0);
	
	if (ac != 2)
	{
		printf ("useage: mesg [n|y] \n");
		exit(-1);
	}

	if (stat(ttydevice, &sb))
	{
		printf ("stat:\n");
		exit(-1);
	}

	if (av[1][0] == 'n')
		chmod(ttyname(0), (sb.st_mode & nmask));
	else if (av[1][0] == 'y')
		chmod(ttyname(0), (sb.st_mode | ymask));
	else
		printf ("av[1] must be [n|y] \n");

	return 0;
}

5.25 通过文件修改时间检查锁是否有效

接收表示秒数的参数,比较当前时间和锁的更新时间,检查锁是否有效,如果无效,删除锁并重新创建

int lock_passwd(int dif)
{
	struct stat infobuf;
	time_t time1;


	int rv = 0;
	if ( link("test.txt", "test.txt.LCK") == -1)
		rv = (errno == EEXIST?1:2);
	if (rv == 1)
	{
		if (stat("test.txt.LCK", &infobuf) == -1)
			perror("test.txt");
		time1 = infobuf.st_mtime;

		if (( time(NULL) - time1) > dif )
		{
			printf ("remove the old LCK and create the new LCK\n");
			if (remove("test.txt.LCK") == -1)
				perror("test.txt.LCK");
			if ( link("test.txt", "test.txt.LCK") == -1)
				rv = (errno == EEXIST?1:2);
		}
		

	}

	return rv;
}

5.28 查看olcuc位的状态

不太清楚题目的中的跟踪OLCUC位的状态 是什么意思。下面的程序仅仅是显示当前终端中OLCUC位的状态

struct termios attribs;
	tcgetattr (0, &attribs);
	if (attribs.c_oflag & OLCUC)
		printf ("OLCUC is on\n");
	else
		printf ("OLCUC is off\n");

项目

结束

这章的重点是终端驱动器的控制,tcgetattr和tcsetattr可以设置相应的位来控制终端。