home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: SysTools
/
SysTools.zip
/
pmcron03.zip
/
process.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-05-09
|
19KB
|
371 lines
/* Copyright (c) 1995 Florian Große-Coosmann, RCS section at the eof */
/* This module includes functions starting a job and copying its output */
/* to our output file. */
#define INCL_NOPM
#define INCL_NOCOMMON
#define INCL_DOSSEMAPHORES
#define INCL_DOSFILEMGR
#define INCL_DOSPROCESS
#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <process.h>
#include <fcntl.h>
#include <share.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include "server.h"
typedef struct _PROC { /* one process slot */
struct _PROC *next;
int pid; /* process ID, the following values */
/* are reserved: */
/* 0 = never started */
/* -1 = can't start, PROC may been */
/* deleted. */
int rc; /* return code */
int reason; /* reason of the termination (signal */
/* number) the following value is */
/* reserverd: -1 = never started */
char *tmpfilename; /* file name of stdout and stderr of */
} PROC; /* the newly started process */
static PROC first = {NULL,0,0,0,NULL};
/*****************************************************************************/
/* function name : EndProcess */
/* */
/* arguments : process id of a terminated job, reason of the */
/* termination (0 or trap number), return code */
/* */
/* description : this is a function for the main thread, which wants to */
/* indicate the termination of a job. The cleanup is done */
/* by the cron thread later. */
/* */
/* note : this has to be called while running in a signal */
/* procedure, because we are NOT blocking the access to */
/* the job list! */
/*****************************************************************************/
void EndProcess(int pid,int reason,int rc)
{
PROC *run = first.next;
while (run != NULL) {
if (pid == run->pid) { /* process found */
run->rc = rc;
run->reason = reason;
return;
}
run = run->next;
}
}
/*****************************************************************************/
/* function name : NewSlot */
/* */
/* return value : a newly allocated and initialized process slot, NULL */
/* in case of insufficent memory */
/* */
/* description : creates a new process slot and initialized it to the */
/* default value. It is appended to the job list. */
/* */
/* note : the blocking of the job list must be done by the */
/* calling routine. */
/*****************************************************************************/
static PROC *NewSlot(void)
{
PROC *run,*last;
last = &first;
run = first.next;
while (run != NULL) { /* search for the insertion place */
last = run;
run = run->next;
}
if ((run = malloc(sizeof(PROC))) == NULL)
return(NULL);
memset(run,0,sizeof(PROC));
run->reason = -1; /* never started */
last->next = run; /* insert into the list */
return(run);
}
/*****************************************************************************/
/* function name : NewTmpFile */
/* */
/* arguments : buffer for a handle */
/* */
/* return value : allocated file name of a temporary file, NULL in case */
/* of insufficent memory or other errors. */
/* */
/* description : creates a new temporary file and returns the filename. */
/* The handle of the file is returned in the argument */
/* buffer. */
/*****************************************************************************/
static char *NewTmpFile(int *handle)
{
char *buf,*ptr;
unsigned i;
if ((buf = malloc(strlen(DefIOPath) + 2 + 11)) == NULL) /* delim+term. 0+*/
return(NULL); /* length of filename component */
strcpy(buf,DefIOPath); /* create the filename base */
if (DefIOPath[0] != '\0')
if (strchr(Delims,DefIOPath[strlen(DefIOPath) - 1]) == NULL)
strcat(buf,"\\");
ptr = buf + strlen(buf); /* where to append Cron????.tmp */
for (i = 0;i <= 0xFFFF;i++) {
sprintf(ptr,"Cron%04X.tmp",i);
if ((*handle = sopen(buf,
O_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_SYNC,
SH_DENYWR,
S_IREAD | S_IWRITE)) != -1)
return(buf);
}
/* can't allocate a tempfile, cleanup*/
free(buf);
return(NULL);
}
/*****************************************************************************/
/* function name : WaitDelete */
/* */
/* arguments : filename to delete */
/* */
/* description : delete the given file. If an error occurs we assume a */
/* race condition and wait approximately 2 time slices, */
/* then we try again once more. If the error persists we */
/* write an error message to the output. */
/*****************************************************************************/
static void WaitDelete(char *s)
{
ULONG os2rc;
if (DosDelete(s) == 0)
return;
DosSleep(64); /* 2 * TimeSlice */
if ((os2rc = DosDelete(s)) != 0)
Message(Get(IDS_TempfileNotDeleted),
s,os2rc);
}
/*****************************************************************************/
/* function name : CopyTemp */
/* */
/* arguments : filename of the output file of a job, process id, */
/* return code und reason of the termination of the job */
/* */
/* description : writes a message that the job has been stoped and */
/* copies the contents of the job output file to our */
/* output file. */
/*****************************************************************************/
static void CopyTemp(char *fn,int pid,int rc,int reason)
{
int chunk,done,done2;
int handle;
long len;
int neednl = 1; /* newline needed at eof? */
static char notbuf[128]; /* minimal emergency buffer */
static const char *Msg;
char *buf;
if (out == NULL) { /* ignore output? */
WaitDelete(fn);
return;
}
if (reason == 0)
Msg = Get(IDS_JobEndsNormal);
else {
Msg = Get(IDS_JobEndsDueSignal);
rc = reason;
}
if ((handle = sopen(fn,O_RDONLY | O_BINARY | O_NOINHERIT,SH_DENYNO)) == -1){
Message(Msg,pid,rc,Get(IDS_TempfileInaccessable));
return;
}
len = filelength(handle);
if (len == 0) { /* file empty? */
Message(Msg,pid,rc,Get(IDS_TempfileEmpty));
close(handle);
WaitDelete(fn);
return;
}
if ((buf = malloc(0x4000)) == NULL) { /* get a temorary buffer */
buf = notbuf; /* no memory, use the emergency buf */
chunk = 128;
} else
chunk = 0x4000;
BlockOutput(); /* don't allow any access to the */
/* output file, we work on it */
if (filelength(fileno(out)) >= Threshold) /* need a fresh output file? */
NextOutputFile(0);
fputs(GetTimeString(),out); /* normal Message processing */
fprintf(out,Msg,pid,rc,Get(IDS_TempfileFollows));
fflush(out); /* flush any buffers */
lseek(fileno(out),0l,SEEK_END); /* seek to end of file and change */
setmode(fileno(out),O_BINARY); /* the writing mode to binary since */
/* the job output file is in binary */
/* mode too. Don't use the slow */
/* text mode. */
while (len > 0) { /* copy until eof */
if ((done = read(handle,buf,chunk)) <= 0)
break;
if ((done2 = write(fileno(out),buf,done)) <= 0)
break;
if ((done2 != done) || (done == 0))
break;
len -= done;
if (len <= 0) /* that's all? Check if last char */
if (buf[done - 1] == '\n') /* was a newline. In this case we */
neednl = 0; /* don't have to do it ourself. */
}
if (neednl) /* append newline? */
write(fileno(out),"\r\n",2);
setmode(fileno(out),O_TEXT); /* back to standard text mode */
fseek(out,0l,SEEK_END); /* seek to eof, update internal FILE */
/* buffers */
UnBlockOutput(); /* end of copy */
if (buf != notbuf) /* is there an allocated buffer? */
free(buf); /* free it! */
close(handle); /* cleanup */
WaitDelete(fn);
}
/*****************************************************************************/
/* function name : StartProcess */
/* */
/* arguments : list entry of a cron job */
/* */
/* description : starts the job and appends job infos to the running */
/* process list (process slot). All errors were process */
/* locally. */
/* We use CMD (getenv(COMSPEC)) to start any job. Every */
/* job gets a freshly created temporary output file. */
/* */
/* note : the blocking of the job list must be done by the */
/* calling routine. */
/*****************************************************************************/
void StartProcess(LIST_ENTRY *job)
{
PROC *proc;
int tmpfilehandle;
static char *cmd = NULL;
if (cmd == NULL) /* never determined? */
if ((cmd = getenv("COMSPEC")) == NULL)
FatalError(Get(IDS_NoComSpec),(HWND) 0);
if ((proc = NewSlot()) == NULL) { /* can't create a job slot? */
Message(Get(IDS_NotEnoughMemory));
return;
}
if ((proc->tmpfilename = NewTmpFile(&tmpfilehandle)) == NULL) {
Message(Get(IDS_NoMemOrNoTempfile));
proc->pid = -1; /* don't delete the job slot */
proc->reason = 0; /* immediately, we may run into race */
return; /* conditions due some signals to */
/* the main thread. The deletion is */
} /* done by ReapChildren */
if (tmpfilehandle != 1) /* reassign stdout and stderr of the */
dup2(tmpfilehandle,1); /* newly created job to the */
if (tmpfilehandle != 2) /* temprary file */
dup2(tmpfilehandle,2);
if ((tmpfilehandle != 1) && (tmpfilehandle != 2)) /* close the tempfile */
close(tmpfilehandle); /* thus the only owner is the new */
/* job. */
/* Now, we start the job, we let it */
/* run in the background of the */
/* current process. This is either */
/* detach or unvisible. The user */
/* (Crontabs!) must support a "start"*/
/* command to show it in a visible */
/* session except in case of a PM */
/* program with crond started as a */
/* PM program, too. */
if ((proc->pid = spawnl(P_NOWAIT, /* P_SESSION has some problems, yet */
cmd,
cmd,
"/C",
job->StartCmd,
NULL)) == -1) {
proc->reason = 0; /* proc->pid is -1, the mess is */
Message(Get(IDS_CantStartJob), /* cleaned up by the next call of */
job->StartCmd,strerror(errno)); /* ReapChildren */
} else /* job started normally */
Message(Get(IDS_JobStarted),
job->StartCmd,proc->pid);
dup2(0,1); /* stdout and stderr back to the */
dup2(0,2); /* "nul" device */
}
/*****************************************************************************/
/* function name : ReapChildren */
/* */
/* return value : number of still outstanding jobs */
/* */
/* description : looks for terminated jobs in the job list, copies */
/* their output to our output files und frees all */
/* allocated resources belonging to the children. */
/*****************************************************************************/
int ReapChildren(void)
{
PROC *run,*last,*del;
int pid,retval = 0;
BlockProcess(); /* block the job list */
last = &first;
run = last->next;
while (run != NULL) { /* check every job slot */
if ((run->pid != 0) && (run->reason != -1)) { /* job has started? */
if ((pid = run->pid) != -1) { /* job stated normally? */
run->pid = -1; /* job has ended, copy its output */
CopyTemp(run->tmpfilename,pid,run->rc,run->reason);
}
/* else: error while spawning the process */
del = run;
last->next = run->next; /* cut off the list */
run = run->next; /* set run to the next candidat */
if (del->tmpfilename != NULL) /* tempfile available? */
free(del->tmpfilename);
free(del); /* free the job slot */
continue;
}
/* job is running: */
last = run;
run = run->next;
retval++;
}
UnBlockProcess(); /* allow the access of the job list */
/* by other threads */
return(retval);
}
/*****************************************************************************/
/* function name : ShowStillRunnings */
/* */
/* description : displays all running jobs with their output file. This */
/* function is called once at the end of the cron thread. */
/*****************************************************************************/
void ShowStillRunnings(void)
{
PROC *run = first.next;
while (run != NULL) { /* no need to block the list */
if ((run->pid != 0) && (run->pid != -1))
Message(Get(IDS_JobYetActive),
run->pid,
run->tmpfilename);
run = run->next;
}
}
/* RCS depending informations
*
* $Name: Version121 $
*
* $Log: process.c $
* Revision 1.1 1995/02/03 10:42:46 Florian
* Initial revision
*
*
*/
static char rcsid[] = "@(#)$Id: process.c 1.1 1995/02/03 10:42:46 Florian Rel $";