2 * slattach A program for handling dialup IP connecions.
3 * This program forces a TTY line to go into a special
4 * terminal line discipline, so that it can be used for
5 * network traffic instead of the regular terminal I/O.
7 * Usage: slattach [-ehlmnqv] [ -k keepalive ] [ -o outfill ]
8 * [-c cmd] [-s speed] [-p protocol] tty | -
10 * Version: @(#)slattach.c 1.20 1999-05-29
12 * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
13 * Copyright 1988-1993 MicroWalt Corporation
16 * Alan Cox, <A.Cox@swansea.ac.uk> , July 16 1994
17 * Miquel van Smoorenburg, <miquels@drinkel.ow.org>, October 1994
18 * George Shearer, <gshearer@one.net>, January 3, 1995
19 * Yossi Gottlieb, <yogo@math.tau.ac.il>, February 11, 1995
20 * Peter Tobias, <tobias@et-inf.fho-emden.de>, July 30 1995
21 * Bernd Eckenfels <net-tools@lina.inka.de>, May 29, 1999
22 * added some more printf's for debug and NOBLOCK to open
23 * this should be enough to support 2.2 ttyS-style locks
25 * This program is free software; you can redistribute it
26 * and/or modify it under the terms of the GNU General
27 * Public License as published by the Free Software
28 * Foundation; either version 2 of the License, or (at
29 * your option) any later version.
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/ioctl.h>
46 #include <linux/if_slip.h>
48 #if defined(__GLIBC__)
49 #if __GLIBC__ == 2 && __GLIBC_MINOR__ == 0
50 # include <termbits.h>
56 #include "pathnames.h"
57 #include "net-support.h"
63 #define _PATH_LOCKD "/var/lock" /* lock files */
66 #define _UID_UUCP "uucp" /* owns locks */
70 #define DEF_PROTO "cslip"
73 char *Release
= RELEASE
,
74 *Version
= "@(#) slattach 1.20 (1999-05-29)",
75 *Signature
= "net-tools, Fred N. van Kempen et al.";
81 } tty_speeds
[] = { /* table of usable baud rates */
82 { "50", B50
}, { "75", B75
},
83 { "110", B110
}, { "300", B300
},
84 { "600", B600
}, { "1200", B1200
},
85 { "2400", B2400
}, { "4800", B4800
},
100 { "115200", B115200
},
104 struct termios tty_saved
, /* saved TTY device state */
105 tty_current
; /* current TTY device state */
106 int tty_sdisc
, /* saved TTY line discipline */
107 tty_ldisc
, /* current TTY line discipline */
108 tty_fd
= -1; /* TTY file descriptor */
109 int opt_c
= 0; /* "command" to run at exit */
110 int opt_e
= 0; /* "activate only" flag */
111 int opt_h
= 0; /* "hangup" on carrier loss */
112 #ifdef SIOCSKEEPALIVE
113 int opt_k
= 0; /* "keepalive" value */
115 int opt_l
= 0; /* "lock it" flag */
116 int opt_L
= 0; /* clocal flag */
117 int opt_m
= 0; /* "set RAW mode" flag */
118 int opt_n
= 0; /* "set No Mesg" flag */
120 int opt_o
= 0; /* "outfill" value */
122 int opt_q
= 0; /* "quiet" flag */
123 int opt_d
= 0; /* debug flag */
124 int opt_v
= 0; /* Verbose flag */
126 /* Disable any messages to the input channel of this process. */
130 if (opt_n
== 0) return(0);
131 return(fchmod(fd
, 0600));
134 /* Check for an existing lock file on our device */
136 tty_already_locked(char *nam
)
139 FILE *fd
= (FILE *)0;
141 /* Does the lock file on our device exist? */
142 if ((fd
= fopen(nam
, "r")) == (FILE *)0)
143 return(0); /* No, return perm to continue */
145 /* Yes, the lock is there. Now let's make sure */
146 /* at least there's no active process that owns */
148 i
= fscanf(fd
, "%d", &pid
);
151 if (i
!= 1) /* Lock file format's wrong! Kill't */
154 /* We got the pid, check if the process's alive */
155 if (kill(pid
, 0) == 0) /* it found process */
156 return(1); /* Yup, it's running... */
158 /* Dead, we can proceed locking this device... */
162 /* Lock or unlock a terminal line. */
164 tty_lock(char *path
, int mode
)
166 static char saved_path
[PATH_MAX
];
167 static int saved_lock
= 0;
172 /* We do not lock standard input. */
173 if ((opt_l
== 0) || ((path
== NULL
) && (saved_lock
== 0))) return(0);
175 if (mode
== 1) { /* lock */
176 sprintf(saved_path
, "%s/LCK..%s", _PATH_LOCKD
, path
);
177 if (tty_already_locked(saved_path
)) {
178 fprintf(stderr
, _("slattach: /dev/%s already locked!\n"), path
);
181 if ((fd
= creat(saved_path
, 0644)) < 0) {
183 if (opt_q
== 0) fprintf(stderr
,
184 _("slattach: tty_lock: (%s): %s\n"),
185 saved_path
, strerror(errno
));
188 sprintf(apid
, "%10d\n", getpid());
189 if (write(fd
, apid
, strlen(apid
)) != strlen(apid
)) {
190 fprintf(stderr
, _("slattach: cannot write PID file\n"));
198 /* Make sure UUCP owns the lockfile. Required by some packages. */
199 if ((pw
= getpwnam(_UID_UUCP
)) == NULL
) {
200 if (opt_q
== 0) fprintf(stderr
, _("slattach: tty_lock: UUCP user %s unknown!\n"),
202 return(0); /* keep the lock anyway */
204 (void) chown(saved_path
, pw
->pw_uid
, pw
->pw_gid
);
206 } else { /* unlock */
207 if (saved_lock
!= 1) return(0);
208 if (unlink(saved_path
) < 0) {
209 if (opt_q
== 0) fprintf(stderr
,
210 "slattach: tty_unlock: (%s): %s\n", saved_path
,
221 /* Find a serial speed code in the table. */
223 tty_find_speed(char *speed
)
228 while (tty_speeds
[i
].speed
!= NULL
) {
229 if (!strcmp(tty_speeds
[i
].speed
, speed
)) return(tty_speeds
[i
].code
);
236 /* Set the number of stop bits. */
238 tty_set_stopbits(struct termios
*tty
, char *stopbits
)
240 if (opt_d
) printf("slattach: tty_set_stopbits: %c\n", *stopbits
);
243 tty
->c_cflag
&= ~CSTOPB
;
247 tty
->c_cflag
|= CSTOPB
;
257 /* Set the number of data bits. */
259 tty_set_databits(struct termios
*tty
, char *databits
)
261 if (opt_d
) printf("slattach: tty_set_databits: %c\n", *databits
);
262 tty
->c_cflag
&= ~CSIZE
;
287 /* Set the type of parity encoding. */
289 tty_set_parity(struct termios
*tty
, char *parity
)
291 if (opt_d
) printf("slattach: tty_set_parity: %c\n", *parity
);
292 switch(toupper(*parity
)) {
294 tty
->c_cflag
&= ~(PARENB
| PARODD
);
298 tty
->c_cflag
&= ~(PARENB
| PARODD
);
299 tty
->c_cflag
|= (PARENB
| PARODD
);
303 tty
->c_cflag
&= ~(PARENB
| PARODD
);
304 tty
->c_cflag
|= (PARENB
);
314 /* Set the line speed of a terminal line. */
316 tty_set_speed(struct termios
*tty
, char *speed
)
320 if (opt_d
) printf("slattach: tty_set_speed: %s\n", speed
);
321 if ((code
= tty_find_speed(speed
)) < 0) return(code
);
322 tty
->c_cflag
&= ~CBAUD
;
323 tty
->c_cflag
|= code
;
328 /* Put a terminal line in a transparent state. */
330 tty_set_raw(struct termios
*tty
)
335 for(i
= 0; i
< NCCS
; i
++)
336 tty
->c_cc
[i
] = '\0'; /* no spec chr */
338 tty
->c_cc
[VTIME
] = 0;
339 tty
->c_iflag
= (IGNBRK
| IGNPAR
); /* input flags */
340 tty
->c_oflag
= (0); /* output flags */
341 tty
->c_lflag
= (0); /* local flags */
342 speed
= (tty
->c_cflag
& CBAUD
); /* save current speed */
343 tty
->c_cflag
= (CRTSCTS
| HUPCL
| CREAD
); /* UART flags */
345 tty
->c_cflag
|= CLOCAL
;
346 tty
->c_cflag
|= speed
; /* restore speed */
351 /* Fetch the state of a terminal. */
353 tty_get_state(struct termios
*tty
)
355 if (ioctl(tty_fd
, TCGETS
, tty
) < 0) {
356 if (opt_q
== 0) fprintf(stderr
,
357 "slattach: tty_get_state: %s\n", strerror(errno
));
364 /* Set the state of a terminal. */
366 tty_set_state(struct termios
*tty
)
368 if (ioctl(tty_fd
, TCSETS
, tty
) < 0) {
369 if (opt_q
== 0) fprintf(stderr
,
370 "slattach: tty_set_state: %s\n", strerror(errno
));
377 /* Get the line discipline of a terminal line. */
379 tty_get_disc(int *disc
)
381 if (ioctl(tty_fd
, TIOCGETD
, disc
) < 0) {
382 if (opt_q
== 0) fprintf(stderr
,
383 "slattach: tty_get_disc: %s\n", strerror(errno
));
390 /* Set the line discipline of a terminal line. */
392 tty_set_disc(int disc
)
394 if (disc
== -1) disc
= tty_sdisc
;
396 if (ioctl(tty_fd
, TIOCSETD
, &disc
) < 0) {
397 if (opt_q
== 0) fprintf(stderr
,
398 "slattach: tty_set_disc(%d, %d): %s\n", tty_fd
,
399 disc
, strerror(errno
));
406 /* Fetch the name of the network interface attached to this terminal. */
408 tty_get_name(char *name
)
410 if (ioctl(tty_fd
, SIOCGIFNAME
, name
) < 0) {
411 if (opt_q
== 0) fprintf(stderr
,
412 "slattach: tty_get_name: %s\n", strerror(errno
));
419 /* Hangup the line. */
426 (void) tty_set_speed(&tty
, "0");
427 if (tty_set_state(&tty
) < 0) {
428 if (opt_q
== 0) fprintf(stderr
, _("slattach: tty_hangup(DROP): %s\n"), strerror(errno
));
434 if (tty_set_state(&tty_current
) < 0) {
435 if (opt_q
== 0) fprintf(stderr
, _("slattach: tty_hangup(RAISE): %s\n"), strerror(errno
));
442 /* Close down a terminal line. */
446 (void) tty_set_disc(tty_sdisc
);
448 (void) tty_lock(NULL
, 0);
453 /* Open and initialize a terminal line. */
455 tty_open(char *name
, char *speed
)
461 /* Try opening the TTY device. */
463 if ((sp
= strrchr(name
, '/')) != (char *)NULL
) *sp
++ = '\0';
465 sprintf(path
, "/dev/%s", sp
);
466 if (opt_d
) printf("slattach: tty_open: looking for lock\n");
467 if (tty_lock(sp
, 1)) return(-1); /* can we lock the device? */
468 if (opt_d
) printf("slattach: tty_open: trying to open %s\n", path
);
469 if ((fd
= open(path
, O_RDWR
|O_NDELAY
)) < 0) {
470 if (opt_q
== 0) fprintf(stderr
,
471 "slattach: tty_open(%s, RW): %s\n",
472 path
, strerror(errno
));
476 if (opt_d
) printf("slattach: tty_open: %s (fd=%d) ", path
, fd
);
482 /* Fetch the current state of the terminal. */
483 if (tty_get_state(&tty_saved
) < 0) {
484 if (opt_q
== 0) fprintf(stderr
, _("slattach: tty_open: cannot get current state!\n"));
487 tty_current
= tty_saved
;
489 /* Fetch the current line discipline of this terminal. */
490 if (tty_get_disc(&tty_sdisc
) < 0) {
491 if (opt_q
== 0) fprintf(stderr
, _("slattach: tty_open: cannot get current line disc!\n"));
494 tty_ldisc
= tty_sdisc
;
496 /* Put this terminal line in a 8-bit transparent mode. */
498 if (tty_set_raw(&tty_current
) < 0) {
499 if (opt_q
== 0) fprintf(stderr
, _("slattach: tty_open: cannot set RAW mode!\n"));
503 /* Set the default speed if we need to. */
505 if (tty_set_speed(&tty_current
, speed
) != 0) {
506 if (opt_q
== 0) fprintf(stderr
, _("slattach: tty_open: cannot set %s bps!\n"),
512 /* Set up a completely 8-bit clean line. */
513 if (tty_set_databits(&tty_current
, "8") ||
514 tty_set_stopbits(&tty_current
, "1") ||
515 tty_set_parity(&tty_current
, "N")) {
516 if (opt_q
== 0) fprintf(stderr
, _("slattach: tty_open: cannot set 8N1 mode!\n"));
520 /* Set the new line mode. */
521 if ((fd
= tty_set_state(&tty_current
)) < 0) return(fd
);
524 /* OK, line is open. Do we need to "silence" it? */
525 (void) tty_nomesg(tty_fd
);
531 /* Catch any signals. */
535 /* (void) signal(sig, sig_catch); */
544 char *usage_msg
= "Usage: slattach [-ehlLmnqv] "
545 #ifdef SIOCSKEEPALIVE
551 "[-c cmd] [-s speed] [-p protocol] tty | -\n"
552 " slattach -V | --version\n";
554 fprintf(stderr
, usage_msg
);
562 printf("%s\n%s\n%s\n", Release
, Version
, Signature
);
568 main(int argc
, char *argv
[])
573 char *proto
= DEF_PROTO
;
574 char *extcmd
= (char *)0;
578 static struct option longopts
[] = {
579 { "version", 0, NULL
, 'V' },
585 /* Scan command line for any arguments. */
587 while ((s
= getopt_long(argc
, argv
, "c:ehlLmnp:qs:vdVk:o:", longopts
, NULL
)) != EOF
) switch(s
) {
600 #ifdef SIOCSKEEPALIVE
602 opt_k
= atoi(optarg
);
624 opt_o
= atoi(optarg
);
659 /* Check the protocol. */
660 if ((ht
= get_hwtype(proto
)) == NULL
&& strcmp(proto
, "tty")) {
661 if (opt_q
== 0) fprintf(stderr
, _("slattach: unsupported protocol %s\n"), proto
);
664 if (ht
== NULL
) opt_m
++;
666 /* Is a terminal given? */
667 if (optind
!= (argc
- 1)) usage();
668 strncpy(path
, argv
[optind
], 128);
669 if (!strcmp(path
, "-")) {
672 if (tty_open(NULL
, speed
) < 0) { return(3); }
674 if ((sp
= strrchr(path
, '/')) != NULL
) *sp
++ = '\0';
676 if (tty_open(sp
, speed
) < 0) { return(3); }
679 /* Start the correct protocol. */
685 (*ht
->activate
)(tty_fd
);
686 if ((opt_v
== 1) || (opt_d
== 1)) {
688 printf(_("%s started"), proto
);
689 if (sp
!= NULL
) printf(_(" on %s"), sp
);
690 printf(_(" interface %s\n"), buff
);
693 /* Configure keepalive and outfill. */
694 #ifdef SIOCSKEEPALIVE
695 if (opt_k
&& (ioctl(tty_fd
, SIOCSKEEPALIVE
, &opt_k
) < 0))
696 fprintf(stderr
, "slattach: ioctl(SIOCSKEEPALIVE): %s\n", strerror(errno
));
699 if (opt_o
&& (ioctl(tty_fd
, SIOCSOUTFILL
, &opt_o
) < 0))
700 fprintf(stderr
, "slattach: ioctl(SIOCSOUTFILL): %s\n", strerror(errno
));
703 (void) signal(SIGHUP
, sig_catch
);
704 (void) signal(SIGINT
, sig_catch
);
705 (void) signal(SIGQUIT
, sig_catch
);
706 (void) signal(SIGTERM
, sig_catch
);
708 /* Wait until we get killed if hanging on a terminal. */
711 if(opt_h
== 1) { /* hangup on carrier loss */
714 ioctl(tty_fd
, TIOCMGET
, &n
);
724 if(extcmd
!=(char *)0) /* external command on exit */