Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sbin / startslip / startslip.c
1 /*-
2  * Copyright (c) 1990, 1991, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#) Copyright (c) 1990, 1991, 1993 The Regents of the University of California.  All rights reserved.
34  * @(#)startslip.c      8.1 (Berkeley) 6/5/93
35  * $FreeBSD: src/sbin/startslip/startslip.c,v 1.31.2.1 2000/05/07 18:26:51 joe Exp $
36  * $DragonFly: src/sbin/startslip/startslip.c,v 1.2 2003/06/17 04:27:34 dillon Exp $
37  */
38
39 #include <sys/types.h>
40 #include <sys/time.h>
41
42 #include <err.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <libutil.h>
46 #include <paths.h>
47 #include <signal.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <syslog.h>
52 #include <termios.h>
53 #include <unistd.h>
54
55 #include <net/slip.h>
56
57 #define DEFAULT_BAUD    B9600
58 int     speed = DEFAULT_BAUD;
59 #define FC_NONE         0       /* flow control: none */
60 #define FC_HW           1       /* flow control: hardware (RTS/CTS) */
61 int     flowcontrol = FC_NONE;
62 int     modem_control = 1;      /* !CLOCAL+HUPCL iff we watch carrier. */
63 int     sl_unit = -1;
64 int     uucp_lock = 0;          /* uucp locking */
65 char    *annex;
66 char    *username;
67 int     hup;
68 int     terminate;
69 int     locked = 0;             /* uucp lock active */
70 int     logged_in = 0;
71 int     wait_time = 60;         /* then back off */
72 int     script_timeout = 90;    /* connect script default timeout */
73 time_t  conn_time, start_time;
74 int     MAXTRIES = 6;           /* w/60 sec and doubling, takes an hour */
75 #define PIDFILE         "%sstartslip.%s.pid"
76
77 #define MAXDIALS 20
78 char *dials[MAXDIALS];
79 int diali, dialc;
80
81 int fd = -1;
82 FILE *pfd;
83 char *dvname, *devicename;
84 char pidfile[80];
85
86 #ifdef DEBUG
87 int     debug = 1;
88 #undef LOG_ERR
89 #undef LOG_INFO
90 #define syslog fprintf
91 #define LOG_ERR stderr
92 #define LOG_INFO stderr
93 #else
94 int     debug = 0;
95 #endif
96 #define printd  if (debug) printf
97
98 int carrier __P((void));
99 void down __P((int));
100 int getline __P((char *, int, int, time_t));
101 static void usage __P((void));
102
103 int
104 main(argc, argv)
105         int argc;
106         char **argv;
107 {
108         char *cp, **ap;
109         int ch, disc;
110         void sighup(), sigterm(), sigurg();
111         FILE *wfd = NULL;
112         char *dialerstring = 0, buf[BUFSIZ];
113         int unitnum, keepal = 0, outfill = 0;
114         char unitname[32];
115         char *password;
116         char *upscript = NULL, *downscript = NULL;
117         int first = 1, tries = 0;
118         time_t fintimeout;
119         long lpid;
120         pid_t pid;
121         struct termios t;
122
123         while ((ch = getopt(argc, argv, "dhlb:s:t:w:A:U:D:W:K:O:S:L")) != -1)
124                 switch (ch) {
125                 case 'd':
126                         debug = 1;
127                         break;
128                 case 'b':
129                         speed = atoi(optarg);
130                         break;
131                 case 's':
132                         if (diali >= MAXDIALS)
133                                 errx(1, "max dial strings number (%d) exceeded", MAXDIALS);
134                         dials[diali++] = strdup(optarg);
135                         break;
136                 case 't':
137                         script_timeout = atoi(optarg);
138                         break;
139                 case 'w':
140                         wait_time = atoi(optarg);
141                         break;
142                 case 'W':
143                         MAXTRIES = atoi(optarg);
144                         break;
145                 case 'A':
146                         annex = strdup(optarg);
147                         break;
148                 case 'U':
149                         upscript = strdup(optarg);
150                         break;
151                 case 'D':
152                         downscript = strdup(optarg);
153                         break;
154                 case 'L':
155                         uucp_lock = 1;
156                         break;
157                 case 'l':
158                         modem_control = 0;
159                         break;
160                 case 'h':
161                         flowcontrol = FC_HW;
162                         break;
163                 case 'K':
164                         keepal = atoi(optarg);
165                         break;
166                 case 'O':
167                         outfill = atoi(optarg);
168                         break;
169                 case 'S':
170                         sl_unit = atoi(optarg);
171                         break;
172                 case '?':
173                 default:
174                         usage();
175                 }
176         argc -= optind;
177         argv += optind;
178
179         if (argc != 3)
180                 usage();
181
182         /*
183          * Copy these so they exist after we clobber them.
184          */
185         devicename = strdup(argv[0]);
186         username = strdup(argv[1]);
187         password = strdup(argv[2]);
188
189         /*
190          * Security hack.  Do not want private information such as the
191          * password and possible phone number to be left around.
192          * So we clobber the arguments.
193          */
194         for (ap = argv - optind + 1; ap < argv + 3; ap++)
195                 for (cp = *ap; *cp != 0; cp++)
196                         *cp = '\0';
197
198         openlog("startslip", LOG_PID|LOG_PERROR, LOG_DAEMON);
199
200         if (debug)
201                 setbuf(stdout, NULL);
202
203         signal(SIGTERM, sigterm);
204         if ((dvname = strrchr(devicename, '/')) == NULL)
205                 dvname = devicename;
206         else
207                 dvname++;
208         if (snprintf(pidfile, sizeof(pidfile), PIDFILE, _PATH_VARRUN, dvname) >= sizeof(pidfile))
209                 usage();
210
211         if ((pfd = fopen(pidfile, "r")) != NULL) {
212                 if (fscanf(pfd, "%ld\n", &lpid) == 1) {
213                         pid = lpid;
214                         if (pid == lpid && pid > 0)
215                                 kill(pid, SIGTERM);
216                 }
217                 fclose(pfd);
218                 pfd = NULL;     /* not remove pidfile yet */
219                 sleep(5);       /* allow down script to be completed */
220         } else
221 restart:
222         signal(SIGHUP, SIG_IGN);
223         signal(SIGURG, SIG_IGN);
224         hup = 0;
225         if (wfd) {
226                 printd("fclose, ");
227                 fclose(wfd);
228                 conn_time = time(NULL) - start_time;
229                 if (uucp_lock)
230                         uu_unlock(dvname);
231                 locked = 0;
232                 wfd = NULL;
233                 fd = -1;
234                 sleep(5);
235         } else if (fd >= 0) {
236                 printd("close, ");
237                 close(fd);
238                 conn_time = time(NULL) - start_time;
239                 if (uucp_lock)
240                         uu_unlock(dvname);
241                 locked = 0;
242                 fd = -1;
243                 sleep(5);
244         }
245         if (logged_in) {
246                 syslog(LOG_INFO, "%s: connection time elapsed: %ld secs",
247                     username, (long)conn_time);
248                 sprintf(buf, "LINE=%d %s %s down",
249                 diali ? (dialc - 1) % diali : 0,
250                 downscript ? downscript : "/sbin/ifconfig" , unitname);
251                 (void) system(buf);
252                 logged_in = 0;
253         }
254         if (terminate)
255                 down(0);
256         tries++;
257         if (MAXTRIES > 0 && tries > MAXTRIES) {
258                 syslog(LOG_ERR, "%s: exiting login after %d tries", username, tries);
259                 /* ???
260                 if (first)
261                 */
262                         down(3);
263         }
264         if (tries > 1) {
265                 syslog(LOG_INFO, "%s: sleeping %d seconds (%d tries)",
266                         username, wait_time * (tries - 1), tries);
267                 sleep(wait_time * (tries - 1));
268                 if (terminate)
269                         goto restart;
270         }
271
272         if (daemon(1, debug) < 0) {
273                 syslog(LOG_ERR, "%s: daemon: %m", username);
274                 down(2);
275         }
276
277         pid = getpid();
278         printd("restart: pid %ld: ", (long)pid);
279         if ((pfd = fopen(pidfile, "w")) != NULL) {
280                 fprintf(pfd, "%ld\n", (long)pid);
281                 fclose(pfd);
282         }
283         printd("open");
284         if (uucp_lock) {
285                 int res;
286                 if ((res = uu_lock(dvname)) != UU_LOCK_OK) {
287                         if (res != UU_LOCK_INUSE)
288                                 syslog(LOG_ERR, "uu_lock: %s", uu_lockerr(res));
289                         syslog(LOG_ERR, "%s: can't lock %s", username, devicename);
290                         goto restart;
291                 }
292                 locked = 1;
293         }
294         if ((fd = open(devicename, O_RDWR | O_NONBLOCK)) < 0) {
295                 syslog(LOG_ERR, "%s: open %s: %m", username, devicename);
296                 if (first)
297                         down(1);
298                 else {
299                         if (uucp_lock)
300                                 uu_unlock(dvname);
301                         locked = 0;
302                         goto restart;
303                 }
304         }
305         printd(" %d", fd);
306         signal(SIGHUP, sighup);
307         if (ioctl(fd, TIOCSCTTY, 0) < 0) {
308                 syslog(LOG_ERR, "%s: ioctl (TIOCSCTTY): %m", username);
309                 down(2);
310         }
311         if (tcsetpgrp(fd, getpid()) < 0) {
312                 syslog(LOG_ERR, "%s: tcsetpgrp failed: %m", username);
313                 down(2);
314         }
315         printd(", ioctl\n");
316         if (tcgetattr(fd, &t) < 0) {
317                 syslog(LOG_ERR, "%s: tcgetattr(%s): %m", username, devicename);
318                 down(2);
319         }
320         cfmakeraw(&t);
321         switch (flowcontrol) {
322         case FC_HW:
323                 t.c_cflag |= (CRTS_IFLOW|CCTS_OFLOW);
324                 break;
325         case FC_NONE:
326                 t.c_cflag &= ~(CRTS_IFLOW|CCTS_OFLOW);
327                 break;
328         }
329         if (modem_control)
330                 t.c_cflag |= HUPCL;
331         else
332                 t.c_cflag &= ~(HUPCL);
333         t.c_cflag |= CLOCAL;    /* until modem commands passes */
334         cfsetispeed(&t, speed);
335         cfsetospeed(&t, speed);
336         if (tcsetattr(fd, TCSAFLUSH, &t) < 0) {
337                 syslog(LOG_ERR, "%s: tcsetattr(%s): %m", username, devicename);
338                 down(2);
339         }
340         sleep(2);               /* wait for flakey line to settle */
341         if (hup || terminate)
342                 goto restart;
343
344         wfd = fdopen(fd, "w+");
345         if (wfd == NULL) {
346                 syslog(LOG_ERR, "%s: can't fdopen %s: %m", username, devicename);
347                 down(2);
348         }
349         setbuf(wfd, NULL);
350
351         if (diali > 0)
352                 dialerstring = dials[dialc++ % diali];
353         if (dialerstring) {
354                 syslog(LOG_INFO, "%s: dialer string: %s\\r", username, dialerstring);
355                 fprintf(wfd, "%s\r", dialerstring);
356         }
357         printd("\n");
358
359         fintimeout = time(NULL) + script_timeout;
360         if (modem_control) {
361                 printd("waiting for carrier\n");
362                 while (time(NULL) < fintimeout && !carrier()) {
363                         sleep(1);
364                         if (hup || terminate)
365                                 goto restart;
366                 }
367                 if (!carrier())
368                         goto restart;
369                 t.c_cflag &= ~(CLOCAL);
370                 if (tcsetattr(fd, TCSANOW, &t) < 0) {
371                         syslog(LOG_ERR, "%s: tcsetattr(%s): %m", username, devicename);
372                         down(2);
373                 }
374                 /* Only now we able to receive HUP on carrier drop! */
375         }
376
377         /*
378          * Log in
379          */
380         printd("look for login: ");
381         for (;;) {
382                 if (getline(buf, BUFSIZ, fd, fintimeout) == 0 || hup || terminate)
383                         goto restart;
384                 if (annex) {
385                         if (bcmp(buf, annex, strlen(annex)) == 0) {
386                                 fprintf(wfd, "slip\r");
387                                 printd("Sent \"slip\"\n");
388                                 continue;
389                         }
390                         if (bcmp(&buf[1], "sername:", 8) == 0) {
391                                 fprintf(wfd, "%s\r", username);
392                                 printd("Sent login: %s\n", username);
393                                 continue;
394                         }
395                         if (bcmp(&buf[1], "assword:", 8) == 0) {
396                                 fprintf(wfd, "%s\r", password);
397                                 printd("Sent password: %s\n", password);
398                                 break;
399                         }
400                 } else {
401                         if (strstr(&buf[1], "ogin:") != NULL) {
402                                 fprintf(wfd, "%s\r", username);
403                                 printd("Sent login: %s\n", username);
404                                 continue;
405                         }
406                         if (strstr(&buf[1], "assword:") != NULL) {
407                                 fprintf(wfd, "%s\r", password);
408                                 printd("Sent password: %s\n", password);
409                                 break;
410                         }
411                 }
412         }
413
414         sleep(5);       /* Wait until login completed */
415         if (hup || terminate)
416                 goto restart;
417         start_time = time(NULL);
418         /*
419          * Attach
420          */
421         printd("setd");
422         disc = SLIPDISC;
423         if (ioctl(fd, TIOCSETD, &disc) < 0) {
424                 syslog(LOG_ERR, "%s: ioctl (%s, TIOCSETD): %m",
425                     username, devicename);
426                 down(2);
427         }
428         if (sl_unit >= 0 && ioctl(fd, SLIOCSUNIT, &sl_unit) < 0) {
429                 syslog(LOG_ERR, "%s: ioctl(SLIOCSUNIT): %m", username);
430                 down(2);
431         }
432         if (ioctl(fd, SLIOCGUNIT, &unitnum) < 0) {
433                 syslog(LOG_ERR, "%s: ioctl(SLIOCGUNIT): %m", username);
434                 down(2);
435         }
436         sprintf(unitname, "sl%d", unitnum);
437
438         if (keepal > 0) {
439                 signal(SIGURG, sigurg);
440                 if (ioctl(fd, SLIOCSKEEPAL, &keepal) < 0) {
441                         syslog(LOG_ERR, "%s: ioctl(SLIOCSKEEPAL): %m", username);
442                         down(2);
443                 }
444         }
445         if (outfill > 0 && ioctl(fd, SLIOCSOUTFILL, &outfill) < 0) {
446                 syslog(LOG_ERR, "%s: ioctl(SLIOCSOUTFILL): %m", username);
447                 down(2);
448         }
449
450         sprintf(buf, "LINE=%d %s %s up",
451                 diali ? (dialc - 1) % diali : 0,
452                 upscript ? upscript : "/sbin/ifconfig" , unitname);
453         (void) system(buf);
454
455         printd(", ready\n");
456         if (!first)
457                 syslog(LOG_INFO, "%s: reconnected on %s (%d tries)", username, unitname, tries);
458         else
459                 syslog(LOG_INFO, "%s: connected on %s", username, unitname);
460         first = 0;
461         tries = 0;
462         logged_in = 1;
463         while (hup == 0 && terminate == 0) {
464                 sigpause(0L);
465                 printd("sigpause return\n");
466         }
467         goto restart;
468         return(0); /* not reached */
469 }
470
471 void
472 sighup()
473 {
474
475         printd("hup\n");
476         if (hup == 0 && logged_in)
477                 syslog(LOG_INFO, "%s: got hangup signal", username);
478         hup = 1;
479 }
480
481 void
482 sigurg()
483 {
484
485         printd("urg\n");
486         if (hup == 0 && logged_in)
487                 syslog(LOG_INFO, "%s: got dead line signal", username);
488         hup = 1;
489 }
490
491 void
492 sigterm()
493 {
494
495         printd("terminate\n");
496         if (terminate == 0 && logged_in)
497                 syslog(LOG_INFO, "%s: got terminate signal", username);
498         terminate = 1;
499 }
500
501 int
502 getline(buf, size, fd, fintimeout)
503         char *buf;
504         int size, fd;
505         time_t fintimeout;
506 {
507         register int i;
508         int ret;
509         fd_set readfds;
510         struct timeval tv;
511         time_t timeout;
512
513         size--;
514         for (i = 0; i < size; i++) {
515                 if (hup || terminate)
516                         return (0);
517                 if ((timeout = fintimeout - time(NULL)) <= 0)
518                         goto tout;
519                 FD_ZERO(&readfds);
520                 FD_SET(fd, &readfds);
521                 tv.tv_sec = timeout;
522                 tv.tv_usec = 0;
523                 if ((ret = select(fd + 1, &readfds, NULL, NULL, &tv)) < 0) {
524                         if (errno != EINTR)
525                                 syslog(LOG_ERR, "%s: getline: select: %m", username);
526                 } else {
527                         if (! ret) {
528                         tout:
529                                 printd("getline: timed out\n");
530                                 return (0);
531                         }
532                         if ((ret = read(fd, &buf[i], 1)) == 1) {
533                                 buf[i] &= 0177;
534                                 if (buf[i] == '\r' || buf[i] == '\0') {
535                                         i--;
536                                         continue;
537                                 }
538                                 if (buf[i] != '\n' && buf[i] != ':')
539                                         continue;
540                                 buf[i + 1] = '\0';
541                                 printd("Got %d: %s", i + 1, buf);
542                                 return (i+1);
543                         }
544                         if (ret <= 0) {
545                                 if (ret < 0) {
546                                         syslog(LOG_ERR, "%s: getline: read: %m", username);
547                                 } else
548                                         syslog(LOG_ERR, "%s: read returned 0", username);
549                                 buf[i] = '\0';
550                                 printd("returning %d after %d: %s\n", ret, i, buf);
551                                 return (0);
552                         }
553                 }
554         }
555         return (0);
556 }
557
558 int
559 carrier()
560 {
561         int comstate;
562
563         if (ioctl(fd, TIOCMGET, &comstate) < 0) {
564                 syslog(LOG_ERR, "%s: ioctl (%s, TIOCMGET): %m",
565                     username, devicename);
566                 down(2);
567         }
568         return !!(comstate & TIOCM_CD);
569 }
570
571 void
572 down(code)
573 {
574         if (fd > -1)
575                 close(fd);
576         if (pfd)
577                 unlink(pidfile);
578         if (uucp_lock && locked)
579                 uu_unlock(dvname);
580         exit(code);
581 }
582
583 static void
584 usage()
585 {
586         (void)fprintf(stderr, "%s\n%s\n%s\n%s\n",  
587 "usage: startslip [-d] [-b speed] [-s string1 [-s string2 [...]]] [-h] [-l]",
588 "                 [-L] [-A annexname] [-U upscript] [-D downscript]",
589 "                 [-t script_timeout] [-W maxtries] [-w retry_pause]",
590 "                 [-K keepalive] [-O outfill] [-S unit] device user passwd");
591         exit(1);
592 }