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