How does nginx write files in C
I searched for access_log
in the entire project and stumbled upon the ngx_http_log_module.c
file which also has the following code:
static void
ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
size_t len)
{
....
} else {
n = ngx_write_fd(log->file->fd, buf, len);
}
....
The func ngx_write_fd
is defined in src/os/unix/ngx_files.h
.
/*
* we use inlined function instead of simple #define
* because glibc 2.3 sets warn_unused_result attribute for write()
* and in this case gcc 4.3 ignores (void) cast
*/
static ngx_inline ssize_t
ngx_write_fd(ngx_fd_t fd, void *buf, size_t n)
{
return write(fd, buf, n);
}
This function is platform dependant, and is also defined in src/os/win32/ngx_files.c
, but I'll ignore that as I'm not using a Windows system. fd
stands for file descriptor.
Now I need to find where these file descriptors are being initialzed. The same files also contain the code to open files.
#define ngx_open_file(name, mode, create, access) \
open((const char *) name, mode|create, access)
And it is referenced in ngx_cycle.c
:
file[i].fd = ngx_open_file(file[i].name.data,
NGX_FILE_APPEND,
NGX_FILE_CREATE_OR_OPEN,
NGX_FILE_DEFAULT_ACCESS);
Remember the goal is to find some code that will help us write files. I have skipped over how nginx
brings all of this together. I'll get to that when I get to that.
For now, I can stitch together what I've found:
- Copy the functions into a new file.
- Search and copy definitions of all undefined typedefs and constants.
- Write a main function that calls the copied functions.
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#ifndef ngx_inline
#define ngx_inline inline
#endif
typedef int ngx_fd_t;
#define NGX_FILE_RDWR O_RDWR
#define NGX_FILE_TRUNCATE (O_CREAT | O_TRUNC)
#define NGX_FILE_DEFAULT_ACCESS 0644
static ngx_inline ssize_t ngx_write_fd(ngx_fd_t fd, void *buf, size_t n) {
return write(fd, buf, n);
}
#define ngx_open_file(name, mode, create, access) \
open((const char *)name, mode | create, access)
int main() {
ngx_fd_t fd = ngx_open_file("hello.txt", NGX_FILE_RDWR, NGX_FILE_TRUNCATE,
NGX_FILE_DEFAULT_ACCESS);
char buf[] = "Hello, World!";
ssize_t buf_sz = sizeof(buf) / sizeof(buf[0]);
ngx_write_fd(fd, buf, buf_sz-1);
return 0;
}
Run this:
$ gcc main.c
$ chmod +x a.out
$ ./a.out
$ cat hello.txt
There is a lot of interesting stuff happening in the snippet above.
- Finding the length of an array
char buf[] = "Hello, World!";
ssize_t buf_sz = sizeof(buf) / sizeof(buf[0]);
// char arrays end with \0 which we do not want to write to file
// which is why we're writing buf_sz-1 bytes only
ngx_write_fd(fd, buf, buf_sz-1);
- The
ssize_t
type
Just read What is size_t for? and What is ssize_t in C?
Besides writing to log files, nginx
reads files as well, important configuration files. And that's my next challenge. How is the config file parsed?