主要函数
NAME
openpty, login_tty, forkpty - tty utility functions
SYNOPSIS
#include <pty.h>
int openpty(int *amaster, int *aslave, char *name,
struct termios *termp, struct winsize *winp);
pid_t forkpty(int *amaster, char *name, struct termios *termp,
struct winsize *winp);
#include <utmp.h>
int login_tty(int fd);
Link with -lutil.
DESCRIPTION
- The openpty() function finds an available pseudo-terminal and returns file descriptors for the master and slave in amaster and aslave. If name is not NULL, the filename of the slave is returned in name. If termp is not NULL, the terminal parameters of the slave will be set to the values in termp. If winp is not NULL, the window size of the slave will be set to the values in winp.
- The login_tty() function prepares for a login on the tty fd (which may be a real tty device, or the slave of a pseudo-terminal as returned by openpty()) by creating a new session, making fd the controlling terminal for the calling process, setting fd to be the standard input, output, and error streams of the current process, and closing fd.
- The forkpty() function combines openpty(), fork(2), and login_tty() to create a new process operating in a pseudo-terminal. The file descriptor of the master side of the pseudo-terminal is returned in amaster, and the filename of the slave in name if it is not NULL. The termp and winp arguments, if not NULL, will determine the terminal attributes and window size of the slave side of the pseudo-terminal.
RETURN VALUE
If a call to openpty(), login_tty(), or forkpty() is not successful, -1 is returned and errno is set to indicate the error. Otherwise, openpty(), login_tty(), and the child process of forkpty() return 0, and the parent process of forkpty() returns the process ID of the child process.
ERRORS
openpty() will fail if:
- ENOENT There are no available ttys.
- login_tty() will fail if ioctl(2) fails to set fd to the controlling terminal of the calling process.
- forkpty() will fail if either openpty() or fork(2) fails.
CONFORMING TO
These are BSD functions, present in libc5 and glibc2.
用例
通常的例子像下面一样
用例一
交互式
//
// Created by : Harris Zhu
// Filename : main.c
// Author : Harris Zhu
// Created On : 2017-11-26 18:06:44
// Last Modified : 2017-11-26 18:06:44
// Update Count : 1
// Tags :
// Description :
// Conclusion :
//
//=======================================================================
#define _XOPEN_SOURCE 600
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
# include <pty.h> /* for openpty and forkpty */
#include <termios.h>
int main(void)
{
int fdm, fds, rc;
char input[150];
char sptyname[20]={'\0'};
int rtn;
int i=0;
rtn = openpty(&fdm, &fds, sptyname, NULL, NULL);
printf("slave name is %s\n", sptyname);
if (rtn != -1)
{
if (fork())
{
// parent
close(fds);
while (i<50)
{
write(1, "Input : ", sizeof("Input : "));
rc = read(0, input, sizeof(input));
if (rc > 0)
{
// Write the input to the child process through PTY
write(fdm, input, rc);
// Read the child's answer through PTY
rc = read(fdm, input, sizeof(input) - 1);
if (rc > 0)
{
input[rc] = '\0';
printf("%s", input);
}
else
{
break;
}
}
} // end while
}
else
{
// Child
close(fdm);
struct termios slave_orig_term_settings; // Saved terminal settings
struct termios new_term_settings; // Current terminal settings
// Save the default parameters of the slave side of the PTY
rc = tcgetattr(fds, &slave_orig_term_settings);
// Set raw mode on the slave side of the PTY
new_term_settings = slave_orig_term_settings;
cfmakeraw (&new_term_settings);
tcsetattr (fds, TCSANOW, &new_term_settings);
// The slave side of the PTY becomes the standard input and outputs of the child process
close(0); // Close standard input (current terminal)
close(1); // Close standard output (current terminal)
close(2); // Close standard error (current terminal)
dup(fds); // PTY becomes standard input (0)
dup(fds); // PTY becomes standard output (1)
dup(fds); // PTY becomes standard error (2)
while (i++<50)
{
rc = read(fds, input, sizeof(input) - 1);
if (rc > 0)
{
input[rc - 1] = '\0';
printf("Child received : '%s'\n", input);
}
else
{
break;
}
} // End while
}
}
return 0;
}
gcc -o main main0.c -lutil
例子二
下面是非交互的例子
//
// Created by : Harris Zhu
// Filename : main.c
// Author : Harris Zhu
// Created On : 2017-11-26 18:06:44
// Last Modified : 2017-11-26 18:06:44
// Update Count : 1
// Tags :
// Description :
// Conclusion :
//
//=======================================================================
#define _XOPEN_SOURCE 600
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
# include <sys/types.h>
# include <linux/limits.h>
# include <pty.h> /* for openpty and forkpty */
#include <utmp.h> /* for login_tty */
#include <termios.h>
int main(void)
{
int fdm, fds, rc;
char sptyname[20]={'\0'};
char input[150];
int rtn;
int i=0;
rtn = openpty(&fdm, &fds, sptyname, NULL,NULL);
if(rtn != -1)
{
printf("slave name is %s\n", sptyname);
if (fork())
{
// Parents
close(fds);
while (i<50)
{
sprintf(input, "the time is %d\n", i++);
write(fdm, input, strlen(input));
rc = read(fdm, input, sizeof(input) - 1);
if (rc > 0)
{
input[rc] = '\0';
printf("%s", input);
}
else
{
break;
}
} // End while
}
else
{
// Child
close(fdm);
struct termios slave_orig_term_settings; // Saved terminal settings
struct termios new_term_settings; // Current terminal settings
// Save the default parameters of the slave side of the PTY
rc = tcgetattr(fds, &slave_orig_term_settings);
// Set raw mode on the slave side of the PTY
new_term_settings = slave_orig_term_settings;
cfmakeraw (&new_term_settings);
tcsetattr (fds, TCSANOW, &new_term_settings);
// The slave side of the PTY becomes the standard input and outputs of the child process
close(0); // Close standard input (current terminal)
close(1); // Close standard output (current terminal)
close(2); // Close standard error (current terminal)
dup(fds); // PTY becomes standard input (0)
dup(fds); // PTY becomes standard output (1)
dup(fds); // PTY becomes standard error (2)
int i=0;
while (i++<50)
{
rc = read(fds, input, sizeof(input) - 1);
if (rc > 0)
{
input[rc - 1] = '\0';
printf("Child received : '%s'\n", input);
}
else
{
break;
}
} // End while
}
}
return 0;
}
上面如果在child里不创建新的term属性,那么在parent进程里,每次write到mpty里的字符会被下一行的read读到,然后输出就会是重复的字符
On the slave side we can note the calls to cfmakeraw() and tcsetattr() to reconfigure the slave side of the pty. This sets the raw mode to disable the echoing among other things.
$ ./main
slave name is /dev/pts/1
the time is 0
Child received : 'the time is 0'
the time is 1
Child received : 'the time is 1'
the time is 2
Child received : 'the time is 2'
the time is 3
Child received : 'the time is 3'
the time is 4
Child received : 'the time is 4'
the time is 5
Child received : 'the time is 5'
the time is 6
Child received : 'the time is 6'
the time is 7
Child received : 'the time is 7'
the time is 8
奇怪的是把上面的cfmakeraw()和tcsetattr()改成login_tty(fds), 还是有回显问题。
用例三
读取另一个程序的输入输出
//
// Created by : Harris Zhu
// Filename : main0.c
// Author : Harris Zhu
// Created On : 2017-11-29 18:02:08
// Last Modified : 2017-11-29 18:02:08
// Update Count : 1
// Tags :
// Description :
// Conclusion :
//
//=======================================================================
#define _XOPEN_SOURCE 600
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <pty.h>
#include <utmp.h>
#include <termios.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <string.h>
int main(int ac, char *av[])
{
int fdm, fds;
int rc;
char input[150];
char fdsname[150];
// Check arguments
if (ac <= 1)
{
fprintf(stderr, "Usage: %s program_name [parameters]\n", av[0]);
exit(1);
}
if (openpty(&fdm, &fds, fdsname, NULL, NULL) == -1)
{
fprintf(stderr, "error open pty pairs\n");
exit(1);
} else {
printf("the slave is %s\n", fdsname);
}
// Create the child process
if (fork())
{
// FATHER
// Close the slave side of the PTY
close(fds);
fd_set fd_in;
while (1)
{
// Wait for data from standard input and master side of PTY
FD_ZERO(&fd_in);
FD_SET(0, &fd_in);
FD_SET(fdm, &fd_in);
rc = select(fdm + 1, &fd_in, NULL, NULL, NULL);
switch(rc)
{
case -1 :
{
fprintf(stderr, "Error %d on select()\n", errno);
exit(1);
}
default :
{
// If data on standard input
if (FD_ISSET(0, &fd_in))
{
rc = read(0, input, sizeof(input));
if (rc > 0)
{
// Send data on the master side of PTY
write(fdm, input, rc);
}
else
{
if (rc < 0)
{
fprintf(stderr, "Error %d on read standard input\n", errno);
exit(1);
}
}
}
// If data on master side of PTY
if (FD_ISSET(fdm, &fd_in))
{
rc = read(fdm, input, sizeof(input));
if (rc > 0)
{
// Send data on standard output
write(1, input, rc);
}
else
{
if (rc < 0)
{
fprintf(stderr, "Error %d on read master PTY\n", errno);
exit(1);
}
}
}
}
} // End switch
} // End while
}
else
{
// CHILD
// Close the master side of the PTY
close(fdm);
struct termios slave_orig_term_settings; // Saved terminal settings
struct termios new_term_settings; // Current terminal settings
// Save the defaults parameters of the slave side of the PTY
rc = tcgetattr(fds, &slave_orig_term_settings);
// Set RAW mode on slave side of PTY
new_term_settings = slave_orig_term_settings;
cfmakeraw (&new_term_settings);
tcsetattr (fds, TCSANOW, &new_term_settings);
// The slave side of the PTY becomes the standard input and outputs of the child process
close(0); // Close standard input (current terminal)
close(1); // Close standard output (current terminal)
close(2); // Close standard error (current terminal)
dup(fds); // PTY becomes standard input (0)
dup(fds); // PTY becomes standard output (1)
dup(fds); // PTY becomes standard error (2)
// Now the original file descriptor is useless
close(fds);
// Make the current process a new session leader
setsid();
// As the child is a session leader, set the controlling terminal to be the slave side of the PTY
// (Mandatory for programs like the shell to make them manage correctly their outputs)
// ioctl(0, TIOCSCTTY, 1);
ioctl(0, TIOCSCTTY, 1);
// Execution of the program
{
char **child_av;
int i;
// Build the command line
child_av = (char **)malloc(ac * sizeof(char *));
for (i = 1; i < ac; i ++)
{
child_av[i - 1] = strdup(av[i]);
}
child_av[i - 1] = NULL;
rc = execvp(child_av[0], child_av);
}
// if Error...
return 1;
}
return 0;
}
运行结果如下:
$ ./main bc
the slave is /dev/pts/1
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
1+2
3
4*5
20
quit
Error 5 on read master PTY
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。