X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fsys-str.c;h=ae3c1018cc3fc94b70b5eafe117071000f7bc895;hp=0754553d6c96df77e8dc668628b6f3769755e264;hb=41bd52fb6047d183d77b914449006deb59425463;hpb=b0dd1694b5dce80f9b03adf0d418e5e73dd65f2d diff --git a/pppd/sys-str.c b/pppd/sys-str.c index 0754553..ae3c101 100644 --- a/pppd/sys-str.c +++ b/pppd/sys-str.c @@ -19,7 +19,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: sys-str.c,v 1.16 1994/10/24 04:30:35 paulus Exp $"; +static char rcsid[] = "$Id: sys-str.c,v 1.20.2.1 1995/06/01 07:01:42 paulus Exp $"; #endif /* @@ -27,6 +27,7 @@ static char rcsid[] = "$Id: sys-str.c,v 1.16 1994/10/24 04:30:35 paulus Exp $"; */ #include +#include #include #include #include @@ -42,6 +43,7 @@ static char rcsid[] = "$Id: sys-str.c,v 1.16 1994/10/24 04:30:35 paulus Exp $"; #include #include +#include #include #include #include @@ -63,9 +65,18 @@ static int str_module_count = 0; static int pushed_ppp; static int closed_stdio; +static int ppp_fd = -1; /* fd currently attached to ppp unit */ + static int restore_term; /* 1 => we've munged the terminal */ static struct termios inittermios; /* Initial TTY termios */ +static int loop_slave = -1; +static int loop_master; +static char loop_name[20]; + +int sockfd; /* socket for doing interface ioctls */ +static char *lock_file; /* lock file created for serial port */ + /* * sys_init - System-dependent initialization. */ @@ -76,6 +87,12 @@ sys_init() setlogmask(LOG_UPTO(LOG_INFO)); if (debug) setlogmask(LOG_UPTO(LOG_DEBUG)); + + /* Get an internet socket for doing socket ioctl's on. */ + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "Couldn't create IP socket: %m"); + die(1); + } } /* @@ -135,19 +152,22 @@ ppp_available() /* - * establish_ppp - Turn the serial port into a ppp interface. + * establish_ppp - Turn the serial port (or loopback) into a ppp interface. */ void establish_ppp() { - /* go through and save the name of all the modules, then pop em */ - for (;;) { - if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 || - ioctl(fd, I_POP, 0) < 0) - break; - MAINDEBUG((LOG_DEBUG, "popped stream module : %s", - str_modules[str_module_count].modname)); - str_module_count++; + if (fd != loop_slave) { + str_module_count = 0; + /* go through and save the name of all the modules, then pop em */ + for (;;) { + if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 || + ioctl(fd, I_POP, 0) < 0) + break; + MAINDEBUG((LOG_DEBUG, "popped stream module : %s", + str_modules[str_module_count].modname)); + str_module_count++; + } } /* now push the async/fcs module */ @@ -156,7 +176,7 @@ establish_ppp() die(1); } /* push the compress module */ - if (ioctl(fd, I_PUSH, "pppcomp") < 0) { + if (fd != loop_slave && ioctl(fd, I_PUSH, "pppcomp") < 0) { syslog(LOG_WARNING, "ioctl(I_PUSH, ppp_comp): %m"); } /* finally, push the ppp_if module that actually handles the */ @@ -166,6 +186,7 @@ establish_ppp() die(1); } pushed_ppp = 1; + /* read mode, message non-discard mode */ if (ioctl(fd, I_SRDOPT, RMSGN) < 0) { syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m"); @@ -185,28 +206,107 @@ establish_ppp() syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m"); } + ppp_fd = fd; + /* close stdin, stdout, stderr if they might refer to the device */ if (default_device && !closed_stdio) { int i; for (i = 0; i <= 2; ++i) - if (i != fd && i != s) + if (i != fd && i != sockfd) close(i); closed_stdio = 1; } } +/* + * transfer_ppp - make the device on fd `fd' take over the PPP interface + * unit that we are using. + */ +void +transfer_ppp(fd) + int fd; +{ + if (fd == ppp_fd) + return; /* we can't get here */ + + if (fd != loop_slave) { + /* go through and save the name of all the modules, then pop em */ + str_module_count = 0; + for (;;) { + if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 || + ioctl(fd, I_POP, 0) < 0) + break; + MAINDEBUG((LOG_DEBUG, "popped stream module : %s", + str_modules[str_module_count].modname)); + str_module_count++; + } + } + + /* now push the async/fcs module */ + if (ioctl(fd, I_PUSH, "pppasync") < 0) { + syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m"); + die(1); + } + /* push the compress module */ + if (ioctl(fd, I_PUSH, "pppcomp") < 0) { + syslog(LOG_WARNING, "ioctl(I_PUSH, ppp_comp): %m"); + } + /* finally, push the ppp_if module that actually handles the */ + /* network interface */ + if (ioctl(fd, I_PUSH, "pppif") < 0) { + syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m"); + die(1); + } + pushed_ppp = 1; + + /* read mode, message non-discard mode */ + if (ioctl(fd, I_SRDOPT, RMSGN) < 0) { + syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m"); + die(1); + } + /* + * Connect to the interface unit we want. + * (ppp_if handles this ioctl) + */ + if (ioctl(fd, SIOCSETU, &ifunit) < 0) { + syslog(LOG_ERR, "ioctl(SIOCSETU): %m"); + die(1); + } + + /* Set debug flags in driver */ + if (ioctl(fd, SIOCSIFDEBUG, &kdebugflag) < 0) { + syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m"); + } + + /* + * Pop the modules off the old ppp stream, and restore + * the modules that were there, if this is the real serial port. + */ + while (ioctl(ppp_fd, I_POP, 0) == 0) /* pop any we pushed */ + ; + if (fd == loop_slave) { + for (; str_module_count > 0; str_module_count--) { + if (ioctl(ppp_fd, I_PUSH, str_modules[str_module_count-1].modname)) { + if (errno != ENXIO) + syslog(LOG_WARNING, + "Couldn't restore STREAMS module %s: %m", + str_modules[str_module_count-1].modname); + } + } + } + ppp_fd = fd; +} + /* * disestablish_ppp - Restore the serial port to normal operation. * It attempts to reconstruct the stream with the previously popped * modules. This shouldn't call die() because it's called from die(). */ void -disestablish_ppp() +disestablish_ppp(fd) + int fd; { - int flags; - char *s; - if (hungup) { /* we can't push or pop modules after the stream has hung up */ str_module_count = 0; @@ -214,50 +314,56 @@ disestablish_ppp() return; } - if (pushed_ppp) { - /* - * Check whether the link seems not to be 8-bit clean. - */ - if (ioctl(fd, SIOCGIFDEBUG, (caddr_t) &flags) == 0) { - s = NULL; - switch (~flags & PAI_FLAGS_HIBITS) { - case PAI_FLAGS_B7_0: - s = "bit 7 set to 1"; - break; - case PAI_FLAGS_B7_1: - s = "bit 7 set to 0"; - break; - case PAI_FLAGS_PAR_EVEN: - s = "odd parity"; - break; - case PAI_FLAGS_PAR_ODD: - s = "even parity"; - break; - } - if (s != NULL) { - syslog(LOG_WARNING, "Serial link is not 8-bit clean:"); - syslog(LOG_WARNING, "All received characters had %s", s); + if (fd == ppp_fd && fd >= 0 && pushed_ppp) { + while (ioctl(fd, I_POP, 0) == 0) /* pop any we pushed */ + ; + pushed_ppp = 0; + + for (; str_module_count > 0; str_module_count--) { + if (ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) { + if (errno != ENXIO) + syslog(LOG_WARNING, + "Couldn't restore STREAMS module %s: %m", + str_modules[str_module_count-1].modname); } } + ppp_fd = -1; + pushed_ppp = 0; } +} - while (ioctl(fd, I_POP, 0) == 0) /* pop any we pushed */ - ; - pushed_ppp = 0; - - for (; str_module_count > 0; str_module_count--) { - if (ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) { - if (errno != ENXIO) - syslog(LOG_WARNING, "str_restore: couldn't push module %s: %m", - str_modules[str_module_count-1].modname); - } else { - MAINDEBUG((LOG_INFO, "str_restore: pushed module %s", - str_modules[str_module_count-1].modname)); +/* + * Check whether the link seems not to be 8-bit clean. + */ +void +clean_check() +{ + int flags; + char *s; + + if (ioctl(ppp_fd, SIOCGIFDEBUG, (caddr_t) &flags) == 0) { + s = NULL; + switch (~flags & PAI_FLAGS_HIBITS) { + case PAI_FLAGS_B7_0: + s = "bit 7 set to 1"; + break; + case PAI_FLAGS_B7_1: + s = "bit 7 set to 0"; + break; + case PAI_FLAGS_PAR_EVEN: + s = "odd parity"; + break; + case PAI_FLAGS_PAR_ODD: + s = "even parity"; + break; + } + if (s != NULL) { + syslog(LOG_WARNING, "Serial link is not 8-bit clean:"); + syslog(LOG_WARNING, "All received characters had %s", s); } } } - /* * List of valid speeds. */ @@ -441,6 +547,15 @@ void restore_tty() { if (restore_term) { + if (!default_device) { + /* + * Turn off echoing, because otherwise we can get into + * a loop with the tty and the modem echoing to each other. + * We presume we are the sole user of this tty device, so + * when we close it, it will revert to its defaults anyway. + */ + inittermios.c_lflag &= ~(ECHO | ECHONL); + } if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) if (errno != ENXIO) syslog(LOG_WARNING, "tcsetattr: %m"); @@ -461,6 +576,65 @@ int fd, on; } +/* + * open_loopback - open the device we use for getting packets + * in demand mode. Here we use a pty. + */ +int +open_loopback() +{ + int flags; + struct termios tios; + static char c1[] = "pqrstuvwxyzPQRST"; + static char c2[] = "0123456789abcdef"; + char *p1, *p2; + + p1 = c1; + p2 = c2; + strcpy(loop_name, "/dev/ptyxx"); + loop_slave = -1; + for (;;) { + loop_name[8] = *p1; + loop_name[9] = *p2; + if ((loop_master = open(loop_name, O_RDWR, 0)) >= 0) { + loop_name[5] = 't'; + chown(loop_name, geteuid(), getegid()); + chmod(loop_name, S_IRUSR|S_IWUSR); + if ((loop_slave = open(loop_name, O_RDWR, 0)) >= 0) + break; + close(loop_master); + loop_name[5] = 'p'; + } else if (errno == ENOENT) + break; + if (*++p2 == 0) { + p2 = c2; + if (*++p1 == 0) + break; + } + } + if (loop_slave < 0) { + syslog(LOG_ERR, "No free pty for loopback"); + die(1); + } + SYSDEBUG((LOG_DEBUG, "using %s for loopback", loop_name)); + if (tcgetattr(loop_slave, &tios) == 0) { + tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB); + tios.c_cflag |= CS8 | CREAD; + tios.c_iflag = IGNPAR; + tios.c_oflag = 0; + tios.c_lflag = 0; + if (tcsetattr(loop_slave, TCSAFLUSH, &tios) < 0) + syslog(LOG_WARNING, "couldn't set attributes on loopback: %m"); + } + if ((flags = fcntl(loop_slave, F_GETFL)) != -1) + if (fcntl(loop_slave, F_SETFL, flags | O_NONBLOCK) == -1) + syslog(LOG_WARNING, "couldn't set loopback to nonblock: %m"); + if ((flags = fcntl(loop_master, F_GETFL)) != -1) + if (fcntl(loop_master, F_SETFL, flags | O_NONBLOCK) == -1) + syslog(LOG_WARNING, "couldn't set loopback(m) to nonblock: %m"); + return loop_slave; +} + /* * output - Output PPP packet. */ @@ -505,6 +679,26 @@ wait_input(timo) } } +/* + * wait_loop_output - wait until there is data available on the, + * loopback, for the length of time specified by *timo (indefinite + * if timo is NULL). + */ +wait_loop_output(timo) + struct timeval *timo; +{ + fd_set ready; + int n; + + FD_ZERO(&ready); + FD_SET(loop_master, &ready); + n = select(loop_master + 1, &ready, NULL, &ready, timo); + if (n < 0 && errno != EINTR) { + syslog(LOG_ERR, "select: %m"); + die(1); + } +} + /* * read_packet - get a PPP packet from the serial device. */ @@ -544,6 +738,29 @@ read_packet(buf) } +/* + * read_loop_output - get characters from the "bottom" of the loopback. + */ +int +read_loop_output(buf, maxlen) + u_char *buf; + int maxlen; +{ + int len; + + if ((len = read(loop_master, buf, maxlen)) < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) + return 0; + syslog(LOG_ERR, "read from loopback: %m"); + die(1); + } else if (len == 0) { + syslog(LOG_ERR, "eof on loopback"); + die(1); + } + return len; +} + + /* * ppp_send_config - configure the transmit characteristics of * the ppp interface. @@ -559,26 +776,26 @@ ppp_send_config(unit, mtu, asyncmap, pcomp, accomp) strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); ifr.ifr_mtu = mtu; - if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) { + if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) { syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m"); - quit(); + die(1); } if(ioctl(fd, SIOCSIFASYNCMAP, (caddr_t) &asyncmap) < 0) { syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m"); - quit(); + die(1); } c = (pcomp? 1: 0); if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) { syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m"); - quit(); + die(1); } c = (accomp? 1: 0); if(ioctl(fd, SIOCSIFCOMPAC, &c) < 0) { syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m"); - quit(); + die(1); } } @@ -695,7 +912,7 @@ sifvjcomp(u, vjcomp, cidcomp, maxcid) } /* - * sifup - Config the interface up and enable IP packets to pass. + * sifup - Config the interface up. */ int sifup(u) @@ -705,22 +922,20 @@ sifup(u) struct npioctl npi; strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { + if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m"); return 0; } ifr.ifr_flags |= IFF_UP; - if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { + if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); return 0; } npi.protocol = PPP_IP; npi.mode = NPMODE_PASS; if (ioctl(fd, SIOCSETNPMODE, &npi) < 0) { - if (errno != ENOTTY) { - syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m"); - return 0; - } + syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m"); + return 0; } return 1; } @@ -740,19 +955,17 @@ sifdown(u) npi.protocol = PPP_IP; npi.mode = NPMODE_ERROR; if (ioctl(fd, SIOCSETNPMODE, (caddr_t) &npi) < 0) { - if (errno != ENOTTY) { - syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m"); - rv = 0; - } + syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m"); + rv = 0; } strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { + if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m"); rv = 0; } else { ifr.ifr_flags &= ~IFF_UP; - if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { + if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); rv = 0; } @@ -760,6 +973,26 @@ sifdown(u) return rv; } +/* + * sifnpmode - Set the mode for handling packets for a given NP. + */ +int +sifnpmode(u, proto, mode) + int u; + int proto; + enum NPmode mode; +{ + struct npioctl npi; + + npi.protocol = proto; + npi.mode = mode; + if (ioctl(fd, SIOCSETNPMODE, &npi) < 0) { + syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m"); + return 0; + } + return 1; +} + /* * SET_SA_FAMILY - initialize a struct sockaddr, setting the sa_family field. */ @@ -782,19 +1015,19 @@ sifaddr(u, o, h, m) strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); SET_SA_FAMILY(ifr.ifr_addr, AF_INET); ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o; - if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) < 0) { + if (ioctl(sockfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) { syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m"); ret = 0; } ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h; - if (ioctl(s, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) { + if (ioctl(sockfd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) { syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m"); ret = 0; } if (m != 0) { ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m; syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m)); - if (ioctl(s, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) { + if (ioctl(sockfd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) { syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m"); ret = 0; } @@ -818,7 +1051,7 @@ cifaddr(u, o, h) SET_SA_FAMILY(rt.rt_gateway, AF_INET); ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o; rt.rt_flags = RTF_HOST; - if (ioctl(s, SIOCDELRT, (caddr_t) &rt) < 0) { + if (ioctl(sockfd, SIOCDELRT, (caddr_t) &rt) < 0) { syslog(LOG_ERR, "ioctl(SIOCDELRT): %m"); return 0; } @@ -839,7 +1072,7 @@ sifdefaultroute(u, g) SET_SA_FAMILY(rt.rt_gateway, AF_INET); ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g; rt.rt_flags = RTF_GATEWAY; - if (ioctl(s, SIOCADDRT, &rt) < 0) { + if (ioctl(sockfd, SIOCADDRT, &rt) < 0) { syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m"); return 0; } @@ -860,7 +1093,7 @@ cifdefaultroute(u, g) SET_SA_FAMILY(rt.rt_gateway, AF_INET); ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g; rt.rt_flags = RTF_GATEWAY; - if (ioctl(s, SIOCDELRT, &rt) < 0) { + if (ioctl(sockfd, SIOCDELRT, &rt) < 0) { syslog(LOG_ERR, "default route ioctl(SIOCDELRT): %m"); return 0; } @@ -891,7 +1124,7 @@ sifproxyarp(unit, hisaddr) SET_SA_FAMILY(arpreq.arp_pa, AF_INET); ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; arpreq.arp_flags = ATF_PERM | ATF_PUBL; - if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) { + if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) { syslog(LOG_ERR, "ioctl(SIOCSARP): %m"); return 0; } @@ -912,7 +1145,7 @@ cifproxyarp(unit, hisaddr) BZERO(&arpreq, sizeof(arpreq)); SET_SA_FAMILY(arpreq.arp_pa, AF_INET); ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; - if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) { + if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) { syslog(LOG_ERR, "ioctl(SIOCDARP): %m"); return 0; } @@ -948,7 +1181,6 @@ cifproxyarp(unit, hisaddr) #include #include #include -#include /* XXX SunOS 4.1 defines this and 3.5 doesn't... */ #ifdef _nlist_h @@ -1088,3 +1320,171 @@ logwtmp(line, name, host) } close(fd); } + +/* + * Return user specified netmask, modified by any mask we might determine + * for address `addr' (in network byte order). + * Here we scan through the system's list of interfaces, looking for + * any non-point-to-point interfaces which might appear to be on the same + * network as `addr'. If we find any, we OR in their netmask to the + * user-specified netmask. + */ +#define MAX_IFS 32 + +u_int32_t +GetMask(addr) + u_int32_t addr; +{ + u_int32_t mask, nmask, ina; + struct ifreq *ifr, *ifend, ifreq; + struct ifconf ifc; + struct ifreq ifs[MAX_IFS]; + + addr = ntohl(addr); + if (IN_CLASSA(addr)) /* determine network mask for address class */ + nmask = IN_CLASSA_NET; + else if (IN_CLASSB(addr)) + nmask = IN_CLASSB_NET; + else + nmask = IN_CLASSC_NET; + /* class D nets are disallowed by bad_ip_adrs */ + mask = netmask | htonl(nmask); + + /* + * Scan through the system's network interfaces. + */ + ifc.ifc_len = sizeof(ifs); + ifc.ifc_req = ifs; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { + syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m"); + return mask; + } + ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); + for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) { + /* + * Check the interface's internet address. + */ + if (ifr->ifr_addr.sa_family != AF_INET) + continue; + ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; + if ((ntohl(ina) & nmask) != (addr & nmask)) + continue; + /* + * Check that the interface is up, and not point-to-point or loopback. + */ + strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0) + continue; + if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK)) + != IFF_UP) + continue; + /* + * Get its netmask and OR it into our mask. + */ + if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0) + continue; + mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr; + } + + return mask; +} + +/* + * Code for locking/unlocking the serial device. + * This code is derived from chat.c. + */ + +#if defined(SUNOS) && SUNOS >= 41 && !defined(HDB) +#define HDB 1 +#endif + +#ifndef LOCK_DIR +# ifdef HDB +# define PIDSTRING +# define LOCK_PREFIX "/usr/spool/locks/LCK.." +# else /* HDB */ +# define LOCK_PREFIX "/usr/spool/uucp/LCK.." +# endif /* HDB */ +#endif /* LOCK_DIR */ + +/* + * lock - create a lock file for the named device. + */ +int +lock(dev) + char *dev; +{ + char hdb_lock_buffer[12]; + int fd, pid, n; + char *p; + + if ((p = strrchr(dev, '/')) != NULL) + dev = p + 1; + lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1); + if (lock_file == NULL) + novm("lock file name"); + strcat(strcpy(lock_file, LOCK_PREFIX), dev); + + while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { + if (errno == EEXIST + && (fd = open(lock_file, O_RDONLY, 0)) >= 0) { + /* Read the lock file to find out who has the device locked */ +#ifdef PIDSTRING + n = read(fd, hdb_lock_buffer, 11); + if (n > 0) { + hdb_lock_buffer[n] = 0; + pid = atoi(hdb_lock_buffer); + } +#else + n = read(fd, &pid, sizeof(pid)); +#endif + if (n <= 0) { + syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file); + close(fd); + } else { + if (kill(pid, 0) == -1 && errno == ESRCH) { + /* pid no longer exists - remove the lock file */ + if (unlink(lock_file) == 0) { + close(fd); + syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)", + dev, pid); + continue; + } else + syslog(LOG_WARNING, "Couldn't remove stale lock on %s", + dev); + } else + syslog(LOG_NOTICE, "Device %s is locked by pid %d", + dev, pid); + } + close(fd); + } else + syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file); + free(lock_file); + lock_file = NULL; + return -1; + } + +#ifdef PIDSTRING + sprintf(hdb_lock_buffer, "%10d\n", getpid()); + write(fd, hdb_lock_buffer, 11); +#else + pid = getpid(); + write(fd, &pid, sizeof pid); +#endif + + close(fd); + return 0; +} + +/* + * unlock - remove our lockfile + */ +void +unlock() +{ + if (lock_file) { + unlink(lock_file); + free(lock_file); + lock_file = NULL; + } +}