This is a frontend to the tool dc; the idea is to type an infix expression (2 + 3), map it to the corresponding postfix notation (2 3 +) and send it to dc. It's what bc does.
I'm doing this with pipes, but the frontend hangs waiting for output.
This is the code; I will continue commenting it below. The "h" command in my dc is unimplemented, hence is what I'm looking for as an end of output from dc.
TL;DR: the process hangs because stdout in dc is not flushed or that's what I think to have found. How can I read it regardless or force a flush after every write?
What I've found is commented below.
#define DC_EOF_RCV "dc: 'h' (0150) unimplemented"
#define DC_EOF_SND "h\n"
static FILE *sndfp, *rcvfp;
int dcinvoke() {
int pfdout[2], pfdin[2];
pid_t pid;
pipe(pfdout);
pipe(pfdin);
switch (pid = fork()) {
case -1: exit(1);
case 0:
dup2(pfdout[0], STDIN_FILENO);
dup2(pfdin[1], STDOUT_FILENO);
close(pfdout[0]);
close(pfdout[1]);
close(pfdin[0]);
close(pfdin[1]);
execlp("dc", "dc", "-", NULL);
}
close(pfdout[0]);
close(pfdin[1]);
sndfp = fdopen(pfdout[1], "w");
rcvfp = fdopen(pfdin[0], "r");
return 1;
}
void dcsnd(const char *s) {
fputs(s, sndfp);
fflush(sndfp);
}
void dcrcv(char *buf, size_t max) {
fgets(buf, max, rcvfp); // <<<<< HANGS HERE
}
int turnaround() {
dcsnd(DC_EOF_SND); fflush(sndfp);
}
int rcvall() {
char buf[256];
turnaround();
for (;;) {
dcrcv(buf, sizeof(buf));
if (! strcmp(buf, DC_EOF_RCV)) {
break;
}
printf("%s", buf);
}
return 1;
}
int prompt(const char *msg, char *res, size_t resmax, int *eofp) {
char *p;
printf("\n%s ", msg);
if (!fgets(res, resmax, stdin)) {
*eofp = 1;
} else {
if (p = strrchr(res, '\n')) {
*p = 0;
}
*eofp = 0;
}
return 1;
}
int main() {
char buf[128], line[128];
int eof;
dcinvoke();
dcsnd("2 3 +\n");
dcsnd(DC_EOF_SND);
rcvall();
for (;;) {
prompt("Expression", buf, sizeof(buf), &eof);
if (eof) {
break;
}
snprintf(line, sizeof(line), "%s\n", buf);
dcsnd(line);
rcvall();
}
dcsnd("q\n");
return 0;
}
I have removed the error checks for simplicity of this question.
The frontend hangs at the line:
fgets(buf, max, rcvfp);
As I really had no idea how to find the problem, I wrote my own dc which does nothing but responds correctly to an "h" command and outputs everything it gets to a file (so I can debug it; I am not aware of any other way). I can add it here if it's useful.
I've found that a call to fflush(stdout) in (my) dc resumes the frontend, as a call to fgets finally returns.
I cannot change dc itself. How can it not hang on fgets?
Some ideas I had:
Use another thread to flush rcvfp (stdout of dc)
Write it using pseudoterminal
I'm looking for suggestions or a simple way to avoid both of them.
I tried to:
Use read() to fileno(rcvfp)
Read this and this similar posts
Use setlinebuf() (man)
dc sends error messages to stderr, not stdout, so you'll never see them -- they go straight to the terminal (or whatever stderr is connected to in your environment). To be able to read them in your program, you also need to redirect stderr. Add
dup2(pfdin[1], STDERR_FILENO);
in the child fork code.
To make your code actually work, I had to also add a newline to the end of the DC_EOF_RCV string (to match what dc sends), and remove the extra dcsnd(DC_EOF_SND); call from main, since you never do a receive that matches it anywhere. Even with this, you can still get race conditions within dc between writing to stdout and stderr, which can cause the output lines to get mixed, resulting in a response that does not match your DC_EOF_RCV string. You can probably avoid those by adding a small sleep to your turnaround function.
An alternate option is using poll in your main loop to read from stdin and dc simultaneously. With this, you don't need the weird "send h command to trigger an error" mechanism to figure out when dc is done -- you just loop. Your main loop ends up looking like:
struct pollfd polling[2] = { { STDIN_FILENO, POLLIN, 0 }, { fileno(rcvfp), POLLIN, 0 } };
printf("Expression ");
for(;;) {
if (poll(polling, 2, -1) < 0) {
perror("poll");
exit(1); }
if (polling[0].revents) {
/* stdin is ready */
if (!fgets(buf, sizeof(buf), stdin))
break;
dcsnd(buf); }
if (polling[1].revents) {
/* dc has something for us */
printf("\r \r"); /* erase the previsouly printed prompt */
dcrcv(buf, sizeof(buf));
printf("%s\n", buf); }
printf("Expression "); /* new prompt */
}
There's more detail you can do here with managing error conditions (the revents might be POLLERR or POLLHUP for an error or hangup rather than POLLIN for normal input -- all of these are non-zero values, so testing just for nonzero is reasonable).
With the dc command provided by macOS 10.14.6 Mojave, sending 2 3 + to the program works fine; it just doesn't say anything because you've not asked it to.
$ dc
2 3 +
p
5
q
$
The p (print) command triggers the response 5. The q command quits.
Sending h gets a mixed response:
$ dc
h
dc: 'h' (0150) unimplemented
q
$
The response is mixed because the dc: (and space) goes to standard error and the message to standard output:
$ dc >/dev/null
h
dc:
q
$
$ dc 2>/dev/null
h
'h' (0150) unimplemented
q
$
Consequently, I think your primary problem is that you are waiting for a response that dc is not going to provide. If you want to ensure that you get a printed value, then you need to add a p command. That can be on the same line or on a different line as the 2 3 + expression.
$ dc
2 3 + p
5
2
3
+
p
5
q
$
Related
Working on an assignment for class and have been battling ncurses for a while now (it's new to me). Creating a program that is able to communicate with another instance of the same program across a network. Part of the program is to interactively get characters from keyboard and send them to the receiving side. (We have been advised to do this with single thread approach and using getch in ncurses, with nonblocking input from getch).
The issue I'm running into is that my getch is having behavior I cannot figure out. In different variations, it would either display every other character I type, and it won't display the most recently typed character until another character is typed after it. I've used nodelay() to get the live input, but .
Here is the setup for my ncurses display. (Note: I used noecho() as later I don't want to display every char that is enter).
/* initialize ncurses */
setlocale(LC_ALL,"");
initscr();
cbreak();
noecho();
nodelay(stdscr, TRUE);
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
clear();
Here is the code I wrote that works with getch and sending/receiving the data over the socket.
while(1) {
rfdset = master;
if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
perror("select");
exit(EXIT_FAILURE);
}
ch = getch();
if (ch != ERR) {
printw("%c",ch);
write(direct, &ch, 1); // direction to send data
}
for(i = 0; i <= maxfd; i++) {
if (FD_ISSET(i, &rfdset)) {
bzero(msgbuf, MSGSIZE);
idx = read(i, msgbuf, MSGSIZE);
if (i != STDIN)
printw("%s",msgbuf); // display received msg
}
}
}
When I run this and type data on any end of the application, I get results as follows:
Computer 1 keyboard input: testing123
Computer 1 screen display: tsig2
Computer 2 message recv'd: tsig2
Because of this, I feel certain that getch is causing most of my issues, and I must be missing or doing something incorrectly in my implementation. Any advice is appreciated.
Edit 1:
I managed to resolve the every other character issue by removing the for loop and just checking the sockets directly for input. I am baffled why this fixed it. Now my only remaining issue is why is a character not displayed until a character is entered after it. Here is my revised code in the while loop:
while(1) {
rfdset = master;
if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
perror("select");
exit(EXIT_FAILURE);
}
ch = getch();
if (ch != ERR) {
printw("%c",ch);
write(direct, &ch, 1);
}
/* check for incoming data from left socket */
if (!NOLEFT && FD_ISSET(lcsad, &rfdset)) {
bzero(leftmsg, MSGSIZE);
idx = read(lcsad, leftmsg, MSGSIZE);
leftmsg[idx] = 0;
printw("%s", leftmsg);
lm = 1;
}
/* check for incoming data from right socket */
if (!NORIGHT && FD_ISSET(rsd, &rfdset)) {
bzero(rghtmsg, MSGSIZE);
idx = read(rsd, rghtmsg, MSGSIZE);
rghtmsg[idx] = 0;
printw("%s", rghtmsg);
rm = 1;
}
/* check and send left message onward */
if (lm && !NORIGHT) {
write(direct, leftmsg, MSGSIZE);
}
/* check and send right message onward */
if (rm && !NOLEFT) {
write(direct, rghtmsg, MSGSIZE);
}
lm, rm = 0;
}
The problem is that because your select call specifies no timeout (the last parameter is NULL), it blocks until there is some pending I/O (such as the next character which you type). At that point, the program continues into the getch call, which does a refresh (echoing the characters from your printw call).
Specifying a short timeout, e.g., 10 milliseconds, would improve things, e.g.,
struct timeval myTimeout;
myTimeout.tv_sec = 0;
myTimeout.tv_usec = 10000;
and pass the address of myTimeout in the call to select...
You can try if using wgetch() instead of getch() solves your problem.
I have a user defined shell project where I'm trying to implement the cat command but allow the user to click CTRL-/ to display the next x-lines. I'm new to signals so I think I have some syntax wrong somewhere...
in main...
while (fgets(buf, sizeof(buf), file) != NULL){ //CITE
//print out first four lines
if (j == 0){
for (i = 0; i < 4; i++){
printf("%s", buf);
fgets(buf, sizeof(buf), file);
}
j++;
}
signal(SIGQUIT, sig_int);
//now check for user input for the next x lines
if (keepRunning){
for (i = 0; i < 4; i++){
printf("%s", buf);
if (i < 3){
if (fgets(buf, sizeof(buf), file) == NULL){
fclose(file);
return 0;
}
}
}
keepRunning = 0;
}
Then I have the following sig_int function defined...
static volatile int keepRunning = 0;
void sig_int(int sig){
keepRunning = 1;
}
The main problem is that you don't slow down or stop anywhere when the signal is not received. You might use pause(), for example; it only returns when a signal is received. You'd then use that in place of the if (keepRunning) block (including the condition).
Alternatively, you might modify the terminal modes so that characters are sent as they're typed ('raw' mode), and attempt to read a character before continuing. However, if you do that, the onus is on you to ensure that the terminal mode is reset before the program exits under as many circumstances as possible. The good news is that there won't be any signals generated from the keyboard in raw mode, but you have to worry about signals from elsewhere.
You might want to let other signals wake the program and exit the loop, but if you don't set a signal handler for them, that'll happen automatically. That is, after pause() returns (it will always return with an error status and errno set to EINTR), you might check whether keepRunning is now 1 and exit the loop if not.
I'm using Intel Edison and SensorTag. In order to get temperature data via BLE, there are a bunch of commands. When I define popen as:
popen(command,"w");
code works fine most of the times. (Crashes other times due to delay issues I assume as I don't control the responses.)
However, when I want to control the command/console responses (such as step into next line when bluetooth connection is established and if not try to connect again etc.), I cannot read the responses. My "data" variable is not changed.
I also tried other modes of "popen" but they give run-time errors.
Here is the code I'm using:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int endsWith (char* base, char* str) {
int blen = strlen(base);
int slen = strlen(str);
return (blen >= slen) && (0 == strcmp(base + blen - slen, str));
}
FILE* get_popen(char* command, int close, int block) {
FILE *pf;
char data[512];
// Setup our pipe for reading and execute our command.
pf = popen(command,"w");
// Error handling
if (block == 1) {
// Get the data from the process execution
char* result;
do {
result=fgets(data, 512 , stderr);
if (result != NULL) {
printf("Data is [%s]\n", data);
}
} while (result != NULL);
// the data is now in 'data'
}
if (close != 0) {
if (pclose(pf) != 0)
fprintf(stderr," Error: Failed to close command stream \n");
}
return pf;
}
FILE* command_cont_exe(FILE* pf, char* command, int close, int block) {
char data[512];
// Error handling
if (pf == NULL) {
// print error
return NULL;
}
fwrite(command, 1, strlen(command), pf);
fwrite("\r\n", 1, 2, pf);
if (block == 1) {
// Get the data from the process execution
char* result;
do {
result=fgets(data, 512 , stderr);
if (result != NULL) {
printf("Data is [%s]\n", data);
}
} while (result != NULL);//
}
// the data is now in 'data'
if (close != 0) {
if (pclose(pf) != 0)
fprintf(stderr," Error: Failed to close command stream \n");
}
return pf;
}
int main()
{
char command[50];
sprintf(command, "rfkill unblock bluetooth");
get_popen(command, 1, 0);
printf("Working...(rfkill)\n");
sleep(2);
sprintf(command, "bluetoothctl 2>&1");
FILE* pf = get_popen(command, 0, 1);
printf("Working...(BT CTRL)\n");
sleep(3);
sprintf(command, "agent KeyboardDisplay");
command_cont_exe(pf, command, 0, 1);
printf("Working...(Agent)\n");
sleep(3);
//Main continues...
You cannot do this with popen, but can build a program using fork, exec and pipe. The last opens two file descriptors, which are related: the parent's connection to a pipe, and the child's connection. To make a two-way connection to a child process, you must use two calls to pipe.
The file-descriptors opened by pipe are not buffered, so you would use read and write to communicate with the child (rather than fgets and fprintf).
For examples and discussion, see
Does one end of a pipe have both read and write fd?
Read / Write through a pipe in C
UNIX pipe() : Example Programs
pipe(7) - Linux man page
6.2.2 Creating Pipes in C
Unfortunately, you can use popen() in one direction only. To get a bidirectional communication, you need to create two anonymous pipes with pipe() for stdin and stdout and assign them to the file handles 0 and 1 with dup2().
See http://tldp.org/LDP/lpg/node11.html for more details.
I am trying to exploit a SUID program.
The program is:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define e(); if(((unsigned int)ptr & 0xff000000)==0xca000000) { setresuid(geteuid(), geteuid(), geteuid()); execlp("/bin/sh", "sh", "-i", NULL); }
void print(unsigned char *buf, int len)
{
int i;
printf("[ ");
for(i=0; i < len; i++) printf("%x ", buf[i]);
printf(" ]\n");
}
int main()
{
unsigned char buf[512];
unsigned char *ptr = buf + (sizeof(buf)/2);
unsigned int x;
while((x = getchar()) != EOF) {
switch(x) {
case '\n': print(buf, sizeof(buf)); continue; break;
case '\\': ptr--; break;
default: e(); if(ptr > buf + sizeof(buf)) continue; ptr++[0] = x; break;
}
}
printf("All done\n");
}
We can easily see that if we somehow change ptr's contents to some address that starts with CA then a new shell will be spawned for us. And as ptr normally holds some address starting with FF the way to decrease it(ptr) is to enter \ character. So I make a file with 0x35000000 '\' characters, and finally 3 'a' at the end of the file
perl -e "print '\\\'x889192448" > file # decimal equivalent of 0x35000000
echo aaa > file # So that e() is called which actually spawns the shell
And finally in gdb,
run < file
However instead of spawning a shell gdb is saying
process <some number> is executing new program /bin/dash
inferior 1 exited normally
And then back to gdb prompt instead of getting a shell.
I have confirmed by setting breakpoints at appropriate locations that ptr is indeed starting with CA before setresuid() gets called.
Also if I pipe this outside of gdb, nothing happens.
./vulnProg < file
Bash prompt returns back.
Please tell me where am I making mistake.
You can see the problem by compiling a simpler test program
int main() { execlp("/bin/sed", "-e", "s/^/XXX:/", NULL); }
All this does is start a version of sed (rather than the shell) and converts input by prepending "XXX:".
If you run the resulting program, and type in the Terminal you get behaviour like this:
$./a.out
Hello
XXX:Hello
Test
XXX:Test
^D
Which is exactly as we'd expect.
Now if you feed it input from a file containing "Hello\nWorld" you get
$./a.out < file
XXX:Hello
XXX:World
$
And the application exits immediately, with the input stream to the application being closed when the input file has all been read.
If you want to provide additional input, you need to use a trick to not break the input stream.
{ cat file ; cat - ; } | ./a.out
This will put all the input from file into a running ./a.out and then
read from stdin and add that too.
$ { cat file ; cat - ; } | ./a.out
XXX:Hello
XXX:World
This is a Test
XXX:This is a Test
In a X function, I am using pipes, to buffer(couple of printfs, which are printed in Y function called inside from X function) the stdout stream if one Fd and then after buffer is complete,close one pipe and other Fd and then use printf on it.
I want to be completely sure that buffer is empty, when next time this X function is called again to do the task.
I tried couple of things which I found online:
fflush
ioctl, _flushlbf: looks like they aren't supported by gcc. Does g++ support it?
fseek(stdin,EOF,SEEK_END);
fpurge(ofp);
I call X() function, couple of times. The present code, I have written, works fine if next set of output is greater than previous set.
If next set of output is less the present set of output. Then next set have some extra garbage values, which gives me an indication , that buffer may have not flushed completely.
Because of certain reason, I have written entire code in C but using g++ compiler.
My code as follows:
void X(int pairs,char* expOut)
{
char buf[256];
int fds[2];
char output[300];
char input[50];
/* opening pipes */
pipe(fds);
/* saving the the given stdout stream */
int bak = dup(STDOUT_FILENO);
/* associating Fds[1] pipe with stdout */
int res=dup2(fds[1],STDOUT_FILENO);
/* associating Fds[0] pipe with stdin */
dup2(fds[0],STDIN_FILENO);
assert(res!=-1);
/* Call To function Y: function combParenthesis is a recursive function,
which prints out some strings couple of time */
combParenthesis(pairs) ;
fflush(stdout);
/* closing stdout FD stream */
close(fds[1]);
fflush(stdout);
/* restoring the old stdout stream */
dup2(bak, 1);
close(bak);
/* opening, stdin stream for reading */
FILE *ofp = fdopen(fds[0], "r");
char strs[30][30];
for (int i=0;i<30;i++) {
memset(strs[i], 0, 30);
}
int i=0;
if (ofp)
{
int sz;
if((pairs*2)+1 <= 1)
{
sz=5;
}
else
{sz = (pairs*2)+1 ;}
/* read the stream line by line */
while (fgets(buf,sz ,ofp)) {
printf("\n next string %s", buf);
i++;
}
if (ferror(ofp)) {
printf("something went wrong in the input to printf");
}
}
/* different ways to flush it out */
char c;
while( (c = fgetc( ofp )) != EOF && c != '\n' );
fseek(stdin,EOF,SEEK_END);
fpurge(ofp);
fclose(ofp);
fflush(stdin);
// _flushlbf();
/* close the fd associated with stdin */
close(fds[0]);
}
EDIT: a precision at the end on fflush positioning.
I managed to run your code simply using a combParenthesis of my own (first pass : medium strings, second : larger strings, third smaller). I never found garbage in output ... as soon as I have replaced your printf("\n next string %s", buf); by an output on stderr
fprintf(stderr, "\n next string %s", buf);
I also got correct output by flushing stdout after stdin and ofp by a single fflush(stdout). IMHO the problem was :
you close the pipe so stdout is no longer copied to ofp or stdin
you write on stdout with printf("\n next string %s", buf) and stdout may be buffered
you flush streams that are allready clean
when you dup stdout on your next call, you may read what remained from last pass in stdout
Here are the main improvements that I found :
if your read output of combParenthesis with a pipe duping stdout, never write to stdout in any over place (or be sure to flush it)
you do an unnecessary dup2(fds[0],STDIN_FILENO); because you directly read on the other end of the pipe (which is better)
you never verify that sz = (pairs*2)+1 is smaller than sizeof(buf)
Edit : In fact, I have just realized that your code could work, even with intermixed printf elsewhere in the application, provided you flush stdout before copying it to fds[1].
So here is a fixed version of your X() function with clearly identified edits (but IMHO you should considered my other suggestions too) :
void X(int pairs,char* expOut)
{
char buf[256];
int fds[2];
char output[300];
char input[50];
/* BEGIN EDIT */
/* first flush stdout */
fflush(stdout);
/* END EDIT */
/* opening pipes */
pipe(fds);
/* saving the the given stdout stream */
int bak = dup(STDOUT_FILENO);
/* associating Fds[1] pipe with stdout */
int res=dup2(fds[1],STDOUT_FILENO);
/* associating Fds[0] pipe with stdin */
dup2(fds[0],STDIN_FILENO);
assert(res!=-1);
/* Call To function Y: function combParenthesis is a recursive function,
which prints out some strings couple of time */
combParenthesis(pairs) ;
/* closing stdout FD stream */
close(fds[1]);
fflush(stdout);
/* restoring the old stdout stream */
dup2(bak, 1);
close(bak);
/* opening, stdin stream for reading */
FILE *ofp = fdopen(fds[0], "r");
char strs[30][30];
for (int i=0;i<30;i++) {
memset(strs[i], 0, 30);
}
int i=0;
if (ofp)
{
int sz;
if((pairs*2)+1 <= 1)
{
sz=5;
}
else
{sz = (pairs*2)+1 ;}
/* read the stream line by line */
// EDIT : changed sz with sizeof(buf)-1 - cause: no correct pairs value
while (fgets(buf, sizeof(buf) - 1,ofp)) {
printf("\n next string %s", buf);
i++;
}
if (ferror(ofp)) {
printf("something went wrong in the input to printf");
}
}
/* different ways to flush it out */
/* BEGIN EDIT : ALL FLUSHING COMMENTED OUT
char c;
while( (c = fgetc( ofp )) != EOF && c != '\n' );
fseek(stdin,EOF,SEEK_END);
fpurge(ofp);
fclose(ofp);
fflush(stdin);
// _flushlbf();
END EDIT */
/* close the fd associated with stdin */
close(fds[0]);
}
I never got garbage in what is read and it works even with output redirected to a file, but for a reason I couldn't explain, the order of the messages is not what I would expect. Hope it's not a concern for you