]> git.ozlabs.org Git - ppp.git/blob - pppd/sys-sunos4.c
Clear hungup in start_link() instead of connect_tty()
[ppp.git] / pppd / sys-sunos4.c
1 /*
2  * System-dependent procedures for pppd under SunOS 4.
3  *
4  * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. The name(s) of the authors of this software must not be used to
14  *    endorse or promote products derived from this software without
15  *    prior written permission.
16  *
17  * 3. Redistributions of any form whatsoever must retain the following
18  *    acknowledgment:
19  *    "This product includes software developed by Paul Mackerras
20  *     <paulus@samba.org>".
21  *
22  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
23  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
24  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
26  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
28  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29  *
30  * Derived from main.c and pppd.h, which are:
31  *
32  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions
36  * are met:
37  *
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  *
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in
43  *    the documentation and/or other materials provided with the
44  *    distribution.
45  *
46  * 3. The name "Carnegie Mellon University" must not be used to
47  *    endorse or promote products derived from this software without
48  *    prior written permission. For permission or any legal
49  *    details, please contact
50  *      Office of Technology Transfer
51  *      Carnegie Mellon University
52  *      5000 Forbes Avenue
53  *      Pittsburgh, PA  15213-3890
54  *      (412) 268-4387, fax: (412) 268-7395
55  *      tech-transfer@andrew.cmu.edu
56  *
57  * 4. Redistributions of any form whatsoever must retain the following
58  *    acknowledgment:
59  *    "This product includes software developed by Computing Services
60  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
61  *
62  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
63  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
64  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
65  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
66  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
67  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
68  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
69  */
70
71 #define RCSID   "$Id: sys-sunos4.c,v 1.33 2004/11/04 10:02:26 paulus Exp $"
72
73 #include <stdio.h>
74 #include <stddef.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <ctype.h>
78 #include <errno.h>
79 #include <fcntl.h>
80 #include <unistd.h>
81 #include <termios.h>
82 #include <signal.h>
83 #include <malloc.h>
84 #include <utmp.h>
85 #include <sys/types.h>
86 #include <sys/param.h>
87 #include <sys/socket.h>
88 #include <sys/sockio.h>
89 #include <sys/stream.h>
90 #include <sys/stropts.h>
91 #include <sys/stat.h>
92 #include <sys/time.h>
93 #include <sys/poll.h>
94 #include <net/if.h>
95 #include <net/if_arp.h>
96 #include <net/nit_if.h>
97 #include <net/route.h>
98 #include <net/ppp_defs.h>
99 #include <net/pppio.h>
100 #include <netinet/in.h>
101
102 #include "pppd.h"
103
104 #if defined(sun) && defined(sparc)
105 #include <alloca.h>
106 #ifndef __GNUC__
107 extern void *alloca();
108 #endif
109 #endif /*sparc*/
110
111 static const char rcsid[] = RCSID;
112
113 static int      pppfd;
114 static int      fdmuxid = -1;
115 static int      iffd;
116 static int      sockfd;
117
118 static int      restore_term;
119 static struct termios inittermios;
120 static struct winsize wsinfo;   /* Initial window size info */
121 static pid_t    parent_pid;     /* PID of our parent */
122
123 extern u_char   inpacket_buf[]; /* borrowed from main.c */
124
125 #define MAX_POLLFDS     32
126 static struct pollfd pollfds[MAX_POLLFDS];
127 static int n_pollfds;
128
129 static int      link_mtu, link_mru;
130
131 #define NMODULES        32
132 static int      tty_nmodules;
133 static char     tty_modules[NMODULES][FMNAMESZ+1];
134
135 static int      if_is_up;       /* Interface has been marked up */
136 static u_int32_t ifaddrs[2];    /* local and remote addresses */
137 static u_int32_t default_route_gateway; /* Gateway for default route added */
138 static u_int32_t proxy_arp_addr;        /* Addr for proxy arp entry added */
139
140 /* Prototypes for procedures local to this file. */
141 static int translate_speed __P((int));
142 static int baud_rate_of __P((int));
143 static int get_ether_addr __P((u_int32_t, struct sockaddr *));
144 static int strioctl __P((int, int, void *, int, int));
145
146
147 /*
148  * sys_init - System-dependent initialization.
149  */
150 void
151 sys_init()
152 {
153     int x;
154
155     /* Get an internet socket for doing socket ioctl's on. */
156     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
157         fatal("Couldn't create IP socket: %m");
158
159     /*
160      * We may want to send a SIGHUP to the session leader associated
161      * with our controlling terminal later.  Because SunOS doesn't
162      * have getsid(), we make do with sending the signal to our
163      * parent process.
164      */
165     parent_pid = getppid();
166
167     /*
168      * Open the ppp device.
169      */
170     pppfd = open("/dev/ppp", O_RDWR | O_NONBLOCK, 0);
171     if (pppfd < 0)
172         fatal("Can't open /dev/ppp: %m");
173     if (kdebugflag) {
174         x = PPPDBG_LOG + PPPDBG_DRIVER;
175         strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0);
176     }
177
178     /* Assign a new PPA and get its unit number. */
179     if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0)
180         fatal("Can't create new PPP interface: %m");
181
182     /*
183      * Open the ppp device again and push the if_ppp module on it.
184      */
185     iffd = open("/dev/ppp", O_RDWR, 0);
186     if (iffd < 0)
187         fatal("Can't open /dev/ppp (2): %m");
188     if (kdebugflag) {
189         x = PPPDBG_LOG + PPPDBG_DRIVER;
190         strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0);
191     }
192     if (strioctl(iffd, PPPIO_ATTACH, &ifunit, sizeof(int), 0) < 0)
193         fatal("Couldn't attach ppp interface to device: %m");
194     if (ioctl(iffd, I_PUSH, "if_ppp") < 0)
195         fatal("Can't push ppp interface module: %m");
196     if (kdebugflag) {
197         x = PPPDBG_LOG + PPPDBG_IF;
198         strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0);
199     }
200     if (strioctl(iffd, PPPIO_NEWPPA, &ifunit, sizeof(int), 0) < 0)
201         fatal("Couldn't create ppp interface unit: %m");
202     x = PPP_IP;
203     if (strioctl(iffd, PPPIO_BIND, &x, sizeof(int), 0) < 0)
204         fatal("Couldn't bind ppp interface to IP SAP: %m");
205
206     n_pollfds = 0;
207 }
208
209 /*
210  * sys_cleanup - restore any system state we modified before exiting:
211  * mark the interface down, delete default route and/or proxy arp entry.
212  * This shouldn't call die() because it's called from die().
213  */
214 void
215 sys_cleanup()
216 {
217     if (if_is_up)
218         sifdown(0);
219     if (ifaddrs[0])
220         cifaddr(0, ifaddrs[0], ifaddrs[1]);
221     if (default_route_gateway)
222         cifdefaultroute(0, 0, default_route_gateway);
223     if (proxy_arp_addr)
224         cifproxyarp(0, proxy_arp_addr);
225 }
226
227 /*
228  * sys_close - Clean up in a child process before execing.
229  */
230 void
231 sys_close()
232 {
233     close(iffd);
234     close(pppfd);
235     close(sockfd);
236 }
237
238 /*
239  * sys_check_options - check the options that the user specified
240  */
241 int
242 sys_check_options()
243 {
244     return 1;
245 }
246
247 #if 0
248 /*
249  * daemon - Detach us from controlling terminal session.
250  */
251 int
252 daemon(nochdir, noclose)
253     int nochdir, noclose;
254 {
255     int pid;
256
257     if ((pid = fork()) < 0)
258         return -1;
259     if (pid != 0)
260         exit(0);                /* parent dies */
261     setsid();
262     if (!nochdir)
263         chdir("/");
264     if (!noclose) {
265         fclose(stdin);          /* don't need stdin, stdout, stderr */
266         fclose(stdout);
267         fclose(stderr);
268     }
269     return 0;
270 }
271 #endif
272
273 /*
274  * ppp_available - check whether the system has any ppp interfaces
275  */
276 int
277 ppp_available()
278 {
279     struct stat buf;
280
281     return stat("/dev/ppp", &buf) >= 0;
282 }
283
284 /*
285  * tty_establish_ppp - Turn the serial port into a ppp interface.
286  */
287 int
288 tty_establish_ppp(fd)
289     int fd;
290 {
291     int i;
292
293     /* Pop any existing modules off the tty stream. */
294     for (i = 0;; ++i)
295         if (ioctl(fd, I_LOOK, tty_modules[i]) < 0
296             || ioctl(fd, I_POP, 0) < 0)
297             break;
298     tty_nmodules = i;
299
300     /* Push the async hdlc module and the compressor module. */
301     if (ioctl(fd, I_PUSH, "ppp_ahdl") < 0)
302         fatal("Couldn't push PPP Async HDLC module: %m");
303     if (ioctl(fd, I_PUSH, "ppp_comp") < 0)
304         error("Couldn't push PPP compression module: %m");
305
306     /* Link the serial port under the PPP multiplexor. */
307     if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0)
308         fatal("Can't link tty to PPP mux: %m");
309
310     return pppfd;
311 }
312
313 /*
314  * disestablish_ppp - Restore the serial port to normal operation.
315  * It attempts to reconstruct the stream with the previously popped
316  * modules.  This shouldn't call die() because it's called from die().
317  */
318 void
319 tty_disestablish_ppp(fd)
320     int fd;
321 {
322     int i;
323
324     if (fdmuxid >= 0) {
325         if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) {
326             if (!hungup)
327                 error("Can't unlink tty from PPP mux: %m");
328         }
329         fdmuxid = -1;
330
331         if (!hungup) {
332             while (ioctl(fd, I_POP, 0) >= 0)
333                 ;
334             for (i = tty_nmodules - 1; i >= 0; --i)
335                 if (ioctl(fd, I_PUSH, tty_modules[i]) < 0)
336                     error("Couldn't restore tty module %s: %m",
337                            tty_modules[i]);
338         }
339         if (hungup && default_device && parent_pid > 0) {
340             /*
341              * If we have received a hangup, we need to send a SIGHUP
342              * to the terminal's controlling process.  The reason is
343              * that the original stream head for the terminal hasn't
344              * seen the M_HANGUP message (it went up through the ppp
345              * driver to the stream head for our fd to /dev/ppp).
346              * Actually we send the signal to the process that invoked
347              * pppd, since SunOS doesn't have getsid().
348              */
349             kill(parent_pid, SIGHUP);
350         }
351     }
352 }
353
354 /*
355  * Check whether the link seems not to be 8-bit clean.
356  */
357 void
358 clean_check()
359 {
360     int x;
361     char *s;
362
363     if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof(x)) < 0)
364         return;
365     s = NULL;
366     switch (~x) {
367     case RCV_B7_0:
368         s = "bit 7 set to 1";
369         break;
370     case RCV_B7_1:
371         s = "bit 7 set to 0";
372         break;
373     case RCV_EVNP:
374         s = "odd parity";
375         break;
376     case RCV_ODDP:
377         s = "even parity";
378         break;
379     }
380     if (s != NULL) {
381         warn("Serial link is not 8-bit clean:");
382         warn("All received characters had %s", s);
383     }
384 }
385
386 /*
387  * List of valid speeds.
388  */
389 struct speed {
390     int speed_int, speed_val;
391 } speeds[] = {
392 #ifdef B50
393     { 50, B50 },
394 #endif
395 #ifdef B75
396     { 75, B75 },
397 #endif
398 #ifdef B110
399     { 110, B110 },
400 #endif
401 #ifdef B134
402     { 134, B134 },
403 #endif
404 #ifdef B150
405     { 150, B150 },
406 #endif
407 #ifdef B200
408     { 200, B200 },
409 #endif
410 #ifdef B300
411     { 300, B300 },
412 #endif
413 #ifdef B600
414     { 600, B600 },
415 #endif
416 #ifdef B1200
417     { 1200, B1200 },
418 #endif
419 #ifdef B1800
420     { 1800, B1800 },
421 #endif
422 #ifdef B2000
423     { 2000, B2000 },
424 #endif
425 #ifdef B2400
426     { 2400, B2400 },
427 #endif
428 #ifdef B3600
429     { 3600, B3600 },
430 #endif
431 #ifdef B4800
432     { 4800, B4800 },
433 #endif
434 #ifdef B7200
435     { 7200, B7200 },
436 #endif
437 #ifdef B9600
438     { 9600, B9600 },
439 #endif
440 #ifdef B19200
441     { 19200, B19200 },
442 #endif
443 #ifdef B38400
444     { 38400, B38400 },
445 #endif
446 #ifdef EXTA
447     { 19200, EXTA },
448 #endif
449 #ifdef EXTB
450     { 38400, EXTB },
451 #endif
452 #ifdef B57600
453     { 57600, B57600 },
454 #endif
455 #ifdef B115200
456     { 115200, B115200 },
457 #endif
458     { 0, 0 }
459 };
460
461 /*
462  * Translate from bits/second to a speed_t.
463  */
464 static int
465 translate_speed(bps)
466     int bps;
467 {
468     struct speed *speedp;
469
470     if (bps == 0)
471         return 0;
472     for (speedp = speeds; speedp->speed_int; speedp++)
473         if (bps == speedp->speed_int)
474             return speedp->speed_val;
475     warn("speed %d not supported", bps);
476     return 0;
477 }
478
479 /*
480  * Translate from a speed_t to bits/second.
481  */
482 static int
483 baud_rate_of(speed)
484     int speed;
485 {
486     struct speed *speedp;
487
488     if (speed == 0)
489         return 0;
490     for (speedp = speeds; speedp->speed_int; speedp++)
491         if (speed == speedp->speed_val)
492             return speedp->speed_int;
493     return 0;
494 }
495
496 /*
497  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
498  * at the requested speed, etc.  If `local' is true, set CLOCAL
499  * regardless of whether the modem option was specified.
500  */
501 void
502 set_up_tty(fd, local)
503     int fd, local;
504 {
505     int speed;
506     struct termios tios;
507
508     if (tcgetattr(fd, &tios) < 0)
509         fatal("tcgetattr: %m");
510
511     if (!restore_term) {
512         inittermios = tios;
513         ioctl(fd, TIOCGWINSZ, &wsinfo);
514     }
515
516     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
517     if (crtscts > 0)
518         tios.c_cflag |= CRTSCTS;
519     else if (crtscts < 0)
520         tios.c_cflag &= ~CRTSCTS;
521
522     tios.c_cflag |= CS8 | CREAD | HUPCL;
523     if (local || !modem)
524         tios.c_cflag |= CLOCAL;
525     tios.c_iflag = IGNBRK | IGNPAR;
526     tios.c_oflag = 0;
527     tios.c_lflag = 0;
528     tios.c_cc[VMIN] = 1;
529     tios.c_cc[VTIME] = 0;
530
531     if (crtscts == -2) {
532         tios.c_iflag |= IXON | IXOFF;
533         tios.c_cc[VSTOP] = 0x13;        /* DC3 = XOFF = ^S */
534         tios.c_cc[VSTART] = 0x11;       /* DC1 = XON  = ^Q */
535     }
536
537     speed = translate_speed(inspeed);
538     if (speed) {
539         cfsetospeed(&tios, speed);
540         cfsetispeed(&tios, speed);
541     } else {
542         speed = cfgetospeed(&tios);
543         /*
544          * We can't proceed if the serial port speed is 0,
545          * since that implies that the serial port is disabled.
546          */
547         if (speed == B0)
548             fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
549     }
550
551     if (tcsetattr(fd, TCSAFLUSH, &tios) < 0)
552         fatal("tcsetattr: %m");
553
554     baud_rate = inspeed = baud_rate_of(speed);
555     restore_term = 1;
556 }
557
558 /*
559  * restore_tty - restore the terminal to the saved settings.
560  */
561 void
562 restore_tty(fd)
563     int fd;
564 {
565     if (restore_term) {
566         if (!default_device) {
567             /*
568              * Turn off echoing, because otherwise we can get into
569              * a loop with the tty and the modem echoing to each other.
570              * We presume we are the sole user of this tty device, so
571              * when we close it, it will revert to its defaults anyway.
572              */
573             inittermios.c_lflag &= ~(ECHO | ECHONL);
574         }
575         if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
576             if (!hungup && errno != ENXIO)
577                 warn("tcsetattr: %m");
578         ioctl(fd, TIOCSWINSZ, &wsinfo);
579         restore_term = 0;
580     }
581 }
582
583 /*
584  * setdtr - control the DTR line on the serial port.
585  * This is called from die(), so it shouldn't call die().
586  */
587 void
588 setdtr(fd, on)
589 int fd, on;
590 {
591     int modembits = TIOCM_DTR;
592
593     ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
594 }
595
596 /*
597  * open_loopback - open the device we use for getting packets
598  * in demand mode.  Under SunOS, we use our existing fd
599  * to the ppp driver.
600  */
601 int
602 open_ppp_loopback()
603 {
604     return pppfd;
605 }
606
607 /*
608  * output - Output PPP packet.
609  */
610 void
611 output(unit, p, len)
612     int unit;
613     u_char *p;
614     int len;
615 {
616     struct strbuf data;
617     int retries;
618     struct pollfd pfd;
619
620     dump_packet("sent", p, len);
621     if (snoop_send_hook) snoop_send_hook(p, len);
622
623     data.len = len;
624     data.buf = (caddr_t) p;
625     retries = 4;
626     while (putmsg(pppfd, NULL, &data, 0) < 0) {
627         if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) {
628             if (errno != ENXIO)
629                 error("Couldn't send packet: %m");
630             break;
631         }
632         pfd.fd = pppfd;
633         pfd.events = POLLOUT;
634         poll(&pfd, 1, 250);     /* wait for up to 0.25 seconds */
635     }
636 }
637
638
639 /*
640  * wait_input - wait until there is data available,
641  * for the length of time specified by *timo (indefinite
642  * if timo is NULL).
643  */
644 void
645 wait_input(timo)
646     struct timeval *timo;
647 {
648     int t;
649
650     t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000;
651     if (poll(pollfds, n_pollfds, t) < 0 && errno != EINTR) {
652         if (errno != EAGAIN)
653             fatal("poll: %m");
654         /* we can get EAGAIN on a heavily loaded system,
655          * just wait a short time and try again. */
656         usleep(50000);
657     }
658 }
659
660 /*
661  * add_fd - add an fd to the set that wait_input waits for.
662  */
663 void add_fd(fd)
664     int fd;
665 {
666     int n;
667
668     for (n = 0; n < n_pollfds; ++n)
669         if (pollfds[n].fd == fd)
670             return;
671     if (n_pollfds < MAX_POLLFDS) {
672         pollfds[n_pollfds].fd = fd;
673         pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP;
674         ++n_pollfds;
675     } else
676         error("Too many inputs!");
677 }
678
679 /*
680  * remove_fd - remove an fd from the set that wait_input waits for.
681  */
682 void remove_fd(fd)
683     int fd;
684 {
685     int n;
686
687     for (n = 0; n < n_pollfds; ++n) {
688         if (pollfds[n].fd == fd) {
689             while (++n < n_pollfds)
690                 pollfds[n-1] = pollfds[n];
691             --n_pollfds;
692             break;
693         }
694     }
695 }
696
697 #if 0
698 /*
699  * wait_loop_output - wait until there is data available on the
700  * loopback, for the length of time specified by *timo (indefinite
701  * if timo is NULL).
702  */
703 void
704 wait_loop_output(timo)
705     struct timeval *timo;
706 {
707     wait_input(timo);
708 }
709
710 /*
711  * wait_time - wait for a given length of time or until a
712  * signal is received.
713  */
714 void
715 wait_time(timo)
716     struct timeval *timo;
717 {
718     int n;
719
720     n = select(0, NULL, NULL, NULL, timo);
721     if (n < 0 && errno != EINTR)
722         fatal("select: %m");
723 }
724 #endif
725
726 /*
727  * read_packet - get a PPP packet from the serial device.
728  */
729 int
730 read_packet(buf)
731     u_char *buf;
732 {
733     struct strbuf ctrl, data;
734     int flags, len;
735     unsigned char ctrlbuf[64];
736
737     for (;;) {
738         data.maxlen = PPP_MRU + PPP_HDRLEN;
739         data.buf = (caddr_t) buf;
740         ctrl.maxlen = sizeof(ctrlbuf);
741         ctrl.buf = (caddr_t) ctrlbuf;
742         flags = 0;
743         len = getmsg(pppfd, &ctrl, &data, &flags);
744         if (len < 0) {
745             if (errno == EAGAIN || errno == EINTR)
746                 return -1;
747             fatal("Error reading packet: %m");
748         }
749
750         if (ctrl.len <= 0)
751             return data.len;
752
753         /*
754          * Got a M_PROTO or M_PCPROTO message.  Huh?
755          */
756         if (debug)
757             dbglog("got ctrl msg len=%d", ctrl.len);
758
759     }
760 }
761
762 /*
763  * get_loop_output - get outgoing packets from the ppp device,
764  * and detect when we want to bring the real link up.
765  * Return value is 1 if we need to bring up the link, 0 otherwise.
766  */
767 int
768 get_loop_output()
769 {
770     int len;
771     int rv = 0;
772
773     while ((len = read_packet(inpacket_buf)) > 0) {
774         if (loop_frame(inpacket_buf, len))
775             rv = 1;
776     }
777     return rv;
778 }
779
780 /*
781  * netif_set_mtu - set the MTU on the PPP network interface.
782  */
783 void
784 netif_set_mtu(unit, mtu)
785     int unit, mtu;
786 {
787     struct ifreq ifr;
788
789     memset(&ifr, 0, sizeof(ifr));
790     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
791     ifr.ifr_metric = link_mtu;
792     if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
793         error("Couldn't set IP MTU: %m");
794     }
795 }
796
797 /*
798  * tty_send_config - configure the transmit characteristics of
799  * the ppp interface.
800  */
801 int
802 tty_send_config(mtu, asyncmap, pcomp, accomp)
803     int mtu;
804     u_int32_t asyncmap;
805     int pcomp, accomp;
806 {
807     int cf[2];
808
809     link_mtu = mtu;
810     if (strioctl(pppfd, PPPIO_MTU, &mtu, sizeof(mtu), 0) < 0) {
811         if (hungup && errno == ENXIO) {
812             ++error_count;
813             return;
814         }
815         error("Couldn't set MTU: %m");
816     }
817     if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0)
818         error("Couldn't set transmit ACCM: %m");
819     cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
820     cf[1] = COMP_PROT | COMP_AC;
821     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0)
822         error("Couldn't set prot/AC compression: %m");
823 }
824
825 /*
826  * tty_set_xaccm - set the extended transmit ACCM for the interface.
827  */
828 void
829 tty_set_xaccm(unit, accm)
830     int unit;
831     ext_accm accm;
832 {
833     if (strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) {
834         if (!hungup || errno != ENXIO)
835             warn("Couldn't set extended ACCM: %m");
836     }
837 }
838
839 /*
840  * tty_recv_config - configure the receive-side characteristics of
841  * the ppp interface.
842  */
843 void
844 tty_recv_config(mru, asyncmap, pcomp, accomp)
845     int mru;
846     u_int32_t asyncmap;
847     int pcomp, accomp;
848 {
849     int cf[2];
850
851     link_mru = mru;
852     if (strioctl(pppfd, PPPIO_MRU, &mru, sizeof(mru), 0) < 0) {
853         if (hungup && errno == ENXIO) {
854             ++error_count;
855             return;
856         }
857         error("Couldn't set MRU: %m");
858     }
859     if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0)
860         error("Couldn't set receive ACCM: %m");
861     cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0);
862     cf[1] = DECOMP_PROT | DECOMP_AC;
863     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0)
864         error("Couldn't set prot/AC decompression: %m");
865 }
866
867 /*
868  * ccp_test - ask kernel whether a given compression method
869  * is acceptable for use.
870  */
871 int
872 ccp_test(unit, opt_ptr, opt_len, for_transmit)
873     int unit, opt_len, for_transmit;
874     u_char *opt_ptr;
875 {
876     if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP),
877                  opt_ptr, opt_len, 0) >= 0)
878         return 1;
879     return (errno == ENOSR)? 0: -1;
880 }
881
882 /*
883  * ccp_flags_set - inform kernel about the current state of CCP.
884  */
885 void
886 ccp_flags_set(unit, isopen, isup)
887     int unit, isopen, isup;
888 {
889     int cf[2];
890
891     cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0);
892     cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR;
893     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
894         if (!hungup || errno != ENXIO)
895             error("Couldn't set kernel CCP state: %m");
896     }
897 }
898
899 /*
900  * get_idle_time - return how long the link has been idle.
901  */
902 int
903 get_idle_time(u, ip)
904     int u;
905     struct ppp_idle *ip;
906 {
907     return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) >= 0;
908 }
909
910 /*
911  * get_ppp_stats - return statistics for the link.
912  */
913 int
914 get_ppp_stats(u, stats)
915     int u;
916     struct pppd_stats *stats;
917 {
918     struct ppp_stats s;
919
920     if (strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof(s)) < 0) {
921         error("Couldn't get link statistics: %m");
922         return 0;
923     }
924     stats->bytes_in = s.p.ppp_ibytes;
925     stats->bytes_out = s.p.ppp_obytes;
926     stats->pkts_in = s.p.ppp_ipackets;
927     stats->pkts_out = s.p.ppp_opackets;
928     return 1;
929 }
930
931
932 /*
933  * ccp_fatal_error - returns 1 if decompression was disabled as a
934  * result of an error detected after decompression of a packet,
935  * 0 otherwise.  This is necessary because of patent nonsense.
936  */
937 int
938 ccp_fatal_error(unit)
939     int unit;
940 {
941     int cf[2];
942
943     cf[0] = cf[1] = 0;
944     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
945         if (errno != ENXIO && errno != EINVAL)
946             error("Couldn't get compression flags: %m");
947         return 0;
948     }
949     return cf[0] & CCP_FATALERROR;
950 }
951
952 /*
953  * sifvjcomp - config tcp header compression
954  */
955 int
956 sifvjcomp(u, vjcomp, xcidcomp, xmaxcid)
957     int u, vjcomp, xcidcomp, xmaxcid;
958 {
959     int cf[2];
960     char maxcid[2];
961
962     if (vjcomp) {
963         maxcid[0] = xcidcomp;
964         maxcid[1] = 15;         /* XXX should be rmaxcid */
965         if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) < 0) {
966             error("Couldn't initialize VJ compression: %m");
967         }
968     }
969
970     cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0)  /* XXX this is wrong */
971         + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0);
972     cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID;
973     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
974         if (vjcomp)
975             error("Couldn't enable VJ compression: %m");
976     }
977
978     return 1;
979 }
980
981 /*
982  * sifup - Config the interface up and enable IP packets to pass.
983  */
984 int
985 sifup(u)
986     int u;
987 {
988     struct ifreq ifr;
989
990     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
991     if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
992         error("Couldn't mark interface up (get): %m");
993         return 0;
994     }
995     ifr.ifr_flags |= IFF_UP;
996     if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
997         error("Couldn't mark interface up (set): %m");
998         return 0;
999     }
1000     if_is_up = 1;
1001     return 1;
1002 }
1003
1004 /*
1005  * sifdown - Config the interface down and disable IP.
1006  */
1007 int
1008 sifdown(u)
1009     int u;
1010 {
1011     struct ifreq ifr;
1012
1013     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1014     if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
1015         error("Couldn't mark interface down (get): %m");
1016         return 0;
1017     }
1018     if ((ifr.ifr_flags & IFF_UP) != 0) {
1019         ifr.ifr_flags &= ~IFF_UP;
1020         if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
1021             error("Couldn't mark interface down (set): %m");
1022             return 0;
1023         }
1024     }
1025     if_is_up = 0;
1026     return 1;
1027 }
1028
1029 /*
1030  * sifnpmode - Set the mode for handling packets for a given NP.
1031  */
1032 int
1033 sifnpmode(u, proto, mode)
1034     int u;
1035     int proto;
1036     enum NPmode mode;
1037 {
1038     int npi[2];
1039
1040     npi[0] = proto;
1041     npi[1] = (int) mode;
1042     if (strioctl(pppfd, PPPIO_NPMODE, npi, 2 * sizeof(int), 0) < 0) {
1043         error("ioctl(set NP %d mode to %d): %m", proto, mode);
1044         return 0;
1045     }
1046     return 1;
1047 }
1048
1049 #define INET_ADDR(x)    (((struct sockaddr_in *) &(x))->sin_addr.s_addr)
1050
1051 /*
1052  * sifaddr - Config the interface IP addresses and netmask.
1053  */
1054 int
1055 sifaddr(u, o, h, m)
1056     int u;
1057     u_int32_t o, h, m;
1058 {
1059     struct ifreq ifr;
1060
1061     memset(&ifr, 0, sizeof(ifr));
1062     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1063     ifr.ifr_addr.sa_family = AF_INET;
1064     INET_ADDR(ifr.ifr_addr) = m;
1065     if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
1066         error("Couldn't set IP netmask: %m");
1067     }
1068     ifr.ifr_addr.sa_family = AF_INET;
1069     INET_ADDR(ifr.ifr_addr) = o;
1070     if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
1071         error("Couldn't set local IP address: %m");
1072     }
1073     ifr.ifr_dstaddr.sa_family = AF_INET;
1074     INET_ADDR(ifr.ifr_dstaddr) = h;
1075     if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) {
1076         error("Couldn't set remote IP address: %m");
1077     }
1078 #if 0   /* now done in ppp_send_config */
1079     ifr.ifr_metric = link_mtu;
1080     if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
1081         error("Couldn't set IP MTU: %m");
1082     }
1083 #endif
1084     ifaddrs[0] = o;
1085     ifaddrs[1] = h;
1086
1087     return 1;
1088 }
1089
1090 /*
1091  * cifaddr - Clear the interface IP addresses, and delete routes
1092  * through the interface if possible.
1093  */
1094 int
1095 cifaddr(u, o, h)
1096     int u;
1097     u_int32_t o, h;
1098 {
1099     struct rtentry rt;
1100
1101     bzero(&rt, sizeof(rt));
1102     rt.rt_dst.sa_family = AF_INET;
1103     INET_ADDR(rt.rt_dst) = h;
1104     rt.rt_gateway.sa_family = AF_INET;
1105     INET_ADDR(rt.rt_gateway) = o;
1106     rt.rt_flags = RTF_HOST;
1107     if (ioctl(sockfd, SIOCDELRT, &rt) < 0)
1108         error("Couldn't delete route through interface: %m");
1109     ifaddrs[0] = 0;
1110     return 1;
1111 }
1112
1113 /*
1114  * sifdefaultroute - assign a default route through the address given.
1115  */
1116 int
1117 sifdefaultroute(u, l, g)
1118     int u;
1119     u_int32_t l, g;
1120 {
1121     struct rtentry rt;
1122
1123     bzero(&rt, sizeof(rt));
1124     rt.rt_dst.sa_family = AF_INET;
1125     INET_ADDR(rt.rt_dst) = 0;
1126     rt.rt_gateway.sa_family = AF_INET;
1127     INET_ADDR(rt.rt_gateway) = g;
1128     rt.rt_flags = RTF_GATEWAY;
1129
1130     if (ioctl(sockfd, SIOCADDRT, &rt) < 0) {
1131         error("Can't add default route: %m");
1132         return 0;
1133     }
1134
1135     default_route_gateway = g;
1136     return 1;
1137 }
1138
1139 /*
1140  * cifdefaultroute - delete a default route through the address given.
1141  */
1142 int
1143 cifdefaultroute(u, l, g)
1144     int u;
1145     u_int32_t l, g;
1146 {
1147     struct rtentry rt;
1148
1149     bzero(&rt, sizeof(rt));
1150     rt.rt_dst.sa_family = AF_INET;
1151     INET_ADDR(rt.rt_dst) = 0;
1152     rt.rt_gateway.sa_family = AF_INET;
1153     INET_ADDR(rt.rt_gateway) = g;
1154     rt.rt_flags = RTF_GATEWAY;
1155
1156     if (ioctl(sockfd, SIOCDELRT, &rt) < 0) {
1157         error("Can't delete default route: %m");
1158         return 0;
1159     }
1160
1161     default_route_gateway = 0;
1162     return 1;
1163 }
1164
1165 /*
1166  * sifproxyarp - Make a proxy ARP entry for the peer.
1167  */
1168 int
1169 sifproxyarp(unit, hisaddr)
1170     int unit;
1171     u_int32_t hisaddr;
1172 {
1173     struct arpreq arpreq;
1174
1175     bzero(&arpreq, sizeof(arpreq));
1176     if (!get_ether_addr(hisaddr, &arpreq.arp_ha))
1177         return 0;
1178
1179     arpreq.arp_pa.sa_family = AF_INET;
1180     INET_ADDR(arpreq.arp_pa) = hisaddr;
1181     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
1182     if (ioctl(sockfd, SIOCSARP, (caddr_t) &arpreq) < 0) {
1183         error("Couldn't set proxy ARP entry: %m");
1184         return 0;
1185     }
1186
1187     proxy_arp_addr = hisaddr;
1188     return 1;
1189 }
1190
1191 /*
1192  * cifproxyarp - Delete the proxy ARP entry for the peer.
1193  */
1194 int
1195 cifproxyarp(unit, hisaddr)
1196     int unit;
1197     u_int32_t hisaddr;
1198 {
1199     struct arpreq arpreq;
1200
1201     bzero(&arpreq, sizeof(arpreq));
1202     arpreq.arp_pa.sa_family = AF_INET;
1203     INET_ADDR(arpreq.arp_pa) = hisaddr;
1204     if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
1205         error("Couldn't delete proxy ARP entry: %m");
1206         return 0;
1207     }
1208
1209     proxy_arp_addr = 0;
1210     return 1;
1211 }
1212
1213 /*
1214  * get_ether_addr - get the hardware address of an interface on the
1215  * the same subnet as ipaddr.
1216  */
1217 #define MAX_IFS         32
1218
1219 static int
1220 get_ether_addr(ipaddr, hwaddr)
1221     u_int32_t ipaddr;
1222     struct sockaddr *hwaddr;
1223 {
1224     struct ifreq *ifr, *ifend;
1225     u_int32_t ina, mask;
1226     struct ifreq ifreq;
1227     struct ifconf ifc;
1228     struct ifreq ifs[MAX_IFS];
1229     int nit_fd;
1230
1231     ifc.ifc_len = sizeof(ifs);
1232     ifc.ifc_req = ifs;
1233     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1234         error("ioctl(SIOCGIFCONF): %m");
1235         return 0;
1236     }
1237
1238     /*
1239      * Scan through looking for an interface with an Internet
1240      * address on the same subnet as `ipaddr'.
1241      */
1242     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1243     for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
1244             ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) {
1245         if (ifr->ifr_addr.sa_family == AF_INET) {
1246
1247             /*
1248              * Check that the interface is up, and not point-to-point
1249              * or loopback.
1250              */
1251             strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1252             if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1253                 continue;
1254             if ((ifreq.ifr_flags &
1255                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
1256                  != (IFF_UP|IFF_BROADCAST))
1257                 continue;
1258
1259             /*
1260              * Get its netmask and check that it's on the right subnet.
1261              */
1262             if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1263                 continue;
1264             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1265             mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
1266             if ((ipaddr & mask) != (ina & mask))
1267                 continue;
1268
1269             break;
1270         }
1271     }
1272
1273     if (ifr >= ifend)
1274         return 0;
1275     info("found interface %s for proxy arp", ifr->ifr_name);
1276
1277     /*
1278      * Grab the physical address for this interface.
1279      */
1280     if ((nit_fd = open("/dev/nit", O_RDONLY)) < 0) {
1281         error("Couldn't open /dev/nit: %m");
1282         return 0;
1283     }
1284     strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1285     if (ioctl(nit_fd, NIOCBIND, &ifreq) < 0
1286         || ioctl(nit_fd, SIOCGIFADDR, &ifreq) < 0) {
1287         error("Couldn't get hardware address for %s: %m",
1288                ifreq.ifr_name);
1289         close(nit_fd);
1290         return 0;
1291     }
1292
1293     hwaddr->sa_family = AF_UNSPEC;
1294     memcpy(hwaddr->sa_data, ifreq.ifr_addr.sa_data, 6);
1295     close(nit_fd);
1296     return 1;
1297 }
1298
1299 /*
1300  * have_route_to - determine if the system has any route to
1301  * a given IP address.
1302  * For demand mode to work properly, we have to ignore routes
1303  * through our own interface.
1304  */
1305 int have_route_to(addr)
1306     u_int32_t addr;
1307 {
1308     return -1;
1309 }
1310
1311 #define WTMPFILE        "/usr/adm/wtmp"
1312
1313 void
1314 logwtmp(line, name, host)
1315     const char *line, *name, *host;
1316 {
1317     int fd;
1318     struct stat buf;
1319     struct utmp ut;
1320
1321     if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
1322         return;
1323     if (!fstat(fd, &buf)) {
1324         strncpy(ut.ut_line, line, sizeof(ut.ut_line));
1325         strncpy(ut.ut_name, name, sizeof(ut.ut_name));
1326         strncpy(ut.ut_host, host, sizeof(ut.ut_host));
1327         (void)time(&ut.ut_time);
1328         if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
1329             (void)ftruncate(fd, buf.st_size);
1330     }
1331     close(fd);
1332 }
1333
1334 /*
1335  * Return user specified netmask, modified by any mask we might determine
1336  * for address `addr' (in network byte order).
1337  * Here we scan through the system's list of interfaces, looking for
1338  * any non-point-to-point interfaces which might appear to be on the same
1339  * network as `addr'.  If we find any, we OR in their netmask to the
1340  * user-specified netmask.
1341  */
1342 u_int32_t
1343 GetMask(addr)
1344     u_int32_t addr;
1345 {
1346     u_int32_t mask, nmask, ina;
1347     struct ifreq *ifr, *ifend, ifreq;
1348     struct ifconf ifc;
1349
1350     addr = ntohl(addr);
1351     if (IN_CLASSA(addr))        /* determine network mask for address class */
1352         nmask = IN_CLASSA_NET;
1353     else if (IN_CLASSB(addr))
1354         nmask = IN_CLASSB_NET;
1355     else
1356         nmask = IN_CLASSC_NET;
1357     /* class D nets are disallowed by bad_ip_adrs */
1358     mask = netmask | htonl(nmask);
1359
1360     /*
1361      * Scan through the system's network interfaces.
1362      */
1363     ifc.ifc_len = MAX_IFS * sizeof(struct ifreq);
1364     ifc.ifc_req = alloca(ifc.ifc_len);
1365     if (ifc.ifc_req == 0)
1366         return mask;
1367     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1368         warn("Couldn't get system interface list: %m");
1369         return mask;
1370     }
1371     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1372     for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
1373         /*
1374          * Check the interface's internet address.
1375          */
1376         if (ifr->ifr_addr.sa_family != AF_INET)
1377             continue;
1378         ina = INET_ADDR(ifr->ifr_addr);
1379         if ((ntohl(ina) & nmask) != (addr & nmask))
1380             continue;
1381         /*
1382          * Check that the interface is up, and not point-to-point or loopback.
1383          */
1384         strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1385         if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1386             continue;
1387         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1388             != IFF_UP)
1389             continue;
1390         /*
1391          * Get its netmask and OR it into our mask.
1392          */
1393         if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1394             continue;
1395         mask |= INET_ADDR(ifreq.ifr_addr);
1396     }
1397
1398     return mask;
1399 }
1400
1401 static int
1402 strioctl(fd, cmd, ptr, ilen, olen)
1403     int fd, cmd, ilen, olen;
1404     void *ptr;
1405 {
1406     struct strioctl str;
1407
1408     str.ic_cmd = cmd;
1409     str.ic_timout = 0;
1410     str.ic_len = ilen;
1411     str.ic_dp = ptr;
1412     if (ioctl(fd, I_STR, &str) == -1)
1413         return -1;
1414     if (str.ic_len != olen)
1415         dbglog("strioctl: expected %d bytes, got %d for cmd %x\n",
1416                olen, str.ic_len, cmd);
1417     return 0;
1418 }
1419
1420 /*
1421  * Use the hostid as part of the random number seed.
1422  */
1423 int
1424 get_host_seed()
1425 {
1426     return gethostid();
1427 }
1428
1429 #if 0
1430 /*
1431  * Code for locking/unlocking the serial device.
1432  * This code is derived from chat.c.
1433  */
1434
1435 #if !defined(HDB) && !defined(SUNOS3)
1436 #define HDB     1               /* ascii lock files are the default */
1437 #endif
1438
1439 #ifndef LOCK_DIR
1440 # if HDB
1441 #  define       PIDSTRING
1442 #  define       LOCK_PREFIX     "/usr/spool/locks/LCK.."
1443 # else /* HDB */
1444 #  define       LOCK_PREFIX     "/usr/spool/uucp/LCK.."
1445 # endif /* HDB */
1446 #endif /* LOCK_DIR */
1447
1448 static char *lock_file;         /* name of lock file created */
1449
1450 /*
1451  * lock - create a lock file for the named device.
1452  */
1453 int
1454 lock(dev)
1455     char *dev;
1456 {
1457     char hdb_lock_buffer[12];
1458     int fd, pid, n;
1459     char *p;
1460     size_t l;
1461
1462     if ((p = strrchr(dev, '/')) != NULL)
1463         dev = p + 1;
1464     l = strlen(LOCK_PREFIX) + strlen(dev) + 1;
1465     lock_file = malloc(l);
1466     if (lock_file == NULL)
1467         novm("lock file name");
1468     slprintf(lock_file, l, "%s%s", LOCK_PREFIX, dev);
1469
1470     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
1471         if (errno == EEXIST
1472             && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
1473             /* Read the lock file to find out who has the device locked */
1474 #ifdef PIDSTRING
1475             n = read(fd, hdb_lock_buffer, 11);
1476             if (n > 0) {
1477                 hdb_lock_buffer[n] = 0;
1478                 pid = atoi(hdb_lock_buffer);
1479             }
1480 #else
1481             n = read(fd, &pid, sizeof(pid));
1482 #endif
1483             if (n <= 0) {
1484                 error("Can't read pid from lock file %s", lock_file);
1485                 close(fd);
1486             } else {
1487                 if (kill(pid, 0) == -1 && errno == ESRCH) {
1488                     /* pid no longer exists - remove the lock file */
1489                     if (unlink(lock_file) == 0) {
1490                         close(fd);
1491                         notice("Removed stale lock on %s (pid %d)",
1492                                dev, pid);
1493                         continue;
1494                     } else
1495                         warn("Couldn't remove stale lock on %s",
1496                                dev);
1497                 } else
1498                     notice("Device %s is locked by pid %d",
1499                            dev, pid);
1500             }
1501             close(fd);
1502         } else
1503             error("Can't create lock file %s: %m", lock_file);
1504         free(lock_file);
1505         lock_file = NULL;
1506         return -1;
1507     }
1508
1509 #ifdef PIDSTRING
1510     slprintf(hdb_lock_buffer, sizeof(hdb_lock_buffer), "%10d\n", getpid());
1511     write(fd, hdb_lock_buffer, 11);
1512 #else
1513     pid = getpid();
1514     write(fd, &pid, sizeof pid);
1515 #endif
1516
1517     close(fd);
1518     return 0;
1519 }
1520
1521 /*
1522  * unlock - remove our lockfile
1523  */
1524 void
1525 unlock()
1526 {
1527     if (lock_file) {
1528         unlink(lock_file);
1529         free(lock_file);
1530         lock_file = NULL;
1531     }
1532 }
1533 #endif /* lock stuff removed */
1534
1535 /*
1536  * get_pty - get a pty master/slave pair and chown the slave side
1537  * to the uid given.  Assumes slave_name points to >= 12 bytes of space.
1538  */
1539 int
1540 get_pty(master_fdp, slave_fdp, slave_name, uid)
1541     int *master_fdp;
1542     int *slave_fdp;
1543     char *slave_name;
1544     int uid;
1545 {
1546     int i, mfd, sfd;
1547     char pty_name[12];
1548     struct termios tios;
1549
1550     sfd = -1;
1551     for (i = 0; i < 64; ++i) {
1552         slprintf(pty_name, sizeof(pty_name), "/dev/pty%c%x",
1553                  'p' + i / 16, i % 16);
1554         mfd = open(pty_name, O_RDWR, 0);
1555         if (mfd >= 0) {
1556             pty_name[5] = 't';
1557             sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
1558             if (sfd >= 0)
1559                 break;
1560             close(mfd);
1561         }
1562     }
1563     if (sfd < 0)
1564         return 0;
1565
1566     strlcpy(slave_name, pty_name, 12);
1567     *master_fdp = mfd;
1568     *slave_fdp = sfd;
1569     fchown(sfd, uid, -1);
1570     fchmod(sfd, S_IRUSR | S_IWUSR);
1571     if (tcgetattr(sfd, &tios) == 0) {
1572         tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
1573         tios.c_cflag |= CS8 | CREAD;
1574         tios.c_iflag  = IGNPAR | CLOCAL;
1575         tios.c_oflag  = 0;
1576         tios.c_lflag  = 0;
1577         if (tcsetattr(sfd, TCSAFLUSH, &tios) < 0)
1578             warn("couldn't set attributes on pty: %m");
1579     } else
1580         warn("couldn't get attributes on pty: %m");
1581
1582     return 1;
1583 }
1584
1585 /*
1586  * SunOS doesn't have strtoul :-(
1587  */
1588 unsigned long
1589 strtoul(str, ptr, base)
1590     char *str, **ptr;
1591     int base;
1592 {
1593     return (unsigned long) strtol(str, ptr, base);
1594 }
1595
1596 /*
1597  * Or strerror :-(
1598  */
1599 extern char *sys_errlist[];
1600 extern int sys_nerr;
1601
1602 char *
1603 strerror(n)
1604     int n;
1605 {
1606     static char unknown[32];
1607
1608     if (n > 0 && n < sys_nerr)
1609         return sys_errlist[n];
1610     slprintf(unknown, sizeof(unknown), "Error %d", n);
1611     return unknown;
1612 }