diff options
Diffstat (limited to 'src/tet3/tcclib/tcfexec.c')
-rw-r--r-- | src/tet3/tcclib/tcfexec.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/src/tet3/tcclib/tcfexec.c b/src/tet3/tcclib/tcfexec.c new file mode 100644 index 00000000..6ff9ba14 --- /dev/null +++ b/src/tet3/tcclib/tcfexec.c @@ -0,0 +1,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. + */ + +#ifndef lint +static char sccsid[] = "@(#)tcfexec.c 1.6 (98/09/01) TET3 release 3.3"; +#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- */ +} + + + + |