]> arthur.barton.de Git - netatalk.git/blob - etc/atalkd/config.c
Remove bdb env on exit
[netatalk.git] / etc / atalkd / config.c
1 /*
2  * $Id: config.c,v 1.20 2009-10-29 11:35:58 didg Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved. See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <sys/socket.h>
15 #include <sys/ioctl.h>
16 #include <atalk/logger.h>
17 #include <sys/param.h>
18 #ifdef TRU64
19 #include <sys/mbuf.h>
20 #include <net/route.h>
21 #endif /* TRU64 */
22 #include <net/if.h>
23 #include <netatalk/at.h>
24 #include <netatalk/endian.h>
25 #include <atalk/paths.h>
26 #include <atalk/util.h>
27 #include <assert.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <ctype.h>
33
34 /* STDC check */
35 #if STDC_HEADERS
36 #include <string.h>
37 #else /* STDC_HEADERS */
38 #ifndef HAVE_STRCHR
39 #define strchr index
40 #define strrchr index
41 #endif /* HAVE_STRCHR */
42 char *strchr (), *strrchr ();
43 #ifndef HAVE_MEMCPY
44 #define memcpy(d,s,n) bcopy ((s), (d), (n))
45 #define memmove(d,s,n) bcopy ((s), (d), (n))
46 #endif /* ! HAVE_MEMCPY */
47 #endif /* STDC_HEADERS */
48
49 #ifdef HAVE_FCNTL_H
50 #include <fcntl.h>
51 #endif /* HAVE_FCNTL_H */
52
53 #ifdef __svr4__
54 #include <sys/sockio.h>
55 #include <sys/stropts.h>
56 #endif /* __svr4__ */
57
58 #include <atalk/unicode.h>
59 #include "interface.h"
60 #include "multicast.h"
61 #include "rtmp.h"
62 #include "zip.h"
63 #include "list.h"
64 #include "main.h"
65
66 #ifndef IFF_SLAVE /* a little backward compatibility */
67 #define IFF_SLAVE 0
68 #endif /* IFF_SLAVE */
69
70 int router(struct interface *iface, char **av);
71 int dontroute(struct interface *iface, char **av);
72 int seed(struct interface *iface, char **av);
73 int phase(struct interface *iface, char **av); 
74 int net(struct interface *iface, char **av);
75 int addr(struct interface *iface, char **av); 
76 int zone(struct interface *iface, char **av);
77 int noallmulti(struct interface *iface, char **av);
78
79 static const struct param {
80     char        *p_name;
81     int         (*p_func)(struct interface *iface, char **av);
82 } params[] = {
83     { "router", router },
84     { "dontroute", dontroute },
85     { "seed",   seed },
86     { "phase",  phase },
87     { "net",    net },
88     { "addr",   addr },
89     { "zone",   zone },
90     { "noallmulti", noallmulti }
91 };
92
93 #define ARGV_CHUNK_SIZE 128
94 #define MAXLINELEN 2048
95 static char **parseline(const char *line)
96 {
97     const char   *p;
98     int           argc = 0;
99     char         *buffer, *tmpbuf;
100     char        **argv;
101
102     /* Ignore empty lines and lines with leading hash marks. */
103     p = line;
104     while ( isspace( *p ) ) {
105         p++;
106     }
107     if ( *p == '#' || *p == '\0' ) {
108         return NULL;
109     }
110
111     buffer = (char *) malloc( strlen( p ) + 1 );
112     if ( !buffer ) {
113         /* FIXME: error handling */
114         return NULL;
115     }
116     strcpy( buffer, p );
117     tmpbuf = buffer;
118
119     argv = (char **) malloc( ARGV_CHUNK_SIZE * sizeof( char * ) );
120     if ( !argv ) {
121         /* FIXME: error handling */
122         free( buffer );
123         return NULL;
124     }
125
126     /*
127      * This parser should be made more powerful -- it should
128      * handle various escapes, e.g. \" and \031.
129      */
130     do {
131         if ( *tmpbuf == '"' ) {
132             argv[ argc++ ] = ++tmpbuf;
133             while ( *tmpbuf != '\0' && *tmpbuf != '"' ) {
134                 tmpbuf++;
135             }
136             if ( *tmpbuf == '"' ) {
137                 /* FIXME: error handling */
138             }
139         } else {
140             argv[ argc++ ] = tmpbuf;
141             while ( *tmpbuf != '\0' && !isspace( *tmpbuf )) {
142                 tmpbuf++;
143             }
144         }
145         *tmpbuf++ = '\0';
146
147         /* Make room for a NULL pointer and our special pointer (s.b.) */
148         if ( (argc + 1) % ARGV_CHUNK_SIZE == 0 ) {
149             char **tmp;
150             tmp = (char **) realloc( argv, argc + 1 + ARGV_CHUNK_SIZE * sizeof( char * ) );
151             if ( !tmp ) {
152                 /* FIXME: error handling */
153                 free( argv );
154                 free( buffer );
155                 return NULL;
156             }
157             argv = tmp;
158         }
159
160         /* Skip white spaces. */
161         while ( isspace( *tmpbuf ) ) {
162             tmpbuf++;
163         }
164     } while ( *tmpbuf != '\0' );
165
166     argv[ argc++ ] = NULL;
167     /* We store our buffer pointer in argv, too, so we can free it later.
168      * (But don't tell anyone.)
169      */
170     argv[ argc ] = buffer;
171
172     return argv;
173 }
174
175 static void freeline( char **argv )
176 {
177     char **tmp = argv;
178
179     if ( argv ) {
180         while ( *tmp ) {
181             tmp++;
182         }
183         free( *++tmp );
184         free( argv );
185     }
186 }
187
188 int writeconf(char *cf)
189 {
190     struct stat         st;
191     char                *path, *p, newpath[ MAXPATHLEN ], line[ MAXLINELEN ];
192     char                **argv;
193     FILE                *conf, *newconf;
194     struct interface    *iface;
195     struct list         *l;
196     int                 mode = 0644, fd;
197     size_t              len;
198     char                *zonename;
199
200     if ( cf == NULL ) {
201         path = _PATH_ATALKDCONF;
202     } else {
203         path = cf;
204     }
205
206     /* check if old conf is writable */
207     if ( stat( path, &st ) == 0 ) {
208         if (( st.st_mode & S_IWUSR ) == 0 ) {
209             LOG(log_info, logtype_atalkd, "%s not writable, won't rewrite", path );
210             return( -1 );
211         }
212          mode = st.st_mode;
213     }
214
215     if (( p = strrchr( path, '/' )) == NULL ) {
216         strcpy( newpath, _PATH_ATALKDTMP );
217     } else {
218         sprintf( newpath, "%.*s/%s", (int)(p - path), path, _PATH_ATALKDTMP );
219     }
220     if (( fd = open( newpath, O_WRONLY|O_CREAT|O_TRUNC, mode )) < 0 ) {
221         LOG(log_error, logtype_atalkd, "%s: %s", newpath, strerror(errno) );
222         return( -1 );
223     }
224     if (( newconf = fdopen( fd, "w" )) == NULL ) {
225         LOG(log_error, logtype_atalkd, "fdreopen %s: %s", newpath, strerror(errno) );
226         return( -1 );
227     }
228
229     if (( conf = fopen( path, "r" )) == NULL && cf ) {
230         LOG(log_error, logtype_atalkd, "%s: %s", path, strerror(errno) );
231         return( -1 );
232     }
233
234     iface = interfaces->i_next;
235
236     while ( conf == NULL || fgets( line, sizeof( line ), conf ) != NULL ) {
237         if ( conf != NULL && ( argv = parseline( line )) == NULL ) {
238             if ( fputs( line, newconf ) == EOF ) {
239                 LOG(log_error, logtype_atalkd, "fputs: %s", strerror(errno) );
240                 return( -1 );
241             }
242             freeline( argv );
243             continue;
244         }
245
246         /* write real lines */
247         if ( iface ) {
248             fprintf( newconf, "%s", iface->i_name );
249             if ( iface->i_flags & IFACE_RSEED ) {
250                 fprintf( newconf, " -router" );
251             } else if ( iface->i_flags & IFACE_SEED ) {
252                 fprintf( newconf, " -seed" );
253             }
254             if ( iface->i_flags & IFACE_DONTROUTE) {
255                 fprintf( newconf, " -dontroute");
256             }
257 #ifdef linux
258             if ( !(iface->i_flags & IFACE_ALLMULTI)) {
259                 fprintf( newconf, " -noallmulti");
260             }
261 #endif
262
263             fprintf( newconf, " -phase %d",
264                     ( iface->i_flags & IFACE_PHASE1 ) ? 1 : 2 );
265             fprintf( newconf, " -net %d", ntohs( iface->i_rt->rt_firstnet ));
266             if ( iface->i_rt->rt_lastnet != iface->i_rt->rt_firstnet ) {
267                 fprintf( newconf, "-%d", ntohs( iface->i_rt->rt_lastnet ));
268             }
269             fprintf( newconf, " -addr %u.%u",
270                     ntohs( iface->i_addr.sat_addr.s_net ),
271                     iface->i_addr.sat_addr.s_node );
272             for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
273                 /* codepage conversion */
274                 if ((size_t)(-1) == (len = convert_string_allocate(CH_MAC, CH_UNIX, 
275                                       ((struct ziptab *)l->l_data)->zt_name,
276                                       ((struct ziptab *)l->l_data)->zt_len,
277                                       &zonename)) ) {
278                     if ( NULL == 
279                       (zonename = strdup(((struct ziptab *)l->l_data)->zt_name))) {
280                         LOG(log_error, logtype_atalkd, "malloc: %s",  strerror(errno) );
281                         return( -1 );
282                     }
283                     len = ((struct ziptab *)l->l_data)->zt_len;
284                 } 
285                 fprintf( newconf, " -zone \"%.*s\"", (int)len, zonename);
286                 free(zonename);
287             }
288             fprintf( newconf, "\n" );
289
290             iface = iface->i_next;
291             if ( conf == NULL && iface == NULL ) {
292                 break;
293             }
294         }
295     }
296     if ( conf != NULL ) {
297         fclose( conf );
298     }
299     fclose( newconf );
300
301     if ( rename( newpath, path ) < 0 ) {
302         LOG(log_error, logtype_atalkd, "rename %s to %s: %s", newpath, path, strerror(errno) );
303         return( -1 );
304     }
305     return( 0 );
306 }
307
308 /*
309  * Read our config file. If it's not there, return -1. If it is there,
310  * but has syntax errors, exit. Format of the file is as follows:
311  *
312  *      interface [ -seed ] [ -phase number ] [ -net net-range ]
313  *      [ -addr net.node ] [ -zone zonename ]...
314  * e.g.
315  *      le0 -phase 1 -net 7938 -zone Argus
316  * or
317  *      le0 -phase 2 -net 8043-8044 -zone Argus -zone "Research Systems"
318  *      le0 -phase 1 -net 7938 -zone Argus
319  *
320  * Pretty much everything is optional. Anything that is unspecified is
321  * searched for on the network.  If -seed is not specified, the
322  * configuration is assumed to be soft, i.e. it can be overridden by
323  * another router. If -seed is specified, atalkd will exit if another
324  * router disagrees.  If the phase is unspecified, it defaults to phase
325  * 2 (the default can be overridden on the command line).  -addr can
326  * replace -net, if the network in question isn't a range.  The default
327  * zone for an interface is the first zone encountered for that
328  * interface.
329  */
330 int readconf(char *cf)
331 {
332     struct ifreq        ifr;
333     struct interface    *iface, *niface;
334     char                line[ MAXLINELEN ], **argv, *p;
335     unsigned int        i, j;
336     int                 s, cc = 0;
337     FILE                *conf;
338
339     if ( cf == NULL ) {
340         p = _PATH_ATALKDCONF;
341     } else {
342         p = cf;
343     }
344     if (( conf = fopen( p, "r" )) == NULL ) {
345         return( -1 );
346     }
347
348 #ifndef __svr4__
349     if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
350         perror( "socket" );
351         fclose(conf);
352         return -1;
353     }
354 #endif /* __svr4__ */
355
356     while ( fgets( line, sizeof( line ), conf ) != NULL ) {
357         if (( argv = parseline( line )) == NULL ) {
358             continue;
359         }
360
361 #ifndef __svr4__
362         /*
363          * Check that av[ 0 ] is a valid interface.
364          * Not possible under sysV.
365          */
366         strlcpy( ifr.ifr_name, argv[ 0 ], sizeof(ifr.ifr_name) );
367
368         /* for devices that don't support appletalk */
369         if ((ioctl(s, SIOCGIFADDR, &ifr) < 0) && (errno == ENODEV)) {
370           perror(argv[0]);
371           goto read_conf_err;
372         }
373
374         if ( ioctl( s, SIOCGIFFLAGS, &ifr ) < 0 ) {
375             perror( argv[ 0 ] );
376             goto read_conf_err;
377         }
378
379         if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT |IFF_SLAVE)) {
380             fprintf( stderr, "%s: can't configure.\n", ifr.ifr_name );
381             goto read_conf_err;
382         }
383
384 #ifdef IFF_MULTICAST
385         if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
386             fprintf(stderr, "%s: multicast may not work properly.\n",
387                     ifr.ifr_name);
388 #endif /* IFF_MULTICAST */
389
390         /* configure hw multicast for this interface. */
391         if (addmulti(ifr.ifr_name, NULL) < 0) {
392           perror(ifr.ifr_name);
393           fprintf(stderr, "Can't configure multicast.\n");
394           goto read_conf_err;
395         }
396
397 #endif /* __svr4__ */
398
399         if (( niface = newiface( argv[ 0 ] )) == NULL ) {
400             perror( "newiface" );
401             goto read_conf_err;
402         }
403
404         for ( i = 1; argv[ i ]; i += cc ) {
405             if ( argv[ i ][ 0 ] == '-' ) {
406                 argv[ i ]++;
407             }
408             for ( j = 0; j < sizeof( params ) / sizeof( params[ 0 ] ); j++ ) {
409                 if ( strcmp( argv[ i ], params[ j ].p_name ) == 0 ) {
410                     if ( params[ j ].p_func != NULL ) {
411                         cc = (*params[ j ].p_func)( niface, &argv[ i + 1 ] );
412                         if (cc < 0) 
413                           goto read_conf_err;
414                         break;
415                     }
416                 }
417             }
418             if ( j >= sizeof( params ) / sizeof( params[ 0 ] )) {
419                 fprintf( stderr, "%s: attribute not found.\n", argv[ i ] );
420                 goto read_conf_err;
421             }
422         }
423
424         for ( iface = interfaces; iface; iface = iface->i_next ) {
425             if ( strcmp( niface->i_name, iface->i_name ) == 0 &&
426                     ((( niface->i_flags & iface->i_flags &
427                     ( IFACE_PHASE1|IFACE_PHASE2 )) != 0 ) ||
428                     niface->i_flags == 0 || iface->i_flags == 0 )) {
429                 break;
430             }
431         }
432         if ( iface ) {  /* Already have this interface and phase */
433             fprintf( stderr, "%s already configured!\n", niface->i_name );
434             goto read_conf_err;
435         }
436
437 #ifdef  linux
438         /* Don't set interface to allmulti if it already is, or -noallmulti was given */
439         if ((ifr.ifr_flags & IFF_ALLMULTI))
440                 niface->i_flags |= IFACE_WASALLMULTI; 
441
442         if ((niface->i_flags & IFACE_ALLMULTI) && !(niface->i_flags & IFACE_WASALLMULTI))
443                 ifsetallmulti(ifr.ifr_name, 1);
444 #endif
445
446         if ( interfaces == NULL ) {
447             interfaces = niface;
448         } else {
449             for ( iface = interfaces; iface->i_next; iface = iface->i_next )
450                 ;
451             iface->i_next = niface;
452         }
453         niface->i_next = NULL;
454     }
455
456 #ifndef __svr4__
457     close( s );
458 #endif /* __svr4__ */
459
460     fclose( conf );
461
462     /*
463      * Note: we've added lo0 to the interface list previously, so we must
464      * have configured more than one interface...
465      */
466     for ( iface = interfaces, cc = 0; iface; iface = iface->i_next, cc++ )
467         ;
468     if ( cc >= IFBASE ) {
469         return( 0 );
470     } else {
471         return( -1 );
472     }
473
474 read_conf_err:
475 #ifndef __svr4__
476     close(s);
477 #endif /* __svr4__ */
478     fclose(conf);
479     return -1;
480 }
481
482 int noallmulti( struct interface *iface, char **av _U_)
483 {
484     /* Linux specific, no effect on other platforms */
485     iface->i_flags &= !IFACE_ALLMULTI;
486
487     return (1);
488 }
489         
490 /*ARGSUSED*/
491 int router(struct interface *iface, char **av _U_)
492 {
493     /* make sure "-router" and "-dontroute" aren't both on the same line. */
494     if (iface->i_flags & IFACE_DONTROUTE) {
495         fprintf( stderr, "Can't specify both -router and -dontroute.\n");
496         return -1;
497     }
498
499     /*
500      * Check to be sure "-router" is before "-zone".
501      */
502     if ( iface->i_czt ) {
503         fprintf( stderr, "Must specify -router before -zone.\n");
504         return -1;
505     }
506
507     /* -router also implies -seed */
508     iface->i_flags |= IFACE_RSEED | IFACE_SEED | IFACE_ISROUTER;
509     return( 1 );
510 }
511
512 /*ARGSUSED*/
513 int dontroute(struct interface *iface, char **av _U_)
514 {
515     /* make sure "-router" and "-dontroute" aren't both on the same line. */
516     if (iface->i_flags & IFACE_RSEED) {
517         fprintf( stderr, "Can't specify both -router and -dontroute.\n");
518         return -1;
519     }
520
521     iface->i_flags |= IFACE_DONTROUTE;
522     return( 1 );
523 }
524
525 /*ARGSUSED*/
526 int seed( struct interface *iface, char **av _U_)
527 {
528     /*
529      * Check to be sure "-seed" is before "-zone". we keep the old
530      * semantics of just ignoring this in a routerless world.
531      */
532     if ( iface->i_czt ) {
533         fprintf( stderr, "Must specify -seed before -zone(%s).\n",
534                  iface->i_czt->zt_name);
535         return -1;
536     }
537
538     iface->i_flags |= IFACE_SEED;
539     return( 1 );
540 }
541
542 int phase(struct interface *iface, char **av)
543 {
544     int                 n;
545     char                *pnum;
546
547     if (( pnum = av[ 0 ] ) == NULL ) {
548         fprintf( stderr, "No phase.\n" );
549         return -1;
550     }
551
552     switch ( n = atoi( pnum )) {
553     case 1 :
554         iface->i_flags |= IFACE_PHASE1;
555         break;
556
557     case 2 :
558         iface->i_flags |= IFACE_PHASE2;
559         break;
560
561     default :
562         fprintf( stderr, "No phase %d.\n", n );
563         return -1;
564     }
565     return( 2 );
566 }
567
568 int net(struct interface *iface, char **av)
569 {
570     char                *nrange;
571     char                *stop;
572     int                 net;
573
574     if (( nrange = av[ 0 ] ) == NULL ) {
575         fprintf( stderr, "No network.\n" );
576         return -1;
577     }
578
579     if (( stop = strchr( nrange, '-' )) != NULL ) {
580         stop++;
581     }
582     net = atoi( nrange );
583     if ( net < 0 || net >= 0xffff ) {
584         fprintf( stderr, "Bad network: %d\n", net );
585         return -1;
586     }
587
588     if ( iface->i_rt == NULL && ( iface->i_rt = newrt(iface)) == NULL ) {
589         perror( "newrt" );
590         return -1;
591     }
592
593     if ( iface->i_flags & IFACE_PHASE1 ) {
594         if ( stop != NULL ) {
595             fprintf( stderr, "Phase 1 doesn't use an address range.\n" );
596             return -1;
597         }
598         if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
599                 ntohs( iface->i_caddr.sat_addr.s_net ) != net ) {
600             fprintf( stderr, "Net-range (%u) doesn't match net %u.\n",
601                     net, ntohs( iface->i_caddr.sat_addr.s_net ));
602             return -1;
603         }
604         iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet = htons( net );
605     } else if ( iface->i_flags & IFACE_PHASE2 ) {
606         iface->i_rt->rt_firstnet = htons( net );
607         if ( stop != NULL ) {
608             net = atoi( stop );
609             if ( net < 0 || net >= 0xffff ) {
610                 fprintf( stderr, "Bad network: %d\n", net );
611                 return -1;
612             }
613         }
614         iface->i_rt->rt_lastnet = htons( net );
615         if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
616                 ( ntohs( iface->i_rt->rt_firstnet ) >
617                 ntohs( iface->i_caddr.sat_addr.s_net ) ||
618                 ntohs( iface->i_rt->rt_lastnet ) <
619                 ntohs( iface->i_caddr.sat_addr.s_net ))) {
620             fprintf( stderr, "Net-range (%u-%u) doesn't contain net (%u).\n",
621                     ntohs( iface->i_rt->rt_firstnet ),
622                     ntohs( iface->i_rt->rt_lastnet ),
623                     ntohs( iface->i_caddr.sat_addr.s_net ));
624             return -1;
625         }
626         if ( iface->i_rt->rt_firstnet != iface->i_rt->rt_lastnet ) {
627             iface->i_rt->rt_flags |= RTMPTAB_EXTENDED;
628         }
629     } else {
630         fprintf( stderr, "Must specify phase before networks.\n" );
631         return -1;
632     }
633     return( 2 );
634 }
635
636 int addr(struct interface *iface, char **av)
637 {
638     if ( av[ 0 ] == NULL ) {
639         fprintf( stderr, "No address.\n" );
640         return -1;
641     }
642     if ( atalk_aton( av[ 0 ], &iface->i_caddr.sat_addr ) == 0 ) {
643         fprintf( stderr, "Bad address, %s\n", av[ 0 ] );
644         return -1;
645     }
646
647     if ( iface->i_rt ) {
648         if ( ntohs( iface->i_rt->rt_firstnet ) >
649                 ntohs( iface->i_caddr.sat_addr.s_net ) ||
650                 ntohs( iface->i_rt->rt_lastnet ) <
651                 ntohs( iface->i_caddr.sat_addr.s_net )) {
652             fprintf( stderr, "Net (%u) not in net-range (%u-%u).\n",
653                     ntohs( iface->i_caddr.sat_addr.s_net ),
654                     ntohs( iface->i_rt->rt_firstnet ),
655                     ntohs( iface->i_rt->rt_lastnet ));
656             return -1;
657         }
658     } else {
659         if (( iface->i_rt = newrt(iface)) == NULL ) {
660             perror( "newrt" );
661             return -1;
662         }
663         iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet =
664                 iface->i_caddr.sat_addr.s_net;
665     }
666
667     return( 2 );
668 }
669
670 int zone(struct interface *iface, char **av)
671 {
672     struct ziptab       *zt;
673     char                *zname;
674
675     if ( av[ 0 ]  == NULL ) {
676         fprintf( stderr, "No zone.\n" );
677         return -1;
678     }
679
680     /* codepage conversion */
681     if ((size_t)(-1) == convert_string_allocate(CH_UNIX, CH_MAC, av[0], -1, &zname)) {
682         zname = strdup(av[0]);
683     }
684
685     /*
686      * Only process "-zone" if this interface has "-seed".  We keep our
687      * list of configured zones in the interface structure.  Then we can
688      * check that the network has given us good zones.
689      */
690     if ( iface->i_flags & IFACE_SEED ) {
691         if ( iface->i_rt == NULL ) {
692             fprintf( stderr, "Must specify net-range before zones.\n" );
693             return -1;
694         }
695
696         if (( zt = newzt( strlen( zname ), zname )) == NULL ) {
697             perror( "newzt" );
698             return -1;
699         }
700         if ( iface->i_czt == NULL ) {
701             iface->i_czt = zt;
702         } else {
703             zt->zt_next = iface->i_czt->zt_next;
704             iface->i_czt->zt_next = zt;
705         }
706     }
707     free(zname);
708
709     return( 2 );
710 }
711
712 /*
713  * Get the configuration from the kernel. Only called if there's no
714  * configuration.
715  */
716 int getifconf(void)
717 {
718     struct interface    *iface, *niface;
719     struct ifreq        ifr;
720     char                **start, **list;
721     int                 s;
722
723     if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
724         perror( "socket" );
725         return -1;
726     }
727
728     start = list = getifacelist();
729     while (list && *list) {
730         strlcpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
731         list++;
732
733         if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
734           continue;
735
736         if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_SLAVE))
737           continue;
738
739         if ((ifr.ifr_flags & IFF_UP) == 0)
740           continue;
741
742         /* for devices that don't support appletalk */
743         if (ioctl(s, SIOCGIFADDR, &ifr) < 0 && (errno == ENODEV))
744           continue;
745
746         for ( iface = interfaces; iface; iface = iface->i_next ) {
747             if ( strcmp( iface->i_name, ifr.ifr_name ) == 0 ) {
748                 break;
749             }
750         }
751         if ( iface ) {  /* Already have this interface name */
752             continue;
753         }
754
755
756 #ifdef IFF_MULTICAST
757         if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
758           fprintf(stderr, "%s: multicast may not work correctly.\n",
759                   ifr.ifr_name);
760 #endif /* IFF_MULTICAST */
761
762         if (addmulti(ifr.ifr_name, NULL) < 0) {
763           fprintf(stderr, "%s: disabled.\n", ifr.ifr_name);
764           continue;
765         }
766         
767         if (( niface = newiface( ifr.ifr_name )) == NULL ) {
768             perror( "newiface" );
769             close(s);
770             freeifacelist(start);
771             return -1;
772         }
773         /*
774          * Could try to get the address from the kernel...
775          */
776
777         if ( interfaces == NULL ) {
778             interfaces = niface;
779         } else {
780             for ( iface = interfaces; iface->i_next; iface = iface->i_next )
781                 ;
782             iface->i_next = niface;
783         }
784         niface->i_next = NULL;
785     }
786     freeifacelist(start);
787     (void)close( s );
788     return( 0 );
789 }
790
791 /*
792  * Allocate a new interface structure.  Centralized here so we can change
793  * the interface structure and have it updated nicely.
794  */
795
796 struct interface *newiface( const char *name)
797 {
798     struct interface    *niface;
799
800     if (( niface = (struct interface *)calloc(1, sizeof( struct interface )))
801             == NULL ) {
802         return( NULL );
803     }
804     strlcpy( niface->i_name, name, sizeof(niface->i_name));
805 #ifdef BSD4_4
806     niface->i_addr.sat_len = sizeof( struct sockaddr_at );
807 #endif /* BSD4_4 */
808     niface->i_addr.sat_family = AF_APPLETALK;
809 #ifdef BSD4_4
810     niface->i_caddr.sat_len = sizeof( struct sockaddr_at );
811 #endif /* BSD4_4 */
812     niface->i_caddr.sat_family = AF_APPLETALK;
813 #ifdef linux
814     niface->i_flags = IFACE_ALLMULTI;
815 #endif
816     return( niface );
817 }
818
819 #ifdef __svr4__
820 int plumb(void)
821 {
822     struct interface    *iface;
823     char                device[ MAXPATHLEN + 1], *p, *t;
824     int                 fd, ppa;
825     int                 digits = 0;
826
827     for ( iface = interfaces; iface != NULL; iface = iface->i_next ) {
828         if ( strcmp( iface->i_name, LOOPIFACE ) == 0 ) {
829             continue;
830         }
831
832         strcpy( device, "/dev/" );
833         strcat( device, iface->i_name );
834         for (t = device; *t != '\0' ; ++t) {
835             if (isdigit(*t) == 0) {
836                 p = t + 1;
837             }
838             else {
839                 digits++;
840             }
841         }
842
843         if (digits == 0) {
844             LOG(log_error, logtype_atalkd, "plumb: invalid device: %s", device );
845             return -1;
846         }
847         ppa = atoi( p );
848         *p = '\0';
849
850         if (( fd = open( device, O_RDWR, 0 )) < 0 ) {
851             LOG(log_error, logtype_atalkd, "%s: %s", device, strerror(errno) );
852             return -1;
853         }
854         if ( ioctl( fd, I_PUSH, "ddp" ) < 0 ) {
855             LOG(log_error, logtype_atalkd, "I_PUSH: %s", strerror(errno) );
856             close(fd);
857             return -1;
858         }
859         if ( ioctl( fd, IF_UNITSEL, ppa ) < 0 ) {
860             LOG(log_error, logtype_atalkd, "IF_UNITSEL: %s", strerror(errno) );
861             close(fd);
862             return -1;
863         }
864
865         /* configure multicast. */
866         if (addmulti(iface->i_name, NULL) < 0) {
867           perror(iface->i_name);
868           fprintf(stderr,"Can't configure multicast.\n");
869           close(fd);
870           return -1;
871         }
872
873         LOG(log_info, logtype_atalkd, "plumbed %s%d", device, ppa );
874
875     close(fd);
876     }
877
878     return( 0 );
879 }
880 #endif /* __svr4__ */