I've written a user space program to read from a kernel device line by line, somehow, the data is always overriden with each read. Can you please tell me how to fix my code?
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#define BUFFER_LENGTH 256
int main()
{
int ret,fd;
char buffer[BUFFER_LENGTH];
FILE * fPtr;
unsigned int i=0;
if((fd = open("/dev/show_log_device_dev", O_RDWR)) == -1){
perror("Failed to open the file");
}
//printf("/dev/show_log_device_dev opened.\n");
//fflush(stdout);
fPtr = fopen("log.txt", "w ");
int bytesRead = 0;
while (bytesRead < sizeof(buffer)) {
int ret = read(fd, buffer bytesRead, sizeof(buffer) - bytesRead);
if (ret == 0)
break;
if (ret == -1) {
perror("Failed to read the message from the device.");
return errno;
/* Handle error */
}
bytesRead = ret;
printf("read from /dev/show_log_device_dev. %s\n",buffer);
}
if(lseek(fPtr,0,SEEK_SET)!=0) {
fprintf(fPtr,"%s",buffer);
}
fclose(fPtr);
}
I would like the output file "log.txt" to contain all the lines written to buffer with each read line after line sith skip-line between lines. Please show me the proper way to do it inctead of the fprintf attempt I've written above.
Thank you.
CodePudding user response:
char buffer[BUFFER_LENGTH];
while()
{...read(fd, buffer bytesRead, sizeof(buffer) - bytesRead);}
This line is a major problem. Basically this attempts to store the entire file in to buffer
. But buffer
has a small size (256 bytes).
If file is too large, read
will store 256 in to buffer
in the first pass. In the second pass in the loop, read
will attempt to add another 256 bytes to the same buffer.
Instead you have to read small chunks and write back within the loop.
fPtr = fopen("log.txt", "w ");
This will open the log file in read/write mode, but you only need to write to it. Since this is a log file, consider using "a"
option to append to the log file.
fprintf(fout, "%s", buffer);
When you read the buffer it may not be null terminated. Try fwrite
instead, or make sure buffer
is null terminated before using fprintf
#define BUFFER_LENGTH 256
int main()
{
int fd = open("/dev/show_log_device_dev", O_RDONLY);
if(fd == -1)
{ perror("open failed"); return 0; }
FILE* fout = fopen("log.txt", "w"); //or "a" to create new file
if(fout == NULL)
{ close(fd); perror("fopen failed, log.txt is busy!"); return 0; }
while (1)
{
char buffer[BUFFER_LENGTH];
int ret = read(fd, buffer, sizeof(buffer));
if (ret == 0)
break;
if (ret == -1)
{
perror("Failed to read the message from the device.");
return errno;
}
fwrite(buffer, 1, ret, fout);
//fprintf(fout, "%s", buffer);
}
fclose(fout);
close(fd);
return 0;
}
Note, lseek(fPtr,0,SEEK_SET)
is wrong and not necessary. This method is excepts a file descriptor obtained from open
. But fPtr
is FILE*
handle obtained from fopen
.
If possible, consider using standard c functions FILE*/fopen
for both input and output. This way you will be able to use the same set of functions fopen
,fread
,fwrite
,fclose
,fseek
,ftell
. You only need one header file for this:
#include <stdio.h>
int main()
{
FILE* fin = fopen("/dev/show_log_device_dev", "r");
if (!fin)
{ perror("input error"); return 0; }
FILE* fout = fopen("log.txt", "w"); //or "a" to append to log
if (!fout)
{fclose(fin); perror("output error, log.txt is busy!"); return 0; }
while (1)
{
char buffer[256];
int ret = fread(buffer, 1, sizeof(buffer), fin);
if (ret == 0)
break;
fwrite(buffer, 1, ret, fout);
}
fclose(fout);
fclose(fin);
return 0;
}