1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
5 * Copyright (C) 2001-2010, Eduardo Silva P. <edsiper@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
43 /* Raise a configuration error */
44 void mk_config_error(const char *path
, int line
, const char *msg
)
46 printf("\nReading %s", path
);
47 printf("\nError in line %i: %s\n\n", line
, msg
);
52 /* Returns a configuration section by [section name] */
53 struct mk_config_section
*mk_config_section_get(struct mk_config
*conf
,
54 const char *section_name
)
56 struct mk_config_section
*section
;
58 section
= conf
->section
;
60 if (strcasecmp(section
->name
, section_name
) == 0) {
63 section
= section
->next
;
69 /* Register a new section into the configuration struct */
70 void mk_config_section_add(struct mk_config
*conf
, char *section_name
)
72 struct mk_config_section
*new, *aux
;
74 /* Alloc section node */
75 new = mk_mem_malloc(sizeof(struct mk_config_section
));
76 new->name
= mk_string_dup(section_name
);
85 /* go to last section available */
95 /* Register a key/value entry in the last section available of the struct */
96 void mk_config_entry_add(struct mk_config
*conf
,
97 const char *key
, const char *val
)
99 struct mk_config_section
*section
;
100 struct mk_config_entry
*aux_entry
, *new_entry
;
102 if (!conf
->section
) {
103 puts("Error: there are not sections available!");
107 /* Go to last section */
108 section
= conf
->section
;
109 while (section
->next
) {
110 section
= section
->next
;
113 /* Alloc new entry */
114 new_entry
= mk_mem_malloc(sizeof(struct mk_config_entry
));
115 new_entry
->key
= mk_string_dup(key
);
116 new_entry
->val
= mk_string_dup(val
);
117 new_entry
->next
= NULL
;
119 /* Add first entry */
120 if (!section
->entry
) {
121 section
->entry
= new_entry
;
125 /* Go to last entry */
126 aux_entry
= section
->entry
;
127 while (aux_entry
->next
) {
128 aux_entry
= aux_entry
->next
;
131 aux_entry
->next
= new_entry
;
134 struct mk_config
*mk_config_create(const char *path
)
142 char *key
, *val
, *last
;
143 struct mk_config
*conf
= 0;
146 /* Open configuration file */
147 if ((f
= fopen(path
, "r")) == NULL
) {
148 fprintf(stderr
, "\nConfig Error: I can't open %s file\n\n", path
);
152 /* Alloc configuration node */
153 conf
= mk_mem_malloc(sizeof(struct mk_config
));
154 conf
->created
= time(NULL
);
155 conf
->file
= mk_string_dup(path
);
156 conf
->section
= NULL
;
158 /* looking for configuration directives */
159 while (fgets(buf
, 255, f
)) {
161 if (buf
[len
- 1] == '\n') {
163 if (len
&& buf
[len
- 1] == '\r') {
175 /* Skip commented lines */
178 mk_mem_free(section
);
184 /* Section definition */
187 end
= mk_string_char_search(buf
, ']', len
);
189 section
= mk_string_copy_substr(buf
, 1, end
);
190 mk_config_section_add(conf
, section
);
194 mk_config_error(path
, line
, "Bad header definition");
198 /* No separator defined */
202 do { i
++; } while (i
< len
&& isblank(buf
[i
]));
204 indent
= mk_string_copy_substr(buf
, 0, i
);
205 indent_len
= strlen(indent
);
207 /* Blank indented line */
213 /* Validate indentation level */
214 if (strncmp(buf
, indent
, indent_len
) != 0 || !section
||
215 isblank(buf
[indent_len
]) != 0) {
216 mk_config_error(path
, line
, "Invalid indentation level");
219 if (buf
[indent_len
] == '#' || indent_len
== len
) {
223 /* get line key and value */
224 key
= strtok_r(buf
+ indent_len
, "\"\t ", &last
);
225 val
= strtok_r(NULL
, "\"\t", &last
);
228 mk_config_error(path
, line
, "Each key must have a value");
233 mk_config_entry_add(conf
, key
, val
);
238 struct mk_config_section *s;
239 struct mk_config_entry *e;
243 printf("\n[%s]", s->name);
246 printf("\n %s = %s", e->key, e->val);
258 void mk_config_free(struct mk_config
*conf
)
260 struct mk_config_section
*prev
=0, *section
;
263 section
= conf
->section
;
265 while (section
->next
) {
267 section
= section
->next
;
270 /* Free section entries */
271 mk_config_free_entries(section
);
273 /* Free section node */
274 mk_mem_free(section
->name
);
275 mk_mem_free(section
);
277 if (section
== conf
->section
) {
281 section
= conf
->section
;
285 void mk_config_free_entries(struct mk_config_section
*section
)
287 struct mk_config_entry
*prev
= 0, *target
;
289 target
= section
->entry
;
291 while (target
->next
) {
293 target
= target
->next
;
296 /* Free memory assigned */
297 mk_mem_free(target
->key
);
298 mk_mem_free(target
->val
);
300 if (target
== section
->entry
) {
301 section
->entry
= NULL
;
306 target
= section
->entry
;
310 void *mk_config_section_getval(struct mk_config_section
*section
, char *key
, int mode
)
313 struct mk_config_entry
*entry
;
315 entry
= section
->entry
;
317 if (strcasecmp(entry
->key
, key
) == 0) {
319 case MK_CONFIG_VAL_STR
:
320 return (void *) entry
->val
;
321 case MK_CONFIG_VAL_NUM
:
322 return (void *) atoi(entry
->val
);
323 case MK_CONFIG_VAL_BOOL
:
324 on
= strcasecmp(entry
->val
, VALUE_ON
);
325 off
= strcasecmp(entry
->val
, VALUE_OFF
);
327 if (on
!= 0 && off
!= 0) {
331 return (void *) VAR_ON
;
334 return (void *) VAR_OFF
;
336 case MK_CONFIG_VAL_LIST
:
337 return mk_string_split_line(entry
->val
);
347 /* Read configuration files */
348 void mk_config_read_files(char *path_conf
, char *file_conf
)
352 struct stat checkdir
;
353 struct mk_config
*cnf
;
354 struct mk_config_section
*section
;
355 struct mk_string_line
*line
, *line_val
;
357 config
->serverconf
= mk_string_dup(path_conf
);
358 config
->workers
= MK_WORKERS_DEFAULT
;
360 if (stat(config
->serverconf
, &checkdir
) == -1) {
361 fprintf(stderr
, "\nERROR: Invalid path to configuration files");
362 fprintf(stderr
, "\nCannot find/open '%s'\n", config
->serverconf
);
366 mk_string_build(&path
, &len
, "%s/%s", path_conf
, file_conf
);
368 cnf
= mk_config_create(path
);
369 section
= mk_config_section_get(cnf
, "SERVER");
372 fprintf(stderr
, "\nERROR: No 'SERVER' section defined");
376 /* Map source configuration */
377 config
->config
= cnf
;
380 config
->listen_addr
= mk_config_section_getval(section
, "Listen",
382 if (!config
->listen_addr
) {
383 config
->listen_addr
= MK_DEFAULT_LISTEN_ADDR
;
386 /* Connection port */
387 config
->serverport
= (int) mk_config_section_getval(section
,
390 if (!config
->serverport
>= 1 && !config
->serverport
<= 65535) {
391 mk_config_print_error_msg("Port", path
);
394 /* Number of thread workers */
395 config
->workers
= (int) mk_config_section_getval(section
,
398 if (config
->workers
< 1) {
399 mk_config_print_error_msg("Workers", path
);
403 config
->timeout
= (int) mk_config_section_getval(section
,
404 "Timeout", MK_CONFIG_VAL_NUM
);
405 if (config
->timeout
< 1) {
406 mk_config_print_error_msg("Timeout", path
);
410 config
->keep_alive
= (int) mk_config_section_getval(section
,
413 if (config
->keep_alive
== VAR_ERR
) {
414 mk_config_print_error_msg("KeepAlive", path
);
417 /* MaxKeepAliveRequest */
418 config
->max_keep_alive_request
= (int)
419 mk_config_section_getval(section
,
420 "MaxKeepAliveRequest",
423 if (config
->max_keep_alive_request
== 0) {
424 mk_config_print_error_msg("MaxKeepAliveRequest", path
);
427 /* KeepAliveTimeout */
428 config
->keep_alive_timeout
= (int) mk_config_section_getval(section
,
431 if (config
->keep_alive_timeout
== 0) {
432 mk_config_print_error_msg("KeepAliveTimeout", path
);
436 config
->pid_file_path
= mk_config_section_getval(section
,
437 "PidFile", MK_CONFIG_VAL_STR
);
439 /* Home user's directory /~ */
440 config
->user_dir
= mk_config_section_getval(section
,
441 "UserDir", MK_CONFIG_VAL_STR
);
444 line_val
= line
= mk_config_section_getval(section
,
445 "Indexfile", MK_CONFIG_VAL_LIST
);
446 while (line_val
!= NULL
) {
447 mk_config_add_index(line_val
->val
);
448 line_val
= line_val
->next
;
451 /* HideVersion Variable */
452 config
->hideversion
= (int) mk_config_section_getval(section
,
455 if (config
->hideversion
== VAR_ERR
) {
456 mk_config_print_error_msg("HideVersion", path
);
460 config
->user
= mk_config_section_getval(section
, "User", MK_CONFIG_VAL_STR
);
463 config
->resume
= (int) mk_config_section_getval(section
,
464 "Resume", MK_CONFIG_VAL_BOOL
);
465 if (config
->resume
== VAR_ERR
) {
466 mk_config_print_error_msg("Resume", path
);
470 config
->symlink
= (int) mk_config_section_getval(section
,
471 "SymLink", MK_CONFIG_VAL_BOOL
);
472 if (config
->symlink
== VAR_ERR
) {
473 mk_config_print_error_msg("SymLink", path
);
477 mk_config_read_hosts(path_conf
);
480 void mk_config_read_hosts(char *path
)
486 struct host
*p_host
, *new_host
; /* debug */
489 mk_string_build(&buf
, &len
, "%s/sites/default", path
);
490 config
->hosts
= mk_config_get_host(buf
);
494 if (!config
->hosts
) {
495 printf("\nError parsing main configuration file 'default'\n");
499 mk_string_build(&buf
, &len
, "%s/sites/", path
);
500 if (!(dir
= opendir(buf
)))
504 p_host
= config
->hosts
;
506 /* Reading content */
507 while ((ent
= readdir(dir
)) != NULL
) {
508 if (strcmp((char *) ent
->d_name
, ".") == 0)
510 if (strcmp((char *) ent
->d_name
, "..") == 0)
512 if (strcasecmp((char *) ent
->d_name
, "default") == 0)
515 mk_string_build(&file
, &len
, "%s/sites/%s", path
, ent
->d_name
);
517 new_host
= (struct host
*) mk_config_get_host(file
);
523 p_host
->next
= new_host
;
531 struct host
*mk_config_get_host(char *path
)
533 unsigned long len
= 0;
534 struct stat checkdir
;
536 struct mk_config
*cnf
;
537 struct mk_config_section
*section
;
539 /* Read configuration file */
540 cnf
= mk_config_create(path
);
542 /* Read tag 'HOST' */
543 section
= mk_config_section_get(cnf
, "HOST");
545 /* Alloc configuration node */
546 host
= mk_mem_malloc_z(sizeof(struct host
));
548 host
->file
= mk_string_dup(path
);
549 host
->servername
= mk_config_section_getval(section
, "Servername",
552 /* document root handled by a mk_pointer */
553 host
->documentroot
.data
= mk_config_section_getval(section
,
556 host
->documentroot
.len
= strlen(host
->documentroot
.data
);
558 /* validate document root configured */
559 if (stat(host
->documentroot
.data
, &checkdir
) == -1) {
560 fprintf(stderr
, "ERROR: Invalid path to DocumentRoot in %s\n\n", path
);
563 else if (!(checkdir
.st_mode
& S_IFDIR
)) {
565 "ERROR: DocumentRoot variable in %s has an invalid directory path\n\n",
570 if (!host
->servername
) {
575 /* Server Signature */
576 if (config
->hideversion
== VAR_OFF
) {
577 mk_string_build(&host
->host_signature
, &len
,
578 "Monkey/%s", VERSION
);
581 mk_string_build(&host
->host_signature
, &len
, "Monkey");
583 mk_string_build(&host
->header_host_signature
.data
,
584 &host
->header_host_signature
.len
,
585 "Server: %s", host
->host_signature
);
589 host
->access_log_path
= mk_config_section_getval(section
,
593 host
->error_log_path
= mk_config_section_getval(section
,
600 /* Imprime error de configuracion y cierra */
601 void mk_config_print_error_msg(char *variable
, char *path
)
603 fprintf(stderr
, "\nError: %s variable in %s has an invalid value.\n",
609 /* Agrega distintos index.xxx */
610 void mk_config_add_index(char *indexname
)
612 struct indexfile
*new_index
= 0, *aux_index
;
614 new_index
= (struct indexfile
*) malloc(sizeof(struct indexfile
));
615 strncpy(new_index
->indexname
, indexname
, MAX_INDEX_NOMBRE
- 1);
616 new_index
->indexname
[MAX_INDEX_NOMBRE
- 1] = '\0';
617 new_index
->next
= NULL
;
619 if (first_index
== NULL
) {
620 first_index
= new_index
;
623 aux_index
= first_index
;
624 while (aux_index
->next
!= NULL
)
625 aux_index
= aux_index
->next
;
626 aux_index
->next
= new_index
;
630 void mk_config_set_init_values(void)
633 config
->timeout
= 15;
634 config
->hideversion
= VAR_OFF
;
635 config
->keep_alive
= VAR_ON
;
636 config
->keep_alive_timeout
= 15;
637 config
->max_keep_alive_request
= 50;
638 config
->resume
= VAR_ON
;
639 config
->standard_port
= 80;
640 config
->listen_addr
= MK_DEFAULT_LISTEN_ADDR
;
641 config
->serverport
= 2001;
642 config
->symlink
= VAR_OFF
;
645 config
->open_flags
= O_RDONLY
| O_NONBLOCK
;
648 config
->plugins
= NULL
;
651 /* read main configuration from monkey.conf */
652 void mk_config_start_configure(void)
656 mk_config_set_init_values();
657 mk_config_read_files(config
->file_config
, M_DEFAULT_CONFIG_FILE
);
659 /* if not index names defined, set default */
660 if (first_index
== NULL
) {
661 mk_config_add_index("index.html");
665 mk_mimetype_read_config();
667 /* Basic server information */
668 if (config
->hideversion
== VAR_OFF
) {
669 mk_string_build(&config
->server_software
.data
,
670 &len
, "Monkey/%s (%s)", VERSION
, OS
);
671 config
->server_software
.len
= len
;
674 mk_string_build(&config
->server_software
.data
, &len
, "Monkey Server");
675 config
->server_software
.len
= len
;
679 struct host
*mk_config_host_find(mk_pointer host
)
681 struct host
*aux_host
;
683 aux_host
= config
->hosts
;
686 if (strncasecmp(aux_host
->servername
, host
.data
, host
.len
) == 0) {
689 aux_host
= aux_host
->next
;
695 void mk_config_sanity_check()
697 /* Check O_NOATIME for current user, flag will just be used
698 * if running user is allowed to.
700 int fd
, flags
= config
->open_flags
;
703 fd
= open(config
->file_config
, flags
);
706 config
->open_flags
= flags
;