Little Palm fixes
[MonkeyD.git] / src / config.c
blob4fa7c46db33f7f8b1368af286366b512b9d659f0
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /* Monkey HTTP Daemon
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.
22 #include <dirent.h>
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <stdlib.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <ctype.h>
34 #include "monkey.h"
35 #include "config.h"
36 #include "str.h"
37 #include "utils.h"
38 #include "mimetype.h"
39 #include "info.h"
40 #include "memory.h"
41 #include "server.h"
42 #include "plugin.h"
44 /* Raise a configuration error */
45 void mk_config_error(const char *path, int line, const char *msg)
47 printf("\nReading %s", path);
48 printf("\nError in line %i: %s\n\n", line, msg);
49 fflush(stdout);
50 exit(1);
53 /* Returns a configuration section by [section name] */
54 struct mk_config_section *mk_config_section_get(struct mk_config *conf,
55 const char *section_name)
57 struct mk_config_section *section;
59 section = conf->section;
60 while (section) {
61 if (strcasecmp(section->name, section_name) == 0) {
62 return section;
64 section = section->next;
67 return NULL;
70 /* Register a new section into the configuration struct */
71 void mk_config_section_add(struct mk_config *conf, char *section_name)
73 struct mk_config_section *new, *aux;
75 /* Alloc section node */
76 new = mk_mem_malloc(sizeof(struct mk_config_section));
77 new->name = mk_string_dup(section_name);
78 new->entry = NULL;
79 new->next = NULL;
81 if (!conf->section) {
82 conf->section = new;
83 return;
86 /* go to last section available */
87 aux = conf->section;
88 while (aux->next) {
89 aux = aux->next;
92 aux->next = new;
93 return;
96 /* Register a key/value entry in the last section available of the struct */
97 void mk_config_entry_add(struct mk_config *conf,
98 const char *key, const char *val)
100 struct mk_config_section *section;
101 struct mk_config_entry *aux_entry, *new_entry;
103 if (!conf->section) {
104 puts("Error: there are not sections available!");
105 exit(1);
108 /* Go to last section */
109 section = conf->section;
110 while (section->next) {
111 section = section->next;
114 /* Alloc new entry */
115 new_entry = mk_mem_malloc(sizeof(struct mk_config_entry));
116 new_entry->key = mk_string_dup(key);
117 new_entry->val = mk_string_dup(val);
118 new_entry->next = NULL;
120 /* Add first entry */
121 if (!section->entry) {
122 section->entry = new_entry;
123 return;
126 /* Go to last entry */
127 aux_entry = section->entry;
128 while (aux_entry->next) {
129 aux_entry = aux_entry->next;
132 aux_entry->next = new_entry;
135 struct mk_config *mk_config_create(const char *path)
137 int len;
138 int line = 0;
139 int indent_len = -1;
140 char buf[255];
141 char *section = 0;
142 char *indent = 0;
143 char *key, *val, *last;
144 struct mk_config *conf = 0;
145 FILE *f;
147 /* Open configuration file */
148 if ((f = fopen(path, "r")) == NULL) {
149 fprintf(stderr, "\nConfig Error: I can't open %s file\n\n", path);
150 exit(1);
153 /* Alloc configuration node */
154 conf = mk_mem_malloc(sizeof(struct mk_config));
155 conf->created = time(NULL);
156 conf->file = mk_string_dup(path);
157 conf->section = NULL;
159 /* looking for configuration directives */
160 while (fgets(buf, 255, f)) {
161 len = strlen(buf);
162 if (buf[len - 1] == '\n') {
163 buf[--len] = 0;
164 if (len && buf[len - 1] == '\r') {
165 buf[--len] = 0;
169 /* Line number */
170 line++;
172 if (!buf[0]) {
173 continue;
176 /* Skip commented lines */
177 if (buf[0] == '#') {
178 if (section) {
179 mk_mem_free(section);
180 section = NULL;
182 continue;
185 /* Section definition */
186 if (buf[0] == '[') {
187 int end = -1;
188 end = mk_string_char_search(buf, ']', len);
189 if (end > 0) {
190 section = mk_string_copy_substr(buf, 1, end);
191 mk_config_section_add(conf, section);
192 continue;
194 else {
195 mk_config_error(path, line, "Bad header definition");
198 else {
199 /* No separator defined */
200 if (!indent) {
201 int i = 0;
203 do { i++; } while (i < len && isblank(buf[i]));
205 indent = mk_string_copy_substr(buf, 0, i);
206 indent_len = strlen(indent);
208 /* Blank indented line */
209 if (i == len) {
210 continue;
214 /* Validate indentation level */
215 if (strncmp(buf, indent, indent_len) != 0 || !section ||
216 isblank(buf[indent_len]) != 0) {
217 mk_config_error(path, line, "Invalid indentation level");
220 if (buf[indent_len] == '#' || indent_len == len) {
221 continue;
224 /* get line key and value */
225 key = strtok_r(buf + indent_len, "\"\t ", &last);
226 val = strtok_r(NULL, "\"\t", &last);
228 if (!key || !val) {
229 mk_config_error(path, line, "Each key must have a value");
230 continue;
233 /* Trim strings */
234 mk_string_trim(&key);
235 mk_string_trim(&val);
237 /* Register entry */
238 mk_config_entry_add(conf, key, val);
243 struct mk_config_section *s;
244 struct mk_config_entry *e;
246 s = conf->section;
247 while(s) {
248 printf("\n[%s]", s->name);
249 e = s->entry;
250 while(e) {
251 printf("\n %s = %s", e->key, e->val);
252 e = e->next;
254 s = s->next;
256 fflush(stdout);
259 fclose(f);
260 return conf;
263 void mk_config_free(struct mk_config *conf)
265 struct mk_config_section *prev=0, *section;
267 /* Free sections */
268 section = conf->section;
269 while (section) {
270 while (section->next) {
271 prev = section;
272 section = section->next;
275 /* Free section entries */
276 mk_config_free_entries(section);
278 /* Free section node */
279 mk_mem_free(section->name);
280 mk_mem_free(section);
282 if (section == conf->section) {
283 return;
285 prev->next = NULL;
286 section = conf->section;
290 void mk_config_free_entries(struct mk_config_section *section)
292 struct mk_config_entry *prev = 0, *target;
294 target = section->entry;
295 while (target) {
296 while (target->next) {
297 prev = target;
298 target = target->next;
301 /* Free memory assigned */
302 mk_mem_free(target->key);
303 mk_mem_free(target->val);
305 if (target == section->entry) {
306 section->entry = NULL;
307 return;
310 prev->next = NULL;
311 target = section->entry;
315 void *mk_config_section_getval(struct mk_config_section *section, char *key, int mode)
317 int on, off;
318 struct mk_config_entry *entry;
320 entry = section->entry;
321 while (entry) {
322 if (strcasecmp(entry->key, key) == 0) {
323 switch (mode) {
324 case MK_CONFIG_VAL_STR:
325 return (void *) entry->val;
326 case MK_CONFIG_VAL_NUM:
327 return (void *) (size_t) atoi(entry->val);
328 case MK_CONFIG_VAL_BOOL:
329 on = strcasecmp(entry->val, VALUE_ON);
330 off = strcasecmp(entry->val, VALUE_OFF);
332 if (on != 0 && off != 0) {
333 return (void *) -1;
335 else if (on >= 0) {
336 return (void *) VAR_ON;
338 else {
339 return (void *) VAR_OFF;
341 case MK_CONFIG_VAL_LIST:
342 return mk_string_split_line(entry->val);
345 else {
346 entry = entry->next;
349 return NULL;
352 /* Read configuration files */
353 void mk_config_read_files(char *path_conf, char *file_conf)
355 unsigned long len;
356 char *path = 0;
357 struct stat checkdir;
358 struct mk_config *cnf;
359 struct mk_config_section *section;
361 config->serverconf = mk_string_dup(path_conf);
362 config->workers = MK_WORKERS_DEFAULT;
364 if (stat(config->serverconf, &checkdir) == -1) {
365 fprintf(stderr, "\nERROR: Invalid path to configuration files");
366 fprintf(stderr, "\nCannot find/open '%s'\n", config->serverconf);
367 exit(1);
370 mk_string_build(&path, &len, "%s/%s", path_conf, file_conf);
372 cnf = mk_config_create(path);
373 section = mk_config_section_get(cnf, "SERVER");
375 if (!section) {
376 fprintf(stderr, "\nERROR: No 'SERVER' section defined\n");
377 exit(1);
380 /* Map source configuration */
381 config->config = cnf;
383 /* Listen */
384 config->listen_addr = mk_config_section_getval(section, "Listen",
385 MK_CONFIG_VAL_STR);
386 if (!config->listen_addr) {
387 config->listen_addr = MK_DEFAULT_LISTEN_ADDR;
390 /* Connection port */
391 config->serverport = (size_t) mk_config_section_getval(section,
392 "Port",
393 MK_CONFIG_VAL_NUM);
394 if (!config->serverport >= 1 && !config->serverport <= 65535) {
395 mk_config_print_error_msg("Port", path);
397 /* Set connection port to mk_pointer */
398 config->port.data = mk_mem_malloc(6);
399 mk_string_itop(config->serverport, &config->port);
400 config->port.len = config->port.len - 2;
403 /* Number of thread workers */
404 config->workers = (size_t) mk_config_section_getval(section,
405 "Workers",
406 MK_CONFIG_VAL_NUM);
407 if (config->workers < 1) {
408 mk_config_print_error_msg("Workers", path);
410 /* Get each worker clients capacity based on FDs system limits */
411 config->worker_capacity = mk_server_worker_capacity(config->workers);
413 /* Timeout */
414 config->timeout = (size_t) mk_config_section_getval(section,
415 "Timeout", MK_CONFIG_VAL_NUM);
416 if (config->timeout < 1) {
417 mk_config_print_error_msg("Timeout", path);
420 /* KeepAlive */
421 config->keep_alive = (size_t) mk_config_section_getval(section,
422 "KeepAlive",
423 MK_CONFIG_VAL_BOOL);
424 if (config->keep_alive == VAR_ERR) {
425 mk_config_print_error_msg("KeepAlive", path);
428 /* MaxKeepAliveRequest */
429 config->max_keep_alive_request = (size_t)
430 mk_config_section_getval(section,
431 "MaxKeepAliveRequest",
432 MK_CONFIG_VAL_NUM);
434 if (config->max_keep_alive_request == 0) {
435 mk_config_print_error_msg("MaxKeepAliveRequest", path);
438 /* KeepAliveTimeout */
439 config->keep_alive_timeout = (size_t) mk_config_section_getval(section,
440 "KeepAliveTimeout",
441 MK_CONFIG_VAL_NUM);
442 if (config->keep_alive_timeout == 0) {
443 mk_config_print_error_msg("KeepAliveTimeout", path);
446 /* Pid File */
447 config->pid_file_path = mk_config_section_getval(section,
448 "PidFile", MK_CONFIG_VAL_STR);
450 /* Home user's directory /~ */
451 config->user_dir = mk_config_section_getval(section,
452 "UserDir", MK_CONFIG_VAL_STR);
454 /* Index files */
455 config->index_files = mk_config_section_getval(section,
456 "Indexfile", MK_CONFIG_VAL_LIST);
458 /* HideVersion Variable */
459 config->hideversion = (size_t) mk_config_section_getval(section,
460 "HideVersion",
461 MK_CONFIG_VAL_BOOL);
462 if (config->hideversion == VAR_ERR) {
463 mk_config_print_error_msg("HideVersion", path);
466 /* User Variable */
467 config->user = mk_config_section_getval(section, "User", MK_CONFIG_VAL_STR);
469 /* Resume */
470 config->resume = (size_t) mk_config_section_getval(section,
471 "Resume", MK_CONFIG_VAL_BOOL);
472 if (config->resume == VAR_ERR) {
473 mk_config_print_error_msg("Resume", path);
476 /* Max Request Size */
477 config->max_request_size = (size_t) mk_config_section_getval(section,
478 "MaxRequestSize",
479 MK_CONFIG_VAL_NUM);
480 if (config->max_request_size <= 0) {
481 mk_config_print_error_msg("MaxRequestSize", path);
483 else {
484 config->max_request_size *= 1024;
487 /* Symbolic Links */
488 config->symlink = (size_t) mk_config_section_getval(section,
489 "SymLink", MK_CONFIG_VAL_BOOL);
490 if (config->symlink == VAR_ERR) {
491 mk_config_print_error_msg("SymLink", path);
494 mk_mem_free(path);
495 mk_config_read_hosts(path_conf);
498 void mk_config_read_hosts(char *path)
500 DIR *dir;
501 unsigned long len;
502 char *buf = 0;
503 char *file;
504 struct host *p_host, *new_host; /* debug */
505 struct dirent *ent;
507 mk_string_build(&buf, &len, "%s/sites/default", path);
508 config->hosts = mk_config_get_host(buf);
509 config->nhosts++;
510 mk_mem_free(buf);
512 if (!config->hosts) {
513 printf("\nError parsing main configuration file 'default'\n");
514 exit(1);
517 mk_string_build(&buf, &len, "%s/sites/", path);
518 if (!(dir = opendir(buf)))
519 exit(1);
522 p_host = config->hosts;
524 /* Reading content */
525 while ((ent = readdir(dir)) != NULL) {
526 if (strcmp((char *) ent->d_name, ".") == 0)
527 continue;
528 if (strcmp((char *) ent->d_name, "..") == 0)
529 continue;
530 if (strcasecmp((char *) ent->d_name, "default") == 0)
531 continue;
533 mk_string_build(&file, &len, "%s/sites/%s", path, ent->d_name);
535 new_host = (struct host *) mk_config_get_host(file);
536 mk_mem_free(file);
537 if (!new_host) {
538 continue;
540 else {
541 p_host->next = new_host;
542 p_host = new_host;
543 config->nhosts++;
546 closedir(dir);
549 struct host *mk_config_get_host(char *path)
551 unsigned long len = 0;
552 struct stat checkdir;
553 struct host *host;
554 struct mk_config *cnf;
555 struct mk_config_section *section;
557 /* Read configuration file */
558 cnf = mk_config_create(path);
560 /* Read tag 'HOST' */
561 section = mk_config_section_get(cnf, "HOST");
563 /* Alloc configuration node */
564 host = mk_mem_malloc_z(sizeof(struct host));
565 host->config = cnf;
566 host->file = mk_string_dup(path);
567 host->servername = mk_config_section_getval(section, "Servername",
568 MK_CONFIG_VAL_STR);
570 /* document root handled by a mk_pointer */
571 host->documentroot.data = mk_config_section_getval(section,
572 "DocumentRoot",
573 MK_CONFIG_VAL_STR);
574 host->documentroot.len = strlen(host->documentroot.data);
576 /* validate document root configured */
577 if (stat(host->documentroot.data, &checkdir) == -1) {
578 fprintf(stderr, "ERROR: Invalid path to DocumentRoot in %s\n\n", path);
579 exit(1);
581 else if (!(checkdir.st_mode & S_IFDIR)) {
582 fprintf(stderr,
583 "ERROR: DocumentRoot variable in %s has an invalid directory path\n\n",
584 path);
585 exit(1);
588 if (!host->servername) {
589 mk_config_free(cnf);
590 return NULL;
593 /* Server Signature */
594 if (config->hideversion == VAR_OFF) {
595 mk_string_build(&host->host_signature, &len,
596 "Monkey/%s", VERSION);
598 else {
599 mk_string_build(&host->host_signature, &len, "Monkey");
601 mk_string_build(&host->header_host_signature.data,
602 &host->header_host_signature.len,
603 "Server: %s", host->host_signature);
606 /* Access log */
607 host->access_log_path = mk_config_section_getval(section,
608 "AccessLog",
609 MK_CONFIG_VAL_STR);
610 /* Error log */
611 host->error_log_path = mk_config_section_getval(section,
612 "ErrorLog",
613 MK_CONFIG_VAL_STR);
614 host->next = NULL;
615 return host;
618 /* Imprime error de configuracion y cierra */
619 void mk_config_print_error_msg(char *variable, char *path)
621 fprintf(stderr, "\nError: %s variable in %s has an invalid value.\n",
622 variable, path);
623 fflush(stderr);
624 exit(1);
627 void mk_config_set_init_values(void)
629 /* Init values */
630 config->timeout = 15;
631 config->hideversion = VAR_OFF;
632 config->keep_alive = VAR_ON;
633 config->keep_alive_timeout = 15;
634 config->max_keep_alive_request = 50;
635 config->resume = VAR_ON;
636 config->standard_port = 80;
637 config->listen_addr = MK_DEFAULT_LISTEN_ADDR;
638 config->serverport = 2001;
639 config->symlink = VAR_OFF;
640 config->nhosts = 0;
641 config->user = NULL;
642 config->open_flags = O_RDONLY | O_NONBLOCK;
643 config->index_files = NULL;
645 /* Max request buffer size allowed
646 * right now, every chunk size is 4KB (4096 bytes),
647 * so we are setting a maximum request size to 32 KB */
648 config->max_request_size = MK_REQUEST_CHUNK * 8;
650 /* Plugins */
651 config->plugins = NULL;
654 /* read main configuration from monkey.conf */
655 void mk_config_start_configure(void)
657 unsigned long len;
659 mk_config_set_init_values();
660 mk_config_read_files(config->file_config, M_DEFAULT_CONFIG_FILE);
662 /* Load mimes */
663 mk_mimetype_read_config();
665 /* Basic server information */
666 if (config->hideversion == VAR_OFF) {
667 mk_string_build(&config->server_software.data,
668 &len, "Monkey/%s (%s)", VERSION, OS);
669 config->server_software.len = len;
671 else {
672 mk_string_build(&config->server_software.data, &len, "Monkey Server");
673 config->server_software.len = len;
677 struct host *mk_config_host_find(mk_pointer host)
679 struct host *aux_host;
681 aux_host = config->hosts;
683 while (aux_host) {
684 if (strncasecmp(aux_host->servername, host.data, host.len) == 0) {
685 return aux_host;
687 aux_host = aux_host->next;
690 return NULL;
693 void mk_config_sanity_check()
695 /* Check O_NOATIME for current user, flag will just be used
696 * if running user is allowed to.
698 int fd, flags = config->open_flags;
700 flags |= O_NOATIME;
701 fd = open(config->file_config, flags);
703 if (fd > -1) {
704 config->open_flags = flags;
705 close(fd);