summaryrefslogtreecommitdiffstats
path: root/gnu/libexec/uucp/contrib/dialHDB.c
blob: 8650ff023b6565535032d9402ff937c3b2225860 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*
# File:		dialHDB.c
# Author:	Daniel Hagerty , hag@eddie.mit.edu
#		Copyright (C) 1993
# Date:		Fri Nov 26 19:22:31 1993
# Description:	Program for using HDB dialers for dialing modems, exiting
		with 0 on success, else failure.
# Version:	1.0
# Revision History:
######
### 11/26/93 Hag - File creation
######
### 1/5/94 Hag - Finally got around to finishing this damn thing.
######
*/
/* Basic theory behind this program-
   dialHDB forks into two processes, a monitor parent, and a child
   that does the exec of the dialer. Child pretty much just execs the
   dialer program, unless there's an exec problem, in which case the
   child sends the parent a SIGUSR1 to indicate failed execution.
*/

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>

#define kUsage	"Usage:\n\t%s dialerPath device number speed\n\
%s dialer -h device speed\n"

#define kExitErrFlag	0x80	/* & in with exit code to determine error */
#define kErrorMask	0x0f	/* Mask to determine error code */

/* Error code defines as lifted from an HDB dialer */
#define	RCE_NULL	0	/* general purpose or unknown error code */
#define	RCE_INUSE	1	/* line in use */
#define	RCE_SIG		2	/* signal aborted dialer */
#define	RCE_ARGS	3	/* invalid arguments */
#define	RCE_PHNO	4	/* invalid phone number */
#define	RCE_SPEED	5	/* invalid baud rate -or- bad connect baud */
#define	RCE_OPEN	6	/* can't open line */
#define	RCE_IOCTL	7	/* ioctl error */
#define	RCE_TIMOUT	8	/* timeout */
#define	RCE_NOTONE	9	/* no dial tone */
#define	RCE_BUSY	13	/* phone is busy */
#define	RCE_NOCARR	14	/* no carrier */
#define	RCE_ANSWER	15	/* no answer */

/* Structure definition to map error codes to strings */
typedef struct
{
  int errNum;
  char *errString;
} errTable;

const errTable errors[]=
{
  { RCE_NULL,	"Unknown Error" },
  { RCE_INUSE,	"Line is being used" },
  { RCE_SIG,	"Recieved fatal signal" },
  { RCE_ARGS,	"Bad arguments" },
  { RCE_PHNO,	"Invalid phone number" },
  { RCE_SPEED,	"Invalid baud rate or bad connection" },
  { RCE_OPEN,	"Unable to open line" },
  { RCE_IOCTL,	"ioctl error" },
  { RCE_TIMOUT,	"Timed out" },
  { RCE_NOTONE,	"No dialtone" },
  { RCE_BUSY,	"Phone number is busy" },
  { RCE_NOCARR,	"No carrier" },
  { RCE_ANSWER,	"No answer" },
  { 0,NULL}
};

/* Function Prototypes */
int figureStat(int stat);
char *findInTable(int error);
void badExec(void);

char *dialerName;		/* basename of our dialer program */
char *dialerPath;		/* full path of dialer program */

main(int argc,char *argv[])
{
  int parent;			/* pid of parent process */
  int child;			/* pid of child process */
  int stat;			/* exit status of child process */
  char *temp;			/* used to get basename of dialer */

  if(argc!=5)
  {
    fprintf(stderr,kUsage,argv[0],argv[0]);
    exit(1);
  }

  dialerPath=argv[1];
  dialerName= (temp=strrchr(argv[1],'/'))!=NULL ? temp+1 : argv[1];

  parent=getpid();

  signal(SIGUSR1,badExec);	/* set up for possible failed exec */

  if((child=fork())<0)
  {
    perror("fork");
    exit(2);
  }
  if(child>0)			/* We're parent, wait for child to exit */
  {
    /* Set up to ignore signals so we can report them on stderror */
    signal(SIGHUP,SIG_IGN);
    signal(SIGINT,SIG_IGN);
    signal(SIGTERM,SIG_IGN);

    wait(&stat);		/* wait for child to exit */
    exit(figureStat(stat));	/* figure out our exit code and die */
  }
  else				/* child process */
  {
    close(0);			/* close of modem file desc, since HDB */
    close(1);			/* doesn't use them */
    dup2(2,1);			/* and remap stdout to stderr, just in case */
    if(execvp(argv[1],argv+1)<0) /* exec program with argv shifted by 1 */
    {				/* if exec fails, send SIGUSR1 to parent */
      kill(parent,SIGUSR1);
      exit(0);
    }
  }
  exit(0);
}

/* Figure out whether or not dialer ran succesfully, and return
with 0 if it worked, otherwise error */
int figureStat(int stat)
{
  int exit;
  int errFlag;
  int error;

  if(WIFSIGNALED(stat))		/* determine if exit was from signal or what */
  {
    fprintf(stderr,"Error: Dialer %s recieved signal %d.\n",dialerName,
	    WTERMSIG(stat));
    return(1);
  }
  if(WIFSTOPPED(stat))
  {
    fprintf(stderr,"Error: Dialer %s recieved signal %d.\n",dialerName,
	    WSTOPSIG(stat));
    return(1);
  }
  exit=WEXITSTATUS(stat);

  errFlag=exit&kExitErrFlag;	/* Is the error flag set? */
  if(errFlag)
  {
    char *errString;

    error=exit&kErrorMask;
    errString=findInTable(error); /* find it's string, print it on stderr */
    fprintf(stderr,"Error: %s - %s.\n",dialerName,errString); /* and return */
    return(1);
  }
  return(0);
}

/* Support routine, look up exit code in error table, and return pointer
to proper string */
char *findInTable(int error)
{
  int i=0;

  for(i=0;errors[i].errString!=NULL;i++)
  {
    if(errors[i].errNum==error)
      return(errors[i].errString);
  }
  /* Still here, return the top entry, for unknown error */
  return(errors[0].errString);
}

/* Called by signal if we recieve SIGUSR 1 */
void badExec(void)
{
  fprintf(stderr,"Error: %s - Execution problem.\n",dialerPath);
  exit(1);
}
OpenPOWER on IntegriCloud