home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume15 / ultrix-modem / modem.c < prev    next >
C/C++ Source or Header  |  1988-05-24  |  10KB  |  411 lines

  1. /*
  2.  * Copyright (c) Dave Settle 1987
  3.  * All rights reserved.
  4.  * Permission is granted to do anything with this program, except remove
  5.  * this copyright notice, or sell it for profit.
  6.  *
  7.  * Problems, suggestions, bug fixes etc, to:
  8.  *
  9.  * Dave Settle, SMB Business Software, Thorn EMI Datasolve
  10.  * 
  11.  * UUCP:
  12.  *     dave@smb.co.uk
  13.  *     ...!mcvax!ukc!nott-cs!smb!dave    
  14.  * 
  15.  * SMAIL:                    Voice:
  16.  *     SMB Business Software             +44 623 651651
  17.  *     High Street
  18.  *     Mansfield            Telex:
  19.  *     Nottingham NG18 1ES             37392 TECSMG
  20.  *     England    
  21.  *                     Fax:
  22.  *                          +44 623 659947
  23.  * 
  24.  * modem.c: a bi-directional "getty" to allow incoming calls AND outgoing 
  25.  * uucico's
  26.  *
  27.  * Modified by Rick Richardson for HDB uucp and AT&T Aztec protocol
  28.  *
  29.  * Modified by Jack Bonn for state logic (allows autoanswer on/off at
  30.  *                       a given time for each day of the week)
  31.  *
  32.  * Modified by Dave Settle:
  33.  *
  34.  * Code fixes:
  35.  *    hangup routine added, to make sure phone is down before script, and
  36.  *        after user disconnects.
  37.  *    Parameterised send-expect routines.
  38.  *    Minor bug fix to dread()
  39.  *    Re-enable SIGALRM in wakeup()
  40.  *    Catch all signals, to enable crashes to be detected.
  41.  *    Chmod device back to 666, so that we can use it afterwards.
  42.  *      Oct 87: fixup modem control with CLOCAL, so that remote disconnect
  43.  *        can be detected and dealt with.
  44.  *    Oct 87: fix autologout to send series of signals, not just SIGHUP
  45.  *    Oct 87: Clean up code, and distribute to other source files.
  46.  *    Nov 87: Fix lurking bug in 'expect'. Clean code for 'lint'.
  47.  *    Nov 87: Ignore SIHGUP's generated by 'hangup'.
  48.  *    Dec 87: Force getty NOT to hangup the line before login.
  49.  *    Jan 87: Open stdio file descriptors.
  50.  *
  51.  *
  52.  */
  53. #include <sys/types.h>
  54. #include <stdio.h>
  55. #include <signal.h>
  56. #include <errno.h>
  57. #include <fcntl.h>
  58. #include <termio.h>
  59. #include <sys/stat.h>
  60. #include <time.h>
  61.  
  62. #ifdef WATCHIT
  63. #include <pwd.h>
  64. struct passwd *getpwuid();
  65. #endif
  66.  
  67. #define MAINDEF
  68. #include "modem.h"        /* variable definitions */
  69. /* 
  70.  * wakeup gets called when the alarm goes off 
  71.  */
  72. wakeup(){
  73.     signal(SIGALRM, wakeup);
  74. }
  75.  
  76. fault(sig){
  77.     printf("Crashed with signal %d\n", sig);
  78.     closedown(sig);
  79. }
  80.  
  81. closedown(sig){
  82.     time_t now;
  83.     now = time((long *) 0);
  84. /*
  85.  * [Nov 87]: Since we're about to hang up the phone, 
  86.  * ignore the signal that this is going to generate.
  87.  */
  88.     signal(SIGHUP, SIG_IGN);
  89.     if(sig) printf("Caught signal %d\n", sig);
  90.     printf("Closedown at %s", asctime(localtime(&now)));
  91. /*
  92.  * Oct 87: new addition for SIGHUP. We receive this signal when    the line
  93.  * is disconnected by a remote caller. Since the line is dead, so should
  94.  * the shell be (it got SIGHUP same as us); log it out anyway, even if it's
  95.  * trying to ignore it.
  96.  */
  97.     if((sig == SIGHUP) && shell) autologout(shell);
  98. /*
  99.  * change the value in utmp back to our pid.
  100.  */        
  101.     if(shell) uchange(shell, getpid());    /* back to normal */
  102. /*
  103.  * clear modem line, which should also hangup the phone (if it wasn't already).
  104.  */    
  105.     hangup(dev);
  106.     close(dev);
  107. /*
  108.  * chmod the device back to 666, so that uucico and cu can access it.
  109.  * NOTE: I prefer this to chown(uucp), which does not allow "cu" access.
  110.  */
  111.     chmod(dname,0666);    /* uucp access */
  112.     unlink(lockf);
  113.     if(status) printf("Logout status 0x%x\n", status);
  114.     fclose(stdout);
  115.     exit(0);
  116. }
  117.         
  118. main(argc, argv, envp)
  119. char **argv, **envp;
  120. {
  121.     long t;
  122.     char *arg[5], *speed;
  123.     int baud, i;
  124.     struct conv *p;
  125.     struct stat sbuf;
  126.     time_t now, mtime;
  127. #ifdef WATCHIT
  128.     FILE *procs;
  129.     struct passwd *pw;
  130.     char psbuff[128];
  131. #endif
  132. #ifdef SPEEDCONFIG
  133.     char c, buff[8];
  134. #endif
  135. #ifdef STATES
  136.     time_t delta, suicide;
  137.     int state;
  138. #endif
  139.     FILE *lock;
  140. /*
  141.  * catch and report all signals, but apply special treatment to legal signals
  142.  * Any program bugs get reported this way. You can get a core dump by sending
  143.  * it SIGFPE.
  144.  */
  145.      for(i=1;i<SIGUSR1;i++) signal(i, fault);
  146.      
  147.      signal(SIGHUP, SIG_IGN);
  148.      signal(SIGINT, SIG_IGN);
  149.      signal(SIGQUIT, SIG_IGN);
  150.      signal(SIGFPE, SIG_DFL);    /* you can get a core dump here */
  151.      signal(SIGALRM, wakeup);
  152.      signal(SIGTERM, closedown);
  153. /*
  154.  * Open the standard I/O file descriptors, if not already open.
  155.  * Running from init, we don't have a terminal, so output to LOGFILE.
  156.  */
  157.      if((i = open("/dev/null", 0)) == 0) {
  158.          open("/dev/null", 1);
  159.          open("/dev/null", 1);
  160.      }
  161.      else close(i);
  162.      freopen(LOGFILE, "a", stdout);
  163. #ifdef SETBUF
  164.     setbuf(stdout, NULL);            /* if setvbuf broken */
  165. #else
  166.      setvbuf(stdout, NULL, _IOLBF, 0);
  167. #endif
  168.  
  169.     if (argc < 2)
  170.     {
  171.         printf("Usage: %s <tty> [<speed>]\n", argv[0]);
  172.         sleep(5);
  173.         exit(5);
  174.     }
  175.           
  176.     sprintf(dname, "/dev/%s", argv[1]);
  177. #if defined(OL3B2)
  178.     sprintf(lockf, "/usr/spool/locks/LCK..%s", argv[1]);
  179. #else
  180. #if  defined(HDB)
  181.     sprintf(lockf, "/usr/spool/locks/LCK.L.%s", argv[1]);
  182. #else
  183.     sprintf(lockf, "/usr/spool/uucp/LCK..%s", argv[1]);
  184. #endif
  185. #endif
  186. /*
  187.  * do not start while device is locked
  188.  */
  189.      while(locked()) sleep(30);
  190.     if((dev = open(dname, O_RDWR | O_NDELAY)) == -1) {
  191.             perror(dname);
  192.             sleep(5);    /* don't go crazy with respawns */
  193.             exit(4);
  194.     }
  195.  
  196.  /*
  197.   * setup correct time zone
  198.   */
  199.     putenv(TIMEZONE);
  200.  /*
  201.   * set terminal parameters
  202.   * Additional argument (if present) can be used to force an initial speed
  203.   * (Thanks rick)
  204.   */
  205.     if(argc > 2) speed = argv[2];
  206.     else speed = DEFSPEED;
  207.     baud = findspeed(speed);
  208.     init_term(dev, baud);
  209. /*
  210.  * send-expect strings - at the end, someone has connected to the modem
  211.  */
  212. #ifdef STATES
  213. /*
  214.  * find out when the next state change is due to occur. At this point, we exit.
  215.  * The next initiation will set the modem up differently.
  216.  */
  217.     delta = duration(&state);
  218.     suicide = time((long *) 0) + delta;
  219. #endif
  220.     for(p = ring; p->c_send; p++) {
  221. #ifdef STATES
  222.         if(!applicable(p, state)) continue;
  223. #endif
  224.         send(p->c_send, mywrite);
  225. #ifdef STATES
  226.         if(expect(p->c_expect, (int)(p->c_wait ? min(p->c_wait, delta) : delta), myread)) {
  227. #else
  228.         if(expect(p->c_expect, p->c_wait, myread)) {
  229. #endif
  230.             t = time((long *) 0);
  231. #ifdef STATES
  232.             if(t >= suicide) {
  233.                 printf("Exit due to state change\n");
  234.                 exit(0);
  235.             }
  236. #endif
  237.             printf("Incoming call failed to connect on %s", asctime(localtime(&t)));
  238. /*
  239.  * we don't have to do anything special here, since no locks have been setup.
  240.  * However, since the main problems appear to be non-responding modems, send
  241.  * it some sort of 'un-wedging' sequence
  242.  */
  243.              send(RESET, mywrite);
  244.              sleep(3);
  245.             hangup(dev);
  246.             sleep(10);
  247.             ioctl(dev, TCFLSH, 2);    /* Flush both queues */
  248.             exit(3);
  249.             /*NOTREACHED*/
  250.         }
  251.     }
  252.     signal(SIGALRM, wakeup);
  253. /*
  254.  * OK - incoming call connected. Find speed (if possible), create lock file,
  255.  * then spawn getty.
  256.  * At this point, we also trap hangups, so that we can clean up after
  257.  * any incoming calls. (Hangups are now detected by the hardware).
  258.  */
  259.      signal(SIGHUP, closedown);
  260. #ifdef SPEEDCONFIG
  261.      dread(dev, &c, 1);
  262.      if(c == '\r') speed = "300";
  263.      else {
  264.          dread(dev, buff, 4);
  265.          if(!strcmp(buff, "1200")) speed = "1200";
  266.          if(!strcmp(buff, "2400")) speed = "2400";
  267.          if(!strcmp(buff, "1275")) speed = "1200";
  268.          if(!strcmp(buff, "7512")) speed = "1200";
  269.      }
  270.      baud = findspeed(speed);
  271. #endif
  272.     
  273.      t = time((long *)0);
  274.      printf("Call connected at %s on %s", speed, asctime(localtime(&t)));
  275. /*
  276.  * Someone has rung in - lock the device.
  277.  */
  278.      lock = fopen(lockf, "w");
  279.  /*
  280.   * hand over to "getty"
  281.   */
  282.      arg[0] = "getty";
  283.      arg[1] = "-h";
  284.      arg[2] = argv[1];
  285.      arg[3] = speed;
  286.     arg[4] = NULL;
  287.     
  288.     if(shell = fork()) {
  289. /*
  290.  * change the utmp pid to the "getty" process, so that it can login
  291.  */
  292.         uchange(getpid(), shell);    /* change utmp entry */
  293. #if defined(OL3B2)
  294.          fprintf(lock,"       %d\n", shell);
  295. #else
  296. #if  defined(HDB)
  297.          fprintf(lock,"%d\n", shell);
  298. #else
  299.         fwrite((char *) &shell, sizeof shell, 1, lock);
  300. #endif
  301. #endif
  302.          fclose(lock);
  303. /*
  304.  * wait for logout from shell. 
  305.  * if terminal is idle for IDLETIME, force a logout anyway
  306.  */
  307.          alarm(SPYTIME);
  308.         while((wait(&status) == -1) && (errno == EINTR)) {
  309.             if(stat(dname, &sbuf) == -1) {
  310.                 perror(dname);
  311.                 continue;
  312.             }
  313.             now = time((long *)0);
  314.             mtime = max(sbuf.st_atime, sbuf.st_mtime);
  315.  
  316.             if((now - mtime) >= IDLETIME) {
  317.                 write(dev, "autologout\r\n", 12);
  318.                 printf("Device idle - autologout at %s\n",
  319.                     asctime(localtime(&now)));
  320.                 uchange(shell, getpid());
  321.                 autologout(shell);
  322.                 break;
  323.             }
  324.  
  325. #ifdef WATCHIT
  326.             t = time((long *) 0);
  327.             pw = getpwuid((int) sbuf.st_uid);
  328.             printf("Logon user is %s on %s", pw->pw_name,
  329.                 asctime(localtime(&t)));
  330.             procs = popen("ps -ef", "r");
  331.             while(fgets(psbuff, sizeof psbuff, procs)) 
  332.                 if(partof(psbuff, argv[1]) && partof(psbuff, pw->pw_name))
  333.                     printf("%s", psbuff);
  334.             pclose(procs);
  335. #endif
  336.             alarm(SPYTIME);
  337.         }
  338.          t = time((long *) 0);
  339.         printf("Call disconnected on %s", asctime(localtime(&t)));
  340.         closedown(0);        /* remove locks etc */
  341.         /*NOTREACHED*/
  342.     }
  343.     else {
  344.         sleep(1);            /* allow changes to utmp */
  345. /*
  346.  * Re-do the termio settings, so that we can login.
  347.  * CLOCAL is removed at this point, so that a hangup will generate SIGHUP.
  348.  * Close all the files which we have open - getty expects none.
  349.  */
  350.          login_term(dev, baud);
  351.          for(i=0;i<20;i++) close(i);
  352. #ifdef    DEBUG     
  353.          printf("%d: /etc/getty %s %s\n", getpid(), arg[1], arg[2]);
  354. #endif
  355.         execve("/etc/getty", arg, envp);
  356.         printf("can't exec getty\n");
  357.         exit(1);
  358.         /* NOTREACHED */
  359.     }
  360. }
  361. /*
  362.  * check for presence of lock file
  363.  * return 1 if locked.
  364.  */
  365. locked(){
  366.     struct stat sb;
  367.     if(stat(lockf, &sb) == -1) return(0);
  368. #ifdef    DEBUG
  369.     printf("%s locked\n", lockf);
  370. #endif
  371.     return(1);
  372. }
  373. #ifdef WATCHIT
  374. /*
  375.  * partof: look for str in text. Has a bug if you look for ...xxx...
  376.  */
  377. partof(text, str)
  378. char *text, *str;
  379. {
  380.     char *needle, *p;
  381.     for(p = text, needle = str; *p ; p++) {
  382.         if(*p != *needle) needle = str;
  383.         if(*p == *needle) needle++;
  384.         if(*needle == '\0') return(1);
  385.     }
  386.     return(0);
  387. }
  388. #endif
  389. /*
  390.  * autologout: log out the child shell. Sends SIGHUP, SIGTERM, SIGKILL
  391.  * until the child exits.
  392.  */
  393. autologout(child)
  394. {
  395.     kill(child, SIGHUP);
  396.     alarm(GRACETIME);
  397.     if(wait(&status) == -1) {
  398.         kill(child, SIGTERM);
  399.         alarm(GRACETIME);
  400.         if(wait(&status) == -1) {
  401.             kill(child, SIGKILL);
  402.             alarm(GRACETIME);
  403.             if(wait(&status) == -1) {
  404.                 printf("Cannot kill child pid %d\n", child);
  405.                 status = 0;
  406.             }
  407.         }
  408.     }
  409.     alarm(0);
  410. }
  411.