new option for nestat, -Z shows SELinux context
[platform/upstream/net-tools.git] / slattach.c
1 /*
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.
6  *
7  * Usage:       slattach [-ehlmnqv] [ -k keepalive ] [ -o outfill ]
8  *                      [-c cmd] [-s speed] [-p protocol] tty | -
9  *
10  * Version:     @(#)slattach.c  1.20  1999-05-29
11  *
12  * Author:      Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
13  *              Copyright 1988-1993 MicroWalt Corporation
14  *
15  * Modified:
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
24  *
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.
30  */
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/ioctl.h>
35 #include <sys/stat.h>
36 #include <stdio.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <limits.h>
41 #include <pwd.h>
42 #include <signal.h>
43 #include <stdlib.h>          
44 #include <string.h>
45 #include <unistd.h>
46 #include <getopt.h>
47 #include <linux/if_slip.h>
48
49 #if defined(__GLIBC__)
50 #if __GLIBC__ == 2 && __GLIBC_MINOR__ == 0
51 # include <termbits.h>
52 #else
53 # include <termios.h>
54 #endif
55 #endif
56
57 #include "pathnames.h"
58 #include "net-support.h"
59 #include "version.h"
60 #include "config.h"
61 #include "intl.h"
62 #include "util.h"
63
64 #ifndef _PATH_LOCKD
65 #define _PATH_LOCKD     "/var/lock"             /* lock files   */
66 #endif
67 #ifndef _UID_UUCP
68 #define _UID_UUCP       "uucp"                  /* owns locks   */
69 #endif
70 #ifndef _PATH_DEVPTMX
71 #define _PATH_DEVPTMX   "/dev/ptmx"             /* pseudo-terminal master */
72 #endif
73
74
75 #define DEF_PROTO       "cslip"
76
77
78 const char *Release = RELEASE,
79            *Version = "$Id: slattach.c,v 1.12 2009/09/06 22:59:43 vapier Exp $",
80            *Signature = "net-tools, Fred N. van Kempen et al.";
81
82
83 struct {
84   const char    *speed;
85   int   code;
86 } tty_speeds[] = {                      /* table of usable baud rates   */
87   { "50",       B50     }, { "75",      B75     },      
88   { "110",      B110    }, { "300",     B300    },
89   { "600",      B600    }, { "1200",    B1200   },
90   { "2400",     B2400   }, { "4800",    B4800   },
91   { "9600",     B9600   },
92 #ifdef B14400
93   { "14400",    B14400  },
94 #endif
95 #ifdef B19200
96   { "19200",    B19200  },
97 #endif
98 #ifdef B38400
99   { "38400",    B38400  },
100 #endif
101 #ifdef B57600
102   { "57600",    B57600  },
103 #endif
104 #ifdef B115200
105   { "115200",   B115200 },
106 #endif
107   { NULL,       0       }
108 };
109 struct termios  tty_saved,              /* saved TTY device state       */
110                 tty_current;            /* current TTY device state     */
111 int             tty_sdisc,              /* saved TTY line discipline    */
112                 tty_ldisc,              /* current TTY line discipline  */
113                 tty_fd = -1;            /* TTY file descriptor          */
114 char *          path_pts = NULL;        /* slave pseudo-terminal device */
115 int             opt_c = 0;              /* "command" to run at exit     */
116 int             opt_e = 0;              /* "activate only" flag         */
117 int             opt_h = 0;              /* "hangup" on carrier loss     */
118 #ifdef SIOCSKEEPALIVE
119 int             opt_k = 0;              /* "keepalive" value            */
120 #endif
121 int             opt_l = 0;              /* "lock it" flag               */
122 int             opt_L = 0;              /* 3-wire mode flag             */
123 int             opt_m = 0;              /* "set RAW mode" flag          */
124 int             opt_n = 0;              /* "set No Mesg" flag           */
125 #ifdef SIOCSOUTFILL
126 int             opt_o = 0;              /* "outfill" value              */
127 #endif
128 int             opt_q = 0;              /* "quiet" flag                 */
129 int             opt_d = 0;              /* debug flag                   */
130 int             opt_v = 0;              /* Verbose flag                 */
131
132 /* Disable any messages to the input channel of this process. */
133 static int
134 tty_nomesg(int fd)
135 {
136   if (opt_n == 0) return(0);
137   return(fchmod(fd, 0600));
138 }
139
140 /* Check for an existing lock file on our device */
141 static int
142 tty_already_locked(char *nam)
143 {
144   int  i = 0, pid = 0;
145   FILE *fd = (FILE *)0;
146
147   /* Does the lock file on our device exist? */
148   if ((fd = fopen(nam, "r")) == (FILE *)0)
149     return(0); /* No, return perm to continue */
150
151   /* Yes, the lock is there.  Now let's make sure */
152   /* at least there's no active process that owns */
153   /* that lock.                                   */
154   i = fscanf(fd, "%d", &pid);
155   (void) fclose(fd);
156  
157   if (i != 1) /* Lock file format's wrong! Kill't */
158     return(0);
159
160   /* We got the pid, check if the process's alive */
161   if (kill(pid, 0) == 0)      /* it found process */
162       return(1);          /* Yup, it's running... */
163
164   /* Dead, we can proceed locking this device...  */
165   return(0);
166 }
167
168 /* Lock or unlock a terminal line. */
169 static int
170 tty_lock(char *path, int mode)
171 {
172   static char saved_path[PATH_MAX];
173   static int saved_lock = 0;
174   struct passwd *pw;
175   int fd;
176   char apid[16];
177
178   /* We do not lock standard input. */
179   if ((opt_l == 0) || ((path == NULL) && (saved_lock == 0))) return(0);
180
181   if (mode == 1) {      /* lock */
182         sprintf(saved_path, "%s/LCK..%s", _PATH_LOCKD, path);
183         if (tty_already_locked(saved_path)) {
184                 fprintf(stderr, _("slattach: /dev/%s already locked!\n"), path);
185                 return(-1);
186         }
187         if ((fd = creat(saved_path, 0644)) < 0) {
188                 if (errno != EEXIST)
189                         if (opt_q == 0) fprintf(stderr,
190                                 _("slattach: tty_lock: (%s): %s\n"),
191                                         saved_path, strerror(errno));
192                 return(-1);
193         }
194         sprintf(apid, "%10d\n", getpid());
195         if (write(fd, apid, strlen(apid)) != strlen(apid)) {
196                 fprintf(stderr, _("slattach: cannot write PID file\n"));
197                 close(fd);
198                 unlink(saved_path);
199                 return(-1);
200         }
201
202         /* Make sure UUCP owns the lockfile.  Required by some packages. */
203         if ((pw = getpwnam(_UID_UUCP)) == NULL) {
204                 if (opt_q == 0) fprintf(stderr, _("slattach: tty_lock: UUCP user %s unknown!\n"),
205                                         _UID_UUCP);
206                 (void) close(fd);
207                 return(0);      /* keep the lock anyway */
208         }
209         (void) fchown(fd, pw->pw_uid, pw->pw_gid);
210
211         (void) close(fd);
212
213         saved_lock = 1;
214   } else {      /* unlock */
215         if (saved_lock != 1) return(0);
216         if (unlink(saved_path) < 0) {
217                 if (opt_q == 0) fprintf(stderr,
218                         "slattach: tty_unlock: (%s): %s\n", saved_path,
219                                                         strerror(errno));
220                 return(-1);
221         }
222         saved_lock = 0;
223   }
224
225   return(0);
226 }
227
228
229 /* Find a serial speed code in the table. */
230 static int
231 tty_find_speed(const char *speed)
232 {
233   int i;
234
235   i = 0;
236   while (tty_speeds[i].speed != NULL) {
237         if (!strcmp(tty_speeds[i].speed, speed)) return(tty_speeds[i].code);
238         i++;
239   }
240   return(-EINVAL);
241 }
242
243
244 /* Set the number of stop bits. */
245 static int
246 tty_set_stopbits(struct termios *tty, char *stopbits)
247 {
248   if (opt_d) printf("slattach: tty_set_stopbits: %c\n", *stopbits);
249   switch(*stopbits) {
250         case '1':
251                 tty->c_cflag &= ~CSTOPB;
252                 break;
253
254         case '2':
255                 tty->c_cflag |= CSTOPB;
256                 break;
257
258         default:
259                 return(-EINVAL);
260   }
261   return(0);
262 }
263
264
265 /* Set the number of data bits. */
266 static int
267 tty_set_databits(struct termios *tty, char *databits)
268 {
269   if (opt_d) printf("slattach: tty_set_databits: %c\n", *databits);
270   tty->c_cflag &= ~CSIZE;
271   switch(*databits) {
272         case '5':
273                 tty->c_cflag |= CS5;
274                 break;
275
276         case '6':
277                 tty->c_cflag |= CS6;
278                 break;
279
280         case '7':
281                 tty->c_cflag |= CS7;
282                 break;
283
284         case '8':
285                 tty->c_cflag |= CS8;
286                 break;
287
288         default:
289                 return(-EINVAL);
290   }
291   return(0);
292 }
293
294
295 /* Set the type of parity encoding. */
296 static int
297 tty_set_parity(struct termios *tty, char *parity)
298 {
299   if (opt_d) printf("slattach: tty_set_parity: %c\n", *parity);
300   switch(toupper(*parity)) {
301         case 'N':
302                 tty->c_cflag &= ~(PARENB | PARODD);
303                 break;  
304
305         case 'O':
306                 tty->c_cflag &= ~(PARENB | PARODD);
307                 tty->c_cflag |= (PARENB | PARODD);
308                 break;
309
310         case 'E':
311                 tty->c_cflag &= ~(PARENB | PARODD);
312                 tty->c_cflag |= (PARENB);
313                 break;
314
315         default:
316                 return(-EINVAL);
317   }
318   return(0);
319 }
320
321
322 /* Set the line speed of a terminal line. */
323 static int
324 tty_set_speed(struct termios *tty, const char *speed)
325 {
326   int code;
327
328   if (opt_d) printf("slattach: tty_set_speed: %s\n", speed);
329   if ((code = tty_find_speed(speed)) < 0) return(code);
330   tty->c_cflag &= ~CBAUD;
331   tty->c_cflag |= code;
332   return(0);
333 }
334
335
336 /* Put a terminal line in a transparent state. */
337 static int
338 tty_set_raw(struct termios *tty)
339 {
340   int i;
341   int speed;
342
343   for(i = 0; i < NCCS; i++)
344                 tty->c_cc[i] = '\0';            /* no spec chr          */
345   tty->c_cc[VMIN] = 1;
346   tty->c_cc[VTIME] = 0;
347   tty->c_iflag = (IGNBRK | IGNPAR);             /* input flags          */
348   tty->c_oflag = (0);                           /* output flags         */
349   tty->c_lflag = (0);                           /* local flags          */
350   speed = (tty->c_cflag & CBAUD);               /* save current speed   */
351   tty->c_cflag = (HUPCL | CREAD);               /* UART flags           */
352   if (opt_L) 
353         tty->c_cflag |= CLOCAL;
354   else
355         tty->c_cflag |= CRTSCTS;
356   tty->c_cflag |= speed;                        /* restore speed        */
357   return(0);
358 }
359
360
361 /* Fetch the state of a terminal. */
362 static int
363 tty_get_state(struct termios *tty)
364 {
365   if (ioctl(tty_fd, TCGETS, tty) < 0) {
366         if (opt_q == 0) fprintf(stderr,
367                 "slattach: tty_get_state: %s\n", strerror(errno));
368         return(-errno);
369   }
370   return(0);
371 }
372
373
374 /* Set the state of a terminal. */
375 static int
376 tty_set_state(struct termios *tty)
377 {
378   if (ioctl(tty_fd, TCSETS, tty) < 0) {
379         if (opt_q == 0) fprintf(stderr,
380                 "slattach: tty_set_state: %s\n", strerror(errno));
381         return(-errno);
382   }
383   return(0);
384 }
385
386
387 /* Get the line discipline of a terminal line. */
388 static int
389 tty_get_disc(int *disc)
390 {
391   if (ioctl(tty_fd, TIOCGETD, disc) < 0) {
392         if (opt_q == 0) fprintf(stderr,
393                 "slattach: tty_get_disc: %s\n", strerror(errno));
394         return(-errno);
395   }
396   return(0);
397 }
398
399
400 /* Set the line discipline of a terminal line. */
401 static int
402 tty_set_disc(int disc)
403 {
404   if (disc == -1) disc = tty_sdisc;
405
406   if (ioctl(tty_fd, TIOCSETD, &disc) < 0) {
407         if (opt_q == 0) fprintf(stderr,
408                 "slattach: tty_set_disc(%d, %d): %s\n", tty_fd,
409                         disc, strerror(errno));
410         return(-errno);
411   }
412   return(0);
413 }
414
415
416 /* Fetch the name of the network interface attached to this terminal. */
417 static int
418 tty_get_name(char *name)
419 {
420   if (ioctl(tty_fd, SIOCGIFNAME, name) < 0) {
421         if (opt_q == 0) 
422             perror("tty_get_name");
423         return(-errno);
424   }
425   return(0);
426 }
427
428
429 /* Hangup the line. */
430 static int
431 tty_hangup(void)
432 {
433   struct termios tty;
434
435   tty = tty_current;
436   (void) tty_set_speed(&tty, "0");
437   if (tty_set_state(&tty) < 0) {
438         if (opt_q == 0) fprintf(stderr, _("slattach: tty_hangup(DROP): %s\n"), strerror(errno));
439         return(-errno);
440   }
441
442   (void) sleep(1);
443
444   if (tty_set_state(&tty_current) < 0) {
445         if (opt_q == 0) fprintf(stderr, _("slattach: tty_hangup(RAISE): %s\n"), strerror(errno));
446         return(-errno);
447   }
448   return(0);
449 }
450
451
452 /* Close down a terminal line. */
453 static int
454 tty_close(void)
455 {
456   (void) tty_set_disc(tty_sdisc);
457   (void) tty_hangup();
458   (void) tty_lock(NULL, 0);
459   return(0);
460 }
461
462
463 /* Open and initialize a terminal line. */
464 static int
465 tty_open(char *name, const char *speed)
466 {
467   char pathbuf[PATH_MAX];
468   register char *path_open, *path_lock;
469   int fd;
470
471   /* Try opening the TTY device. */
472   if (name != NULL) {
473         if (name[0] != '/') {
474                 if (strlen(name + 6) > sizeof(pathbuf)) {
475                         if (opt_q == 0) fprintf(stderr, 
476                                 _("slattach: tty name too long\n"));
477                         return (-1);
478                 }
479                 sprintf(pathbuf, "/dev/%s", name);
480                 path_open = pathbuf;
481                 path_lock = name;
482         } else if (!strncmp(name, "/dev/", 5)) {
483                 path_open = name;
484                 path_lock = name + 5;
485         } else {
486                 path_open = name;
487                 path_lock = name;
488         }
489         if (opt_d) printf("slattach: tty_open: looking for lock\n");
490         if (tty_lock(path_lock, 1)) return(-1); /* can we lock the device? */
491         if (opt_d) printf("slattach: tty_open: trying to open %s\n", path_open);
492         if ((fd = open(path_open, O_RDWR|O_NDELAY)) < 0) {
493                 if (opt_q == 0) fprintf(stderr,
494                         "slattach: tty_open(%s, RW): %s\n",
495                                         path_open, strerror(errno));
496                 return(-errno);
497         }
498         tty_fd = fd;
499         if (opt_d) printf("slattach: tty_open: %s (fd=%d)\n", path_open, fd);
500         if (!strcmp(path_open, _PATH_DEVPTMX)) {
501                 if (opt_d) printf("slattach: tty_open: trying to grantpt and unlockpt\n");
502                 if (grantpt(fd) < 0) {
503                     if (opt_q == 0) fprintf(stderr,
504                             "slattach: tty_open: grantpt: %s\n", strerror(errno));
505                     return(-errno);
506                 }
507                 if (unlockpt(fd) < 0) {
508                     if (opt_q == 0) fprintf(stderr,
509                             "slattach: tty_open: unlockpt: %s\n", strerror(errno));
510                     return(-errno);
511                 }
512                 path_pts = ptsname(fd);
513                 if (path_pts == NULL) {
514                     if (opt_q == 0) fprintf(stderr,
515                             "slattach: tty_open: ptsname: %s\n", strerror(errno));
516                     return(-errno);
517                 }
518                 if (opt_d) printf("slattach: tty_open: %s: slave pseudo-terminal is %s\n",
519                                   path_open, path_pts);
520         }
521   } else {
522         tty_fd = 0;
523   }
524
525   /* Fetch the current state of the terminal. */
526   if (tty_get_state(&tty_saved) < 0) {
527         if (opt_q == 0) fprintf(stderr, _("slattach: tty_open: cannot get current state!\n"));
528         return(-errno);
529   }
530   tty_current = tty_saved;
531
532   /* Fetch the current line discipline of this terminal. */
533   if (tty_get_disc(&tty_sdisc) < 0) {
534         if (opt_q == 0) fprintf(stderr, _("slattach: tty_open: cannot get current line disc!\n"));
535         return(-errno);
536   } 
537   tty_ldisc = tty_sdisc;
538
539   /* Put this terminal line in a 8-bit transparent mode. */
540   if (opt_m == 0) {
541         if (tty_set_raw(&tty_current) < 0) {
542                 if (opt_q == 0) fprintf(stderr, _("slattach: tty_open: cannot set RAW mode!\n"));
543                 return(-errno);
544         }
545
546         /* Set the default speed if we need to. */
547         if (speed != NULL) {
548                 if (tty_set_speed(&tty_current, speed) != 0) {
549                         if (opt_q == 0) fprintf(stderr, _("slattach: tty_open: cannot set %s bps!\n"),
550                                                 speed);
551                         return(-errno);
552                 }
553         }
554
555         /* Set up a completely 8-bit clean line. */
556         if (tty_set_databits(&tty_current, "8") ||
557             tty_set_stopbits(&tty_current, "1") ||
558             tty_set_parity(&tty_current, "N")) {
559                 if (opt_q == 0) fprintf(stderr, _("slattach: tty_open: cannot set 8N1 mode!\n"));
560                 return(-errno);
561         }
562
563         /* Set the new line mode. */
564         if ((fd = tty_set_state(&tty_current)) < 0) return(fd);
565   }
566
567   /* OK, line is open.  Do we need to "silence" it? */
568   (void) tty_nomesg(tty_fd);
569
570   return(0);
571 }
572
573
574 /* Catch any signals. */
575 static void
576 sig_catch(int sig)
577 {
578 /*  (void) signal(sig, sig_catch); */
579   tty_close();
580   exit(0);
581 }
582
583
584 static void
585 usage(void)
586 {
587   char *usage_msg = "Usage: slattach [-ehlLmnqv] "
588 #ifdef SIOCSKEEPALIVE
589           "[-k keepalive] "
590 #endif
591 #ifdef SIOCSOUTFILL
592           "[-o outfill] "
593 #endif
594           "[-c cmd] [-s speed] [-p protocol] tty | -\n"
595           "       slattach -V | --version\n";
596
597   fputs(usage_msg, stderr);
598   exit(1);
599 }
600
601
602 static void 
603 version(void)
604 {
605     printf("%s\n%s\n%s\n", Release, Version, Signature);
606     exit(E_VERSION);
607 }
608
609
610 int
611 main(int argc, char *argv[])
612 {
613   char path_buf[128];
614   char *path_dev;
615   char buff[128];
616   const char *speed = NULL;
617   const char *proto = DEF_PROTO;
618   const char *extcmd = NULL;
619   int s;
620   static struct option longopts[] = {
621     { "version", 0, NULL, 'V' },
622     { NULL, 0, NULL, 0 }
623   };
624
625   strcpy(path_buf, "");
626   path_dev = path_buf;
627
628   /* Scan command line for any arguments. */
629   opterr = 0;
630   while ((s = getopt_long(argc, argv, "c:ehlLmnp:qs:vdVk:o:", longopts, NULL)) != EOF) switch(s) {
631         case 'c':
632                 extcmd = optarg;
633                 break;
634
635         case 'e':
636                 opt_e = 1 - opt_e;
637                 break;
638
639         case 'h':
640                 opt_h = 1 - opt_h;
641                 break;
642
643 #ifdef SIOCSKEEPALIVE
644         case 'k':
645                 opt_k = atoi(optarg);
646                 break;
647 #endif
648
649         case 'L':
650                 opt_L = 1 - opt_L;
651                 break;
652
653         case 'l':
654                 opt_l = 1 - opt_l;
655                 break;
656
657         case 'm':
658                 opt_m = 1 - opt_m;
659                 break;
660
661         case 'n':
662                 opt_n = 1 - opt_n;
663                 break;
664
665 #ifdef SIOCSOUTFILL
666         case 'o':
667                 opt_o = atoi(optarg);
668                 break;
669 #endif
670
671         case 'p':
672                 proto = optarg;
673                 break;
674
675         case 'q':
676                 opt_q = 1 - opt_q;
677                 break;
678
679         case 's':
680                 speed = optarg;
681                 break;
682
683         case 'd':
684                 opt_d = 1 - opt_d;
685                 break;
686
687         case 'v':
688                 opt_v = 1 - opt_v;
689                 break;
690
691         case 'V':
692                 version();
693                 /*NOTREACHED*/
694
695         default:
696                 usage();
697                 /*NOTREACHED*/
698   }
699   
700   if (setvbuf(stdout,0,_IOLBF,0)) {
701         if (opt_q == 0) fprintf(stderr, _("slattach: setvbuf(stdout,0,_IOLBF,0) : %s\n"),
702                                 strerror(errno));
703         exit(1);
704   }
705
706   activate_init();
707
708   if (!strcmp(proto, "tty"))
709        opt_m++;
710
711   /* Is a terminal given? */
712   if (optind != (argc - 1)) usage();
713   safe_strncpy(path_buf, argv[optind], sizeof(path_buf));
714   if (!strcmp(path_buf, "-")) {
715         opt_e = 1;
716         path_dev = NULL;
717         if (tty_open(NULL, speed) < 0) { return(3); }
718   } else {
719         path_dev = path_buf;
720         if (tty_open(path_dev, speed) < 0) { return(3); }
721   }
722
723   /* Start the correct protocol. */
724   if (!strcmp(proto, "tty")) {
725         tty_sdisc = N_TTY;
726         tty_close();
727         return(0);
728   }
729   if (activate_ld(proto, tty_fd))
730         return(1);
731   if ((opt_v == 1) || (opt_d == 1)) {
732         if (tty_get_name(buff)) { return(3); }
733         printf(_("%s started"), proto);
734         if (path_dev != NULL) printf(_(" on %s"), path_dev);
735         if (path_pts != NULL) printf(_(" ptsname %s"), path_pts);
736         printf(_(" interface %s\n"), buff);
737   }
738
739   /* Configure keepalive and outfill. */
740 #ifdef SIOCSKEEPALIVE
741   if (opt_k && (ioctl(tty_fd, SIOCSKEEPALIVE, &opt_k) < 0))
742           fprintf(stderr, "slattach: ioctl(SIOCSKEEPALIVE): %s\n", strerror(errno));
743 #endif
744 #ifdef SIOCSOUTFILL
745   if (opt_o && (ioctl(tty_fd, SIOCSOUTFILL, &opt_o) < 0))
746           fprintf(stderr, "slattach: ioctl(SIOCSOUTFILL): %s\n", strerror(errno));
747 #endif
748
749   (void) signal(SIGHUP, sig_catch);
750   (void) signal(SIGINT, sig_catch);
751   (void) signal(SIGQUIT, sig_catch);
752   (void) signal(SIGTERM, sig_catch);
753
754   /* Wait until we get killed if hanging on a terminal. */
755   if (opt_e == 0) {
756         while(1) {
757                 if(opt_h == 1) { /* hangup on carrier loss */
758                         int n = 0;
759
760                         ioctl(tty_fd, TIOCMGET, &n);
761                         if(!(n & TIOCM_CAR))
762                                 break;
763                         sleep(15);
764                 }
765                 else
766                         sleep(60);
767         };
768
769         tty_close();
770         if(extcmd)      /* external command on exit */
771                 system(extcmd);
772   }
773   exit(0);
774 }