Ive got a function here that blocks on fgets but when I print something before fgets it doesn't block.
int exec_command(char *command, char *output_buf, int buf_size)
{
FILE* pipe = NULL;
char buffer[BUFFER_SIZE];
char tmp[SMALL_BUFFER_SIZE];
unsigned total_read = 0;
pipe = popen( command, "r");
if( !pipe )
{
//Error
return -1;
}
memset(buffer, 0, sizeof(buffer));
while( !feof(pipe) )
{
//printf("reading"); //If I uncomment this fgets doesnt block
if( fgets(tmp, sizeof(tmp), pipe) != NULL )
{
// check that it'll fit:
size_t len = strlen(tmp);
if (total_read + len >= sizeof(buffer))
break;
// and add it to the big buffer if it fits
strcat(buffer, tmp);
total_read += len;
}
}
//Is there anything to copy
if ( total_read )
strncpy (output_buf, buffer, buf_size);
return pclose(pipe);
}
Is there anything wrong on my function above?
Its because whatever is writing your pipe isn't flushing its out buffer. When you print, it ends up flushing that (not garenteed to happen though). When you don't print, the pipe isn't actually getting written to because its because stored in a kernel buffer until it fills, and then the kernel will write the data. Call fsync or flush on the pipe fd in the process that is writing to the pipe to make sure that the kernel buffer is flushed.
Add a new-line to the print-statement. It is (probably) line-buffered, and doesn't print until a new-line is encountered, you call fflush.
Related
I need to read from stdin and fill a buffer of _SC_PAGESIZE (from sysconf()) until stdin is at EOF. This program is supposed to be a wc clone, so I would be expecting something like the contents of a regular file to be passed in. If the buffer isn't big enough for stdin, then I have to keep filling it, process it for information, then clear it and continue to fill the buffer again from the file offset in stdin. I'm just having a problem with tracking the EOF of stdin, and I'm getting an infinite loop. Here's what I have:
int pSize = sysconf(_SC_PAGESIZE);
char *buf = calloc(pSize, sizeof(char));
assert(buf);
if (argc < 2) {
int fd;
while (!feof(stdin)) {
fd = read(0, buf, pSize);
if (fd == -1)
err_sys("Error reading from file\n");
lseek(0, pSize, SEEK_CUR);
if (fd == -1)
err_sys("Error reading from file\n");
processBuffer(buf);
buf = calloc(pSize, sizeof(char));
}
close(fd);
}
I'm assuming the problem has to do with the test condition (while (!feof(stdin)), so I guess what I need is a correct test condition to exit the loop.
Why are you using a low-level read instead of opening a FILE *stream and using fgets (or POSIX getline)? Further, you leak memory every time you call:
buf = calloc(pSize, sizeof(char));
in your loop because you overwrite the address contained in buf losing the reference to the previous block of memory making it impossible to free.
Instead, allocate your buffer once, then continually fill the buffer passing the filled buffer to processBuffer. You can even use a ternary operator to determine whether to open a file or just read from stdin, e.g.
int pSize = sysconf(_SC_PAGESIZE);
char *buf = calloc(pSize, sizeof(char));
assert(buf);
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) {
perror ("fopen failed");
return 1;
}
while (fgets (buf, pSize, fp))
processBuffer(buf); /* do not call calloc again -- memory leak */
if (fp != stdin) fclose (fp); /* close file if not stdin */
(note: since fgets will read a line-at-a-time, you can simply count the number of iterations to obtain your line count -- provided your lines are not longer than _SC_PAGESIZE)
If you want to use exact pSize chunks, then you can use fread instead of fgets. The only effect would be to reduce the number of calls to processBuffer marginally, but it is completely up to you. The only thing that you would need to do is change the while (...) line to:
while (fread (buf, (size_t)pSize, 1, fp) == 1)
processBuffer(buf); /* do not call calloc again -- memory leak */
if (ferror(fp)) /* you can test ferror to insure loop exited on EOF */
perror ("fread ended in error");
(note: like read, fread does not insure a nul-terminated string in buf, so insure that processBuffer does not pass buf to a function expecting a string, or iterate over buf expecting to find a nul-terminating character at the end.)
Look things over and let me know if you have further questions.
You can write the loop like
int n;
do {
n = read(0, buf, pSize);
// process it
} while(n > 0);
Remember EOF is just one exit condition that may not occur before any other error condition occurs. True check for validity to run the loop is a healthy return code from read. Also, note that condition while(n > 0) is enough or not depends on where you are reading from. In case of stdin it may be enough. But for example for sockets the condition can be written like while(n > 0 || errno == EAGAIN)
For an assignment, I'm supposed to create two methods: Method one will read() and write() the input file to an empty output file, one byte at a time (slowly).
The other method will instead use char buf[BUFSIZ]; where BUFSIZ is from <stdio.h>. We are supposed to read() and write() with the BUFSIZ which will make things a lot faster.
The input file we test each method on is just a linux dictionary (/dict/linux.words).
I've correctly implemented method one, where I call read() and write() on one character at a time, copying the input file to the output file. Although it's very slow, it at least copies everything over.
My code for this looks like this:
// assume we have a valid, opened fd_in and fd_out file.
char buf;
while(read(fd_in, buf, 1) != 0)
write(fd_out, buf, 1);
For method two however, where I use BUFSIZ, I am not able to transfer every single entry into the output file. It fails in the z entries, and doesn't write anymore.
So, my first try:
// assume we have a valid, opened fd_in and fd_out file
char buf[BUFSIZ];
while(read(fd_in, buf, BUFSIZ) != 0)
write(fd_out, buf, BUFSIZ);
doesn't work.
I understand that read() will return either the number of bytes read or 0 if it is at the end of a file. The problem I'm having is understanding how I can compare read() to BUFSIZ, and then loop around and start read() at where it left off until I reach the real end of file.
Since your file will most likely not be an exact multiple of BUFSIZ you need to check for the actual number of bytes read, so that the last block will be written correctly, e.g.
char buf[BUFSIZ];
ssize_t n;
while((n = read(fd_in, buf, BUFSIZ)) > 0)
write(fd_out, buf, n);
this code:
// assume we have a valid, opened fd_in and fd_out file
char buf[BUFSIZ];
while(read(fd_in, buf, BUFSIZ) != 0)
write(fd_out, buf, BUFSIZ);
leaves much to be desired,
does not handle a short remaining char count at the end of the file,
does not handle errors, etc.
a much better code block would be:
// assume we have a valid, opened fd_in and fd_out file
char buf[BUFSIZ];
int readCount; // number of bytes read
int writeCount; // number of bytes written
while(1)
{
if( 0 > (readCount = read(fd_in, buf, BUFSIZ) ) )
{ // then, read failed
perror( "read failed" );
exit( EXIT_FAILURE );
}
// implied else, read successful
if( 0 == readCount )
{ // then assume end of file
break; // exit while loop
}
// implied else, readCount > 0
if( readCount != (writeCount = write( fd_out, buf, readCount ) ) )
{ // then, error occurred
perror( "write failed" );
exit( EXIT_FAILURE );
}
// implied else, write successful
} // end while
Note: I did not include the closing of input/output files statements
before each call to exit() however, that does need to be added
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
I am trying to switch modem to command mode, write AT command and parse the response, but I am not too good with C and I do not understand what is wrong. The code I am calling is:
void switch_to_command_mode(int uart)
{
current_command_type = BTCommandTypeSwitchToATMode;
char switchCmd[] = "\x2F\x2F\x2F";
char emptySymbol[] = " ";
char checkAT[] = "AT\r";
ssize_t len = 0;
write(uart, emptySymbol, strlen(emptySymbol));
sleep(1);
write(uart, switchCmd, strlen(switchCmd));
sleep(1);
write(uart, checkAT, strlen(checkAT));
char buffer[255]; /* Input buffer */
char *bufptr; /* Current char in buffer */
int nbytes;
bufptr = buffer;
while (ioctl(uart, FIONREAD, (unsigned long)&len) == 0 && len < 2) {
warnx("waiting");
usleep(1000);
}
while ((nbytes = read(uart, bufptr, buffer + sizeof(buffer) - bufptr - 1)) > 0)
{
bufptr += nbytes;
warnx("buffer %s", buffer);
if (bufptr[-1] == '\n' || bufptr[-1] == '\r')
break;
}
warnx("Final buffer: %s", buffer);
if (strncmp(buffer, "OK", 2) == 0) {
warnx("Great success!");
}
}
What I get as console output is:
waiting
waiting
buffer AT
O p �0
buffer AT
OK
�0
Final buffer: AT
OK
�0
According to documentation for the BT Module, the response should be in form of <CR><LF>OK<CR><LF>.
Any guidance on why this is possibly happening and what can I do with that would be highly appreciated.
P.S. I also already went through Serial programming for POSIX OS.
In C a "string" needs to be 0-terminated.
If they are not before being processed (printed here) the program runs into undefined behaviour. Which could also lead to "garbage" being printed.
To fix this easily initialise the buffer used to all 0s before using it, by doing:
char buffer[255] = "";
Also read() returns ssize_t not int. So you better do:
ssize_t nbytes;
I have to write a SSL client in C that connects to a server,and gets either a html,either a file. I managed to get the html,but i can't download a binary file. For example,i'm trying to download a 3.8mb file from https://www.openssl.org/source/openssl-1.0.0d.tar.gz and my code only manages to download 1.1mb of them,and i don't even know if i get the right data in it.
Here is the function that i made for it:
char *sslReadfile (connection *c)
{
const int readSize = 1024;
char *rc = NULL;
int received, count = 0;
char buffer[1024];
char filename[40];
printf("Input the file name to be saved:\n");
scanf("%s",filename);
FILE *fp;
fp = fopen(filename, "wb");
if (c)
{
while (1)
{
if (!rc)
rc = malloc (readSize * sizeof (char) + 1);
else
rc = realloc (rc, readSize * sizeof (char) + 1);
received = SSL_read (c->sslHandle, buffer, readSize);
buffer[received] = '\0';
if (received > 0)
fprintf(fp,"%s",buffer);//strcat (rc, buffer);
if (received < readSize)
break;
//count++;
}
}
printf("\nFile saved!! %s !!!\n\n",filename);
fclose(fp);
return rc;
}
oh, and i call it like that:
char command[50];
sprintf(command,"GET /%s\r\n\r\n",relativepath);
sslWrite (c, command);
response = sslReadfile (c);
where c is my connection.
Don't use fprintf to write binary data. Use fwrite. The reason your output is smaller is that fprintf is stopping at the first null character, skipping any characters that remain in the 1024 byte buffer. Also, you don't appear to be using, and don't need the mallocd rc buffer.
So, after the call to SSL_read, you want something like this:
if (received <= 0) break;
fwrite(buffer, 1, received, fp);
You break the loop when received < readSize, instead you should only break the loop when received <= 0 and you have inspected SSL_shutdown() and/or SSL_get_error().
Also, you shouldn't NUL terminate your buffer and use fprintf, but keep the buffer as is while using fwrite. You are now introducing NULs in your data that weren't there.