Configuration reader: add 'read line by values'
[MonkeyD.git] / src / config.c
blobfc762cbbbf2ad8f3b5dd0a1489940ff83b482144
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
3 /* Monkey HTTP Daemon
4 * ------------------
5 * Copyright (C) 2001-2003, Eduardo Silva P.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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>
33 #include "monkey.h"
34 #include "config.h"
35 #include "str.h"
36 #include "utils.h"
37 #include "mimetype.h"
38 #include "info.h"
39 #include "logfile.h"
40 #include "memory.h"
41 #include "plugin.h"
43 struct mk_config *mk_config_create(char *path)
45 FILE *f;
46 int len;
47 char buf[255];
48 char *key=0, *val=0, *last=0;
49 struct mk_config *cnf=0, *new, *p;
51 if((f=fopen(path, "r")) == NULL) {
52 fprintf(stderr, "\nConfig Error: I can't open %s file\n\n", path);
53 exit(1);
56 /* looking for configuration directives */
57 while(fgets(buf, 255, f)){
58 len = strlen(buf);
59 if(buf[len-1] == '\n') {
60 buf[--len] = 0;
61 if(len && buf[len-1] == '\r')
62 buf[--len] = 0;
65 if(!buf[0] || buf[0] == '#')
66 continue;
68 key = strtok_r(buf, "\"\t ", &last);
69 val = strtok_r(NULL, "\n", &last);
71 if(!key || !val){
72 continue;
75 /* Allow new entry found */
76 new = mk_mem_malloc(sizeof(struct mk_config));
77 new->key = mk_string_dup(key);
78 new->val = mk_string_dup(val);
79 new->next = NULL;
81 /* Link to main list */
82 if(!cnf){
83 cnf = new;
85 else{
86 p = cnf;
87 while(p->next){
88 p = p->next;
90 p->next = new;
94 fclose(f);
95 return cnf;
98 void mk_config_free(struct mk_config *cnf)
100 struct mk_config *prev=0, *target;
102 target = cnf;
103 while(target){
104 while(target->next){
105 prev = target;
106 target = target->next;
109 mk_mem_free(target);
111 if(target == cnf){
112 return;
114 prev->next = NULL;
115 target = cnf;
119 void *mk_config_getval(struct mk_config *cnf, char *key, int mode)
121 int on, off;
122 struct mk_config *p;
124 p = cnf;
125 while(p){
126 if(strcasecmp(p->key, key) == 0){
127 switch(mode){
128 case MK_CONFIG_VAL_STR:
129 return (void *) p->val;
130 case MK_CONFIG_VAL_NUM:
131 return (void *) atoi(p->val);
132 case MK_CONFIG_VAL_BOOL:
133 on = strcasecmp(p->val, VALUE_ON);
134 off = strcasecmp(p->val,VALUE_OFF);
136 if(on!=0 && off!=0){
137 return (void *) -1;
139 else if(on>=0){
140 return (void *) VAR_ON;
142 else{
143 return (void *) VAR_OFF;
145 case MK_CONFIG_VAL_LIST:
146 return mk_string_split_line(p->val);
149 else{
150 p = p->next;
153 return NULL;
156 /* Read configuration files */
157 void mk_config_read_files(char *path_conf, char *file_conf)
159 unsigned long len;
160 char *path=0;
161 struct stat checkdir;
162 struct mk_config *cnf;
163 struct mk_string_line *line, *line_val;
165 config->serverconf = mk_string_dup(path_conf);
166 config->workers = MK_WORKERS_DEFAULT;
168 if(stat(config->serverconf, &checkdir)==-1){
169 fprintf(stderr, "ERROR: Invalid path to configuration files.");
170 exit(1);
173 m_build_buffer(&path, &len, "%s/%s", path_conf, file_conf);
175 cnf = mk_config_create(path);
177 /* Connection port */
178 config->serverport = (int) mk_config_getval(cnf,
179 "Port",
180 MK_CONFIG_VAL_NUM);
181 if(!config->serverport>=1 && !config->serverport<=65535){
182 mk_config_print_error_msg("Port", path);
185 /* Number of thread workers */
186 config->workers = (int) mk_config_getval(cnf,
187 "Workers",
188 MK_CONFIG_VAL_NUM);
189 if(config->maxclients < 1){
190 mk_config_print_error_msg("Workers", path);
193 /* Timeout */
194 config->timeout = (int) mk_config_getval(cnf,
195 "Timeout",
196 MK_CONFIG_VAL_NUM);
197 if(config->timeout < 1){
198 mk_config_print_error_msg("Timeout", path);
201 /* KeepAlive */
202 config->keep_alive = (int) mk_config_getval(cnf,
203 "KeepAlive",
204 MK_CONFIG_VAL_BOOL);
205 if(config->keep_alive == VAR_ERR){
206 mk_config_print_error_msg("KeepAlive", path);
209 /* MaxKeepAliveRequest */
210 config->max_keep_alive_request = (int) mk_config_getval(cnf,
211 "MaxKeepAliveRequest",
212 MK_CONFIG_VAL_NUM);
213 if(config->max_keep_alive_request == 0){
214 mk_config_print_error_msg("MaxKeepAliveRequest", path);
217 /* KeepAliveTimeout */
218 config->keep_alive_timeout = (int) mk_config_getval(cnf,
219 "KeepAliveTimeout",
220 MK_CONFIG_VAL_NUM);
221 if(config->keep_alive_timeout == 0){
222 mk_config_print_error_msg("KeepAliveTimeout", path);
225 /* Pid File */
226 config->pid_file_path = mk_config_getval(cnf,
227 "PidFile",
228 MK_CONFIG_VAL_STR);
230 /* Home user's directory /~ */
231 config->user_dir = mk_config_getval(cnf, "UserDir", MK_CONFIG_VAL_STR);
233 /* Index files */
234 line_val = line = mk_config_getval(cnf, "Indexfile", MK_CONFIG_VAL_LIST);
235 while(line_val!=NULL) {
236 mk_config_add_index(line_val->val);
237 line_val = line_val->next;
240 /* HideVersion Variable */
241 config->hideversion = (int) mk_config_getval(cnf,
242 "HideVersion",
243 MK_CONFIG_VAL_BOOL);
244 if(config->hideversion == VAR_ERR){
245 mk_config_print_error_msg("HideVersion", path);
248 /* User Variable */
249 config->user = mk_config_getval(cnf, "User", MK_CONFIG_VAL_STR);
251 /* Resume */
252 config->resume = (int) mk_config_getval(cnf,
253 "Resume",
254 MK_CONFIG_VAL_BOOL);
255 if(config->resume == VAR_ERR){
256 mk_config_print_error_msg("Resume", path);
259 /* Symbolic Links */
260 config->symlink = (int) mk_config_getval(cnf,
261 "SymLink",
262 MK_CONFIG_VAL_BOOL);
263 if(config->symlink == VAR_ERR){
264 mk_config_print_error_msg("SymLink", path);
267 mk_mem_free(path);
268 mk_config_free(cnf);
269 mk_config_read_hosts(path_conf);
272 void mk_config_read_hosts(char *path)
274 DIR *dir;
275 unsigned long len;
276 char *buf=0;
277 char *file;
278 struct host *p_host, *new_host; /* debug */
279 struct dirent *ent;
281 m_build_buffer(&buf, &len, "%s/sites/default", path);
282 config->hosts = mk_config_get_host(buf);
283 config->nhosts++;
284 mk_mem_free(buf);
286 if(!config->hosts)
288 printf("\nError parsing main configuration file 'default'\n");
289 exit(1);
292 m_build_buffer(&buf, &len, "%s/sites/", path);
293 if (!(dir = opendir(buf)))
294 exit(1);
297 p_host = config->hosts;
299 /* Reading content */
300 while ((ent = readdir(dir)) != NULL)
302 if (strcmp((char *) ent->d_name, "." ) == 0) continue;
303 if (strcmp((char *) ent->d_name, ".." ) == 0) continue;
304 if (strcasecmp((char *) ent->d_name, "default" ) == 0) continue;
306 m_build_buffer(&file, &len, "%s/sites/%s", path, ent->d_name);
308 new_host = (struct host *) mk_config_get_host(file);
309 mk_mem_free(file);
310 if(!new_host)
312 continue;
314 else{
315 p_host->next = new_host;
316 p_host = new_host;
317 config->nhosts++;
320 closedir(dir);
322 h = config->hosts;
323 while(h)
325 printf("*** HOST ***\n");
326 printf(" [servername]\t\t%s\n", h->servername);
327 printf(" [documentroot]\t\t%s\n", h->documentroot);
328 printf(" [conf file]\t\t%s\n", h->file);
329 printf(" [access log]\t\t%s\n", h->access_log_path);
330 printf(" [error log]\t\t%s\n", h->error_log_path);
331 printf(" [script alias]\t\t%s %s\n", h->scriptalias[0], h->scriptalias[1]);
332 printf(" [get dir]\t\t%i\n", h->getdir);
333 printf(" [header file]\t\t%s\n", h->header_file);
334 printf(" [footer file]\t\t%s\n\n", h->footer_file);
336 h = h->next;
338 fflush(stdout);
342 struct host *mk_config_get_host(char *path)
344 unsigned long len=0;
345 struct stat checkdir;
346 struct host *host;
347 struct mk_config *cnf;
349 cnf = mk_config_create(path);
351 host = mk_mem_malloc_z(sizeof(struct host));
352 host->servername = 0;
353 host->file = mk_string_dup(path);
355 host->servername = mk_config_getval(cnf, "Servername", MK_CONFIG_VAL_STR);
356 host->documentroot.data = mk_config_getval(cnf,
357 "DocumentRoot",
358 MK_CONFIG_VAL_STR);
359 host->documentroot.len = strlen(host->documentroot.data);
360 if(stat(host->documentroot.data, &checkdir)==-1) {
361 fprintf(stderr,
362 "ERROR: Invalid path to Server_root in %s\n\n",
363 path);
364 exit(1);
366 else if(!(checkdir.st_mode & S_IFDIR)) {
367 fprintf(stderr,
368 "ERROR: DocumentRoot variable in %s has an invalid directory path\n\n",
369 path);
370 exit(1);
373 /* Access log */
374 host->access_log_path = mk_config_getval(cnf,
375 "AccessLog",
376 MK_CONFIG_VAL_STR);
377 /* Error log */
378 host->error_log_path = mk_config_getval(cnf,
379 "ErrorLog",
380 MK_CONFIG_VAL_STR);
382 /* Get directory */
383 host->getdir = (int) mk_config_getval(cnf, "GetDir", MK_CONFIG_VAL_BOOL);
384 if(host->getdir == VAR_ERR){
385 mk_config_print_error_msg("GetDir", path);
388 if(!host->servername){
389 mk_config_free(cnf);
390 return NULL;
393 /* Server Signature */
394 if(config->hideversion==VAR_OFF){
395 m_build_buffer(&host->host_signature, &len,
396 "Monkey/%s Server (Host: %s, Port: %i)",
397 VERSION, host->servername, config->serverport);
399 else{
400 m_build_buffer(&host->host_signature, &len,
401 "Monkey Server (Host: %s, Port: %i)",
402 host->servername, config->serverport);
404 m_build_buffer(&host->header_host_signature.data,
405 &host->header_host_signature.len,
406 "Server: %s", host->host_signature);
408 if(pipe(host->log_access)<0){
409 perror("pipe");
412 if(pipe(host->log_error)<0){
413 perror("pipe");
416 fcntl(host->log_access[1], F_SETFL, O_NONBLOCK);
417 fcntl(host->log_error[1], F_SETFL, O_NONBLOCK);
419 host->next = NULL;
420 mk_config_free(cnf);
421 return host;
424 /* Imprime error de configuracion y cierra */
425 void mk_config_print_error_msg(char *variable, char *path)
427 fprintf(stderr, "\nError: %s variable in %s has an invalid value.\n", variable, path);
428 fflush(stderr);
429 exit(1);
432 /* Agrega distintos index.xxx */
433 void mk_config_add_index(char *indexname)
435 struct indexfile *new_index=0, *aux_index;
437 new_index = (struct indexfile *) malloc(sizeof(struct indexfile));
438 strncpy(new_index->indexname,indexname,MAX_INDEX_NOMBRE - 1);
439 new_index->indexname[MAX_INDEX_NOMBRE - 1]='\0';
440 new_index->next=NULL;
442 if(first_index==NULL) {
443 first_index=new_index;
445 else {
446 aux_index=first_index;
447 while(aux_index->next!=NULL)
448 aux_index=aux_index->next;
449 aux_index->next=new_index;
453 void mk_config_set_init_values(void)
455 /* Valores iniciales */
456 config->timeout=15;
457 config->hideversion=VAR_OFF;
458 config->keep_alive=VAR_ON;
459 config->keep_alive_timeout=15;
460 config->max_keep_alive_request=50;
461 config->maxclients=150;
462 config->max_ip = 15;
463 config->resume=VAR_ON;
464 config->standard_port=80;
465 config->serverport=2001;
466 config->symlink=VAR_OFF;
467 config->nhosts = 0;
468 config->user = NULL;
469 config->open_flags = O_RDONLY | O_NONBLOCK;
471 /* Plugins */
472 config->plugins = mk_mem_malloc_z(sizeof(struct plugin_stages));
475 /* read main configuration from monkey.conf */
476 void mk_config_start_configure(void)
478 unsigned long len;
480 mk_config_set_init_values();
481 mk_config_read_files(config->file_config, M_DEFAULT_CONFIG_FILE);
483 /* if not index names defined, set default */
484 if(first_index==NULL){
485 mk_config_add_index("index.html");
488 /* Load mimes */
489 mk_mimetype_read_config();
491 /* Basic server information */
492 if(config->hideversion==VAR_OFF)
494 m_build_buffer(&config->server_software.data,
495 &len, "Monkey/%s (%s)",VERSION,OS);
496 config->server_software.len = len;
498 else
500 m_build_buffer(&config->server_software.data, &len,
501 "Monkey Server");
502 config->server_software.len = len;
506 struct host *mk_config_host_find(mk_pointer host)
508 struct host *aux_host;
510 aux_host = config->hosts;
512 while(aux_host){
513 if(strncasecmp(aux_host->servername, host.data, host.len)==0)
514 break;
515 else
516 aux_host=aux_host->next;
519 return aux_host;
522 void mk_config_sanity_check()
524 /* Check O_NOATIME for current user, flag will just be used
525 * if running user is allowed to.
527 int fd, flags=config->open_flags;
529 flags |= O_NOATIME;
530 fd = open(config->file_config, flags);
532 if(fd > -1){
533 config->open_flags = flags;
534 close(fd);