2 * $Id: main.c,v 1.16 2009-11-25 14:59:15 franklahm Exp $
4 * Copyright (C) Joerg Lenneis 2003
5 * Copyright (c) Frank Lahm 2009
6 * All Rights Reserved. See COPYING.
11 #endif /* HAVE_CONFIG_H */
15 #endif /* HAVE_UNISTD_H */
18 #endif /* HAVE_FCNTL_H */
24 #ifdef HAVE_SYS_TYPES_H
25 #include <sys/types.h>
26 #endif /* HAVE_SYS_TYPES_H */
27 #include <sys/param.h>
28 #ifdef HAVE_SYS_STAT_H
30 #endif /* HAVE_SYS_STAT_H */
34 #include <netatalk/endian.h>
35 #include <atalk/cnid_dbd_private.h>
36 #include <atalk/logger.h>
37 #include <atalk/util.h>
45 Note: DB_INIT_LOCK is here so we can run the db_* utilities while netatalk is running.
46 It's a likey performance hit, but it might we worth it.
48 #define DBOPTIONS (DB_CREATE | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN)
51 static int exit_sig = 0;
54 static void sig_exit(int signo)
60 static void block_sigs_onoff(int block)
65 sigaddset(&set, SIGINT);
66 sigaddset(&set, SIGTERM);
68 sigprocmask(SIG_BLOCK, &set, NULL);
70 sigprocmask(SIG_UNBLOCK, &set, NULL);
75 The dbd_XXX and comm_XXX functions all obey the same protocol for return values:
77 1: Success, if transactions are used commit.
78 0: Failure, but we continue to serve requests. If transactions are used abort/rollback.
79 -1: Fatal error, either from t
80 he database or from the socket. Abort the transaction if applicable
81 (which might fail as well) and then exit.
83 We always try to notify the client process about the outcome, the result field
84 of the cnid_dbd_rply structure contains further details.
88 #define min(a,b) ((a)<(b)?(a):(b))
91 static int loop(struct db_param *dbp)
93 struct cnid_dbd_rqst rqst;
94 struct cnid_dbd_rply rply;
98 time_t now, time_next_flush, time_last_rqst;
100 static char namebuf[MAXPATHLEN + 1];
104 sigprocmask(SIG_SETMASK, NULL, &set);
105 sigdelset(&set, SIGINT);
106 sigdelset(&set, SIGTERM);
110 time_next_flush = now + dbp->flush_interval;
111 time_last_rqst = now;
115 strftime(timebuf, 63, "%b %d %H:%M:%S.",localtime(&time_next_flush));
116 LOG(log_debug, logtype_cnid, "Checkpoint interval: %d seconds. Next checkpoint: %s",
117 dbp->flush_interval, timebuf);
120 timeout = min(time_next_flush, time_last_rqst +dbp->idle_timeout);
126 if ((cret = comm_rcv(&rqst, timeout, &set, &now)) < 0)
130 /* comm_rcv returned from select without receiving anything. */
132 /* Received signal (TERM|INT) */
135 if (now - time_last_rqst >= dbp->idle_timeout && comm_nbe() <= 0) {
139 /* still active connections, reset time_last_rqst */
140 time_last_rqst = now;
142 /* We got a request */
143 time_last_rqst = now;
145 memset(&rply, 0, sizeof(rply));
147 /* ret gets set here */
148 case CNID_DBD_OP_OPEN:
149 case CNID_DBD_OP_CLOSE:
150 /* open/close are noops for now. */
154 case CNID_DBD_OP_ADD:
155 ret = dbd_add(dbd, &rqst, &rply, 0);
157 case CNID_DBD_OP_GET:
158 ret = dbd_get(dbd, &rqst, &rply);
160 case CNID_DBD_OP_RESOLVE:
161 ret = dbd_resolve(dbd, &rqst, &rply);
163 case CNID_DBD_OP_LOOKUP:
164 ret = dbd_lookup(dbd, &rqst, &rply, 0);
166 case CNID_DBD_OP_UPDATE:
167 ret = dbd_update(dbd, &rqst, &rply);
169 case CNID_DBD_OP_DELETE:
170 ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID);
172 case CNID_DBD_OP_GETSTAMP:
173 ret = dbd_getstamp(dbd, &rqst, &rply);
175 case CNID_DBD_OP_REBUILD_ADD:
176 ret = dbd_rebuild_add(dbd, &rqst, &rply);
179 LOG(log_error, logtype_cnid, "loop: unknown op %d", rqst.op);
184 if ((cret = comm_snd(&rply)) < 0 || ret < 0) {
189 if (ret == 0 || cret == 0) {
190 if (dbif_txn_abort(dbd) < 0)
193 ret = dbif_txn_commit(dbd);
197 /* We had a designated txn because we wrote to the db */
200 } /* got a request */
203 Shall we checkpoint bdb ?
204 "flush_interval" seconds passed ?
206 if (now >= time_next_flush) {
207 LOG(log_info, logtype_cnid, "Checkpointing BerkeleyDB for volume '%s'", dbp->dir);
208 if (dbif_txn_checkpoint(dbd, 0, 0, 0) < 0)
211 time_next_flush = now + dbp->flush_interval;
213 strftime(timebuf, 63, "%b %d %H:%M:%S.",localtime(&time_next_flush));
214 LOG(log_debug, logtype_cnid, "Checkpoint interval: %d seconds. Next checkpoint: %s",
215 dbp->flush_interval, timebuf);
219 Shall we checkpoint bdb ?
220 Have we commited "count" more changes than "flush_frequency" ?
222 if (count > dbp->flush_frequency) {
223 LOG(log_info, logtype_cnid, "Checkpointing BerkeleyDB after %d writes for volume '%s'", count, dbp->dir);
224 if (dbif_txn_checkpoint(dbd, 0, 0, 0) < 0)
231 /* ------------------------ */
232 static void switch_to_user(char *dir)
236 if (chdir(dir) < 0) {
237 LOG(log_error, logtype_cnid, "chdir to %s failed: %s", dir, strerror(errno));
241 if (stat(".", &st) < 0) {
242 LOG(log_error, logtype_cnid, "error in stat for %s: %s", dir, strerror(errno));
246 LOG(log_info, logtype_cnid, "Setting uid/gid to %i/%i", st.st_uid, st.st_gid);
247 if (setgid(st.st_gid) < 0 || setuid(st.st_uid) < 0) {
248 LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
255 /* ----------------------- */
256 static void set_signal(void)
260 sv.sa_handler = sig_exit;
262 sigemptyset(&sv.sa_mask);
263 sigaddset(&sv.sa_mask, SIGINT);
264 sigaddset(&sv.sa_mask, SIGTERM);
265 if (sigaction(SIGINT, &sv, NULL) < 0 || sigaction(SIGTERM, &sv, NULL) < 0) {
266 LOG(log_error, logtype_cnid, "main: sigaction: %s", strerror(errno));
269 sv.sa_handler = SIG_IGN;
270 sigemptyset(&sv.sa_mask);
271 if (sigaction(SIGPIPE, &sv, NULL) < 0) {
272 LOG(log_error, logtype_cnid, "main: sigaction: %s", strerror(errno));
277 /* ------------------------ */
278 int main(int argc, char *argv[])
280 struct db_param *dbp;
283 char *dir, *logconfig;
285 set_processname("cnid_dbd");
287 /* FIXME: implement -d from cnid_metad */
289 LOG(log_error, logtype_cnid, "main: not enough arguments");
294 ctrlfd = atoi(argv[2]);
295 clntfd = atoi(argv[3]);
296 logconfig = strdup(argv[4]);
302 if ((db_locked = get_lock(LOCK_EXCL, dir)) == -1) {
303 LOG(log_error, logtype_cnid, "main: fatal db lock error");
306 if (db_locked != LOCK_EXCL) {
307 /* Couldn't get exclusive lock, try shared lock */
308 if ((db_locked = get_lock(LOCK_SHRD, NULL)) != LOCK_SHRD) {
309 LOG(log_error, logtype_cnid, "main: fatal db lock error");
314 LOG(log_info, logtype_cnid, "Startup, DB dir %s", dir);
318 /* SIGINT and SIGTERM are always off, unless we are in pselect */
321 if ((dbp = db_param_read(dir, CNID_DBD)) == NULL)
323 LOG(log_maxdebug, logtype_cnid, "Finished parsing db_param config file");
325 if (NULL == (dbd = dbif_init(".", "cnid2.db")))
328 /* Only recover if we got the lock */
329 if (dbif_env_open(dbd,
331 (db_locked == LOCK_EXCL) ? DBOPTIONS | DB_RECOVER : DBOPTIONS) < 0)
332 exit(2); /* FIXME: same exit code as failure for dbif_open() */
333 LOG(log_debug, logtype_cnid, "Finished initializing BerkeleyDB environment");
335 if (dbif_open(dbd, dbp, 0) < 0) {
339 LOG(log_debug, logtype_cnid, "Finished opening BerkeleyDB databases");
341 /* Downgrade db lock */
342 if (db_locked == LOCK_EXCL) {
343 if (get_lock(LOCK_UNLOCK, NULL) != 0) {
347 if (get_lock(LOCK_SHRD, NULL) != LOCK_SHRD) {
354 if (dbd_stamp(dbd) < 0) {
358 LOG(log_maxdebug, logtype_cnid, "Finished checking database stamp");
360 if (comm_init(dbp, ctrlfd, clntfd) < 0) {
368 if (dbif_close(dbd) < 0)
371 if (dbif_prep_upgrade(dir) < 0)
377 LOG(log_info, logtype_cnid, "main: Exiting on signal %i", exit_sig);
379 LOG(log_info, logtype_cnid, "main: Idle timeout, exiting");