]> arthur.barton.de Git - netatalk.git/blobdiff - etc/cnid_dbd/cnid_metad.c
fix a signed/unsigned, 16/32 bits mismatch. from Burkhard Schmidt, bs at cpfs.mpg.de.
[netatalk.git] / etc / cnid_dbd / cnid_metad.c
index 4e8541b15ab126c7c00ec4558c5da53e53b70c9b..d5c44d028d597305cc233532519e51386a11d6c0 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * $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.
  *
  */
 
@@ -36,6 +36,7 @@
 #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];
@@ -110,11 +132,19 @@ static int send_cred(int socket, int fd)
    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;
@@ -126,7 +156,7 @@ static int send_cred(int socket, int fd)
    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;
@@ -141,8 +171,10 @@ static int send_cred(int socket, int fd)
    } 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;
 }
 
@@ -151,13 +183,16 @@ static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
 {
     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;
        }
@@ -173,6 +208,7 @@ static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
                 free(up->name);
                 up->tm = t;
                 up->count = 0;
+                up->toofast = 0;
                 /* copy name */
                 up->name = strdup(dbdir);
                 break;
@@ -186,12 +222,18 @@ static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
     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 ? */
@@ -202,8 +244,8 @@ static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
     /* 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;
     }
         
@@ -212,21 +254,36 @@ static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
        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);
        }
@@ -235,6 +292,8 @@ static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
      *  Parent.
      */
     up->pid = pid;
+    close(sv[1]);
+    up->control_fd = sv[0];
     return 0;
 }
 
@@ -310,9 +369,9 @@ int main(int argc, char *argv[])
     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;
@@ -321,6 +380,8 @@ int main(int argc, char *argv[])
     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) {
@@ -356,7 +417,7 @@ int main(int argc, char *argv[])
         }
     }
     
-    if (err || !host || !port || !dbdpn) {
+    if (err) {
         LOG(log_error, logtype_cnid, "main: bad arguments");
         exit(1);
     }
@@ -392,18 +453,18 @@ int main(int argc, char *argv[])
 
     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);
             }
@@ -413,6 +474,7 @@ int main(int argc, char *argv[])
     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++) {
@@ -421,8 +483,7 @@ int main(int argc, char *argv[])
 #if 0                   
                    free(srv[i].name);
 #endif                   
-                   close(srv[i].sv[0]);
-                   close(srv[i].sv[1]);
+                   close(srv[i].control_fd);
                    break;
                }
             }
@@ -437,7 +498,7 @@ int main(int argc, char *argv[])
            /* 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 ... */