]> git.ozlabs.org Git - ppp.git/blob - pppd/sys-str.c
Update to state of pppd-new directory
[ppp.git] / pppd / sys-str.c
1 /*
2  * sys-str.c - System-dependent procedures for setting up
3  * PPP interfaces on systems which use the STREAMS ppp interface.
4  *
5  * Copyright (c) 1989 Carnegie Mellon University.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by Carnegie Mellon University.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20
21 #ifndef lint
22 static char rcsid[] = "$Id: sys-str.c,v 1.20.2.1 1995/06/01 07:01:42 paulus Exp $";
23 #endif
24
25 /*
26  * TODO:
27  */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <syslog.h>
33 #include <termios.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <time.h>
37 #include <utmp.h>
38 #include <poll.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/sockio.h>
42 #include <sys/time.h>
43 #include <sys/stream.h>
44 #include <sys/stropts.h>
45
46 #include <arpa/inet.h>
47 #include <net/if.h>
48 #include <net/ppp_defs.h>
49 #include <net/ppp_str.h>
50 #include <net/route.h>
51 #include <net/if_arp.h>
52 #include <netinet/in.h>
53
54 #include "pppd.h"
55
56 #ifndef ifr_mtu
57 #define ifr_mtu         ifr_metric
58 #endif
59
60 #define MAXMODULES      10      /* max number of module names to save */
61 static struct   modlist {
62     char        modname[FMNAMESZ+1];
63 } str_modules[MAXMODULES];
64 static int      str_module_count = 0;
65 static int      pushed_ppp;
66 static int      closed_stdio;
67
68 static int      ppp_fd = -1;    /* fd currently attached to ppp unit */
69
70 static int      restore_term;   /* 1 => we've munged the terminal */
71 static struct termios inittermios; /* Initial TTY termios */
72
73 static int loop_slave = -1;
74 static int loop_master;
75 static char loop_name[20];
76
77 int sockfd;                     /* socket for doing interface ioctls */
78 static char *lock_file;         /* lock file created for serial port */
79
80 /*
81  * sys_init - System-dependent initialization.
82  */
83 void
84 sys_init()
85 {
86     openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
87     setlogmask(LOG_UPTO(LOG_INFO));
88     if (debug)
89         setlogmask(LOG_UPTO(LOG_DEBUG));
90
91     /* Get an internet socket for doing socket ioctl's on. */
92     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
93         syslog(LOG_ERR, "Couldn't create IP socket: %m");
94         die(1);
95     }
96 }
97
98 /*
99  * note_debug_level - note a change in the debug level.
100  */
101 void
102 note_debug_level()
103 {
104     if (debug) {
105         syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
106         setlogmask(LOG_UPTO(LOG_DEBUG));
107     } else {
108         setlogmask(LOG_UPTO(LOG_WARNING));
109     }
110 }
111
112 /*
113  * daemon - Detach us from the terminal session.
114  */
115 int
116 daemon(nochdir, noclose)
117     int nochdir, noclose;
118 {
119     int pid;
120
121     if ((pid = fork()) < 0)
122         return -1;
123     if (pid != 0)
124         exit(0);                /* parent dies */
125     setsid();
126     if (!nochdir)
127         chdir("/");
128     if (!noclose) {
129         fclose(stdin);          /* don't need stdin, stdout, stderr */
130         fclose(stdout);
131         fclose(stderr);
132     }
133     return 0;
134 }
135
136
137 /*
138  * ppp_available - check if this kernel supports PPP.
139  */
140 int
141 ppp_available()
142 {
143     int fd, ret;
144
145     fd = open("/dev/tty", O_RDONLY, 0);
146     if (fd < 0)
147         return 1;               /* can't find out - assume we have ppp */
148     ret = ioctl(fd, I_FIND, "pppasync") >= 0;
149     close(fd);
150     return ret;
151 }
152
153
154 /*
155  * establish_ppp - Turn the serial port (or loopback) into a ppp interface.
156  */
157 void
158 establish_ppp()
159 {
160     if (fd != loop_slave) {
161         str_module_count = 0;
162         /* go through and save the name of all the modules, then pop em */
163         for (;;) { 
164             if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 ||
165                 ioctl(fd, I_POP, 0) < 0)
166                 break;
167             MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
168                        str_modules[str_module_count].modname));
169             str_module_count++;
170         }
171     }
172
173     /* now push the async/fcs module */
174     if (ioctl(fd, I_PUSH, "pppasync") < 0) {
175         syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m");
176         die(1);
177     }
178     /* push the compress module */
179     if (fd != loop_slave && ioctl(fd, I_PUSH, "pppcomp") < 0) {
180         syslog(LOG_WARNING, "ioctl(I_PUSH, ppp_comp): %m");
181     }
182     /* finally, push the ppp_if module that actually handles the */
183     /* network interface */ 
184     if (ioctl(fd, I_PUSH, "pppif") < 0) {
185         syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m");
186         die(1);
187     }
188     pushed_ppp = 1;
189
190     /* read mode, message non-discard mode */
191     if (ioctl(fd, I_SRDOPT, RMSGN) < 0) {
192         syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
193         die(1);
194     }
195     /*
196      * Find out which interface we were given.
197      * (ppp_if handles this ioctl)
198      */
199     if (ioctl(fd, SIOCGETU, &ifunit) < 0) {
200         syslog(LOG_ERR, "ioctl(SIOCGETU): %m");
201         die(1);
202     }
203
204     /* Set debug flags in driver */
205     if (ioctl(fd, SIOCSIFDEBUG, &kdebugflag) < 0) {
206         syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
207     }
208
209     ppp_fd = fd;
210
211     /* close stdin, stdout, stderr if they might refer to the device */
212     if (default_device && !closed_stdio) {
213         int i;
214
215         for (i = 0; i <= 2; ++i)
216             if (i != fd && i != sockfd)
217                 close(i);
218         closed_stdio = 1;
219     }
220 }
221
222 /*
223  * transfer_ppp - make the device on fd `fd' take over the PPP interface
224  * unit that we are using.
225  */
226 void
227 transfer_ppp(fd)
228     int fd;
229 {
230     if (fd == ppp_fd)
231         return;                 /* we can't get here */
232
233     if (fd != loop_slave) {
234         /* go through and save the name of all the modules, then pop em */
235         str_module_count = 0;
236         for (;;) { 
237             if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 ||
238                 ioctl(fd, I_POP, 0) < 0)
239                 break;
240             MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
241                        str_modules[str_module_count].modname));
242             str_module_count++;
243         }
244     }
245
246     /* now push the async/fcs module */
247     if (ioctl(fd, I_PUSH, "pppasync") < 0) {
248         syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m");
249         die(1);
250     }
251     /* push the compress module */
252     if (ioctl(fd, I_PUSH, "pppcomp") < 0) {
253         syslog(LOG_WARNING, "ioctl(I_PUSH, ppp_comp): %m");
254     }
255     /* finally, push the ppp_if module that actually handles the */
256     /* network interface */ 
257     if (ioctl(fd, I_PUSH, "pppif") < 0) {
258         syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m");
259         die(1);
260     }
261     pushed_ppp = 1;
262
263     /* read mode, message non-discard mode */
264     if (ioctl(fd, I_SRDOPT, RMSGN) < 0) {
265         syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
266         die(1);
267     }
268     /*
269      * Connect to the interface unit we want.
270      * (ppp_if handles this ioctl)
271      */
272     if (ioctl(fd, SIOCSETU, &ifunit) < 0) {
273         syslog(LOG_ERR, "ioctl(SIOCSETU): %m");
274         die(1);
275     }
276
277     /* Set debug flags in driver */
278     if (ioctl(fd, SIOCSIFDEBUG, &kdebugflag) < 0) {
279         syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
280     }
281
282     /*
283      * Pop the modules off the old ppp stream, and restore
284      * the modules that were there, if this is the real serial port.
285      */
286     while (ioctl(ppp_fd, I_POP, 0) == 0)        /* pop any we pushed */
287         ;
288     if (fd == loop_slave) {
289         for (; str_module_count > 0; str_module_count--) {
290             if (ioctl(ppp_fd, I_PUSH, str_modules[str_module_count-1].modname)) {
291                 if (errno != ENXIO)
292                     syslog(LOG_WARNING,
293                            "Couldn't restore STREAMS module %s: %m",
294                            str_modules[str_module_count-1].modname);
295             }
296         }
297     }
298     ppp_fd = fd;
299 }
300
301 /*
302  * disestablish_ppp - Restore the serial port to normal operation.
303  * It attempts to reconstruct the stream with the previously popped
304  * modules.  This shouldn't call die() because it's called from die().
305  */
306 void
307 disestablish_ppp(fd)
308     int fd;
309 {
310     if (hungup) {
311         /* we can't push or pop modules after the stream has hung up */
312         str_module_count = 0;
313         restore_term = 0;       /* nor can we fix up terminal settings */
314         return;
315     }
316
317     if (fd == ppp_fd && fd >= 0 && pushed_ppp) {
318         while (ioctl(fd, I_POP, 0) == 0)        /* pop any we pushed */
319             ;
320         pushed_ppp = 0;
321   
322         for (; str_module_count > 0; str_module_count--) {
323             if (ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) {
324                 if (errno != ENXIO)
325                     syslog(LOG_WARNING,
326                            "Couldn't restore STREAMS module %s: %m",
327                            str_modules[str_module_count-1].modname);
328             }
329         }
330         ppp_fd = -1;
331         pushed_ppp = 0;
332     }
333 }
334
335 /*
336  * Check whether the link seems not to be 8-bit clean.
337  */
338 void
339 clean_check()
340 {
341     int flags;
342     char *s;
343
344     if (ioctl(ppp_fd, SIOCGIFDEBUG, (caddr_t) &flags) == 0) {
345         s = NULL;
346         switch (~flags & PAI_FLAGS_HIBITS) {
347         case PAI_FLAGS_B7_0:
348             s = "bit 7 set to 1";
349             break;
350         case PAI_FLAGS_B7_1:
351             s = "bit 7 set to 0";
352             break;
353         case PAI_FLAGS_PAR_EVEN:
354             s = "odd parity";
355             break;
356         case PAI_FLAGS_PAR_ODD:
357             s = "even parity";
358             break;
359         }
360         if (s != NULL) {
361             syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
362             syslog(LOG_WARNING, "All received characters had %s", s);
363         }
364     }
365 }
366
367 /*
368  * List of valid speeds.
369  */
370 struct speed {
371     int speed_int, speed_val;
372 } speeds[] = {
373 #ifdef B50
374     { 50, B50 },
375 #endif
376 #ifdef B75
377     { 75, B75 },
378 #endif
379 #ifdef B110
380     { 110, B110 },
381 #endif
382 #ifdef B134
383     { 134, B134 },
384 #endif
385 #ifdef B150
386     { 150, B150 },
387 #endif
388 #ifdef B200
389     { 200, B200 },
390 #endif
391 #ifdef B300
392     { 300, B300 },
393 #endif
394 #ifdef B600
395     { 600, B600 },
396 #endif
397 #ifdef B1200
398     { 1200, B1200 },
399 #endif
400 #ifdef B1800
401     { 1800, B1800 },
402 #endif
403 #ifdef B2000
404     { 2000, B2000 },
405 #endif
406 #ifdef B2400
407     { 2400, B2400 },
408 #endif
409 #ifdef B3600
410     { 3600, B3600 },
411 #endif
412 #ifdef B4800
413     { 4800, B4800 },
414 #endif
415 #ifdef B7200
416     { 7200, B7200 },
417 #endif
418 #ifdef B9600
419     { 9600, B9600 },
420 #endif
421 #ifdef B19200
422     { 19200, B19200 },
423 #endif
424 #ifdef B38400
425     { 38400, B38400 },
426 #endif
427 #ifdef EXTA
428     { 19200, EXTA },
429 #endif
430 #ifdef EXTB
431     { 38400, EXTB },
432 #endif
433 #ifdef B57600
434     { 57600, B57600 },
435 #endif
436 #ifdef B115200
437     { 115200, B115200 },
438 #endif
439     { 0, 0 }
440 };
441
442 /*
443  * Translate from bits/second to a speed_t.
444  */
445 int
446 translate_speed(bps)
447     int bps;
448 {
449     struct speed *speedp;
450
451     if (bps == 0)
452         return 0;
453     for (speedp = speeds; speedp->speed_int; speedp++)
454         if (bps == speedp->speed_int)
455             return speedp->speed_val;
456     syslog(LOG_WARNING, "speed %d not supported", bps);
457     return 0;
458 }
459
460 /*
461  * Translate from a speed_t to bits/second.
462  */
463 int
464 baud_rate_of(speed)
465     int speed;
466 {
467     struct speed *speedp;
468
469     if (speed == 0)
470         return 0;
471     for (speedp = speeds; speedp->speed_int; speedp++)
472         if (speed == speedp->speed_val)
473             return speedp->speed_int;
474     return 0;
475 }
476
477 /*
478  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
479  * at the requested speed, etc.  If `local' is true, set CLOCAL
480  * regardless of whether the modem option was specified.
481  */
482 set_up_tty(fd, local)
483     int fd, local;
484 {
485     int speed;
486     struct termios tios;
487
488     if (tcgetattr(fd, &tios) < 0) {
489         syslog(LOG_ERR, "tcgetattr: %m");
490         die(1);
491     }
492
493     if (!restore_term)
494         inittermios = tios;
495
496     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
497     if (crtscts > 0)
498         tios.c_cflag |= CRTSCTS;
499     else if (crtscts < 0)
500         tios.c_cflag &= ~CRTSCTS;
501
502     tios.c_cflag |= CS8 | CREAD | HUPCL;
503     if (local || !modem)
504         tios.c_cflag |= CLOCAL;
505     tios.c_iflag = IGNBRK | IGNPAR;
506     tios.c_oflag = 0;
507     tios.c_lflag = 0;
508     tios.c_cc[VMIN] = 1;
509     tios.c_cc[VTIME] = 0;
510
511     if (crtscts == 2) {
512         tios.c_iflag |= IXOFF;
513         tios.c_cc[VSTOP] = 0x13;        /* DC3 = XOFF = ^S */
514         tios.c_cc[VSTART] = 0x11;       /* DC1 = XON  = ^Q */
515     }
516
517     speed = translate_speed(inspeed);
518     if (speed) {
519         cfsetospeed(&tios, speed);
520         cfsetispeed(&tios, speed);
521     } else {
522         speed = cfgetospeed(&tios);
523         /*
524          * We can't proceed if the serial port speed is B0,
525          * since that implies that the serial port is disabled.
526          */
527         if (speed == B0) {
528             syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate",
529                    devnam);
530             die(1);
531         }
532     }
533
534     if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
535         syslog(LOG_ERR, "tcsetattr: %m");
536         die(1);
537     }
538
539     baud_rate = inspeed = baud_rate_of(speed);
540     restore_term = 1;
541 }
542
543 /*
544  * restore_tty - restore the terminal to the saved settings.
545  */
546 void
547 restore_tty()
548 {
549     if (restore_term) {
550         if (!default_device) {
551             /*
552              * Turn off echoing, because otherwise we can get into
553              * a loop with the tty and the modem echoing to each other.
554              * We presume we are the sole user of this tty device, so
555              * when we close it, it will revert to its defaults anyway.
556              */
557             inittermios.c_lflag &= ~(ECHO | ECHONL);
558         }
559         if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
560             if (errno != ENXIO)
561                 syslog(LOG_WARNING, "tcsetattr: %m");
562         restore_term = 0;
563     }
564 }
565
566 /*
567  * setdtr - control the DTR line on the serial port.
568  * This is called from die(), so it shouldn't call die().
569  */
570 setdtr(fd, on)
571 int fd, on;
572 {
573     int modembits = TIOCM_DTR;
574
575     ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
576 }
577
578
579 /*
580  * open_loopback - open the device we use for getting packets
581  * in demand mode.  Here we use a pty.
582  */
583 int
584 open_loopback()
585 {
586     int flags;
587     struct termios tios;
588     static char c1[] = "pqrstuvwxyzPQRST";
589     static char c2[] = "0123456789abcdef";
590     char *p1, *p2;
591
592     p1 = c1;
593     p2 = c2;
594     strcpy(loop_name, "/dev/ptyxx");
595     loop_slave = -1;
596     for (;;) {
597         loop_name[8] = *p1;
598         loop_name[9] = *p2;
599         if ((loop_master = open(loop_name, O_RDWR, 0)) >= 0) {
600             loop_name[5] = 't';
601             chown(loop_name, geteuid(), getegid());
602             chmod(loop_name, S_IRUSR|S_IWUSR);
603             if ((loop_slave = open(loop_name, O_RDWR, 0)) >= 0)
604                 break;
605             close(loop_master);
606             loop_name[5] = 'p';
607         } else if (errno == ENOENT)
608             break;
609         if (*++p2 == 0) {
610             p2 = c2;
611             if (*++p1 == 0)
612                 break;
613         }
614     }
615     if (loop_slave < 0) {
616         syslog(LOG_ERR, "No free pty for loopback");
617         die(1);
618     }
619     SYSDEBUG((LOG_DEBUG, "using %s for loopback", loop_name));
620     if (tcgetattr(loop_slave, &tios) == 0) {
621         tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
622         tios.c_cflag |= CS8 | CREAD;
623         tios.c_iflag = IGNPAR;
624         tios.c_oflag = 0;
625         tios.c_lflag = 0;
626         if (tcsetattr(loop_slave, TCSAFLUSH, &tios) < 0)
627             syslog(LOG_WARNING, "couldn't set attributes on loopback: %m");
628     }
629     if ((flags = fcntl(loop_slave, F_GETFL)) != -1) 
630         if (fcntl(loop_slave, F_SETFL, flags | O_NONBLOCK) == -1)
631             syslog(LOG_WARNING, "couldn't set loopback to nonblock: %m");
632     if ((flags = fcntl(loop_master, F_GETFL)) != -1) 
633         if (fcntl(loop_master, F_SETFL, flags | O_NONBLOCK) == -1)
634             syslog(LOG_WARNING, "couldn't set loopback(m) to nonblock: %m");
635     return loop_slave;
636 }
637
638 /*
639  * output - Output PPP packet.
640  */
641 void
642 output(unit, p, len)
643     int unit;
644     u_char *p;
645     int len;
646 {
647     struct strbuf       str;
648
649     if (unit != 0)
650         MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
651     if (debug)
652         log_packet(p, len, "sent ");
653
654     str.len = len;
655     str.buf = (caddr_t) p;
656     if (putmsg(fd, NULL, &str, 0) < 0) {
657         if (errno != ENXIO) {
658             syslog(LOG_ERR, "putmsg: %m");
659             die(1);
660         }
661     }
662 }
663
664 /*
665  * wait_input - wait for input, for a length of time specified in *timo.
666  */
667 wait_input(timo)
668     struct timeval *timo;
669 {
670     int t;
671     struct pollfd pfd;
672
673     t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000;
674     pfd.fd = fd;
675     pfd.events = POLLIN | POLLPRI | POLLHUP;
676     if (poll(&pfd, 1, t) < 0 && errno != EINTR) {
677         syslog(LOG_ERR, "poll: %m");
678         die(1);
679     }
680 }
681
682 /*
683  * wait_loop_output - wait until there is data available on the,
684  * loopback, for the length of time specified by *timo (indefinite
685  * if timo is NULL).
686  */
687 wait_loop_output(timo)
688     struct timeval *timo;
689 {
690     fd_set ready;
691     int n;
692
693     FD_ZERO(&ready);
694     FD_SET(loop_master, &ready);
695     n = select(loop_master + 1, &ready, NULL, &ready, timo);
696     if (n < 0 && errno != EINTR) {
697         syslog(LOG_ERR, "select: %m");
698         die(1);
699     }
700 }
701
702 /*
703  * read_packet - get a PPP packet from the serial device.
704  */
705 int
706 read_packet(buf)
707     u_char *buf;
708 {
709     struct strbuf str, ctl;
710     int len, i;
711     unsigned char ctlbuf[16];
712
713     str.maxlen = PPP_MTU + PPP_HDRLEN;
714     str.buf = (caddr_t) buf;
715     ctl.maxlen = sizeof(ctlbuf);
716     ctl.buf = (caddr_t) ctlbuf;
717     i = 0;
718     len = getmsg(fd, &ctl, &str, &i);
719     if (len < 0) {
720         if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
721             return -1;
722         }
723         syslog(LOG_ERR, "getmsg(fd) %m");
724         die(1);
725     }
726     if (len) 
727         MAINDEBUG((LOG_DEBUG, "getmsg returned 0x%x",len));
728     if (ctl.len > 0)
729         syslog(LOG_NOTICE, "got ctrl msg len %d %x %x\n", ctl.len,
730                ctlbuf[0], ctlbuf[1]);
731
732     if (str.len < 0) {
733         MAINDEBUG((LOG_DEBUG, "getmsg short return length %d", str.len));
734         return -1;
735     }
736
737     return str.len;
738 }
739
740
741 /*
742  * read_loop_output - get characters from the "bottom" of the loopback.
743  */
744 int
745 read_loop_output(buf, maxlen)
746     u_char *buf;
747     int maxlen;
748 {
749     int len;
750
751     if ((len = read(loop_master, buf, maxlen)) < 0) {
752         if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
753             return 0;
754         syslog(LOG_ERR, "read from loopback: %m");
755         die(1);
756     } else if (len == 0) {
757         syslog(LOG_ERR, "eof on loopback");
758         die(1);
759     }
760     return len;
761 }
762
763
764 /*
765  * ppp_send_config - configure the transmit characteristics of
766  * the ppp interface.
767  */
768 void
769 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
770     int unit, mtu;
771     u_int32_t asyncmap;
772     int pcomp, accomp;
773 {
774     char c;
775     struct ifreq ifr;
776
777     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
778     ifr.ifr_mtu = mtu;
779     if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
780         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
781         die(1);
782     }
783
784     if(ioctl(fd, SIOCSIFASYNCMAP, (caddr_t) &asyncmap) < 0) {
785         syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m");
786         die(1);
787     }
788
789     c = (pcomp? 1: 0);
790     if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) {
791         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
792         die(1);
793     }
794
795     c = (accomp? 1: 0);
796     if(ioctl(fd, SIOCSIFCOMPAC, &c) < 0) {
797         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
798         die(1);
799     }
800 }
801
802
803 /*
804  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
805  */
806 void
807 ppp_set_xaccm(unit, accm)
808     int unit;
809     ext_accm accm;
810 {
811     if (ioctl(fd, SIOCSIFXASYNCMAP, accm) < 0 && errno != ENOTTY)
812         syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
813 }
814
815
816 /*
817  * ppp_recv_config - configure the receive-side characteristics of
818  * the ppp interface.
819  */
820 void
821 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
822     int unit, mru;
823     u_int32_t asyncmap;
824     int pcomp, accomp;
825 {
826     char c;
827
828     if (ioctl(fd, SIOCSIFMRU, &mru) < 0) {
829         syslog(LOG_ERR, "ioctl(SIOCSIFMRU): %m");
830     }
831
832     if (ioctl(fd, SIOCSIFRASYNCMAP, (caddr_t) &asyncmap) < 0) {
833         syslog(LOG_ERR, "ioctl(SIOCSIFRASYNCMAP): %m");
834     }
835
836     c = 2 + (pcomp? 1: 0);
837     if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) {
838         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
839     }
840
841     c = 2 + (accomp? 1: 0);
842     if (ioctl(fd, SIOCSIFCOMPAC, &c) < 0) {
843         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
844     }
845 }
846
847 /*
848  * ccp_test - ask kernel whether a given compression method
849  * is acceptable for use.
850  */
851 ccp_test(unit, opt_ptr, opt_len, for_transmit)
852     int unit, opt_len, for_transmit;
853     u_char *opt_ptr;
854 {
855     struct ppp_option_data data;
856
857     if ((unsigned) opt_len > MAX_PPP_OPTION)
858         opt_len = MAX_PPP_OPTION;
859     data.length = opt_len;
860     data.transmit = for_transmit;
861     BCOPY(opt_ptr, data.opt_data, opt_len);
862     return ioctl(fd, SIOCSCOMPRESS, (caddr_t) &data) >= 0;
863 }
864
865 /*
866  * ccp_flags_set - inform kernel about the current state of CCP.
867  */
868 void
869 ccp_flags_set(unit, isopen, isup)
870     int unit, isopen, isup;
871 {
872     int x;
873
874     x = (isopen? 1: 0) + (isup? 2: 0);
875     if (ioctl(fd, SIOCSIFCOMP, (caddr_t) &x) < 0 && errno != ENOTTY)
876         syslog(LOG_ERR, "ioctl (SIOCSIFCOMP): %m");
877 }
878
879 /*
880  * ccp_fatal_error - returns 1 if decompression was disabled as a
881  * result of an error detected after decompression of a packet,
882  * 0 otherwise.  This is necessary because of patent nonsense.
883  */
884 int
885 ccp_fatal_error(unit)
886     int unit;
887 {
888     int x;
889
890     if (ioctl(fd, SIOCGIFCOMP, (caddr_t) &x) < 0) {
891         syslog(LOG_ERR, "ioctl(SIOCGIFCOMP): %m");
892         return 0;
893     }
894     return x & CCP_FATALERROR;
895 }
896
897 /*
898  * sifvjcomp - config tcp header compression
899  */
900 int
901 sifvjcomp(u, vjcomp, cidcomp, maxcid)
902     int u, vjcomp, cidcomp, maxcid;
903 {
904     char x;
905
906     x = (vjcomp? 1: 0) + (cidcomp? 0: 2) + (maxcid << 4);
907     if (ioctl(fd, SIOCSIFVJCOMP, (caddr_t) &x) < 0) {
908         syslog(LOG_ERR, "ioctl(SIOCSIFVJCOMP): %m");
909         return 0;
910     }
911     return 1;
912 }
913
914 /*
915  * sifup - Config the interface up.
916  */
917 int
918 sifup(u)
919     int u;
920 {
921     struct ifreq ifr;
922     struct npioctl npi;
923
924     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
925     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
926         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
927         return 0;
928     }
929     ifr.ifr_flags |= IFF_UP;
930     if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
931         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
932         return 0;
933     }
934     npi.protocol = PPP_IP;
935     npi.mode = NPMODE_PASS;
936     if (ioctl(fd, SIOCSETNPMODE, &npi) < 0) {
937         syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
938         return 0;
939     }
940     return 1;
941 }
942
943 /*
944  * sifdown - Config the interface down.
945  */
946 int
947 sifdown(u)
948     int u;
949 {
950     struct ifreq ifr;
951     int rv;
952     struct npioctl npi;
953
954     rv = 1;
955     npi.protocol = PPP_IP;
956     npi.mode = NPMODE_ERROR;
957     if (ioctl(fd, SIOCSETNPMODE, (caddr_t) &npi) < 0) {
958         syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
959         rv = 0;
960     }
961
962     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
963     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
964         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
965         rv = 0;
966     } else {
967         ifr.ifr_flags &= ~IFF_UP;
968         if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
969             syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
970             rv = 0;
971         }
972     }
973     return rv;
974 }
975
976 /*
977  * sifnpmode - Set the mode for handling packets for a given NP.
978  */
979 int
980 sifnpmode(u, proto, mode)
981     int u;
982     int proto;
983     enum NPmode mode;
984 {
985     struct npioctl npi;
986
987     npi.protocol = proto;
988     npi.mode = mode;
989     if (ioctl(fd, SIOCSETNPMODE, &npi) < 0) {
990         syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
991         return 0;
992     }
993     return 1;
994 }
995
996 /*
997  * SET_SA_FAMILY - initialize a struct sockaddr, setting the sa_family field.
998  */
999 #define SET_SA_FAMILY(addr, family)             \
1000     BZERO((char *) &(addr), sizeof(addr));      \
1001     addr.sa_family = (family);
1002
1003 /*
1004  * sifaddr - Config the interface IP addresses and netmask.
1005  */
1006 int
1007 sifaddr(u, o, h, m)
1008     int u;
1009     u_int32_t o, h, m;
1010 {
1011     int ret;
1012     struct ifreq ifr;
1013
1014     ret = 1;
1015     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1016     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
1017     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
1018     if (ioctl(sockfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
1019         syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
1020         ret = 0;
1021     }
1022     ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
1023     if (ioctl(sockfd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
1024         syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
1025         ret = 0;
1026     }
1027     if (m != 0) {
1028         ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
1029         syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
1030         if (ioctl(sockfd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
1031             syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
1032             ret = 0;
1033         }
1034     }
1035     return ret;
1036 }
1037
1038 /*
1039  * cifaddr - Clear the interface IP addresses, and delete routes
1040  * through the interface if possible.
1041  */
1042 int
1043 cifaddr(u, o, h)
1044     int u;
1045     u_int32_t o, h;
1046 {
1047     struct rtentry rt;
1048
1049     SET_SA_FAMILY(rt.rt_dst, AF_INET);
1050     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
1051     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
1052     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
1053     rt.rt_flags = RTF_HOST;
1054     if (ioctl(sockfd, SIOCDELRT, (caddr_t) &rt) < 0) {
1055         syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
1056         return 0;
1057     }
1058     return 1;
1059 }
1060
1061 /*
1062  * sifdefaultroute - assign a default route through the address given.
1063  */
1064 int
1065 sifdefaultroute(u, g)
1066     int u;
1067     u_int32_t g;
1068 {
1069     struct rtentry rt;
1070
1071     SET_SA_FAMILY(rt.rt_dst, AF_INET);
1072     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
1073     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
1074     rt.rt_flags = RTF_GATEWAY;
1075     if (ioctl(sockfd, SIOCADDRT, &rt) < 0) {
1076         syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
1077         return 0;
1078     }
1079     return 1;
1080 }
1081
1082 /*
1083  * cifdefaultroute - delete a default route through the address given.
1084  */
1085 int
1086 cifdefaultroute(u, g)
1087     int u;
1088     u_int32_t g;
1089 {
1090     struct rtentry rt;
1091
1092     SET_SA_FAMILY(rt.rt_dst, AF_INET);
1093     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
1094     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
1095     rt.rt_flags = RTF_GATEWAY;
1096     if (ioctl(sockfd, SIOCDELRT, &rt) < 0) {
1097         syslog(LOG_ERR, "default route ioctl(SIOCDELRT): %m");
1098         return 0;
1099     }
1100     return 1;
1101 }
1102
1103 /*
1104  * sifproxyarp - Make a proxy ARP entry for the peer.
1105  */
1106 int
1107 sifproxyarp(unit, hisaddr)
1108     int unit;
1109     u_int32_t hisaddr;
1110 {
1111     struct arpreq arpreq;
1112
1113     BZERO(&arpreq, sizeof(arpreq));
1114
1115     /*
1116      * Get the hardware address of an interface on the same subnet
1117      * as our local address.
1118      */
1119     if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
1120         syslog(LOG_WARNING, "Cannot determine ethernet address for proxy ARP");
1121         return 0;
1122     }
1123
1124     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
1125     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
1126     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
1127     if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) {
1128         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
1129         return 0;
1130     }
1131
1132     return 1;
1133 }
1134
1135 /*
1136  * cifproxyarp - Delete the proxy ARP entry for the peer.
1137  */
1138 int
1139 cifproxyarp(unit, hisaddr)
1140     int unit;
1141     u_int32_t hisaddr;
1142 {
1143     struct arpreq arpreq;
1144
1145     BZERO(&arpreq, sizeof(arpreq));
1146     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
1147     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
1148     if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
1149         syslog(LOG_ERR, "ioctl(SIOCDARP): %m");
1150         return 0;
1151     }
1152     return 1;
1153 }
1154
1155 /*
1156  * get_ether_addr - get the hardware address of an interface on the
1157  * the same subnet as ipaddr.  Code borrowed from myetheraddr.c
1158  * in the cslip-2.6 distribution, which is subject to the following
1159  * copyright notice (which also applies to logwtmp below):
1160  *
1161  * Copyright (c) 1990, 1992 The Regents of the University of California.
1162  * All rights reserved.
1163  *
1164  * Redistribution and use in source and binary forms, with or without
1165  * modification, are permitted provided that: (1) source code distributions
1166  * retain the above copyright notice and this paragraph in its entirety, (2)
1167  * distributions including binary code include the above copyright notice and
1168  * this paragraph in its entirety in the documentation or other materials
1169  * provided with the distribution, and (3) all advertising materials mentioning
1170  * features or use of this software display the following acknowledgement:
1171  * ``This product includes software developed by the University of California,
1172  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1173  * the University nor the names of its contributors may be used to endorse
1174  * or promote products derived from this software without specific prior
1175  * written permission.
1176  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1177  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1178  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1179  */
1180
1181 #include <fcntl.h>
1182 #include <nlist.h>
1183 #include <kvm.h>
1184
1185 /* XXX SunOS 4.1 defines this and 3.5 doesn't... */
1186 #ifdef _nlist_h
1187 #define SUNOS4
1188 #endif
1189
1190 #ifdef SUNOS4
1191 #include <netinet/in_var.h>
1192 #endif
1193 #include <netinet/if_ether.h>
1194
1195 /* Cast a struct sockaddr to a structaddr_in */
1196 #define SATOSIN(sa) ((struct sockaddr_in *)(sa))
1197
1198 /* Determine if "bits" is set in "flag" */
1199 #define ALLSET(flag, bits) (((flag) & (bits)) == (bits))
1200
1201 static struct nlist nl[] = {
1202 #define N_IFNET 0
1203         { "_ifnet" },
1204         { 0 }
1205 };
1206
1207 static void kread();
1208
1209 int
1210 get_ether_addr(ipaddr, hwaddr)
1211     u_int32_t ipaddr;
1212     struct sockaddr *hwaddr;
1213 {
1214     register kvm_t *kd;
1215     register struct ifnet *ifp;
1216     register struct arpcom *ac;
1217     struct arpcom arpcom;
1218     struct in_addr *inp;
1219 #ifdef SUNOS4
1220     register struct ifaddr *ifa;
1221     register struct in_ifaddr *in;
1222     union {
1223         struct ifaddr ifa;
1224         struct in_ifaddr in;
1225     } ifaddr;
1226 #endif
1227     u_int32_t addr, mask;
1228
1229     /* Open kernel memory for reading */
1230     kd = kvm_open(0, 0, 0, O_RDONLY, NULL);
1231     if (kd == 0) {
1232         syslog(LOG_ERR, "kvm_open: %m");
1233         return 0;
1234     }
1235
1236     /* Fetch namelist */
1237     if (kvm_nlist(kd, nl) != 0) {
1238         syslog(LOG_ERR, "kvm_nlist failed");
1239         return 0;
1240     }
1241
1242     ac = &arpcom;
1243     ifp = &arpcom.ac_if;
1244 #ifdef SUNOS4
1245     ifa = &ifaddr.ifa;
1246     in = &ifaddr.in;
1247 #endif
1248
1249     if (kvm_read(kd, nl[N_IFNET].n_value, (char *)&addr, sizeof(addr))
1250         != sizeof(addr)) {
1251         syslog(LOG_ERR, "error reading ifnet addr");
1252         return 0;
1253     }
1254     for ( ; addr; addr = (u_int32_t)ifp->if_next) {
1255         if (kvm_read(kd, addr, (char *)ac, sizeof(*ac)) != sizeof(*ac)) {
1256             syslog(LOG_ERR, "error reading ifnet");
1257             return 0;
1258         }
1259
1260         /* Only look at configured, broadcast interfaces */
1261         if (!ALLSET(ifp->if_flags, IFF_UP | IFF_BROADCAST))
1262             continue;
1263 #ifdef SUNOS4
1264         /* This probably can't happen... */
1265         if (ifp->if_addrlist == 0)
1266             continue;
1267 #endif
1268
1269         /* Get interface ip address */
1270 #ifdef SUNOS4
1271         if (kvm_read(kd, (u_int32_t)ifp->if_addrlist, (char *)&ifaddr,
1272                      sizeof(ifaddr)) != sizeof(ifaddr)) {
1273             syslog(LOG_ERR, "error reading ifaddr");
1274             return 0;
1275         }
1276         inp = &SATOSIN(&ifa->ifa_addr)->sin_addr;
1277 #else
1278         inp = &SATOSIN(&ifp->if_addr)->sin_addr;
1279 #endif
1280
1281         /* Check if this interface on the right subnet */
1282 #ifdef SUNOS4
1283         mask = in->ia_subnetmask;
1284 #else
1285         mask = ifp->if_subnetmask;
1286 #endif
1287         if ((ipaddr & mask) != (inp->s_addr & mask))
1288             continue;
1289
1290         /* Copy out the local ethernet address */
1291         hwaddr->sa_family = AF_UNSPEC;
1292         BCOPY((caddr_t) &arpcom.ac_enaddr, hwaddr->sa_data,
1293               sizeof(arpcom.ac_enaddr));
1294         return 1;               /* success! */
1295     }
1296
1297     /* couldn't find one */
1298     return 0;
1299 }
1300
1301 #define WTMPFILE        "/usr/adm/wtmp"
1302
1303 int
1304 logwtmp(line, name, host)
1305     char *line, *name, *host;
1306 {
1307     int fd;
1308     struct stat buf;
1309     struct utmp ut;
1310
1311     if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
1312         return;
1313     if (!fstat(fd, &buf)) {
1314         (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
1315         (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
1316         (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
1317         (void)time(&ut.ut_time);
1318         if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
1319             (void)ftruncate(fd, buf.st_size);
1320     }
1321     close(fd);
1322 }
1323
1324 /*
1325  * Return user specified netmask, modified by any mask we might determine
1326  * for address `addr' (in network byte order).
1327  * Here we scan through the system's list of interfaces, looking for
1328  * any non-point-to-point interfaces which might appear to be on the same
1329  * network as `addr'.  If we find any, we OR in their netmask to the
1330  * user-specified netmask.
1331  */
1332 #define MAX_IFS         32
1333
1334 u_int32_t
1335 GetMask(addr)
1336     u_int32_t addr;
1337 {
1338     u_int32_t mask, nmask, ina;
1339     struct ifreq *ifr, *ifend, ifreq;
1340     struct ifconf ifc;
1341     struct ifreq ifs[MAX_IFS];
1342
1343     addr = ntohl(addr);
1344     if (IN_CLASSA(addr))        /* determine network mask for address class */
1345         nmask = IN_CLASSA_NET;
1346     else if (IN_CLASSB(addr))
1347         nmask = IN_CLASSB_NET;
1348     else
1349         nmask = IN_CLASSC_NET;
1350     /* class D nets are disallowed by bad_ip_adrs */
1351     mask = netmask | htonl(nmask);
1352
1353     /*
1354      * Scan through the system's network interfaces.
1355      */
1356     ifc.ifc_len = sizeof(ifs);
1357     ifc.ifc_req = ifs;
1358     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1359         syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m");
1360         return mask;
1361     }
1362     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1363     for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
1364         /*
1365          * Check the interface's internet address.
1366          */
1367         if (ifr->ifr_addr.sa_family != AF_INET)
1368             continue;
1369         ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1370         if ((ntohl(ina) & nmask) != (addr & nmask))
1371             continue;
1372         /*
1373          * Check that the interface is up, and not point-to-point or loopback.
1374          */
1375         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1376         if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1377             continue;
1378         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1379             != IFF_UP)
1380             continue;
1381         /*
1382          * Get its netmask and OR it into our mask.
1383          */
1384         if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1385             continue;
1386         mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
1387     }
1388
1389     return mask;
1390 }
1391
1392 /*
1393  * Code for locking/unlocking the serial device.
1394  * This code is derived from chat.c.
1395  */
1396
1397 #if defined(SUNOS) && SUNOS >= 41 && !defined(HDB)
1398 #define HDB     1
1399 #endif
1400
1401 #ifndef LOCK_DIR
1402 # ifdef HDB
1403 #  define       PIDSTRING
1404 #  define       LOCK_PREFIX     "/usr/spool/locks/LCK.."
1405 # else /* HDB */
1406 #  define       LOCK_PREFIX     "/usr/spool/uucp/LCK.."
1407 # endif /* HDB */
1408 #endif /* LOCK_DIR */
1409
1410 /*
1411  * lock - create a lock file for the named device.
1412  */
1413 int
1414 lock(dev)
1415     char *dev;
1416 {
1417     char hdb_lock_buffer[12];
1418     int fd, pid, n;
1419     char *p;
1420
1421     if ((p = strrchr(dev, '/')) != NULL)
1422         dev = p + 1;
1423     lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1);
1424     if (lock_file == NULL)
1425         novm("lock file name");
1426     strcat(strcpy(lock_file, LOCK_PREFIX), dev);
1427
1428     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
1429         if (errno == EEXIST
1430             && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
1431             /* Read the lock file to find out who has the device locked */
1432 #ifdef PIDSTRING
1433             n = read(fd, hdb_lock_buffer, 11);
1434             if (n > 0) {
1435                 hdb_lock_buffer[n] = 0;
1436                 pid = atoi(hdb_lock_buffer);
1437             }
1438 #else
1439             n = read(fd, &pid, sizeof(pid));
1440 #endif
1441             if (n <= 0) {
1442                 syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
1443                 close(fd);
1444             } else {
1445                 if (kill(pid, 0) == -1 && errno == ESRCH) {
1446                     /* pid no longer exists - remove the lock file */
1447                     if (unlink(lock_file) == 0) {
1448                         close(fd);
1449                         syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)",
1450                                dev, pid);
1451                         continue;
1452                     } else
1453                         syslog(LOG_WARNING, "Couldn't remove stale lock on %s",
1454                                dev);
1455                 } else
1456                     syslog(LOG_NOTICE, "Device %s is locked by pid %d",
1457                            dev, pid);
1458             }
1459             close(fd);
1460         } else
1461             syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
1462         free(lock_file);
1463         lock_file = NULL;
1464         return -1;
1465     }
1466
1467 #ifdef PIDSTRING
1468     sprintf(hdb_lock_buffer, "%10d\n", getpid());
1469     write(fd, hdb_lock_buffer, 11);
1470 #else
1471     pid = getpid();
1472     write(fd, &pid, sizeof pid);
1473 #endif
1474
1475     close(fd);
1476     return 0;
1477 }
1478
1479 /*
1480  * unlock - remove our lockfile
1481  */
1482 void
1483 unlock()
1484 {
1485     if (lock_file) {
1486         unlink(lock_file);
1487         free(lock_file);
1488         lock_file = NULL;
1489     }
1490 }