]> arthur.barton.de Git - netatalk.git/blob - etc/cnid_dbd/db_param.c
Fix dbd vs cnid_dbd locking
[netatalk.git] / etc / cnid_dbd / db_param.c
1 /*
2  * $Id: db_param.c,v 1.9 2009-11-23 19:04:14 franklahm Exp $
3  *
4  * Copyright (C) Joerg Lenneis 2003
5  * Copyright (c) Frank Lahm 2009
6  * All Rights Reserved.  See COPYING.
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif /* HAVE_CONFIG_H */
12
13 #include <unistd.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <errno.h>
18 #include <sys/param.h>
19 #include <sys/un.h>
20 #include <sys/select.h>
21 #include <atalk/logger.h>
22
23 #include "db_param.h"
24
25 #define DB_PARAM_FN       "db_param"
26 #define MAXKEYLEN         64
27
28 #define DEFAULT_LOGFILE_AUTOREMOVE 1
29 #define DEFAULT_CACHESIZE          (8 * 1024)
30 #define DEFAULT_FLUSH_FREQUENCY    1000
31 #define DEFAULT_FLUSH_INTERVAL     1800
32 #define DEFAULT_USOCK_FILE         "usock"
33 #define DEFAULT_FD_TABLE_SIZE      512
34 #define DEFAULT_IDLE_TIMEOUT       (10 * 60)
35
36 static struct db_param params;
37 static int parse_err;
38
39 static size_t usock_maxlen(void)
40 {
41     struct sockaddr_un addr;
42     return sizeof(addr.sun_path) - 1;
43 }
44
45 static int make_pathname(char *path, char *dir, char *fn, size_t maxlen)
46 {
47     size_t len;
48
49     if (fn[0] != '/') {
50         len = strlen(dir);
51         if (len + 1 + strlen(fn) > maxlen)
52             return -1;      
53         strcpy(path, dir);
54         if (path[len - 1] != '/')
55             strcat(path, "/");
56         strcat(path, fn);
57     } else {
58         if (strlen(fn) > maxlen)
59             return -1;
60         strcpy(path, fn);
61     }
62     return 0;
63 }
64
65 static void default_params(struct db_param *dbp, char *dir)
66 {        
67     dbp->logfile_autoremove  = DEFAULT_LOGFILE_AUTOREMOVE;
68     dbp->cachesize           = DEFAULT_CACHESIZE;
69     dbp->flush_frequency     = DEFAULT_FLUSH_FREQUENCY;
70     dbp->flush_interval      = DEFAULT_FLUSH_INTERVAL;
71     if (make_pathname(dbp->usock_file, dir, DEFAULT_USOCK_FILE, usock_maxlen()) < 0) {
72         /* Not an error yet, it might be set in the config file */
73         dbp->usock_file[0] = '\0';
74     }
75     dbp->fd_table_size       = DEFAULT_FD_TABLE_SIZE;
76     if ( dbp->fd_table_size > FD_SETSIZE -1)
77         dbp->fd_table_size = FD_SETSIZE -1;
78     dbp->idle_timeout        = DEFAULT_IDLE_TIMEOUT;
79
80     return;
81 }
82
83 static int parse_int(char *val)
84 {
85     char *tmp;
86     int   result = 0;
87
88     result = strtol(val, &tmp, 10);
89     if (tmp[0] != '\0') {
90         LOG(log_error, logtype_cnid, "invalid characters in token %s", val);
91         parse_err++;
92     }
93     return result;
94 }
95
96
97 /* TODO: This configuration file reading routine is neither very robust (%s
98    buffer overflow) nor elegant, we need to add support for whitespace in
99    filenames as well. */
100
101 struct db_param *db_param_read(char *dir, enum identity id)
102 {
103     FILE *fp;
104     static char key[MAXKEYLEN + 1];
105     static char val[MAXPATHLEN + 1];
106     static char pfn[MAXPATHLEN + 1];
107     int    items;
108     
109     default_params(&params, dir);
110     params.dir = dir;
111     
112     if (make_pathname(pfn, dir, DB_PARAM_FN, MAXPATHLEN) < 0) {
113         LOG(log_error, logtype_cnid, "Parameter filename too long");
114         return NULL;
115     }
116
117     if ((fp = fopen(pfn, "r")) == NULL) {
118         if (errno == ENOENT) {
119             if (strlen(params.usock_file) == 0) {
120                 LOG(log_error, logtype_cnid, "default usock filename too long");
121                 return NULL;
122             } else {
123                 return &params;
124             }
125         } else {
126             LOG(log_error, logtype_cnid, "error opening %s: %s", pfn, strerror(errno));
127             return NULL;
128         }
129     }
130     parse_err = 0;
131
132     while ((items = fscanf(fp, " %s %s", key, val)) != EOF) {
133         if (items != 2) {
134             LOG(log_error, logtype_cnid, "error parsing config file");
135             parse_err++;
136             break;
137         }
138
139         /* Config for both cnid_meta and dbd */
140         if (! strcmp(key, "usock_file")) {
141             if (make_pathname(params.usock_file, dir, val, usock_maxlen()) < 0) {
142                 LOG(log_error, logtype_cnid, "usock filename %s too long", val);
143                 parse_err++;
144             } else
145                 LOG(log_info, logtype_cnid, "db_param: setting UNIX domain socket filename to %s", params.usock_file);
146         }
147
148         /* Config for cnid_metad only */
149         if ( id == METAD ) {
150             /* Currently empty */
151         }
152
153         /* Config for dbd only */
154         else if (id == CNID_DBD ) {
155             if (! strcmp(key, "fd_table_size")) {
156                 params.fd_table_size = parse_int(val);
157                 LOG(log_info, logtype_cnid, "db_param: setting max number of concurrent afpd connections per volume (fd_table_size) to %d", params.fd_table_size);
158             } else if (! strcmp(key, "logfile_autoremove")) {
159                 params.logfile_autoremove = parse_int(val);
160                 LOG(log_info, logtype_cnid, "db_param: setting logfile_autoremove to %d", params.logfile_autoremove);
161             } else if (! strcmp(key, "cachesize")) {
162                 params.cachesize = parse_int(val);
163                 LOG(log_info, logtype_cnid, "db_param: setting cachesize to %d", params.cachesize);
164             } else if (! strcmp(key, "flush_frequency")) {
165                 params.flush_frequency = parse_int(val);
166                 LOG(log_info, logtype_cnid, "db_param: setting flush_frequency to %d", params.flush_frequency);
167             } else if (! strcmp(key, "flush_interval")) {
168                 params.flush_interval = parse_int(val);
169                 LOG(log_info, logtype_cnid, "db_param: setting flush_interval to %d", params.flush_interval);
170             } else if (! strcmp(key, "idle_timeout")) {
171                 params.idle_timeout = parse_int(val);
172                 LOG(log_info, logtype_cnid, "db_param: setting idle timeout to %d", params.idle_timeout);
173             }
174         }
175         if (parse_err)
176             break;
177     }
178     
179     if (strlen(params.usock_file) == 0) {
180         LOG(log_error, logtype_cnid, "default usock filename too long");
181         parse_err++;
182     }
183
184     fclose(fp);
185     if (! parse_err) {
186         /* sanity checks */
187         if (params.flush_frequency <= 0) 
188             params.flush_frequency = 86400;
189
190         if (params.flush_interval <= 0)
191             params.flush_interval = 1000000;
192
193         if (params.fd_table_size <= 2)
194             params.fd_table_size = 32;
195
196         if (params.idle_timeout <= 0)
197             params.idle_timeout = 86400;
198
199         return &params;
200     }
201     else
202         return NULL;
203 }
204
205
206