summaryrefslogtreecommitdiff
path: root/fonts/utilities/mff-29/fx.c
blob: 86935452e6362d4ef9bdc2cf546d534533d23587 (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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
/* fx.c 2.9.0 92/07/06 - the simple fork-and-exec function used in mff.c
 *
 *  The only f&x needed is calling up METAFONT and GFtoPK,
 *  and these programs take only one argument.  It is convenient
 *  to allow the templates given to include spaces, e.g.,
 *  `-M "jobserver -q cmmf"' actually runs `jobserver'.
 *
 *  I have ignored the "struct wait" nonsense -- Edition 7 all the way! :-)
 *
 *  ATARI ST (and presumablu MS-DOS?) modification -- pdc 25 Jul 91
 *  There is no fork-&-exec in TOS; Use spawnvp instead.
 *
-----------------------------------------------------------------------
    This software module copyright (c) 1990, 1991 Damian Cugley.  
    It is provided for free on an "as-is" basis.
    See the file COPYING for more information.
-----------------------------------------------------------------------
 *  Created - pdc Mon 15 Jan 1990
 */

#include "config.h"

#ifndef NO_EXEC_USE_SPAWN
#  include <signal.h>		/* NSIG */
#else
#  include <process.h>		/* P_WAIT */
#endif /* no_exec_use_spawn */

#include <errno.h>

#include "stdc.h"
#include "xstdio.h"		/* <stdio.h> plus prototypes */
#include "fatal.h"		/* how to error messages */
#include "strmisc.h"		/* incl. <string(s).h> */
#include "fx.h"

NONRETURNING void exit ARGS((int));

#define TRUE	1
#define FALSE	0


#ifndef lint
addr realloc ARGS((addr, sizeof_t));
#else
#  define realloc(P,S) 0
#endif

#define MORE	16
/*
 *  generate more argv slots in batches of 16
 *  (I will be surprised if 16 are needed!)
 */

/*
 *  Construct an argv vector for the child process.
 *
 * |command| is pointer to zero-terminated string of characters;
 *  it is broken up as per strword(3) into separate arguments.
 * |arg| is a final argument to append to the |argv| vector;
 *  it is *not* broken into words.
 */
static inline char **
construct_args(command, argc, argv)
     int argc;
     char *command, **argv;
{
  int		num_args = 0, max_args = MORE + argc;
  char	      **nargv = (char **)xmalloc(max_args * sizeof(char *)),
	       *p, *strword_state;

  if (!(p = strword(command, &strword_state)))
    syntaxf("command string is empty!");
				/* There should always be at least one word */
  do 
    {
      if (max_args - num_args == 1 + argc) /* always two spare arg slots */
	{
	  /*  try to make some more room  */
	  nargv = (char **)
	    xrealloc(nargv, (max_args += MORE) * sizeof (char *));
	}
      nargv[num_args++] = p;
      p = strword((char *)NULL, &strword_state);
    } while (p);

  /*  There are always two free slots in the |nargv| array:  */
  while (argc-- > 0)
    nargv[num_args++] = *argv++;
  
  nargv[num_args] = (char *)NULL;
  return nargv;
}


/*
 *  fx -- run a subprocess and wait for it to finish
 */

#ifdef NO_EXEC_USE_SPAWN

void
fx(char *command, int argc, char **argv)
{
  char	      **argv = construct_args(command, argc, argv);
  int		exit_code = spawnvp(P_WAIT, argv[0], argv);
  
  xfree((addr)argv);
  if (exit_code < 0)		/* I am guessing positive exit codes are OK */
    fatalf("%s terminated with exit code %d\n", command, exit_code);
}

#else /* EXEC is available: */

#ifdef BSD
#  ifndef vfork
#    define fork vfork
/*
 *  use vfork in preference to fork -- unless vfork has been #defined
 *  to fork (which might be expected on post-VM-problems UNIXes
 */
#  endif
#endif

int	wait ARGS((int *));
int	fork ARGS((void));
int	execvp ARGS((const char *, const char **));
void NONRETURNING _exit ARGS((int));
     
#ifdef NO_SIGLIST

/*  
 *  Must supply own list of signal names:
 */
static const char *sys_siglist[] =
{
  "shookum hip RALLO dine!",	/* there is no signal 0 */
  "hangup",
  "interrupt",
  "quit",
  "illegal instruction",
  "trace trap",			/* 5 */
  "IOT Trap",
  "EMT trap", 
  "arithmetic exception",
  "kill -KILL",
  "bus error",			/* 10 */
  "violation of segments",
  "bad argument to system call",
  "unrequited pipe",
  "alarm clock",
  "software terminate -- from kill(2)",	/* 15 */
  /*  that was the Edition 7 signals (0-15)... */
#ifdef USG
  "user-defined signal number 1", /* 16 */
  "user-defined signal number 2", /* 17 */
  "lonely child process",	/* 18 */
  "death! death! death!",	/* 19 -- power failure */
  /*
   *  For other systems (4.1 BSD?), signals > 15
   *  will be reported numerically.
   */
#endif /* USG */
};

/*  define NSIG to be # of messages in above:  */
#  undef NSIG
#  define NSIG ((sizeof sys_siglist)/sizeof (char *))

#else /* have siglist */
      extern const char *sys_siglist[];
#endif

extern char *sys_errlist[];
extern int sys_nerr;


/*
 *  classic fork and exec -- |command| and |arg| as above.
 *  Waits for child to finish.
 */
void				/* aborts if can't exec */
fx(command, argc, argv)
     int argc;
     char *command, **argv;
{
  int		pid, t;
  int		status,		/* status word from wait() */
  		exit_code;	/* exit code of child */
  
  argv = construct_args(command, argc, argv);
  
  if ((pid = fork()) < 0) pfatalf("fork");
  else if (pid == 0)
    {
      /*  This is the child  */
      (void)execvp((const char *)argv[0], (const char **)argv);
      /*  If we get here, something's gone wrong:  */
      perrorf(argv[0]);
      _exit(1);			/* don't use exit() in child */
    }

  /*  This is the parent process  */
#ifdef BSD
  t = wait(&status);
#else
  while ((t = wait(&status)) < 0 && errno == EINTR)
    ;
#endif
  if (t != pid) pfatalf("very surprised because wait returned %d", t);
  xfree((addr)argv);

  if ((status & 0xFF) != 0)
    {
      /*  Terminated by signal: */
      int sig = status & 0x7F;

      fprintf(stderr, "%s killed by signal %d", command, sig);
      if (sig < NSIG)
	fprintf(stderr, " (%s)\n", sys_siglist[sig]);
      if (status & 0x80)
	fprintf(stderr, "Wow, coredump city.\n");
      exit(1);
    }
  else if (exit_code = status >> 8 & 0xFF)
    {
      fprintf(stderr, "%s terminated with exit code %d.\n", 
	      command, exit_code);
      exit(1);
    }
}


#ifdef NO_EXECVP
/*
 *  This is intended as a version of execvp for systems that don't have it.
 *  (V7, BSD 4.2?)
 *
 *  If an executable file is found for which execv() fails,
 *  it is assumed to be a shellscript and /bin/sh is invoked with
 *  its full pathname as first argument.
 *
 *  pdc Thur. 27 June 1991
 */

#include <sys/param.h>
#ifndef MAXPATHLEN
#  define MAXPATHLEN 1024
#endif
#include "strmisc.h"
#include "searchpath.h"		/* might as well use that */

int				/* returns -1 if fails */
execvp(progname, argv)
     const char *progname;		/* name of prog to search for */
     const char *argv[];		/* vector of arguments */
{
  const char *getenv ARGS((const char *));
  int execv ARGS((const char *, const char *[]));
  
  char scratch[MAXPATHLEN];
  const char *path = getenv("PATH");

  if (!path) path = "";		/* for mad people who like PATH-free shells */
  
  if (findfile(scratch, progname, path, (char *)0))
    {
      if (execv(scratch, argv),  errno == ENOEXEC)
	{
	  /*
	   *  a /bin/sh command file
	   *  Substitute pathname of file as 1st argument to sh:
	   *    execvp("fo", {"fo","arg","brg",0}) -> 
	   *      /bin/sh /usr/local/bin/fo arg brg
	   */
	  const char **nargv; /* ptr to vect of ptrs to vects of const char */
	  int argc;

	  /*
	   *  count args:
	   */
	  {
	    register const char **t = argv;
	    while (*t) ++t;
	    argc = (t - argv);
	  }
	  
	  /* allocate room for 1 more arg & the NULL */
	  /* copy the NULL and the args except the 0'th arg */
	  nargv = (const char **)xmalloc(sizeof (char *) * (argc + 2));
	  bcopy((addr)(argv + 1), (addr)(nargv + 2),
		argc*(sizeof (char *)));
	  nargv[0] = "/bin/sh"; 
	  nargv[1] = scratch;
	  execv(nargv[0], nargv);

	  /*  failed -- */
	  xfree((addr)nargv);
	}
    }
  else
    {
      /*  findfile returned FALSE  */
      errno = ENOENT;
    }

  return -1;
}
#endif  /* NO_EXECVP */
#endif  /* NO_EXEC_USE_SPAWN */