2 * $Id: main.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
4 * Copyright (C) Joerg Lenneis 2003
5 * All Rights Reserved. See COPYING.
10 #endif /* HAVE_CONFIG_H */
14 #endif /* HAVE_UNISTD_H */
17 #endif /* HAVE_FCNTL_H */
23 #ifdef HAVE_SYS_TYPES_H
24 #include <sys/types.h>
25 #endif /* HAVE_SYS_TYPES_H */
26 #include <sys/param.h>
27 #ifdef HAVE_SYS_STAT_H
29 #endif /* HAVE_SYS_STAT_H */
33 #include <netatalk/endian.h>
34 #include <atalk/cnid_dbd_private.h>
35 #include <atalk/logger.h>
43 #define LOCKFILENAME "lock"
45 static int exit_sig = 0;
48 static void sig_exit(int signo)
54 static void block_sigs_onoff(int block)
59 sigaddset(&set, SIGINT);
60 sigaddset(&set, SIGTERM);
62 sigprocmask(SIG_BLOCK, &set, NULL);
64 sigprocmask(SIG_UNBLOCK, &set, NULL);
69 The dbd_XXX and comm_XXX functions all obey the same protocol for return values:
71 1: Success, if transactions are used commit.
72 0: Failure, but we continue to serve requests. If transactions are used abort/rollback.
73 -1: Fatal error, either from the database or from the socket. Abort the transaction if applicable
74 (which might fail as well) and then exit.
76 We always try to notify the client process about the outcome, the result field
77 of the cnid_dbd_rply structure contains further details.
81 static int loop(struct db_param *dbp)
83 struct cnid_dbd_rqst rqst;
84 struct cnid_dbd_rply rply;
86 time_t now, time_next_flush, time_last_rqst;
88 static char namebuf[MAXPATHLEN + 1];
89 u_int32_t checkp_flags;
93 time_next_flush = now + dbp->flush_interval;
96 checkp_flags = DB_FORCE;
103 if ((cret = comm_rcv(&rqst)) < 0)
108 if (count > dbp->flush_frequency || now > time_next_flush) {
109 #ifdef CNID_BACKEND_DBD_TXN
110 if (dbif_txn_checkpoint(0, 0, checkp_flags) < 0)
117 time_next_flush = now + dbp->flush_interval;
125 if (dbp->idle_timeout && comm_nbe() <= 0 && (now - time_last_rqst) > dbp->idle_timeout)
129 /* We got a request */
130 time_last_rqst = now;
133 #ifdef CNID_BACKEND_DBD_TXN
134 if (dbif_txn_begin() < 0)
136 #endif /* CNID_BACKEND_DBD_TXN */
138 memset(&rply, 0, sizeof(rply));
140 /* ret gets set here */
141 case CNID_DBD_OP_OPEN:
142 case CNID_DBD_OP_CLOSE:
143 /* open/close are noops for now. */
147 case CNID_DBD_OP_ADD:
148 ret = dbd_add(&rqst, &rply);
150 case CNID_DBD_OP_GET:
151 ret = dbd_get(&rqst, &rply);
153 case CNID_DBD_OP_RESOLVE:
154 ret = dbd_resolve(&rqst, &rply);
156 case CNID_DBD_OP_LOOKUP:
157 ret = dbd_lookup(&rqst, &rply);
159 case CNID_DBD_OP_UPDATE:
160 ret = dbd_update(&rqst, &rply);
162 case CNID_DBD_OP_DELETE:
163 ret = dbd_delete(&rqst, &rply);
165 case CNID_DBD_OP_GETSTAMP:
166 ret = dbd_getstamp(&rqst, &rply);
168 case CNID_DBD_OP_REBUILD_ADD:
169 ret = dbd_rebuild_add(&rqst, &rply);
172 LOG(log_error, logtype_cnid, "loop: unknown op %d", rqst.op);
177 if ((cret = comm_snd(&rply)) < 0 || ret < 0) {
178 #ifdef CNID_BACKEND_DBD_TXN
180 #endif /* CNID_BACKEND_DBD_TXN */
183 #ifdef CNID_BACKEND_DBD_TXN
184 if (ret == 0 || cret == 0) {
185 if (dbif_txn_abort() < 0)
188 if (dbif_txn_commit() < 0)
191 #endif /* CNID_BACKEND_DBD_TXN */
195 /* ------------------------ */
196 static void switch_to_user(char *dir)
200 if (chdir(dir) < 0) {
201 LOG(log_error, logtype_cnid, "chdir to %s failed: %s", dir, strerror(errno));
205 if (stat(".", &st) < 0) {
206 LOG(log_error, logtype_cnid, "error in stat for %s: %s", dir, strerror(errno));
210 LOG(log_info, logtype_cnid, "Setting uid/gid to %i/%i", st.st_uid, st.st_gid);
211 if (setgid(st.st_gid) < 0 || setuid(st.st_uid) < 0) {
212 LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
218 /* ------------------------ */
224 if ((lockfd = open(LOCKFILENAME, O_RDWR | O_CREAT, 0644)) < 0) {
225 LOG(log_error, logtype_cnid, "main: error opening lockfile: %s", strerror(errno));
230 lock.l_whence = SEEK_SET;
232 lock.l_type = F_WRLCK;
234 if (fcntl(lockfd, F_SETLK, &lock) < 0) {
235 if (errno == EACCES || errno == EAGAIN) {
238 LOG(log_error, logtype_cnid, "main: fcntl F_WRLCK lockfile: %s", strerror(errno));
246 /* ----------------------- */
247 void set_signal(void)
251 sv.sa_handler = sig_exit;
253 sigemptyset(&sv.sa_mask);
254 sigaddset(&sv.sa_mask, SIGINT);
255 sigaddset(&sv.sa_mask, SIGTERM);
256 if (sigaction(SIGINT, &sv, NULL) < 0 || sigaction(SIGTERM, &sv, NULL) < 0) {
257 LOG(log_error, logtype_cnid, "main: sigaction: %s", strerror(errno));
260 sv.sa_handler = SIG_IGN;
261 sigemptyset(&sv.sa_mask);
262 if (sigaction(SIGPIPE, &sv, NULL) < 0) {
263 LOG(log_error, logtype_cnid, "main: sigaction: %s", strerror(errno));
268 /* ----------------------- */
269 void free_lock(int lockfd)
274 lock.l_whence = SEEK_SET;
276 lock.l_type = F_UNLCK;
277 fcntl(lockfd, F_SETLK, &lock);
281 /* ------------------------ */
282 int main(int argc, char *argv[])
284 struct db_param *dbp;
287 int lockfd, ctrlfd, clntfd;
290 set_processname("cnid_dbd");
291 syslog_setup(log_debug, logtype_default, logoption_ndelay | logoption_pid, logfacility_daemon);
294 LOG(log_error, logtype_cnid, "main: not enough arguments");
299 ctrlfd = atoi(argv[2]);
300 clntfd = atoi(argv[3]);
304 /* Before we do anything else, check if there is an instance of cnid_dbd
305 running already and silently exit if yes. */
308 LOG(log_info, logtype_cnid, "Startup, DB dir %s", dir);
312 /* SIGINT and SIGTERM are always off, unless we get a return code of 0 from
313 comm_rcv (no requests for one second, see above in loop()). That means we
314 only shut down after one second of inactivity. */
317 if ((dbp = db_param_read(dir)) == NULL)
320 if (dbif_env_init(dbp) < 0)
321 exit(2); /* FIXME: same exit code as failure for dbif_open() */
323 #ifdef CNID_BACKEND_DBD_TXN
324 if (dbif_txn_begin() < 0)
328 if (dbif_open(dbp, 0) < 0) {
329 #ifdef CNID_BACKEND_DBD_TXN
336 #ifndef CNID_BACKEND_DBD_TXN
337 if (dbp->check && (ret = dbd_check(dir))) {
343 LOG(log_info, logtype_cnid, "main: re-opening, secondaries will be rebuilt. This may take some time");
344 if (dbif_open(dbp, 1) < 0) {
345 LOG(log_info, logtype_cnid, "main: re-opening databases failed");
349 LOG(log_info, logtype_cnid, "main: rebuilt done");
353 if (dbd_stamp() < 0) {
354 #ifdef CNID_BACKEND_DBD_TXN
360 #ifdef CNID_BACKEND_DBD_TXN
361 if (dbif_txn_commit() < 0)
365 if (comm_init(dbp, ctrlfd, clntfd) < 0) {
373 #ifndef CNID_BACKEND_DBD_TXN
374 /* FIXME: Do we really need to sync before closing the DB? Just closing it
380 if (dbif_close() < 0)
388 LOG(log_info, logtype_cnid, "main: Exiting on signal %i", exit_sig);
390 LOG(log_info, logtype_cnid, "main: Idle timeout, exiting");