Hey, hopefully this should be my last PTY-related question and I can move onto more exciting issues. (c;
Here's a set of small functions I have written for creating and reading/writing to a pty: http://pastebin.com/m4fcee34d The only problem is that they don't work! After I run the initializer and writeToPty( "ls -l" ) , 'output' from readFromPty is still empty.
Ubuntu, QT C++
EDITED: Ok, I can confirm all this stuff works except for the read loop. In the debuggers' locals/watchers tab it shows that the QString 'output' actually does get the right data put in it, but after it ( the read() ) runs out of characters from the output it runs and then hangs. What is going on and how can I fix it?
Thanks! (c:
#include <iostream>
#include <unistd.h>
#include <utmp.h>
#include <pty.h>
#include <QString>
#include <QThread>
// You also need libutil in your .pro file for this to compile.
class CMkPty
{
public:
CMkPty( int *writeChannel, int *readChannel );
~CMkPty();
int runInPty( char *command );
int writeToPty( char *input );
int readFromPty( QString output );
int m_nPid;
private:
int m_nMaster, m_nSlave, m_nPosition, m_nBytes;
char *m_chName;
void safe_print( char *s );
char m_output;
};
CMkPty::CMkPty( int *masterFD, int *slaveFD )
{
openpty( &m_nMaster, &m_nSlave, (char*)0, __null, __null );
m_nPid = fork();
*masterFD = m_nMaster;
*slaveFD = m_nSlave;
if( m_nPid == 0 )
{
login_tty( m_nSlave );
execl( "/bin/bash", "-l", (char*)0 );
return;
}
else if( m_nPid > 0 )
{
return;
}
else if( m_nPid < 0 )
{
std::cout << "Failed to fork." ;
return;
}
}
CMkPty::~CMkPty()
{
close( m_nMaster );
close( m_nSlave );
}
int CMkPty::writeToPty( char *szInput )
{
int nWriteTest;
write( m_nMaster, szInput, sizeof( szInput ) );
nWriteTest = write( m_nMaster, "\n", 1 );
if( nWriteTest < 0 )
{
std::cout << "Write to PTY failed" ;
return -1;
}
return 0;
}
int CMkPty::readFromPty( QString output )
{
char buffer[ 160 ];
m_nBytes = sizeof( buffer );
while ( ( m_nPosition = read( m_nMaster, buffer, m_nBytes ) ) > 0 )
{
buffer[ m_nPosition ] = 0;
output += buffer;
}
return 0;
}
EDIT: Here's a link to the question with the code that finally worked for me.
I'm note entirely familiar with posix, but after reading this page http://pwet.fr/man/linux/fonctions_bibliotheques/posix/read I had some insight. What's more, I don't see you adjusting your M_nBytes value if you haven't read as much as you were expecting on the first pass of the loop.
edit: from that link, perhaps this will be of some help:
If some process has the pipe open for writing and O_NONBLOCK is clear, read() shall block the calling thread until some data is written or the pipe is closed by all processes that had the pipe open for writing.
When attempting to read a file (other than a pipe or FIFO) that supports non-blocking reads and has no data currently available:
*
If O_NONBLOCK is clear, read() shall block the calling thread until some data becomes available.
so essentially, if you're not in an error state, and you tell it to keep reading, it will block until it finds something to read.
Related
I want to open some files, redirect the output of them and then go back to previous situation, so I wrote:
int fd = open("test.txt", O_WRONLY | O_CREAT, 0666);
dup(1);
dup2(3, 1);
close(3);
//call my func() to print in std::cout which will write to test.txt
dup2(4, 1);//Close file
I know that the default input channel is in index 0, output channel (screen) in index 1 and stderr in index 2 so fd will get 3, dup 1 will create another pointer to output channel in index 4, then I replace screen with my file and close that isn't needed.
My code is correct, but did I forget anything else or can it be made shorter/ more clear?
Most importantly, in case one line fails I want to return false but this will be a lot of checks and in every advance step we need to close more. How can I solve this problem?
What if I wanted in case of failure to make everything go back to default situation?
Please Note, I only know and want to use open,close,dup,dup2
Most importantly it is the duty of a programmer to write reliable, faultless code, and this includes thorough error checking. Error checking often makes for large parts of the code, especially when user interaction is part of the program. But, there is no way around it, if you want to be/become a good programmer.
That said, it is easy (in a first step) to change your code so that it does not depend on specific file descriptor numbers (not tested).
int fileFd;
int redirectFd1;
int redirectFd2;
fileFd = open( "test.txt", O_WRONLY | O_CREAT, 0666 );
redirectFd1 = dup( 1 );
redirectFd2 = dup2( fileFd, 1 );
close( fileFd );
//call my func() to print in std::cout which will write to test.txt
dup2( redirectFd1, 1 );//Close file
Next step is to add error checking.
int fileFd;
int redirectFd1;
int redirectFd2;
if ( ( fileFd = open( "test.txt", O_WRONLY | O_CREAT, 0666 ) ) == -1 ) {
// open() failed. Do appropriate error handling here...
exit( 1 );
}
if ( ( redirectFd1 = dup( 1 ) ) == -1 ) {
// dup() failed. Do appropriate error handling here...
// Since we arrvied here, fileFd *is* open. So we need to close it.
// But redirectFd1 is *not* open
close( fileFd );
exit(1);
}
if ( ( redirectFd2 = dup2( fileFD, 1 ) ) == -1 ) {
// dup() failed. Do appropriate error handling here...
// Since we arrvied here, fileFd *and* redirectFd1 *are* open.
// So we need to close them.
// But redirectFd2 is *not* open
close( fileFd );
close( redirectFd1 );
exit(1);
}
close( fileFd );
//call my func() to print in std::cout which will write to test.txt
if ( dup2( redirectFD1, 1 ) == -1 ) {
// dup2() failed. Do appropriate error handling here...
close( redirectFd1 );
}
close( redirectFd1 );
One can argue whether checking for errors on the close( fileFd ) statement is needed or nor. Fact is that open() succeeded, so it would be very unsusual for close() to fail here. One can also argue whether checking for errors on the last dup2() is needed or not.
In general, I keep track of open files, and take care of closing in case of errros in a clean-up routine. The code might look like this:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int fileFd;
bool fileFdIsOpen = false;
int redirectFd1;
bool redirectFd1IsOpen = false;
int redirectFd2;
bool redirectFd2IsOpen = false;
void cleanup();
int main( int argc, char* argv[] ) {
int stdoutFd = fileno( stdout );
if ( ( fileFd = open( "test.txt", O_WRONLY | O_CREAT, 0666 ) ) == -1 ) {
// open() failed. Do appropriate error handling here...
exit( 1 );
}
fileFdIsOpen = true;
if ( ( redirectFd1 = dup( stdoutFd ) ) == -1 ) {
// dup() failed. Do appropriate error handling here...
cleanup();
exit(1);
}
redirectFd1IsOpen = true;
if ( ( redirectFd2 = dup2( fileFd, stdoutFd ) ) == -1 ) {
// dup() failed. Do appropriate error handling here...
cleanup();
exit(1);
}
redirectFd2IsOpen = true;
close( fileFd );
fileFdIsOpen = false;
//call my func() to print in std::cout which will write to test.txt
if ( dup2( redirectFd1, stdoutFd ) == -1 ) {
// dup2() failed. Do appropriate error handling here...
cleanup();
}
cleanup();
exit (0);
}
void cleanup() {
if ( fileFdIsOpen ) {
close( fileFd );
fileFdIsOpen = false;
}
if ( redirectFd1IsOpen ) {
close( redirectFd1 );
redirectFd1IsOpen = false;
}
if ( redirectFd2IsOpen ) {
close( redirectFd2 );
redirectFd2IsOpen = false;
}
}
I know that default input channel is in index 0, output channel
(screen) in index 1 and stderr in index 2 so fd will get 3
That's undetermined, process can be run in away those ids would be altered and starting descriptor also might be different from stderr+1. Theremore, on Linux there are situation where process can be created with none open, but that's different.
In C header <stdio.h> defines those variables that are supposed to be initialized by runtime library.
extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;
Code you had shown is pretty much C code, not C++, but you can use <cstdio> and fileno function to obtain descriptor
int fileno(FILE *stream);
You have to check returned results of fileno, dup and open to be sure that you program didn't run into some limitations imposed on it, and errno variable would tell you a reason. On some other platforms, like Windows, more appropriate error reporting functions do exist.
Recently I have been trying to redirect the output of a named pipe into a running instance of omxplayer (see here for a minimum working example that doesn't control omxplayer even though it should). I suspected that it had something to do with reading and writing to pipes --perhaps a new line got appended-- so I got some help and wrote a C program which writes to a pipe and reads from it (see here) but turns out that it is not a read/write error either. So I went and traced omxplayer's code thinking that no matter how complicated it was, eventually there has to be a place which has standard C++ code which reads user input, and thank god I found it. Here is the method which, to the best of my understanding, is responsible for getting user input and preparing it for the Dbus to do all its heavenly goodness:
void Keyboard::Process()
{
while(!m_bStop && conn && dbus_connection_read_write_dispatch(conn, 0))
{
int ch[8];
int chnum = 0;
while ((ch[chnum] = getchar()) != EOF) chnum++;
if (chnum > 1) ch[0] = ch[chnum - 1] | (ch[chnum - 2] << 8);
if (m_keymap[ch[0]] != 0)
send_action(m_keymap[ch[0]]);
else
Sleep(20);
}
}
As far as I can glean, the while(!m_bStop... is a conditional just to make sure things are still working, m_keymap is a cypher which matches integers such as 'p' or 'q' to enum values such as ACTION_PAUSE and ACTION_QUIT, and I presume send_action() just gets the ball rolling.
Questions:
Here is what I do not understand:
How is EOF detected when I am not even pressing Enter --> while ((ch[chnum] = getchar()) != EOF) (in case you are confused by this, when a movie is playing I press p to pause the film, not p and then Enter or Ctrl+D). I have attached a small script below labeled getchar.c which illustrates how it is looping forever.
Why are we looping for potentially more than 8 iterations in the while loop while ((ch[chnum] = getchar()) != EOF) chnum++ when the array ch is only of length 8?
This might be implementation specific, but why an array of size 8 when all inputs are guaranteed to be 1 character long (I can both see it here in the map, and by the fact that keys are processed instantly). Is this in any way related to the arrow keys and the escape key?
Assuming it is possible to have more than 1 character, somehow, what is this line supposed to do if (chnum > 1) ch[0] = ch[chnum - 1] | (ch[chnum - 2] << 8)?
Knowing, finally, how omxplayer reads user generated input, can anyone tell me why my simple script, labelled omxplayer_test.c, does not succeed in controlling the player?
getchar.c:
#include <stdio.h>
int main( int argc, char *argv[] ) {
int ch [ 8 ];
int chnum = 0;
while ( ( ch [ chnum ] = getchar() ) != EOF ) chnum++;
printf ( "You will never make it here!\n" );
return 0;
}
omxplayer_test.c:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#define PIPE_PATH "testpipe"
#define VIDEO_PATH "Matrix.mkv"
#define P_MESSAGE "p"
#define Q_MESSAGE "q"
#define I_MESSAGE "."
#define VIDEO_PLAYER "omxplayer"
#define SLEEP_PERIOD 2L
int main()
{
int fd;
pid_t pid;
pid_t wpid;
int status;
char shellCmd [ 1000 ];
struct timespec time1, time2; //used for sleeping
bool parent;
char c;
parent = false;
//Make pipe BEFORE forking
mkfifo ( PIPE_PATH, 0666 );
if ( ( pid = fork () ) < 0 )
{
perror ( "Fork Failed\n" );
return -1;
}
else if ( pid == 0 )
{ //first child launches the movie
sprintf ( shellCmd, "%s %s < %s >/dev/null 2>&1", VIDEO_PLAYER, VIDEO_PATH, PIPE_PATH );
if ( system ( shellCmd ) == -1 )
{
printf ( "Error: %s\n", shellCmd );
fflush(stdout);
}
printf ("First child finished\n");
fflush (stdout);
}
else
{
if ( ( pid = fork () ) < 0 )
{
perror ( "Fork Failed\n" );
return -1;
}
else if ( pid == 0 )
{ //second child waits x seconds then pauses/unpauses/quits movie
time1.tv_sec = SLEEP_PERIOD; //sleep for x seconds
time1.tv_nsec = 0L; //Dont worry about milli seconds
nanosleep ( &time1, &time2 );
//Suprisingly, this signal which gets ball rolling works
fd = open ( PIPE_PATH, O_WRONLY );
write ( fd, I_MESSAGE, sizeof ( I_MESSAGE ) );
nanosleep ( &time1, &time2 );
printf ( "Sleep over, pausing movie\n");
fflush(stdout);
write ( fd, I_MESSAGE, sizeof ( P_MESSAGE ) );
nanosleep ( &time1, &time2 );
printf ( "Sleep over, unpausing movie\n");
fflush(stdout);
write ( fd, P_MESSAGE, sizeof ( P_MESSAGE ) );
nanosleep ( &time1, &time2 );
printf ( "Sleep over, quiting movie\n");
fflush(stdout);
write ( fd, Q_MESSAGE, sizeof ( Q_MESSAGE ) );
close ( fd );
printf ("Second child finished\n");
fflush (stdout);
}
else
{
parent = true;
}
}
while ( ( wpid = wait ( &status ) ) > 0 )
{
printf ( "Exit status of %d was %d (%s)\n", ( int ) wpid, status, ( status == 0 ) ? "accept" : "reject" );
fflush(stdout);
}
if ( parent == true )
{
printf ("deleting pipe\n");
fflush(stdout);
unlink ( PIPE_PATH );
}
return 0;
}
#puk I stumbled upon your 'oldĀ“ question but in case you didn't have it answered by yourself.
Look at something similar on https://github.com/popcornmix/omxplayer/issues/131. As omxplayer releases 0.3.x comes from this 'popcornmix' repository, I will answer these questions there because it is a better place for your omxplayer questions ;)
But I will answer the question why your omxplayer_test.c isn't working here, as it is your code that let omxplayer fail :) Strictly not true, as it is a current issue in omxplayer :(
The sending of I_MESSAGE surprises me the most, as I don't know of any keyboard input handling on a '.' character. On the other hand, 'i' commands omxplayer to go to the previous chapter. So if you didn't key-mapped anything on the '.' input key or meant the real 'i' actions, just leave that out; it isn't (and shouldn't be) needed to start omxplayer.
To pause omxplayer, your typo'd it with the I_MESSAGE in stead of P_MESSAGE.
But sending commands to omxplayer with the write() and the sizeof() of the message causes the same effect as mentioned in forementioned issue. The sizeof() of an x_MESSAGE gives 2 as result back, and not 1 (one)! The sizeof() counts in the '\0'-character of a (c-coded) string; e.g. "p" is stored as 'p''\0', so at least 2 characters. So use strlen() (which needs #include <string.h>) in stead, as it will sent only the x_MESSAGE character.
Recently I've been playing about with using shared memory for IPC. One thing I've been trying to implement is a simple ring buffer with 1 process producing and 1 process consuming. Each process has its own sequence number to track its position. These sequence numbers are updated using atomic ops to ensure the correct values are visible to the other process. The producer will block once the ring buffer is full. The code is lock free in that no semaphores or mutexes are used.
Performance wise I'm getting roughly 20 million messages per second on my rather modest VM - Pretty happy with that :)
What I'm curious about how 'correct' my code is. Can anyone spot any inherent issues / race conditions? Here's my code. Thanks in advance for any comments.
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#define SHM_ID "/mmap-test"
#define BUFFER_SIZE 4096
#define SLEEP_NANOS 1000 // 1 micro
struct Message
{
long _id;
char _data[128];
};
struct RingBuffer
{
size_t _rseq;
char _pad1[64];
size_t _wseq;
char _pad2[64];
Message _buffer[BUFFER_SIZE];
};
void
producerLoop()
{
int size = sizeof( RingBuffer );
int fd = shm_open( SHM_ID, O_RDWR | O_CREAT, 0600 );
ftruncate( fd, size+1 );
// create shared memory area
RingBuffer* rb = (RingBuffer*)mmap( 0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
close( fd );
// initialize our sequence numbers in the ring buffer
rb->_wseq = rb->_rseq = 0;
int i = 0;
timespec tss;
tss.tv_sec = 0;
tss.tv_nsec = SLEEP_NANOS;
while( 1 )
{
// as long as the consumer isn't running behind keep producing
while( (rb->_wseq+1)%BUFFER_SIZE != rb->_rseq%BUFFER_SIZE )
{
// write the next entry and atomically update the write sequence number
Message* msg = &rb->_buffer[rb->_wseq%BUFFER_SIZE];
msg->_id = i++;
__sync_fetch_and_add( &rb->_wseq, 1 );
}
// give consumer some time to catch up
nanosleep( &tss, 0 );
}
}
void
consumerLoop()
{
int size = sizeof( RingBuffer );
int fd = shm_open( SHM_ID, O_RDWR, 0600 );
if( fd == -1 ) {
perror( "argh!!!" ); return;
}
// lookup producers shared memory area
RingBuffer* rb = (RingBuffer*)mmap( 0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
// initialize our sequence numbers in the ring buffer
size_t seq = 0;
size_t pid = -1;
timespec tss;
tss.tv_sec = 0;
tss.tv_nsec = SLEEP_NANOS;
while( 1 )
{
// while there is data to consume
while( seq%BUFFER_SIZE != rb->_wseq%BUFFER_SIZE )
{
// get the next message and validate the id
// id should only ever increase by 1
// quit immediately if not
Message msg = rb->_buffer[seq%BUFFER_SIZE];
if( msg._id != pid+1 ) {
printf( "error: %d %d\n", msg._id, pid ); return;
}
pid = msg._id;
++seq;
}
// atomically update the read sequence in the ring buffer
// making it visible to the producer
__sync_lock_test_and_set( &rb->_rseq, seq );
// wait for more data
nanosleep( &tss, 0 );
}
}
int
main( int argc, char** argv )
{
if( argc != 2 ) {
printf( "please supply args (producer/consumer)\n" ); return -1;
} else if( strcmp( argv[1], "consumer" ) == 0 ) {
consumerLoop();
} else if( strcmp( argv[1], "producer" ) == 0 ) {
producerLoop();
} else {
printf( "invalid arg: %s\n", argv[1] ); return -1;
}
}
Seems correct to me at a first glance. I realize that you are happy with the performance but a fun experiment might be to use something more light weight than a __sync_fetch_and_add. AFAIK it is a full memory barrier, which is expensive. Since there is a single producer and a single consumer, a release and a corresponding acquire operation should give you better performance. Facebook's Folly library has a single producer single consumer queue that uses the new C++11 atomics here: https://github.com/facebook/folly/blob/master/folly/ProducerConsumerQueue.h
I need to open a file as ofstream and write to the front of the file, while preserving
the remaining contents of the file, which will be "moved". Similar to "prepend"
a file.
Is this possible using the STL or boost ?
No -- the language (or library) doesn't really make much difference here. Most file systems just don't allow it, full stop.
The usual way to get the same effect is to write your new data to a new file, then copy the data in the old file to the new file following the data you wrote.
No it isn't. And this has been asked here many times before. If you want to do this you have to create new file, write the "prepend" data to it, then open the existing file and copy its contents to the new file.
A new iostream class can wrap that functionality. This assumes your prepend data isn't too large to comfortably fit in memory. Use it like a regular ofstream.
#include <fstream>
#include <sstream>
#include <vector>
class prepend_ofstream
: public std::ostringstream {
std::filebuf file;
public:
prepend_ofstream() {}
prepend_ofstream( char const *name, openmode mode = out ) {
open( name, mode );
}
~prepend_ofstream() {
if ( is_open() ) close();
}
void open( char const *name, openmode mode ) {
if ( ! file.open( name, mode & binary | in | out ) ) {
setstate( failbit );
}
}
bool is_open() { return file.is_open(); }
void close() {
if ( ! is_open() ) {
setstate( failbit );
return;
}
char *strbuf = &str()[0];
std::vector<char> buf( str().size() );
int rdsz;
do {
rdsz = file.sgetn( &buf[0], buf.size() );
file.pubseekoff( -rdsz, cur );
file.sputn( strbuf, buf.size() );
file.pubseekoff( 0, cur ); // "update the output sequence"
std::copy( &buf[0], &buf[0]+rdsz, strbuf );
} while ( rdsz == buf.size() );
file.sputn( &buf[0], rdsz );
if ( ! file.close() ) {
setstate( failbit );
}
}
};
Typically features are added through new stream buffer classes, not actual streams, but in this case the new functionality is in close, which is unfortunately not virtual.
This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
How can I run an external program from C and parse its output?
Hi,
Could someone please tell us how to capture a result when executing system() function ?
Actually I wrote a c++ program that displays the machine's IP address, called "ipdisp" and I want when a sever program executes this ipdisp program, the server captes the display IP address. So, is this possible? if yes, how?
thanks for your replies
Yes, you can do this but you can't use system(), you'll have to use popen() instead. Something like:
FILE *f = popen("ipdisp", "r");
while (!feof(f)) {
// ... read lines from f using regular stdio functions
}
pclose(f);
Greg is not entirely correct. You can use system, but it's a really bad idea. You can use system by writing the output of the command to a temporary file and then reading the file...but popen() is a much better approach. For example:
#include <stdlib.h>
#include <stdio.h>
void
die( char *msg ) {
perror( msg );
exit( EXIT_FAILURE );
}
int
main( void )
{
size_t len;
FILE *f;
int c;
char *buf;
char *cmd = "echo foo";
char *path = "/tmp/output"; /* Should really use mkstemp() */
len = (size_t) snprintf( buf, 0, "%s > %s", cmd, path ) + 1;
buf = malloc( len );
if( buf == NULL ) die( "malloc");
snprintf( buf, len, "%s > %s", cmd, path );
if( system( buf )) die( buf );
f = fopen( path, "r" );
if( f == NULL ) die( path );
printf( "output of command: %s\n", buf );
while(( c = getc( f )) != EOF )
fputc( c, stdout );
return EXIT_SUCCESS;
}
There are lots of problems with this approach...(portability of the syntax for redirection, leaving the file on the filesystem, security issues with other processes reading the temporary file, etc, etc.)