]> arthur.barton.de Git - netatalk.git/blob - etc/cnid_dbd/main.c
big merge for db frontend and unicode.
[netatalk.git] / etc / cnid_dbd / main.c
1 /*
2  * $Id: main.c,v 1.1.4.1 2003-09-09 16:42:20 didg Exp $
3  *
4  * Copyright (C) Joerg Lenneis 2003
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #ifdef HAVE_UNISTD_H
13 #include <unistd.h>
14 #endif /* HAVE_UNISTD_H */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <errno.h>
19 #include <signal.h>
20 #include <string.h>
21
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif /* HAVE_SYS_TYPES_H */
25 #include <sys/param.h>
26 #ifdef HAVE_SYS_STAT_H
27 #include <sys/stat.h>
28 #endif /* HAVE_SYS_STAT_H */
29 #include <time.h>
30
31 #include <netatalk/endian.h>
32 #include <atalk/cnid_dbd_private.h>
33 #include <atalk/logger.h>
34
35 #include "db_param.h"
36 #include "dbif.h"
37 #include "dbd.h"
38 #include "comm.h"
39
40
41 #define LOCKFILENAME  "lock"
42
43 static int exit_sig = 0;
44
45
46 static void sig_exit(int signo)
47 {
48     exit_sig = signo;
49     return;
50 }
51
52 /* 
53    The dbd_XXX and comm_XXX functions all obey the same protocol for return values:
54    
55    1: Success, if transactions are used commit.
56    0: Failure, but we continue to serve requests. If transactions are used abort/rollback.
57   -1: Fatal error, either from the database or from the socket. Abort the transaction if applicable 
58       (which might fail as well) and then exit.
59
60   We always try to notify the client process about the outcome, the result field
61   of the cnid_dbd_rply structure contains further details.
62
63  */
64
65 static void block_sigs_onoff(int block)
66 {
67     sigset_t set;
68     
69     sigemptyset(&set);
70     sigaddset(&set, SIGINT);
71     sigaddset(&set, SIGTERM);
72     if (block)
73         sigprocmask(SIG_BLOCK, &set, NULL);
74     else
75         sigprocmask(SIG_UNBLOCK, &set, NULL);
76     return;
77 }
78
79
80 static int loop(struct db_param *dbp)
81 {
82     struct cnid_dbd_rqst rqst;
83     struct cnid_dbd_rply rply;
84     int ret, cret;
85     time_t now, time_next_flush, time_last_rqst;
86     int count;
87     static char namebuf[MAXPATHLEN + 1];
88     u_int32_t checkp_flags;
89
90     count = 0;
91     now = time(NULL);
92     time_next_flush = now + dbp->flush_interval;
93     time_last_rqst = now;
94     if (dbp->nosync)
95         checkp_flags = DB_FORCE;
96     else 
97         checkp_flags = 0;
98     
99     rqst.name = namebuf;
100
101     while (1) {
102         if ((cret = comm_rcv(&rqst)) < 0) 
103             return -1;
104
105         now = time(NULL);
106         
107         if (count > dbp->flush_frequency || now > time_next_flush) {
108 #ifdef CNID_BACKEND_DBD_TXN
109             if (dbif_txn_checkpoint(0, 0, checkp_flags) < 0)
110                 return -1;
111 #else
112             if (dbif_sync() < 0)
113                 return -1;
114 #endif
115             count = 0;
116             time_next_flush = now + dbp->flush_interval;
117         }
118
119         if (cret == 0) {
120             block_sigs_onoff(0);
121             block_sigs_onoff(1);
122             if (exit_sig)
123                 return 0;
124             if (dbp->idle_timeout && comm_nbe() <= 0 && (now - time_last_rqst) > dbp->idle_timeout)
125                 return 0;
126             continue;
127         }
128         /* We got a request */
129         time_last_rqst = now;
130         count++;
131         
132 #ifdef CNID_BACKEND_DBD_TXN
133         if (dbif_txn_begin() < 0) 
134             return -1;
135 #endif /* CNID_BACKEND_DBD_TXN */
136
137         memset(&rply, 0, sizeof(rply));
138         switch(rqst.op) {
139             /* ret gets set here */
140         case CNID_DBD_OP_OPEN:
141         case CNID_DBD_OP_CLOSE:
142             /* open/close are noops for now. */
143             rply.namelen = 0; 
144             ret = 1;
145             break;
146         case CNID_DBD_OP_ADD:
147             ret = dbd_add(&rqst, &rply);
148             break;
149         case CNID_DBD_OP_GET:
150             ret = dbd_get(&rqst, &rply);
151             break;
152         case CNID_DBD_OP_RESOLVE:
153             ret = dbd_resolve(&rqst, &rply);
154             break;
155         case CNID_DBD_OP_LOOKUP:
156             ret = dbd_lookup(&rqst, &rply);
157             break;
158         case CNID_DBD_OP_UPDATE:
159             ret = dbd_update(&rqst, &rply);
160             break;
161         case CNID_DBD_OP_DELETE:
162             ret = dbd_delete(&rqst, &rply);
163             break;
164         default:
165             LOG(log_error, logtype_cnid, "loop: unknow op %d", rqst.op);
166             break;
167         }       
168
169         if ((cret = comm_snd(&rply)) < 0 || ret < 0) {
170 #ifdef CNID_BACKEND_DBD_TXN
171             dbif_txn_abort();
172 #endif /* CNID_BACKEND_DBD_TXN */
173             return -1;
174         }
175 #ifdef CNID_BACKEND_DBD_TXN
176         if (ret == 0 || cret == 0) {
177             if (dbif_txn_abort() < 0) 
178                 return -1;
179         } else {
180             if (dbif_txn_commit() < 0) 
181                 return -1;
182         }
183 #endif /* CNID_BACKEND_DBD_TXN */
184     }
185 }
186
187
188 int main(int argc, char *argv[])
189 {
190     struct sigaction sv;
191     struct db_param *dbp;
192     int err = 0;
193     struct stat st;
194     int lockfd;
195     char *dir;
196         
197     if (argc  != 2) {
198         LOG(log_error, logtype_cnid, "main: not enough arguments");
199         exit(1);
200     }
201     dir = argv[1];
202     if (chdir(dir) < 0) {
203         LOG(log_error, logtype_cnid, "chdir to %s failed: %s", dir, strerror(errno));
204         exit(1);
205     }
206     if (stat(".", &st) < 0) {
207         LOG(log_error, logtype_cnid, "error in stat for %s: %s", dir, strerror(errno));
208         exit(1);
209     }
210 #if 0
211     LOG(log_info, logtype_cnid, "Setting uid/gid to %i/%i", st.st_uid, st.st_gid);
212     if (setegid(st.st_gid) < 0 || seteuid(st.st_uid) < 0) {
213         LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
214         exit(1);
215     }
216 #endif    
217     /* Before we do anything else, check if there is an instance of cnid_dbd
218        running already and silently exit if yes. */
219     if ((lockfd = open(LOCKFILENAME, O_RDONLY | O_CREAT, 0644)) < 0) {
220         LOG(log_error, logtype_cnid, "main: error opening lockfile: %s", strerror(errno));
221         exit(1);
222     }
223     if (flock(lockfd, LOCK_EX | LOCK_NB) < 0) {
224         if (errno == EWOULDBLOCK) {
225             exit(0);
226         } else {
227             LOG(log_error, logtype_cnid, "main: error in flock: %s", strerror(errno));
228             exit(1);
229         }
230     }
231     LOG(log_info, logtype_cnid, "Startup, DB dir %s", dir);
232
233     sv.sa_handler = sig_exit;
234     sv.sa_flags = 0;
235     sigemptyset(&sv.sa_mask);
236     sigaddset(&sv.sa_mask, SIGINT);
237     sigaddset(&sv.sa_mask, SIGTERM);
238     if (sigaction(SIGINT, &sv, NULL) < 0 || sigaction(SIGTERM, &sv, NULL) < 0) {
239         LOG(log_error, logtype_cnid, "main: sigaction: %s", strerror(errno));
240         exit(1);
241     }
242     sv.sa_handler = SIG_IGN;
243     sigemptyset(&sv.sa_mask);
244     if (sigaction(SIGPIPE, &sv, NULL) < 0) {
245         LOG(log_error, logtype_cnid, "main: sigaction: %s", strerror(errno));
246         exit(1);
247     }
248     /* SIGINT and SIGTERM are always off, unless we get a return code of 0 from
249        comm_rcv (no requests for one second, see above in loop()). That means we
250        only shut down after one second of inactivity. */
251     block_sigs_onoff(1);
252     if ((dbp = db_param_read(dir)) == NULL)
253         exit(1);
254
255     if (dbif_open(dbp) < 0) {
256         dbif_close();
257         exit(2);
258     }
259     if (dbd_stamp() < 0) {
260         dbif_close();
261         exit(5);
262     }
263     if (comm_init(dbp) < 0) {
264         dbif_close();
265         exit(3);
266     }
267     if (loop(dbp) < 0)
268         err++;
269     
270     if (dbif_sync() < 0)
271         err++;
272         
273     if (dbif_close() < 0)
274         err++;
275
276     flock(lockfd, LOCK_UN);
277     close(lockfd);
278     
279     if (err) 
280         exit(4);
281     else {
282         if (exit_sig)
283             LOG(log_info, logtype_cnid, "main: Exiting on signal %i", exit_sig);
284         else
285             LOG(log_info, logtype_cnid, "main: Idle timeout, exiting");
286         exit(0);
287     }
288 }