]> arthur.barton.de Git - netatalk.git/blobdiff - etc/atalkd/config.c
Several small fixes, from Riccardo Magliocchetti
[netatalk.git] / etc / atalkd / config.c
index da2edeeecb1176fc04cd1334badd6fa4520b8b4d..4005d6995631e8256608262dc457300a7623f5b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: config.c,v 1.5 2001-08-15 01:39:39 srittau Exp $
+ * $Id: config.c,v 1.20 2009-10-29 11:35:58 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved. See COPYRIGHT.
@@ -13,7 +13,7 @@
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
-#include <syslog.h>
+#include <atalk/logger.h>
 #include <sys/param.h>
 #ifdef TRU64
 #include <sys/mbuf.h>
 #include <netatalk/endian.h>
 #include <atalk/paths.h>
 #include <atalk/util.h>
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 #include <ctype.h>
+
+/* STDC check */
+#if STDC_HEADERS
+#include <string.h>
+#else /* STDC_HEADERS */
+#ifndef HAVE_STRCHR
+#define strchr index
+#define strrchr index
+#endif /* HAVE_STRCHR */
+char *strchr (), *strrchr ();
+#ifndef HAVE_MEMCPY
+#define memcpy(d,s,n) bcopy ((s), (d), (n))
+#define memmove(d,s,n) bcopy ((s), (d), (n))
+#endif /* ! HAVE_MEMCPY */
+#endif /* STDC_HEADERS */
+
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #endif /* HAVE_FCNTL_H */
-#include <errno.h>
 
 #ifdef __svr4__
 #include <sys/sockio.h>
 #include <sys/stropts.h>
 #endif /* __svr4__ */
 
+#include <atalk/unicode.h>
 #include "interface.h"
 #include "multicast.h"
 #include "rtmp.h"
 #include "zip.h"
 #include "list.h"
+#include "main.h"
 
 #ifndef IFF_SLAVE /* a little backward compatibility */
 #define IFF_SLAVE 0
 #endif /* IFF_SLAVE */
 
-int    router(), dontroute(), seed(), phase(), net(), addr(), zone();
+int router(struct interface *iface, char **av);
+int dontroute(struct interface *iface, char **av);
+int seed(struct interface *iface, char **av);
+int phase(struct interface *iface, char **av); 
+int net(struct interface *iface, char **av);
+int addr(struct interface *iface, char **av); 
+int zone(struct interface *iface, char **av);
+int noallmulti(struct interface *iface, char **av);
 
-static struct param {
+static const struct param {
     char       *p_name;
-    int                (*p_func)();
+    int                (*p_func)(struct interface *iface, char **av);
 } params[] = {
     { "router", router },
     { "dontroute", dontroute },
@@ -61,68 +87,115 @@ static struct param {
     { "net",   net },
     { "addr",  addr },
     { "zone",  zone },
+    { "noallmulti", noallmulti }
 };
 
-static char **
-parseline( line )
-    char       *line;
+#define ARGV_CHUNK_SIZE 128
+#define MAXLINELEN 2048
+static char **parseline(const char *line)
 {
-    char       *p;
-    int                argc = 0;
-    static char        *argv[ 128 ];
-    static char        buf[ 1024 ];
+    const char  *p;
+    int                  argc = 0;
+    char        *buffer, *tmpbuf;
+    char       **argv;
 
-    if ( *line == '#' ) {
-       return( NULL );
+    /* Ignore empty lines and lines with leading hash marks. */
+    p = line;
+    while ( isspace( *p ) ) {
+       p++;
     }
-    argc = 0;
+    if ( *p == '#' || *p == '\0' ) {
+       return NULL;
+    }
+
+    buffer = (char *) malloc( strlen( p ) + 1 );
+    if ( !buffer ) {
+       /* FIXME: error handling */
+       return NULL;
+    }
+    strcpy( buffer, p );
+    tmpbuf = buffer;
 
-    memset(argv, 0, sizeof(argv));
-    strcpy( buf, line );
-    p = buf;
+    argv = (char **) malloc( ARGV_CHUNK_SIZE * sizeof( char * ) );
+    if ( !argv ) {
+       /* FIXME: error handling */
+       free( buffer );
+       return NULL;
+    }
 
     /*
      * This parser should be made more powerful -- it should
      * handle various escapes, e.g. \" and \031.
      */
-    while ( *p != '\0' ) {
-       while ( *p != '\0' && *p != '"' && isspace( *p )) {
-           p++;
-       }
-       if ( *p == '\0' ) {
-           argv[ argc ] = 0;
-           break;
-       }
-       if ( *p == '"' ) {
-           argv[ argc ] = ++p;
-           while ( *p != '\0' && *p != '"' ) {
-               p++;
+    do {
+       if ( *tmpbuf == '"' ) {
+           argv[ argc++ ] = ++tmpbuf;
+           while ( *tmpbuf != '\0' && *tmpbuf != '"' ) {
+               tmpbuf++;
+           }
+           if ( *tmpbuf == '"' ) {
+               /* FIXME: error handling */
            }
        } else {
-           argv[ argc ] = p;
-           while ( *p != '\0' && !isspace( *p )) {
-               p++;
+           argv[ argc++ ] = tmpbuf;
+           while ( *tmpbuf != '\0' && !isspace( *tmpbuf )) {
+               tmpbuf++;
            }
        }
-       *p++ = '\0';
-       argc++;
-    }
-    if ( argv[ 0 ] == '\0' || *argv[ 0 ] == '#' ) {
-       return( NULL );
+       *tmpbuf++ = '\0';
+
+       /* Make room for a NULL pointer and our special pointer (s.b.) */
+       if ( (argc + 1) % ARGV_CHUNK_SIZE == 0 ) {
+           char **tmp;
+           tmp = (char **) realloc( argv, argc + 1 + ARGV_CHUNK_SIZE * sizeof( char * ) );
+           if ( !tmp ) {
+               /* FIXME: error handling */
+               free( argv );
+               free( buffer );
+               return NULL;
+           }
+           argv = tmp;
+       }
+
+       /* Skip white spaces. */
+        while ( isspace( *tmpbuf ) ) {
+            tmpbuf++;
+        }
+    } while ( *tmpbuf != '\0' );
+
+    argv[ argc++ ] = NULL;
+    /* We store our buffer pointer in argv, too, so we can free it later.
+     * (But don't tell anyone.)
+     */
+    argv[ argc ] = buffer;
+
+    return argv;
+}
+
+static void freeline( char **argv )
+{
+    char **tmp = argv;
+
+    if ( argv ) {
+       while ( *tmp ) {
+           tmp++;
+       }
+       free( *++tmp );
+       free( argv );
     }
-    return( argv );
 }
 
-int writeconf( cf )
-    char       *cf;
+int writeconf(char *cf)
 {
     struct stat                st;
-    char               *path, *p, newpath[ MAXPATHLEN ], line[ 1024 ];
+    char               *path, *p, newpath[ MAXPATHLEN ], line[ MAXLINELEN ];
     char               **argv;
     FILE               *conf, *newconf;
     struct interface   *iface;
     struct list                *l;
     int                        mode = 0644, fd;
+    size_t             len;
+    char               *zonename;
 
     if ( cf == NULL ) {
        path = _PATH_ATALKDCONF;
@@ -133,7 +206,7 @@ int writeconf( cf )
     /* check if old conf is writable */
     if ( stat( path, &st ) == 0 ) {
        if (( st.st_mode & S_IWUSR ) == 0 ) {
-           syslog( LOG_INFO, "%s not writable, won't rewrite", path );
+           LOG(log_info, logtype_atalkd, "%s not writable, won't rewrite", path );
            return( -1 );
        }
         mode = st.st_mode;
@@ -145,16 +218,16 @@ int writeconf( cf )
        sprintf( newpath, "%.*s/%s", (int)(p - path), path, _PATH_ATALKDTMP );
     }
     if (( fd = open( newpath, O_WRONLY|O_CREAT|O_TRUNC, mode )) < 0 ) {
-       syslog( LOG_ERR, "%s: %m", newpath );
+       LOG(log_error, logtype_atalkd, "%s: %s", newpath, strerror(errno) );
        return( -1 );
     }
     if (( newconf = fdopen( fd, "w" )) == NULL ) {
-       syslog( LOG_ERR, "fdreopen %s: %m", newpath );
+       LOG(log_error, logtype_atalkd, "fdreopen %s: %s", newpath, strerror(errno) );
        return( -1 );
     }
 
     if (( conf = fopen( path, "r" )) == NULL && cf ) {
-       syslog( LOG_ERR, "%s: %m", path );
+       LOG(log_error, logtype_atalkd, "%s: %s", path, strerror(errno) );
        return( -1 );
     }
 
@@ -163,9 +236,10 @@ int writeconf( cf )
     while ( conf == NULL || fgets( line, sizeof( line ), conf ) != NULL ) {
        if ( conf != NULL && ( argv = parseline( line )) == NULL ) {
            if ( fputs( line, newconf ) == EOF ) {
-               syslog( LOG_ERR, "fputs: %m" );
+               LOG(log_error, logtype_atalkd, "fputs: %s", strerror(errno) );
                return( -1 );
            }
+           freeline( argv );
            continue;
        }
 
@@ -180,6 +254,11 @@ int writeconf( cf )
            if ( iface->i_flags & IFACE_DONTROUTE) {
                fprintf( newconf, " -dontroute");
            }
+#ifdef linux
+            if ( !(iface->i_flags & IFACE_ALLMULTI)) {
+               fprintf( newconf, " -noallmulti");
+            }
+#endif
 
            fprintf( newconf, " -phase %d",
                    ( iface->i_flags & IFACE_PHASE1 ) ? 1 : 2 );
@@ -191,9 +270,20 @@ int writeconf( cf )
                    ntohs( iface->i_addr.sat_addr.s_net ),
                    iface->i_addr.sat_addr.s_node );
            for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
-               fprintf( newconf, " -zone \"%.*s\"",
-                       ((struct ziptab *)l->l_data)->zt_len,
-                       ((struct ziptab *)l->l_data)->zt_name );
+                /* codepage conversion */
+                if ((size_t)(-1) == (len = convert_string_allocate(CH_MAC, CH_UNIX, 
+                                      ((struct ziptab *)l->l_data)->zt_name,
+                                      ((struct ziptab *)l->l_data)->zt_len,
+                                      &zonename)) ) {
+                    if ( NULL == 
+                      (zonename = strdup(((struct ziptab *)l->l_data)->zt_name))) {
+                       LOG(log_error, logtype_atalkd, "malloc: %s",  strerror(errno) );
+                       return( -1 );
+                    }
+                    len = ((struct ziptab *)l->l_data)->zt_len;
+                } 
+               fprintf( newconf, " -zone \"%.*s\"", (int)len, zonename);
+                free(zonename);
            }
            fprintf( newconf, "\n" );
 
@@ -209,7 +299,7 @@ int writeconf( cf )
     fclose( newconf );
 
     if ( rename( newpath, path ) < 0 ) {
-       syslog( LOG_ERR, "rename %s to %s: %m", newpath, path );
+       LOG(log_error, logtype_atalkd, "rename %s to %s: %s", newpath, path, strerror(errno) );
        return( -1 );
     }
     return( 0 );
@@ -237,13 +327,13 @@ int writeconf( cf )
  * zone for an interface is the first zone encountered for that
  * interface.
  */
-int readconf( cf )
-    char               *cf;
+int readconf(char *cf)
 {
     struct ifreq       ifr;
     struct interface   *iface, *niface;
-    char               line[ 1024 ], **argv, *p;
-    int                        i, j, s, cc;
+    char               line[ MAXLINELEN ], **argv, *p;
+    unsigned int       i, j;
+    int                        s, cc = 0;
     FILE               *conf;
 
     if ( cf == NULL ) {
@@ -273,7 +363,7 @@ int readconf( cf )
         * Check that av[ 0 ] is a valid interface.
         * Not possible under sysV.
         */
-       strcpy( ifr.ifr_name, argv[ 0 ] );
+       strlcpy( ifr.ifr_name, argv[ 0 ], sizeof(ifr.ifr_name) );
 
        /* for devices that don't support appletalk */
        if ((ioctl(s, SIOCGIFADDR, &ifr) < 0) && (errno == ENODEV)) {
@@ -303,6 +393,7 @@ int readconf( cf )
          fprintf(stderr, "Can't configure multicast.\n");
          goto read_conf_err;
        }
+
 #endif /* __svr4__ */
 
        if (( niface = newiface( argv[ 0 ] )) == NULL ) {
@@ -343,6 +434,15 @@ int readconf( cf )
            goto read_conf_err;
        }
 
+#ifdef linux
+       /* Don't set interface to allmulti if it already is, or -noallmulti was given */
+       if ((ifr.ifr_flags & IFF_ALLMULTI))
+               niface->i_flags |= IFACE_WASALLMULTI; 
+
+       if ((niface->i_flags & IFACE_ALLMULTI) && !(niface->i_flags & IFACE_WASALLMULTI))
+               ifsetallmulti(ifr.ifr_name, 1);
+#endif
+
        if ( interfaces == NULL ) {
            interfaces = niface;
        } else {
@@ -379,10 +479,16 @@ read_conf_err:
     return -1;
 }
 
+int noallmulti( struct interface *iface, char **av _U_)
+{
+    /* Linux specific, no effect on other platforms */
+    iface->i_flags &= !IFACE_ALLMULTI;
+
+    return (1);
+}
+       
 /*ARGSUSED*/
-int router( iface, av )
-    struct interface   *iface;
-    char               **av;
+int router(struct interface *iface, char **av _U_)
 {
     /* make sure "-router" and "-dontroute" aren't both on the same line. */
     if (iface->i_flags & IFACE_DONTROUTE) {
@@ -404,9 +510,7 @@ int router( iface, av )
 }
 
 /*ARGSUSED*/
-int dontroute( iface, av )
-    struct interface   *iface;
-    char               **av;
+int dontroute(struct interface *iface, char **av _U_)
 {
     /* make sure "-router" and "-dontroute" aren't both on the same line. */
     if (iface->i_flags & IFACE_RSEED) {
@@ -419,9 +523,7 @@ int dontroute( iface, av )
 }
 
 /*ARGSUSED*/
-int seed( iface, av )
-    struct interface   *iface;
-    char               **av;
+int seed( struct interface *iface, char **av _U_)
 {
     /*
      * Check to be sure "-seed" is before "-zone". we keep the old
@@ -437,9 +539,7 @@ int seed( iface, av )
     return( 1 );
 }
 
-int phase( iface, av )
-    struct interface   *iface;
-    char               **av;
+int phase(struct interface *iface, char **av)
 {
     int                        n;
     char               *pnum;
@@ -465,9 +565,7 @@ int phase( iface, av )
     return( 2 );
 }
 
-int net( iface, av )
-    struct interface   *iface;
-    char               **av;
+int net(struct interface *iface, char **av)
 {
     char               *nrange;
     char               *stop;
@@ -478,7 +576,7 @@ int net( iface, av )
        return -1;
     }
 
-    if (( stop = strchr( nrange, '-' )) != 0 ) {
+    if (( stop = strchr( nrange, '-' )) != NULL ) {
        stop++;
     }
     net = atoi( nrange );
@@ -493,7 +591,7 @@ int net( iface, av )
     }
 
     if ( iface->i_flags & IFACE_PHASE1 ) {
-       if ( stop != 0 ) {
+       if ( stop != NULL ) {
            fprintf( stderr, "Phase 1 doesn't use an address range.\n" );
            return -1;
        }
@@ -506,7 +604,7 @@ int net( iface, av )
        iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet = htons( net );
     } else if ( iface->i_flags & IFACE_PHASE2 ) {
        iface->i_rt->rt_firstnet = htons( net );
-       if ( stop != 0 ) {
+       if ( stop != NULL ) {
            net = atoi( stop );
            if ( net < 0 || net >= 0xffff ) {
                fprintf( stderr, "Bad network: %d\n", net );
@@ -535,9 +633,7 @@ int net( iface, av )
     return( 2 );
 }
 
-int addr( iface, av )
-    struct interface   *iface;
-    char               **av;
+int addr(struct interface *iface, char **av)
 {
     if ( av[ 0 ] == NULL ) {
        fprintf( stderr, "No address.\n" );
@@ -571,18 +667,21 @@ int addr( iface, av )
     return( 2 );
 }
 
-int zone( iface, av )
-    struct interface   *iface;
-    char               **av;
+int zone(struct interface *iface, char **av)
 {
     struct ziptab      *zt;
     char               *zname;
 
-    if (( zname = av[ 0 ] ) == NULL ) {
+    if ( av[ 0 ]  == NULL ) {
        fprintf( stderr, "No zone.\n" );
        return -1;
     }
 
+    /* codepage conversion */
+    if ((size_t)(-1) == convert_string_allocate(CH_UNIX, CH_MAC, av[0], -1, &zname)) {
+       zname = strdup(av[0]);
+    }
+
     /*
      * Only process "-zone" if this interface has "-seed".  We keep our
      * list of configured zones in the interface structure.  Then we can
@@ -593,6 +692,7 @@ int zone( iface, av )
            fprintf( stderr, "Must specify net-range before zones.\n" );
            return -1;
         }
+
        if (( zt = newzt( strlen( zname ), zname )) == NULL ) {
            perror( "newzt" );
            return -1;
@@ -604,6 +704,8 @@ int zone( iface, av )
            iface->i_czt->zt_next = zt;
        }
     }
+    free(zname);
+
     return( 2 );
 }
 
@@ -611,7 +713,7 @@ int zone( iface, av )
  * Get the configuration from the kernel. Only called if there's no
  * configuration.
  */
-int getifconf()
+int getifconf(void)
 {
     struct interface   *iface, *niface;
     struct ifreq        ifr;
@@ -625,7 +727,7 @@ int getifconf()
 
     start = list = getifacelist();
     while (list && *list) {
-        strncpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
+        strlcpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
        list++;
 
        if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
@@ -691,8 +793,7 @@ int getifconf()
  * the interface structure and have it updated nicely.
  */
 
-struct interface *newiface( name )
-    const char         *name;
+struct interface *newiface( const char *name)
 {
     struct interface   *niface;
 
@@ -700,7 +801,7 @@ struct interface *newiface( name )
            == NULL ) {
        return( NULL );
     }
-    strncpy( niface->i_name, name, sizeof(niface->i_name));
+    strlcpy( niface->i_name, name, sizeof(niface->i_name));
 #ifdef BSD4_4
     niface->i_addr.sat_len = sizeof( struct sockaddr_at );
 #endif /* BSD4_4 */
@@ -709,15 +810,19 @@ struct interface *newiface( name )
     niface->i_caddr.sat_len = sizeof( struct sockaddr_at );
 #endif /* BSD4_4 */
     niface->i_caddr.sat_family = AF_APPLETALK;
+#ifdef linux
+    niface->i_flags = IFACE_ALLMULTI;
+#endif
     return( niface );
 }
 
 #ifdef __svr4__
-int plumb()
+int plumb(void)
 {
     struct interface   *iface;
-    char               device[ MAXPATHLEN + 1], *p;
+    char               device[ MAXPATHLEN + 1], *p, *t;
     int                        fd, ppa;
+    int                        digits = 0;
 
     for ( iface = interfaces; iface != NULL; iface = iface->i_next ) {
        if ( strcmp( iface->i_name, LOOPIFACE ) == 0 ) {
@@ -726,24 +831,33 @@ int plumb()
 
        strcpy( device, "/dev/" );
        strcat( device, iface->i_name );
-       if (( p = strpbrk( device, "0123456789" )) == NULL ) {
-           syslog( LOG_ERR, "plumb: invalid device: %s", device );
+       for (t = device; *t != '\0' ; ++t) {
+           if (isdigit(*t) == 0) {
+               p = t + 1;
+           }
+           else {
+               digits++;
+           }
+       }
+
+       if (digits == 0) {
+           LOG(log_error, logtype_atalkd, "plumb: invalid device: %s", device );
            return -1;
        }
        ppa = atoi( p );
        *p = '\0';
 
        if (( fd = open( device, O_RDWR, 0 )) < 0 ) {
-           syslog( LOG_ERR, "%s: %m", device );
+           LOG(log_error, logtype_atalkd, "%s: %s", device, strerror(errno) );
            return -1;
        }
        if ( ioctl( fd, I_PUSH, "ddp" ) < 0 ) {
-           syslog( LOG_ERR, "I_PUSH: %m" );
+           LOG(log_error, logtype_atalkd, "I_PUSH: %s", strerror(errno) );
            close(fd);
            return -1;
        }
        if ( ioctl( fd, IF_UNITSEL, ppa ) < 0 ) {
-           syslog( LOG_ERR, "IF_UNITSEL: %m" );
+           LOG(log_error, logtype_atalkd, "IF_UNITSEL: %s", strerror(errno) );
            close(fd);
            return -1;
        }
@@ -756,7 +870,9 @@ int plumb()
          return -1;
        }
 
-       syslog( LOG_INFO, "plumbed %s%d", device, ppa );
+       LOG(log_info, logtype_atalkd, "plumbed %s%d", device, ppa );
+
+    close(fd);
     }
 
     return( 0 );