1/* 2# File: dialHDB.c 3# Author: Daniel Hagerty , hag@eddie.mit.edu 4# Copyright (C) 1993 5# Date: Fri Nov 26 19:22:31 1993 6# Description: Program for using HDB dialers for dialing modems, exiting 7 with 0 on success, else failure. 8# Version: 1.0 9# Revision History: 10###### 11### 11/26/93 Hag - File creation 12###### 13### 1/5/94 Hag - Finally got around to finishing this damn thing. 14###### 15*/ 16/* Basic theory behind this program- 17 dialHDB forks into two processes, a monitor parent, and a child 18 that does the exec of the dialer. Child pretty much just execs the 19 dialer program, unless there's an exec problem, in which case the 20 child sends the parent a SIGUSR1 to indicate failed execution. 21*/ 22 23#include <stdio.h> 24#include <string.h> 25#include <sys/types.h> 26#include <sys/wait.h> 27#include <signal.h> 28 29#define kUsage "Usage:\n\t%s dialerPath device number speed\n\ 30%s dialer -h device speed\n" 31 32#define kExitErrFlag 0x80 /* & in with exit code to determine error */ 33#define kErrorMask 0x0f /* Mask to determine error code */ 34 35/* Error code defines as lifted from an HDB dialer */ 36#define RCE_NULL 0 /* general purpose or unknown error code */ 37#define RCE_INUSE 1 /* line in use */ 38#define RCE_SIG 2 /* signal aborted dialer */ 39#define RCE_ARGS 3 /* invalid arguments */ 40#define RCE_PHNO 4 /* invalid phone number */ 41#define RCE_SPEED 5 /* invalid baud rate -or- bad connect baud */ 42#define RCE_OPEN 6 /* can't open line */ 43#define RCE_IOCTL 7 /* ioctl error */ 44#define RCE_TIMOUT 8 /* timeout */ 45#define RCE_NOTONE 9 /* no dial tone */ 46#define RCE_BUSY 13 /* phone is busy */ 47#define RCE_NOCARR 14 /* no carrier */ 48#define RCE_ANSWER 15 /* no answer */ 49 50/* Structure definition to map error codes to strings */ 51typedef struct 52{ 53 int errNum; 54 char *errString; 55} errTable; 56 57const errTable errors[]= 58{ 59 { RCE_NULL, "Unknown Error" }, 60 { RCE_INUSE, "Line is being used" }, 61 { RCE_SIG, "Recieved fatal signal" }, 62 { RCE_ARGS, "Bad arguments" }, 63 { RCE_PHNO, "Invalid phone number" }, 64 { RCE_SPEED, "Invalid baud rate or bad connection" }, 65 { RCE_OPEN, "Unable to open line" }, 66 { RCE_IOCTL, "ioctl error" }, 67 { RCE_TIMOUT, "Timed out" }, 68 { RCE_NOTONE, "No dialtone" }, 69 { RCE_BUSY, "Phone number is busy" }, 70 { RCE_NOCARR, "No carrier" }, 71 { RCE_ANSWER, "No answer" }, 72 { 0,NULL} 73}; 74 75/* Function Prototypes */ 76int figureStat(int stat); 77char *findInTable(int error); 78void badExec(void); 79 80char *dialerName; /* basename of our dialer program */ 81char *dialerPath; /* full path of dialer program */ 82 83main(int argc,char *argv[]) 84{ 85 int parent; /* pid of parent process */ 86 int child; /* pid of child process */ 87 int stat; /* exit status of child process */ 88 char *temp; /* used to get basename of dialer */ 89 90 if(argc!=5) 91 { 92 fprintf(stderr,kUsage,argv[0],argv[0]); 93 exit(1); 94 } 95 96 dialerPath=argv[1]; 97 dialerName= (temp=strrchr(argv[1],'/'))!=NULL ? temp+1 : argv[1]; 98 99 parent=getpid(); 100 101 signal(SIGUSR1,badExec); /* set up for possible failed exec */ 102 103 if((child=fork())<0) 104 { 105 perror("fork"); 106 exit(2); 107 } 108 if(child>0) /* We're parent, wait for child to exit */ 109 { 110 /* Set up to ignore signals so we can report them on stderror */ 111 signal(SIGHUP,SIG_IGN); 112 signal(SIGINT,SIG_IGN); 113 signal(SIGTERM,SIG_IGN); 114 115 wait(&stat); /* wait for child to exit */ 116 exit(figureStat(stat)); /* figure out our exit code and die */ 117 } 118 else /* child process */ 119 { 120 close(0); /* close of modem file desc, since HDB */ 121 close(1); /* doesn't use them */ 122 dup2(2,1); /* and remap stdout to stderr, just in case */ 123 if(execvp(argv[1],argv+1)<0) /* exec program with argv shifted by 1 */ 124 { /* if exec fails, send SIGUSR1 to parent */ 125 kill(parent,SIGUSR1); 126 exit(0); 127 } 128 } 129 exit(0); 130} 131 132/* Figure out whether or not dialer ran succesfully, and return 133with 0 if it worked, otherwise error */ 134int figureStat(int stat) 135{ 136 int exit; 137 int errFlag; 138 int error; 139 140 if(WIFSIGNALED(stat)) /* determine if exit was from signal or what */ 141 { 142 fprintf(stderr,"Error: Dialer %s recieved signal %d.\n",dialerName, 143 WTERMSIG(stat)); 144 return(1); 145 } 146 if(WIFSTOPPED(stat)) 147 { 148 fprintf(stderr,"Error: Dialer %s recieved signal %d.\n",dialerName, 149 WSTOPSIG(stat)); 150 return(1); 151 } 152 exit=WEXITSTATUS(stat); 153 154 errFlag=exit&kExitErrFlag; /* Is the error flag set? */ 155 if(errFlag) 156 { 157 char *errString; 158 159 error=exit&kErrorMask; 160 errString=findInTable(error); /* find it's string, print it on stderr */ 161 fprintf(stderr,"Error: %s - %s.\n",dialerName,errString); /* and return */ 162 return(1); 163 } 164 return(0); 165} 166 167/* Support routine, look up exit code in error table, and return pointer 168to proper string */ 169char *findInTable(int error) 170{ 171 int i=0; 172 173 for(i=0;errors[i].errString!=NULL;i++) 174 { 175 if(errors[i].errNum==error) 176 return(errors[i].errString); 177 } 178 /* Still here, return the top entry, for unknown error */ 179 return(errors[0].errString); 180} 181 182/* Called by signal if we recieve SIGUSR 1 */ 183void badExec(void) 184{ 185 fprintf(stderr,"Error: %s - Execution problem.\n",dialerPath); 186 exit(1); 187} 188