This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main()
{
int fd=open("/home/victor/hello",O_WRONLY);
if(fd<0)
{
perror("Open");
exit(EXIT_FAILURE);
}
struct stat sbuf;
if(fstat(fd, &sbuf)==-1){
perror("stat");
close(fd);
exit(EXIT_FAILURE);
}
void* file_memory= mmap(NULL, sbuf.st_size, PROT_WRITE, MAP_SHARED,fd,0);
if (file_memory == MAP_FAILED ) {
perror("Error mmapping the file");
close(fd);
exit(EXIT_FAILURE);
}
return 0;
}
I tried this too
int fd=open("/home/victor/hello",O_WRONLY|0777);
but it's the same error:
Error mmapping the file: Permission denied
Doing ls -l | grep hola
-rwxrwxrwx 1 victor victor 24 oct 24 01:47 hello
What's wrong?
From the glibc manual, and as already pointed out by R.. and Iwillnotexist Idonotexist above:
Note that most hardware designs cannot support write permission
without read permission, and many do not distinguish read and execute
permission. Thus, you may receive wider permissions than you ask for,
and mappings of write-only files may be denied even if you do not use
PROT_READ.
http://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html
Related
I'm trying to open a shared mem file and write into it. The problem is that ftruncate is returning -1 .
Here is my code:
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include<sys/mman.h>
#include<sys/stat.h>
#include <fcntl.h>
int main(void) {
int fd;
fd=shm_open("/shmem-m", O_CREAT,0777);
printf("%d\n",fd);
int a=ftruncate(fd, 1024);
printf("%d\n",a);
void* addr=mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED,fd, 0);
char* msg= "hola mundo!";
memcpy(addr,msg,strlen(msg));
exit(EXIT_SUCCESS);
//return 0;
}
The output is:
3
-1
Segmentation fault
Any ideas? Thank you very much
The problem is that POSIX requires the file to be opened in write mode for a call to ftruncate to succeed as stated in the ftruncate man page.
So the call to shm_open becomes shm_open("/shmem-m", O_CREAT | O_RDWR, 0777), with the O_RDWR flag set (shm_open man page).
Have a problem.
I have a file which contents look like number:error_description.
Now i need to put this file to shared memory (POSIX). If any contents are modified it should be saved to the base-file.
There is a need to search in the content in the shared memory (results will be sent to a client over a message queue).
How do I implement all this? First I thought I have to open (fopen("my_file", "r")) and then I have to create shared memory and mmap the file.
Can someone help me?
edit:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
/*
* \ /tmp/errors -> Error File
*/
#define MSGQ_HANDLER "/error_handler"
#define PATH_TO_FILE "/tmp/errors"
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int main(void) {
int fd = open(PATH_TO_FILE, O_RDWR);
struct stat file_stat;
fstat(fd, &file_stat);
printf("File size: %zd\n", file_stat.st_size);
char *byte_ptr = mmap(NULL, file_stat.st_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if(byte_ptr == MAP_FAILED){
perror("error:");
}
while(1){
printf("%s\n", byte_ptr);
if(byte_ptr)
exit(1);
}
return EXIT_SUCCESS;
}
So far it is what I have now.
Read a line works.
How do I change the content?
Don't use fopen and forget about shared memory (the sh* API I mean). mmap is all that's needed.
Open your file with open and the right options (read/write). Then use mmap with the option MAP_SHARED. All changes in the file will be reflected directly and visible to all processes that map the same file. On Linux and Solaris (on other systems I don't know, but it is not guaranteed by POSIX or any standard) you can even access the file concurrently with read/write. It is a bad idea though.
Concurrent memory accesses from different processes will, of course, need synchronisation (mutex, semaphores etc.).
This question already has answers here:
Why are the file permissions changed when creating a file with the open system call on Linux?
(3 answers)
Closed 3 years ago.
I create a file using the code below:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
const char* filename = "./test.out";
int fd;
if(-1 == (fd = open(filename, O_CREAT|O_RDWR, 0666)))
{
perror("Error");
errno = 0;
}
else
puts("File opened");
if(-1 == (close(fd)))
{
perror("Error");
errno = 0;
}
else
puts("File closed");
return 0;
}
I specify the mode argument as 0666, which should grant read,write access to everyone. However, an ls -l shows
-rw-r--r-- 1 kmehta users 0 2012-01-29 16:29 test.out
As you can see, write permissions are only granted to the owner of the file. I do not know why everyone else is not granted permissions correctly. chmod a+w test.out sets the permissions correctly though.
Code compiled as gcc -Wall test.c
Specs: gcc v 4.5.0 on Opensuse 11.3 64 bit
The mode argument to open specifies the maximum allowed permissions. The umask setting is then applied to further restrict the permissions.
If you need to make the permissions be 0666 specifically you will need to use fchmod on the file handle after the open succeeds or use umask to set the process’ permissions mask before the open.
Executing this code :
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int fd;
if((fd = open("new.file",O_CREAT,S_IRWXU | S_IRWXG | S_IRWXO)) == -1)
{
perror("open");
return 1;
}
close(fd);
return 0;
}
on my Linux box, where umask returns 0022, gives me a file with the following attributes :
-rwxr-xr-x 1 daniel daniel 0 Jan 29 23:46 new.file
So, as you can see, the umask masks out the write bits in my case. It looks like it's the same on your system, too.
Given the path, is there a way to find out whether the file exists without opening the file?
Thanks
The most efficient way is access with the F_OK flag.
stat also works but it's much heavier weight since it has to read the inode contents, not just the directory.
You can use the stat system call. Make sure though that you check errno for the correct error because stat may return -1 for a number of other reasons/Failures.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
main()
{
struct stat BUF;
if(stat("/Filepath/FileName",&BUF)==0)
{
printf("File exists\n");
}
}
Another way is by using the access function.
#include <unistd.h>
main()
{
if(access("/Filepath/FileName", F_OK) != -1 )
{
printf("File exists\n");
}
else
{
printf("File does not exist\n");
}
}
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
int rc;
struct stat mystat;
rc = stat(path, &mystat);
Now check rc and (maybe) errno.
EDIT 2011-09-18 addendum:
Both access() and stat() return 0 if the path points to a non-file (directory, fifo,symlink, whatever)
In the stat() case, this can be tested with "((st_mode & S_IFREG) == S_IFREG)".
Best way still is to just try to open the file with open() or fopen().
Try to remove it (unlink()). If successful, it doesn't exist anymore. If unsuccessful,
interpret errno to see if it exists :)
I was reading through this Advanced Linux Programming tutorial when I encountered a problem. I was trying to eject the CD-ROM drive using this code:
int fd = open(path_to_cdrom, O_RDONLY);
// Eject the CD-ROM drive
ioctl(fd, CDROMEJECT);
close(fd);
Then I try to compile this code and get the following output:
In file included from /usr/include/linux/cdrom.h:14,
from new.c:2:
/usr/include/asm/byteorder.h: In function ‘___arch__swab32’:
/usr/include/asm/byteorder.h:19: error: expected ‘)’ before ‘:’ token
/usr/include/asm/byteorder.h: In function ‘___arch__swab64’:
/usr/include/asm/byteorder.h:43: error: expected ‘)’ before ‘:’ token
So what am I doing wrong?
The error message you're seeing looks like something is wrong in your #include lines, not with the code you posted. I tried compiling http://www.advancedlinuxprogramming.com/listings/chapter-6/cdrom-eject.c and it compiles just fine.
According to this, you need to specify O_NONBLOCK when opening the device, otherwise it won't work.
From that page:
cdrom = open(CDDEVICE,O_RDONLY | O_NONBLOCK)
You are missing a #include, I think. Do you have:
#include <fcntl.h>
#include <linux/cdrom.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
Those are the ones in the example...
In the previous examples the following includes are not needed.
#include <sys/stat.h>
#include <sys/types.h>
Also as stated before you may need to open with O_NONBLOCK
You can find more options for interacting with the CDROM device in the header file located at '/usr/include/linux/cdrom.h' or here https://github.com/torvalds/linux/blob/master/include/uapi/linux/cdrom.h
Also here is another example for opening and closing the CD tray with the mentioned changes.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/cdrom.h>
#include <sys/ioctl.h>
#include <unistd.h>
int main (int argc, char* argv[])
{
// Path to CD-ROM drive
char *dev = "/dev/dvd";
int fd = open(dev, O_RDONLY | O_NONBLOCK);
if(fd == -1){
printf("Failed to open '%s'\n", dev);
exit(1);
}
printf("fd :%d\n", fd);
// Eject the CD-ROM tray
ioctl (fd, CDROMEJECT);
sleep(2);
// Close the CD-ROM tray
ioctl (fd, CDROMCLOSETRAY);
close(fd);
return 0;
}
The open syscall has some unwanted behaviours which must be handled by setting it to Not blocking ie O_NONBLOCK
Also check that you have included the header file
#include <linux/cdrom.h>