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