First we have to make some things clear:
- Use void* for the variable addr
- Open the file with Read and Write enabled (O_RDWR). This is necessary so that the mmap() perform the mapping.
- In the permissions (the mode of open()), to create the file use S_IRWXU instead of 0700.
- If the size of server log. for zero, to write to the file you need to increase it (and the mmap() unaccepted length zero). (see next item)
- There’s a problem with you using the argument
MAP_PRIVATE
in mmap(): With MAP_PRIVATE
, as it says in the manual user@host:~$ man 2 mmap
, what you write in the mapped region will not be written in the file server log.; and also only its process has access to the mapped region (not shared). To write in server log., as much as to have shared mapping, you need to use MAP_SHARED
, whose implementation is a little different and I will show it below.
- If the offset is different from zero, he accurate be a multiple of the value returned when you call the function sysconf(_SC_PAGE_SIZE).
- Compare addr with MAP_FAILED instead of -1.
- Remember at the end of closing the file close (fd) and also "wean" it with munmap(addr, mapped region size).
- And also remember to include all headers (headers) needed at the beginning of the code.
Just in case:
prototype of open()
int open(const char *pathname, int flags, mode_t mode);
prototype of mmap()
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
The Code
First I tried to make a version of your code (with MAP_PRIVATE) corrected (I commented her with some of the items I mentioned above):
Compile it with: gcc mmap.c -o mmap
mmap. c
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int
main (void) {
int fd;
void *addr; /* use void* */
struct stat sb;
int retval = 0; /* valor que será retornado por main() */
/* use O_RDWR ao invés de O_WRONLY ( necessário para o mmap() )
* e também S_IRWXU ao invés de 00700 */
if ((fd = open("server.log", O_RDWR | O_CREAT, S_IRWXU)) == -1) {
perror("open");
return 1;
}
/* fstat() para obter o tamanho do arquivo */
if (fstat(fd, &sb) == -1) {
perror("stat");
retval = 1;
goto _go_close_fd;
}
/* se o tamanho for igual a zero, precisamos aumentá-lo!
* Caso contrário não conseguiremos escrever nada e mmap() vai falhar */
if (sb.st_size == 0) {
printf("file size is zero!\n");
ftruncate(fd, 1024); /* __define__ o tamanho do arquivo
* (não aumenta em cima do que já é) */
sb.st_size = 1024;
}
/* use NULL no primeiro argumento */
/* E se quiser usar outro offset, este precisa ser maior que o valor
* retornado por sysconf(_SC_PAGE_SIZE) */
addr = mmap(NULL, sb.st_size, PROT_WRITE, MAP_PRIVATE, fd, 0);
if (addr == MAP_FAILED) { /* use MAP_FAILED ao invés de -1 */
perror("mmap"); /* "memória partilhada"? MAP_PRIVATE inibe o
* compartilhamento do map(eamento) e também não
* escreve suas alterações no arquivo em disco.
* Se quiser compartilhar com outros processos e
* também "salvar" o que escreveu no arquivo
* deve usar MAP_SHARED */
goto _go_close_fd;
}
/* **************************************************************
* Escreva o que quiser no arquivo mapeado DESDE QUE não exceda o
* tamanho do arquivo `sb.st_size`. E lembre-se de que nada será
* "salvo" (transferido) para o arquivo `server.log` no disco
* ************************************************************** */
munmap(addr, sb.st_size); /* unmap o file descriptor */
_go_close_fd:
close(fd); /* precisamos fechar o file descriptor */
return retval;
}
This other code uses MAP_SHARED and write to the archive (I took some comments to make the code as clean as possible):
Compile it with: gcc mmap_shared.c -o mmap_shared
mmap_shared. c
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int
main (void) {
int fd;
void *addr;
struct stat sb;
int retval = 0; /* valor que será retornado por main() */
if ((fd = open("server.log", O_RDWR | O_CREAT, S_IRWXU)) == -1) {
perror("open");
return 1;
}
if (fstat(fd, &sb) == -1) {
perror("stat");
retval = 1;
goto _go_close_fd;
}
if (sb.st_size == 0) {
printf("file size is zero!\n");
ftruncate(fd, 1024);
sb.st_size = 1024;
}
/* se quiser pode mapear além do tamanho do arquivo, mas o que escrever
* nesta memória além-arquivo não irá ter efeito nele :-) */
addr = mmap(NULL, sb.st_size, PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
perror("mmap");
goto _go_close_fd;
}
/* **************************************************************
* Escreva o que quiser no arquivo mapeado DESDE QUE não exceda o
* tamanho do arquivo `sb.st_size`. Exemplo:
* ************************************************************** */
snprintf((char*) addr, sb.st_size, "Hello World!\n");
/* vamos usar msync() para ter certeza que nossa informação irá para o
* arquivo em disco!
* msync() faz um flush nos dados :-)
* -> A flag MS_SYNC diz que msync só irá retornar para a gente quando
* a informação for escrita no arquivo */
msync(addr, sb.st_size, MS_SYNC);
munmap(addr, sb.st_size); /* unmap o file descriptor */
_go_close_fd:
close(fd); /* precisamos fechar o file descriptor */
return retval;
}
What I changed from the first to this second code was the flag MAP_SHARED, the snprintf() that I added and the msync() which guarantees the writing in the file.
For more details see these manuals (in English):
ftruncate, mmap, msync, open and snprintf
put the parameter MAP_ANONYMOUS next to MAP_PRIVATE, will look like this MAP_ANONYMOUS | MAP_PRIVATE
– Brumazzi DB