summaryrefslogtreecommitdiff
path: root/src/tet3/tcclib/tcfexec.c
blob: cc6e76fb525b9b6e27cab260c76180c9ff486e68 (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
/*
 *	SCCS: @(#)tcfexec.c	1.6 (98/09/01)
 *
 *	UniSoft Ltd., London, England
 *
 * (C) Copyright 1996 X/Open Company Limited
 *
 * All rights reserved.  No part of this source code may be reproduced,
 * stored in a retrieval system, or transmitted, in any form or by any
 * means, electronic, mechanical, photocopying, recording or otherwise,
 * except as stated in the end-user licence agreement, without the prior
 * permission of the copyright owners.
 * A copy of the end-user licence agreement is contained in the file
 * Licence which accompanies this distribution.
 * 
 * X/Open and the 'X' symbol are trademarks of X/Open Company Limited in
 * the UK and other countries.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/************************************************************************

SCCS:   	@(#)tcfexec.c	1.6 98/09/01 TETware release 3.3
NAME:		tcfexec.c
PRODUCT:	TETware
AUTHOR:		Andrew Dingwall, UniSoft Ltd.
DATE CREATED:	October 1996

DESCRIPTION:
	tcc action function - start a new process, possibly with redirected
	stdout and stderr

	this function moved from tccd/exec.c to here

MODIFICATIONS:
	Andrew Dingwall, UniSoft Ltd., May 1997
	port to Windows 95

	Andrew Dingwall, UniSoft Ltd., July 1997
	Only do NO sync from a child process so as to avoid deadlock.
	Added support the MT DLL version of the C runtime support library
	on Win32 systems.

	Andrew Dingwall, UniSoft Ltd., July 1998
	Added support for shared API libraries.
 

************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#  include <unistd.h>
#include "dtmac.h"
#include "dtmsg.h"
#include "error.h"
#include "globals.h"
#include "synreq.h"
#include "servlib.h"
#include "dtetlib.h"
#include "tcclib.h"

#ifndef NOTRACE
#  include "ltoa.h"
#endif

/* open mode for files */
#define MODEANY \
	((mode_t) (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))

#ifdef NEEDsrcFile
static char srcFile[] = __FILE__;	/* file name for error reporting */
#endif


#ifndef TET_LITE	/* -START-LITE-CUT- */
extern void tet_disconnect();
#endif /* !TET_LITE */	/* -END-LITE-CUT- */

extern char **ENVIRON;

/* static function declarations */
static int checkexec PROTOLIST((char *));
static void donasync PROTOLIST((long));


/*
**	tcf_exec() - start a new process
**
**	return ER_OK if successful or other ER_* error code on error
**
**	if successful, the pid of the new process is returned indirectly
**	through *pidp
*/

int tcf_exec(path, argv, outfile, snid, flag, pidp)
char *path, **argv, *outfile;
long snid;
int flag, *pidp;
{
	register int pid, rc;

	register int fd, n;

#ifndef NOTRACE
	register char **ap;
#endif /* !NOTRACE */

	/* see if an exec has any chance of succeeding */
	if (checkexec(path) < 0) {
		TRACE3(Ttcclib, 4, "checkexec(\"%s\") failed, errno = %s",
			path, tet_errname(errno));
		return(ER_NOENT);
	}

#ifndef NOTRACE
	if (Ttcclib > 0) {
		TRACE2(Ttcclib, 4, "exec \"%s\"", path);
		for (ap = argv; *ap; ap++)
			TRACE2(Ttcclib, 6, "arg = \"%s\"", *ap);
		for (ap = ENVIRON; *ap; ap++)
			TRACE2(Ttcclib, 8, "env = \"%s\"", *ap);
	}
#endif /* !NOTRACE */


	/* open the output file if one has been specified */
	if (outfile && *outfile) {
		TRACE2(Ttcclib, 4, "send output to \"%s\"", outfile);
		if ((fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, MODEANY)) < 0) {
			error(errno, "can't open", outfile);
			return(ER_ERR);
		}
		else if (tet_fioclex(fd) < 0) {
			(void) close(fd);
			return(ER_ERR);
		}
	}
	else
		fd = -1;

	/* do the fork and exec -
		in the child process:
		if outfile was specified, attach stdout and stderr to outfile
		the original outfile fd is already close-on-exec
		stdin is attached to /dev/null
		close all other file descriptors
		the "can't exec" message goes to outfile if one is specified */
	if ((pid = tet_dofork()) == 0) {
		/* in child */
		if (fd >= 0) {
			(void) fflush(stdout);
			(void) close(1);
			if (fcntl(fd, F_DUPFD, 1) != 1) {
				error(errno, "can't dup stdout", (char *) 0);
				_exit(~0);
			}
			(void) fflush(stderr);
			(void) close(2);
			if (fcntl(fd, F_DUPFD, 2) != 2) {
				error(errno, "can't dup stderr", (char *) 0);
				_exit(~0 - 1);
			}
		}
		for (n = tet_getdtablesize() - 1; n > 2; n--) {
			if (n != fd)
				(void) close(n);
		}
		tcc_exec_signals();
		(void) execvp(path, argv);
		error(errno, "can't exec", path);
		switch (flag) {
		case TCF_EXEC_TEST:
		case TCF_EXEC_USER:
			donasync(snid);
			break;
		}
		_exit(~0);
		/* NOTREACHED */
	}
	else if (pid < 0) {
		error(errno, "fork failed: path =", path);
		rc = ER_FORK;
	}
	else {
		/* in parent */
		rc = ER_OK;
	}

	/* close outfile in the parent if one was specified */
	if (fd >= 0)
		(void) close(fd);


	TRACE3(Ttcclib, 4, "after exec: pid = %s, return %s",
		tet_i2a(pid), tet_ptrepcode(rc));

	*pidp = pid;
	return(rc);
}



/*
**	checkexec() - see if an exec has any chance of succeeding
**
**	return 0 if successful or -1 on error
*/

static int checkexec(file)
char *file;
{
	register char *p1, *p2;
	register char *path;
	char fname[MAXPATH];

	/* see if there is a / in the file name */
	for (p1 = file; *p1; p1++)
		if (*p1 == '/')
			break;

	/* if there is or there is no PATH, just check the file name */
	if (*p1 || (path = getenv("PATH")) == (char *) 0 || !*path) {
		TRACE2(Ttcclib, 6, "checkexec: try \"%s\"", file);
		return(tet_eaccess(file, 01));
	}

	/*
	** otherwise, try prepending each component of the PATH environment
	** variable
	*/
	TRACE2(Ttcclib, 6, "checkexec: PATH = \"%s\"", path);
	p1 = path;
	p2 = fname;
	do {
		if (!*p1 || *p1 == ':') {
			if (p2 > fname && p2 < &fname[sizeof fname - 2])
				*p2++ = '/';
			*p2 = '\0';
			(void) sprintf(p2, "%.*s",
				(int) (&fname[sizeof fname - 1] - p2), file);
			TRACE2(Ttcclib, 6, "checkexec: try \"%s\"", fname);
			if (tet_eaccess(fname, 01) == 0)
				return(0);
			p2 = fname;
		}
		else if (p2 < &fname[sizeof fname - 2])
			*p2++ = *p1;
	} while (*p1++);

	/* here if not found anywhere */
	return(-1);
}

/*
**	donasync() - do a NO auto-sync if a testcase or user exec fails
**
**	since this function may block, it can only be called from a
**	child process; so it can't be used on WIN32
*/

#ifdef TET_LITE	/* -LITE-CUT-LINE- */
/* ARGSUSED */
#endif /* TET_LITE */	/* -LITE-CUT-LINE- */

static void donasync(snid)
long snid;
{
#ifndef TET_LITE	/* -START-LITE-CUT- */

	/* log on to the syncd */
	if (tet_sdlogon() < 0)
		return;

	if (tet_sdasync(snid, -1L, SV_EXEC_SPNO, SV_NO, SV_EXEC_TIMEOUT, (struct synreq *) 0, (int *) 0) < 0)
		error(0, "after failed exec, autosync(NO) failed:",
			tet_ptrepcode(tet_sderrno));

	SLEEP(2);
	(void) tet_sdlogoff(0);

#endif /* !TET_LITE */	/* -END-LITE-CUT- */
}