Update from NeXT-ppp-2.2-0.4.6
[ppp.git] / pppd / sys-NeXT.c
1 /*
2  * sys-next.c - System-dependent procedures for setting up
3  * PPP interfaces on NeXT 3.2/3.3  systems
4  *
5  * Copyright (c) 1989 Carnegie Mellon University.
6  * Copyright (c) 1994 Philippe-Andre Prindeville.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms are permitted
10  * provided that the above copyright notice and this paragraph are
11  * duplicated in all such forms and that any documentation,
12  * advertising materials, and other materials related to such
13  * distribution and use acknowledge that the software was developed
14  * by Carnegie Mellon University.  The name of the
15  * University may not be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
19  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21
22 #ifndef lint
23 static char rcsid[] = "$Id: sys-NeXT.c,v 1.3 1995/12/18 03:30:47 paulus Exp $";
24 #endif
25
26 #include <stdio.h>
27 #include <syslog.h>
28 #include <termios.h>
29 #include <utmp.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <strings.h>
33 #include <sys/types.h>
34 #include <sys/file.h>
35 #include <sys/socket.h>
36 #include <sys/ioctl.h>
37 #include <sys/time.h>
38 #include <sys/errno.h>
39 #include <sys/stat.h>
40 #include <sys/fcntl.h>
41
42 #include <net/if.h>
43 #include <net/ppp_defs.h>
44 #include <net/if_ppp.h>
45 #include <netdb.h>
46 #include <netinet/in.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/in_var.h>
49 #include <netinet/ip.h>
50 #include <netinet/if_ether.h>
51 #include <net/route.h>
52 #include <netinet/in.h>
53
54 #include <netinfo/ni.h>
55
56 #include "pppd.h"
57
58 static int initdisc = -1;       /* Initial TTY discipline */
59 static int initfdflags = -1;    /* Initial file descriptor flags for fd */
60
61 extern int errno;
62
63 static int      restore_term;   /* 1 => we've munged the terminal */
64 static struct termios inittermios; /* Initial TTY termios */
65
66 static char *lock_file;
67
68 static int sockfd;              /* socket for doing interface ioctls */
69
70 #if defined(i386) && defined(HAS_BROKEN_IOCTL)
71 #define ioctl   myioctl
72 #endif
73
74 static int if_is_up;            /* the interface is currently up */
75 static u_int32_t default_route_gateway; /* gateway addr for default route */
76 static u_int32_t proxy_arp_addr;        /* remote addr for proxy arp */
77
78 /* Prototypes for procedures local to this file. */
79 static int translate_speed __P((int));
80 static int baud_rate_of __P((int));
81 static int dodefaultroute __P((u_int32_t, int));
82 static int get_ether_addr __P((u_int32_t, struct sockaddr *));
83 static int ether_by_host __P((char *, struct ether_addr *));
84
85
86 /*
87  * sys_init - System-dependent initialization.
88  */
89 void
90 sys_init()
91 {
92     openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
93     setlogmask(LOG_UPTO(LOG_INFO));
94     if (debug)
95         setlogmask(LOG_UPTO(LOG_DEBUG));
96
97     /* Get an internet socket for doing socket ioctl's on. */
98     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
99         syslog(LOG_ERR, "Couldn't create IP socket: %m");
100         die(1);
101     }
102 }
103
104 /*
105  * sys_cleanup - restore any system state we modified before exiting:
106  * mark the interface down, delete default route and/or proxy arp entry.
107  * This should call die() because it's called from die().
108  */
109 void
110 sys_cleanup()
111 {
112     struct ifreq ifr;
113
114     if (if_is_up) {
115         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
116         if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) >= 0
117             && ((ifr.ifr_flags & IFF_UP) != 0)) {
118             ifr.ifr_flags &= ~IFF_UP;
119             ioctl(sockfd, SIOCSIFFLAGS, &ifr);
120         }
121     }
122
123     if (default_route_gateway)
124         cifdefaultroute(0, default_route_gateway);
125     if (proxy_arp_addr)
126         cifproxyarp(0, proxy_arp_addr);
127 }
128
129 /*
130  * note_debug_level - note a change in the debug level.
131  */
132 void
133 note_debug_level()
134 {
135     if (debug) {
136         syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
137         setlogmask(LOG_UPTO(LOG_DEBUG));
138     } else {
139         setlogmask(LOG_UPTO(LOG_WARNING));
140     }
141 }
142
143 /*
144  * ppp_available - check whether the system has any ppp interfaces
145  * (in fact we check whether we can do an ioctl on ppp0).
146  */
147 int
148 ppp_available()
149 {
150     int s, ok;
151     struct ifreq ifr;
152
153     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
154         return 1;               /* can't tell - maybe we're not root */
155
156     strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
157     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
158     close(s);
159
160     return ok;
161 }
162
163 /*
164  * establish_ppp - Turn the serial port into a ppp interface.
165  */
166 void
167 establish_ppp()
168 {
169     int pppdisc = PPPDISC;
170     int x;
171
172     if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
173         syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
174         die(1);
175     }
176     if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
177         syslog(LOG_ERR, "ioctl(establish TIOCSETD): %m");
178         die(1);
179     }
180
181     /*
182      * Find out which interface we were given.
183      */
184     if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {  
185         syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
186         die(1);
187     }
188
189     /*
190      * Enable debug in the driver if requested.
191      */
192     if (kdebugflag) {
193         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
194             syslog(LOG_WARNING, "ioctl(PPPIOCGFLAGS): %m");
195         } else {
196             x |= (kdebugflag & 0xFF) * SC_DEBUG;
197             if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
198                 syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
199         }
200     }
201
202     /*
203      * Set device for non-blocking reads.
204      */
205     if ((initfdflags = fcntl(fd, F_GETFL)) == -1
206         || fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
207         syslog(LOG_WARNING, "Couldn't set device to non-blocking mode: %m");
208     }
209 }
210
211
212 /*
213  * disestablish_ppp - Restore the serial port to normal operation.
214  * This shouldn't call die() because it's called from die().
215  */
216 void
217 disestablish_ppp()
218 {
219     int x;
220     char *s;
221
222     /* Reset non-blocking mode on the file descriptor. */
223     if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)
224         syslog(LOG_WARNING, "Couldn't restore device fd flags: %m");
225     initfdflags = -1;
226
227     if (initdisc >= 0) {
228         /*
229          * Check whether the link seems not to be 8-bit clean.
230          */
231         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
232             s = NULL;
233             switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
234             case SC_RCV_B7_0:
235                 s = "bit 7 set to 1";
236                 break;
237             case SC_RCV_B7_1:
238                 s = "bit 7 set to 0";
239                 break;
240             case SC_RCV_EVNP:
241                 s = "odd parity";
242                 break;
243             case SC_RCV_ODDP:
244                 s = "even parity";
245                 break;
246             }
247             if (s != NULL) {
248                 syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
249                 syslog(LOG_WARNING, "All received characters had %s", s);
250             }
251         }
252         if (ioctl(fd, TIOCSETD, &initdisc) < 0)
253             syslog(LOG_ERR, "ioctl(disestablish TIOCSETD): %m");
254     }
255 }
256
257 /*
258  * List of valid speeds.
259  */
260 struct speed {
261     int speed_int, speed_val;
262 } speeds[] = {
263 #ifdef B50
264     { 50, B50 },
265 #endif
266 #ifdef B75
267     { 75, B75 },
268 #endif
269 #ifdef B110
270     { 110, B110 },
271 #endif
272 #ifdef B134
273     { 134, B134 },
274 #endif
275 #ifdef B150
276     { 150, B150 },
277 #endif
278 #ifdef B200
279     { 200, B200 },
280 #endif
281 #ifdef B300
282     { 300, B300 },
283 #endif
284 #ifdef B600
285     { 600, B600 },
286 #endif
287 #ifdef B1200
288     { 1200, B1200 },
289 #endif
290 #ifdef B1800
291     { 1800, B1800 },
292 #endif
293 #ifdef B2000
294     { 2000, B2000 },
295 #endif
296 #ifdef B2400
297     { 2400, B2400 },
298 #endif
299 #ifdef B3600
300     { 3600, B3600 },
301 #endif
302 #ifdef B4800
303     { 4800, B4800 },
304 #endif
305 #ifdef B7200
306     { 7200, B7200 },
307 #endif
308 #ifdef B9600
309     { 9600, B9600 },
310 #endif
311 #ifdef B19200
312     { 19200, B19200 },
313 #endif
314 #ifdef B38400
315     { 38400, B38400 },
316 #endif
317 #ifdef EXTA
318     { 19200, EXTA },
319 #endif
320 #ifdef EXTB
321     { 38400, EXTB },
322 #endif
323 #ifdef B14400
324     { 14400, B14400 },
325 #endif
326 #ifdef B28800
327     { 28800, B28800 },
328 #endif
329 #ifdef B43200
330     { 43200, B43200 },
331 #endif
332 #ifdef B57600
333     { 57600, B57600 },
334 #endif
335 /*
336 #ifndef B115200
337 #warning Defining B115200
338 #define B115200 20
339 #endif
340 */
341 #ifdef B115200
342     { 115200, B115200 },
343 #endif
344     { 0, 0 }
345 };
346
347 /*
348  * Translate from bits/second to a speed_t.
349  */
350 int
351 translate_speed(bps)
352     int bps;
353 {
354     struct speed *speedp;
355
356     if (bps == 0)
357         return 0;
358     for (speedp = speeds; speedp->speed_int; speedp++)
359         if (bps == speedp->speed_int)
360             return speedp->speed_val;
361     syslog(LOG_WARNING, "speed %d not supported", bps);
362     return 0;
363 }
364
365 /*
366  * Translate from a speed_t to bits/second.
367  */
368 static int
369 baud_rate_of(speed)
370     int speed;
371 {
372     struct speed *speedp;
373
374     if (speed == 0)
375         return 0;
376     for (speedp = speeds; speedp->speed_int; speedp++)
377         if (speed == speedp->speed_val)
378             return speedp->speed_int;
379     return 0;
380 }
381
382
383 /*
384  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
385  * at the requested speed, etc.  If `local' is true, set CLOCAL
386  * regardless of whether the modem option was specified.
387  */
388 void
389 set_up_tty(fd, local)
390     int fd, local;
391 {
392     int speed, x, modembits;
393     struct termios tios;
394
395     if (tcgetattr(fd, &tios) < 0) {
396         syslog(LOG_ERR, "tcgetattr: %m");
397         die(1);
398     }
399
400     if (!restore_term)
401         inittermios = tios;
402
403     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
404
405     tios.c_cflag |= CS8 | CREAD | HUPCL;
406     if (local || !modem)
407         tios.c_cflag |= CLOCAL;
408
409     tios.c_iflag = IGNBRK | IGNPAR;
410     tios.c_oflag = 0;
411     tios.c_lflag = 0;
412     tios.c_cc[VMIN] = 1;
413     tios.c_cc[VTIME] = 0;
414
415     if (crtscts == -2) {
416         tios.c_iflag |= IXON | IXOFF;
417         tios.c_cc[VSTOP] = 0x13;        /* DC3 = XOFF = ^S */
418         tios.c_cc[VSTART] = 0x11;       /* DC1 = XON  = ^Q */
419     }
420
421     speed = translate_speed(inspeed);
422     if (speed) {
423         cfsetospeed(&tios, speed);
424         cfsetispeed(&tios, speed);
425     } else {
426         speed = cfgetospeed(&tios);
427     }
428
429     if (modem) {
430       modembits = TIOCM_RTS | TIOCM_CTS;
431       if (ioctl(fd, (crtscts ? TIOCMBIS : TIOCMBIC), &modembits) < 0)
432         syslog(LOG_ERR, "ioctl: TIOCMBIS/BIC: %m");
433     }
434
435     if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
436         syslog(LOG_ERR, "tcsetattr: %m");
437         die(1);
438     }
439
440    baud_rate = inspeed = baud_rate_of(speed);
441    restore_term = 1;
442 }
443
444 /*
445  * restore_tty - restore the terminal to the saved settings.
446  */
447 void
448 restore_tty()
449 {
450     if (restore_term) {
451         if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
452             if (errno != ENXIO)
453                 syslog(LOG_WARNING, "tcsetattr: %m");
454         restore_term = 0;
455     }
456 }
457
458 /*
459  * setdtr - control the DTR line on the serial port.
460  * This is called from die(), so it shouldn't call die().
461  *
462  * The write hack is to get NXFax to recognize that there is
463  * activity on the port.  Not using the write nukes
464  * NXFax's capability to determine port usage.
465  *
466  */
467 void
468 setdtr(fd, on)
469 int fd, on;
470 {
471     int modembits = TIOCM_DTR;
472
473     if (!on)
474       {
475         write(fd, " ", 1);
476         sleep(1);
477       }
478
479 /*    ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits); */
480     ioctl(fd, (on? TIOCSDTR: TIOCCDTR), 0);
481 }
482
483
484 /*
485  * output - Output PPP packet.
486  */
487 void
488 output(unit, p, len)
489     int unit;
490     u_char *p;
491     int len;
492 {
493     if (debug)
494         log_packet(p, len, "sent ");
495
496     if (write(fd, p, len) < 0) {
497         if (errno == EWOULDBLOCK || errno == ENOBUFS
498             || errno == ENXIO || errno == EIO) {
499             syslog(LOG_WARNING, "write: warning: %m");
500         } else {
501             syslog(LOG_ERR, "write: %m");
502             die(1);
503         }
504     }
505 }
506
507
508 /*
509  * wait_input - wait until there is data available on fd,
510  * for the length of time specified by *timo (indefinite
511  * if timo is NULL).
512  */
513 void
514 wait_input(timo)
515     struct timeval *timo;
516 {
517     fd_set ready;
518     int n;
519
520     FD_ZERO(&ready);
521     FD_SET(fd, &ready);
522     n = select(fd+1, &ready, NULL, &ready, timo);
523     if (n < 0 && errno != EINTR) {
524         syslog(LOG_ERR, "select: %m");
525         die(1);
526     }
527 }
528
529
530 /*
531  * read_packet - get a PPP packet from the serial device.
532  */
533 int
534 read_packet(buf)
535     u_char *buf;
536 {
537     int len;
538
539     if ((len = read(fd, buf, PPP_MTU + PPP_HDRLEN)) < 0) {
540         if (errno == EWOULDBLOCK || errno == EINTR) {
541             MAINDEBUG((LOG_DEBUG, "read(fd): %m"));
542             return -1;
543         }
544         syslog(LOG_ERR, "read(fd): %m");
545         die(1);
546     }
547     return len;
548 }
549
550
551 /*
552  * ppp_send_config - configure the transmit characteristics of
553  * the ppp interface.
554  */
555 void
556 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
557     int unit, mtu;
558     u_int32_t asyncmap;
559     int pcomp, accomp;
560 {
561     u_int x;
562     struct ifreq ifr;
563
564     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
565     ifr.ifr_mtu = mtu;
566     if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
567         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
568         quit();
569     }
570
571     if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
572         syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
573         quit();
574     }
575
576     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
577         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
578         quit();
579     }
580     x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
581     x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
582     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
583         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
584         quit();
585     }
586 }
587
588
589 /*
590  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
591  */
592 void
593 ppp_set_xaccm(unit, accm)
594     int unit;
595     ext_accm accm;
596 {
597     if (ioctl(fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
598         syslog(LOG_WARNING, "ioctl(PPPIOCSXASYNCMAP): %m");
599 }
600
601
602 /*
603  * ppp_recv_config - configure the receive-side characteristics of
604  * the ppp interface.
605  */
606 void
607 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
608     int unit, mru;
609     u_int32_t asyncmap;
610     int pcomp, accomp;
611 {
612     int x;
613
614     if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
615         syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
616         quit();
617     }
618     if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
619         syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
620         quit();
621     }
622     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
623         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
624         quit();
625     }
626     x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
627     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
628         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
629         quit();
630     }
631 }
632
633 /*
634  * ccp_test - ask kernel whether a given compression method
635  * is acceptable for use.
636  */
637 int
638 ccp_test(unit, opt_ptr, opt_len, for_transmit)
639     int unit, opt_len, for_transmit;
640     u_char *opt_ptr;
641 {
642     struct ppp_option_data data;
643
644     data.ptr = opt_ptr;
645     data.length = opt_len;
646     data.transmit = for_transmit;
647     if (ioctl(fd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0)
648         return 1;
649     return (errno == ENOBUFS)? 0: -1;
650 }
651
652 /*
653  * ccp_flags_set - inform kernel about the current state of CCP.
654  */
655 void
656 ccp_flags_set(unit, isopen, isup)
657     int unit, isopen, isup;
658 {
659     int x;
660
661     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
662         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
663         return;
664     }
665     x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
666     x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
667     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
668         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
669 }
670
671 /*
672  * ccp_fatal_error - returns 1 if decompression was disabled as a
673  * result of an error detected after decompression of a packet,
674  * 0 otherwise.  This is necessary because of patent nonsense.
675  */
676 int
677 ccp_fatal_error(unit)
678     int unit;
679 {
680     int x;
681
682     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
683         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
684         return 0;
685     }
686     return x & SC_DC_FERROR;
687 }
688
689 /*
690  * sifvjcomp - config tcp header compression
691  */
692 int
693 sifvjcomp(u, vjcomp, cidcomp, maxcid)
694     int u, vjcomp, cidcomp, maxcid;
695 {
696     u_int x;
697
698     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
699         syslog(LOG_ERR, "ioctl(PPIOCGFLAGS): %m");
700         return 0;
701     }
702     x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
703     x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
704     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
705         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
706         return 0;
707     }
708     if (ioctl(fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
709         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
710         return 0;
711     }
712     return 1;
713 }
714
715 /*
716  * sifup - Config the interface up and enable IP packets to pass.
717  */
718 #ifndef SC_ENABLE_IP
719 #define SC_ENABLE_IP    0x100   /* compat for old versions of kernel code */
720 #endif
721
722 int
723 sifup(u)
724     int u;
725 {
726     struct ifreq ifr;
727     u_int x;
728     struct npioctl npi;
729
730     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
731     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
732         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
733         return 0;
734     }
735     ifr.ifr_flags |= IFF_UP;
736     if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
737         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
738         return 0;
739     }
740     if_is_up = 1;
741     npi.protocol = PPP_IP;
742     npi.mode = NPMODE_PASS;
743     if (ioctl(fd, PPPIOCSNPMODE, &npi) < 0) {
744         if (errno != ENOTTY) {
745             syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m");
746             return 0;
747         }
748         /* for backwards compatibility */
749         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
750             syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
751             return 0;
752         }
753         x |= SC_ENABLE_IP;
754         if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
755             syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
756             return 0;
757         }
758     }
759     return 1;
760 }
761
762 /*
763  * sifdown - Config the interface down and disable IP.
764  */
765 int
766 sifdown(u)
767     int u;
768 {
769     struct ifreq ifr;
770     u_int x;
771     int rv;
772     struct npioctl npi;
773
774     rv = 1;
775     npi.protocol = PPP_IP;
776     npi.mode = NPMODE_ERROR;
777     if (ioctl(fd, PPPIOCSNPMODE, (caddr_t) &npi) < 0) {
778         if (errno != ENOTTY) {
779             syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m");
780             rv = 0;
781         } else {
782             /* backwards compatibility */
783             if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
784                 syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
785                 rv = 0;
786             } else {
787                 x &= ~SC_ENABLE_IP;
788                 if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
789                     syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
790                     rv = 0;
791                 }
792             }
793         }
794     }
795
796     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
797     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
798         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
799         rv = 0;
800     } else {
801         ifr.ifr_flags &= ~IFF_UP;
802         if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
803             syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
804             rv = 0;
805         } else
806             if_is_up = 0;
807     }
808     return rv;
809 }
810
811 /*
812  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
813  * if it exists.
814  */
815 #define SET_SA_FAMILY(addr, family)             \
816     BZERO((char *) &(addr), sizeof(addr));      \
817     addr.sa_family = (family); 
818
819 /*
820  * sifaddr - Config the interface IP addresses and netmask.
821  */
822 int
823 sifaddr(u, o, h, m)
824     int u;
825     u_int32_t o, h, m;
826 {
827     int ret;
828     struct ifreq ifr;
829
830     ret = 1;
831     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
832     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
833     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
834     if (ioctl(sockfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
835         syslog(LOG_ERR, "ioctl(SIOCAIFADDR): %m");
836         ret = 0;
837     }
838     ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
839     if (ioctl(sockfd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
840         syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
841         ret = 0;
842     }
843     if (m != 0) {
844         ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
845         syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
846         if (ioctl(sockfd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
847             syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
848             ret = 0;
849         }
850     }
851     return ret;
852 }
853
854 /*
855  * cifaddr - Clear the interface IP addresses, and delete routes
856  * through the interface if possible.
857  *
858  * N.B.: under NextStep, you can't *delete* an address on an interface,
859  * so we change it to 0.0.0.0...  A real hack.  But it simplifies
860  * reconnection on the server side.
861  */
862 int
863 cifaddr(u, o, h)
864     int u;
865     u_int32_t o, h;
866 {
867     struct rtentry rt;
868
869 #if 1
870     h = o = 0L;
871     (void) sifaddr(u, o, h, 0L);
872 #endif
873     SET_SA_FAMILY(rt.rt_dst, AF_INET);
874     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
875     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
876     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
877     rt.rt_flags = RTF_HOST;
878     if (ioctl(sockfd, SIOCDELRT, (caddr_t) &rt) < 0) {
879         syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
880         return 0;
881     }
882     return 1;
883 }
884
885 /*
886  * sifdefaultroute - assign a default route through the address given.
887  */
888 int
889 sifdefaultroute(u, g)
890     int u;
891     u_int32_t g;
892 {
893     return dodefaultroute(g, 's');
894 }
895
896 /*
897  * cifdefaultroute - delete a default route through the address given.
898  */
899 int
900 cifdefaultroute(u, g)
901     int u;
902     u_int32_t g;
903 {
904     return dodefaultroute(g, 'c');
905 }
906
907 /*
908  * dodefaultroute - talk to a routing socket to add/delete a default route.
909  */
910 int
911 dodefaultroute(g, cmd)
912     u_int32_t g;
913     int cmd;
914 {
915     struct rtentry rt;
916
917     SET_SA_FAMILY(rt.rt_dst, AF_INET);
918     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = 0L;
919     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
920     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
921     rt.rt_flags = RTF_GATEWAY;
922     if (ioctl(sockfd, (cmd == 's') ? SIOCADDRT : SIOCDELRT, &rt) < 0) {
923         syslog(LOG_ERR, "%cifdefaultroute: ioctl(%s): %m", cmd,
924                (cmd == 's') ? "SIOCADDRT" : "SIOCDELRT");
925         return 0;
926     }
927     default_route_gateway = (cmd == 's')? g: 0;
928     return 1;
929 }
930
931 /*
932  * sifproxyarp - Make a proxy ARP entry for the peer.
933  */
934 int
935 sifproxyarp(unit, hisaddr)
936     int unit;
937     u_int32_t hisaddr;
938 {
939     struct arpreq arpreq;
940
941     BZERO(&arpreq, sizeof(arpreq));
942
943     /*
944      * Get the hardware address of an interface on the same subnet
945      * as our local address.
946      */
947     if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
948         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
949         return 0;
950     }
951
952     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
953     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
954     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
955     if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) {
956         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
957         return 0;
958     }
959
960     proxy_arp_addr = hisaddr;
961     return 1;
962 }
963
964 /*
965  * cifproxyarp - Delete the proxy ARP entry for the peer.
966  */
967 int
968 cifproxyarp(unit, hisaddr)
969     int unit;
970     u_int32_t hisaddr;
971 {
972     struct arpreq arpreq;
973
974     BZERO(&arpreq, sizeof(arpreq));
975     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
976     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
977     if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
978         syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
979         return 0;
980     }
981     proxy_arp_addr = 0;
982     return 1;
983 }
984
985 /*
986  * get_ether_addr - get the hardware address of an interface on the
987  * the same subnet as ipaddr.
988  */
989 #define MAX_IFS         32
990
991 int
992 get_ether_addr(ipaddr, hwaddr)
993     u_int32_t ipaddr;
994     struct sockaddr *hwaddr;
995 {
996     struct ifreq *ifr, *ifend, *ifp;
997     u_int32_t ina, mask;
998     struct ether_addr dla;
999     struct ifreq ifreq;
1000     struct ifconf ifc;
1001     struct ifreq ifs[MAX_IFS];
1002     struct hostent *hostent;
1003
1004     ifc.ifc_len = sizeof(ifs);
1005     ifc.ifc_req = ifs;
1006     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1007         syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
1008         return 0;
1009     }
1010
1011     /*
1012      * Scan through looking for an interface with an Internet
1013      * address on the same subnet as `ipaddr'.
1014      */
1015     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1016     for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
1017                 ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) {
1018         if (ifr->ifr_addr.sa_family == AF_INET) {
1019             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1020             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1021             /*
1022              * Check that the interface is up, and not point-to-point
1023              * or loopback.
1024              */
1025             if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1026                 continue;
1027             if ((ifreq.ifr_flags &
1028                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
1029                  != (IFF_UP|IFF_BROADCAST))
1030                 continue;
1031             /*
1032              * Get its netmask and check that it's on the right subnet.
1033              */
1034             if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1035                 continue;
1036             mask = ((struct sockaddr_in*)&ifreq.ifr_addr)->sin_addr.s_addr;
1037             if ((ipaddr & mask) != (ina & mask))
1038                 continue;
1039
1040             break;
1041         }
1042     }
1043
1044     if (ifr >= ifend)
1045         return 0;
1046     syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
1047
1048     /*
1049      * Get the hostname and look for an entry using the ethers database.
1050      * Under NeXTStep this is the best we can do for now.
1051      */
1052     if ((hostent = gethostbyaddr((char*)&ina, sizeof(ina), AF_INET)) == NULL)
1053         return 0;
1054
1055     if (ether_by_host(hostent->h_name, &dla)) {
1056         syslog(LOG_INFO, "Add entry for %s in /etc/ethers", hostent->h_name);
1057         return 0;       /* it's not there */
1058     }
1059     hwaddr->sa_family = AF_UNSPEC;
1060     BCOPY(&dla, hwaddr->sa_data, sizeof(dla));
1061     return 1;
1062 }
1063
1064 static int
1065 ether_by_host(hostname, etherptr)
1066     char *hostname;
1067     struct ether_addr *etherptr;
1068 {
1069     struct ether_addr *thisptr;
1070     void *conn;
1071     ni_id root;
1072     ni_namelist val;
1073     char path[256];
1074
1075     if (!ether_hostton(hostname, etherptr))
1076         return 0;
1077     /*
1078      * We shall now try and
1079      * find the address in the
1080      * top domain of netinfo.
1081      */
1082     strcat(strcpy(path, "/machines/"), hostname);
1083
1084     if (ni_open((void *)0, "/", &conn)
1085      || ni_root(conn, &root)
1086      || ni_pathsearch(conn, &root, path)
1087      || ni_lookupprop(conn, &root, "en_address", &val))
1088         return 1;
1089
1090     /*
1091      * Now we can convert the returned string into an ethernet address.
1092      */
1093     strcpy(path, val.ni_namelist_val[0]);
1094     ni_free(conn);
1095     if ((thisptr = (struct ether_addr*)ether_aton(path)) == NULL)
1096         return 1;
1097     BCOPY(thisptr, etherptr, sizeof(struct ether_addr));
1098     return 0;
1099 }
1100
1101
1102
1103 /*
1104  * Return user specified netmask, modified by any mask we might determine
1105  * for address `addr' (in network byte order).
1106  * Here we scan through the system's list of interfaces, looking for
1107  * any non-point-to-point interfaces which might appear to be on the same
1108  * network as `addr'.  If we find any, we OR in their netmask to the
1109  * user-specified netmask.
1110  */
1111 u_int32_t
1112 GetMask(addr)
1113     u_int32_t addr;
1114 {
1115     u_int32_t mask, nmask, ina;
1116     struct ifreq *ifr, *ifend, ifreq;
1117     struct ifconf ifc;
1118     struct ifreq ifs[MAX_IFS];
1119
1120     addr = ntohl(addr);
1121     if (IN_CLASSA(addr))        /* determine network mask for address class */
1122         nmask = IN_CLASSA_NET;
1123     else if (IN_CLASSB(addr))
1124         nmask = IN_CLASSB_NET;
1125     else
1126         nmask = IN_CLASSC_NET;
1127     /* class D nets are disallowed by bad_ip_adrs */
1128     mask = netmask | htonl(nmask);
1129
1130     /*
1131      * Scan through the system's network interfaces.
1132      */
1133     ifc.ifc_len = sizeof(ifs);
1134     ifc.ifc_req = ifs;
1135     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1136         syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m");
1137         return mask;
1138     }
1139     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1140     for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
1141                 ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) {
1142         /*
1143          * Check the interface's internet address.
1144          */
1145         if (ifr->ifr_addr.sa_family != AF_INET)
1146             continue;
1147         ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1148         if ((ntohl(ina) & nmask) != (addr & nmask))
1149             continue;
1150         /*
1151          * Check that the interface is up, and not point-to-point or loopback.
1152          */
1153         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1154         if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1155             continue;
1156         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1157             != IFF_UP)
1158             continue;
1159         /*
1160          * Get its netmask and OR it into our mask.
1161          */
1162         if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1163             continue;
1164         mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
1165     }
1166
1167     return mask;
1168 }
1169
1170
1171
1172 /*
1173  * daemon - Detach us from the terminal session.
1174  */
1175 int
1176 daemon(nochdir, noclose)
1177     int nochdir, noclose;
1178 {
1179     int pid;
1180
1181     if ((pid = fork()) < 0)
1182         return -1;
1183     if (pid != 0)
1184         exit(0);                /* parent dies */
1185     (void)setsid();
1186     if (!nochdir)
1187         chdir("/");
1188     if (!noclose) {
1189         fclose(stdin);          /* don't need stdin, stdout, stderr */
1190         fclose(stdout);
1191         fclose(stderr);
1192     }
1193     return 0;
1194 }
1195
1196
1197 char *
1198 strdup(s)
1199     const char *s;
1200 {
1201     char *d = malloc(strlen(s) + 1);
1202
1203     if (d) strcpy(d, s);
1204     return d;
1205 }
1206
1207 /*
1208  * This logwtmp() implementation is subject to the following copyright:
1209  *
1210  * Copyright (c) 1988 The Regents of the University of California.
1211  * All rights reserved.
1212  *
1213  * Redistribution and use in source and binary forms are permitted
1214  * provided that the above copyright notice and this paragraph are
1215  * duplicated in all such forms and that any documentation,
1216  * advertising materials, and other materials related to such
1217  * distribution and use acknowledge that the software was developed
1218  * by the University of California, Berkeley.  The name of the
1219  * University may not be used to endorse or promote products derived
1220  * from this software without specific prior written permission.
1221  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1222  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1223  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1224  */
1225
1226 #define WTMPFILE        "/usr/adm/wtmp"
1227
1228 int
1229 logwtmp(line, name, host)
1230     char *line, *name, *host;
1231 {
1232     int fd;
1233     struct stat buf;
1234     struct utmp ut;
1235
1236     if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
1237         return;
1238     if (!fstat(fd, &buf)) {
1239         (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
1240         (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
1241         (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
1242         (void)time(&ut.ut_time);
1243         if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
1244             (void)ftruncate(fd, buf.st_size);
1245     }
1246     close(fd);
1247 }
1248
1249 /*
1250  * Routines for locking and unlocking the serial device, moved here
1251  * from chat.c.
1252  */
1253
1254 #define LOCK_PREFIX     "/usr/spool/uucp/LCK/LCK.."
1255
1256 /*
1257  * lock - create a lock file for the named device
1258  */
1259 int
1260 lock(dev)
1261     char *dev;
1262 {
1263     int fd, pid, n;
1264     char *p;
1265
1266     if ((p = strrchr(dev, '/')) != NULL)
1267         dev = p + 1;
1268     lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1);
1269     if (lock_file == NULL)
1270         novm("lock file name");
1271     strcat(strcpy(lock_file, LOCK_PREFIX), dev);
1272
1273     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
1274         if (errno == EEXIST
1275             && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
1276             /* Read the lock file to find out who has the device locked */
1277             n = read(fd, &pid, sizeof(pid));
1278             if (n <= 0) {
1279                 syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
1280                 close(fd);
1281             } else {
1282                 if (kill(pid, 0) == -1 && errno == ESRCH) {
1283                     /* pid no longer exists - remove the lock file */
1284                     if (unlink(lock_file) == 0) {
1285                         close(fd);
1286                         syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)",
1287                                dev, pid);
1288                         continue;
1289                     } else
1290                         syslog(LOG_WARNING, "Couldn't remove stale lock on %s",
1291                                dev);
1292                 } else
1293                     syslog(LOG_NOTICE, "Device %s is locked by pid %d",
1294                            dev, pid);
1295             }
1296             close(fd);
1297         } else
1298             syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
1299         free(lock_file);
1300         lock_file = NULL;
1301         return -1;
1302     }
1303
1304     pid = getpid();
1305     write(fd, &pid, sizeof pid);
1306
1307     close(fd);
1308     return 0;
1309 }
1310
1311 /*
1312  * unlock - remove our lockfile
1313  */
1314 void
1315 unlock()
1316 {
1317     if (lock_file) {
1318         unlink(lock_file);
1319         free(lock_file);
1320         lock_file = NULL;
1321     }
1322 }
1323
1324 #if defined(i386) && defined(HAS_BROKEN_IOCTL)
1325 int
1326 ioctl(fd, cmd, c)
1327     int fd, cmd;
1328     caddr_t c;
1329 {
1330 #undef  ioctl
1331     int ret;
1332
1333 #ifdef DEBUGIOCTL
1334     int serrno;
1335     u_char let, code, size;
1336
1337     size = (cmd >> 16) & IOCPARM_MASK;
1338     let = (cmd >> 8);
1339     code = cmd;
1340
1341     if (let == 't' && (75 <= code && code <= 90))
1342     syslog(LOG_INFO, "ioctl(%d, 0x%x ('%c', %d, %d), 0x%x)\n", fd, cmd,
1343            let, code, size, c);
1344 #endif
1345
1346     ret = ioctl(fd, cmd, c);
1347
1348 #ifdef DEBUGIOCTL
1349     serrno = errno;
1350     if (ret == -1)
1351         syslog(LOG_INFO, "ioctl('%c', %d, %d) errno = %d (%m)\n",
1352                 let, code, size, errno);
1353     if (let == 't' && (75 <= code && code <= 90) && (cmd & IOC_OUT)) {
1354         int i, len = ((cmd >> 16) & IOCPARM_MASK);
1355         for (i = 0; i < len / 4; ++i)
1356                 syslog(LOG_INFO, "word[%d] @ 0x%06x = 0x%x\n",
1357                        i, &((int *) c)[i],((int *)c)[i]);
1358     }
1359     errno = serrno;
1360 #endif
1361
1362     if (ret == -1 && errno == EPERM)
1363         errno = ret = 0;
1364     return ret;
1365 }
1366 #endif  /* HAS_BROKEN_IOCTL */
1367
1368
1369 #if defined(FIXSIGS) && (defined (hppa) || defined(sparc))
1370
1371 /*
1372  * These redefinitions of Posix functions are necessary
1373  * because HPPA systems have an OS bug that causes 
1374  * sigaction to core dump:
1375  *
1376  * AlainF 9-Nov-1994    HACK FOR HP-PA/NEXTSTEP
1377  *                      sigaction(3) seems broken in the HP-PA NeXTSTEP 3.2
1378  *                      Posix lib. This causes pppd to SIGBUS at the expiration
1379  *                      of the first timeout (_sigtramp seems to invoke
1380  *                      the SIGALRM handler at an unreasonably low address).
1381  *                      All calls so sigaction(3) have been changed to calls
1382  *                      to sigvec(2) and sigprocmask(SIG_BLOCK,...) to
1383  *                      sigblock(2).
1384  *                      This is kind of a hack, especially since there are
1385  *                      other routines of the Posix lib still used, but
1386  *                      it worked for me.
1387  *
1388  * Dave Hess <David-Hess@net.tamu.edu> noted that 3.3 Sparc seems to
1389  * have the same bug.  Thus this fix has been enabled for SPARC also.
1390  *
1391  *
1392  */
1393
1394 int sigemptyset(sigset_t *mask)
1395 {
1396   *mask = 0;
1397 }
1398
1399 sigaddset(sigset_t *mask, int which_sig)
1400 {
1401   *mask |= sigmask(which_sig);
1402 }
1403
1404
1405 int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
1406 {
1407    struct sigvec sv;
1408    static int in = 0;
1409
1410    sv.sv_handler = act->sa_handler;
1411    sv.sv_mask = act->sa_mask;
1412    sv.sv_flags = 0;
1413
1414    if (!in)
1415      {
1416        in = 1;
1417        syslog(LOG_WARNING, "PPPD: Inside modified HP and SPARC sigaction\n");
1418      }
1419
1420    return sigvec(sig, &sv, NULL);
1421 }
1422
1423 #endif