/*
- * $Id: cnid_metad.c,v 1.1.4.3 2003-10-28 07:24:02 didg Exp $
+ * $Id: cnid_metad.c,v 1.1.4.15 2004-09-06 07:19:21 didg Exp $
*
* Copyright (C) Joerg Lenneis 2003
- * All Rights Reserved. See COPYRIGHT.
+ * All Rights Reserved. See COPYING.
*
*/
#include <sys/uio.h>
#endif
#include <sys/un.h>
+#define _XPG4_2 1
#include <sys/socket.h>
#include <stdio.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
+/* FIXME */
+#ifdef linux
+#ifndef USE_SETRESUID
+#define USE_SETRESUID 1
+#define SWITCH_TO_GID(gid) ((setresgid(gid,gid,gid) < 0 || setgid(gid) < 0) ? -1 : 0)
+#define SWITCH_TO_UID(uid) ((setresuid(uid,uid,uid) < 0 || setuid(uid) < 0) ? -1 : 0)
+#endif
+#else
+#ifndef USE_SETEUID
+#define USE_SETEUID 1
+#define SWITCH_TO_GID(gid) ((setegid(gid) < 0 || setgid(gid) < 0) ? -1 : 0)
+#define SWITCH_TO_UID(uid) ((setuid(uid) < 0 || seteuid(uid) < 0 || setuid(uid) < 0) ? -1 : 0)
+#endif
+#endif
+
#include <atalk/logger.h>
#include <atalk/cnid_dbd_private.h>
static int srvfd;
static int rqstfd;
-#define MAXSRV 20
+#define MAXSRV 128
#define MAXSPAWN 3 /* Max times respawned in.. */
-#define TESTTIME 20 /* this much seconds */
+
+#define DEFAULTHOST "localhost"
+#define DEFAULTPORT 4700
+#define TESTTIME 22 /* this much seconds apfd client tries to
+ * to reconnect every 5 secondes, catch it
+ */
struct server {
char *name;
pid_t pid;
time_t tm; /* When respawned last */
int count; /* Times respawned in the last TESTTIME secondes */
- int sv[2];
+ int toofast;
+ int control_fd; /* file descriptor to child cnid_dbd process */
};
static struct server srv[MAXSRV +1];
struct msghdr msgh;
struct iovec iov[1];
struct cmsghdr *cmsgp = NULL;
- char buf[CMSG_SPACE(sizeof fd)];
+ char *buf;
+ size_t size;
int er=0;
+ size = CMSG_SPACE(sizeof fd);
+ buf = malloc(size);
+ if (!buf) {
+ LOG(log_error, logtype_cnid, "error in sendmsg: %s", strerror(errno));
+ return -1;
+ }
+
memset(&msgh,0,sizeof (msgh));
- memset(buf,0,sizeof (buf));
+ memset(buf,0, size);
msgh.msg_name = NULL;
msgh.msg_namelen = 0;
iov[0].iov_len = sizeof(er);
msgh.msg_control = buf;
- msgh.msg_controllen = sizeof(buf);
+ msgh.msg_controllen = size;
cmsgp = CMSG_FIRSTHDR(&msgh);
cmsgp->cmsg_level = SOL_SOCKET;
} while ( ret == -1 && errno == EINTR );
if (ret == -1) {
LOG(log_error, logtype_cnid, "error in sendmsg: %s", strerror(errno));
+ free(buf);
return -1;
}
+ free(buf);
return 0;
}
{
pid_t pid;
struct server *up;
+ int sv[2];
int i;
time_t t;
+ char buf1[8];
+ char buf2[8];
up = test_usockfn(dbdir, usockfn);
if (up && up->pid) {
/* we already have a process, send our fd */
- if (send_cred(up->sv[0], rqstfd) < 0) {
+ if (send_cred(up->control_fd, rqstfd) < 0) {
/* FIXME */
return -1;
}
free(up->name);
up->tm = t;
up->count = 0;
+ up->toofast = 0;
/* copy name */
up->name = strdup(dbdir);
break;
else {
/* we have a slot but no process, check for respawn too fast */
if (up->tm + TESTTIME > t) {
+ if (up->toofast) {
+ /* silently exit */
+ return -1;
+ }
up->count++;
} else {
up->count = 0;
+ up->toofast = 0;
up->tm = t;
}
- if (up->count >= MAXSPAWN) {
+ if (up->count > MAXSPAWN) {
+ up->toofast = 1;
up->tm = t;
LOG(log_error, logtype_cnid, "respawn too fast %s", up->name);
/* FIXME should we sleep a little ? */
/* create socketpair for comm between parent and child
* FIXME Do we really need a permanent pipe between them ?
*/
- if (socketpair(PF_UNIX, SOCK_STREAM, 0, up->sv) < 0) {
- LOG(log_error, logtype_cnid, "error in fork: %s", strerror(errno));
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) {
+ LOG(log_error, logtype_cnid, "error in socketpair: %s", strerror(errno));
return -1;
}
return -1;
}
if (pid == 0) {
+ int ret;
/*
* Child. Close descriptors and start the daemon. If it fails
* just log it. The client process will fail connecting
* afterwards anyway.
*/
- close(0);
- close(1);
+
close(srvfd);
- dup2(up->sv[1], 0);
- dup2(rqstfd, 1);
+ close(sv[0]);
+
+ for (i = 1; i <= MAXSRV; i++) {
+ if (srv[i].pid && up != &srv[i]) {
+ close(srv[i].control_fd);
+ }
+ }
- close(up->sv[0]);
- close(up->sv[1]);
- close(rqstfd);
- if (execlp(dbdpn, dbdpn, dbdir, NULL) < 0) {
+ sprintf(buf1, "%i", sv[1]);
+ sprintf(buf2, "%i", rqstfd);
+
+ if (up->count == MAXSPAWN) {
+ /* there's a pb with the db inform child
+ * it will run recover, delete the db whatever
+ */
+ LOG(log_error, logtype_cnid, "try with -d %s", up->name);
+ ret = execlp(dbdpn, dbdpn, "-d", dbdir, buf1, buf2, NULL);
+ }
+ else {
+ ret = execlp(dbdpn, dbdpn, dbdir, buf1, buf2, NULL);
+ }
+ if (ret < 0) {
LOG(log_error, logtype_cnid, "Fatal error in exec: %s", strerror(errno));
exit(0);
}
* Parent.
*/
up->pid = pid;
+ close(sv[1]);
+ up->control_fd = sv[0];
return 0;
}
int len;
pid_t pid;
int status;
- char *dbdpn = NULL;
- char *host = NULL;
- int port = 0;
+ char *dbdpn = _PATH_CNID_DBD;
+ char *host = DEFAULTHOST;
+ u_int16_t port = DEFAULTPORT;
struct db_param *dbp;
int i;
int cc;
int err = 0;
int debug = 0;
int ret;
+
+ set_processname("cnid_metad");
while (( cc = getopt( argc, argv, "ds:p:h:u:g:")) != -1 ) {
switch (cc) {
}
}
- if (err || !host || !port || !dbdpn) {
+ if (err) {
LOG(log_error, logtype_cnid, "main: bad arguments");
exit(1);
}
if ((srvfd = tsockfd_create(host, port, 10)) < 0)
exit(1);
+
/* switch uid/gid */
if (uid || gid) {
-
LOG(log_info, logtype_cnid, "Setting uid/gid to %i/%i", uid, gid);
if (gid) {
- if (setresgid(gid,gid,gid) < 0 || setgid(gid) < 0) {
+ if (SWITCH_TO_GID(gid) < 0) {
LOG(log_info, logtype_cnid, "unable to switch to group %d", gid);
exit(1);
}
}
if (uid) {
- if (setresuid(uid,uid,uid) < 0 || setuid(uid) < 0) {
+ if (SWITCH_TO_UID(uid) < 0) {
LOG(log_info, logtype_cnid, "unable to switch to user %d", uid);
exit(1);
}
signal(SIGPIPE, SIG_IGN);
while (1) {
+ rqstfd = usockfd_check(srvfd, 10000000);
/* Collect zombie processes and log what happened to them */
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
for (i = 1; i <= MAXSRV; i++) {
#if 0
free(srv[i].name);
#endif
- close(srv[i].sv[0]);
- close(srv[i].sv[1]);
+ close(srv[i].control_fd);
break;
}
}
/* FIXME should */
}
- if ((rqstfd = usockfd_check(srvfd, 10000000)) <= 0)
+ if (rqstfd <= 0)
continue;
/* TODO: Check out read errors, broken pipe etc. in libatalk. Is
SIGIPE ignored there? Answer: Ignored for dsi, but not for asp ... */