]> arthur.barton.de Git - netatalk.git/commitdiff
Merge 2-2
authorFrank Lahm <franklahm@googlemail.com>
Sat, 5 May 2012 06:20:14 +0000 (08:20 +0200)
committerFrank Lahm <franklahm@googlemail.com>
Sat, 5 May 2012 06:20:14 +0000 (08:20 +0200)
1  2 
etc/afpd/afp_config.c
etc/afpd/afp_dsi.c
etc/afpd/main.c
include/atalk/dsi.h
include/atalk/server_child.h
libatalk/dsi/dsi_getsess.c
libatalk/util/server_child.c

diff --combined etc/afpd/afp_config.c
index ed8067048da2e483bec545c8f61ba4580f5f9dd8,29b552d38b641fb77e5ddc131d5138dadd3998c3..a61fe1022f551ccc84b9fef03c860cfe16c51a30
  #include <netinet/in.h>
  #include <arpa/inet.h>
  
 -#ifdef USE_SRVLOC
 -#include <slp.h>
 -#endif /* USE_SRVLOC */
 -
  #include <atalk/logger.h>
  #include <atalk/util.h>
  #include <atalk/dsi.h>
 -#include <atalk/atp.h>
 -#include <atalk/asp.h>
 -#include <atalk/nbp.h>
  #include <atalk/afp.h>
  #include <atalk/compat.h>
  #include <atalk/server_child.h>
 +#include <atalk/globals.h>
 +#include <atalk/errchk.h>
 +#include <atalk/netatalk_conf.h>
 +#include <atalk/fce_api.h>
  
  #ifdef HAVE_LDAP
  #include <atalk/ldapconfig.h>
  #endif
  
 -#include <atalk/globals.h>
  #include "afp_config.h"
  #include "uam_auth.h"
  #include "status.h"
  #include "volume.h"
  #include "afp_zeroconf.h"
  
 -#define LINESIZE 1024  
  
 -/* get rid of unneeded configurations. i use reference counts to deal
 - * w/ multiple configs sharing the same afp_options. oh, to dream of
 - * garbage collection ... */
 -void configfree(AFPConfig *configs, const AFPConfig *config)
 +/*!
 + * Free and cleanup all linked DSI objects from config
 + *
 + * Preserve object pointed to by "dsi".
 + * "dsi" can be NULL in which case all DSI objects _and_ the options object are freed 
 + */
 +void configfree(AFPObj *obj, DSI *dsi)
  {
 -    AFPConfig *p, *q;
 +    DSI *p, *q;
  
 -    for (p = configs; p; p = q) {
 +    /* the master loaded the volumes for zeroconf, get rid of that */
 +    unload_volumes(obj);
 +
 +    for (p = obj->dsi; p; p = q) {
          q = p->next;
 -        if (p == config)
 +        if (p == dsi)
              continue;
 -
 -        /* do a little reference counting */
 -        if (--(*p->optcount) < 1) {
 -            afp_options_free(&p->obj.options, p->defoptions);
 -            free(p->optcount);
 -        }
 -
 -        switch (p->obj.proto) {
 -#ifndef NO_DDP
 -        case AFPPROTO_ASP:
 -            free(p->obj.Obj);
 -            free(p->obj.Type);
 -            free(p->obj.Zone);
 -            atp_close(((ASP) p->obj.handle)->asp_atp);
 -            free(p->obj.handle);
 -            break;
 -#endif /* no afp/asp */
 -        case AFPPROTO_DSI:
 -            close(p->fd);
 -            free(p->obj.handle);
 -            break;
 -        }
 +        close(p->socket);
          free(p);
      }
 -    /* the master loaded the volumes for zeroconf, get rid of that */
 -    unload_volumes_and_extmap();
 -}
 -
 -#ifdef USE_SRVLOC
 -static void SRVLOC_callback(SLPHandle hslp _U_, SLPError errcode, void *cookie) {
 -    *(SLPError*)cookie = errcode;
 -}
 -
 -static char hex[17] = "0123456789abcdef";
 -
 -static char * srvloc_encode(const struct afp_options *options, const char *name)
 -{
 -      static char buf[512];
 -      char *conv_name;
 -      unsigned char *p;
 -      unsigned int i = 0;
 -#ifndef NO_DDP
 -      char *Obj, *Type = "", *Zone = "";
 -#endif
 -
 -      /* Convert name to maccharset */
 -        if ((size_t)-1 ==(convert_string_allocate( options->unixcharset, options->maccharset,
 -                       name, -1, &conv_name)) )
 -              return (char*)name;
 -
 -      /* Escape characters */
 -      p = conv_name;
 -      while (*p && i<(sizeof(buf)-4)) {
 -          if (*p == '@')
 -              break;
 -          else if (isspace(*p)) {
 -              buf[i++] = '%';
 -              buf[i++] = '2';
 -              buf[i++] = '0';
 -              p++;
 -          }   
 -          else if ((!isascii(*p)) || *p <= 0x2f || *p == 0x3f ) {
 -              buf[i++] = '%';
 -              buf[i++] = hex[*p >> 4];
 -              buf[i++] = hex[*p++ & 15];
 -          }
 -          else {
 -              buf[i++] = *p++;
 -          }
 -      }
 -      buf[i] = '\0';
 -
 -#ifndef NO_DDP
 -      /* Add ZONE,  */
 -        if (nbp_name(options->server, &Obj, &Type, &Zone )) {
 -              LOG(log_error, logtype_afpd, "srvloc_encode: can't parse %s", options->server );
 -      }
 -      else {
 -              snprintf( buf+i, sizeof(buf)-i-1 ,"&ZONE=%s", Zone);
 -      }
 -#endif
 -      free (conv_name);
 -
 -      return buf;
 -}
 -#endif /* USE_SRVLOC */
 -
 -static void dsi_cleanup(const AFPConfig *config)
 -{
 -#ifdef USE_SRVLOC
 -    SLPError err;
 -    SLPError callbackerr;
 -    SLPHandle hslp;
 -    DSI *dsi = (DSI *)config->obj.handle;
 -
 -    /*  Do nothing if we didn't register.  */
 -    if (!dsi || dsi->srvloc_url[0] == '\0')
 -        return;
 -
 -    err = SLPOpen("en", SLP_FALSE, &hslp);
 -    if (err != SLP_OK) {
 -        LOG(log_error, logtype_afpd, "dsi_cleanup: Error opening SRVLOC handle");
 -        goto srvloc_dereg_err;
 -    }
 -
 -    err = SLPDereg(hslp,
 -                   dsi->srvloc_url,
 -                   SRVLOC_callback,
 -                   &callbackerr);
 -    if (err != SLP_OK) {
 -        LOG(log_error, logtype_afpd, "dsi_cleanup: Error unregistering %s from SRVLOC", dsi->srvloc_url);
 -        goto srvloc_dereg_err;
 -    }
 -
 -    if (callbackerr != SLP_OK) {
 -        LOG(log_error, logtype_afpd, "dsi_cleanup: Error in callback while trying to unregister %s from SRVLOC (%d)", dsi->srvloc_url, callbackerr);
 -        goto srvloc_dereg_err;
 -    }
 -
 -srvloc_dereg_err:
 -    dsi->srvloc_url[0] = '\0';
 -    SLPClose(hslp);
 -#endif /* USE_SRVLOC */
 -}
 -
 -#ifndef NO_DDP
 -static void asp_cleanup(const AFPConfig *config)
 -{
 -    /* we need to stop tickle handler */
 -    asp_stop_tickle();
 -    nbp_unrgstr(config->obj.Obj, config->obj.Type, config->obj.Zone,
 -                &config->obj.options.ddpaddr);
 -}
 -
 -/* these two are almost identical. it should be possible to collapse them
 - * into one with minimal junk. */
 -static int asp_start(AFPConfig *config, AFPConfig *configs,
 -                     server_child *server_children)
 -{
 -    ASP asp;
 -
 -    if (!(asp = asp_getsession(config->obj.handle, server_children,
 -                               config->obj.options.tickleval))) {
 -        LOG(log_error, logtype_afpd, "main: asp_getsession: %s", strerror(errno) );
 -        exit( EXITERR_CLNT );
 -    }
 -
 -    if (asp->child) {
 -        configfree(configs, config); /* free a bunch of stuff */
 -        afp_over_asp(&config->obj);
 -        exit (0);
 -    }
 -
 -    return 0;
 -}
 -#endif /* no afp/asp */
 -
 -static afp_child_t *dsi_start(AFPConfig *config, AFPConfig *configs,
 -                              server_child *server_children)
 -{
 -    DSI *dsi = config->obj.handle;
 -    afp_child_t *child = NULL;
 -
 -    if (!(child = dsi_getsession(dsi,
 -                                 server_children,
 -                                 config->obj.options.tickleval))) {
 -        /* we've forked. */
 -        configfree(configs, config);
 -        afp_over_dsi(&config->obj); /* start a session */
 -        exit (0);
 -    }
 -
 -    return child;
 -}
 -
 -#ifndef NO_DDP
 -static AFPConfig *ASPConfigInit(const struct afp_options *options,
 -                                unsigned char *refcount)
 -{
 -    AFPConfig *config;
 -    ATP atp;
 -    ASP asp;
 -    char *Obj, *Type = "AFPServer", *Zone = "*";
 -    char *convname = NULL;
 -
 -    if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL)
 -        return NULL;
 -
 -    if ((atp = atp_open(ATADDR_ANYPORT, &options->ddpaddr)) == NULL)  {
 -        LOG(log_error, logtype_afpd, "main: atp_open: %s", strerror(errno) );
 -        free(config);
 -        return NULL;
 -    }
 -
 -    if ((asp = asp_init( atp )) == NULL) {
 -        LOG(log_error, logtype_afpd, "main: asp_init: %s", strerror(errno) );
 -        atp_close(atp);
 -        free(config);
 -        return NULL;
 -    }
 -
 -    /* register asp server */
 -    Obj = (char *) options->hostname;
 -    if (options->server && (size_t)-1 ==(convert_string_allocate( options->unixcharset, options->maccharset,
 -                         options->server, strlen(options->server), &convname)) ) {
 -        if ((convname = strdup(options->server)) == NULL ) {
 -            LOG(log_error, logtype_afpd, "malloc: %s", strerror(errno) );
 -            goto serv_free_return;
 -        }
 -    }
 -
 -    if (nbp_name(convname, &Obj, &Type, &Zone )) {
 -        LOG(log_error, logtype_afpd, "main: can't parse %s", options->server );
 -        goto serv_free_return;
 -    }
 -    if (convname)
 -        free (convname);
 -
 -    /* dup Obj, Type and Zone as they get assigned to a single internal
 -     * buffer by nbp_name */
 -    if ((config->obj.Obj  = strdup(Obj)) == NULL)
 -        goto serv_free_return;
 -
 -    if ((config->obj.Type = strdup(Type)) == NULL) {
 -        free(config->obj.Obj);
 -        goto serv_free_return;
 -    }
 -
 -    if ((config->obj.Zone = strdup(Zone)) == NULL) {
 -        free(config->obj.Obj);
 -        free(config->obj.Type);
 -        goto serv_free_return;
 -    }
 -
 -    /* make sure we're not registered */
 -    nbp_unrgstr(Obj, Type, Zone, &options->ddpaddr);
 -    if (nbp_rgstr( atp_sockaddr( atp ), Obj, Type, Zone ) < 0 ) {
 -        LOG(log_error, logtype_afpd, "Can't register %s:%s@%s", Obj, Type, Zone );
 -        free(config->obj.Obj);
 -        free(config->obj.Type);
 -        free(config->obj.Zone);
 -        goto serv_free_return;
 -    }
 -
 -    LOG(log_info, logtype_afpd, "%s:%s@%s started on %u.%u:%u (%s)", Obj, Type, Zone,
 -        ntohs( atp_sockaddr( atp )->sat_addr.s_net ),
 -        atp_sockaddr( atp )->sat_addr.s_node,
 -        atp_sockaddr( atp )->sat_port, VERSION );
 -
 -    config->fd = atp_fileno(atp);
 -    config->obj.handle = asp;
 -    config->obj.config = config;
 -    config->obj.proto = AFPPROTO_ASP;
 -
 -    memcpy(&config->obj.options, options, sizeof(struct afp_options));
 -    config->optcount = refcount;
 -    (*refcount)++;
 -
 -    config->server_start = asp_start;
 -    config->server_cleanup = asp_cleanup;
 -
 -    return config;
 -
 -serv_free_return:
 -                    asp_close(asp);
 -    free(config);
 -    return NULL;
 -}
 -#endif /* no afp/asp */
 -
 -
 -static AFPConfig *DSIConfigInit(const struct afp_options *options,
 -                                unsigned char *refcount,
 -                                const dsi_proto protocol)
 -{
 -    AFPConfig *config;
 -    DSI *dsi;
 -    char *p, *q;
 -
 -    if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
 -        LOG(log_error, logtype_afpd, "DSIConfigInit: malloc(config): %s", strerror(errno) );
 -        return NULL;
 -    }
 -
 -    LOG(log_debug, logtype_afpd, "DSIConfigInit: hostname: %s, ip/port: %s/%s, ",
 -        options->hostname,
 -        options->ipaddr ? options->ipaddr : "default",
 -        options->port ? options->port : "548");
 -
 -    if ((dsi = dsi_init(protocol, "afpd", options->hostname,
 -                        options->ipaddr, options->port,
 -                        options->flags & OPTION_PROXY,
 -                        options->server_quantum)) == NULL) {
 -        LOG(log_error, logtype_afpd, "main: dsi_init: %s", strerror(errno) );
 -        free(config);
 -        return NULL;
 -    }
 -    dsi->dsireadbuf = options->dsireadbuf;
 -
 -    if (options->flags & OPTION_PROXY) {
 -        LOG(log_note, logtype_afpd, "AFP/TCP proxy initialized for %s:%d (%s)",
 -            getip_string((struct sockaddr *)&dsi->server), getip_port((struct sockaddr *)&dsi->server), VERSION);
 +    if (dsi) {
 +        dsi->next = NULL;
 +        obj->dsi = dsi;
      } else {
 -        LOG(log_note, logtype_afpd, "AFP/TCP started, advertising %s:%d (%s)",
 -            getip_string((struct sockaddr *)&dsi->server), getip_port((struct sockaddr *)&dsi->server), VERSION);
 +        afp_options_free(&obj->options);
      }
 -
 -#ifdef USE_SRVLOC
 -    dsi->srvloc_url[0] = '\0';        /*  Mark that we haven't registered.  */
 -    if (!(options->flags & OPTION_NOSLP)) {
 -        SLPError err;
 -        SLPError callbackerr;
 -        SLPHandle hslp;
 -        unsigned int afp_port;
 -        int   l;
 -        char *srvloc_hostname;
 -        const char *hostname;
 -
 -      err = SLPOpen("en", SLP_FALSE, &hslp);
 -      if (err != SLP_OK) {
 -          LOG(log_error, logtype_afpd, "DSIConfigInit: Error opening SRVLOC handle");
 -          goto srvloc_reg_err;
 -      }
 -
 -      /* XXX We don't want to tack on the port number if we don't have to.
 -       * Why?
 -       * Well, this seems to break MacOS < 10.  If the user _really_ wants to
 -       * use a non-default port, they can, but be aware, this server might
 -       * not show up int the Network Browser.
 -       */
 -      afp_port = getip_port((struct sockaddr *)&dsi->server);
 -      /* If specified use the FQDN to register with srvloc, otherwise use IP. */
 -      p = NULL;
 -      if (options->fqdn) {
 -          hostname = options->fqdn;
 -          p = strchr(hostname, ':');
 -      }       
 -      else 
 -          hostname = getip_string((struct sockaddr *)&dsi->server);
 -
 -      srvloc_hostname = srvloc_encode(options, (options->server ? options->server : options->hostname));
 -
 -      if ((p) || afp_port == 548) {
 -          l = snprintf(dsi->srvloc_url, sizeof(dsi->srvloc_url), "afp://%s/?NAME=%s", hostname, srvloc_hostname);
 -      }
 -      else {
 -          l = snprintf(dsi->srvloc_url, sizeof(dsi->srvloc_url), "afp://%s:%d/?NAME=%s", hostname, afp_port, srvloc_hostname);
 -      }
 -
 -      if (l == -1 || l >= (int)sizeof(dsi->srvloc_url)) {
 -          LOG(log_error, logtype_afpd, "DSIConfigInit: Hostname is too long for SRVLOC");
 -          dsi->srvloc_url[0] = '\0';
 -          goto srvloc_reg_err;
 -      }
 -
 -      err = SLPReg(hslp,
 -                   dsi->srvloc_url,
 -                   SLP_LIFETIME_MAXIMUM,
 -                   "afp",
 -                   "",
 -                   SLP_TRUE,
 -                   SRVLOC_callback,
 -                   &callbackerr);
 -      if (err != SLP_OK) {
 -          LOG(log_error, logtype_afpd, "DSIConfigInit: Error registering %s with SRVLOC", dsi->srvloc_url);
 -          dsi->srvloc_url[0] = '\0';
 -          goto srvloc_reg_err;
 -      }
 -
 -      if (callbackerr != SLP_OK) {
 -          LOG(log_error, logtype_afpd, "DSIConfigInit: Error in callback trying to register %s with SRVLOC", dsi->srvloc_url);
 -          dsi->srvloc_url[0] = '\0';
 -          goto srvloc_reg_err;
 -      }
 -
 -      LOG(log_info, logtype_afpd, "Sucessfully registered %s with SRVLOC", dsi->srvloc_url);
 -      config->server_cleanup = dsi_cleanup;
 -
 -srvloc_reg_err:
 -      SLPClose(hslp);
 -    }
 -#endif /* USE_SRVLOC */
 -
 -    config->fd = dsi->serversock;
 -    config->obj.handle = dsi;
 -    dsi->AFPobj = &config->obj;
 -    config->obj.config = config;
 -    config->obj.proto = AFPPROTO_DSI;
 -
 -    memcpy(&config->obj.options, options, sizeof(struct afp_options));
 -    /* get rid of any appletalk info. we use the fact that the DSI
 -     * stuff is done after the ASP stuff. */
 -    p = config->obj.options.server;
 -    if (p && (q = strchr(p, ':')))
 -        *q = '\0';
 -
 -    config->optcount = refcount;
 -    (*refcount)++;
--
 -    config->server_start = dsi_start;
 -    return config;
  }
  
 -/* allocate server configurations. this should really store the last
 - * entry in config->last or something like that. that would make
 - * supporting multiple dsi transports easier. */
 -static AFPConfig *AFPConfigInit(struct afp_options *options,
 -                                const struct afp_options *defoptions)
 +/*!
 + * Get everything running
 + */
 +int configinit(AFPObj *obj)
  {
 -    AFPConfig *config = NULL, *next = NULL;
 -    unsigned char *refcount;
 -
 -    if ((refcount = (unsigned char *)
 -                    calloc(1, sizeof(unsigned char))) == NULL) {
 -        LOG(log_error, logtype_afpd, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
 -        return NULL;
 -    }
 -
 -#ifndef NO_DDP
 -    /* handle asp transports */
 -    if ((options->transports & AFPTRANS_DDP) &&
 -            (config = ASPConfigInit(options, refcount)))
 -        config->defoptions = defoptions;
 -#endif /* NO_DDP */
 -
 -
 -    /* set signature */
 -    set_signature(options);
 +    EC_INIT;
 +    DSI *dsi, **next = &obj->dsi;
 +    char *p = NULL, *q = NULL, *savep;
 +    const char *r;
  
 -    /* handle dsi transports and dsi proxies. we only proxy
 -     * for DSI connections. */
 +    auth_load(obj->options.uampath, obj->options.uamlist);
 +    set_signature(&obj->options);
  
 -    /* this should have something like the following:
 -     * for (i=mindsi; i < maxdsi; i++)
 -     *   if (options->transports & (1 << i) && 
 -     *     (next = DSIConfigInit(options, refcount, i)))
 -     *     next->defoptions = defoptions;
 -     */
 -    if ((options->transports & AFPTRANS_TCP) &&
 -            (((options->flags & OPTION_PROXY) == 0) ||
 -             ((options->flags & OPTION_PROXY) && config))
 -            && (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
 -        next->defoptions = defoptions;
 +    LOG(log_debug, logtype_afpd, "DSIConfigInit: hostname: %s, listen: %s, port: %s",
 +        obj->options.hostname,
 +        obj->options.listen ? obj->options.listen : "(default: hostname)",
 +        obj->options.port);
  
 -    /* load in all the authentication modules. we can load the same
 -       things multiple times if necessary. however, loading different
 -       things with the same names will cause complaints. by not loading
 -       in any uams with proxies, we prevent ddp connections from succeeding.
 -    */
 -    auth_load(options->uampath, options->uamlist);
 +    /* obj->options->listen is of the from "IP[:port][,IP:[PORT], ...]" */
 +    /* obj->options->port is the default port to listen (548) */
  
 -    /* this should be able to accept multiple dsi transports. i think
 -     * the only thing that gets affected is the net addresses. */
 -    status_init(config, next, options);
 -
 -    /* attach dsi config to tail of asp config */
 -    if (config) {
 -        config->next = next;
 -        return config;
 +    if (obj->options.listen) {
 +        EC_NULL( q = p = strdup(obj->options.listen) );
 +        EC_NULL( p = strtok_r(p, ", ", &savep) );
      }
  
 -    return next;
 -}
 -
 -/* fill in the appropriate bits for each interface */
 -AFPConfig *configinit(struct afp_options *cmdline)
 -{
 -    FILE *fp;
 -    char buf[LINESIZE + 1], *p, have_option = 0;
 -    size_t len;
 -    struct afp_options options;
 -    AFPConfig *config=NULL, *first = NULL; 
 -
 -    /* if config file doesn't exist, load defaults */
 -    if ((fp = fopen(cmdline->configfile, "r")) == NULL)
 -    {
 -        LOG(log_debug, logtype_afpd, "ConfigFile %s not found, assuming defaults",
 -            cmdline->configfile);
 -        return AFPConfigInit(cmdline, cmdline);
 -    }
 -
 -    /* scan in the configuration file */
 -    len = 0;
 -    while (!feof(fp)) {
 -      if (!fgets(&buf[len], LINESIZE - len, fp) || buf[len] == '#')
 -            continue;
 -      len = strlen(buf);
 -      if ( len >= 2 && buf[len-2] == '\\' ) {
 -          len -= 2;
 -          continue;
 -      } else
 -          len = 0;
 -
 -        /* a little pre-processing to get rid of spaces and end-of-lines */
 -        p = buf;
 -        while (p && isspace(*p))
 -            p++;
 -        if (!p || (*p == '\0'))
 -            continue;
 +    while (1) {
 +        if ((dsi = dsi_init(obj, obj->options.hostname, p, obj->options.port)) == NULL)
 +            break;
  
 -        have_option = 1;
 +        status_init(obj, dsi);
 +        *next = dsi;
 +        next = &dsi->next;
++        dsi->AFPobj = obj;
  
 -        memcpy(&options, cmdline, sizeof(options));
 -        if (!afp_options_parseline(p, &options))
 -            continue;
 +        LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on %s:%d",
 +            getip_string((struct sockaddr *)&dsi->server),
 +            getip_port((struct sockaddr *)&dsi->server));
  
 -        /* AFPConfigInit can return two linked configs due to DSI and ASP */
 -        if (!first) {
 -            if ((first = AFPConfigInit(&options, cmdline)))
 -                config = first->next ? first->next : first;
 -        } else if ((config->next = AFPConfigInit(&options, cmdline))) {
 -            config = config->next->next ? config->next->next : config->next;
 -        }
 +        if (p)
 +            /* p is NULL if ! obj->options.listen */
 +            p = strtok_r(NULL, ", ", &savep);
 +        if (!p)
 +            break;
      }
  
-     if (obj->dsi == NULL)
-         EC_FAIL;
  #ifdef HAVE_LDAP
 -    /* Parse afp_ldap.conf */
 -    acl_ldap_readconfig(_PATH_ACL_LDAPCONF);
 +    /* Parse afp.conf */
 +    acl_ldap_readconfig(obj->iniconfig);
  #endif /* HAVE_LDAP */
  
 -    LOG(log_debug, logtype_afpd, "Finished parsing Config File");
 -    fclose(fp);
 -
 -    if (!have_option)
 -        first = AFPConfigInit(cmdline, cmdline);
 -
      /* Now register with zeroconf, we also need the volumes for that */
 -    if (first && !(first->obj.options.flags & OPTION_NOZEROCONF)) {
 -        load_volumes(&first->obj);
 -        zeroconf_register(first);
 +    if (! (obj->options.flags & OPTION_NOZEROCONF)) {
 +        load_volumes(obj, NULL);
 +        zeroconf_register(obj);
 +    }
 +
 +    if ((r = iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce listener", NULL))) {
 +              LOG(log_note, logtype_afpd, "Adding FCE listener: %s", r);
 +              fce_add_udp_socket(r);
 +    }
 +    if ((r = iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce coalesce", NULL))) {
 +              LOG(log_note, logtype_afpd, "Fce coalesce: %s", r);
 +              fce_set_coalesce(r);
 +    }
 +    if ((r = iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce events", NULL))) {
 +              LOG(log_note, logtype_afpd, "Fce events: %s", r);
 +              fce_set_events(r);
      }
  
 -    return first;
 +EC_CLEANUP:
 +    if (q)
 +        free(q);
 +    EC_EXIT;
  }
diff --combined etc/afpd/afp_dsi.c
index f1e371676eac9d1213dbc7b667e6cc8c35cd9a9c,bf454e15e8b16cbbd4b377a6b19033afd0ca0760..58c37009ef501ee47313c057fcd9a07941bd82c8
  #include <atalk/paths.h>
  #include <atalk/server_ipc.h>
  #include <atalk/fce_api.h>
 -
  #include <atalk/globals.h>
 +#include <atalk/netatalk_conf.h>
 +
  #include "switch.h"
  #include "auth.h"
  #include "fork.h"
  #include "dircache.h"
  
 -#ifdef FORCE_UIDGID
 -#warning UIDGID
 -#include "uid.h"
 -#endif /* FORCE_UIDGID */
 -
  #ifndef SOL_TCP
  #define SOL_TCP IPPROTO_TCP
  #endif
@@@ -75,7 -79,7 +75,7 @@@ static rc_elem_t replaycache[REPLAYCACH
  static sigjmp_buf recon_jmp;
  static void afp_dsi_close(AFPObj *obj)
  {
 -    DSI *dsi = obj->handle;
 +    DSI *dsi = obj->dsi;
  
      close(obj->ipc_fd);
      obj->ipc_fd = -1;
@@@ -92,7 -96,7 +92,7 @@@
          }
      }
  
 -    close_all_vol();
 +    close_all_vol(obj);
      if (obj->logout)
          (*obj->logout)();
  
   */
  static void afp_dsi_die(int sig)
  {
 -    DSI *dsi = (DSI *)AFPobj->handle;
 +    DSI *dsi = (DSI *)AFPobj->dsi;
  
      if (dsi->flags & DSI_RECONINPROG) {
          /* Primary reconnect succeeded, got SIGTERM from afpd parent */
          exit(0);
      }
  
 -    dsi_attention(AFPobj->handle, AFPATTN_SHUTDOWN);
 +    dsi_attention(AFPobj->dsi, AFPATTN_SHUTDOWN);
      afp_dsi_close(AFPobj);
     if (sig) /* if no signal, assume dieing because logins are disabled &
                  don't log it (maintenance mode)*/
  /* SIGQUIT handler */
  static void ipc_reconnect_handler(int sig _U_)
  {
 -    DSI *dsi = (DSI *)AFPobj->handle;
 +    DSI *dsi = (DSI *)AFPobj->dsi;
  
      if (reconnect_ipc(AFPobj) != 0) {
          LOG(log_error, logtype_afpd, "ipc_reconnect_handler: failed IPC reconnect");
@@@ -159,7 -163,7 +159,7 @@@ static void afp_dsi_transfer_session(in
  {
      uint16_t dsiID;
      int socket;
 -    DSI *dsi = (DSI *)AFPobj->handle;
 +    DSI *dsi = (DSI *)AFPobj->dsi;
  
      LOG(log_debug, logtype_afpd, "afp_dsi_transfer_session: got SIGURG, trying to receive session");
  
@@@ -210,13 -214,13 +210,13 @@@ static void afp_dsi_timedown(int sig _U
  {
      struct sigaction  sv;
      struct itimerval  it;
 -    DSI                 *dsi = (DSI *)AFPobj->handle;
 +    DSI                 *dsi = (DSI *)AFPobj->dsi;
      dsi->flags |= DSI_DIE;
      /* shutdown and don't reconnect. server going down in 5 minutes. */
      setmessage("The server is going down for maintenance.");
 -    if (dsi_attention(AFPobj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
 +    if (dsi_attention(AFPobj->dsi, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
                    AFPATTN_MESG | AFPATTN_TIME(5)) < 0) {
 -        DSI *dsi = (DSI *)AFPobj->handle;
 +        DSI *dsi = (DSI *)AFPobj->dsi;
          dsi->down_request = 1;
      }                  
  
@@@ -273,17 -277,17 +273,17 @@@ static void afp_dsi_debug(int sig _U_
  /* ---------------------- */
  static void afp_dsi_getmesg (int sig _U_)
  {
 -    DSI *dsi = (DSI *)AFPobj->handle;
 +    DSI *dsi = (DSI *)AFPobj->dsi;
  
      dsi->msg_request = 1;
 -    if (dsi_attention(AFPobj->handle, AFPATTN_MESG | AFPATTN_TIME(5)) < 0)
 +    if (dsi_attention(AFPobj->dsi, AFPATTN_MESG | AFPATTN_TIME(5)) < 0)
          dsi->msg_request = 2;
  }
  
  static void alarm_handler(int sig _U_)
  {
      int err;
 -    DSI *dsi = (DSI *)AFPobj->handle;
 +    DSI *dsi = (DSI *)AFPobj->dsi;
  
      /* we have to restart the timer because some libraries may use alarm() */
      setitimer(ITIMER_REAL, &dsi->timer, NULL);
  
      if ((err = pollvoltime(AFPobj)) == 0)
          LOG(log_debug, logtype_afpd, "afp_alarm: sending DSI tickle");
 -        err = dsi_tickle(AFPobj->handle);
 +        err = dsi_tickle(AFPobj->dsi);
      if (err <= 0) {
          if (geteuid() == 0) {
              LOG(log_note, logtype_afpd, "afp_alarm: unauthenticated user, connection problem");
@@@ -361,14 -365,14 +361,14 @@@ static void pending_request(DSI *dsi
      if (dsi->msg_request) {
          if (dsi->msg_request == 2) {
              /* didn't send it in signal handler */
 -            dsi_attention(AFPobj->handle, AFPATTN_MESG | AFPATTN_TIME(5));
 +            dsi_attention(AFPobj->dsi, AFPATTN_MESG | AFPATTN_TIME(5));
          }
          dsi->msg_request = 0;
          readmessage(AFPobj);
      }
      if (dsi->down_request) {
          dsi->down_request = 0;
 -        dsi_attention(AFPobj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
 +        dsi_attention(AFPobj->dsi, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
                    AFPATTN_MESG | AFPATTN_TIME(5));
      }
  }
  */
  void afp_over_dsi(AFPObj *obj)
  {
 -    DSI *dsi = (DSI *) obj->handle;
 +    DSI *dsi = (DSI *) obj->dsi;
      int rc_idx;
 -    u_int32_t err, cmd;
 -    u_int8_t function;
 +    uint32_t err, cmd;
 +    uint8_t function;
      struct sigaction action;
  
      AFPobj = obj;
-     dsi->AFPobj = obj;
      obj->exit = afp_dsi_die;
      obj->reply = (int (*)()) dsi_cmdreply;
      obj->attention = (int (*)(void *, AFPUserBytes)) dsi_attention;
  
          if (reload_request) {
              reload_request = 0;
 -            load_volumes(AFPobj);
 +            load_volumes(AFPobj, closevol);
          }
  
          /* The first SIGINT enables debugging, the next restores the config */
  
              if (debugging) {
                  if (obj->options.logconfig)
 -                    setuplog(obj->options.logconfig);
 +                    setuplog(obj->options.logconfig, obj->options.logfile);
                  else
 -                    setuplog("default log_note");
 +                    setuplog("default:note", NULL);
                  debugging = 0;
              } else {
                  char logstr[50];
                  debugging = 1;
 -                sprintf(logstr, "default log_maxdebug /tmp/afpd.%u.XXXXXX", getpid());
 -                setuplog(logstr);
 +                sprintf(logstr, "/tmp/afpd.%u.XXXXXX", getpid());
 +                setuplog("default:maxdebug", logstr);
              }
          }
  
  
                      dir_free_invalid_q();
  
 -#ifdef FORCE_UIDGID
 -                    /* bring everything back to old euid, egid */
 -                    if (obj->force_uid)
 -                        restore_uidgid ( &obj->uidgid );
 -#endif /* FORCE_UIDGID */
                      dsi->flags &= ~DSI_RUNNING;
  
                      /* Add result to the AFP replay cache */
                      AfpNum2name(function), AfpErr2name(err));
  
                  dsi->flags &= ~DSI_RUNNING;
 -#ifdef FORCE_UIDGID
 -              /* bring everything back to old euid, egid */
 -              if (obj->force_uid)
 -                  restore_uidgid ( &obj->uidgid );
 -#endif /* FORCE_UIDGID */
              } else {
                  LOG(log_error, logtype_afpd, "(write) bad function %x", function);
                  dsi->datalen = 0;
diff --combined etc/afpd/main.c
index 5b79c08dea6872eb8396f75ec6e8e9a5838fcf88,e23d5570db2f4114ce28c06cc7bb287435447359..e89d0a2e9e58d6aacf2e2cc5af061a56959bb5dc
  #include <stdlib.h>
  #include <string.h>
  #include <signal.h>
 -
  #include <sys/param.h>
  #include <sys/uio.h>
 -#include <atalk/logger.h>
  #include <sys/time.h>
  #include <sys/socket.h>
  #include <sys/poll.h>
  #include <sys/wait.h>
  #include <sys/resource.h>
  
 +#include <atalk/logger.h>
  #include <atalk/adouble.h>
 -
 -#include <netatalk/at.h>
  #include <atalk/compat.h>
  #include <atalk/dsi.h>
 -#include <atalk/atp.h>
 -#include <atalk/asp.h>
  #include <atalk/afp.h>
  #include <atalk/paths.h>
  #include <atalk/util.h>
  #include <atalk/server_child.h>
  #include <atalk/server_ipc.h>
 +#include <atalk/errchk.h>
  #include <atalk/globals.h>
 +#include <atalk/netatalk_conf.h>
  
  #include "afp_config.h"
  #include "status.h"
  #include "uam_auth.h"
  #include "afp_zeroconf.h"
  
 -#ifdef TRU64
 -#include <sys/security.h>
 -#include <prot.h>
 -#include <sia.h>
 -
 -static int argc = 0;
 -static char **argv = NULL;
 -#endif /* TRU64 */
 -
  #define AFP_LISTENERS 32
  #define FDSET_SAFETY  5
  
 -unsigned char nologin = 0;
 -struct afp_options default_options;
 -static AFPConfig *configs;
 +unsigned char nologin = 0;
 +
 +static AFPObj obj;
  static server_child *server_children;
  static sig_atomic_t reloadconfig = 0;
  static sig_atomic_t gotsigchld = 0;
@@@ -56,34 -68,45 +56,34 @@@ static int fdset_size;          /* curr
  static int fdset_used;          /* number of used elements */
  static int disasociated_ipc_fd; /* disasociated sessions uses this fd for IPC */
  
 -#ifdef TRU64
 -void afp_get_cmdline( int *ac, char ***av)
 -{
 -    *ac = argc;
 -    *av = argv;
 -}
 -#endif /* TRU64 */
 +static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child *server_children);
  
 -/* This is registered with atexit() */
 -static void afp_exit(void)
 +static void afp_exit(int ret)
  {
 -    if (parent_or_child == 0)
 -        /* Only do this in the parent */
 -        server_unlock(default_options.pidfile);
 +    exit(ret);
  }
  
  
  /* ------------------
     initialize fd set we are waiting for.
  */
 -static void fd_set_listening_sockets(void)
 +static void fd_set_listening_sockets(const AFPObj *config)
  {
 -    AFPConfig   *config;
 +    DSI *dsi;
  
 -    for (config = configs; config; config = config->next) {
 -        if (config->fd < 0) /* for proxies */
 -            continue;
 -        fdset_add_fd(default_options.connections + AFP_LISTENERS + FDSET_SAFETY,
 +    for (dsi = config->dsi; dsi; dsi = dsi->next) {
 +        fdset_add_fd(config->options.connections + AFP_LISTENERS + FDSET_SAFETY,
                       &fdset,
                       &polldata,
                       &fdset_used,
                       &fdset_size,
 -                     config->fd,
 +                     dsi->serversock,
                       LISTEN_FD,
 -                     config);
 +                     dsi);
      }
  
 -    if (default_options.flags & OPTION_KEEPSESSIONS)
 -        fdset_add_fd(default_options.connections + AFP_LISTENERS + FDSET_SAFETY,
 +    if (config->options.flags & OPTION_KEEPSESSIONS)
 +        fdset_add_fd(config->options.connections + AFP_LISTENERS + FDSET_SAFETY,
                       &fdset,
                       &polldata,
                       &fdset_used,
                       NULL);
  }
   
 -static void fd_reset_listening_sockets(void)
 +static void fd_reset_listening_sockets(const AFPObj *config)
  {
 -    AFPConfig   *config;
 +    const DSI *dsi;
  
 -    for (config = configs; config; config = config->next) {
 -        if (config->fd < 0) /* for proxies */
 -            continue;
 -        fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, config->fd);
 +    for (dsi = config->dsi; dsi; dsi = dsi->next) {
 +        fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, dsi->serversock);
      }
  
 -    if (default_options.flags & OPTION_KEEPSESSIONS)
 +    if (config->options.flags & OPTION_KEEPSESSIONS)
          fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, disasociated_ipc_fd);
  }
  
  /* ------------------ */
  static void afp_goaway(int sig)
  {
 -        AFPConfig *config;
 -
 -#ifndef NO_DDP
 -    asp_kill(sig);
 -#endif /* ! NO_DDP */
 -
      switch( sig ) {
  
      case SIGTERM:
              LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGTERM");
              break;
          case SIGQUIT:
 -            if (default_options.flags & OPTION_KEEPSESSIONS) {
 +            if (obj.options.flags & OPTION_KEEPSESSIONS) {
                  LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGQUIT, NOT disconnecting clients");
              } else {
                  LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGQUIT");
          if (server_children)
              server_child_kill(server_children, CHILD_DSIFORK, sig);
  
 -        for (config = configs; config; config = config->next)
 -            if (config->server_cleanup)
 -                config->server_cleanup(config);
 -        server_unlock(default_options.pidfile);
 -        exit(0);
 +        _exit(0);
          break;
  
      case SIGUSR1 :
@@@ -210,37 -245,53 +210,37 @@@ static int setlimits(void
  
  int main(int ac, char **av)
  {
 -    AFPConfig           *config;
      fd_set              rfds;
      void                *ipc;
      struct sigaction  sv;
      sigset_t            sigs;
      int                 ret;
  
 -#ifdef TRU64
 -    argc = ac;
 -    argv = av;
 -    set_auth_parameters( ac, av );
 -#endif /* TRU64 */
 -
      /* Parse argv args and initialize default options */
 -    afp_options_init(&default_options);
 -    if (!afp_options_parse(ac, av, &default_options))
 -        exit(EXITERR_CONF);
 -
 -    if (check_lockfile("afpd", default_options.pidfile) != 0)
 -        exit(EXITERR_SYS);
 -
 -    if (!(default_options.flags & OPTION_DEBUG) && (daemonize(0, 0) != 0))
 -        exit(EXITERR_SYS);
 +    afp_options_parse_cmdline(&obj, ac, av);
  
 -    if (create_lockfile("afpd", default_options.pidfile) != 0)
 +    if (!(obj.cmdlineflags & OPTION_DEBUG) && (daemonize(0, 0) != 0))
          exit(EXITERR_SYS);
  
      /* Log SIGBUS/SIGSEGV SBT */
      fault_setup(NULL);
  
 -    /* Default log setup: log to syslog */
 -    set_processname("afpd");
 -    setuplog("default log_note");
 +    if (afp_config_parse(&obj, "afpd") != 0)
 +        afp_exit(EXITERR_CONF);
  
      /* Save the user's current umask */
 -    default_options.save_mask = umask( default_options.umask );
 -
 -    atexit(afp_exit);
 +    obj.options.save_mask = umask(obj.options.umask);
  
      /* install child handler for asp and dsi. we do this before afp_goaway
       * as afp_goaway references stuff from here. 
       * XXX: this should really be setup after the initial connections. */
 -    if (!(server_children = server_child_alloc(default_options.connections,
 -                            CHILD_NFORKS))) {
 +    if (!(server_children = server_child_alloc(obj.options.connections, CHILD_NFORKS))) {
          LOG(log_error, logtype_afpd, "main: server_child alloc: %s", strerror(errno) );
 -        exit(EXITERR_SYS);
 +        afp_exit(EXITERR_SYS);
      }
 +    
 +    sigemptyset(&sigs);
 +    pthread_sigmask(SIG_SETMASK, &sigs, NULL);
  
      memset(&sv, 0, sizeof(sv));    
      /* linux at least up to 2.4.22 send a SIGXFZ for vfat fs,
      sigemptyset( &sv.sa_mask );
      if (sigaction(SIGXFSZ, &sv, NULL ) < 0 ) {
          LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
 -        exit(EXITERR_SYS);
 +        afp_exit(EXITERR_SYS);
      }
  #endif
      
      sv.sa_flags = SA_RESTART;
      if ( sigaction( SIGCHLD, &sv, NULL ) < 0 ) {
          LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
 -        exit(EXITERR_SYS);
 +        afp_exit(EXITERR_SYS);
      }
  
      sigemptyset( &sv.sa_mask );
      sv.sa_flags = SA_RESTART;
      if ( sigaction( SIGUSR1, &sv, NULL ) < 0 ) {
          LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
 -        exit(EXITERR_SYS);
 +        afp_exit(EXITERR_SYS);
      }
  
      sigemptyset( &sv.sa_mask );
      sv.sa_flags = SA_RESTART;
      if ( sigaction( SIGHUP, &sv, NULL ) < 0 ) {
          LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
 -        exit(EXITERR_SYS);
 +        afp_exit(EXITERR_SYS);
      }
  
 -
      sigemptyset( &sv.sa_mask );
      sigaddset(&sv.sa_mask, SIGALRM);
      sigaddset(&sv.sa_mask, SIGHUP);
      sv.sa_flags = SA_RESTART;
      if ( sigaction( SIGTERM, &sv, NULL ) < 0 ) {
          LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
 -        exit(EXITERR_SYS);
 +        afp_exit(EXITERR_SYS);
      }
  
      sigemptyset( &sv.sa_mask );
      sv.sa_flags = SA_RESTART;
      if (sigaction(SIGQUIT, &sv, NULL ) < 0 ) {
          LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
 -        exit(EXITERR_SYS);
 +        afp_exit(EXITERR_SYS);
      }
  
 -    /* afpd.conf: not in config file: lockfile, connections, configfile
 +    /* afp.conf:  not in config file: lockfile, configfile
       *            preference: command-line provides defaults.
       *                        config file over-writes defaults.
       *
      sigaddset(&sigs, SIGCHLD);
  
      pthread_sigmask(SIG_BLOCK, &sigs, NULL);
 -    if (!(configs = configinit(&default_options))) {
 +    if (configinit(&obj) != 0) {
          LOG(log_error, logtype_afpd, "main: no servers configured");
 -        exit(EXITERR_CONF);
 +        afp_exit(EXITERR_CONF);
      }
      pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
  
 -    /* Register CNID  */
 +    /* Initialize */
      cnid_init();
 -
 +    
      /* watch atp, dsi sockets and ipc parent/child file descriptor. */
  
 -    if (default_options.flags & OPTION_KEEPSESSIONS) {
 +    if (obj.options.flags & OPTION_KEEPSESSIONS) {
          LOG(log_note, logtype_afpd, "Activating continous service");
          disasociated_ipc_fd = ipc_server_uds(_PATH_AFP_IPC);
      }
  
 -    fd_set_listening_sockets();
 +    fd_set_listening_sockets(&obj);
  
      /* set limits */
      (void)setlimits();
  
      afp_child_t *child;
-     int fd[2];  /* we only use one, but server_child_add expects [2] */
+     int recon_ipc_fd;
      pid_t pid;
      int saveerrno;
  
          if (reloadconfig) {
              nologin++;
              auth_unload();
 -            fd_reset_listening_sockets();
 +            fd_reset_listening_sockets(&obj);
  
              LOG(log_info, logtype_afpd, "re-reading configuration file");
 -            for (config = configs; config; config = config->next)
 -                if (config->server_cleanup)
 -                    config->server_cleanup(config);
 -
 -            /* configfree close atp socket used for DDP tickle, there's an issue
 -             * with atp tid. */
 -            configfree(configs, NULL);
 -            if (!(configs = configinit(&default_options))) {
 +
 +            configfree(&obj, NULL);
 +            if (configinit(&obj) != 0) {
                  LOG(log_error, logtype_afpd, "config re-read: no servers configured");
 -                exit(EXITERR_CONF);
 +                afp_exit(EXITERR_CONF);
              }
  
 -            fd_set_listening_sockets();
 +            fd_set_listening_sockets(&obj);
  
              nologin = 0;
              reloadconfig = 0;
          }
  
          for (int i = 0; i < fdset_used; i++) {
 -            if (fdset[i].revents & (POLLIN | POLLERR | POLLHUP)) {
 +            if (fdset[i].revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL)) {
                  switch (polldata[i].fdtype) {
  
                  case LISTEN_FD:
 -                    config = (AFPConfig *)polldata[i].data;
 -                    /* config->server_start is afp_config.c:dsi_start() for DSI */
 -                    if (child = config->server_start(config, configs, server_children)) {
 +                    if (child = dsi_start(&obj, (DSI *)polldata[i].data, server_children)) {
                          /* Add IPC fd to select fd set */
 -                        fdset_add_fd(default_options.connections + AFP_LISTENERS + FDSET_SAFETY,
 +                        fdset_add_fd(obj.options.connections + AFP_LISTENERS + FDSET_SAFETY,
                                       &fdset,
                                       &polldata,
                                       &fdset_used,
                                       &fdset_size,
-                                      child->ipc_fds[0],
+                                      child->ipc_fd,
                                       IPC_FD,
                                       child);
                      }
                      child = (afp_child_t *)polldata[i].data;
                      LOG(log_debug, logtype_afpd, "main: IPC request from child[%u]", child->pid);
  
-                     if (ipc_server_read(server_children, child->ipc_fds[0]) != 0) {
-                         fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, child->ipc_fds[0]);
-                         close(child->ipc_fds[0]);
-                         child->ipc_fds[0] = -1;
+                     if (ipc_server_read(server_children, child->ipc_fd) != 0) {
+                         fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, child->ipc_fd);
+                         close(child->ipc_fd);
+                         child->ipc_fd = -1;
 -                        if ((default_options.flags & OPTION_KEEPSESSIONS) && child->disasociated) {
 +                        if ((obj.options.flags & OPTION_KEEPSESSIONS) && child->disasociated) {
                              LOG(log_note, logtype_afpd, "main: removing reattached child[%u]", child->pid);
                              server_child_remove(server_children, CHILD_DSIFORK, child->pid);
                          }
  
                  case DISASOCIATED_IPC_FD:
                      LOG(log_debug, logtype_afpd, "main: IPC reconnect request");
-                     if ((fd[0] = accept(disasociated_ipc_fd, NULL, NULL)) == -1) {
+                     if ((recon_ipc_fd = accept(disasociated_ipc_fd, NULL, NULL)) == -1) {
                          LOG(log_error, logtype_afpd, "main: accept: %s", strerror(errno));
                          break;
                      }
-                     if (readt(fd[0], &pid, sizeof(pid_t), 0, 1) != sizeof(pid_t)) {
+                     if (readt(recon_ipc_fd, &pid, sizeof(pid_t), 0, 1) != sizeof(pid_t)) {
                          LOG(log_error, logtype_afpd, "main: readt: %s", strerror(errno));
-                         close(fd[0]);
+                         close(recon_ipc_fd);
                          break;
                      }
                      LOG(log_note, logtype_afpd, "main: IPC reconnect from pid [%u]", pid);
-                     if ((child = server_child_add(server_children, CHILD_DSIFORK, pid, fd)) == NULL) {
+                     if ((child = server_child_add(server_children, CHILD_DSIFORK, pid, recon_ipc_fd)) == NULL) {
                          LOG(log_error, logtype_afpd, "main: server_child_add");
-                         close(fd[0]);
+                         close(recon_ipc_fd);
                          break;
                      }
                      child->disasociated = 1;
 -                    fdset_add_fd(default_options.connections + AFP_LISTENERS + FDSET_SAFETY,
 +                    fdset_add_fd(obj.options.connections + AFP_LISTENERS + FDSET_SAFETY,
                                   &fdset,
                                   &polldata,
                                   &fdset_used,
                                   &fdset_size,
-                                  fd[0],
+                                  recon_ipc_fd,
                                   IPC_FD,
                                   child);
                      break;
  
      return 0;
  }
-     if (!(child = dsi_getsession(dsi,
-                                  server_children,
-                                  obj->options.tickleval))) {
 +
 +static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child *server_children)
 +{
 +    afp_child_t *child = NULL;
 +
-     if (child->ipc_fds[0] == -1) {
++    if (dsi_getsession(dsi, server_children, obj->options.tickleval, &child) != 0) {
 +        LOG(log_error, logtype_afpd, "dsi_start: session error: %s", strerror(errno));
 +        return NULL;
 +    }
 +
 +    /* we've forked. */
-         obj->ipc_fd = child->ipc_fds[1];
-         free(child);
++    if (child == NULL) {
 +        configfree(obj, dsi);
 +        afp_over_dsi(obj); /* start a session */
 +        exit (0);
 +    }
 +
 +    return child;
 +}
diff --combined include/atalk/dsi.h
index 60afc18659f5140b59b36433dfc41105993efce0,eded2b8f5ad7d5e97980970694f1bf51381d6de8..bd8cc8b4e50ec700970fb05bcefa5f6267810cbe
   * All rights reserved.
   */
  
 -#ifndef _ATALK_DSI_H 
 +#ifndef _ATALK_DSI_H
  #define _ATALK_DSI_H
  
 -#include <sys/cdefs.h>
  #include <sys/types.h>
  #include <sys/time.h>
 -#include <signal.h>
  #include <sys/socket.h>
 +#include <signal.h>
 +#include <arpa/inet.h>
  #include <netinet/in.h>
  
  #include <atalk/afp.h>
  #include <atalk/server_child.h>
  #include <atalk/globals.h>
 -#include <netatalk/endian.h>
 -
  
  /* What a DSI packet looks like:
 - 0                               32
 - |-------------------------------|
 - |flags  |command| requestID     |
 - |-------------------------------|
 - |error code/enclosed data offset|
 - |-------------------------------|
 - |total data length              |
 - |-------------------------------|
 - |reserved field                 |
 - |-------------------------------|
 -
 - CONVENTION: anything with a dsi_ prefix is kept in network byte order.
 +   0                               32
 +   |-------------------------------|
 +   |flags  |command| requestID     |
 +   |-------------------------------|
 +   |error code/enclosed data offset|
 +   |-------------------------------|
 +   |total data length              |
 +   |-------------------------------|
 +   |reserved field                 |
 +   |-------------------------------|
 +
 +   CONVENTION: anything with a dsi_ prefix is kept in network byte order.
  */
  
 -/* these need to be kept in sync w/ AFPTRANS_* in <atalk/afp.h>. 
 +/* these need to be kept in sync w/ AFPTRANS_* in <atalk/afp.h>.
   * convention: AFPTRANS_* = (1 << DSI_*) */
  typedef enum {
 -  DSI_MIN = 1,
 -  DSI_TCPIP = 1,
 -  DSI_MAX = 1
 +    DSI_MIN = 1,
 +    DSI_TCPIP = 1,
 +    DSI_MAX = 1
  } dsi_proto;
  
  #define DSI_BLOCKSIZ 16
  struct dsi_block {
 -  u_int8_t dsi_flags;       /* packet type: request or reply */
 -  u_int8_t dsi_command;     /* command */
 -  u_int16_t dsi_requestID;  /* request ID */
 -  u_int32_t dsi_code;       /* error code or data offset */
 -  u_int32_t dsi_len;        /* total data length */
 -  u_int32_t dsi_reserved;   /* reserved field */
 +    uint8_t dsi_flags;       /* packet type: request or reply */
 +    uint8_t dsi_command;     /* command */
 +    uint16_t dsi_requestID;  /* request ID */
 +    uint32_t dsi_code;       /* error code or data offset */
 +    uint32_t dsi_len;        /* total data length */
 +    uint32_t dsi_reserved;   /* reserved field */
  };
  
 -#define DSI_CMDSIZ        8192 
 +#define DSI_CMDSIZ        8192
  #define DSI_DATASIZ       8192
  
  /* child and parent processes might interpret a couple of these
   * differently. */
  typedef struct DSI {
 -  AFPObj *AFPobj;
 -  dsi_proto protocol;
 -  struct dsi_block header;
 -  struct sockaddr_storage server, client;
 -  struct itimerval timer;
 -  int      tickle;        /* tickle count */
 -  int    in_write;      /* in the middle of writing multiple packets,
 -                             signal handlers can't write to the socket */
 -  int      msg_request;   /* pending message to the client */
 -  int      down_request;  /* pending SIGUSR1 down in 5 mn */
 -
 -  u_int32_t attn_quantum, datasize, server_quantum;
 -  u_int16_t serverID, clientID;
 -  char      *status;
 -  u_int8_t  commands[DSI_CMDSIZ], data[DSI_DATASIZ];
 -  size_t statuslen;
 -  size_t datalen, cmdlen;
 -  off_t  read_count, write_count;
 -  uint32_t flags;             /* DSI flags like DSI_SLEEPING, DSI_DISCONNECTED */
 -  const char *program; 
 -  int socket, serversock;
 -
 -  /* protocol specific open/close, send/receive
 -   * send/receive fill in the header and use dsi->commands.
 -   * write/read just write/read data */
 -  pid_t  (*proto_open)(struct DSI *);
 -  void   (*proto_close)(struct DSI *);
 -
 -  /* url registered with slpd */
 -#ifdef USE_SRVLOC
 -  char srvloc_url[512];
 -#endif 
 +    struct DSI *next;             /* multiple listening addresses */
 +    AFPObj   *AFPobj;
 +    int      statuslen;
 +    char     status[1400];
 +    char     *signature;
 +    struct dsi_block        header;
 +    struct sockaddr_storage server, client;
 +    struct itimerval        timer;
 +    int      tickle;            /* tickle count */
 +    int      in_write;          /* in the middle of writing multiple packets,
 +                                   signal handlers can't write to the socket */
 +    int      msg_request;       /* pending message to the client */
 +    int      down_request;      /* pending SIGUSR1 down in 5 mn */
 +
 +    uint32_t attn_quantum, datasize, server_quantum;
 +    uint16_t serverID, clientID;
 +    uint8_t  commands[DSI_CMDSIZ], data[DSI_DATASIZ];
 +    size_t   datalen, cmdlen;
 +    off_t    read_count, write_count;
 +    uint32_t flags;             /* DSI flags like DSI_SLEEPING, DSI_DISCONNECTED */
 +    int      socket;            /* AFP session socket */
 +    int      serversock;        /* listening socket */
 +
 +    /* DSI readahead buffer used for buffered reads in dsi_peek */
 +    size_t   dsireadbuf;        /* size of the DSI readahead buffer used in dsi_peek() */
 +    char     *buffer;           /* buffer start */
 +    char     *start;            /* current buffer head */
 +    char     *eof;              /* end of currently used buffer */
 +    char     *end;
  
  #ifdef USE_ZEROCONF
 -  char *bonjourname;      /* server name as UTF8 maxlen MAXINSTANCENAMELEN */
 -  int zeroconf_registered;
 +    char *bonjourname;      /* server name as UTF8 maxlen MAXINSTANCENAMELEN */
 +    int zeroconf_registered;
  #endif
  
 -  /* DSI readahead buffer used for buffered reads in dsi_peek */
 -  size_t dsireadbuf; /* size of the DSI readahead buffer used in dsi_peek() */
 -  char *buffer;
 -  char *start;
 -  char *eof;
 -  char *end;
 +    /* protocol specific open/close, send/receive
 +     * send/receive fill in the header and use dsi->commands.
 +     * write/read just write/read data */
 +    pid_t  (*proto_open)(struct DSI *);
 +    void   (*proto_close)(struct DSI *);
  } DSI;
 -  
 +
  /* DSI flags */
  #define DSIFL_REQUEST    0x00
  #define DSIFL_REPLY      0x01
  #define DSIFUNC_MAX     8       /* largest command */
  
  /* DSI Error codes: most of these aren't used. */
 -#define DSIERR_OK     0x0000
 -#define DSIERR_BADVERS        0xfbd6
 -#define DSIERR_BUFSMALL       0xfbd5
 -#define DSIERR_NOSESS 0xfbd4
 -#define DSIERR_NOSERV 0xfbd3
 -#define DSIERR_PARM   0xfbd2
 -#define DSIERR_SERVBUSY       0xfbd1
 -#define DSIERR_SESSCLOS       0xfbd0
 -#define DSIERR_SIZERR 0xfbcf
 -#define DSIERR_TOOMANY        0xfbce
 -#define DSIERR_NOACK  0xfbcd
 +#define DSIERR_OK   0x0000
 +#define DSIERR_BADVERS  0xfbd6
 +#define DSIERR_BUFSMALL 0xfbd5
 +#define DSIERR_NOSESS   0xfbd4
 +#define DSIERR_NOSERV   0xfbd3
 +#define DSIERR_PARM 0xfbd2
 +#define DSIERR_SERVBUSY 0xfbd1
 +#define DSIERR_SESSCLOS 0xfbd0
 +#define DSIERR_SIZERR   0xfbcf
 +#define DSIERR_TOOMANY  0xfbce
 +#define DSIERR_NOACK    0xfbcd
  
  /* server and client quanta */
  #define DSI_DEFQUANT        2           /* default attention quantum size */
  #endif
  
  /* basic initialization: dsi_init.c */
 -extern DSI *dsi_init (const dsi_proto /*protocol*/,
 -                        const char * /*program*/, 
 -                        const char * /*host*/, const char * /*address*/,
 -                        const char * /*port*/, const int /*proxy*/,
 -                        const u_int32_t /* server quantum */);
 +extern DSI *dsi_init(AFPObj *obj, const char *hostname, const char *address, const char *port);
  extern void dsi_setstatus (DSI *, char *, const size_t);
 +extern int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address, const char *port);
  
  /* in dsi_getsess.c */
--extern afp_child_t *dsi_getsession (DSI *, server_child *, const int);
++extern int dsi_getsession (DSI *, server_child *, const int, afp_child_t **);
  extern void dsi_kill (int);
  
  
@@@ -174,8 -183,6 +174,8 @@@ extern void dsi_getstatus (DSI *)
  extern void dsi_close (DSI *);
  
  #define DSI_NOWAIT 1
 +#define DSI_MSG_MORE 2
 +
  /* low-level stream commands -- in dsi_stream.c */
  extern ssize_t dsi_stream_write (DSI *, void *, const size_t, const int mode);
  extern size_t dsi_stream_read (DSI *, void *, const size_t);
@@@ -184,7 -191,7 +184,7 @@@ extern int dsi_stream_receive (DSI *)
  extern int dsi_disconnect(DSI *dsi);
  
  #ifdef WITH_SENDFILE
 -extern ssize_t dsi_stream_read_file(DSI *, int, off_t off, const size_t len);
 +extern ssize_t dsi_stream_read_file(DSI *, int, off_t off, const size_t len, const int err);
  #endif
  
  /* client writes -- dsi_write.c */
@@@ -195,15 -202,15 +195,15 @@@ extern void   dsi_writeflush (DSI *)
  
  /* client reads -- dsi_read.c */
  extern ssize_t dsi_readinit (DSI *, void *, const size_t, const size_t,
 -                               const int);
 +                             const int);
  extern ssize_t dsi_read (DSI *, void *, const size_t);
  extern void dsi_readdone (DSI *);
  
  /* some useful macros */
  #define dsi_serverID(x)   ((x)->serverID++)
 -#define dsi_send(x)       do { \
 -    (x)->header.dsi_len = htonl((x)->cmdlen); \
 -    dsi_stream_send((x), (x)->commands, (x)->cmdlen); \
 -} while (0)
 +#define dsi_send(x)       do {                              \
 +        (x)->header.dsi_len = htonl((x)->cmdlen);           \
 +        dsi_stream_send((x), (x)->commands, (x)->cmdlen);   \
 +    } while (0)
  
  #endif /* atalk/dsi.h */
index 262ee201795d6c1e9e3a285394b8c4c98a6d9fab,5ee8314f3dd44c40992e788c7009a69ba20f782d..ad41bceccec2441f95ee4907547e1b93d39ce4ba
@@@ -6,8 -6,9 +6,8 @@@
  #ifndef _ATALK_SERVER_CHILD_H
  #define _ATALK_SERVER_CHILD_H 1
  
 -#include <sys/cdefs.h>
  #include <sys/types.h>
 -#include <netatalk/endian.h>
 +#include <arpa/inet.h>
  
  /* useful stuff for child processes. most of this is hidden in 
   * server_child.c to ease changes in implementation */
@@@ -31,19 -32,21 +31,19 @@@ typedef struct server_child_data 
    uint32_t  time;             /* client boot time (from the mac client) */
    uint32_t  idlen;            /* clientid len (from the Mac client) */
    char      *clientid;  /* clientid (from the Mac client) */
-   int       ipc_fds[2]; /* socketpair for IPC bw */
+   int       ipc_fd; /* socket for IPC bw afpd parent and childs */
    struct server_child_data **prevp, *next;
  } afp_child_t;
  
 -extern int parent_or_child;
 -
  /* server_child.c */
  extern server_child *server_child_alloc (const int, const int);
- extern afp_child_t *server_child_add (server_child *, int, pid_t, uint ipc_fds[2]);
+ extern afp_child_t *server_child_add (server_child *, int, pid_t, int ipc_fd);
  extern int  server_child_remove (server_child *, const int, const pid_t);
  extern void server_child_free (server_child *);
  
  extern void server_child_kill (server_child *, const int, const int);
  extern void server_child_kill_one_by_id (server_child *children, const int forkid, const pid_t pid, const uid_t,
 -                                               const u_int32_t len, char *id, u_int32_t boottime);
 +                                               const uint32_t len, char *id, uint32_t boottime);
  extern int  server_child_transfer_session(server_child *children, int forkid, pid_t, uid_t, int, uint16_t);
  extern void server_child_setup (server_child *, const int, void (*)(const pid_t));
  extern void server_child_handler (server_child *);
index 8d6e544cdbc5d620d725abf70a158127b0ebf4b2,bcc32da23c04e3d7e677c6e459099beba2637f06..001279cd74ae6ad717eef7fe01a7880a77b3dfab
  #include <sys/types.h>
  #include <sys/socket.h>
  
 -/* POSIX.1 sys/wait.h check */
  #include <sys/types.h>
 -#ifdef HAVE_SYS_WAIT_H
  #include <sys/wait.h>
 -#endif /* HAVE_SYS_WAIT_H */
 -#ifndef WEXITSTATUS
 -#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
 -#endif /* ! WEXITSTATUS */
 -#ifndef WIFEXITED
 -#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
 -#endif /* ! WIFEXITED */
 -
  #include <sys/time.h>
  #include <atalk/logger.h>
  #include <atalk/util.h>
  #include <atalk/dsi.h>
  #include <atalk/server_child.h>
  
--/* hand off the command. return child connection to the main program */
--afp_child_t *dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval)
++/*!
++ * Start a DSI session, fork an afpd process
++ *
++ * @param childp    (w) after fork: parent return pointer to child, child returns NULL
++ * @returns             0 on sucess, any other value denotes failure
++ */
++int dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval, afp_child_t **childp)
  {
    pid_t pid;
    unsigned int ipc_fds[2];  
  
    if (socketpair(PF_UNIX, SOCK_STREAM, 0, ipc_fds) < 0) {
        LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
--      exit( EXITERR_CLNT );
++      return -1;
    }
  
    if (setnonblock(ipc_fds[0], 1) != 0 || setnonblock(ipc_fds[1], 1) != 0) {
        LOG(log_error, logtype_dsi, "dsi_getsess: setnonblock: %s", strerror(errno));
--      exit(EXITERR_CLNT);
++      return -1;
    }
  
    switch (pid = dsi->proto_open(dsi)) { /* in libatalk/dsi/dsi_tcp.c */
    case -1:
      /* if we fail, just return. it might work later */
      LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
--    return NULL;
++    return -1;
  
    case 0: /* child. mostly handled below. */
      break;
  
    default: /* parent */
-     /* using SIGQUIT is hokey, but the child might not have
+     /* using SIGKILL is hokey, but the child might not have
       * re-established its signal handler for SIGTERM yet. */
-     if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds)) ==  NULL) {
+     close(ipc_fds[1]);
+     if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds[0])) ==  NULL) {
        LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
+       close(ipc_fds[0]);
        dsi->header.dsi_flags = DSIFL_REPLY;
        dsi->header.dsi_code = DSIERR_SERVBUSY;
        dsi_send(dsi);
        dsi->header.dsi_code = DSIERR_OK;
-       kill(pid, SIGQUIT);
+       kill(pid, SIGKILL);
      }
-     close(ipc_fds[1]);
      dsi->proto_close(dsi);
--    return child;
++    *childp = child;
++    return 0;
    }
    
    /* child: check number of open connections. this is one off the
    }
  
    /* get rid of some stuff */
+   dsi->AFPobj->ipc_fd = ipc_fds[1];
    close(ipc_fds[0]);
    close(dsi->serversock);
 +  dsi->serversock = -1;
    server_child_free(serv_children); 
  
    switch (dsi->header.dsi_command) {
      dsi->timer.it_interval.tv_usec = dsi->timer.it_value.tv_usec = 0;
      signal(SIGPIPE, SIG_IGN); /* we catch these ourselves */
      dsi_opensession(dsi);
-     if ((child = calloc(1, sizeof(afp_child_t))) == NULL)
-         exit(EXITERR_SYS);
-     child->ipc_fds[0] = -1;
-     child->ipc_fds[1] = ipc_fds[1];
-     close(ipc_fds[0]);
-     return child;
 -    return NULL;
++    *childp = NULL;
++    return 0;
  
    default: /* just close */
      LOG(log_info, logtype_dsi, "DSIUnknown %d", dsi->header.dsi_command);
index c87417d54702bbfb58a022ac1e6755b744ac655c,86f05a09230a0ed5b4dd785f48197dd3050f3d06..ada3e61052353b972776eae3fa85046dac7057f1
  
  #include <stdlib.h>
  #include <string.h>
 -#ifdef HAVE_UNISTD_H
  #include <unistd.h>
 -#endif /* HAVE_UNISTD_H */
  #include <signal.h>
  #include <errno.h>
 -
 -/* POSIX.1 sys/wait.h check */
  #include <sys/types.h>
 -#ifdef HAVE_SYS_WAIT_H
  #include <sys/wait.h>
 -#endif /* HAVE_SYS_WAIT_H */
  #include <sys/time.h>
  
  #include <atalk/logger.h>
@@@ -55,6 -61,8 +55,6 @@@ typedef struct server_child_fork 
      void (*cleanup)(const pid_t);
  } server_child_fork;
  
 -int parent_or_child; /* 0: parent, 1: child */
 -
  static inline void hash_child(struct server_child_data **htable,
                                struct server_child_data *child)
  {
@@@ -113,7 -121,7 +113,7 @@@ server_child *server_child_alloc(const 
   * add a child
   * @return pointer to struct server_child_data on success, NULL on error
   */
- afp_child_t *server_child_add(server_child *children, int forkid, pid_t pid, uint ipc_fds[2])
+ afp_child_t *server_child_add(server_child *children, int forkid, pid_t pid, int ipc_fd)
  {
      server_child_fork *fork;
      afp_child_t *child = NULL;
      child->pid = pid;
      child->valid = 0;
      child->killed = 0;
-     child->ipc_fds[0] = ipc_fds[0];
-     child->ipc_fds[1] = ipc_fds[1];
+     child->ipc_fd = ipc_fd;
  
      hash_child(fork->table, child);
      children->count++;
@@@ -173,15 -180,9 +172,9 @@@ int server_child_remove(server_child *c
      }
  
      /* In main:child_handler() we need the fd in order to remove it from the pollfd set */
-     fd = child->ipc_fds[0];
-     if (child->ipc_fds[0] != -1) {
-         close(child->ipc_fds[0]);
-         child->ipc_fds[0] = -1;
-     }
-     if (child->ipc_fds[1] != -1) {
-         close(child->ipc_fds[1]);
-         child->ipc_fds[1] = -1;
-     }
+     fd = child->ipc_fd;
+     if (fd != -1)
+         close(fd);
  
      free(child);
      children->count--;
@@@ -206,9 -207,7 +199,7 @@@ void server_child_free(server_child *ch
              child = fork->table[j]; /* start at the beginning */
              while (child) {
                  tmp = child->next;
-                 if (child->ipc_fds[0] != -1)
-                     close(child->ipc_fds[0]);
+                 close(child->ipc_fd);
                  if (child->clientid) {
                      free(child->clientid);
                  }
@@@ -300,12 -299,12 +291,12 @@@ int server_child_transfer_session(serve
  
      LOG(log_note, logtype_default, "Reconnect: transfering session to child[%u]", pid);
      
-     if (writet(child->ipc_fds[0], &DSI_requestID, 2, 0, 2) != 2) {
+     if (writet(child->ipc_fd, &DSI_requestID, 2, 0, 2) != 2) {
          LOG(log_error, logtype_default, "Reconnect: error sending DSI id to child[%u]", pid);
          EC_STATUS(-1);
          goto EC_CLEANUP;
      }
-     EC_ZERO_LOG(send_fd(child->ipc_fds[0], afp_socket));
+     EC_ZERO_LOG(send_fd(child->ipc_fd, afp_socket));
      EC_ZERO_LOG(kill(pid, SIGURG));
  
      EC_STATUS(1);