This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / sbin / slattach / slattach.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1988 Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Adams.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
78ed81a3 37/*
38 * Hacks to support "-a|c|n" flags on the command line which enable VJ
39 * header compresion and disable ICMP.
40 * If this is good all rights go to B & L Jolitz, otherwise send your
41 * comments to Reagan (/dev/null).
42 *
43 * nerd@percival.rain.com (Michael Galassi) 92.09.03
44 *
45 * Hacked to change from sgtty to POSIX termio style serial line control
46 * and added flag to enable cts/rts style flow control.
47 *
48 * blymn@awadi.com.au (Brett Lymn) 93.04.04
49 *
50 * Put slattach in it's own process group so it can't be killed
51 * accidentally. Close the connection on SIGHUP and SIGINT. Write a
52 * syslog entry upon opening and closing the connection. Rich Murphey
53 * and Brad Huntting.
54 *
55 * Add '-r command' option: runs 'command' upon recieving SIGHUP
56 * resulting from loss of carrier. Log any errors after forking.
57 * Rich 8/13/93
58 *
59 * This version of slattach includes many changes by David Greenman, Brian
60 * Smith, Chris Bradley, and me (Michael Galassi). None of them are
61 * represented as functional anywhere outside of RAINet though they do work
62 * for us. Documentation is limited to the usage message for now. If you
63 * make improovments please pass them back.
64 *
65 * Added '-u UCMD' which runs 'UCMD <old> <new>' whenever the slip
66 * unit number changes where <old> and <new> are the old and new unit
67 * numbers, respectively. Also added the '-z' option which forces
68 * invocation of the redial command (-r CMD) upon startup regardless
69 * of whether the com driver claims (sometimes mistakenly) that
70 * carrier is present. Also added '-e ECMD' which runs ECMD before
71 * exiting.
72 *
73 * marc@escargot.rain.com (Marc Frajola) 93/09/10
74 *
75 * Minor fixes to allow passive SLIP links to work (connections with
76 * modem control that do not have an associated dial command). Added
77 * code to re-check for carrier after dial command has been executed.
78 * Added SIGTERM handler to properly handle normal kill signals. Fixed
79 * bug in logic that caused message about no -u command to be logged
80 * even when -u was specified and the sl number changes. Tried to get
81 * rid of redundant syslog()'s to minimize console log output. Improved
82 * logging of improper command line options or number of command
83 * arguments. Removed spurious newline characters from syslog() calls.
84 */
85
15637ed4
RG
86#ifndef lint
87char copyright[] =
88"@(#) Copyright (c) 1988 Regents of the University of California.\n\
89 All rights reserved.\n";
90#endif /* not lint */
91
92#ifndef lint
78ed81a3 93/*static char sccsid[] = "from: @(#)slattach.c 4.6 (Berkeley) 6/1/90";*/
94static char rcsid[] = "$Id";
15637ed4
RG
95#endif /* not lint */
96
97#include <sys/param.h>
78ed81a3 98#include <sys/ioctl.h>
99#include <termios.h>
15637ed4
RG
100#include <sys/socket.h>
101#include <netinet/in.h>
102#include <net/if.h>
78ed81a3 103#include <net/if_slvar.h>
15637ed4
RG
104#include <netdb.h>
105#include <fcntl.h>
78ed81a3 106#include <stdlib.h>
15637ed4 107#include <stdio.h>
78ed81a3 108#include <unistd.h>
15637ed4 109#include <paths.h>
78ed81a3 110#include <syslog.h>
111#include <signal.h>
112#include <strings.h>
113
114extern int errno;
115extern char *sys_errlist[];
15637ed4
RG
116
117#define DEFAULT_BAUD 9600
78ed81a3 118
119void sighup_handler(); /* SIGHUP handler */
120void sigint_handler(); /* SIGINT handler */
121void sigterm_handler(); /* SIGTERM handler */
122void exit_handler(int ret); /* run exit_cmd iff specified upon exit. */
123void setup_line(); /* configure slip line */
124void attach_line(); /* switch to slip line discipline */
125
126int fd = -1;
127char *dev = (char *)0;
15637ed4 128int slipdisc = SLIPDISC;
78ed81a3 129int ttydisc = TTYDISC;
130int flow_control = 0; /* non-zero to enable hardware flow control. */
131int modem_control = 0; /* non-zero iff we watch carrier. */
132int comstate; /* TIOCMGET current state of serial driver */
133int redial_on_startup = 0; /* iff non-zero execute redial_cmd on startup */
134int speed = DEFAULT_BAUD;
135int slflags = 0; /* compression flags */
136int unit = -1; /* slip device unit number */
137int foreground = 0;
138FILE *console;
15637ed4
RG
139
140char devname[32];
141char hostname[MAXHOSTNAMELEN];
78ed81a3 142char *redial_cmd = 0; /* command to exec upon shutdown. */
143char *config_cmd = 0; /* command to exec if slip unit changes. */
144char *exit_cmd = 0; /* command to exec before exiting. */
145char string[100];
146
147static char usage_str[] = "\
148usage: %s [-acfhlnz] [-e command] [-r command] [-s speed] [-u command] device\n\
149 -a -- autoenable VJ compression\n\
150 -c -- enable VJ compression\n\
151 -e ECMD -- run ECMD before exiting\n\
152 -f -- run in foreground (don't detach from controlling tty)\n\
153 -h -- turn on cts/rts style flow control\n\
154 -l -- disable modem control (CLOCAL) and ignore carrier detect\n\
155 -n -- throw out ICMP packets\n\
156 -r RCMD -- run RCMD upon loss of carrier\n\
157 -s # -- set baud rate (default 9600)\n\
158 -u UCMD -- run 'UCMD <old sl#> <new sl#>' before switch to slip discipline\n\
159 -z -- run RCMD upon startup irrespective of carrier\n";
15637ed4 160
78ed81a3 161int main(int argc, char **argv)
15637ed4 162{
78ed81a3 163 int option;
164 char name[32];
165 extern char *optarg;
166 extern int optind;
167
168 while ((option = getopt(argc, argv, "ace:fhlnr:s:u:z")) != EOF) {
169 switch (option) {
170 case 'a':
171 slflags |= SC_AUTOCOMP;
172 slflags &= ~SC_COMPRESS;
173 break;
174 case 'c':
175 slflags |= SC_COMPRESS;
176 slflags &= ~SC_AUTOCOMP;
177 break;
178 case 'e':
179 exit_cmd = (char*) strdup (optarg);
180 break;
181 case 'f':
182 foreground = 1;
183 break;
184 case 'h':
185 flow_control |= CRTSCTS;
186 break;
187 case 'l':
188 modem_control |= CLOCAL;
189 break;
190 case 'n':
191 slflags |= SC_NOICMP;
192 break;
193 case 'r':
194 redial_cmd = (char*) strdup (optarg);
195 break;
196 case 's':
197 speed = atoi(optarg);
198 break;
199 case 'u':
200 config_cmd = (char*) strdup (optarg);
201 break;
202 case 'z':
203 redial_on_startup = 1;
204 break;
205 default:
206 fprintf(stderr, "%s: Invalid option -- '%c'\n",
207 option);
208 case '?':
209 fprintf(stderr, usage_str, argv[0]);
210 exit_handler(1);
211 }
212 }
213
214 if (optind == argc - 1)
215 dev = argv[optind];
216
217 if (optind < (argc - 1)) {
218 fprintf(stderr, "%s: Too many args, first='%s'\n",
219 argv[0], argv[optind]);
220 }
221 if (optind > (argc - 1)) {
222 fprintf(stderr, "%s: Not enough args\n", argv[0]);
15637ed4 223 }
78ed81a3 224 if (dev == (char *)0) {
225 fprintf(stderr, usage_str, argv[0]);
226 exit_handler(2);
15637ed4
RG
227 }
228 if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) {
78ed81a3 229 strcpy(devname, _PATH_DEV);
230 strcat(devname, "/");
231 strncat(devname, dev, 10);
15637ed4
RG
232 dev = devname;
233 }
78ed81a3 234
235 if (!foreground)
236 daemon(0,0); /* fork, setsid, chdir /, and close std*. */
237
238 /* Note: daemon() closes stderr, so log errors from here on. */
239 (void)sprintf(name,"slattach[%d]", getpid());
240 openlog(name,LOG_CONS,LOG_DAEMON);
241
242 if ((fd = open(dev, O_RDWR | O_NONBLOCK)) < 0) {
243 syslog(LOG_ERR, "open(%s): %m", dev);
244 exit_handler(1);
245 }
246 /* acquire the serial line as a controling terminal. */
247 if (ioctl(fd, TIOCSCTTY, 0) < 0)
248 syslog(LOG_NOTICE,"ioctl(TIOCSCTTY) failed: %s: %m");
249 /* Make us the foreground process group associated with the
250 slip line which is our controlling terminal. */
251 if (tcsetpgrp(fd, getpid()) < 0)
252 syslog(LOG_NOTICE,"tcsetpgrp failed: %s: %m");
253 /* upon INT log a timestamp and exit. */
254 if ((int)signal(SIGINT,sigint_handler) < 0)
255 syslog(LOG_NOTICE,"cannot install SIGINT handler: %s: %m");
256 /* upon TERM log a timestamp and exit. */
257 if ((int)signal(SIGTERM,sigterm_handler) < 0)
258 syslog(LOG_NOTICE,"cannot install SIGTERM handler: %s: %m");
259 /* upon HUP redial and reconnect. */
260 if ((int)signal(SIGHUP,sighup_handler) < 0)
261 syslog(LOG_NOTICE,"cannot install SIGHUP handler: %s: %m");
262
263 setup_line();
264
265 if (redial_on_startup)
266 sighup_handler();
267 else
268 attach_line();
269 if (!(modem_control & CLOCAL)) {
270 ioctl(fd, TIOCMGET, &comstate);
271 if (!(comstate & TIOCM_CD)) { /* check for carrier */
272 /* force a redial if no carrier */
273 kill (getpid(), SIGHUP);
274 }
15637ed4 275 }
78ed81a3 276 for (;;) {
277 sigset_t mask = 0;
278 sigsuspend(&mask);
279 }
280}
281
282void setup_line()
283{
284 struct termios tty;
285
286 tty.c_lflag = tty.c_iflag = tty.c_oflag = 0;
287 tty.c_cflag = CREAD | CS8 | flow_control | modem_control;
288 tty.c_ispeed = tty.c_ospeed = speed;
289 /* set the line speed and flow control */
290 if (tcsetattr(fd, TCSAFLUSH, &tty) < 0) {
291 syslog(LOG_ERR, "tcsetattr(TCSAFLUSH): %m");
292 exit_handler(1);
15637ed4 293 }
78ed81a3 294 /* set data terminal ready */
295 if (ioctl(fd, TIOCSDTR) < 0) {
296 syslog(LOG_ERR, "ioctl(TIOCSDTR): %m");
297 exit_handler(1);
298 }
299 /* Switch to slip line discipline. */
15637ed4 300 if (ioctl(fd, TIOCSETD, &slipdisc) < 0) {
78ed81a3 301 syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
302 exit_handler(1);
15637ed4 303 }
78ed81a3 304 /* Assert any compression or no-icmp flags. */
305 if (ioctl(fd, SLIOCSFLAGS, &slflags) < 0) {
306 syslog(LOG_ERR, "ioctl(SLIOCSFLAGS): %m");
307 exit_handler(1);
308 }
309}
310
311/* switch to slip line discipline and configure the network. */
312void attach_line()
313{
314 int new_unit;
15637ed4 315
78ed81a3 316 /* find out what unit number we were assigned */
317 if (ioctl(fd, SLIOCGUNIT, (caddr_t)&new_unit) < 0) {
318 syslog(LOG_ERR, "ioctl(SLIOCGUNIT): %m");
319 exit_handler(1);
320 }
321 /* don't compare unit numbers if this is the first time to attach. */
322 if (unit < 0)
323 unit = new_unit;
324 /* iff the unit number changes either invoke config_cmd or punt. */
325 if (config_cmd) {
326 char *s;
327 s = (char*) malloc(strlen(config_cmd) + 32);
328 sprintf (s, "%s %d %d", config_cmd, unit, new_unit);
329 syslog(LOG_NOTICE, "Configuring %s (sl%d):", dev, unit);
330 syslog(LOG_NOTICE, " '%s'", s);
331 system(s);
332 free (s);
333 unit = new_unit;
334 } else {
335 if (new_unit != unit) {
336 syslog(LOG_ERR, "slip unit changed from sl%d to sl%d, but no -u CMD was specified!");
337 exit_handler(1);
338 }
339 syslog(LOG_NOTICE,"sl%d connected to %s at %d baud",unit,dev,speed);
340 }
15637ed4
RG
341}
342
78ed81a3 343/* Signal handler for SIGHUP when carrier is dropped. */
344void sighup_handler()
15637ed4 345{
78ed81a3 346again:
347 /* reset discipline */
348 if (ioctl(fd, TIOCSETD, &ttydisc) < 0) {
349 syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
350 exit_handler(1);
351 }
352 /* invoke a shell for redial_cmd or punt. */
353 if (redial_cmd) {
354 syslog(LOG_NOTICE,"SIGHUP on %s (sl%d); running %s",
355 dev,unit,redial_cmd);
356 system(redial_cmd);
357 /* Now check again for carrier (dial command is done): */
358 if (!(modem_control & CLOCAL)) {
359 ioctl(fd, TIOCMGET, &comstate);
360 if (!(comstate & TIOCM_CD)) { /* check for carrier */
361 /* force a redial if no carrier */
362 goto again;
363 }
364 }
365 } else {
366 /*
367 * No redial command.
368 *
369 * If modem control, just wait for carrier before
370 * falling through to setup_line() and attach_line().
371 * If no modem control, just fall through immediately.
372 */
373 if (!(modem_control & CLOCAL)) {
374 int carrier = 0;
15637ed4 375
78ed81a3 376 syslog(LOG_NOTICE, "Waiting for carrier on %s (sl%d)",
377 dev, unit);
378
379 /* Now wait for carrier before attaching line: */
380 while (! carrier) {
381 /*
382 * Don't burn the CPU checking for carrier;
383 * carrier must be polled since there is no
384 * way to have a signal sent when carrier
385 * goes high (SIGHUP can only be sent when
386 * carrier is dropped); so add space between
387 * checks for carrier:
388 */
389 sleep(2);
390
391 /* Check for carrier present on tty port: */
392 ioctl(fd, TIOCMGET, &comstate);
393 if (comstate & TIOCM_CD) {
394 carrier = 1;
395 }
396 }
397
398 syslog(LOG_NOTICE, "Carrier now present on %s (sl%d)",
399 dev, unit);
400 }
401 }
402 setup_line();
403 attach_line();
404}
405/* Signal handler for SIGINT. We just log and exit. */
406void sigint_handler()
407{
408 syslog(LOG_NOTICE,"sl%d on %s caught SIGINT, exiting.",unit,dev);
409 exit_handler(0);
15637ed4 410}
78ed81a3 411/* Signal handler for SIGTERM. We just log and exit. */
412void sigterm_handler()
413{
414 syslog(LOG_NOTICE,"SIGTERM on %s (sl%d); exiting",dev,unit);
415 exit_handler(0);
416}
417/* Run config_cmd if specified before exiting. */
418void exit_handler(int ret)
419{
420 /*
421 * First close the slip line in case exit_cmd wants it (like to hang
422 * up a modem or something).
423 */
424 if (fd != -1)
425 close(fd);
426 /* invoke a shell for exit_cmd. */
427 if (exit_cmd) {
428 syslog(LOG_NOTICE,"exiting after running %s", exit_cmd);
429 system(exit_cmd);
430 }
431 exit(ret);
432}
433
434/* local variables: */
435/* c-indent-level: 8 */
436/* c-argdecl-indent: 0 */
437/* c-label-offset: -8 */
438/* c-continued-statement-offset: 8 */
439/* c-brace-offset: 0 */
440/* comment-column: 32 */
441/* end: */