int main(int argc,char* argv[]){
int fd;
off_t foffset;
char* fpath;
char* rbuf;
if(argc!=2){
printf("insert filename as argument!\n");
exit(1);
}
strcpy(fpath,argv[1]);
if( (fd = open(fpath,O_RDWR | O_APPEND)) <0 )
perror("error on open()");
//try to use lseek in file opened in O_APPEND mode
char buf[] = "I'm appending some text!\n";
if( write(fd, buf , sizeof(buf)) <0 )
perror("error on write()");
printf("the write() operation was succesful, let's try to seek and read the file..\n");
foffset = lseek(fd,0L,SEEK_CUR);
if(foffset<0)
perror("error on lseek() :");
close(fd);
return 0;
}
Why does it generate a segmentation fault when I execute this code??
The segFault occurs only if the lseek operation is added, otherwise is fine.
fpath is a wild pointer, i.e. you haven't allocated any storage for it before you call strcpy. However since you only need a const char * for the file name you can just make the following change.
Change:
strcpy(fpath,argv[1]);
to:
fpath = argv[1];
If you want to use fpath separately, change your definition:
char fpath[30];
Now your strcpy will work as expected (though you should check the length of the string is under 30). You can just pass argv[1] directly, however, to open, since you're not doing anything else with it.
Related
I am trying to write a struct to a .dat file and when I open it it shows me this:
"1^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#041720881^#^#^#^#^#^#^#^#^#^#^#Denko^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#Brenko^#^#^#^#^#^#^#^#^#^#^#^#^#^#13.07.2000^#^#^#^#^#^#^#^#^#^#
"
It adds random symbols between the actual values. And now when I at least try to read and print some values, it just doesn't work. It's like the buffer is empty. But I followed the instructions and guides I read.
Using fwrite or similar is not an option since I have to work with these specific functions write() and read().
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
struct info{
char id[20];
char telefon[20];
char ime[20];
char priimek[20];
char datum[20];
};
int main(int argc, char* argv[]) {
struct info dude =
{
"01",
"041720881",
"Denko",
"Brenko",
"13.07.2000"
};
struct info dude2 =
{
"02",
"041581734",
"Denko",
"Badenko",
"13.07.1990"
};
if(strcmp(argv[1], "-c") == 0){
int fd = open("xpo.dat", O_CREAT| O_APPEND | S_IRWXG, 0666);
if(fd == -1){
perror("Error while creating file");
exit(EXIT_FAILURE);
}
}
else if(strcmp(argv[1], "-o") == 0){
struct stat sizefile;
int fd = open("xpo.dat", O_RDWR);
if(fd == -1){
perror("Error while opening file");
exit(EXIT_FAILURE);
}
fstat(fd,&sizefile);
int wr = write(fd, &dude,sizeof(struct info));
char buf[101];
int sz = read(fd, buf, 100);
buf[sz] = '\0';
if(sz == -1) {
perror("Error while creating file");
exit(EXIT_FAILURE);
}
printf("%s", buf);
int cl = close(fd);
}
return 0;
}
The struct contains 100 chars of data. But you are setting only some of them. When you set ime as Denko, the first six chars are set as 'D', 'e', 'n', 'k', 'o','\0'. The remaining 14 are not initialized (or rather initialized implicitly, see #dave_thompson_085's comment below).
If you want to omit those chars, you cannot write the struct as one block. Either write each field separately, or concatenate the fields into a string and write it instead.
As stated in the comments and in the accepted answer, you have some issues, the why and the what is already talked about and explained.
I would like to add some more information:
And now when I at least try to read and print some values, it just doesn't work. It's like the buffer is empty.
What happens is that you are reading from the end of the file, if you want to read after you write without closing and reopening the file, you can, but you'll need to reposition the offset of the opened file to the beginning using lseek.
Another thing to note is that if you want to write the data as a structure you then need to read it as a structure as well, not as a string.
Taking that in consideration your code could look more or less like this (skipping return value validations, but you should do it, as you know):
//...
else if(strcmp(argv[1], "-o") == 0){
int fd = open("xpo.dat", O_RDWR);
int wr = write(fd, &dude, sizeof dude);
lseek(fd, 0, SEEK_SET); // set the reading position to the beginning of the file
struct info buf;
wr = read(fd, &buf, sizeof buf);
int cl = close(fd);
printf("%s %s %s %s %s", buf.id, buf.telefon, buf.ime, buf.priimek, buf.datum);
}
//...
If you prefer it as a string you can easily concatenate it using something like snprintf or similar.
I wrote this simple code to concatenate two files. Why doesn't this work? Please help.
int main(int arg, char* argv[]){
int fd1, fd2;
char c;
fd1 = open(argv[1], O_APPEND);
fd2 = open(argv[2], O_RDONLY);
while(read(fd2, &c, sizeof(c))) {
write(fd1, &c, sizeof(c));
}
close(fd1);
close(fd2);
return 0;
}
As I noted in a comment:
You need to test the results of open() and write(). Your call with O_APPEND needs O_WRONLY too. And if you want it to create the file too, you need various other options too — O_CREAT; maybe O_TRUNC but probably not; maybe O_EXCL; maybe some others too — and you need a mode argument for the third argument (e.g. 0644 — owner can read or write, group and others can only read; or something more restrictive).
You also need to check that you have 2 file name arguments.
Fixing those issues leads to code similar to this:
int main(int arg, char* argv[]){
if (argc < 3)
{
fprintf(stderr, "Usage: %s out-file in-file\n", argv[0]);
return 1;
}
int fd1 = open(argv[1], O_APPEND|O_WRONLY|O_CREAT, 0644);
if (fd1 < 0)
{
fprintf(stderr, "%s: failed to open/create file %s for writing\n", argv[0], argv[1]);
return 1;
}
int fd2 = open(argv[2], O_RDONLY);
if (fd2 < 0)
{
fprintf(stderr, "%s: failed to open file %s for reading\n", argv[0], argv[2]);
return 1;
}
char c;
while (read(fd2, &c, sizeof(c)) == sizeof(c)) {
if (write(fd1, &c, sizeof(c)) != sizeof(c))
break;
}
close(fd1);
close(fd2);
return 0;
}
I note that you might get warnings about comparing signed and unsigned values with the read() and write() tests — the functions return a ssize_t and sizeof produces a size_t (2 vs 1 letters s). You can cast around that, but it's ugly. The code is also woefully inefficient. Single character reads and writes work, but you get dramatically better performance in general with buffer sizes in the 1 KiB to 4 KiB range, and even bigger. Of course, then you have to trap and use the value returned by read() so that the correct amount of data is written.
Note that the original code would continue the loop if the read() failed (returned -1). It would only stop if the read() was successful at returning 0 when it reached EOF.
I've been out of programming in C for almost 2 years and have recently gotten an assignment in school on using write() and read().
Somewhere in the code I'm receiving the Segmentation Fault error, possibly on the filecopy function is where I'd put my money on. I was trying GDB but I haven't used that since that last time I programmed in C so I turn to here.
The code.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[]) {
void filecopy(int infd, int outfd);
int fd = -1;
char *prog = argv[0];
if(argc == 1)
filecopy(STDIN_FILENO, STDOUT_FILENO);
else
while(--argc > 0) {
if((fd = open(*++argv, O_RDONLY, "rb")) == -1) {
// we don't have fprintf... but we have sprintf =]
char tmp[30];
sprintf(tmp, "%s: can't open %s\0", prog, *argv);
write(STDOUT_FILENO, &tmp, sizeof(tmp));
exit(-1);
} else {
filecopy(fd, STDOUT_FILENO);
close(fd);
}
}
exit(0);
}
void filecopy(int infd, int outfd) {
// char *buf[1]; <-- causes unreadable characters outputted by write
char *buf;
while(read(infd, buf, 1) != -1)
write(outfd, buf, sizeof(buf));
}
The input/output
Thanks!
char *buf; is an uninitialized pointer, writing data through that pointer is
undefined behaviour.
char buf[1024];
ssize_t len;
while((len = read(infd, buf, sizeof buf)) != -1)
write(outfd, buf, len);
would be correct.
Note that char *buf[1]; is a array (of dimension 1) of pointers, that's
different to an array of chars. Using that you would need to do
read(infd, buf[0], somelength), but here again buf[0] would be an
uninitialized pointer and you would have the same problem. That's why declaring
an char array of say 1024 (you can choose another size) is the correct thing
to do.
Also in main use strlen(tmp) and not sizeof(tmp)
char tmp[30];
sprintf(tmp, "%s: can't open %s\0", prog, *argv);
write(STDOUT_FILENO, &tmp, strlen(tmp));
strlen returns you the length of the string which might be smaller than 29 and
if you use sizeof(tmp) you might be writing garbage past the end of the
string. Note also that 0 may be too small for the whole string, I'd use a
larger number or construct the string using snprintf:
snprintf(tmp, sizeof tmp, "%s: can't open %s\0", prog, *argv);
would be more safe.
Last thing:
while(--argc > 0)
if((fd = open(*++argv, O_RDONLY, "rb")) == -1) {
...
While this is correct, I feel that this code is awkward and hard to read. It
would be so much simpler to read if you did:
for(int i = 1; i < argc; ++i)
if((fd = open(argv[i], O_RDONLY, "rb")) == -1) {
...
I've never seen open being called with "rb" as the mode. My man page says:
man 2 open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags, mode_t mode);
[...]
The mode argument specifies the file mode bits be applied when a new file is created. This argument must be supplied when
O_CREAT or O_TMPFILE is specified in flags; if neither O_CREAT nor O_TMPFILE is specified, then mode is ignored.
The effective mode is modified by the process's umask in the usual way: in the absence of a default ACL, the mode of the created file is
(mode & ~umask). Note that this mode applies only to future accesses of the newly created file; the open() call that creates a
read-only file may well return a read/write file descriptor.
The following symbolic constants are provided for mode:
S_IRWXU 00700 user (file owner) has read, write, and execute permission
S_IRUSR 00400 user has read permission
S_IWUSR 00200 user has write permission
S_IXUSR 00100 user has execute permission
[...]
As you are neither using O_CREAT nor O_TMPFILE, this parameter will be
ignore and you are passing a char* as a mode_t which is integer in nature.
Hence your call should be:
if((fd = open(argv[i], O_RDONLY, 0)) == -1) {
...
Two adjustments are needed for you filecopy function:
You need to allocate space for your buffer. Right now you are using an uninitialized pointer and passing it to read which is undefined behavior.
You need to save the return value of read and pass the value to write
The end result should look something like this.
void filecopy(int infd, int outfd) {
char buf[1024];
size_t bytes_read;
while((bytes_read = read(infd, buf, sizeof buf)) != -1)
write(outfd, buf, bytes_read);
}
Running this through a static analysis tool gives 2 warnings:
1) The uninitialized variable that #Pablo points to
2) a buffer overrun when you sprintf *argv into tmp as *argv can very large (as #Pablo also suggested in his comment re: snprintf)
I am trying to read following file from C code.
file: /sys/bus/iio/devices/iio\:device0/in_voltage7_raw
but file pointer I am getting is -1.
Using cat command it is able to read the file.
But I am trying to read the same from my code as follows:
nos_int32 nos_adc_read_port (ADC_PORT_DB *p_port, nos_int32 *data)
{
char file_name[VALUE_MAX];
int value;
char buffer[BUFFER_LENGTH];
char intBuffer[INT_BUFFER_LENGTH];
int fd;
sprintf(file_name, "/sys/bus/iio/devices/iio\\:device0/in_voltage7_raw");
fd = open(file_name, O_RDONLY);
if (fd == -1) {
return(-1);
}
if (read(fd, buffer, BUFFER_LENGTH) == -1) {
return(-1);
}
close(fd);
memcpy(intBuffer, buffer, BUFFER_LENGTH);
intBuffer[INT_BUFFER_LENGTH-1] = '\0';
value = atoi(intBuffer);
*data = value;
return(0);
}
After the line:
fd = open(file_name, O_RDONLY);
value of fd is -1. How can it be solved?
Most command line shells use some characters for special actions and if you're trying to use them as their actual character, you need to prefix them with a backslash to escape them. In this case, your shell needs you to escape the colon when accessing that filename.
In C you don't have this issue so you can put in your code the filename as it truly is, such as:
"/sys/bus/iio/devices/iio:device0/in_voltage7_raw"
Here is my code snippet:
int fd;
bufsize = 30;
char buf[bufsize];
char cmd[100] = "file.txt";
int newfd = 1;
if (fd = open(cmd,O_RDONLY) >=0){
puts("wanna read");
while (read(fd,&bin_buf,bufsize)==1){
puts("reading");
write(newfd,&bin_buf,bufsize);
}
close(fd);
}
So here the program prints "wanna read" but never prints "reading". I have also tried opening using nonblock flag, but no use. Can anybody help me? I must use open() and read() system calls only. Thanks.
Edit: I have made some clarifications in the code. Actually the newfd that I'm writing to is a socket descriptor, but I don't think that is important for this problem because it sticks on the read which is before the write.
The first problem is your if statement. You forgot to use enough parentheses, so if the open() works, the read tries to read from file descriptor 1, aka standard output. If that's your terminal (it probably is) on a Unix box, then that works — surprising though that may be; the program is waiting for you to type something.
Fix: use parentheses!
if ((fd = open(cmd, O_RDONLY)) >= 0)
The assignment is done before, not after, the comparison.
I observe in passing that you don't show how you set cmd, but if you see the 'wanna read' message, it must be OK. You don't show how newfd is initialized; maybe that's 1 too.
You also have the issue with 'what the read() call returns'. You probably need:
int fd;
char buf[bufsize];
int newfd = 1;
if ((fd = open(cmd, O_RDONLY)) >= 0)
{
puts("wanna read");
int nbytes; // ssize_t if you prefer
while ((nbytes = read(fd, buf, sizeof(buf))) > 0)
{
puts("reading");
write(newfd, buf, nbytes);
}
close(fd);
}
You can demonstrate my primary observation by typing something ('Surprise', or 'Terminal file descriptors are often readable and writable' or something) with your original if but my loop body and then writing that somewhere.
Your read() call attempts to read bufsize bytes and returns the number of bytes actually read. Unless bufsize ==, it is quite unlikely read() will return 1, so the block is almost always skipped and nothing get written.
Also note that if (fd = open(cmd, O_RDONLY) >= 0) is incorrect and would set fd to 1, the handle for standard output, if the file exists, causing the read to fail as standard input is most likely not opened for reading.
Note that reading with the read system call is tricky on some environments, because a return value of -1 may be restartable.
Here is an improved version:
int catenate_file(const char *cmd, int newfd, size_t bufsize) {
int fd;
char buf[bufsize];
if ((fd = open(cmd, O_RDONLY)) >= 0) {
puts("wanna read");
ssize_t nc;
while ((nc = read(fd, buf, bufsize)) != 0) {
if (nc < 0) {
if (errno == EINTR)
continue;
else
break;
}
printf("read %zd bytes\n", nc);
write(newfd, buf, nc);
}
close(fd);
return 0;
}
return -1;
}
read returns the number of bytes read from file that can be bufsize or less if the remainder of the file that has to be read is shorter than bufsize.
In your case most probably bufsize is bigger than 1 and the file is bigger than 1 byte so the condition of the while loop is evaluated false, the code is skipped to the point where file is closed.
You should check if there if there are more bytes to be read:
while( read(fd,&bin_buf,bufsize) > 0 ) {