fis-gtm/sr_unix/iorm_close.c

224 lines
6.5 KiB
C

/****************************************************************
* *
* Copyright 2001, 2011 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#include "mdef.h"
#include <errno.h>
#include <sys/wait.h>
#include "gtm_unistd.h"
#include "gtm_stat.h"
#include "gtm_stdio.h"
#include "io.h"
#include "iormdef.h"
#include "io_params.h"
#include "eintr_wrappers.h"
#include "gtmio.h"
#include "iosp.h"
#include "string.h"
#include "stringpool.h"
GBLREF io_pair io_curr_device;
GBLREF io_pair io_std_device;
GBLREF boolean_t gtm_pipe_child;
error_def(ERR_CLOSEFAIL);
LITREF unsigned char io_params_size[];
void iorm_close(io_desc *iod, mval *pp)
{
d_rm_struct *rm_ptr;
d_rm_struct *in_rm_ptr;
d_rm_struct *stderr_rm_ptr;
unsigned char c;
char *path, *path2;
int fclose_res;
int stat_res;
int fstat_res;
struct stat statbuf, fstatbuf;
int p_offset;
pid_t done_pid;
int wait_status, rc;
unsigned int *dollarx_ptr;
unsigned int *dollary_ptr;
char *savepath2 = 0;
int path2len;
assert (iod->type == rm);
if (iod->state != dev_open)
return;
rm_ptr = (d_rm_struct *)iod->dev_sp;
#ifdef __MVS__
/* on zos if it is a fifo device then point to the pair.out for $X and $Y */
if (rm_ptr->fifo)
{
dollarx_ptr = &(iod->pair.out->dollar.x);
dollary_ptr = &(iod->pair.out->dollar.y);
} else
#endif
{
dollarx_ptr = &(iod->dollar.x);
dollary_ptr = &(iod->dollar.y);
}
iorm_use(iod,pp);
if (*dollarx_ptr && rm_ptr->lastop == RM_WRITE && !iod->dollar.za)
iorm_flush(iod);
p_offset = 0;
while (*(pp->str.addr + p_offset) != iop_eol)
{
switch (c = *(pp->str.addr + p_offset++))
{
case iop_delete:
path = iod->trans_name->dollar_io;
FSTAT_FILE(rm_ptr->fildes, &fstatbuf, fstat_res);
if (-1 == fstat_res)
rts_error(VARLSTCNT(1) errno);
STAT_FILE(path, &statbuf, stat_res);
if (-1 == stat_res)
rts_error(VARLSTCNT(1) errno);
if (CYGWIN_ONLY(rm_ptr->fifo ||) fstatbuf.st_ino == statbuf.st_ino)
if (UNLINK(path) == -1)
rts_error(VARLSTCNT(1) errno);
break;
case iop_rename:
path = iod->trans_name->dollar_io;
path2 = (char*)(pp->str.addr + p_offset + 1);
FSTAT_FILE(rm_ptr->fildes, &fstatbuf, fstat_res);
if (-1 == fstat_res)
rts_error(VARLSTCNT(1) errno);
STAT_FILE(path, &statbuf, stat_res);
if (-1 == stat_res)
rts_error(VARLSTCNT(1) errno);
if (CYGWIN_ONLY(rm_ptr->fifo ||) fstatbuf.st_ino == statbuf.st_ino)
{
/* make a copy of path2 so we can null terminate it */
path2len = (int)*((unsigned char *)(pp->str.addr + p_offset));
assert(stringpool.free >= stringpool.base);
ENSURE_STP_FREE_SPACE(path2len + 1);
savepath2 = (char *)stringpool.free;
memcpy(savepath2, path2, path2len);
savepath2[path2len] = '\0';
stringpool.free += path2len + 1;
assert(stringpool.free >= stringpool.base);
assert(stringpool.free <= stringpool.top);
if (LINK(path, savepath2) == -1)
rts_error(VARLSTCNT(1) errno);
if (UNLINK(path) == -1)
rts_error(VARLSTCNT(1) errno);
}
break;
default:
break;
}
p_offset += ( io_params_size[c]==IOP_VAR_SIZE ?
(unsigned char)(*(pp->str.addr + p_offset) + 1) : io_params_size[c] );
}
if (iod->pair.in != iod)
assert(iod->pair.out == iod);
if (iod->pair.out != iod)
assert(iod->pair.in == iod);
iod->state = dev_closed;
iod->dollar.zeof = FALSE;
*dollarx_ptr = 0;
*dollary_ptr = 0;
rm_ptr->lastop = RM_NOOP;
if (rm_ptr->inbuf)
{
free(rm_ptr->inbuf);
rm_ptr->inbuf = NULL;
}
if (rm_ptr->outbuf)
{
free(rm_ptr->outbuf);
rm_ptr->outbuf = NULL;
}
/* Do the close first. If the fclose() is done first and we are being called from io_rundown just prior to the execv
in a newly JOBbed off process, the fclose() does an implied fflush() which is known to do an lseek() which resets
the file pointers of any open (flat) files in the parent due to an archane interaction between child and parent
processes prior to an execv() call. The fclose (for stream files) will fail but it will clean up structures orphaned
by the CLOSEFILE_RESET.
*/
/* Close the fildes unless this is a direct close of the stderr device */
if (!rm_ptr->stderr_parent)
{
int save_fd;
/* Before closing a pipe device file descriptor, check if the fd was already closed as part of a "write /eof".
* If so, do not attempt the close now. Only need to free up the device structures.
*/
if (FD_INVALID != rm_ptr->fildes)
{
save_fd = rm_ptr->fildes;
CLOSEFILE_RESET(rm_ptr->fildes, rc); /* resets "rm_ptr->fildes" to FD_INVALID */
if (0 != rc)
rts_error(VARLSTCNT(4) ERR_CLOSEFAIL, 1, save_fd, rc);
}
if (rm_ptr->filstr != NULL)
{
FCLOSE(rm_ptr->filstr, fclose_res);
rm_ptr->filstr = NULL;
}
/* if this is a pipe and read_fildes and read_filstr are set then close them also */
if (0 < rm_ptr->read_fildes)
{
save_fd = rm_ptr->read_fildes;
CLOSEFILE_RESET(rm_ptr->read_fildes, rc); /* resets "rm_ptr->read_fildes" to FD_INVALID */
if (0 != rc)
rts_error(VARLSTCNT(4) ERR_CLOSEFAIL, 1, save_fd, rc);
}
if (rm_ptr->read_filstr != NULL)
{
FCLOSE(rm_ptr->read_filstr, fclose_res);
rm_ptr->read_filstr = NULL;
}
}
/* reap the forked shell process if a pipe - it will be a zombie, otherwise*/
if (rm_ptr->pipe_pid > 0)
{
/* Don't reap if in a child process creating a new pipe or if in parent and independent is set */
if (FALSE == gtm_pipe_child)
{
if (!rm_ptr->independent)
{
WAITPID(rm_ptr->pipe_pid, &wait_status, 0, done_pid);
assert(done_pid == rm_ptr->pipe_pid);
}
}
if (rm_ptr->stderr_child)
{
/* If the stderr device is the current device then set it to the principal device. This
is handled in op_close for a direct close of the stderr device. */
if (io_curr_device.in == rm_ptr->stderr_child)
{
io_curr_device.in = io_std_device.in;
io_curr_device.out = io_std_device.out;
}
/* have to make it look open in case it was closed directly */
/* reset the stderr_parent field so the fildes will be closed */
rm_ptr->stderr_child->state = dev_open;
stderr_rm_ptr = (d_rm_struct *)rm_ptr->stderr_child->dev_sp;
stderr_rm_ptr->stderr_parent = 0;
iorm_close(rm_ptr->stderr_child,pp);
remove_rms(rm_ptr->stderr_child);
}
}
return;
}