]> arthur.barton.de Git - netatalk.git/commitdiff
Rework volume parsing code to ini style and rework main, config init and dsi startup
authorFrank Lahm <franklahm@googlemail.com>
Mon, 13 Feb 2012 16:40:50 +0000 (17:40 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Mon, 13 Feb 2012 16:40:50 +0000 (17:40 +0100)
12 files changed:
etc/afpd/afp_config.c
etc/afpd/afp_options.c
etc/afpd/main.c
etc/afpd/volume.c
etc/afpd/volume.h
include/atalk/dsi.h
include/atalk/globals.h
include/atalk/iniparser.h
include/atalk/uuid.h
libatalk/dsi/dsi_init.c
libatalk/dsi/dsi_tcp.c
libatalk/iniparser/iniparser.c

index c07b2e9272229cdd4b0743967d304f0cf0b19487..f859637942f5e7ce8ebee2c3afc1bcf3d51ee5fc 100644 (file)
@@ -25,6 +25,7 @@
 #include <atalk/compat.h>
 #include <atalk/server_child.h>
 #include <atalk/globals.h>
+#include <atalk/errchk.h>
 
 #ifdef HAVE_LDAP
 #include <atalk/ldapconfig.h>
 #include "volume.h"
 #include "afp_zeroconf.h"
 
-/* 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 are freed
+ */
+void configfree(AFPObj *obj, DSI *dsi)
 {
-    AFPConfig *p, *q;
+    DSI *p, *q;
 
-    for (p = configs; p; p = q) {
+    afp_options_free(obj->options);
+
+    for (p = obj->dsi; p; p = q) {
         q = p->next;
-        if (p == config)
+        if (p == dsi)
             continue;
-
-        afp_options_free(&p->obj.options, p->defoptions);
-
-        switch (p->obj.proto) {
-        case AFPPROTO_DSI:
-            close(p->fd);
-            free(p->obj.dsi);
-            break;
-        }
+        close(p->socket);
+        free(p->dsi);
         free(p);
     }
-
-    /* the master loaded the volumes for zeroconf, get rid of that */
-    unload_volumes_and_extmap();
-}
-
-
-static void dsi_cleanup(const AFPConfig *config)
-{
-    return;
-}
-
-static afp_child_t *dsi_start(AFPConfig *config, AFPConfig *configs,
-                              server_child *server_children)
-{
-    DSI *dsi = config->obj.dsi;
-    afp_child_t *child = NULL;
-
-    if (!(child = dsi_getsession(dsi,
-                                 server_children,
-                                 config->obj.options.tickleval))) {
-        LOG(log_error, logtype_afpd, "dsi_start: session error: %s", strerror(errno));
-        return NULL;
-    }
-
-    /* we've forked. */
-    if (parent_or_child == 1) {
-        configfree(configs, config);
-        config->obj.ipc_fd = child->ipc_fds[1];
-        close(child->ipc_fds[0]); /* Close parent IPC fd */
-        free(child);
-        afp_over_dsi(&config->obj); /* start a session */
-        exit (0);
+    if (dsi) {
+        dsi->next = NULL;
+        obj->dsi = dsi;
     }
-
-    return child;
+    /* the master loaded the volumes for zeroconf, get rid of that */
+    unload_volumes();
 }
 
-static AFPConfig *DSIConfigInit(const struct afp_options *options,
-                                unsigned char *refcount,
-                                const dsi_proto protocol)
+/*!
+ * Get everything running
+ */
+int configinit(AFPObj *obj)
 {
-    AFPConfig *config;
-    DSI *dsi;
-    char *p, *q;
+    EC_INIT;
+    DSI *dsi, **next = &obj->dsi;
+    char *p, *q = NULL;
 
-    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, listen: %s, port: %s",
+        obj->options->hostname,
+        obj->options->listen ? obj->options->listen : "(default: hostname)",
+        obj->options->port);
 
-    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,
-                        0, options->server_quantum)) == NULL) {
-        LOG(log_error, logtype_afpd, "main: dsi_init: %s", strerror(errno) );
-        free(config);
-        return NULL;
-    }
-    dsi->dsireadbuf = options->dsireadbuf;
-
-    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);
+    /* obj->options->listen is of the from "IP[:port][,IP:[PORT], ...]" */
+    /* obj->options->port is the default port to listen (548) */
 
-    config->dsi = dsi;
+    EC_NULL( q = p = strdup(obj->options->listen) );
+    EC_NULL( p = strtok(p, ',') );
 
-    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';
+    while (p) {
+        if ((dsi = dsi_init(obj, obj->options->hostname, p, obj->options->port)) == NULL)
+            break;
 
-    return config;
-}
+        *next = dsi;
+        next = &dsi->next;
 
-/* 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)
-{
-    AFPConfig *next = NULL;
-    unsigned char *refcount;
+        LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on %s:%d",
+            getip_string((struct sockaddr *)&dsi->server),
+            getip_port((struct sockaddr *)&dsi->server));
 
-    if ((refcount = (unsigned char *)
-                    calloc(1, sizeof(unsigned char))) == NULL) {
-        LOG(log_error, logtype_afpd, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
-        return NULL;
+        p = strtok(NULL, ',');
     }
 
-    /* set signature */
-    set_signature(options);
-
-    if ((next = DSIConfigInit(options, refcount, DSI_TCPIP)))
-        /* 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);
-
-    /* this should be able to accept multiple dsi transports. i think
-     * the only thing that gets affected is the net addresses. */
-    status_init(next, options);
-
-    return next;
-}
+    if (obj->dsi == NULL)
+        EC_FAIL;
 
-/*!
- * Get everything running
- */
-int configinit(AFPObj *AFPObj)
-{
-    AFPConfigInit(AFPObj);
+    auth_load(obj->options->uampath, obj->options->uamlist);
+    status_init(obj);
+    set_signature(obj->options);
 
 #ifdef HAVE_LDAP
     /* Parse afp_ldap.conf */
@@ -188,5 +118,8 @@ int configinit(AFPObj *AFPObj)
         zeroconf_register(AFPObj);
     }
 
-    return first;
+EC_CLEANUP:
+    if (q)
+        free(q);
+    EC_EXIT;
 }
index 79b4df07206fdcd8976954cb4f640cc4e7b3ed0d..e39bf3f7217985cd8babe174e8379a6d370666c7 100644 (file)
@@ -93,7 +93,7 @@ void afp_options_free(struct afp_options *opt)
 #define MAXVAL 1024
 int afp_config_parse(AFPObj *AFPObj)
 {
-    dictionary *config = AFPObj->iniconfig;
+    dictionary *config;
     struct afp_options *options = &AFPObj->options;
     int i;
     const char *p, *tmp;
@@ -113,7 +113,7 @@ int afp_config_parse(AFPObj *AFPObj)
         case 'F':
             if (options->configfile)
                 free(options->configfile);
-            options->configfile = optarg;
+            options->configfile = strdup(optarg);
             break;
         default :
             break;
@@ -162,14 +162,22 @@ int afp_config_parse(AFPObj *AFPObj)
 
     /* figure out options w values */
 
-    options->loginmesg      = iniparser_getstring(config, INISEC_AFP, "loginmesg",      "");
-    options->guest          = iniparser_getstring(config, INISEC_AFP, "guestname",      "nobody");
-    options->passwdfile     = iniparser_getstring(config, INISEC_AFP, "passwdfile",     _PATH_AFPDPWFILE);
-    options->uampath        = iniparser_getstring(config, INISEC_AFP, "uampath",        _PATH_AFPDUAMPATH);
-    options->uamlist        = iniparser_getstring(config, INISEC_AFP, "uamlist",        "uams_dhx.so,uams_dhx2.so");
-    options->port           = iniparser_getstring(config, INISEC_AFP, "port",           "548");
-    options->signatureopt   = iniparser_getstring(config, INISEC_AFP, "signature",      "auto");
-
+    options->loginmesg      = iniparser_getstrdup(config, INISEC_AFP, "loginmesg",      "");
+    options->guest          = iniparser_getstrdup(config, INISEC_AFP, "guestname",      "nobody");
+    options->passwdfile     = iniparser_getstrdup(config, INISEC_AFP, "passwdfile",     _PATH_AFPDPWFILE);
+    options->uampath        = iniparser_getstrdup(config, INISEC_AFP, "uampath",        _PATH_AFPDUAMPATH);
+    options->uamlist        = iniparser_getstrdup(config, INISEC_AFP, "uamlist",        "uams_dhx.so,uams_dhx2.so");
+    options->port           = iniparser_getstrdup(config, INISEC_AFP, "port",           "548");
+    options->signatureopt   = iniparser_getstrdup(config, INISEC_AFP, "signature",      "auto");
+    options->k5service      = iniparser_getstrdup(config, INISEC_AFP, "k5service",      NULL);
+    options->k5realm        = iniparser_getstrdup(config, INISEC_AFP, "k5realm",        NULL);
+    options->authprintdir   = iniparser_getstrdup(config, INISEC_AFP, "authprintdir",   NULL);
+    options->listen         = iniparser_getstrdup(config, INISEC_AFP, "listen",         NULL);
+    options->hostname       = iniparser_getstrdup(config, INISEC_AFP, "hostname",       NULL);
+    options->ntdomain       = iniparser_getstrdup(config, INISEC_AFP, "ntdomain",       NULL);
+    options->ntseparator    = iniparser_getstrdup(config, INISEC_AFP, "ntseparator",    NULL);
+    options->mimicmodel     = iniparser_getstrdup(config, INISEC_AFP, "mimicmodel",     NULL);
+    options->adminauthuser  = iniparser_getstrdup(config, INISEC_AFP, "adminauthuser",  NULL);
     options->connections    = iniparser_getint   (config, INISEC_AFP, "maxcon",         200);
     options->passwdminlen   = iniparser_getint   (config, INISEC_AFP, "passwdminlen",   0);
     options->tickleval      = iniparser_getint   (config, INISEC_AFP, "tickleval",      30);
@@ -184,15 +192,6 @@ int afp_config_parse(AFPObj *AFPObj)
     options->sleep          = iniparser_getint   (config, INISEC_AFP, "sleep",          10) * 60 * 2;
     options->disconnect     = iniparser_getint   (config, INISEC_AFP, "disconnect"      24) * 60 * 2;
 
-    options->k5service      = iniparser_getstringdup(config, INISEC_AFP, "k5service", NULL);
-    options->k5realm        = iniparser_getstringdup(config, INISEC_AFP, "k5realm", NULL);
-    options->authprintdir   = iniparser_getstringdup(config, INISEC_AFP, "authprintdir", NULL);
-    options->ipaddr         = iniparser_getstringdup(config, INISEC_AFP, "ipaddr", NULL);
-    options->hostname       = iniparser_getstringdup(config, INISEC_AFP, "hostname", NULL);
-    options->ntdomain       = iniparser_getstringdup(config, INISEC_AFP, "ntdomain", NULL);
-    options->ntseparator    = iniparser_getstringdup(config, INISEC_AFP, "ntseparator", NULL);
-    options->mimicmodel     = iniparser_getstringdup(config, INISEC_AFP, "mimicmodel", NULL);
-    options->adminauthuser  = iniparser_getstringdup(config, INISEC_AFP, "adminauthuser", NULL);
 
     if ((p = iniparser_getstring(config, INISEC_AFP, "k5keytab", NULL))) {
         EC_NULL_LOG( options->k5keytab = malloc(strlen(p) + 14) );
@@ -276,7 +275,7 @@ int afp_config_parse(AFPObj *AFPObj)
     if (options->volnamelen > 255)
            options->volnamelen = 255; /* AFP3 spec */
 
-    return 1;
+    return 0;
 }
 
 /*
index 80b475b17e897690b05e9c22b1e28225a4875321..d96d52dbd79022f6e965431316d5fa184ae54e94 100644 (file)
@@ -55,6 +55,8 @@ static int fdset_size;          /* current allocated size */
 static int fdset_used;          /* number of used elements */
 static int disasociated_ipc_fd; /* disasociated sessions uses this fd for IPC */
 
+static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child *server_children);
+
 /* This is registered with atexit() */
 static void afp_exit(void)
 {
@@ -128,7 +130,6 @@ static void afp_goaway(int sig)
         if (server_children)
             server_child_kill(server_children, CHILD_DSIFORK, sig);
 
-        dsi_cleanup(AFPObj);
         server_unlock(AFPObj->options.pidfile);
         exit(0);
         break;
@@ -221,7 +222,7 @@ int main(int ac, char **av)
     /* Parse argv args and initialize default options */
     AFPObj.argc = ac;
     AFPObj.argv = av;
-    if (!afp_config_parse(&AFPObj))
+    if (afp_config_parse(&AFPObj) != 0)
         exit(EXITERR_CONF);
 
     if (check_lockfile("afpd", _PATH_AFPDLOCK) != 0)
@@ -394,9 +395,7 @@ int main(int ac, char **av)
 
             LOG(log_info, logtype_afpd, "re-reading configuration file");
 
-            /* configfree close atp socket used for DDP tickle, there's an issue
-             * with atp tid. */
-            configfree(&AFPObj);
+            configfree(&AFPObj, NULL);
             if (configinit(&AFPObj) != 0) {
                 LOG(log_error, logtype_afpd, "config re-read: no servers configured");
                 exit(EXITERR_CONF);
@@ -491,3 +490,27 @@ int main(int ac, char **av)
 
     return 0;
 }
+
+static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child *server_children)
+{
+    afp_child_t *child = NULL;
+
+    if (!(child = dsi_getsession(dsi,
+                                 server_children,
+                                 obj->options.tickleval))) {
+        LOG(log_error, logtype_afpd, "dsi_start: session error: %s", strerror(errno));
+        return NULL;
+    }
+
+    /* we've forked. */
+    if (parent_or_child == 1) {
+        configfree(obj, dsi);
+        obj->ipc_fd = child->ipc_fds[1];
+        close(child->ipc_fds[0]); /* Close parent IPC fd */
+        free(child);
+        afp_over_dsi(obj); /* start a session */
+        exit (0);
+    }
+
+    return child;
+}
index d15e9a4640a869d6baa1012796f37b3d03264ebd..f09381b3559a2542524d9d091b9897fe6669c085 100644 (file)
@@ -37,6 +37,7 @@
 #include <atalk/globals.h>
 #include <atalk/fce_api.h>
 #include <atalk/errchk.h>
+#include <atalk/iniparser.h>
 
 #ifdef CNID_DB
 #include <atalk/cnid.h>
 
 extern int afprun(int root, char *cmd, int *outfd);
 
-#ifndef MIN
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#endif /* ! MIN */
-
-#ifndef UUID_PRINTABLE_STRING_LENGTH
-#define UUID_PRINTABLE_STRING_LENGTH 37
-#endif
-
 /* Globals */
 struct vol *current_vol;        /* last volume from getvolbyvid() */
 
@@ -68,10 +61,6 @@ static struct vol *Volumes = NULL;
 static uint16_t    lastvid = 0;
 static char     *Trash = "\02\024Network Trash Folder";
 
-static struct extmap    *Extmap = NULL, *Defextmap = NULL;
-static int              Extmap_cnt;
-static void             free_extmap(void);
-
 #define VOLOPT_ALLOW      0  /* user allow list */
 #define VOLOPT_DENY       1  /* user deny list */
 #define VOLOPT_RWLIST     2  /* user rw list */
@@ -106,8 +95,6 @@ static void             free_extmap(void);
 #define VOLOPT_NUM           (VOLOPT_MAX + 1)
 
 #define VOLPASSLEN  8
-#define VOLOPT_DEFAULT     ":DEFAULT:"
-#define VOLOPT_DEFAULT_LEN 9
 
 struct vol_option {
     char *c_value;
@@ -132,7 +119,6 @@ static void deletevol(struct vol *vol);
 static void volume_free(struct vol *vol);
 static void check_ea_sys_support(struct vol *vol);
 static char *get_vol_uuid(const AFPObj *obj, const char *volname);
-static int readvolfile(AFPObj *obj, struct afp_volume_name *p1,char *p2, int user, struct passwd *pwent);
 
 static void volfree(struct vol_option *options, const struct vol_option *save)
 {
@@ -322,18 +308,6 @@ static char *volxlate(AFPObj *obj,
     return ret;
 }
 
-/* to make sure that val is valid, make sure to select an opt that
-   includes val */
-static int optionok(const char *buf, const char *opt, const char *val)
-{
-    if (!strstr(buf,opt))
-        return 0;
-    if (!val[1])
-        return 0;
-    return 1;
-}
-
-
 /* -------------------- */
 static void setoption(struct vol_option *options, struct vol_option *save, int opt, const char *val)
 {
@@ -342,162 +316,152 @@ static void setoption(struct vol_option *options, struct vol_option *save, int o
     options[opt].c_value = strdup(val + 1);
 }
 
-/* ------------------------------------------
-   handle all the options. tmp can't be NULL. */
-static void volset(struct vol_option *options, struct vol_option *save,
-                   char *volname, int vlen,
-                   const char *tmp)
+/* Parse iniconfig and initalize volume options */
+static void volset(const dictionary *conf, const char *vol, struct vol_option *options, const struct vol_option *save)
 {
-    char *val;
+    const char *val;
+    const char *p;
 
-    val = strchr(tmp, ':');
-    if (!val) {
-        /* we'll assume it's a volume name. */
-        strncpy(volname, tmp, vlen);
-        volname[vlen] = 0;
-        return;
-    }
-#if 0
-    LOG(log_debug, logtype_afpd, "Parsing volset %s", val);
-#endif
-    if (optionok(tmp, "allow:", val)) {
+    if (val = iniparser_getstring(conf, vol, "allow"))
         setoption(options, save, VOLOPT_ALLOW, val);
 
-    } else if (optionok(tmp, "deny:", val)) {
+    if (val = iniparser_getstring(conf, vol, "deny"))
         setoption(options, save, VOLOPT_DENY, val);
 
-    } else if (optionok(tmp, "rwlist:", val)) {
+    if (val = iniparser_getstring(conf, vol, "rwlist"))
         setoption(options, save, VOLOPT_RWLIST, val);
 
-    } else if (optionok(tmp, "rolist:", val)) {
+    if (val = iniparser_getstring(conf, vol, "rolist"))
         setoption(options, save, VOLOPT_ROLIST, val);
 
-    } else if (optionok(tmp, "codepage:", val)) {
-        LOG (log_error, logtype_afpd, "The old codepage system has been removed. Please make sure to read the documentation !!!!");
-        /* Make sure we don't screw anything */
-        exit (EXITERR_CONF);
-    } else if (optionok(tmp, "volcharset:", val)) {
+    if (val = iniparser_getstring(conf, vol, "volcharset"))
         setoption(options, save, VOLOPT_ENCODING, val);
-    } else if (optionok(tmp, "maccharset:", val)) {
-        setoption(options, save, VOLOPT_MACCHARSET, val);
-    } else if (optionok(tmp, "veto:", val)) {
-        setoption(options, save, VOLOPT_VETO, val);
-    } else if (optionok(tmp, "cnidscheme:", val)) {
-        setoption(options, save, VOLOPT_CNIDSCHEME, val);
-    } else if (optionok(tmp, "casefold:", val)) {
-        if (strcasecmp(val + 1, "tolower") == 0)
-            options[VOLOPT_CASEFOLD].i_value = AFPVOL_UMLOWER;
-        else if (strcasecmp(val + 1, "toupper") == 0)
-            options[VOLOPT_CASEFOLD].i_value = AFPVOL_UMUPPER;
-        else if (strcasecmp(val + 1, "xlatelower") == 0)
-            options[VOLOPT_CASEFOLD].i_value = AFPVOL_UUPPERMLOWER;
-        else if (strcasecmp(val + 1, "xlateupper") == 0)
-            options[VOLOPT_CASEFOLD].i_value = AFPVOL_ULOWERMUPPER;
-    } else if (optionok(tmp, "adouble:", val)) {
-        if (strcasecmp(val + 1, "v2") == 0)
-            options[VOLOPT_ADOUBLE].i_value = AD_VERSION2;
-        else if (strcasecmp(val + 1, "ea") == 0)
-            options[VOLOPT_ADOUBLE].i_value = AD_VERSION_EA;
-    } else if (optionok(tmp, "options:", val)) {
-        char *p;
 
-        if ((p = strtok(val + 1, ",")) == NULL) /* nothing */
-            return;
-
-        while (p) {
-            if (strcasecmp(p, "ro") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_RO;
-            else if (strcasecmp(p, "nohex") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_NOHEX;
-            else if (strcasecmp(p, "usedots") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_USEDOTS;
-            else if (strcasecmp(p, "invisibledots") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_USEDOTS | AFPVOL_INV_DOTS;
-            else if (strcasecmp(p, "nostat") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_NOSTAT;
-            else if (strcasecmp(p, "preexec_close") == 0)
-                options[VOLOPT_PREEXEC].i_value = 1;
-            else if (strcasecmp(p, "root_preexec_close") == 0)
-                options[VOLOPT_ROOTPREEXEC].i_value = 1;
-            else if (strcasecmp(p, "upriv") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_UNIX_PRIV;
-            else if (strcasecmp(p, "nodev") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_NODEV;
-            else if (strcasecmp(p, "caseinsensitive") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_CASEINSEN;
-            else if (strcasecmp(p, "illegalseq") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_EILSEQ;
-            else if (strcasecmp(p, "tm") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_TM;
-            else if (strcasecmp(p, "searchdb") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_SEARCHDB;
-            else if (strcasecmp(p, "nonetids") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_NONETIDS;
-            else if (strcasecmp(p, "noacls") == 0)
-                options[VOLOPT_FLAGS].i_value &= ~AFPVOL_ACLS;
-            else if (strcasecmp(p, "nov2toeaconv") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_NOV2TOEACONV;
-            p = strtok(NULL, ",");
-        }
-
-    } else if (optionok(tmp, "cnidserver:", val)) {
-        setoption(options, save, VOLOPT_CNIDSERVER, val);
+    if (val = iniparser_getstring(conf, vol, "maccharset"))
+        setoption(options, save, VOLOPT_MACCHARSET, val);
 
-        char *p = strrchr(val + 1, ':');
-        if (p) {
-            *p = 0;
-            setoption(options, save, VOLOPT_CNIDPORT, p);
-        }
+    if (val = iniparser_getstring(conf, vol, "veto"))
+        setoption(options, save, VOLOPT_VETO, val);
 
-        LOG(log_debug, logtype_afpd, "CNID Server for volume '%s': %s:%s",
-            volname, val + 1, p ? p + 1 : Cnid_port);
+    if (val = iniparser_getstring(conf, vol, "cnidscheme"))
+        setoption(options, save, VOLOPT_CNIDSCHEME, val);
 
-    } else if (optionok(tmp, "dbpath:", val)) {
+    if (val = iniparser_getstring(conf, vol, "dbpath"))
         setoption(options, save, VOLOPT_DBPATH, val);
 
-    } else if (optionok(tmp, "umask:", val)) {
-        options[VOLOPT_UMASK].i_value = (int)strtol(val +1, NULL, 8);
-    } else if (optionok(tmp, "dperm:", val)) {
-        options[VOLOPT_DPERM].i_value = (int)strtol(val+1, NULL, 8);
-    } else if (optionok(tmp, "fperm:", val)) {
-        options[VOLOPT_FPERM].i_value = (int)strtol(val+1, NULL, 8);
-    } else if (optionok(tmp, "perm:", val)) {
-        options[VOLOPT_DFLTPERM].i_value = (int)strtol(val+1, NULL, 8);
-    } else if (optionok(tmp, "password:", val)) {
+    if (val = iniparser_getstring(conf, vol, "password"))
         setoption(options, save, VOLOPT_PASSWORD, val);
-    } else if (optionok(tmp, "root_preexec:", val)) {
+
+    if (val = iniparser_getstring(conf, vol, "root_preexec"))
         setoption(options, save, VOLOPT_ROOTPREEXEC, val);
 
-    } else if (optionok(tmp, "preexec:", val)) {
+    if (val = iniparser_getstring(conf, vol, "preexec"))
         setoption(options, save, VOLOPT_PREEXEC, val);
 
-    } else if (optionok(tmp, "root_postexec:", val)) {
+    if (val = iniparser_getstring(conf, vol, "root_postexec"))
         setoption(options, save, VOLOPT_ROOTPOSTEXEC, val);
 
-    } else if (optionok(tmp, "postexec:", val)) {
+    if (val = iniparser_getstring(conf, vol, "postexec"))
         setoption(options, save, VOLOPT_POSTEXEC, val);
 
-    } else if (optionok(tmp, "allowed_hosts:", val)) {
+    if (val = iniparser_getstring(conf, vol, "allowed_hosts"))
         setoption(options, save, VOLOPT_ALLOWED_HOSTS, val);
 
-    } else if (optionok(tmp, "denied_hosts:", val)) {
+    if (val = iniparser_getstring(conf, vol, "denied_hosts"))
         setoption(options, save, VOLOPT_DENIED_HOSTS, val);
 
-    } else if (optionok(tmp, "ea:", val)) {
-        if (strcasecmp(val + 1, "ad") == 0)
+    if (val = iniparser_getstring(conf, vol, "umask"))
+        options[VOLOPT_UMASK].i_value = (int)strtol(val, NULL, 8);
+
+    if (val = iniparser_getstring(conf, vol, "dperm"))
+        options[VOLOPT_DPERM].i_value = (int)strtol(val, NULL, 8);
+
+    if (val = iniparser_getstring(conf, vol, "fperm"))
+        options[VOLOPT_FPERM].i_value = (int)strtol(val, NULL, 8);
+
+    if (val = iniparser_getstring(conf, vol, "perm"))
+        options[VOLOPT_DFLTPERM].i_value = (int)strtol(val, NULL, 8);
+
+    if (val = iniparser_getstring(conf, vol, "volsizelimit"))
+        options[VOLOPT_LIMITSIZE].i_value = (uint32_t)strtoul(val, NULL, 10);
+
+    if (val = iniparser_getstring(conf, vol, "casefold")) {
+        if (strcasecmp(val, "tolower") == 0)
+            options[VOLOPT_CASEFOLD].i_value = AFPVOL_UMLOWER;
+        else if (strcasecmp(val, "toupper") == 0)
+            options[VOLOPT_CASEFOLD].i_value = AFPVOL_UMUPPER;
+        else if (strcasecmp(val, "xlatelower") == 0)
+            options[VOLOPT_CASEFOLD].i_value = AFPVOL_UUPPERMLOWER;
+        else if (strcasecmp(val, "xlateupper") == 0)
+            options[VOLOPT_CASEFOLD].i_value = AFPVOL_ULOWERMUPPER;
+    }
+
+    if (val = iniparser_getstring(conf, vol, "adouble")) {
+        if (strcasecmp(val, "v2") == 0)
+            options[VOLOPT_ADOUBLE].i_value = AD_VERSION2;
+        else if (strcasecmp(val, "ea") == 0)
+            options[VOLOPT_ADOUBLE].i_value = AD_VERSION_EA;
+    }
+
+    if (val = iniparser_getstring(conf, vol, "ea")) {
+        if (strcasecmp(val, "ad") == 0)
             options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_AD;
-        else if (strcasecmp(val + 1, "sys") == 0)
+        else if (strcasecmp(val, "sys") == 0)
             options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_SYS;
-        else if (strcasecmp(val + 1, "none") == 0)
+        else if (strcasecmp(val, "none") == 0)
             options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_NONE;
+    }
 
-    } else if (optionok(tmp, "volsizelimit:", val)) {
-        options[VOLOPT_LIMITSIZE].i_value = (uint32_t)strtoul(val + 1, NULL, 10);
-
-    } else {
-        /* ignore unknown options */
-        LOG(log_debug, logtype_afpd, "ignoring unknown volume option: %s", tmp);
+    if (val = iniparser_getstrdup(conf, vol, "cnidserver")) {
+        if (p = strrchr(val, ':')) {
+            *p = 0;
+            setoption(options, save, VOLOPT_CNIDPORT, p + 1);
+        }
+        setoption(options, save, VOLOPT_CNIDSERVER, val);
+        LOG(log_debug, logtype_afpd, "CNID Server for volume '%s': %s:%s",
+            volname, val, p ? p + 1 : Cnid_port);
+        free(val);
+    }
 
+    if (val = iniparser_getstrdup(conf, vol, "options")) {
+        if (p = strtok(val, ",")) {
+            while (p) {
+                if (strcasecmp(p, "ro") == 0)
+                    options[VOLOPT_FLAGS].i_value |= AFPVOL_RO;
+                else if (strcasecmp(p, "nohex") == 0)
+                    options[VOLOPT_FLAGS].i_value |= AFPVOL_NOHEX;
+                else if (strcasecmp(p, "usedots") == 0)
+                    options[VOLOPT_FLAGS].i_value |= AFPVOL_USEDOTS;
+                else if (strcasecmp(p, "invisibledots") == 0)
+                    options[VOLOPT_FLAGS].i_value |= AFPVOL_USEDOTS | AFPVOL_INV_DOTS;
+                else if (strcasecmp(p, "nostat") == 0)
+                    options[VOLOPT_FLAGS].i_value |= AFPVOL_NOSTAT;
+                else if (strcasecmp(p, "preexec_close") == 0)
+                    options[VOLOPT_PREEXEC].i_value = 1;
+                else if (strcasecmp(p, "root_preexec_close") == 0)
+                    options[VOLOPT_ROOTPREEXEC].i_value = 1;
+                else if (strcasecmp(p, "upriv") == 0)
+                    options[VOLOPT_FLAGS].i_value |= AFPVOL_UNIX_PRIV;
+                else if (strcasecmp(p, "nodev") == 0)
+                    options[VOLOPT_FLAGS].i_value |= AFPVOL_NODEV;
+                else if (strcasecmp(p, "caseinsensitive") == 0)
+                    options[VOLOPT_FLAGS].i_value |= AFPVOL_CASEINSEN;
+                else if (strcasecmp(p, "illegalseq") == 0)
+                    options[VOLOPT_FLAGS].i_value |= AFPVOL_EILSEQ;
+                else if (strcasecmp(p, "tm") == 0)
+                    options[VOLOPT_FLAGS].i_value |= AFPVOL_TM;
+                else if (strcasecmp(p, "searchdb") == 0)
+                    options[VOLOPT_FLAGS].i_value |= AFPVOL_SEARCHDB;
+                else if (strcasecmp(p, "nonetids") == 0)
+                    options[VOLOPT_FLAGS].i_value |= AFPVOL_NONETIDS;
+                else if (strcasecmp(p, "noacls") == 0)
+                    options[VOLOPT_FLAGS].i_value &= ~AFPVOL_ACLS;
+                else if (strcasecmp(p, "nov2toeaconv") == 0)
+                    options[VOLOPT_FLAGS].i_value |= AFPVOL_NOV2TOEACONV;
+                p = strtok(NULL, ",");
+            }
+        }
+        free(val);
     }
 }
 
@@ -516,9 +480,7 @@ static void showvol(const ucs2_t *name)
 /* ------------------------------- */
 static int creatvol(AFPObj *obj, struct passwd *pwd,
                     char *path, char *name,
-                    struct vol_option *options,
-                    const int user /* user defined volume */
-    )
+                    struct vol_option *options)
 {
     struct vol  *volume;
     int         suffixlen, vlen, tmpvlen, u8mvlen, macvlen;
@@ -757,21 +719,19 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
         if ((volume->v_flags & AFPVOL_EILSEQ))
             volume->v_utom_flags |= CONV__EILSEQ;
 
-        if (!user) {
-            if (options[VOLOPT_PREEXEC].c_value)
-                volume->v_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_PREEXEC].c_value, pwd, path, name);
-            volume->v_preexec_close = options[VOLOPT_PREEXEC].i_value;
+        if (options[VOLOPT_PREEXEC].c_value)
+            volume->v_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_PREEXEC].c_value, pwd, path, name);
+        volume->v_preexec_close = options[VOLOPT_PREEXEC].i_value;
 
-            if (options[VOLOPT_POSTEXEC].c_value)
-                volume->v_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_POSTEXEC].c_value, pwd, path, name);
+        if (options[VOLOPT_POSTEXEC].c_value)
+            volume->v_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_POSTEXEC].c_value, pwd, path, name);
 
-            if (options[VOLOPT_ROOTPREEXEC].c_value)
-                volume->v_root_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPREEXEC].c_value, pwd, path,  name);
-            volume->v_root_preexec_close = options[VOLOPT_ROOTPREEXEC].i_value;
+        if (options[VOLOPT_ROOTPREEXEC].c_value)
+            volume->v_root_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPREEXEC].c_value, pwd, path,  name);
+        volume->v_root_preexec_close = options[VOLOPT_ROOTPREEXEC].i_value;
 
-            if (options[VOLOPT_ROOTPOSTEXEC].c_value)
-                volume->v_root_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPOSTEXEC].c_value, pwd, path,  name);
-        }
+        if (options[VOLOPT_ROOTPOSTEXEC].c_value)
+            volume->v_root_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPOSTEXEC].c_value, pwd, path,  name);
     }
     volume->v_dperm |= volume->v_perm;
     volume->v_fperm |= volume->v_perm;
@@ -944,102 +904,6 @@ static int hostaccessvol(int type, const char *volname, const char *args, const
     return 0;
 }
 
-static void setextmap(char *ext, char *type, char *creator, int user)
-{
-    struct extmap   *em;
-    int                 cnt;
-
-    if (Extmap == NULL) {
-        if (( Extmap = calloc(1, sizeof( struct extmap ))) == NULL ) {
-            LOG(log_error, logtype_afpd, "setextmap: calloc: %s", strerror(errno) );
-            return;
-        }
-    }
-    ext++;
-    for ( em = Extmap, cnt = 0; em->em_ext; em++, cnt++) {
-        if ( (strdiacasecmp( em->em_ext, ext )) == 0 ) {
-            break;
-        }
-    }
-
-    if ( em->em_ext == NULL ) {
-        if (!(Extmap  = realloc( Extmap, sizeof( struct extmap ) * (cnt +2))) ) {
-            LOG(log_error, logtype_afpd, "setextmap: realloc: %s", strerror(errno) );
-            return;
-        }
-        (Extmap +cnt +1)->em_ext = NULL;
-        em = Extmap +cnt;
-    } else if ( !user ) {
-        return;
-    }
-    if (em->em_ext)
-        free(em->em_ext);
-
-    if (!(em->em_ext = strdup(  ext))) {
-        LOG(log_error, logtype_afpd, "setextmap: strdup: %s", strerror(errno) );
-        return;
-    }
-
-    if ( *type == '\0' ) {
-        memcpy(em->em_type, "\0\0\0\0", sizeof( em->em_type ));
-    } else {
-        memcpy(em->em_type, type, sizeof( em->em_type ));
-    }
-    if ( *creator == '\0' ) {
-        memcpy(em->em_creator, "\0\0\0\0", sizeof( em->em_creator ));
-    } else {
-        memcpy(em->em_creator, creator, sizeof( em->em_creator ));
-    }
-}
-
-/* -------------------------- */
-static int extmap_cmp(const void *map1, const void *map2)
-{
-    const struct extmap *em1 = map1;
-    const struct extmap *em2 = map2;
-    return strdiacasecmp(em1->em_ext, em2->em_ext);
-}
-
-static void sortextmap( void)
-{
-    struct extmap   *em;
-
-    Extmap_cnt = 0;
-    if ((em = Extmap) == NULL) {
-        return;
-    }
-    while (em->em_ext) {
-        em++;
-        Extmap_cnt++;
-    }
-    if (Extmap_cnt) {
-        qsort(Extmap, Extmap_cnt, sizeof(struct extmap), extmap_cmp);
-        if (*Extmap->em_ext == 0) {
-            /* the first line is really "." the default entry,
-             * we remove the leading '.' in setextmap
-             */
-            Defextmap = Extmap;
-        }
-    }
-}
-
-/* ----------------------
- */
-static void free_extmap( void)
-{
-    struct extmap   *em;
-
-    if (Extmap) {
-        for ( em = Extmap; em->em_ext; em++) {
-            free (em->em_ext);
-        }
-        free(Extmap);
-        Extmap = NULL;
-        Defextmap = Extmap;
-        Extmap_cnt = 0;
-    }
-}
-
 /* ----------------------
  */
 static int volfile_changed(struct afp_volume_name *p)
@@ -1059,76 +923,40 @@ static int volfile_changed(struct afp_volume_name *p)
     return 0;
 }
 
+static int vol_section(const char *sec)
+{
+    if (STRCMP(sec, ==, INISEC_GLOBAL) == 0)
+        return 0;
+    if (strcmp(sec, INISEC_AFP) == 0)
+        return 0;
+    if (strcmp(sec, INISEC_CNID) == 0)
+        return 0;
+    return 1;
+}
+
 /* ----------------------
- * Read a volume configuration file and add the volumes contained within to
+ * Read volumes from iniconfig and add the volumes contained within to
  * the global volume list. This gets called from the forked afpd childs.
  * The master now reads this too for Zeroconf announcements.
- *
- * If p2 is non-NULL, the file that is opened is
- * p1/p2
- *
- * Lines that begin with # and blank lines are ignored.
- * Volume lines are of the form:
- *      <unix path> [<volume name>] [allow:<user>,<@group>,...] \
- *                           [codepage:<file>] [casefold:<num>]
- *      <extension> TYPE [CREATOR]
- *
  */
-static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int user, struct passwd *pwent)
+static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, struct passwd *pwent)
 {
-    FILE        *fp;
     char        path[MAXPATHLEN + 1];
-    char        tmp[MAXPATHLEN + 1];
     char        volname[AFPVOL_U8MNAMELEN + 1];
-    char        buf[BUFSIZ];
-    char        type[5], creator[5];
+    char        tmp[MAXPATHLEN + 1];
     char        *u, *p;
     int         fd;
     int         i;
-    struct passwd   *pw;
-    struct vol_option   save_options[VOLOPT_NUM];
-    struct vol_option   default_options[VOLOPT_NUM];
-    struct vol_option   options[VOLOPT_NUM];
-    struct stat         st;
+    struct passwd     *pw;
+    struct vol_option save_options[VOLOPT_NUM];
+    struct vol_option default_options[VOLOPT_NUM];
+    struct vol_option options[VOLOPT_NUM];
+
+    LOG(log_debug, logtype_afpd, "readvolfile(\"%s\"): BEGIN", p1->name);
 
     if (!p1->name)
         return -1;
     p1->mtime = 0;
-    strcpy( path, p1->name );
-    if ( p2 != NULL ) {
-        strcat( path, "/" );
-        strcat( path, p2 );
-        if (p1->full_name) {
-            free(p1->full_name);
-        }
-        p1->full_name = strdup(path);
-    }
-
-    if (NULL == ( fp = fopen( path, "r" )) ) {
-        return( -1 );
-    }
-    fd = fileno(fp);
-    if (fd != -1 && !fstat( fd, &st) ) {
-        p1->mtime = st.st_mtime;
-    }
-
-    /* try putting a read lock on the volume file twice, sleep 1 second if first attempt fails */
-    int retries = 2;
-    while (1) {
-        if ((read_lock(fd, 0, SEEK_SET, 0)) != 0) {
-            retries--;
-            if (!retries) {
-                LOG(log_error, logtype_afpd, "readvolfile: can't lock volume file \"%s\"", path);
-                if ( fclose( fp ) != 0 ) {
-                    LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) );
-                }
-                return -1;
-            }
-            sleep(1);
-            continue;
-        }
-        break;
-    }
 
     memset(default_options, 0, sizeof(default_options));
 
@@ -1137,127 +965,63 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us
     default_options[VOLOPT_FLAGS].i_value |= AFPVOL_ACLS;
 #endif
     default_options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_AUTO;
-    LOG(log_maxdebug, logtype_afpd, "readvolfile: seeding default umask: %04o",
-        obj->options.umask);
     default_options[VOLOPT_UMASK].i_value = obj->options.umask;
     memcpy(save_options, default_options, sizeof(options));
 
-    LOG(log_debug, logtype_afpd, "readvolfile: \"%s\"", path);
+    int secnum = iniparser_getnsec(obj->iniconfig);    
+    const char *secname;
 
-    while ( myfgets( buf, sizeof( buf ), fp ) != NULL ) {
-        initline( strlen( buf ), buf );
-        parseline( sizeof( path ) - 1, path );
-        switch ( *path ) {
-        case '\0' :
-        case '#' :
+    for (i = 0; i < secnum; secname = iniparser_getsecname(obj->iniconfig, i), i++) { 
+        if (!vol_section(secname))
+            continue;
+        if ((p = iniparser_getstring(obj->iniconfig, secname, "path")) == NULL)
             continue;
+        strlcpy(path, p, MAXPATHLEN);
+        strcpy(tmp, path);
+        strlcpy(volname, secname, AFPVOL_U8MNAMELEN);
 
-        case ':':
-            /* change the default options for this file */
-            if (strncmp(path, VOLOPT_DEFAULT, VOLOPT_DEFAULT_LEN) == 0) {
-                volfree(default_options, save_options);
-                memcpy(default_options, save_options, sizeof(options));
-                *tmp = '\0';
-                for (i = 0; i < VOLOPT_NUM; i++) {
-                    if (parseline( sizeof( path ) - VOLOPT_DEFAULT_LEN - 1,
-                                   path + VOLOPT_DEFAULT_LEN) < 0)
-                        break;
-                    volset(default_options, NULL, tmp, sizeof(tmp) - 1,
-                           path + VOLOPT_DEFAULT_LEN);
-                }
-            }
-            break;
+        if (!pwent && obj->username)
+            pwent = getpwnam(obj->username);
 
-        case '~' :
-            if (( p = strchr( path, '/' )) != NULL ) {
-                *p++ = '\0';
-            }
-            u = path;
-            u++;
-            if ( *u == '\0' ) {
-                u = obj->username;
-            }
-            if ( u == NULL || *u == '\0' || ( pw = getpwnam( u )) == NULL ) {
-                continue;
-            }
-            strcpy( tmp, pw->pw_dir );
-            if ( p != NULL && *p != '\0' ) {
-                strcat( tmp, "/" );
-                strcat( tmp, p );
-            }
-            /* fall through */
+        if (volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL, NULL) == NULL)
+            continue;
 
-        case '/' :
-            /* send path through variable substitution */
-            if (*path != '~') /* need to copy path to tmp */
-                strcpy(tmp, path);
-            if (!pwent && obj->username)
-                pwent = getpwnam(obj->username);
+        memcpy(options, default_options, sizeof(options));
+        volset(obj->iniconfig, secname, options, default_options);
+
+        /* check allow/deny lists (if not afpd master loading volumes for Zeroconf reg.):
+           allow -> either no list (-1), or in list (1)
+           deny -> either no list (-1), or not in list (0) */
+        if (parent_or_child == 0
+            ||
+            (accessvol(options[VOLOPT_ALLOW].c_value, obj->username) &&
+             (accessvol(options[VOLOPT_DENY].c_value, obj->username) < 1) &&
+             hostaccessvol(VOLOPT_ALLOWED_HOSTS, volname, options[VOLOPT_ALLOWED_HOSTS].c_value, obj) &&
+             (hostaccessvol(VOLOPT_DENIED_HOSTS, volname, options[VOLOPT_DENIED_HOSTS].c_value, obj) < 1))) {
+
+            /* handle read-only behaviour. semantics:
+             * 1) neither the rolist nor the rwlist exist -> rw
+             * 2) rolist exists -> ro if user is in it.
+             * 3) rwlist exists -> ro unless user is in it. */
+            if (parent_or_child == 1
+                &&
+                ((options[VOLOPT_FLAGS].i_value & AFPVOL_RO) == 0)
+                &&
+                ((accessvol(options[VOLOPT_ROLIST].c_value, obj->username) == 1) ||
+                 !accessvol(options[VOLOPT_RWLIST].c_value, obj->username)))
+                options[VOLOPT_FLAGS].i_value |= AFPVOL_RO;
 
-            if (volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL, NULL) == NULL)
+            /* do variable substitution for volname */
+            if (volxlate(obj, tmp, sizeof(tmp) - 1, secname, pwent, path, NULL) == NULL) {
+                volfree(options, default_options);
                 continue;
-
-            /* this is sort of braindead. basically, i want to be
-             * able to specify things in any order, but i don't want to
-             * re-write everything. */
-
-            memcpy(options, default_options, sizeof(options));
-            *volname = '\0';
-
-            /* read in up to VOLOP_NUM possible options */
-            for (i = 0; i < VOLOPT_NUM; i++) {
-                if (parseline( sizeof( tmp ) - 1, tmp ) < 0)
-                    break;
-
-                volset(options, default_options, volname, sizeof(volname) - 1, tmp);
             }
 
-            /* check allow/deny lists (if not afpd master loading volumes for Zeroconf reg.):
-               allow -> either no list (-1), or in list (1)
-               deny -> either no list (-1), or not in list (0) */
-            if (parent_or_child == 0
-                ||
-                (accessvol(options[VOLOPT_ALLOW].c_value, obj->username) &&
-                 (accessvol(options[VOLOPT_DENY].c_value, obj->username) < 1) &&
-                 hostaccessvol(VOLOPT_ALLOWED_HOSTS, volname, options[VOLOPT_ALLOWED_HOSTS].c_value, obj) &&
-                 (hostaccessvol(VOLOPT_DENIED_HOSTS, volname, options[VOLOPT_DENIED_HOSTS].c_value, obj) < 1))) {
-
-                /* handle read-only behaviour. semantics:
-                 * 1) neither the rolist nor the rwlist exist -> rw
-                 * 2) rolist exists -> ro if user is in it.
-                 * 3) rwlist exists -> ro unless user is in it. */
-                if (parent_or_child == 1
-                    &&
-                    ((options[VOLOPT_FLAGS].i_value & AFPVOL_RO) == 0)
-                    &&
-                    ((accessvol(options[VOLOPT_ROLIST].c_value, obj->username) == 1) ||
-                     !accessvol(options[VOLOPT_RWLIST].c_value, obj->username)))
-                    options[VOLOPT_FLAGS].i_value |= AFPVOL_RO;
-
-                /* do variable substitution for volname */
-                if (volxlate(obj, tmp, sizeof(tmp) - 1, volname, pwent, path, NULL) == NULL)
-                    continue;
-
-                creatvol(obj, pwent, path, tmp, options, p2 != NULL);
-            }
-            volfree(options, default_options);
-            break;
-
-        case '.' :
-            parseline( sizeof( type ) - 1, type );
-            parseline( sizeof( creator ) - 1, creator );
-            setextmap( path, type, creator, user);
-            break;
-
-        default :
-            break;
+            creatvol(obj, pwent, path, tmp, options);
         }
+        volfree(options, default_options);
     }
     volfree(save_options, NULL);
-    sortextmap();
-    if ( fclose( fp ) != 0 ) {
-        LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) );
-    }
     p1->loaded = 1;
     return( 0 );
 }
@@ -1815,27 +1579,10 @@ static int stat_vol(uint16_t bitmap, struct vol *vol, char *rbuf, size_t *rbufle
 /* ------------------------------- */
 void load_volumes(AFPObj *obj)
 {
+    EC_INIT;
+    int fd = -1;
     struct passwd   *pwent;
-
-    if (Volumes) {
-        int changed = 0;
-
-        /* check files date */
-        if (obj->options.defaultvol.loaded) {
-            changed = volfile_changed(&obj->options.defaultvol);
-        }
-        if (obj->options.systemvol.loaded) {
-            changed |= volfile_changed(&obj->options.systemvol);
-        }
-        if (obj->options.uservol.loaded) {
-            changed |= volfile_changed(&obj->options.uservol);
-        }
-        if (!changed)
-            return;
-
-        free_extmap();
-        free_volumes();
-    }
+    struct stat         st;
 
     if (parent_or_child == 0) {
         LOG(log_debug, logtype_afpd, "load_volumes: AFP MASTER");
@@ -1843,39 +1590,39 @@ void load_volumes(AFPObj *obj)
         LOG(log_debug, logtype_afpd, "load_volumes: user: %s", obj->username);
     }
 
-    pwent = getpwnam(obj->username);
-    if ( (obj->options.flags & OPTION_USERVOLFIRST) == 0 ) {
-        readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent);
-    }
+    if (Volumes && volfile_changed(&obj->options.volfile))
+        free_volumes();
 
-    if ((*obj->username == '\0') || (obj->options.flags & OPTION_NOUSERVOL)) {
-        readvolfile(obj, &obj->options.defaultvol, NULL, 1, pwent);
-    } else if (pwent) {
-        /*
-         * Read user's AppleVolumes or .AppleVolumes file
-         * If neither are readable, read the default volumes file. if
-         * that doesn't work, create a user share.
-         */
-        if (obj->options.uservol.name) {
-            free(obj->options.uservol.name);
-        }
-        obj->options.uservol.name = strdup(pwent->pw_dir);
-        if ( readvolfile(obj, &obj->options.uservol,    "AppleVolumes", 1, pwent) < 0 &&
-             readvolfile(obj, &obj->options.uservol, ".AppleVolumes", 1, pwent) < 0 &&
-             readvolfile(obj, &obj->options.uservol, "applevolumes", 1, pwent) < 0 &&
-             readvolfile(obj, &obj->options.uservol, ".applevolumes", 1, pwent) < 0 &&
-             obj->options.defaultvol.name != NULL ) {
-            if (readvolfile(obj, &obj->options.defaultvol, NULL, 1, pwent) < 0)
-                creatvol(obj, pwent, pwent->pw_dir, NULL, NULL, 1);
+    /* try putting a read lock on the volume file twice, sleep 1 second if first attempt fails */
+    int retries = 2;
+    fd = open(p1->name, O_RDWR);
+    if (fd != -1 && fstat(fd, &st) == 0)
+        p1->mtime = st.st_mtime; 
+    while (1) {
+        if ((read_lock(fd, 0, SEEK_SET, 0)) != 0) {
+            retries--;
+            if (!retries) {
+                LOG(log_error, logtype_afpd, "readvolfile: can't lock volume file \"%s\"", path);
+                EC_FAIL;
+            }
+            sleep(1);
+            continue;
         }
-    }
-    if ( obj->options.flags & OPTION_USERVOLFIRST ) {
-        readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent );
+        break;
     }
 
-    if ( obj->options.closevol ) {
-        struct vol *vol;
+    iniparser_freedict(obj->iniconfig);
+    obj->iniconfig = iniparser_load(obj->configfile);
+
+    if (obj->username)
+        pwent = getpwnam(obj->username);
+    else
+        pwent = NULL;
+
+    readvolfile(obj, &obj->options.volfile, pwent);
 
+    if ( obj->options.flags & OPTION_CLOSEVOL) {
+        struct vol *vol;
         for ( vol = Volumes; vol; vol = vol->v_next ) {
             if (vol->v_deleted && !vol->v_new ) {
                 of_closevol(vol);
@@ -1884,6 +1631,11 @@ void load_volumes(AFPObj *obj)
             }
         }
     }
+
+EC_CLEANUP:
+    if (fd != -1)
+        (void)close(fd);
+    EC_EXIT;
 }
 
 /* ------------------------------- */
@@ -2703,10 +2455,9 @@ const struct vol *getvolumes(void)
     return Volumes;
 }
 
-void unload_volumes_and_extmap(void)
+void unload_volumes(void)
 {
     LOG(log_debug, logtype_afpd, "unload_volumes_and_extmap");
-    free_extmap();
     free_volumes();
 }
 
index 0a9f0f01fedba48e3e23fdc8566bee32c67e281f..90febbfee00803f6fc803058ffaac982ff599b8d 100644 (file)
@@ -22,7 +22,7 @@ extern void             setvoltime (AFPObj *, struct vol *);
 extern int              pollvoltime (AFPObj *);
 extern void             load_volumes (AFPObj *obj);
 extern const struct vol *getvolumes(void);
-extern void             unload_volumes_and_extmap(void);
+extern void             unload_volumes(void);
 extern void             vol_fce_tm_event(void);
 
 /* FP functions */
index 6f7cddd03a2be05ca7d673242bf18c4e56460323..f520c209b400effd11975f8ee0be723c3a9799af 100644 (file)
@@ -75,7 +75,6 @@ typedef struct DSI {
     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;            /* AFP session socket */
     int      serversock;        /* listening socket */
 
index 716c60382eb36e33b47fdd54ca982425d466dbad..83fd3a1eeb0894e3795a001c9103c77ff35129ec 100644 (file)
@@ -48,6 +48,7 @@
 
 #define INISEC_GLOBAL "General"
 #define INISEC_AFP    "AFP"
+#define INISEC_CNID   "CNID"
 
 struct DSI;
 #define AFPOBJ_TMPSIZ (MAXPATHLEN)
@@ -62,8 +63,6 @@ struct afp_volume_name {
 };
 
 struct afp_options {
-    int argc;
-    char **argv;
     int connections;            /* Maximum number of possible AFP connections */
     int tickleval;
     int timeout;
@@ -77,7 +76,7 @@ struct afp_options {
     uint32_t server_quantum;
     int dsireadbuf; /* scale factor for sizefof(dsi->buffer) = server_quantum * dsireadbuf */
     char *hostname;
-    char *ipaddr, *port;
+    char *listen, *port;
     char *Cnid_srv, *Cnid_port;
     char *configfile;
     char *uampath, *fqdn;
@@ -103,9 +102,12 @@ struct afp_options {
     char *logfile;
     char *mimicmodel;
     char *adminauthuser;
+    struct afp_volume_name volfile;
 };
 
 typedef struct AFPObj {
+    int argc;
+    char **argv;
     int statuslen;
     char status[1400];
     const void *signature;
@@ -142,10 +144,9 @@ extern const char         *Cnid_port;
 
 extern int  get_afp_errno   (const int param);
 extern void afp_options_init (struct afp_options *);
-extern int  afp_options_parse_cmdline (int, char **, struct afp_options *);
-extern int  afp_options_parseline (char *, struct afp_options *);
-extern void afp_options_free (struct afp_options *,
-                                      const struct afp_options *);
+extern int  afp_options_parse_cmdline (int ac, char **av);
+extern int  afp_config_parse(AFPObj *AFPObj);
+extern void afp_options_free(struct afp_options *);
 extern void setmessage (const char *);
 extern void readmessage (AFPObj *);
 
index 6436e4e0ecca04c6348960e692a092ce2eb29e52..6466358c8192265beb13013cac0ec9a867cc1c66 100644 (file)
@@ -39,7 +39,7 @@ char       *iniparser_getsecname(dictionary * d, int n);
 void       iniparser_dump_ini(dictionary * d, FILE * f);
 void       iniparser_dump(dictionary * d, FILE * f);
 char       *iniparser_getstring(dictionary * d, char *section, char * key, char * def);
-char       *iniparser_getstringdup(dictionary * d, char *section, char * key, char * def);
+char       *iniparser_getstrdup(dictionary * d, char *section, char * key, char * def);
 int        iniparser_getint(dictionary * d, char *section, char * key, int notfound);
 double     iniparser_getdouble(dictionary * d, char *section, char * key, double notfound);
 int        iniparser_getboolean(dictionary * d, char *section, char * key, int notfound);
index 941930d328d9020491605f81f7d59592952441a9..6cf872dd28ccd6bfac07ab8e2ab27de9cb406e50 100644 (file)
@@ -17,6 +17,7 @@
 
 #define UUID_BINSIZE 16
 #define UUID_STRINGSIZE 36
+#define UUID_PRINTABLE_STRING_LENGTH 37
 
 typedef const unsigned char *uuidp_t;
 typedef unsigned char atalk_uuid_t[UUID_BINSIZE];
index ee75fcc71ebb26be21a7c3ca40241c352a1d2409..568f9ffdfd9f6565547f453f45a0f1ea49ed409e 100644 (file)
 #include <atalk/dsi.h>
 #include "dsi_private.h"
 
-DSI *dsi_init(const dsi_proto protocol, const char *program, 
-             const char *hostname, const char *address,
-             const char *port, const int proxy, const uint32_t quantum)
+DSI *dsi_init(AFPObj *obj, const char *hostname, const char *address, const char *port)
 {
     DSI                *dsi;
 
-    if ((dsi = (DSI *) calloc(1, sizeof(DSI))) == NULL) {
-      return( NULL );
-    }
-    dsi->attn_quantum = DSI_DEFQUANT; /* default quantum size */
-    dsi->server_quantum = quantum; /* default server quantum */
-    dsi->program = program;
-
-    switch (protocol) {
-      /* currently the only transport protocol that exists for dsi */
-    case DSI_TCPIP: 
-      if (!dsi_tcp_init(dsi, hostname, address, port, proxy)) {
-       free(dsi);
-       dsi = NULL;
-      }
-      break;
-
-    default: /* unknown protocol */
-      free(dsi);
-      dsi = NULL;
-      break;
+    if ((dsi = (DSI *)calloc(1, sizeof(DSI))) == NULL)
+        return NULL;
+
+    dsi->attn_quantum = DSI_DEFQUANT;
+    dsi->server_quantum = obj->options.server_quantum;
+    dsi->dsireadbuf = obj->options->dsireadbuf;
+
+    /* currently the only transport protocol that exists for dsi */
+    if (dsi_tcp_init(dsi, hostname, address, port) != 0) {
+        free(dsi);
+        dsi = NULL;
     }
 
     return dsi;
index c707612607f0d1579e3910f8bc6c4a2faad14cc5..f11eca51f59d2f93aaab5b60bef6d292b34b5b31 100644 (file)
@@ -51,6 +51,7 @@ int deny_severity = log_warning;
 #include <atalk/dsi.h>
 #include <atalk/compat.h>
 #include <atalk/util.h>
+#include <atalk/errchk.h>
 
 #include "dsi_private.h"
 
@@ -268,14 +269,22 @@ iflist_done:
 #endif
 
 /* this needs to accept passed in addresses */
-int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address,
-                 const char *port, const int proxy)
+int dsi_tcp_init(DSI *dsi, const char *hostname, const char *inaddress, const char *inport)
 {
-    int                ret;
+    EC_INIT;
     int                flag;
+    char               *p, *address = NULL;
     struct addrinfo    hints, *servinfo, *p;
 
-    dsi->protocol = DSI_TCPIP;
+    /* Check whether address is of the from IP:PORT and split */
+    address = inaddress;
+    port = inport;
+    if (address && strchr(address, ':')) {
+        EC_NULL_LOG( address = strdup(inaddress) );
+        p = strchr(address, ':');
+        *p = 0;
+        port = p + 1;
+    }
 
     /* Prepare hint for getaddrinfo */
     memset(&hints, 0, sizeof hints);
@@ -296,9 +305,9 @@ int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address,
         hints.ai_family = AF_UNSPEC;
 #endif
     }
-    if ((ret = getaddrinfo(address ? address : NULL, port ? port : "548", &hints, &servinfo)) != 0) {
+    if ((ret = getaddrinfo(address ? address : NULL, port, &hints, &servinfo)) != 0) {
         LOG(log_error, logtype_dsi, "dsi_tcp_init: getaddrinfo: %s\n", gai_strerror(ret));
-        return 0;
+        EC_FAIL;
     }
 
     /* create a socket */
@@ -352,7 +361,7 @@ int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address,
         if (p == NULL)  {
             LOG(log_error, logtype_dsi, "dsi_tcp_init: no suitable network config for TCP socket");
             freeaddrinfo(servinfo);
-            return 0;
+            EC_FAIL;
         }
 
         /* Copy struct sockaddr to struct sockaddr_storage */
@@ -368,7 +377,7 @@ int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address,
 
     if (address) {
         /* address is a parameter, use it 'as is' */
-        return 1;
+        goto EC_CLEANUP;
     }
 
     /* Prepare hint for getaddrinfo */
@@ -376,7 +385,7 @@ int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address,
     hints.ai_family = AF_UNSPEC;
     hints.ai_socktype = SOCK_STREAM;
 
-    if ((ret = getaddrinfo(hostname, port ? port : "548", &hints, &servinfo)) != 0) {
+    if ((ret = getaddrinfo(hostname, port, &hints, &servinfo)) != 0) {
         LOG(log_info, logtype_dsi, "dsi_tcp_init: getaddrinfo '%s': %s\n", hostname, gai_strerror(ret));
         goto interfaces;
     }
@@ -398,13 +407,17 @@ int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address,
         /* Store found address in dsi->server */
         memcpy(&dsi->server, p->ai_addr, p->ai_addrlen);
         freeaddrinfo(servinfo);
-        return 1;
+        goto EC_CLEANUP;
     }
     LOG(log_info, logtype_dsi, "dsi_tcp: hostname '%s' resolves to loopback address", hostname);
     freeaddrinfo(servinfo);
 
 interfaces:
     guess_interface(dsi, hostname, port ? port : "548");
-    return 1;
+
+EC_CLEANUP:
+    if (address)
+        free(address);
+    EC_EXIT;
 }
 
index c1f5cc61725064fc8eafef51a9fd2662d8f01576..0308ed2c8a2a2d015c84aa0a410d381b5c443b02 100644 (file)
@@ -264,7 +264,7 @@ char * iniparser_getstring(dictionary * d, char *section, char * key, char * def
   The returned char pointer a strdup'ed allocated string, so the caller must free it.
  */
 /*--------------------------------------------------------------------------*/
-char * iniparser_getstringdup(dictionary * d, char *section, char * key, char * def)
+char * iniparser_getstrdup(dictionary * d, char *section, char * key, char * def)
 {
     char * sval ;