/**************************************************************** * * * Copyright 2001, 2013 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 #include #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; boolean_t rm_destroy = TRUE; boolean_t rm_rundown = FALSE; assert (iod->type == rm); if (iod->state != dev_open) { remove_rms(iod); 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_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); STAT_FILE(path, &statbuf, stat_res); if (-1 == stat_res) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); if (CYGWIN_ONLY(rm_ptr->fifo ||) fstatbuf.st_ino == statbuf.st_ino) if (UNLINK(path) == -1) rts_error_csa(CSA_ARG(NULL) 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_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); STAT_FILE(path, &statbuf, stat_res); if (-1 == stat_res) rts_error_csa(CSA_ARG(NULL) 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_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); if (UNLINK(path) == -1) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); } break; case iop_destroy: rm_destroy = TRUE; break; case iop_nodestroy: rm_destroy = FALSE; break; case iop_rundown: rm_rundown = TRUE; 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_csa(CSA_ARG(NULL) 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_csa(CSA_ARG(NULL) 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); } } if ((rm_destroy || rm_ptr->pipe) && !rm_rundown) remove_rms (iod); return; }