LinuxQuestions.org
Visit the LQ Articles and Editorials section
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - General
User Name
Password
Linux - General This 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

Reply
 
Search this Thread
Old 07-30-2008, 08:31 PM   #1
bytehunter
LQ Newbie
 
Registered: Jul 2008
Distribution: RHEL4
Posts: 8

Rep: Reputation: 1
Thumbs up Using Linux pseudo terminal pairs


Hello,

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);

if(c > 0)
{
printf("###-<%d>\n", c);
}
}
}
else
{
printf("PseudoTerm, creation failed...\n");
}

return rtnVal;
}

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.

Thx,

ByteHunter
 
Old 07-30-2008, 11:02 PM   #2
estabroo
Senior Member
 
Registered: Jun 2008
Distribution: debian, ubuntu, sidux
Posts: 1,094
Blog Entries: 2

Rep: Reputation: 111Reputation: 111
I think the master and slave are tied together, writes to the slave appear on the master and writes to the master appear on the slave.
 
Old 07-31-2008, 09:45 AM   #3
bytehunter
LQ Newbie
 
Registered: Jul 2008
Distribution: RHEL4
Posts: 8

Original Poster
Rep: Reputation: 1
Lightbulb Using Linux pseudo terminal pairs

Estabroo,

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?

Thanks,

ByteHunter
 
Old 07-31-2008, 11:13 PM   #4
estabroo
Senior Member
 
Registered: Jun 2008
Distribution: debian, ubuntu, sidux
Posts: 1,094
Blog Entries: 2

Rep: Reputation: 111Reputation: 111
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.
 
Old 08-05-2008, 02:50 PM   #5
bytehunter
LQ Newbie
 
Registered: Jul 2008
Distribution: RHEL4
Posts: 8

Original Poster
Rep: Reputation: 1
Question Using Pseudo Terminals

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?

Should it be able to be used in both cases?


Thanks,

ByteHunter
 
Old 09-15-2008, 03:33 AM   #6
Mak_Rana
LQ Newbie
 
Registered: Sep 2008
Posts: 3

Rep: Reputation: 0
PTY Usage

ByHunter,

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 View Post
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?

Should it be able to be used in both cases?


Thanks,

ByteHunter
 
Old 09-19-2008, 02:54 PM   #7
bytehunter
LQ Newbie
 
Registered: Jul 2008
Distribution: RHEL4
Posts: 8

Original Poster
Rep: Reputation: 1
Using Linux pseudo terminal pairs

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.

Good luck!

ByteHunter
 
Old 09-20-2008, 12:06 AM   #8
Mak_Rana
LQ Newbie
 
Registered: Sep 2008
Posts: 3

Rep: Reputation: 0
Thanks ByteHunter for providing information.

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 View Post
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.

Good luck!

ByteHunter
 
Old 09-21-2008, 11:23 AM   #9
bytehunter
LQ Newbie
 
Registered: Jul 2008
Distribution: RHEL4
Posts: 8

Original Poster
Rep: Reputation: 1
RE:Using Linux pseudo terminal pairs

Mayank,

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, &params);

// Modify terminal attributes
cfmakeraw(&params);

rc = cfsetispeed(&params, B9600);

rc = cfsetospeed(&params, 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, &params);

// 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.

ByteHunter
 
Old 11-28-2008, 07:50 AM   #10
vicky_brsh
LQ Newbie
 
Registered: Sep 2008
Posts: 3

Rep: Reputation: 0
Writing to Master PTY

Hi Mayank and ByteHunter,

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.

#############################
Master.cpp
#############################
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <wait.h>
#include <sys/select.h>

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define SIZE 25

int main ()
{
int masterpt=posix_openpt(O_RDWR|O_NOCTTY);
cout <<"MASTEr = " << masterpt <<endl;
char buffer[SIZE];
char buffer1[SIZE] = "COMMAND OUTPUT";

if( masterpt==-1 ) {
perror("Failed to get a pseudo terminal");

return 2;
}

if( grantpt( masterpt )!=0 ) {
perror("Failed to change pseudo terminal's permission");

return 2;
}

if( unlockpt( masterpt )!=0 ) {
perror("Failed to unlock pseudo terminal");

return 2;
}

//setsid();


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);



fd_set readfd, writefd;
FD_ZERO(&readfd);
FD_SET(masterpt, &readfd);

int selret;
int SlaveWritten ;

{

while(1)
{

FD_ZERO(&readfd);
FD_SET(masterpt, &readfd);

// int slavept=open(name, O_RDWR );
//fprintf(stderr, "Opened %s with fd %d\n", name, slavept);
selret = select(masterpt+1, &readfd, NULL, NULL, NULL );
//close( slavept );

if(FD_ISSET(masterpt,&readfd))
{
if( selret == 1)
{

int num=read( masterpt, buffer1, SIZE );
//cout << "SelRet =" << endl;
cout <<"RECEIVED COMMAND=>" << buffer <<endl;

//SlaveWritten = 1;
}
write(masterpt,buffer1,SIZE);

}
}
}

close( masterpt );
close( slavept );

return 0;
}




###################################
Slave.cpp
###################################

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <wait.h>

#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 );

FD_ZERO(&readfd);
FD_SET(slavept, &readfd);
//sleep (10);
selret = select(slavept+1, &readfd, NULL, NULL, &time);
cout << "SelRet =" << selret << endl;




if (selret > 0 ) {
read( slavept, buffer, SIZE );
cout << "DATA FROM MASTER IS =>"<<buffer << endl;
}

}
close( slavept );

return 0;
}


Thanks & Regards
Vikram
 
Old 12-01-2008, 12:00 PM   #11
Mak_Rana
LQ Newbie
 
Registered: Sep 2008
Posts: 3

Rep: Reputation: 0
Hi Vikram,

Try to set pty into raw mode and disable local echo and try.


Regards,
_-_Mayank Rana_-_
 
Old 03-02-2009, 04:41 AM   #12
max1232
LQ Newbie
 
Registered: Mar 2009
Posts: 5

Rep: Reputation: 0
Hi,

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.

In process B , I am doing

ttyfd = open(Options.DeviceName,O_RDWR|O_NOCTTY);

FD_ZERO(&ReadSet);
FD_ZERO(&WriteSet);
FD_SET(ttyfd,&ReadSet);
FD_CLR(ttyfd,&WriteSet);
for( ; ; )
{
SIMLOG(NOTIFY,"Going to wait for select");
if( ( nSelReturn = select(ttyfd+1,&ReadSet,&WriteSet,NULL,NULL) ) < 0 )

I am weriting data from Processs A but Proces B is still waiting on select. Why is data not reaching the slave fd??
 
Old 03-03-2009, 12:19 AM   #13
max1232
LQ Newbie
 
Registered: Mar 2009
Posts: 5

Rep: Reputation: 0
somebody please help
 
  


Reply

Tags
blocking


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Pseudo Terminal Problem gabsik Linux - Software 8 07-25-2008 05:00 AM
Pseudo terminal programming Alien_Hominid Programming 5 01-20-2008 04:19 AM
Switch to pseudo terminal you didn't log out of? xnomad Linux - General 2 07-19-2005 12:35 AM
Questions about (Pseudo)Terminal devices beginner16 Programming 0 04-09-2004 10:03 AM
Pseudo Terminal Problems ailiez Programming 2 02-09-2004 01:58 AM


All times are GMT -5. The time now is 11:38 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration