I'm trying to print out the contents of a file, however the program will pause at the read() function and won't continue until I hit the enter key. Once the enter key is pressed, nothing is printed to the terminal. The rest of the program is not shown, but here is the method that is causing the issue.
{
char buff[1024];
ssize_t bytesRead = 0;
int readFile, error;
if((readFile = open(file,O_RDONLY)<0))
{
printf("can't open %s\n",file);
error = errno;
return -1;
}
do{
memset(buff,0,1024);
if((bytesRead=read(readFile,buff,1024))==-1)
{
printf("error reading file");
error = errno;
printf("%d",error);
}
else
printf("%s",buff);
}while(bytesRead==1024);
printf("\n");
close(readFile);
return 1;
}
Alternatively, if I change the read() function to pread(file,buff,1024,0) it throws an illegal seek 29 error.
Hitting the enter key should not effect the read call unless you are reading from stdin (standard input). In that case, the input you provided - whitespace - may be printed out in the printf("%s", buff); call. If you could include some steps on how you found out that this is the method causing the issue or how you found out that it pauses at the read line (and if you are reading from /dev/stdin), it may be easier to help.
Consequently, the same printf call may never return, if the bytes read do not contain a null and the bytesRead count is 1024 - the string in buff would not be null terminated. You can fix this by either doing buff[1023] = '\0'; or by setting a length limit in the printf call like printf("%.1024s", buff);
do{
memset(buff,0,1024);
if((bytesRead=read(readFile,buff,1024))==-1)
{
printf("error reading file");
error = errno;
printf("%d",error);
}
else
printf("%s",buff);
}while(bytesRead==1024);
Your loop isn't correct. It assumes that read() fills the buffer; it fails if the file isn't a multiple of 1024 bytes; it corrupts errno before printing it; and it does unnecessary memset() operations. Honey it's a mess. It should look like this:
while ((bytesRead=read(readFile, buff, sizeof buff)) > 0)
{
printf("%.*s", bytesRead, buff);
}
if (bytesRead < 0)
{
error = errno;
perror("error reading file");
printf("errno=%d\n",error);
}
Related
I'm writing a function that perform some authentications actions. I have a file with all the user_id:password:flag couples structured like this:
Users.txt
user_123:a1b2:0 user_124:a2b1:1 user_125:a2b2:2
This is the code:
int main(){
/*...*/
/*user_id, password retrieving*/
USRPSW* p = malloc(sizeof(USRPSW));
if(p == NULL){
fprintf(stderr, "Dynamic alloc error\n");
exit(EXIT_FAILURE);
}
memset((void*)p, 0, sizeof(USRPSW));
if(usr_psw_read(acc_sock_ds, p->user_id, USR_SIZE) <= 0){
printf("Failed read: connection with %s aborted.\n",
inet_ntoa(client_addr.sin_addr));
close(acc_sock_ds);
continue;
}
if(usr_psw_read(acc_sock_ds, p->password, PSW_SIZE) <= 0){
printf("Failed read: connection with %s aborted.\n",
inet_ntoa(client_addr.sin_addr));
close(acc_sock_ds);
continue;
}
/*Authentication through user_id, password*/
FILE *fd;
fd = fopen(USERSFILE, "r");
if(fd == NULL){
fprintf(stderr, "Users file opening error\n");
exit(EXIT_FAILURE);
}
char *usr_psw_line = malloc(USR_SIZE+PSW_SIZE+3+1);
if(usr_psw_line == NULL){
fprintf(stderr, "Dynamic alloc error\n");
exit(EXIT_FAILURE);
}
while(1){
memset((void*)usr_psw_line, 0, sizeof(USR_SIZE+PSW_SIZE+3+1));
fgets(usr_psw_line, USR_SIZE+PSW_SIZE+3+1, fd);
printf("%s\n", usr_psw_line);
fseek(fd, 1, SEEK_CUR);
/*EOF management*/
/*usr_id - password matching checking */
}
/*...*/
}
How can I manage the EOF reaching? I saw that when EOF is reached fgets doesn't edits anymore the usr_psw_line but neither returns a NULL pointer. If EOF is reached it mean that no match are found in the users file and the loop breaks.
Can someone give me some tips or suggests?
fgets() return a null pointer when it reaches end-of-file or an error condition.
(EOF is a macro that specifies the value returned by certain other functions in similar conditions; it's not just an abbreviation for the phrase "end of file".)
You're ignoring the result returned by fgets(). Don't do that.
Note that just checking feof(fd) won't do what you want. feof() returns a true result if you've reached the end of the file. If you encounter an error instead, feof() still returns false, and you've got yourself an infinite loop if you're using feof() to decide when you're done. And it doesn't return true until after you've failed to read input.
Most C input functions return some special value to indicate that there's nothing more to read. For fgets() it's NULL, for fgetc() it's EOF, and so forth. If you like, you can call feof() and/or ferror() afterwards to determine why there's nothing more to read.
You might want to try something like this in your loop:
while(1)
{
memset((void*)usr_psw_line, 0, sizeof(USR_SIZE+PSW_SIZE+3+1));
if( !fgets(usr_psw_line, USR_SIZE+PSW_SIZE+3+1, fd)
|| ferror( fd ) || feof( fd ) )
{
break;
}
printf("%s\n", usr_psw_line);
fseek(fd, 1, SEEK_CUR);
/*EOF management*/
/*usr_id - password matching checking */
}
With the extra code, the loop will terminate if fgets returns NULL (no more data to read) or if you're read the EOF mark or had any error on the file. I'm sure it is overkill, but those tests have always worked for me.
void download(char *file)
{
int size = getsize(file);
printf("Got size %d\n", size);
sprintf(buff, "GET %s\n", file);
send(sockfd, buff, strlen(buff), 0);
rsize = recv(sockfd, buff, 1000, 0);
sscanf(buff, "%d", &resultcode);
printf("%s", buff);
if (strcmp(buff, "+OK\n") != 0)
{
printf("download failed\n");
}
FILE *dlfile = NULL;
if ((dlfile = fopen(file, "r")) != NULL)
{
dlfile = fopen(file, "w");
do
{
rsize = recv(sockfd, buff, 1000, 0);
for (int i = 0; i < rsize; i++)
{
fprintf(dlfile, "%c", buff[i]);
}
size = size - rsize;
} while (size != 0);
}
fclose(dlfile);
}
I am trying to make the download function print out contents of file user typed, then save it to their current directory. I did a debug line printf("%s", buff); and it prints out +OK\n(filename). It is supposed to print out +OK\n. It also prints out download failed then a segmentation fault error. What am I missing?
Several things going on here. First, recv and send basically operate on arrays of bytes so they do not know about line endings and such. Also note that recv is not guaranteed to fill the buffer - it generally reads what is available up to the limit of the buffer. For your strcmp against "+OK\n", you could use strncmp with a length of 4 but that is a bit direct (see below). Next note that the buff string is not null terminated by recv so your printf could easily crash.
When you go in to your loop, the buffer already has part of the rest of your I/O in it. May include other fields or parts of the file. You need to process it as well. It is not clear to me what getsize does - but using that size to drive your loop seems off. Also, your loop to fprintf the values can be replaced by a call to fwrite.
Overall, you need to properly buffer and then parse the incoming stream of data. If you want to do it yourself, you could look at fdopen to get a FILE object.
I have a function that reads a file from a server and returns the data:
int readMessageFromServer(int fileDescriptor) {
char buffer[MAXMSG];
int nOfBytes;
nOfBytes = read(fileDescriptor, buffer, MAXMSG);
if(nOfBytes < 0) {
perror("Could not read data from server\n");
exit(EXIT_FAILURE);
}
else
if(nOfBytes == 0)
return(-1);
else
printf("Server Message: %s\n", buffer);
return(0);
}
The problem is with the line
printf("Server Message: %s\n", buffer);
If I change this line to
printf("Server Message: %s\n>", buffer);
It refuses to print the '>' sign until it gets more data.
Is this a known limitation or am I doing something wrong?
I should probably add that the call to this function looks like this:
while(readMessageFromServer(sock) > 0) {continue;};
Besides the fact that you probably wanted to write the > inside the quotes, you'll need to flush the output buffer by calling fflush(stdout). The buffers are usually only flushed after newlines.
nOfBytes = read(fileDescriptor, buffer, MAXMSG);
There is no guarantee how many bytes you read or whether they constitute a null terminated string. At a minimum you should change to something like this:
int readMessageFromServer(int fileDescriptor) {
char buffer[MAXMSG];
int nOfBytes;
nOfBytes = read(fileDescriptor, buffer, MAXMSG - 1);
if(nOfBytes < 0) {
perror("Could not read data from server\n");
exit(EXIT_FAILURE);
}
else
if(nOfBytes == 0)
return(-1);
else
{
buffer[nOfBytes] = '\0';
printf("Server Message: %s\n", buffer);
return(0);
}
printf uses stdout which is a buffered output.
Changing printf with fprintf(stderr, ...) should solve your problem.
I'm writing a function that perform some authentications actions. I have a file with all the user_id:password:flag couples structured like this:
Users.txt
user_123:a1b2:0 user_124:a2b1:1 user_125:a2b2:2
This is the code:
int main(){
/*...*/
/*user_id, password retrieving*/
USRPSW* p = malloc(sizeof(USRPSW));
if(p == NULL){
fprintf(stderr, "Dynamic alloc error\n");
exit(EXIT_FAILURE);
}
memset((void*)p, 0, sizeof(USRPSW));
if(usr_psw_read(acc_sock_ds, p->user_id, USR_SIZE) <= 0){
printf("Failed read: connection with %s aborted.\n",
inet_ntoa(client_addr.sin_addr));
close(acc_sock_ds);
continue;
}
if(usr_psw_read(acc_sock_ds, p->password, PSW_SIZE) <= 0){
printf("Failed read: connection with %s aborted.\n",
inet_ntoa(client_addr.sin_addr));
close(acc_sock_ds);
continue;
}
/*Authentication through user_id, password*/
FILE *fd;
fd = fopen(USERSFILE, "r");
if(fd == NULL){
fprintf(stderr, "Users file opening error\n");
exit(EXIT_FAILURE);
}
char *usr_psw_line = malloc(USR_SIZE+PSW_SIZE+3+1);
if(usr_psw_line == NULL){
fprintf(stderr, "Dynamic alloc error\n");
exit(EXIT_FAILURE);
}
while(1){
memset((void*)usr_psw_line, 0, sizeof(USR_SIZE+PSW_SIZE+3+1));
fgets(usr_psw_line, USR_SIZE+PSW_SIZE+3+1, fd);
printf("%s\n", usr_psw_line);
fseek(fd, 1, SEEK_CUR);
/*EOF management*/
/*usr_id - password matching checking */
}
/*...*/
}
How can I manage the EOF reaching? I saw that when EOF is reached fgets doesn't edits anymore the usr_psw_line but neither returns a NULL pointer. If EOF is reached it mean that no match are found in the users file and the loop breaks.
Can someone give me some tips or suggests?
fgets() return a null pointer when it reaches end-of-file or an error condition.
(EOF is a macro that specifies the value returned by certain other functions in similar conditions; it's not just an abbreviation for the phrase "end of file".)
You're ignoring the result returned by fgets(). Don't do that.
Note that just checking feof(fd) won't do what you want. feof() returns a true result if you've reached the end of the file. If you encounter an error instead, feof() still returns false, and you've got yourself an infinite loop if you're using feof() to decide when you're done. And it doesn't return true until after you've failed to read input.
Most C input functions return some special value to indicate that there's nothing more to read. For fgets() it's NULL, for fgetc() it's EOF, and so forth. If you like, you can call feof() and/or ferror() afterwards to determine why there's nothing more to read.
You might want to try something like this in your loop:
while(1)
{
memset((void*)usr_psw_line, 0, sizeof(USR_SIZE+PSW_SIZE+3+1));
if( !fgets(usr_psw_line, USR_SIZE+PSW_SIZE+3+1, fd)
|| ferror( fd ) || feof( fd ) )
{
break;
}
printf("%s\n", usr_psw_line);
fseek(fd, 1, SEEK_CUR);
/*EOF management*/
/*usr_id - password matching checking */
}
With the extra code, the loop will terminate if fgets returns NULL (no more data to read) or if you're read the EOF mark or had any error on the file. I'm sure it is overkill, but those tests have always worked for me.
I am writing a utility which accepts either a filename, or reads from stdin.
I would like to know the most robust / fastest way of checking to see if stdin exists (data is being piped to the program) and if so reading that data in. If it doesn't exist, the processing will take place on the filename given. I have tried using the following the test for size of stdin but I believe since it's a stream and not an actual file, it's not working as I suspected it would and it's always printing -1. I know I could always read the input 1 character at a time while != EOF but I would like a more generic solution so I could end up with either a fd or a FILE* if stdin exists so the rest of the program will function seamlessly. I would also like to be able to know its size, pending the stream has been closed by the previous program.
long getSizeOfInput(FILE *input){
long retvalue = 0;
fseek(input, 0L, SEEK_END);
retvalue = ftell(input);
fseek(input, 0L, SEEK_SET);
return retvalue;
}
int main(int argc, char **argv) {
printf("Size of stdin: %ld\n", getSizeOfInput(stdin));
exit(0);
}
Terminal:
$ echo "hi!" | myprog
Size of stdin: -1
You're thinking it wrong.
What you are trying to do:
If stdin exists use it, else check whether the user supplied a filename.
What you should be doing instead:
If the user supplies a filename, then use the filename. Else use stdin.
You cannot know the total length of an incoming stream unless you read it all and keep it buffered. You just cannot seek backwards into pipes. This is a limitation of how pipes work. Pipes are not suitable for all tasks and sometimes intermediate files are required.
First, ask the program to tell you what is wrong by checking the errno, which is set on failure, such as during fseek or ftell.
Others (tonio & LatinSuD) have explained the mistake with handling stdin versus checking for a filename. Namely, first check argc (argument count) to see if there are any command line parameters specified if (argc > 1), treating - as a special case meaning stdin.
If no parameters are specified, then assume input is (going) to come from stdin, which is a stream not file, and the fseek function fails on it.
In the case of a stream, where you cannot use file-on-disk oriented library functions (i.e. fseek and ftell), you simply have to count the number of bytes read (including trailing newline characters) until receiving EOF (end-of-file).
For usage with large files you could speed it up by using fgets to a char array for more efficient reading of the bytes in a (text) file. For a binary file you need to use fopen(const char* filename, "rb") and use fread instead of fgetc/fgets.
You could also check the for feof(stdin) / ferror(stdin) when using the byte-counting method to detect any errors when reading from a stream.
The sample below should be C99 compliant and portable.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
long getSizeOfInput(FILE *input){
long retvalue = 0;
int c;
if (input != stdin) {
if (-1 == fseek(input, 0L, SEEK_END)) {
fprintf(stderr, "Error seek end: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (-1 == (retvalue = ftell(input))) {
fprintf(stderr, "ftell failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (-1 == fseek(input, 0L, SEEK_SET)) {
fprintf(stderr, "Error seek start: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
} else {
/* for stdin, we need to read in the entire stream until EOF */
while (EOF != (c = fgetc(input))) {
retvalue++;
}
}
return retvalue;
}
int main(int argc, char **argv) {
FILE *input;
if (argc > 1) {
if(!strcmp(argv[1],"-")) {
input = stdin;
} else {
input = fopen(argv[1],"r");
if (NULL == input) {
fprintf(stderr, "Unable to open '%s': %s\n",
argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
}
} else {
input = stdin;
}
printf("Size of file: %ld\n", getSizeOfInput(input));
return EXIT_SUCCESS;
}
You may want to look at how this is done in the cat utility, for example.
See code here.
If there is no filename as argument, or it is "-", then stdin is used for input.
stdin will be there, even if no data is pushed to it (but then, your read call may wait forever).
You can just read from stdin unless the user supply a filename ?
If not, treat the special "filename" - as meaning "read from stdin". The user would have to start the program like cat file | myprogram - if he wants to pipe data to it, and myprogam file if he wants it to read from a file.
int main(int argc,char *argv[] ) {
FILE *input;
if(argc != 2) {
usage();
return 1;
}
if(!strcmp(argv[1],"-")) {
input = stdin;
} else {
input = fopen(argv[1],"rb");
//check for errors
}
If you're on *nix, you can check whether stdin is a fifo:
struct stat st_info;
if(fstat(0,&st_info) != 0)
//error
}
if(S_ISFIFO(st_info.st_mode)) {
//stdin is a pipe
}
Though that won't handle the user doing myprogram <file
You can also check if stdin is a terminal/console
if(isatty(0)) {
//stdin is a terminal
}
Just testing for end of file with feof would do, I think.
Note that what you want is to know if stdin is connected to a terminal or not, not if it exists. It always exists but when you use the shell to pipe something into it or read a file, it is not connected to a terminal.
You can check that a file descriptor is connected to a terminal via the termios.h functions:
#include <termios.h>
#include <stdbool.h>
bool stdin_is_a_pipe(void)
{
struct termios t;
return (tcgetattr(STDIN_FILENO, &t) < 0);
}
This will try to fetch the terminal attributes of stdin. If it is not connected to a pipe, it is attached to a tty and the tcgetattr function call will succeed. In order to detect a pipe, we check for tcgetattr failure.