I have the following C program:
#include<stdio.h>
main()
{
char buf[64];
gets(buf);
printf("Your input: %s\n", buf);
gets(buf);
printf("Your input: %s\n", buf);
}
I want to send data to the program using pipes or redirection. The problem is that the program don't wait for the second gets to enter new data.
e.g
$ echo "a" | ./test
Output:
Your input: a
Your input: a
How can I send let the program wait for the user input at each gets using pipes or redirection.
P.S I don't have persmission to write to /proc/$pid/fd/0 and I don't have to change the code.
Any help would be appreciated.
If you use pipes | to input data to a command, it is disconnected from the (input portion) of your terminal. gets reads the first line "a\n" and writes this to the buf as "a\0". Then it hits the end of the pipe, or EOF (end of file).
Your second gets then does nothing (as there is nothing to read after EOF) and lets buf alone; buf still contains "a\0", which is duly printed.
Further hints:
When doing I/O, which can inherently fail at any time, you have to check for errors after each and every call, or bad things will happen. Train yourself to do this and save lots of debugging time.
Never do an I/O like gets(buf) because it will lead to buffer overflows, the bane of computing security. If you input arbitrary data, you must use a call that lets you limit the number of bytes written. The man page for gets contains the sentence "Never use this function" right at the top. You can find other, better functions, read being a baseline, and if you are in C++ there will be plenty of other standard solutions for that.
Related
When you read from stdin using getchar, fgets or some similar function, if you type some text and then put an eof (control+d in linux) you cannot delete the previous text. For example, if I type 'program' and then enter eof by pressing control+d, I can't delete what I typed before, i.e. program.
#include<string.h>
#include<stdlib.h>
int main() {
char buffer[1024] = "";
printf("> ");
if(fgets(buffer,sizeof(buffer),stdin) == NULL){
puts("eof");
}
else{
puts(buffer);
}
return 0;
}
How can this be avoided?
The readline function of The GNU Readline Library I think is my best option to do the job. It's pretty simple to use but it uses dynamic memory to host the string so you have to use the free function to free up the memory. You can find more information by opening a terminal and typing 'man readline'.
The code would look like this:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <readline/readline.h>
int main() {
char *ptr = readline("> ");
if(!ptr){
puts("eof");
}
else{
puts(ptr);
}
free(ptr);
return 0;
}
To be able to use readline with gcc you must pass it -lreadline
When fgets reads a line, what will happen is that it will read characters from the specified stream until it encounters a '\n' or EOF, until it has read the specified maximum size to read or a read error occurs. It does not see what you are doing on your keyboard at all. It only sees the stream, but it is the terminal that sends the data to the stream.
What's happening when you are editing the input has absolutely nothing to do with fgets. That's the terminals job.
As Eric Postpischil wrote in the comments:
Pressing control-D in Linux does not signal EOF. It actually means “Complete the current read operation.” At that point, if characters have been typed, they are immediately sent to the program, whereas the system would usually wait until Enter is pressed. If no characters have been typed, the read operation completes with zero characters read, which some I/O routines treat as an EOF, and that is why programs may seem to receive an EOF when control-D is pressed at the start of a line of input. Since the data is sent to the program, of course there is no way to undo it—it has already been sent.
I guess there is some way to alter the behavior of pressing C-d, but then you need to decide what it should do instead. If you want it to do "nothing" instead of sending the data to stdin I cannot really see what you have won. The only use case I can see with this is if you for some reason are having a problem with accidentally pressing C-d from time to time.
One thing you could do is to take complete control of every keystroke. Then you would have to write code to move the cursor every time the user presses a key, and also write code to remove characters when the user is pressing backspace. You can use a library like ncurses for this.
It can't be avoided. Simply put, Ctrl+D ends the current read operation.
If you want to ignore this, make your own fgets based on fgetc and have it ignore end-of-file.
I have a simple C program with the read function and I don't understand the output.
//code1.c
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main()
{
int r;
char c; // In C, char values are stored in 1 byte
r = read ( 0, &c, 1);
// DOC:
//ssize_t read (int filedes, void *buffer, size_t size)
//The read function reads up to size bytes from the file with descriptor filedes, storing the results in the buffer.
//The return value is the number of bytes actually read.
// Here:
// filedes is 0, which is stdin from <stdio.h>
// *buffer is &c : address in memory of char c
// size is 1 meaning it will read only 1 byte
printf ("r = %d\n", r);
return 0;
}
And here is a screenshot of the result:
I ran this program 2 times as showed above and typed "a" for the first try and "aecho hi" for the second try.
How I try to explain the results:
When read is called it sees that stdin is closed and opens it (from my point of view, why? It should just read it. I don't know why it opens it).
I type "aecho hi" in the bash and press enter.
read has priority to process stdin and reads the first byte of "aecho hi" : "a".
I get the confirmation that read has processed 1 byte with the printf.
a.out has finished and is terminated.
Somehow the remaining data in stdin is processed in bash (the father of my program) and goes to stdout which executes it and for some reason the first byte has been deleted by read.
This is all hypothetical and very blurry. Any help understanding what is happening would be very welcome.
When you type at your terminal emulator, it writes your keystrokes to a "file", in this case an in-memory buffer that, thanks to the file system, looks just like any other file that might be on disk.
Every process inherits 3 open file handles from its parent. We are interested in one of them here, standard input. The program executed by the terminal emulator (here, bash), is given as its standard input the in-memory buffer described in the first paragraph.
a.out, when run by bash, also receives this same file as its standard input. Keep this in mind: bash and a.out are reading from the same, already-opened file.
After you run a.out, its read blocks, because its standard input is empty. When you type aecho hi<enter>, the terminal writes these characters to the buffer (<enter> becoming a single linefeed character). a.out only requests one character, so it gets a and leaves the rest of the characters in the file. (Or more precisely, the file pointer is still pointing at the e after a is read.)
After a.out completes, bash tries to read from the same file. Normally, the file is empty (i.e., the file pointer is at the end of the file), so bash blocks waiting for another command. In this case, though, there is input available already: echo hi\n. bash reads this now the same as if you had typed it after a.out completed.
Check this. As alk suggests stdin and stdout are already open with the program. Now you have to understand, once you type:
aecho hi
and hit return the stdin buffer is filled with all those letters (and space) - and will continue to be as long as you don't flush it. When the program exits, the stdin buffer is still full, and your terminal automatically handles a write into stdin by echoing it to stdout - this is what you're seeing at the end - your shell reading stdin.
Now as you point out, your code "presses return" for you so to speak - in the first execution adding an empty shell line, and in the second executing echo hi. But you must remember, you pressed return, so "\n" is in the buffer! To be explicit, you in fact typed:
aecho hi\n
Once your program exits the shell reads the remaining characters in the buffer, including the return, and that's what you see!
We just started the topic of low level functions in C and for a part of this assignment we have to ask for user input. Normally I would use printf() and scanf() however for this assignment we are only allowed to use read(), write(), open(), close(), and lseek().
My question is how would you read input from the keyboard after printing to the screen?
I understand that I would have to use read, the file descriptor would be STDIN_FILENO, however how would I determine the size count? Also how would I keep track of what the user inputted? Would I have to create an char array just for that?
Also if anyone could reference some good reading material or tutorials for programming with low level functions that would help a lot.
Reading char by char would be bad for performance. System calls are kind of expensive. Most usually you want some kind of buffer (malloced, static memory, on the stack).
The size (once it's past certain size) doesn't really matter that much.
If your fd 0 is a terminal in cooked mode, you will get a line on each call to read (which will usually fail to fill your entire buffer). What's important to realize is that a read request for N bytes doesn't need to return N bytes and a return of less than N bytes doesn't need to mean an IO error. If it's a disk-based file, then your read request for the size of your buffer will tend to get fullfilled fully.
Advanced Programming in the Unix Environment by Richard Stevens is a good book on this.
Then of course, the man pages for the system calls.
Continuing from my earlier comment, there is really little difference between reading and writing to stdin using read and write and using higher level functions like fgets and printf. The primary difference is you cannot rely on the format string provided by the variadic printf, and with read, you are responsible for making use of the return to know how many characters were actually read.
Below is a short example showing the basics of reading input from stdin with read and then writing that information back with write (note: there are additional checks you should add like checking that the number of characters read is less than the size of the buffer to know if more characters remain to be read, etc...) You can always put much of the prompt and read into a function to ease repetitive use.
With write, just remember, the order you write things to stdout is the format string. So simply make logical calls to write to accomplish the formatting you desire. While you are free to use the STDIN_FILENO defines, you can also simply use 0 - stdin, 1 - stdout and 2 - stderr:
#include <unistd.h>
#define MAXC 256
int main (void) {
char buf[MAXC] = {0};
ssize_t nchr = 0;
/* write the prompt to stdout requesting input */
write (1, "\n enter text : ", sizeof ("\n enter text : "));
/* read up to MAXC characters from stdin */
if ((nchr = read (0, buf, MAXC)) == -1) {
write (2, "error: read failure.\n", sizeof ("error: read failure.\n"));
return 1;
}
/* test if additional characters remain unread in stdin */
if (nchr == MAXC && buf[nchr - 1] != '\n')
write (2, "warning: additional chars remain unread.\n",
sizeof ("warning: additional chars remain unread.\n"));
/* write the contents of buf to stdout */
write (1, "\n text entered: ", sizeof ("\n text entered: "));
write (1, buf, nchr-1);
write (1, "\n\n", sizeof ("\n\n"));
return 0;
}
Compile
gcc -Wall -Wextra -o bin/read_write_stdin read_write_stdin.c
Output
$ ./bin/read_write_stdin
enter text : The quick brown fox jumps over the lazy dog!
text entered: The quick brown fox jumps over the lazy dog!
EDIT: GDB was not the issue. Bugs in my code created the behaviour.
I am wondering how GDB's input works.
For example I created the following small c program:
#include <stdlib.h>
#include <stdio.h>
int main(){
setbuf(stdout,NULL);
printf("first:\n");
char *inp;
size_t k = 0;
getline(&inp, &k, stdin);
printf("%s",inp);
free(inp);
// read buffer overflow
printf("second:\n");
char buf[0x101];
read(fileno(stdin),buf,0x100);
printf("%s",buf);
printf("finished\n");
}
It reads two times a string from stdin and prints the echo of it.
To automate this reading I created following python code:
python3 -c 'import sys,time; l1 = b"aaaa\n"; l2 = b"bbbb\n"; sys.stdout.buffer.write(l1); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(l2); sys.stdout.buffer.flush();'
Running the c programm works fine. Running the c program with the python input runs fine, too:
python-snippet-above | ./c-program
Running gdb without an input file, typing the strings when requested, seems also fine.
But when it comes to using an inputfile in gdb, I am afraid I am using the debugger wrongly.
Through tutorials and stackoverflow posts I know that gdb can take input via file.
So I tried:
& python-snippet > in
& gdb ./c-program
run < in
I expected that gdb would use for the first read the first line of the file in and for the second read the second line of in.
in looks like (due to the python code):
aaaa
bbbb
But instead gdb prints:
(gdb) r < in
Starting program: /home/user/tmp/stackoverflow/test < in
first:
aaaa
second:
finished
[Inferior 1 (process 24635) exited with code 011]
Observing the variable buf after read(fileno(stdin),buf,0x100) shows me:
(gdb) print buf
$1 = 0x0
So i assume that my second input (bbbb) gets lost. How can I use multiple input inside gdb?
Thanks for reading :)
I am wondering how GDB's input works.
Your problem doesn't appear to have anything to with GDB, and everything to do with bugs in your program itself.
First, if you run the program outside of GDB in the same way, namely:
./a.out < in
you should see the same behavior that you see in GDB. Here is what I see:
./a.out < in
first:
aaaa
second:
p ��finished
So what are the bugs?
The first one: from "man getline"
getline() reads an entire line from stream, storing the address
of the buffer containing the text into *lineptr.
If *lineptr is NULL, then getline() will allocate a buffer
for storing the line, which should be freed by the user program.
You did not set inp to NULL, nor to an allocated buffer. If inp didn't happen to be NULL, you would have gotten heap corruption.
Second bug: you don't check return value from read. If you did, you'd discover that it returns 0, and therefore your printf("%s",buf); prints uninitialized values (which are visible in my terminal as ��).
Third bug: you are expecting read to return the second line. But you used getline on stdin before, and when reading from a file, stdin will use full buffering. Since your input is small, the first getline tries to read BUFSIZ worth of data, and reads (buffers) all of it. A subsequent read (naturally) returns 0 since you've already reached end of file.
You have setbuf(stdout,NULL);. Did you mean to disable buffering on stdin instead?
Fourth bug: read does not NUL-terminate the string, you have to do that yourself, before you can call printf("%s", ...) on it.
With the bugs corrected, I get expected:
first:
aaaa
second:
bbbb
finished
My program has to read just ONE character from the standard input, and so I use read(0, buffer, 1).
But if the user insert more than one single character, they remain in some buffer and when I call a read again they are still there.
So, how can I discard these characters?
I want that when I call a read again, the buffer is filled with the new character, not with the old ones.
An example:
I've a read(0, buffer, 1) and the user writes abcde. My buffer contains a (and it's right), but then I call read(0, buffer, 1) again and I want the next character written by the user from now, and not the b written before.
The POSIX answer is tcflush(): flush non-transmitted output data, non-read input data, or both. There is also tcdrain() which waits for output to be transmitted. They've been in POSIX since there was a POSIX standard (1988 for the trial-use version), though I don't recall ever using them directly.
Example program
Compile this code so the resulting program is called tcflush:
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
int main(void)
{
char buffer[20] = "";
read(0, buffer, 1);
printf("%c\n", buffer[0]);
tcflush(0, TCIFLUSH);
read(0, buffer, 1);
printf("%c\n", buffer[0]);
tcflush(0, TCIFLUSH);
return 0;
}
Example dialog
$ ./tcflush
abc
a
def
d
$
Looks like what the doctor ordered. Without the second tcflush(), the shell complains that it can't find a command ef. You can place a tcflush() before the first read if you like. It wasn't necessary for my simple testing, but if I'd used sleep 10; ./tcflush and then typed ahead, it would make a difference.
Tested on RHEL 5 Linux on an x86/64 machine, and also on Mac OS X 10.7.4.
When your program wants to start reading characters, it must drain the buffer of existing characters and then wait to read the character.
Otherwise, it will read the last character entered, not the last character entered after right now.
Naturally, you do not need to do anything with the read characters; but, you do need to read them.