Commit | Line | Data |
---|---|---|
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 |
87 | char 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";*/ |
94 | static 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 | ||
114 | extern int errno; | |
115 | extern char *sys_errlist[]; | |
15637ed4 RG |
116 | |
117 | #define DEFAULT_BAUD 9600 | |
78ed81a3 | 118 | |
119 | void sighup_handler(); /* SIGHUP handler */ | |
120 | void sigint_handler(); /* SIGINT handler */ | |
121 | void sigterm_handler(); /* SIGTERM handler */ | |
122 | void exit_handler(int ret); /* run exit_cmd iff specified upon exit. */ | |
123 | void setup_line(); /* configure slip line */ | |
124 | void attach_line(); /* switch to slip line discipline */ | |
125 | ||
126 | int fd = -1; | |
127 | char *dev = (char *)0; | |
15637ed4 | 128 | int slipdisc = SLIPDISC; |
78ed81a3 | 129 | int ttydisc = TTYDISC; |
130 | int flow_control = 0; /* non-zero to enable hardware flow control. */ | |
131 | int modem_control = 0; /* non-zero iff we watch carrier. */ | |
132 | int comstate; /* TIOCMGET current state of serial driver */ | |
133 | int redial_on_startup = 0; /* iff non-zero execute redial_cmd on startup */ | |
134 | int speed = DEFAULT_BAUD; | |
135 | int slflags = 0; /* compression flags */ | |
136 | int unit = -1; /* slip device unit number */ | |
137 | int foreground = 0; | |
138 | FILE *console; | |
15637ed4 RG |
139 | |
140 | char devname[32]; | |
141 | char hostname[MAXHOSTNAMELEN]; | |
78ed81a3 | 142 | char *redial_cmd = 0; /* command to exec upon shutdown. */ |
143 | char *config_cmd = 0; /* command to exec if slip unit changes. */ | |
144 | char *exit_cmd = 0; /* command to exec before exiting. */ | |
145 | char string[100]; | |
146 | ||
147 | static char usage_str[] = "\ | |
148 | usage: %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 | 161 | int 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 | ||
282 | void 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. */ | |
312 | void 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. */ |
344 | void sighup_handler() | |
15637ed4 | 345 | { |
78ed81a3 | 346 | again: |
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. */ | |
406 | void 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. */ |
412 | void 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. */ | |
418 | void 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: */ |