|
Packit |
857059 |
/* BEGIN_ICS_COPYRIGHT5 ****************************************
|
|
Packit |
857059 |
|
|
Packit |
857059 |
Copyright (c) 2015, Intel Corporation
|
|
Packit |
857059 |
|
|
Packit |
857059 |
Redistribution and use in source and binary forms, with or without
|
|
Packit |
857059 |
modification, are permitted provided that the following conditions are met:
|
|
Packit |
857059 |
|
|
Packit |
857059 |
* Redistributions of source code must retain the above copyright notice,
|
|
Packit |
857059 |
this list of conditions and the following disclaimer.
|
|
Packit |
857059 |
* Redistributions in binary form must reproduce the above copyright
|
|
Packit |
857059 |
notice, this list of conditions and the following disclaimer in the
|
|
Packit |
857059 |
documentation and/or other materials provided with the distribution.
|
|
Packit |
857059 |
* Neither the name of Intel Corporation nor the names of its contributors
|
|
Packit |
857059 |
may be used to endorse or promote products derived from this software
|
|
Packit |
857059 |
without specific prior written permission.
|
|
Packit |
857059 |
|
|
Packit |
857059 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
Packit |
857059 |
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
857059 |
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
Packit |
857059 |
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
Packit |
857059 |
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
Packit |
857059 |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
Packit |
857059 |
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
Packit |
857059 |
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
Packit |
857059 |
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
Packit |
857059 |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
857059 |
|
|
Packit |
857059 |
* ** END_ICS_COPYRIGHT5 ****************************************/
|
|
Packit |
857059 |
/* [ICS VERSION STRING: unknown] */
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/*
|
|
Packit |
857059 |
* qlgc_fork.c -- TCL extension to workaround problems in exp_fork/exp_wait
|
|
Packit |
857059 |
* when TCL_THREADS enabled in build
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
#include <tcl.h>
|
|
Packit |
857059 |
#include <sys/types.h>
|
|
Packit |
857059 |
#include <unistd.h>
|
|
Packit |
857059 |
#include <sys/wait.h>
|
|
Packit |
857059 |
#include <errno.h>
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static int
|
|
Packit |
857059 |
Qlgc_fork_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
pid_t pid;
|
|
Packit |
857059 |
char result[20];
|
|
Packit |
857059 |
|
|
Packit |
857059 |
fflush(stdout);
|
|
Packit |
857059 |
fflush(stderr);
|
|
Packit |
857059 |
/* this is a bit of a hack, but seems to solve the problem
|
|
Packit |
857059 |
* by stopping and starting the notifier we ensure a notifier
|
|
Packit |
857059 |
* exists for the child process. We must stop it because the
|
|
Packit |
857059 |
* startup depends on hidden static status variables.
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
Tcl_FinalizeNotifier(NULL); // arg not used in TCL 8.4 on Linux
|
|
Packit |
857059 |
pid = fork();
|
|
Packit |
857059 |
(void)Tcl_InitNotifier();
|
|
Packit |
857059 |
sprintf(result, "%d", pid);
|
|
Packit |
857059 |
Tcl_SetObjResult(interp, Tcl_NewStringObj(result, -1));
|
|
Packit |
857059 |
return TCL_OK;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static int
|
|
Packit |
857059 |
Qlgc_wait_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
pid_t pid;
|
|
Packit |
857059 |
int status;
|
|
Packit |
857059 |
char result[20];
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* don't check args, this way the -i -1 arg of exp_wait is simply ignored */
|
|
Packit |
857059 |
pid = wait(&status);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
sprintf(result, "%d", pid);
|
|
Packit |
857059 |
Tcl_SetObjResult(interp, Tcl_NewStringObj(result, -1));
|
|
Packit |
857059 |
return TCL_OK;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#if 0 /* this is comparible to TCL's normal exit command, don't need this */
|
|
Packit |
857059 |
static int
|
|
Packit |
857059 |
Qlgc_exit_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int status;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/*
|
|
Packit |
857059 |
* Check params.
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
if (objc != 2) {
|
|
Packit |
857059 |
Tcl_WrongNumArgs(interp, 1, objv, "status");
|
|
Packit |
857059 |
return TCL_ERROR;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (Tcl_GetIntFromObj(interp, objv[1], &status) != TCL_OK) {
|
|
Packit |
857059 |
return TCL_ERROR;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
Tcl_Exit(status);
|
|
Packit |
857059 |
//fflush(stdout);
|
|
Packit |
857059 |
//fflush(stderr);
|
|
Packit |
857059 |
//exit(status);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/*NOTREACHED*/
|
|
Packit |
857059 |
return TCL_OK;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* This is a quick and dirty implementation of dup capability for TCL
|
|
Packit |
857059 |
* Usage: dup file
|
|
Packit |
857059 |
* Parameters:
|
|
Packit |
857059 |
* file - an existing TCL file/channel opened read/write
|
|
Packit |
857059 |
* Additional Information:
|
|
Packit |
857059 |
* Implemented and tested for intended usage of: close stderr; dup stdout
|
|
Packit |
857059 |
* such that stderr can be redirected to the same file used for stdout
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static int
|
|
Packit |
857059 |
Qlgc_dup_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
char *file;
|
|
Packit |
857059 |
Tcl_Channel channel;
|
|
Packit |
857059 |
Tcl_Channel newchannel;
|
|
Packit |
857059 |
ClientData handle;
|
|
Packit |
857059 |
int fd, newfd;
|
|
Packit |
857059 |
int mode;
|
|
Packit |
857059 |
char result[100];
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/*
|
|
Packit |
857059 |
* Check params.
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
if (objc != 2) {
|
|
Packit |
857059 |
Tcl_WrongNumArgs(interp, 1, objv, "file");
|
|
Packit |
857059 |
return TCL_ERROR;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
file = Tcl_GetStringFromObj(objv[1], NULL);
|
|
Packit |
857059 |
channel = Tcl_GetChannel(interp, file, &mode);
|
|
Packit |
857059 |
if (! channel)
|
|
Packit |
857059 |
goto failfile;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (Tcl_Flush(channel) == TCL_ERROR) {
|
|
Packit |
857059 |
errno = Tcl_GetErrno();
|
|
Packit |
857059 |
goto failerrno;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (TCL_ERROR == Tcl_GetChannelHandle(channel, TCL_WRITABLE, &handle))
|
|
Packit |
857059 |
goto failfile;
|
|
Packit |
857059 |
fd = (int)(long int)handle;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
newfd = dup(fd);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
newchannel = Tcl_MakeFileChannel((ClientData)(long)newfd, mode);
|
|
Packit |
857059 |
Tcl_RegisterChannel(interp, newchannel);
|
|
Packit |
857059 |
Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_GetChannelName(newchannel), -1));
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return TCL_OK;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
failfile:
|
|
Packit |
857059 |
Tcl_ResetResult(interp);
|
|
Packit |
857059 |
Tcl_AppendResult(interp, "qlgc_dup failed: invalid file handle: ", file, NULL);
|
|
Packit |
857059 |
goto fail;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
failerrno:
|
|
Packit |
857059 |
snprintf(result, sizeof(result), "qlgc_dup failed: %s", Tcl_PosixError(interp));
|
|
Packit |
857059 |
Tcl_SetObjResult(interp, Tcl_NewStringObj(result, -1));
|
|
Packit |
857059 |
|
|
Packit |
857059 |
fail:
|
|
Packit |
857059 |
return TCL_ERROR;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#if 0
|
|
Packit |
857059 |
// this idea was viable and sort of worked. Except that
|
|
Packit |
857059 |
// the TCL shell did not process the resulting trap handler
|
|
Packit |
857059 |
// until after the command being executed completed.
|
|
Packit |
857059 |
// This was intended as a way for opacmdall to set a timeout for
|
|
Packit |
857059 |
// remote ssh commands
|
|
Packit |
857059 |
typedef void (*signal_handler_t)(int);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static int have_old_alarm_handler = 0;
|
|
Packit |
857059 |
static signal_handler_t old_alarm_handler;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static void save_alarm_handler(signal_handler_t handler)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
if (! have_old_alarm_handler) {
|
|
Packit |
857059 |
printf("saving alarm handler\n");
|
|
Packit |
857059 |
old_alarm_handler = handler;
|
|
Packit |
857059 |
have_old_alarm_handler = 1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static void restore_alarm_handler()
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
if (have_old_alarm_handler) {
|
|
Packit |
857059 |
printf("restoring alarm handler\n");
|
|
Packit |
857059 |
signal(SIGALRM, old_alarm_handler);
|
|
Packit |
857059 |
have_old_alarm_handler = 0;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* This is a quick and dirty way to get alarms into a "trapable" signal
|
|
Packit |
857059 |
* for expect code. Expect uses SIGALRM, so it won't allow trap for it
|
|
Packit |
857059 |
* however, if we are careful not to use the qlgc_alarm code within
|
|
Packit |
857059 |
* expect {} statements, we should be safe to borrow the alarms as long as
|
|
Packit |
857059 |
* we restore the handler when we are done.
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static void alarm_handler(int x)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int ret;
|
|
Packit |
857059 |
printf("got alarm\n");
|
|
Packit |
857059 |
restore_alarm_handler();
|
|
Packit |
857059 |
printf("send SIGUSR1 to %d\n", getpid());
|
|
Packit |
857059 |
if (0 != (ret = kill (0 /*getpid()*/, SIGUSR1)))
|
|
Packit |
857059 |
printf("kill SIGUSR1 failed %s\n", strerror(errno));
|
|
Packit |
857059 |
//if (0 != (ret = kill (getpid(), SIGHUP)))
|
|
Packit |
857059 |
// printf("kill SIGHUP %s\n", strerror(errno));
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* This is a quick and dirty implementation of alarm capability for TCL
|
|
Packit |
857059 |
* Usage: alarm seconds
|
|
Packit |
857059 |
* Parameters:
|
|
Packit |
857059 |
* seconds - number of seconds til next SIGALRM, 0 to disable
|
|
Packit |
857059 |
* Returns:
|
|
Packit |
857059 |
* number of seconds remaining until any previously scheduled alarm was due to
|
|
Packit |
857059 |
* be delivered.
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static int
|
|
Packit |
857059 |
Qlgc_alarm_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int seconds;
|
|
Packit |
857059 |
int secondsleft;
|
|
Packit |
857059 |
char result[20];
|
|
Packit |
857059 |
signal_handler_t ret;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/*
|
|
Packit |
857059 |
* Check params.
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
if (objc != 2) {
|
|
Packit |
857059 |
Tcl_WrongNumArgs(interp, 1, objv, "seconds");
|
|
Packit |
857059 |
return TCL_ERROR;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (Tcl_GetIntFromObj(interp, objv[1], &seconds) != TCL_OK) {
|
|
Packit |
857059 |
return TCL_ERROR;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
printf("qlgc_alarm %d\n", seconds);
|
|
Packit |
857059 |
if (seconds) {
|
|
Packit |
857059 |
ret = signal(SIGALRM, alarm_handler);
|
|
Packit |
857059 |
if (ret == SIG_ERR)
|
|
Packit |
857059 |
goto failerrno;
|
|
Packit |
857059 |
save_alarm_handler(ret);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
secondsleft = (int)alarm((unsigned int)seconds);
|
|
Packit |
857059 |
if (! seconds)
|
|
Packit |
857059 |
restore_alarm_handler();
|
|
Packit |
857059 |
|
|
Packit |
857059 |
sprintf(result, "%d", secondsleft);
|
|
Packit |
857059 |
Tcl_SetObjResult(interp, Tcl_NewStringObj(result, -1));
|
|
Packit |
857059 |
return TCL_OK;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
failerrno:
|
|
Packit |
857059 |
sprintf(result, "qlgc_alarm failed: %s", strerror(errno));
|
|
Packit |
857059 |
Tcl_SetObjResult(interp, Tcl_NewStringObj(result, -1));
|
|
Packit |
857059 |
return TCL_ERROR;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/*
|
|
Packit |
857059 |
* qlgc_fork_Init -- Called when Tcl loads the extension.
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
int DLLEXPORT
|
|
Packit |
857059 |
Qlgc_fork_Init(Tcl_Interp *interp)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
|
|
Packit |
857059 |
return TCL_ERROR;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
/* changed this to check for an error - GPS */
|
|
Packit |
857059 |
if (Tcl_PkgProvide(interp, "qlgc_fork", "1.0") == TCL_ERROR) {
|
|
Packit |
857059 |
return TCL_ERROR;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
Tcl_CreateObjCommand(interp, "qlgc_fork", Qlgc_fork_Cmd, NULL, NULL);
|
|
Packit |
857059 |
Tcl_CreateObjCommand(interp, "qlgc_wait", Qlgc_wait_Cmd, NULL, NULL);
|
|
Packit |
857059 |
//Tcl_CreateObjCommand(interp, "qlgc_exit", Qlgc_exit_Cmd, NULL, NULL);
|
|
Packit |
857059 |
Tcl_CreateObjCommand(interp, "qlgc_dup", Qlgc_dup_Cmd, NULL, NULL);
|
|
Packit |
857059 |
//Tcl_CreateObjCommand(interp, "qlgc_alarm", Qlgc_alarm_Cmd, NULL, NULL);
|
|
Packit |
857059 |
return TCL_OK;
|
|
Packit |
857059 |
}
|