I am little bit ruggy with C coding, but I need this script working to test serial communication with a microcontroller. I have the following code written as:
int main() {
char *portname = "/dev/ttyACM0";
FILE *csv = fopen("~/Desktop/my.csv", "wb");
int fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0)
{
//error_message ("error %d opening %s: %s", errno, portname, strerror (errno));
return 1;
}
set_interface_attribs (fd, B9600, 0); // set speed to 9600 bps, 8n1 (no parity)
set_blocking (fd, 1); // set no blocking
char a = 255;
int i = 0;
write(fd, &a, 1);
do {
char c;
read(fd, &c, 1); // wait for next value
fprintf(csv, "%d\n", c);
i ++;
} while(i < 10000); //keep running this loop for a while
write(fd, &a, 1);
fclose(csv);
close(fd);
return 0;
This scripts should connect successfully for serial communication, send a start bit (255) to the receiver which operates some actions, and then start writing received data on csv file until the while loop ends up. Have compiled that source with the instruction:
g++ -o serial c-serial.c
where c-serial.c is the name of the source code. Just skip the two "set" function, they are visible in this scope so the error comes not out of this. In fact, when executing I receive:
Segmentation fault (core dumped)
How do I fix it?
Function call fopen is not able to resolve ~ as your home directory. Please take a look at how to open a file in user's home folder.
In your fprintf statement you tell the programm to print an integer (usually two bytes) but provide a char variable (one byte) to print from. fprintf relies on the supplied format string to decide how many bytes to read from the source. In this case fprintf tries to read (at least) two bytes from a one-byte-memory block. Therefore fprintf will try to access memory which might not even be allocated to the program, producing a segmentation fault.
Correct the format string to print a character only.
For more information on fprintf and format strings see here.
Related
EDIT 3
THE FILE CONTAINS BYTES - I guess I have to sort the bytes, the task doesn't say more - it says that I pass an argument - the name of a binary file that contains bytes - that's it. And I am trying to work with low-level funcs.
I am trying to sort a binary file using qsort but I got stuck - I dont know how to write the content of a file to a buffer so I could pass it to qsort
What I have done:
int main(int argc, char*argv[]){
int fd1;
if((fd1=open(argv[1], O_RDONLY))==-1){
printf("Error occurred while opening the file");
exit(-1);
}
int size;
char c;
while(read(fd1, &c, 1)){
size=size+1;
}
size=size+1;
close(fd1);
fd1=open(argv[1], O_RDONLY);
if(fd1==-1){
printf("Error occured while opening the file");
}
char*buffer;
buffer=malloc(size);
setbuf(fd1, buffer);
//EDIT I TRIED THIS AND IT STILL DOES NOT WORK
int i=0;
while(read(fd1, &c, 1)){
buffer[i]=c;
i++;
}
for(int i=0; i<size;i++){
printf("lele %s", buffer[i]);
}
//EDIT 2: after making buffer[i]=c I get this error Segmentation fault
}
SetBuf does not work this way.. How to make it work? Also, I am trying to use func like open, close, read, write, etc.
Your algorithm for reading a file into a buffer is good:
Open the file
Count bytes in file
Close the file
Allocate the buffer
Open the file
Read the file
Close the file
A bit inefficient, because you read the file twice, but that's fine. You just have to implement it properly; any small mistake will make it look like it doesn't work. Use a debugger to check each step.
Here is my try. I didn't debug, to not deny you the "fun" of debugging. I put comments instead.
int main(int argc, char*argv[])
{
// 1. Open the file
int fd1;
if((fd1=open(argv[1], O_RDONLY))==-1){
printf("Error occurred while opening the file");
exit(-1);
}
// 2. Count bytes in file
int size = 0;
char c;
while(read(fd1, &c, 1))
size=size+1;
// To check that this part is good, print the size here!
// 3. Close the file
close(fd1);
// Allocate the buffer
char *buffer;
buffer = malloc(size);
// Might want to print the buffer here, to make sure it's not NULL
// 5. Open the file
fd1=open(argv[1], O_RDONLY);
if(fd1==-1){
printf("Error occurred while opening the file");
}
// 6. Read the file
for (int index = 0; index < size; ++index)
read(fd1, &buffer[index], 1);
// Might want to print what "read" returns in each iteration, to make sure it's successful
// 7. Close the file
close(fd1);
}
As noted by Eric Postpischil, the algorithm is actually not good.
The size of the file at one time does not guarantee the size at another time.
If you want to do that correctly, you must read the file only once. This will make the allocation harder: you cannot calculate the required buffer size, so you have to "guess" an initial size and use realloc.
However, in this small example, this is clearly not the requirement - you can probably ignore the possibility of the file changing asynchronously.
There is another possible problem - I/O error on the file when you read it the second time. This is easy to check, so maybe you should add it.
In the code below, I am trying to read from a socket and store the results in a file.
What actually happens, is that my client sends a GET request to my server for a file.html. My server finds the file and writes the contents of it to the socket. Lastly my client reads the content from thread_fd and recreates the file.
For some reason the recreated file has less content than the original. I have located the problem to be some lines in the end, that are missing. When I use printf("%s", buffer) inside the while loop everything seems fine in STDOUT but my fprintf misses somewhat 3.000 bytes for a file of 81.000 bytes size.
#define MAXSIZE 1000
int bytes_read, thread_fd;
char buffer[MAXSIZE];
FILE* new_file;
memset(buffer, 0, MAXSIZE);
if((new_file = fopen(path, "wb+")) == NULL)
{
printf("can not open file \n");
exit(EXIT_FAILURE);
}
while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0)
{
fprintf(new_file, "%s", buffer);
if(bytes_read < MAXSIZE)
break;
memset(buffer, 0, MAXSIZE);
}
You read binary data from the socket that may or may not contain a \0 byte. When you then fprintf that data the fprintf will stop at the first \0 it encounters. In your case that is 3000 bytes short of the full file. If your file contains no \0 byte the fprintf will simply continue printing the ram contents until it segfaults.
Use write() to write the data back to the file and check for errors. Don't forget to close() the file and check that for errors too.
Your code should/could look like:
int readfile(int thread_fd, char *path)
{
unsigned int bytes_read;
char buffer[MAXSIZE];
int new_file;
if ((new_file = open(path, _O_CREAT|_O_BINARY,_S_IWRITE)) == -1) return -1;
while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0)
{
if (write(new_file, buffer, bytes_read)!= bytes_read) {
close(new_file);
return -2;
}
}
close(new_file);
return 0;
}
There are a few issues with your code that can cause this.
The most likely cause is this :
if(bytes_read < MAXSIZE)
break;
This ends the loop when read returns less than the requested amount of bytes. This is however perfectly normal behavior, and can happen eg. when not enough bytes are available at the time of the read call (it's reading from a network socket after all). Just let the loop continue as long as read returns a value > 0 (assuming the socket is a blocking socket - if not, you'll also have to check for EAGAIN and EWOULDBLOCK).
Additionally, if the file you're receiving contains binary data, then it's not a good idea to use fprintf with "%s" to write to the target file. This will stop writing as soon as it finds a '\0' byte (which is not uncommon in binary data). Use fwrite instead.
Even if you're receiving text (suggested by the html file extension), it's still not a good idea to use fprintf with "%s", since the received data won't be '\0' terminated.
This worked!
ps: I don't know if I should be doing this, since I am new here, but really there is no reason for negativity. Any question is a good question. Just answer it if you know it. Do not judge it.
#define MAXSIZE 1000
int bytes_read, thread_fd, new_file;
char buffer[MAXSIZE];
memset(buffer, 0, MAXSIZE);
if((new_file = open(path, O_RDONLY | O_WRONLY | O_CREAT)) < 0)
{
printf("can not open file \n");
exit(EXIT_FAILURE);
}
while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0)
write(new_file, buffer, bytes_read);
close(new_file);
I'm trying to make a program that would copy 512 bytes from 1 file to another using said system calls (I could make a couple buffers, memcpy() and then fwrite() but I want to practice with Unix specific low level I/O). Here is the beginning of the code:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
int src, dest, bytes_read;
char tmp_buf[512];
if (argc < 3)
printf("Needs 2 arguments.");
printf("And this message I for some reason don't see.... o_O");
if ((src = open(argv[1], O_RDWR, 0)) == -1 || (dest = open(argv[2], O_CREAT, 0)) == -1)
perror("Error");
while ((bytes_read = read(src, tmp_buf, 512)) != -1)
write(dest, tmp_buf, 512);
return 0;
}
I know I didn't deal with the fact that the file read from isn't going to be a multiple of 512 in size. But first I really need to figure out 2 things:
Why isn't my message showing up? No segmentation fault either, so I end up having to just C-c out of the program
How exactly do those low level functions work? Is there a pointer which shifts with each system call, like say if we were using FILE *file with fwrite, where our *file would automatically increment, or do we have to increment the file pointer by hand? If so, how would we access it assuming that open() and etc. never specify a file pointer, rather just the file ID?
Any help would be great. Please. Thank you!
The reason you don't see the printed message is because you don't flush the buffers. The text should show up once the program is done though (which never happens, and why this is, is explained in a comment by trojanfoe and in an answer by paxdiablo). Simply add a newline at the end of the strings to see them.
And you have a serious error in the read/write loop. If you read less than the requested 512 bytes, you will still write 512 bytes.
Also, while you do check for errors when opening, you don't know which of the open calls that failed. And you still continue the program even if you get an error.
And finally, the functions are very simple: They call a function in the kernel which handles everything for you. If you read X bytes the file pointer is moved forward X bytes after the call is done.
The reason you don't see the message is because you're in line-buffered mode. It will only be flushed if it discovers a newline character.
As to why it's waiting forever, you'll only get -1 on an error.
Successfully reading to end of file will give you a 0 return value.
A better loop would be along the lines of:
int bytes_left = 512;
while ((bytes_left > 0) {
bytes_read = read(src, tmp_buf, bytes_left);
if (bytes_read < 1) break;
write(dest, tmp_buf, bytes_read);
bytes_left -= bytes_read;
}
if (bytes_left < 0)
; // error of some sort
I am trying to use stderr but i am totally confused with respect to its usage.I was about to reply to a question asked here but when i think to try it first , i find myself stucked.
I read about stderr in this link,and as per the information i tried to use it like this
FILE *stderr;
stderr = fopen("<path to file>","w");
.....//some code and conditions
fprintf(stderr,"found a error here");
using this gives me a seg fault, which i wasn't able to figure out why?
then i used freopen(), then also i get the seg fault.Is stderr byitself send the standard err if any to some default file instead of stdout.
Here is my code in which i am only trying to use stderr as any other FILE * pointer.May i am totlly takingit as wrong way to execute.Or it only write standard compiler errors to some default file.Need help.
#include<stdio.h>
#include<string.h>
#include<time.h>
FILE *stderr;
int main()
{
time_t start,end;
volatile long unsigned counter;
start = time(NULL);
for(counter = 0; counter < 500000000; counter++)
{}
int i;
char str1[]="XXXXXXX-XXXXXXXXX-YYYYYYYY-TTTTTT";
char str2[]="pro1_0.0";
char str3[]="CC";
char str4[]="ZZ";
char str5[]="QQ";
char serialstring[100];
stderr = fopen("path to file","w");
//freopen("llog.out","w",stderr);
printf("enter a serial string:");
scanf("%s",serialstring);
if((strstr(serialstring,str1)))
{
printf("String1 matched\n");
if((strstr(serialstring,str2)))
{
fprintf(stderr,"str2 matched\n"); //it is where i tried using fprintf and stderr, rest of code is working pretty file
if((strstr(serialstring,str3)))
{
printf("str3 matched\n");
}
else if((strstr(serialstring,str4)))
{printf("str4 matched\n");}
else if((strstr(serialstring,str5)))
{printf("str5 matched\n");
for(i=232;i<290;i++)
{
printf("Sending some values: %d\n",i);}}
}
else{printf("str2 not matched\n");}
}
else{printf("str1 not matched\n");}
end = time(NULL);
printf("The loop used %f seconds.\n", difftime(end, start));
return 0;
}
You are not supposed to try to override stderr yourself. Just use it. It's provided to you by the program that's running your program. If your program is being run interactively from a shell on a terminal, then both stdout and stderr normally go to the terminal, but there are plenty of ways that could be overridden. The most common way it's overridden is that the caller has redirected stdout to a file, to save the output, but left stderr connected to the terminal so that the user can see status/error messages.
Use dup2():
int fd = open("mylog.txt", O_RDWR | O_APPEND | O_CREAT);
if (fd < 0) {
printf("Cannot open mylog.txt!\n");
exit(1);
}
if (dup2(fd, STDERR_FILENO) < 0) {
printf("Cannot redirect stderr!\n");
exit(1);
}
From this point on, any writes to stderr will go to "mylog.txt".
You can use similar approach to redirect stdout as well - just use STDOUT_FILENO.
I have got a small program that prints the contents of files using the system call - read.
unsigned char buffer[8];
size_t offset=0;
size_t bytes_read;
int i;
int fd = open(argv[1], O_RDONLY);
do{
bytes_read = read(fd, buffer, sizeof(buffer));
printf("0x%06x : ", offset);
for(i=0; i<bytes_read; ++i)
{
printf("%c ", buffer[i]);
}
printf("\n");
offset = offset + bytes_read;
}while(bytes_read == sizeof(buffer));
Now while running I give a file name that doesn't exist.
It prints some kind of data mixed with environment variables and a segmentation fault at the end.
How is this possible? What is the program printing?
Thanks,
John
It's printing rubbish because fd will invariably be set to -1 which is not a good thing to pass to read since it will, in turn do nothing other than return -1 as well. It will leave your buffer untouched meaning that it's holding whatever rubbish you had in there when you started.
You could probably put the entire do loop inside something like:
if (fd == -1) {
printf ("error here");
} else {
// do loop here
}
read is returning -1 because fd is invalid, you store that in bytes_read which is of type size_t which is unsigned, so your loop prints (size_t)-1 chars, which is a very large number, much larger than the size of buffer. So, you're printing a big chunk of your address space and then getting a segfault when you eventually reach the end and access an invalid address.
As others have mentioned (without answering your actual question), you should be checking the results of open for an error. e.g.,
int fd = open(argv[1], O_RDONLY);
if( fd < 0 ){
fprintf(stderr, "error opening %s: %s\n", argv[1], strerror(errno));
exit(1);
}
A caveat: if you do another system call, or call any routine that might do a system call (e.g., printf) before calling strerror, you must save errno and then pass the saved copy to strerror.
Another note about your program:
while(bytes_read == sizeof(buffer))
This is not a good test, because read can return less than the amount you ask for. Your loop should continue until read returns <= 0.
You should probably check that the file descriptor returned by open is valid before using it. As per these docs, you should get a non-negative response for a valid file. Reading from an invalid descriptor is likely the source of your problem.
Upon successful completion, open function shall open the file and return a non-negative integer representing the file descriptor. Otherwise, -1 shall be returned and errno set to indicate the error. So please check fd before entering the loop to perform the read.