/*
- * $Id: config.c,v 1.4 2001-06-25 20:13:45 rufustfirefly 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.
#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 <net/route.h>
+#endif /* TRU64 */
#include <net/if.h>
#include <netatalk/at.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 },
{ "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;
/* 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;
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 );
}
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;
}
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 );
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" );
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 );
* 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 ) {
* 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)) {
fprintf(stderr, "Can't configure multicast.\n");
goto read_conf_err;
}
+
#endif /* __svr4__ */
if (( niface = newiface( argv[ 0 ] )) == NULL ) {
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 {
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) {
}
/*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) {
}
/*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
return( 1 );
}
-int phase( iface, av )
- struct interface *iface;
- char **av;
+int phase(struct interface *iface, char **av)
{
int n;
char *pnum;
return( 2 );
}
-int net( iface, av )
- struct interface *iface;
- char **av;
+int net(struct interface *iface, char **av)
{
char *nrange;
char *stop;
return -1;
}
- if (( stop = strchr( nrange, '-' )) != 0 ) {
+ if (( stop = strchr( nrange, '-' )) != NULL ) {
stop++;
}
net = atoi( nrange );
}
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;
}
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 );
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" );
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
fprintf( stderr, "Must specify net-range before zones.\n" );
return -1;
}
+
if (( zt = newzt( strlen( zname ), zname )) == NULL ) {
perror( "newzt" );
return -1;
iface->i_czt->zt_next = zt;
}
}
+ free(zname);
+
return( 2 );
}
* 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;
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)
* the interface structure and have it updated nicely.
*/
-struct interface *newiface( name )
- const char *name;
+struct interface *newiface( const char *name)
{
struct interface *niface;
== 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 */
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 ) {
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;
}
return -1;
}
- syslog( LOG_INFO, "plumbed %s%d", device, ppa );
+ LOG(log_info, logtype_atalkd, "plumbed %s%d", device, ppa );
+
+ close(fd);
}
return( 0 );