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