Linux - GeneralThis Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I am looking to use some pseudo terminals for a small project. I did some reading, looked through the forum posts here and in other places and found information on creating them.
So to start out I wrote a simple program in C to test them out and see how they worked. As things usually seem to go it didn't work. This is either because I have misunderstood something about pseudo terminals or they just plain don't work.
My distro is RHEL4, the code snippet is below:
int main(int argc, char *argv[])
{
int rtnVal=0;
int mpty, spty, c=0, dev=0;
char *pName=NULL;
char ptyBuff[100];
rtnVal = openpty(&mpty, &spty, NULL, NULL, NULL);
// Check if Pseudo-Term pair was created
if(rtnVal != -1)
{
pName = ptsname(mpty);
printf("Name of slave side is <%s>\n", pName);
// Go into loop and read what is sent to Slave side of pair
while(1)
{
c = read(spty, ptyBuff, 100);
In general calling openpty() creates the pseudo-terminal pair, a "master"(mpty) side and a "slave"(spty) side. Since spty is supposed to look like a normal tty I should be able to do reads & writes.
What I did when I ran this code was attempt to send something to the slave side at its device name, /dev/pts/2 in my case. Then from another terminal window using the command "echo 'x' > /dev/pts/2" I hoped on sending spty some data to read to verify the slave side was reading correctly.
When I do this I see nothing printed. So either I have missed setting something up or it doesn't work the way I think.
Any suggestions would be appreciated.
Ultimately my small application needs to fit in between an existing application and the serial port on the box so I can modify the serial data between the app and the device connected.
Thanks for the reply, I guess I sort of knew that but my code was brain dead.
I have made the following change:
// Go into loop and read what is sent to Master side of pair
while(1)
{
c = read(mpty, ptyBuff, 100);
if(c > 0)
{
printf("###-<%d>\n", c);
}
}
I wasn't reading the master, so now when I type "echo 'x' > /dev/pts/2" from a second terminal session to send to the slave, I see the data displayed on the master read().
So far, so good.....
I further modified the code to also try reading the slave side of the pseudo term in the while loop after the master is read.
I then tried sending data (from a 2nd terminal session) to the master using the same command "echo 'x' > /dev/ptmx" but that didn't work.
How does one write to the master?
If I create a 2nd program to do this (instead of the echo) can it access the master like it was a TTY? I get the impression from what I've read that only the slave side acts like a normal TTY not the master unfortunately nothing further is said about how the master is accessed.
Perhaps we are now in the area where some articles talk about the slave and master being in 2 different processes?
well normally you'd open the master/slave pair and then fork your other process, you'll have the file descriptors of both the master and slave so its easy to write/read either. You can then set the slave to be the stdin/stdout/stderr of the child process by using login_tty (or use forkpty and combine all those steps). Then you if you want you can exec a new program and it'll keep that slave tty as its stdin/stdout/stderr. I believe it also sets the slave tty as the controlling terminal for the process.
I'm a bit farther along, used threads and was able to send/recv data between master/slave PTY (writing master shows up in slave read and vice-versa).
Now I'm attempting to fake an application to use the Slave PTY as if it was a regular TTY.
What I am doing now is running my first application (call it pseudo-app) which creates the pseudo terminal and then creates 2 threads, one to read/write master PTY and the other to monitor the slave PTY.
I wrote a 2nd application (call it user-app) to connect to the device name of the Slave PTY and try writing to it. What I expected was data written by the user-app to the Slave PTY to appear at the Master PTY read() in pseudo-app, this didn't happen.
When developers use pseudo-terminals and want to have the Slave PTY accessed by some code as a normal TTY how is it done?
Is the Slave opened by the code that needs to use it (slave created in the user-app)?
Can the Slave PTY get created in a separate process or thread and be used by a user-app running in another process or thread?
I am also having need to create similar application using PTY. I am still not able to write to PTY Master and read it from PTY Slav.
as U have mentioned below. Can you give more information that how can I achieve it ?
Thanks.
Regards,
_-_Mayank Rana_-_
Quote:
Originally Posted by bytehunter
Estabroo,
I'm a bit farther along, used threads and was able to send/recv data between master/slave PTY (writing master shows up in slave read and vice-versa).
Now I'm attempting to fake an application to use the Slave PTY as if it was a regular TTY.
What I am doing now is running my first application (call it pseudo-app) which creates the pseudo terminal and then creates 2 threads, one to read/write master PTY and the other to monitor the slave PTY.
I wrote a 2nd application (call it user-app) to connect to the device name of the Slave PTY and try writing to it. What I expected was data written by the user-app to the Slave PTY to appear at the Master PTY read() in pseudo-app, this didn't happen.
When developers use pseudo-terminals and want to have the Slave PTY accessed by some code as a normal TTY how is it done?
Is the Slave opened by the code that needs to use it (slave created in the user-app)?
Can the Slave PTY get created in a separate process or thread and be used by a user-app running in another process or thread?
I was able to get this going w/o much trouble, the code snippets below should get you rolling:
int rc=0;
int serialDev=0;
string deviceName = "/dev/ptmx"; //Unix98 form of Master device name
char *pSptyName=NULL;
// Creating the MasterPTY, Open the device
serialDev = open(deviceName.c_str(), O_RDWR|O_NOCTTY);
// Change permission of Slave PTY
rc = grantpt(serialDev);
// Unlock Slave PTY so others can use it
rc = unlockpt(serialDev);
// Get the Slave side device name of Pseudo-Term
pSptyName = ptsname(serialDev));
Setting up the pseudo-term is now complete, to talk to the SlavePTY side you would have code call:
newDevice = open(pSptyName, O_RDWR|O_NOCTTY);
If successful you should be able to read & write to/from this pseudo-term as if it was a ttySx type connection. You will have other code to monitor the Master side to read & write from it.
In my case I have created the pseudo-term and stuck it in between an application that was setup to read/write to ttyS0 via a symlink (sterm->/dev/ttyS0). I created the pseudo term, get the slavepty name and substitute that in the symlink (sterm->/dev/pts/x) so the application doesn't know the difference. Then on the Master side I have code to communicate with the actual terminal, ttyS0. The purpose for me was to capture the data between the app and the "real" serial port and do some "massaging". My distro was RHEL3.
Note at the top my deviceName of "/dev/ptmx", this is the Unix98 form, there is an earlier form (called BSDPty I think) but I'm assuming that 98 means 1998 and any Linux distros built after that date are using the form above, I could be wrong as I am not an expert.
I tried with PTY and I was able to transfer data successfully. But As I came to know that PTY doesn't support IOCTL related to Serial Port. How to handle those IOCTL call if application wants to do that ? If you have any information, let me know that.
Thanks.
Regards,
_-_Mayank Rana_-_
Quote:
Originally Posted by bytehunter
Mayank,
I was able to get this going w/o much trouble, the code snippets below should get you rolling:
int rc=0;
int serialDev=0;
string deviceName = "/dev/ptmx"; //Unix98 form of Master device name
char *pSptyName=NULL;
// Creating the MasterPTY, Open the device
serialDev = open(deviceName.c_str(), O_RDWR|O_NOCTTY);
// Change permission of Slave PTY
rc = grantpt(serialDev);
// Unlock Slave PTY so others can use it
rc = unlockpt(serialDev);
// Get the Slave side device name of Pseudo-Term
pSptyName = ptsname(serialDev));
Setting up the pseudo-term is now complete, to talk to the SlavePTY side you would have code call:
newDevice = open(pSptyName, O_RDWR|O_NOCTTY);
If successful you should be able to read & write to/from this pseudo-term as if it was a ttySx type connection. You will have other code to monitor the Master side to read & write from it.
In my case I have created the pseudo-term and stuck it in between an application that was setup to read/write to ttyS0 via a symlink (sterm->/dev/ttyS0). I created the pseudo term, get the slavepty name and substitute that in the symlink (sterm->/dev/pts/x) so the application doesn't know the difference. Then on the Master side I have code to communicate with the actual terminal, ttyS0. The purpose for me was to capture the data between the app and the "real" serial port and do some "massaging". My distro was RHEL3.
Note at the top my deviceName of "/dev/ptmx", this is the Unix98 form, there is an earlier form (called BSDPty I think) but I'm assuming that 98 means 1998 and any Linux distros built after that date are using the form above, I could be wrong as I am not an expert.
I was able to set the pseudo terms using the tc* series of function calls, below is an initialization of my pty:
====================================================
int rc=0;
struct termios params;
// Get terminal atributes
rc = tcgetattr(serialDev, ¶ms);
// Modify terminal attributes
cfmakeraw(¶ms);
rc = cfsetispeed(¶ms, B9600);
rc = cfsetospeed(¶ms, B9600);
// CREAD - Enable port to read data
// CLOCAL - Ignore modem control lines
params.c_cflag |= (CLOCAL|CREAD);
// Make Read Blocking
fcntl(serialDev, F_SETFL, 0);
// Set serial attributes
rc = tcsetattr(serialDev, TCSANOW, ¶ms);
// Flush serial device of both non-transmitted
// output data and non-read input data....
tcflush(serialDev, TCIOFLUSH);
===================================================
I have not included error checking so be sure to do that for the various calls.
I am facinf some problems to write to the master pty. Can some one of you please help me to resolve the problem.
I have written two programs,
Master.cpp & Slave.cpp
In Master.cpp,
I am opening the master pty using posix_openpt(O_RDWR|O_NOCTTY);
In Slave.cpp i am writing into the slave device whose name i got from the Master.cpp
In Master.cpp i am reading the master device to get the data written by slave.cpp. The read call is under a select call(which waits till data appears to read).
After reading data from master in Master.cpp i have to communicate some messages to slave. So soon after reading data i am writing to the master once again. I am waiting in Slave.cpp to catch the data sent by master.cpp.
I am able to read data sent from slave.cpp im Master.cpp. but, i am not able to write data into the Master.
I am attaching the code for master.cpp and slave.cpp below.
Please have a look at them and correct me where i am goin g wrong.
const char *name=ptsname(masterpt);
int slavept=open(name, O_RDWR|O_NOCTTY); // This line makes the ptty our controlling tty. We do not otherwise need it open
fprintf(stderr, "Opened %s with fd %d\n", name, slavept);
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define SIZE 25
int main ()
{
char buffer[205];
int slavept;
slavept=open("/dev/pts/4", O_RDWR|O_NOCTTY ); // I am opening "/dev/pts/4" because this is the slave device name i got from Master.cpp
fd_set readfd, errfd;
int selret;
struct timeval time;
time.tv_sec = 10;
while (1)
{
cout <<"ENTER WIZARD COMMAND ==>"<< endl;
cin >> buffer;
int num=write( slavept, buffer, SIZE );
//sleep(20);
// write( slavept, "YO YO MAN", SIZE );
I am facing some problems in reading from slave fd. I am openig a psuedoterminal devioce from my process A and I am doing grant and unlock functions and calling getptsname on masterfd and spwaning a new process B with ptsname as commandline.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.