void cmj_incoming_call(struct NTD *tsk)
{
	int rval, rc;
	struct CLB *lnk;
	struct sockaddr_in in;
	GTM_SOCKLEN_TYPE sz = sizeof(in);
	cmi_status_t status;

	while ((-1 == (rval = accept(tsk->listen_fd, (struct sockaddr *)&in, &sz))) && EINTR == errno)
		;
	while (rval >= 0)
	{
		status = cmj_setupfd(rval);
		if (CMI_ERROR(status))
		{
			CLOSEFILE(rval, rc);
			return;
		}
		status = cmj_set_async(rval);
		if (CMI_ERROR(status))
		{
			CLOSEFILE(rval, rc);
			return;
		}

		/* grab a clb off of the free list */
		lnk = cmi_alloc_clb();
		if (!lnk || !tsk->acc || !tsk->acc(lnk) || !tsk->crq)
		{
			/* no point if the callbacks are not in place */
			cmi_free_clb(lnk);
			CLOSEFILE(rval, rc);
			return;
		}
		if (rval > tsk->max_fd)
			tsk->max_fd = rval;
		lnk->mun = rval;
		lnk->sta = CM_CLB_IDLE;
		lnk->peer = in;
		insqh(&lnk->cqe, &tsk->cqh);
		lnk->ntd = tsk;
		FD_SET(rval, &tsk->es);
		/* setup for callback processing */
		lnk->deferred_event = TRUE;
		lnk->deferred_reason = CMI_REASON_CONNECT;
		while ((-1 == (rval = accept(tsk->listen_fd, (struct sockaddr *)&in, &sz))) && EINTR == errno)
			;
	}
}
Beispiel #2
0
static int file_collect (lua_State *L) {
  IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
  FILE *f = getnonullfile(L, ctrl, 1);
  if (f != stdin && f != stdout && f != stderr)
    CLOSEFILE(L, f);
  return 0;
}
Beispiel #3
0
static int closefile (lua_State *L, IOCtrl *ctrl, FILE *f) {
  if (f == stdin || f == stdout || f == stderr)
    return 1;
  else {
    lua_pushusertag(L, f, ctrl->iotag);
    lua_settag(L, ctrl->closedtag);
    return (CLOSEFILE(L, f) == 0);
  }
}
Beispiel #4
0
short ionl_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout)
{
	unsigned char	ch;
	io_desc		*d_in, *d_out, *ioptr;
	int		p_offset, status;

	p_offset = 0;
	/* If UNIX, then /dev/null was actually opened by io_open_try so we have to close it
	   since we don't use the device, we just simulate it by doing nothing on writes except
	   maintaining the appropriate pointers. We test for fd >= 0 since the less than zero
	   values mean no device was opened.
	*/
	UNIX_ONLY(
		if (0 <= fd)
	        {
		        CLOSEFILE(fd, status);
		}
	);
Beispiel #5
0
boolean_t mur_fopen_sp(jnl_ctl_list *jctl)
{
	struct stat		stat_buf;
	int			status, perms;

	error_def(ERR_JNLFILEOPNERR);
	error_def(ERR_SYSCALL);

	perms = O_RDONLY;
	jctl->read_only = TRUE;
	/* Both for recover and rollback open in read/write mode. We do not need to write in journal file
	 * for mupip journal extract/show/verify or recover -forward.  So open it as read-only
	 */
	if (mur_options.update && !mur_options.forward)
	{
		perms = O_RDWR;
		jctl->read_only = FALSE;
	}
	jctl->channel = OPEN((char *)jctl->jnl_fn, perms);
	if (-1 != jctl->channel)
	{
		FSTAT_FILE(jctl->channel, &stat_buf, status);
		if (-1 != status)
		{
			jctl->os_filesize = (off_jnl_t)stat_buf.st_size;
			return TRUE;
		}
		jctl->status = errno;
		CLOSEFILE(jctl->channel, status);
	} else
		jctl->status = errno;
	if (ENOENT == jctl->status)	/* File Not Found is a common error, so no need for SYSCALL */
		gtm_putmsg(VARLSTCNT(5) ERR_JNLFILEOPNERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, jctl->status);
	else
		gtm_putmsg(VARLSTCNT(12) ERR_JNLFILEOPNERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, ERR_SYSCALL, 5,
			LEN_AND_STR((-1 == jctl->channel) ? "open" : "fstat"), CALLFROM, jctl->status);
	jctl->channel = NOJNL;
	return FALSE;
}
/* Initialize communication stuff */
int gtmrecv_comm_init(in_port_t port)
{
	struct addrinfo		*ai_ptr = NULL, hints;
	const	int		enable_reuseaddr = 1;
	struct  linger  	disable_linger = {0, 0};
	int			rc;
	int			errcode;
	char			port_buffer[NI_MAXSERV];
	int			port_buffer_len;
	int			temp_sock_fd;
	int			af;

	if (FD_INVALID != gtmrecv_listen_sock_fd) /* Initialization done already */
		return (0);

	/* Create the socket used for communicating with primary */
	af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET);
	if (FD_INVALID == (temp_sock_fd = socket(af, SOCK_STREAM, IPPROTO_TCP)))
	{
		af = AF_INET;
		if (FD_INVALID == (temp_sock_fd = socket(af, SOCK_STREAM, IPPROTO_TCP)))
		{
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
					RTS_ERROR_LITERAL("Error with receiver server socket create"), ERRNO);
			return (-1);
		}
	}

	/* Make it known to the world that you are ready for a Source Server */
	SERVER_HINTS(hints, af);
	SPRINTF(port_buffer, "%hu", port);
	if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &ai_ptr)))
	{
		CLOSEFILE(temp_sock_fd, rc);
		RTS_ERROR_ADDRINFO_CTX(NULL, ERR_GETADDRINFO, errcode, "FAILED in obtaining IP address on receiver server.");
		return -1;
	}


	gtmrecv_listen_sock_fd = temp_sock_fd;
	if (0 > setsockopt(gtmrecv_listen_sock_fd, SOL_SOCKET, SO_LINGER, (const void *)&disable_linger, SIZEOF(disable_linger)))
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
				RTS_ERROR_LITERAL("Error with receiver server listen socket disable linger"), ERRNO);
	if (0 > setsockopt(gtmrecv_listen_sock_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&enable_reuseaddr,
			SIZEOF(enable_reuseaddr)))
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
				RTS_ERROR_LITERAL("Error with receiver server listen socket enable reuseaddr"), ERRNO);
	}
	if (0 > BIND(gtmrecv_listen_sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen))
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
				 RTS_ERROR_LITERAL("Could not bind local address"), ERRNO);
		CLOSEFILE_RESET(gtmrecv_listen_sock_fd, rc);	/* resets "gtmrecv_listen_sock_fd" to FD_INVALID */
		return (-1);
	}

	if (0 > listen(gtmrecv_listen_sock_fd, 5))
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
				 RTS_ERROR_LITERAL("Could not listen"), ERRNO);
		CLOSEFILE_RESET(gtmrecv_listen_sock_fd, rc);	/* resets "gtmrecv_listen_sock_fd" to FD_INVALID */
		return (-1);
	}

	return (0);
}
Beispiel #7
0
XRAW_STRUCT *preloadXraw(char *fname) { // just get the metadata

  // open input file
#if defined(USEGZ)
  gzFile fin = gzopen(fname, "rb");
#else
  FILE *fin = fopen(fname, "rb");
#endif
  if (!fin) {
    fprintf(stderr, "Failed to open file '%s'.\n", fname);
    return NULL;
  }

  // allocate container
  XRAW_STRUCT *xrs = (XRAW_STRUCT *)malloc(1 * sizeof(XRAW_STRUCT));
  if (!xrs) {
    fprintf(stderr, "Failed to create container for file '%s'.\n", fname);
    CLOSEFILE(fin);
    return NULL;
  }

  strcpy(xrs->filename, fname);

  // get nx, ny, nz
#if defined(USEGZ)
  if ((gzread(fin, &(xrs->nx), sizeof(xrs->nx)) != sizeof(xrs->nx)) ||
      (gzread(fin, &(xrs->ny), sizeof(xrs->ny)) != sizeof(xrs->ny)) ||
      (gzread(fin, &(xrs->nz), sizeof(xrs->nz)) != sizeof(xrs->nz))) {
#else
  if (!fread(&(xrs->nx), sizeof(xrs->nx), 1, fin) ||
      !fread(&(xrs->ny), sizeof(xrs->ny), 1, fin) || 
      !fread(&(xrs->nz), sizeof(xrs->nz), 1, fin)) {
#endif
    fprintf(stderr, "Failed to read volume dimensions.\n");
    free(xrs);
    CLOSEFILE(fin);
    return NULL;
  }

  //fprintf(stderr, "vol dimensions are %d %d %d\n", xrs->nx, xrs->ny, xrs->nz);
  //fprintf(stderr, "ftell is %ld\n", ftell(fin));

  // get wdx, wdy, wdz
#if defined(USEGZ)
  if ((gzread(fin, &(xrs->wdx), sizeof(xrs->wdx)) != sizeof(xrs->wdx)) ||
      (gzread(fin, &(xrs->wdy), sizeof(xrs->wdy)) != sizeof(xrs->wdy)) ||
      (gzread(fin, &(xrs->wdz), sizeof(xrs->wdz)) != sizeof(xrs->wdz))) {
#else
  if (!fread(&xrs->wdx, sizeof(xrs->wdx), 1, fin) ||
      !fread(&xrs->wdy, sizeof(xrs->wdy), 1, fin) || 
      !fread(&xrs->wdz, sizeof(xrs->wdz), 1, fin)) {
#endif
    fprintf(stderr, "Failed to read voxel sizes.\n");
    free(xrs);
    CLOSEFILE(fin);
    return NULL;
  }

  //fprintf(stderr, "voxels sizes are %f %f %f\n", xrs->wdx, xrs->wdy, xrs->wdz);
  //fprintf(stderr, "ftell is %ld\n", ftell(fin));

  CLOSEFILE(fin);
  return xrs;
}

XRAW_STRUCT *loadXraw(char *fname) {

  XRAW_STRUCT *xrs = preloadXraw(fname);
  if (!xrs) {
    fprintf(stderr, "Failed to preload Xraw file\n");
    return NULL;
  }

  // open input file
#if defined(USEGZ)
  gzFile fin = gzopen(fname, "rb");
#else
  FILE *fin = fopen(fname, "rb");
#endif
  if (!fin) {
    fprintf(stderr, "Failed to open file '%s'.\n", fname);
    return NULL;
  }

#if (1) 
  int offset = 3 * sizeof(xrs->nx) + 3 * sizeof(xrs->wdx);
  gzseek(fin, offset, SEEK_SET);


#else
  // allocate container
  XRAW_STRUCT *xrs = (XRAW_STRUCT *)malloc(1 * sizeof(XRAW_STRUCT));
  if (!xrs) {
    fprintf(stderr, "Failed to create container for file '%s'.\n", fname);
    CLOSEFILE(fin);
    return NULL;
  }

  strcpy(xrs->filename, fname);

  // get nx, ny, nz
#if defined(USEGZ)
  if ((gzread(fin, &(xrs->nx), sizeof(xrs->nx)) != sizeof(xrs->nx)) ||
      (gzread(fin, &(xrs->ny), sizeof(xrs->ny)) != sizeof(xrs->ny)) ||
      (gzread(fin, &(xrs->nz), sizeof(xrs->nz)) != sizeof(xrs->nz))) {
#else
  if (!fread(&(xrs->nx), sizeof(xrs->nx), 1, fin) ||
      !fread(&(xrs->ny), sizeof(xrs->ny), 1, fin) || 
      !fread(&(xrs->nz), sizeof(xrs->nz), 1, fin)) {
#endif
    fprintf(stderr, "Failed to read volume dimensions.\n");
    free(xrs);
    CLOSEFILE(fin);
    return NULL;
  }

  //fprintf(stderr, "vol dimensions are %d %d %d\n", xrs->nx, xrs->ny, xrs->nz);
  //fprintf(stderr, "ftell is %ld\n", ftell(fin));

  // get wdx, wdy, wdz
#if defined(USEGZ)
  if ((gzread(fin, &(xrs->wdx), sizeof(xrs->wdx)) != sizeof(xrs->wdx)) ||
      (gzread(fin, &(xrs->wdy), sizeof(xrs->wdy)) != sizeof(xrs->wdy)) ||
      (gzread(fin, &(xrs->wdz), sizeof(xrs->wdz)) != sizeof(xrs->wdz))) {
#else
  if (!fread(&xrs->wdx, sizeof(xrs->wdx), 1, fin) ||
      !fread(&xrs->wdy, sizeof(xrs->wdy), 1, fin) || 
      !fread(&xrs->wdz, sizeof(xrs->wdz), 1, fin)) {
#endif
    fprintf(stderr, "Failed to read voxel sizes.\n");
    free(xrs);
    CLOSEFILE(fin);
    return NULL;
  }

  //fprintf(stderr, "voxels sizes are %f %f %f\n", xrs->wdx, xrs->wdy, xrs->wdz);
  //fprintf(stderr, "ftell is %ld\n", ftell(fin));

#endif

  // get data
  long nvals = (long)xrs->nx * xrs->ny * xrs->nz;
  fprintf(stderr, "attempting to allocate %ld bytes...\n", nvals);
  //xrs->data = (unsigned char *)malloc(nvals * sizeof(unsigned char));
  xrs->data = (unsigned char *)calloc(xrs->nx * sizeof(unsigned char), xrs->ny * xrs->nz);
  if (!xrs->data) {
    fprintf(stderr, "Failed to allocate storage for volume.\n");
    free(xrs);
    CLOSEFILE(fin);
    return NULL;
  }     
  
#if defined(USEGZ)
  //if (gzread(fin, xrs->data, sizeof(unsigned char)*nvals) != sizeof(unsigned char)*nvals) {
  int _fail = 0;
  int stripe = 0;
  int stripesize = xrs->ny * xrs->nz * sizeof(unsigned char);
  while ((stripe < xrs->nx) && !_fail) {
    _fail = gzread(fin, xrs->data + (long)stripe * stripesize, stripesize) != stripesize;
    stripe++;
  }
  if (_fail) {
#else
  if (fread(xrs->data, sizeof(unsigned char), nvals, fin) != nvals) {
#endif
    fprintf(stderr, "Failed to read entire volume: inconsistent file.\n");
    free(xrs->data);
    free(xrs);
    CLOSEFILE(fin);
    return NULL;
  }
  
  //fprintf(stderr, "ftell is %ld\n", ftell(fin));
  // get look-up table components
#if defined(USEGZ)
  if ((gzread(fin, xrs->red, sizeof(unsigned char)*256) != sizeof(unsigned char)*256) ||
      (gzread(fin, xrs->green, sizeof(unsigned char)*256) != sizeof(unsigned char)*256) ||
      (gzread(fin, xrs->blue, sizeof(unsigned char)*256) != sizeof(unsigned char)*256)) {
#else
  if ((fread(xrs->red, sizeof(unsigned char), 256, fin) != 256) ||
      (fread(xrs->green, sizeof(unsigned char), 256, fin) != 256) ||
      (fread(xrs->blue, sizeof(unsigned char), 256, fin) != 256)) {
#endif
    fprintf(stderr, "Failed reading embedded colour look-up table.\n");
    //if (feof(fin)) {
    //  fprintf(stderr, "at feof of fin\n");
    //}
    free(xrs->data);
    free(xrs);
    CLOSEFILE(fin);
    return NULL;
  }

  // try to read one more byte ... this should result in feof being true
#if defined(USEGZ)
  gzread(fin, NULL, sizeof(unsigned char));
  if (!gzeof(fin)) {
#else
  fread(NULL, sizeof(unsigned char), 1, fin);
  if (!feof(fin)) {
#endif
    fprintf(stderr, "Read data, but not at end of file.  Invalid state.\n");
    free(xrs->data);
    free(xrs);
    CLOSEFILE(fin);
    return NULL;
  }

  CLOSEFILE(fin);
  return xrs;
}
  
XRAW_STRUCT *createXraw(char *fname, int nx, int ny, int nz, int borderwidth) {

  XRAW_STRUCT *xrw = (XRAW_STRUCT *)malloc(sizeof(XRAW_STRUCT));
  
  strcpy(xrw->filename, fname);

  xrw->nx = nx;
  xrw->ny = ny;
  xrw->nz = nz;
  
  xrw->wdx = xrw->wdy = xrw->wdz = 1.0;
  
  xrw->data = (unsigned char *)calloc((long)nx * (long)ny, (long)nz * sizeof(unsigned char));
  long i, j, k;
  unsigned char val, border;
  for (i = 0; i < (long)nx; i++) {
    for (j = 0; j < (long)ny; j++) {
      for (k = 0; k < (long)nz; k++) {
	val = 0;
	border = 0;
	if ((i < borderwidth) || (i > nx-borderwidth)) {
	  border++;
	}
	if ((j < borderwidth) || (j > ny-borderwidth)) {
	  border++;
	}
	if ((k < borderwidth) || (k > nz-borderwidth)) {
	  border++;
	}
	if (border == 2) {
	  val = 255;
	}
	xrw->data[k * (long)nz * (long)ny + j * (long)nx + i]  = val;
      }
    }
  }

  for (i = 0; i < 256; i++) {
    xrw->red[i] = xrw->green[i] = xrw->blue[i] = (unsigned char)i;
  }

  return xrw;

 }


XRAW_STRUCT *trimXraw(XRAW_STRUCT *xr, int trim[3]) {

  if ((2 * trim[0] > xr->nx - 2) ||
      (2 * trim[1] > xr->ny - 2) ||
      (2 * trim[2] > xr->nz - 2)) {
    fprintf(stderr, "trimXraw: cannot trim to a negative volume size\n");
    return NULL;
  } 

  XRAW_STRUCT *xro = (XRAW_STRUCT *)malloc(1 * sizeof(XRAW_STRUCT));
  if (!xro) {
    fprintf(stderr, "Failed to create container for trimmed xrw file.\n");
    return NULL;
  }

  strcpy(xro->filename, xr->filename);

  xro->nx = xr->nx - 2 * trim[0];
  xro->ny = xr->ny - 2 * trim[1];
  xro->nz = xr->nz - 2 * trim[2];

  xro->wdx = xr->wdx;
  xro->wdy = xr->wdy;
  xro->wdz = xr->wdz;

  xro->data = (unsigned char *)calloc(xro->nx * sizeof(unsigned char), xro->ny * xro->nz);
  if (!xro->data) {
    fprintf(stderr, "Failed to allocate unsigned char volume.\n");
    free(xro);
    return NULL;
  }
  long i, j, k;
  for (i = 0; i < xro->nx; i++) {
    for (j = 0; j < xro->ny; j++) {
#pragma omp parallel for private(k)
      for (k = 0; k < xro->nz; k++) {
	xro->data[k * xro->nx * xro->ny + j * xro->nx + i] = 
	  xr->data[(k+trim[2]) * xr->nx * xr->ny + (j+trim[1]) * xr->nx + (i+trim[0])];
      }
    }
  }    	   

  for (i = 0; i < 256; i++) {
    xro->red[i] = xr->red[i];
    xro->green[i] = xr->green[i];
    xro->blue[i] = xr->blue[i];
  }
  
  return xro;
}

void showXraw(XRAW_STRUCT *xr) {
  fprintf(stdout, "XRW file: '%s'\n", xr->filename);
  fprintf(stdout, "volume dimensions: %6d %6d %6d\n", xr->nx, xr->ny, xr->nz);
  fprintf(stdout, "      voxel sizes: %6.3f %6.3f %6.3f\n", xr->wdx, xr->wdy, xr->wdz);
  fprintf(stdout, "total volume size: %6.1f %6.1f %6.1f\n", xr->wdx*xr->nx, xr->wdy*xr->ny,
	  xr->wdz*xr->nz);
}


int saveXraw(XRAW_STRUCT *xr) {
  if (!xr) {
    fprintf(stderr, "Invalid xraw structure passed to saveXraw.\n");
    return -1;
  }

#if defined(USEGZ)
  gzFile fout = gzopen(xr->filename, "wb9");
#else
  FILE *fout = fopen(xr->filename, "wb");
#endif
  if (!fout) {
    fprintf(stderr, "Unable to create xraw output file.\n");
    return -1;
  }
  
  // put nx, ny, nz
#if defined(USEGZ)
  if ((gzwrite(fout, &(xr->nx), sizeof(xr->nx)) != sizeof(xr->nx)) ||
      (gzwrite(fout, &(xr->ny), sizeof(xr->ny)) != sizeof(xr->ny)) ||
      (gzwrite(fout, &(xr->nz), sizeof(xr->nz)) != sizeof(xr->nz))) {
#else
  if (!fwrite(&(xr->nx), sizeof(xr->nx), 1, fout) ||
      !fwrite(&(xr->ny), sizeof(xr->ny), 1, fout) ||
      !fwrite(&(xr->nz), sizeof(xr->nz), 1, fout)) {
#endif
    fprintf(stderr, "Failed to write volume dimensions.\n");
    CLOSEFILE(fout);
    return -1;
  }

  // put wdx, wdy, wdz
#if defined(USEGZ)
  if ((gzwrite(fout, &(xr->wdx), sizeof(xr->wdx)) != sizeof(xr->wdx)) ||
      (gzwrite(fout, &(xr->wdy), sizeof(xr->wdy)) != sizeof(xr->wdy)) ||
      (gzwrite(fout, &(xr->wdz), sizeof(xr->wdz)) != sizeof(xr->wdz))) {
#else
  if (!fwrite(&(xr->wdx), sizeof(xr->wdx), 1, fout) ||
      !fwrite(&(xr->wdy), sizeof(xr->wdy), 1, fout) ||
      !fwrite(&(xr->wdz), sizeof(xr->wdz), 1, fout)) {
#endif
    fprintf(stderr, "Failed to write voxel sizes.\n");
    CLOSEFILE(fout);
    return -1;
  }
  
  // put data
  //long nvals = xr->nx * xr->ny * xr->nz;
#if defined(USEGZ)
  //if (gzwrite(fout, xr->data, sizeof(unsigned char)*nvals) != sizeof(unsigned char)*nvals) {
  int _fail = 0;
  int stripe = 0;
  int stripesize = xr->ny * xr->nz * sizeof(unsigned char);
  while ((stripe < xr->nx) && !_fail) {
    _fail = gzwrite(fout, xr->data + (long)stripe * stripesize,  stripesize) != stripesize;
    stripe++;
  }
  if (_fail) {
#else
  long nvals = xr->nx * xr->ny * xr->nz;
  if (!fwrite(xr->data, sizeof(unsigned char), nvals, fout)) {
#endif
    fprintf(stderr, "Failed to write entire volume.\n");
    CLOSEFILE(fout);
    return -1;
  }

  // put look-up table components
#if defined(USEGZ)
  if ((gzwrite(fout, xr->red, sizeof(unsigned char)*256) != sizeof(unsigned char)*256) ||
      (gzwrite(fout, xr->green, sizeof(unsigned char)*256) != sizeof(unsigned char)*256) ||
      (gzwrite(fout, xr->blue, sizeof(unsigned char)*256) != sizeof(unsigned char)*256)) {
#else
  if (!fwrite(xr->red, sizeof(unsigned char), 256, fout) ||
      !fwrite(xr->green, sizeof(unsigned char), 256, fout) ||
      !fwrite(xr->blue, sizeof(unsigned char), 256, fout)) {
#endif
    fprintf(stderr, "Failed writing colour look-up table.\n");
    CLOSEFILE(fout);
    return -1;
  }

  CLOSEFILE(fout);
  return 0;
}

VOL_STRUCT *makePow2Xvol(VOL_STRUCT *xrv) {
  // verify provided struct
  if (!xrv || !xrv->data) {
    fprintf(stderr, "Invalid data given to makePow2Xraw.\n");
    return NULL;
  }

  // allocate container
  VOL_STRUCT *vol = (VOL_STRUCT *)malloc(1 * sizeof(VOL_STRUCT));
  if (!vol) {
    fprintf(stderr, "Failed to create parsed volume container.\n");
    return NULL;
  }

  //int w, h;
  //w = xrv->nx;
  //h = xrv->ny;

  // set filename
  strcpy(vol->filename, xrv->filename);

  // choose power-of-2 side lengths
  vol->nx = 1;
  while (vol->nx <= xrv->nx/2) {
    vol->nx *= 2;
  }
  vol->ny = 1;
  while (vol->ny <= xrv->ny/2) {
    vol->ny *= 2;
  }
  vol->nz = 1;
  while (vol->nz <= xrv->nz/2) {
    vol->nz *= 2;
  }

  // update voxel sizes
  vol->wdx = xrv->wdx * (float)xrv->nx / (float)vol->nx;
  vol->wdy = xrv->wdy * (float)xrv->ny / (float)vol->ny;
  vol->wdz = xrv->wdz * (float)xrv->nz / (float)vol->nz;
  
  // copy data with bilinear interpolation
  vol->data = (float ***)malloc(vol->nx * sizeof(float **));
  if (!vol->data) {
    fprintf(stderr,"Failed to allocate float volume.\n");
    free(vol);
    return NULL;
  }

  float xc, yc, zc; // fractional pixel in input data
  float xw1, yw1, zw1; // weights
  int i1, i2, j1, j2, k1, k2;

  int i, j, k, /* ii, ij, ik, */ ax, ay, az;
  float sum, wgt;
  for (i = 0; i < vol->nx; i++) {
    xc = (float)i * (float)xrv->nx / (float)vol->nx;
    i1 = floorf(xc);
    i2 = ceilf(xc);
    xw1 = fabs(xc-(float)i2);
    i1 = i1 < 0 ? 0 : (i1 > xrv->nx-1) ? xrv->nx-1 : i1;
    i2 = i2 < 0 ? 0 : (i2 > xrv->nx-1) ? xrv->nx-1 : i2;
    // copy this frame in to this slice
    vol->data[i] = (float **)malloc(vol->ny * sizeof(float *));
    if (!vol->data[i]) {
      fprintf(stderr, "Failed to allocate row in float volume.\n");
      return NULL;
    }
    for (j = 0; j < vol->ny; j++) {
      yc = (float)j * (float)xrv->ny / (float)vol->ny;
      j1 = floorf(yc);
      j2 = ceilf(yc);
      yw1 = fabs(yc-(float)j2);
      j1 = j1 < 0 ? 0 : (j1 > xrv->ny-1) ? xrv->ny-1 : j1;
      j2 = j2 < 0 ? 0 : (j2 > xrv->ny-1) ? xrv->ny-1 : j2;
      vol->data[i][j] = (float *)malloc(vol->nz * sizeof(float *));
      if (!vol->data[i][j]) {
	fprintf(stderr, "Failed to allocate column in float volume.\n");
	return NULL;
      }
#pragma omp parallel for private(k,zc,k1,k2,zw1,sum,wgt,ax,ay,az)
      for (k = 0; k < vol->nz; k++) {
	zc = (float)k * (float)xrv->nz / (float)vol->nz;
	k1 = floorf(zc);
	k2 = ceilf(zc);
	zw1 = fabs(zc-(float)k2);
	k1 = k1 < 0 ? 0 : (k1 > xrv->nz-1) ? xrv->nz-1 : k1;
	k2 = k2 < 0 ? 0 : (k2 > xrv->nz-1) ? xrv->nz-1 : k2;

	// averaging
	sum = 0.0;
	wgt = 0.0;
	float uxw, uyw, uzw;
	for (ax = i1; ax <= i2; ax++) {
	  uxw = xw1;
	  if (ax == i2) {
	    uxw = 1. - xw1;
	  }
	  for (ay = j1; ay <= j2; ay++) {
	    uyw = yw1;
	    if (ay == j2) {
	      uyw = 1. - yw1;
	    }
	    for (az = k1; az <= k2; az++) {
	      uzw = zw1;
	      if (az == k2) {
		uzw = 1. - zw1;
	      }
	      sum += (uxw * uyw * uzw) * xrv->data[ax][ay][az];
	      wgt += (uxw * uyw * uzw);
	    }
	  }
	}
	vol->data[i][j][k] = sum / wgt;
      }
    }
  }

  // copy look-up table
  for (i = 0; i < 256; i++) {
    vol->red[i]   = xrv->red[i];
    vol->green[i] = xrv->green[i];
    vol->blue[i]  = xrv->blue[i];
  }

  return vol;
}



VOL_STRUCT *Xraw2Xvol(XRAW_STRUCT *xrs, int stride[3]) {
  // verify loaded data
  if (!xrs || !xrs->data) {
    fprintf(stderr, "Invalid data given to parseXraw.\n");
    return NULL;
  }

  // allocate container
  VOL_STRUCT *vol = (VOL_STRUCT *)malloc(1 * sizeof(VOL_STRUCT));
  if (!vol) {
    fprintf(stderr, "Failed to create parsed volume container.\n");
    return NULL;
  }

  int w, h;
  w = xrs->nx;
  h = xrs->ny;

  strcpy(vol->filename, xrs->filename);

  // copy scalars
  vol->nx = xrs->nx / stride[0];
  vol->ny = xrs->ny / stride[1];
  vol->nz = xrs->nz / stride[2];
  vol->wdx = xrs->wdx * stride[0];
  vol->wdy = xrs->wdy * stride[1];
  vol->wdz = xrs->wdz * stride[2];

  // copy data with stride
  vol->data = (float ***)malloc(vol->nx * sizeof(float **));
  if (!vol->data) {
    fprintf(stderr,"Failed to allocate float volume.\n");
    free(vol);
    return NULL;
  }
  int i, j, k, ii, ij, ik, ax, ay, az;
  float sum;
  for (i = 0; i < vol->nx; i++) {
    ii = i * stride[0];
    // copy this frame in to this slice
    vol->data[i] = (float **)malloc(vol->ny * sizeof(float *));
    if (!vol->data[i]) {
      fprintf(stderr, "Failed to allocate row in float volume.\n");
      return NULL;
    }
    for (j = 0; j < vol->ny; j++) {
      ij = j * stride[1];
      // fill y planes in reverse direction - see below for reason
      vol->data[i][vol->ny-1-j] = (float *)malloc(vol->nz * sizeof(float *));
      if (!vol->data[i][vol->ny-1-j]) {
	fprintf(stderr, "Failed to allocate column in float volume.\n");
	return NULL;
      }
#pragma omp parallel for private(k,ik,sum,ax,ay,az)
      for (k = 0; k < vol->nz; k++) {
	ik = k * stride[2];
	// averaging
	sum = 0.0;
	for (ax = 0; ax < stride[0]; ax++) {
	  for (ay = 0; ay < stride[1]; ay++) {
	    for (az = 0; az < stride[2]; az++) {
	      sum += (float)(xrs->data[(long)(ik+az)*w*h + (ij+ay)*w + (ii+ax)]) / 255.0;
	    }
	  }
	}
	// fill y and z planes in reverse directions so that home view in 
	// s2plot (and pdf) matches orientation xrw was exported from in 
	// OsiriX
	vol->data[i][vol->ny-1-j][vol->nz-1-k] = sum / (float)(stride[0] * stride[1] * stride[2]);

      }
    }
  }

  // copy look-up table
  for (i = 0; i < 256; i++) {
    vol->red[i]   = (float)(xrs->red[i])   / 255.0;
    vol->green[i] = (float)(xrs->green[i]) / 255.0;
    vol->blue[i]  = (float)(xrs->blue[i])  / 255.0;
  }

  return vol;
}

void showXvol(VOL_STRUCT *xv) {
  fprintf(stdout, "Parsed data (from '%s'):\n", xv->filename);
  fprintf(stdout, "volume dimensions: %6d %6d %6d\n", xv->nx, xv->ny, xv->nz);
  fprintf(stdout, "      voxel sizes: %6.3f %6.3f %6.3f\n", xv->wdx, xv->wdy, xv->wdz);
  fprintf(stdout, "total volume size: %6.1f %6.1f %6.1f\n", xv->wdx*xv->nx, xv->wdy*xv->ny,
	  xv->wdz*xv->nz);
  int i, j, k;
  float v, min, max, mean, meansq;
  min = max = xv->data[0][0][0];
  mean = 0.0;
  meansq = 0.0;
  for (i = 0; i < xv->nx; i++) {
    for (j = 0; j < xv->ny; j++) {
      for (k = 0; k < xv->nz; k++) {
	v = xv->data[i][j][k];
	if (v < min) {
	  min = v;
	}
	if (v > max) {
	  max = v;
	}
	mean += v;
	meansq += v*v;
      }
    }
  }
  meansq /= (float)((float)xv->nx * xv->ny * xv->nz);
  mean /= (float)((float)xv->nx * xv->ny * xv->nz);
  float rms = sqrt(meansq - mean*mean);
  fprintf(stdout, "    min, mean(stddev), max: %6.4f %6.4f(%6.4f) %6.4f\n", 
	  min, mean, rms, max);

}

VOL_STRUCT *loadUshortRaw(char *ifname, int nx, int ny, int nz) {
  fprintf(stderr, "LIBXRW WARNING: loadUshortRaw NOT 64BIT COMPLIANT\n");
  VOL_STRUCT *vol = (VOL_STRUCT *)malloc(1 * sizeof(VOL_STRUCT));
  if (!vol) {
    fprintf(stderr, "Failed to create parsed volume container.\n");
    return NULL;
  }
  
  sprintf(vol->filename, "%s", ifname);
  vol->nx = nx;
  vol->data = (float ***)malloc(vol->nx * sizeof(float **));
  if (vol->data == NULL) {
    fprintf(stderr,"Failed to allocate %ld bytes\n",(long)(vol->nx*sizeof(float **)));
    exit(-1);
  }

  vol->ny = ny;
  vol->nz = nz;
  
  unsigned short *inu = (unsigned short *)malloc(nx * ny * nz * sizeof(unsigned short));
  FILE *fin = fopen(ifname, "r");
  if (fread(inu, sizeof(unsigned short), nx * ny * nz, fin) != nx * ny * nz) {
    fprintf(stderr, "Failed to read expect number of voxels from file %s.\n", ifname);
    return NULL;
  }
  
  int i, j, k;
  for (i = 0; i < nx; i++) {
    // copy this frame in to this slice
    vol->data[i] = (float **)malloc(ny * sizeof(float *));
    for (j = 0; j < ny; j++) {
      vol->data[i][j] = (float *)malloc(nz * sizeof(float *));
      for (k = 0; k < nz; k++) {
	vol->data[i][j][nz-k-1] = (float)inu[i * ny * nz + j * nz + k];
      }
    }
  }

  vol->wdx = vol->wdy = vol->wdz = 1.0;
  for (i = 0; i < 256; i++) {
    vol->red[i] = vol->green[i] = vol->blue[i] = (float)i / 255.;
  }
  
  return vol;
}

BITMAP4 *ReadTGATexture(char *fname,int *w,int *h);
VOL_STRUCT *loadTGAstack(char *basename, int startframe, int endframe, int stride) {

  VOL_STRUCT *vol = (VOL_STRUCT *)malloc(1 * sizeof(VOL_STRUCT));
  if (!vol) {
    fprintf(stderr, "Failed to create parsed volume container.\n");
    return NULL;
  }

  char fname[255];
  BITMAP4 *readbits;
  int i, j, k;
  int w, h;

  sprintf(vol->filename, "from_TGA_stack_%s", basename);
  
  vol->nx = (endframe - startframe + 1) / stride;
  vol->data = (float ***)malloc(vol->nx * sizeof(float **));
  if (vol->data == NULL) {
    fprintf(stderr,"Failed to allocate %ld bytes\n",(long)(vol->nx*sizeof(float **)));
    exit(-1);
  }

  for (i = 0; i < (endframe - startframe +1); i+=stride) {
    sprintf(fname, basename, startframe + i);
    fprintf(stderr, "reading file %s...\n", fname);
    readbits = ReadTGATexture(fname, &w, &h);
    if (!readbits) {
      fprintf(stderr, "Failed to read image %s\n", fname);
      exit(-1);
    }
    if (i == 0) {
      vol->ny = w;
      vol->nz = h;
      fprintf(stderr, "Slices are %d x %d\n", vol->ny, vol->nz);
    }

    // copy this frame in to this slice
    vol->data[i/stride] = (float **)malloc(w * sizeof(float *));
    for (j = 0; j < w; j++) {
      vol->data[i/stride][j] = (float *)malloc(h * sizeof(float *));
#pragma omp parallel for private(k)
      for (k = 0; k < h; k++) {
	vol->data[i/stride][j][h-k-1] = readbits[j + k * w].r +
	  readbits[j + k * w].g + readbits[j + k * w].b;
      }
    }
    free(readbits);
  }

  vol->wdx = vol->wdy = vol->wdz = 1.0;
  for (i = 0; i < 256; i++) {
    vol->red[i] = vol->green[i] = vol->blue[i] = (float)i / 255.;
  }

  return vol;

}

VOL_STRUCT *rebinXvol(VOL_STRUCT *ivol, int stride[3]) {
  // verify loaded data
  if (!ivol || !ivol->data) {
    fprintf(stderr, "Invalid data given to parseXraw.\n");
    return NULL;
  }

  // allocate container
  VOL_STRUCT *vol = (VOL_STRUCT *)malloc(1 * sizeof(VOL_STRUCT));
  if (!vol) {
    fprintf(stderr, "Failed to create parsed volume container.\n");
    return NULL;
  }

  //int w, h;
  //w = ivol->nx;
  //h = ivol->ny;

  strcpy(vol->filename, ivol->filename);

  // copy scalars
  vol->nx = ivol->nx / stride[0];
  vol->ny = ivol->ny / stride[1];
  vol->nz = ivol->nz / stride[2];
  vol->wdx = ivol->wdx * stride[0];
  vol->wdy = ivol->wdy * stride[1];
  vol->wdz = ivol->wdz * stride[2];

  // copy data with stride
  vol->data = (float ***)malloc(vol->nx * sizeof(float **));
  if (!vol->data) {
    fprintf(stderr,"Failed to allocate float volume.\n");
    free(vol);
    return NULL;
  }
  int i, j, k, ii, ij, ik, ax, ay, az;
  float sum;
  for (i = 0; i < vol->nx; i++) {
    ii = i * stride[0];
    // copy this frame in to this slice
    vol->data[i] = (float **)malloc(vol->ny * sizeof(float *));
    if (!vol->data[i]) {
      fprintf(stderr, "Failed to allocate row in float volume.\n");
      return NULL;
    }
    for (j = 0; j < vol->ny; j++) {
      ij = j * stride[1];
      vol->data[i][j] = (float *)malloc(vol->nz * sizeof(float *));
      if (!vol->data[i][j]) {
	fprintf(stderr, "Failed to allocate column in float volume.\n");
	return NULL;
      }
#pragma omp parallel for private(k,ik,sum,ax,ay,az)
      for (k = 0; k < vol->nz; k++) {
	ik = k * stride[2];
	// averaging
	sum = 0.0;
	for (ax = 0; ax < stride[0]; ax++) {
	  for (ay = 0; ay < stride[1]; ay++) {
	    for (az = 0; az < stride[2]; az++) {
	      sum += (float)(ivol->data[ii+ax][ij+ay][ik+az]);
	    }
	  }
	}
	vol->data[i][j][k] = sum / (float)(stride[0] * stride[1] * stride[2]);
      }
    }
  }

  // copy look-up table
  for (i = 0; i < 256; i++) {
    vol->red[i]   = ivol->red[i];
    vol->green[i] = ivol->green[i];
    vol->blue[i]  = ivol->blue[i];
  }

  return vol;
}


void normaliseXvol(VOL_STRUCT *vol) {
  int i, j, k;
  float dmin=9e99, dmax=-9e99;
  for (i = 0; i < vol->nx; i++) {
    for (j = 0; j < vol->ny; j++) {
      for (k = 0; k < vol->nz; k++) {
	if (vol->data[i][j][k] < dmin) {
	  dmin = vol->data[i][j][k];
	}
	if (vol->data[i][j][k] > dmax) {
	  dmax = vol->data[i][j][k];
	}
      }
    }
  }
  rangeNormaliseXvol(vol, dmin, dmax);
}

void rangeNormaliseXvol(VOL_STRUCT *vol, float dmin, float dmax) {
  int i, j, k;
  for (i = 0; i < vol->nx; i++) {
    for (j = 0; j < vol->ny; j++) {
#pragma omp parallel for private(k)
      for (k = 0; k < vol->nz; k++) {
	vol->data[i][j][k] = (vol->data[i][j][k] - dmin) / (dmax - dmin);
      }
    }
  }

  vol->bzero = dmin;
  vol->bscale = (dmax - dmin);
}

void tightenXvol(VOL_STRUCT *vol, float lo_sigma, float hi_sigma) {
  int i, j, k;
  float lmean = 0.0, lvar = 0.0;
  for (i = 0; i < vol->nx; i++) {
    for (j = 0; j < vol->ny; j++) {
      for (k = 0; k < vol->nz; k++) {
	lmean += vol->data[i][j][k];
	lvar += vol->data[i][j][k] * vol->data[i][j][k];
      }
    }
  }

  lmean /= (float)(vol->nx * vol->ny * vol->nz);
  lvar = lvar / (float)(vol->nx * vol->ny * vol->nz) - lmean*lmean;
  lvar = sqrt(lvar);
  float lmin = lmean + lo_sigma * lvar;
  float lmax = lmean + hi_sigma * lvar;

  for (i = 0; i < vol->nx; i++) {
    for (j = 0; j < vol->ny; j++) {
#pragma omp parallel for private(k)
      for (k = 0; k < vol->nz; k++) {
	vol->data[i][j][k] = (vol->data[i][j][k] - lmin) / (lmax - lmin);
      }
    }
  }

  vol->bzero = lmin;
  vol->bscale = (lmax - lmin);
  



 }

void derivXvol(VOL_STRUCT *vol) {

  float ***ndat = (float ***)malloc(vol->nx * sizeof(float **));

  int i, j, k;
  float dmin=9e99, dmax=-9e99;
  float dx, dy, dz;
  for (i = 0; i < vol->nx; i++) {
    ndat[i] = (float **)malloc(vol->ny * sizeof(float *));
    for (j = 0; j < vol->ny; j++) {
      ndat[i][j] = (float *)malloc(vol->nz * sizeof(float));
      for (k = 0; k < vol->nz; k++) {
	if ((i == 0) || (i == vol->nx-1) ||
	    (j == 0) || (j == vol->ny-1) ||
	    (k == 0) || (k == vol->nz-1)) {
	  ndat[i][j][k] = 0.;
	  continue;
	}
	
	dx = fabs(vol->data[i+1][j][k] - vol->data[i-1][j][k]);
	dy = fabs(vol->data[i][j+1][k] - vol->data[i][j-1][k]);
	dz = fabs(vol->data[i][j][k+1] - vol->data[i][j][k-1]);
	// normalised, so max(dx*dx+dy*dy+dz*dz) = 3

	ndat[i][j][k] = sqrt(0.333333*(dx*dx+dy*dy+dz*dz));
	

	if (ndat[i][j][k] < dmin) {
	  dmin = ndat[i][j][k];
	}
	if (ndat[i][j][k] > dmax) {
	  dmax = ndat[i][j][k];
	}
      }
    }
  }
  for (i = 0; i < vol->nx; i++) {
    for (j = 0; j < vol->ny; j++) {
#pragma omp parallel for private(k)
      for (k = 0; k < vol->nz; k++) {
	vol->data[i][j][k] = (ndat[i][j][k] - dmin) / (dmax - dmin);
      }
      free(ndat[i][j]);
    }
    free(ndat[i]);
  }

  vol->bzero = dmin;
  vol->bscale = (dmax - dmin);

}



XRAW_STRUCT *Xvol2Xraw(VOL_STRUCT *vol) {
  
  // verify Xvol data
  if (!vol || !vol->data) {
    fprintf(stderr, "Invalid data given to parseXraw.\n");
    return NULL;
  }

  // allocate container
  XRAW_STRUCT *xrs = (XRAW_STRUCT *)malloc(1 * sizeof(XRAW_STRUCT));
  if (!xrs) {
    fprintf(stderr, "Failed to create parsed volume container.\n");
    return NULL;
  }

  int w, h;
  w = vol->nx;
  h = vol->ny;

  strcpy(xrs->filename, vol->filename);

  // copy scalars
  xrs->nx = vol->nx;
  xrs->ny = vol->ny;
  xrs->nz = vol->nz;
  xrs->wdx = vol->wdx;
  xrs->wdy = vol->wdy;
  xrs->wdz = vol->wdz;

  // copy data
  //xrs->data = (unsigned char *)malloc(xrs->nx * xrs->ny * xrs->nz * sizeof(unsigned char));
  xrs->data = (unsigned char *)calloc(xrs->nx * sizeof(unsigned char), xrs->ny * xrs->nz);
  if (!xrs->data) {
    fprintf(stderr,"Failed to allocate unsigned char volume.\n");
    free(vol);
    return NULL;
  }

  int i, j, k;
  float tmp;
  for (i = 0; i < xrs->nx; i++) {
    for (j = 0; j < xrs->ny; j++) {
#pragma omp parallel for private(k,tmp)
      for (k = 0; k < xrs->nz; k++) {
	// fill y and z planes in reverse directions so that home view in 
	// s2plot (and pdf) matches orientation xrw was exported from in 
	// OsiriX
	tmp = vol->data[i][xrs->ny-1-j][xrs->nz-1-k] * 256;
	if (tmp < 0.) { tmp = 0.; }
	if (tmp > 255.999) { tmp = 255.999; }
	xrs->data[(long)k * w * h + j * w + i] = (unsigned char)(floorf(tmp));
      }
    }
  }
  
  // copy look-up table
  for (i = 0; i < 256; i++) {
    xrs->red[i]   = (unsigned char)floorf((vol->red[i]) *255.999);
    xrs->green[i] = (unsigned char)floorf((vol->green[i]) * 255.999);
    xrs->blue[i]  = (unsigned char)floorf((vol->blue[i]) * 255.999);
  }

  return xrs;
}


VOL_STRUCT *loadRaw(char *filename, int nx, int ny, int nz, int type) {
  fprintf(stderr, "LIBXRW WARNING: loadRaw NOT 64BIT COMPLIANT\n");
  VOL_STRUCT *vol = (VOL_STRUCT *)malloc(1 * sizeof(VOL_STRUCT));
  if (!vol) {
    fprintf(stderr, "Failed to create parsed volume container.\n");
    return NULL;
  }

  FILE *fin = fopen(filename, "rb");
  if (!fin) {
    fprintf(stderr, "Failed to open %s.\n", filename);
    return NULL;
  }

  vol->nx = nx;
  vol->ny = ny;
  vol->nz = nz;
  int np = nx * ny * nz;
  int i, j, k;

  switch (type) {
  case RAW_UINT8:
    {
      fprintf(stderr, "RAW_UINT8 not yet implemented!\n");
      return NULL;
      break;
    }

  case RAW_UINT16:
    {
      if (sizeof(unsigned short) != 2) {
	fprintf(stderr, "Um, no suitable storage for 16b raw!!!\n");
	return NULL;
      }
      unsigned short *id = (unsigned short *)malloc(np * sizeof(unsigned short));
      if (fread(id, sizeof(unsigned short), np, fin) != np) {
	fprintf(stderr, "failed to read correct number of data points!\n");
	return NULL;
      }
      vol->data = (float ***)malloc(nx * sizeof(float **));
      
      for (i = 0; i < nx; i++) {
	vol->data[i] = (float **)malloc(ny * sizeof(float *));
	for (j = 0; j < ny; j++) {
	  vol->data[i][j] = (float *)malloc(nz * sizeof(float));
	  for (k = 0; k < nz; k++) {
	    vol->data[i][j][k] = (float)id[i + j * nx + k * nx * ny];
	    //vol->data[i][j][k] = (float)id[i * ny * nz + j * nz + k];
	    
	    // apply specific window
	    if (vol->data[i][j][k] < 100) {
	      vol->data[i][j][k] = 0;
	    }
	    if (vol->data[i][j][k] > 1500) {
	      vol->data[i][j][k] = 1500;
	    }
	  }
	}
      }
      break;
    }

  default:
    {
      fprintf(stderr, "Unknown RAW format.\n");
      return NULL;
    }
  }

  vol->wdx = vol->wdy = vol->wdz = 1.0;
  for (i = 0; i < 256; i++) {
    vol->red[i] = vol->green[i] = vol->blue[i] = (float)i / 255.;
  }

  strcpy(vol->filename, filename);

  return vol;
}
Beispiel #8
0
/*
 * This is a plain way to read file header.
 * User needs to take care of concurrency issue etc.
 * Parameters :
 *	fn : full name of a database file.
 *	header: Pointer to database file header structure (may not be in shared memory)
 *	len: size of header (may be just SGMNT_HDR_LEN or SIZEOF_FILE_HDR_MAX)
 */
boolean_t file_head_read(char *fn, sgmnt_data_ptr_t header, int4 len)
{
	int 		save_errno, fd, header_size;
	struct stat	stat_buf;

	error_def(ERR_DBFILOPERR);
	error_def(ERR_DBNOTGDS);

	header_size = sizeof(sgmnt_data);
	OPENFILE(fn, O_RDONLY, fd);
	if (-1 == fd)
	{
		save_errno = errno;
		gtm_putmsg(VARLSTCNT(5) ERR_DBFILOPERR, 2, LEN_AND_STR(fn), save_errno);
		return FALSE;
	}
	FSTAT_FILE(fd, &stat_buf, save_errno);
	if (-1 == save_errno)
	{
		save_errno = errno;
		gtm_putmsg(VARLSTCNT(5) ERR_DBFILOPERR, 2, LEN_AND_STR(fn), save_errno);
 		CLOSEFILE(fd, save_errno);
		return FALSE;
	}
	if (!S_ISREG(stat_buf.st_mode) || stat_buf.st_size < header_size)
	{
		gtm_putmsg(VARLSTCNT(4) ERR_DBNOTGDS, 2, LEN_AND_STR(fn));
 		CLOSEFILE(fd, save_errno);
		return FALSE;
	}
	LSEEKREAD(fd, 0, header, header_size, save_errno);
	if (0 != save_errno)
	{
		gtm_putmsg(VARLSTCNT(5) ERR_DBFILOPERR, 2, LEN_AND_STR(fn), save_errno);
 		CLOSEFILE(fd, save_errno);
		return FALSE;
	}
	if (memcmp(header->label, GDS_LABEL, GDS_LABEL_SZ - 1))
	{
		gtm_putmsg(VARLSTCNT(4) ERR_DBNOTGDS, 2, LEN_AND_STR(fn));
 		CLOSEFILE(fd, save_errno);
		return FALSE;
	}
	CHECK_DB_ENDIAN(header, strlen(fn), fn);
	assert(MASTER_MAP_SIZE_MAX >= MASTER_MAP_SIZE(header));
	assert(SGMNT_HDR_LEN == len || SIZEOF_FILE_HDR(header) <= len);
	if (SIZEOF_FILE_HDR(header) <= len)
	{
		LSEEKREAD(fd, ROUND_UP(SGMNT_HDR_LEN + 1, DISK_BLOCK_SIZE), MM_ADDR(header), MASTER_MAP_SIZE(header), save_errno);
		if (0 != save_errno)
		{
			gtm_putmsg(VARLSTCNT(5) ERR_DBFILOPERR, 2, LEN_AND_STR(fn), save_errno);
			CLOSEFILE(fd, save_errno);
			return FALSE;
		}
	}
	CLOSEFILE(fd, save_errno);
	if (0 != save_errno)
	{
		gtm_putmsg(VARLSTCNT(5) ERR_DBFILOPERR, 2, LEN_AND_STR(fn), save_errno);
		return FALSE;
	}
	return TRUE;
}
Beispiel #9
0
int gtmsource()
{
	int			status, log_init_status, waitpid_res, save_errno;
	char			print_msg[1024], tmpmsg[1024];
	gd_region		*reg, *region_top;
	sgmnt_addrs		*csa, *repl_csa;
	boolean_t		all_files_open, isalive;
	pid_t			pid, ppid, procgp;
	seq_num			read_jnl_seqno, jnl_seqno;
	unix_db_info		*udi;
	gtmsource_local_ptr_t	gtmsource_local;
	boolean_t		this_side_std_null_coll;
	int			null_fd, rc;

	memset((uchar_ptr_t)&jnlpool, 0, SIZEOF(jnlpool_addrs));
	call_on_signal = gtmsource_sigstop;
	ESTABLISH_RET(gtmsource_ch, SS_NORMAL);
	if (-1 == gtmsource_get_opt())
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
	if (gtmsource_options.shut_down)
	{	/* Wait till shutdown time nears even before going to "jnlpool_init". This is because the latter will return
		 * with the ftok semaphore and access semaphore held and we do not want to be holding those locks (while
		 * waiting for the user specified timeout to expire) as that will affect new GTM processes and/or other
		 * MUPIP REPLIC commands that need these locks for their function.
		 */
		if (0 < gtmsource_options.shutdown_time)
		{
			repl_log(stdout, TRUE, TRUE, "Waiting for %d seconds before signalling shutdown\n",
												gtmsource_options.shutdown_time);
			LONG_SLEEP(gtmsource_options.shutdown_time);
		} else
			repl_log(stdout, TRUE, TRUE, "Signalling shutdown immediate\n");
	} else if (gtmsource_options.start)
	{
		repl_log(stdout, TRUE, TRUE, "Initiating START of source server for secondary instance [%s]\n",
			gtmsource_options.secondary_instname);
	}
	if (gtmsource_options.activate && (ROOTPRIMARY_SPECIFIED == gtmsource_options.rootprimary))
	{	/* MUPIP REPLIC -SOURCE -ACTIVATE -UPDOK has been specified. We need to open the gld and db regions now
		 * in case this is a secondary -> primary transition. This is so we can later switch journal files in all
		 * journaled regions when the transition actually happens inside "gtmsource_rootprimary_init". But since
		 * we have not yet done a "jnlpool_init", we dont know if updates are disabled in it or not. Although we
		 * need to do the gld/db open only if updates are currently disabled in the jnlpool, we do this always
		 * because once we do a jnlpool_init, we will come back with the ftok on the jnlpool held and that has
		 * issues with later db open since we will try to hold the db ftok as part of db open and the ftok logic
		 * currently has assumptions that a process holds only one ftok at any point in time.
		 */
		assert(NULL == gd_header);
		gvinit();
		all_files_open = region_init(FALSE);
		if (!all_files_open)
		{
			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTALLDBOPN);
			gtmsource_exit(ABNORMAL_SHUTDOWN);
		}
	}
	jnlpool_init(GTMSOURCE, gtmsource_options.start, &is_jnlpool_creator);
	/* is_jnlpool_creator == TRUE ==> this process created the journal pool
	 * is_jnlpool_creator == FALSE ==> journal pool already existed and this process simply attached to it.
	 */
	if (gtmsource_options.shut_down)
		gtmsource_exit(gtmsource_shutdown(FALSE, NORMAL_SHUTDOWN) - NORMAL_SHUTDOWN);
	else if (gtmsource_options.activate)
		gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_ACTIVE_REQUESTED) - NORMAL_SHUTDOWN);
	else if (gtmsource_options.deactivate)
		gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_PASSIVE_REQUESTED) - NORMAL_SHUTDOWN);
	else if (gtmsource_options.checkhealth)
		gtmsource_exit(gtmsource_checkhealth() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.changelog)
		 gtmsource_exit(gtmsource_changelog() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.showbacklog)
		gtmsource_exit(gtmsource_showbacklog() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.stopsourcefilter)
		gtmsource_exit(gtmsource_stopfilter() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.jnlpool)
		gtmsource_exit(gtmsource_jnlpool() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.losttncomplete)
		gtmsource_exit(gtmsource_losttncomplete() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.needrestart)
		gtmsource_exit(gtmsource_needrestart() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.showfreeze)
		gtmsource_exit(gtmsource_showfreeze() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.setfreeze)
		gtmsource_exit(gtmsource_setfreeze() - NORMAL_SHUTDOWN);
	else if (!gtmsource_options.start)
	{
		assert(CLI_PRESENT == cli_present("STATSLOG"));
		gtmsource_exit(gtmsource_statslog() - NORMAL_SHUTDOWN);
	}
	assert(gtmsource_options.start);
#	ifndef REPL_DEBUG_NOBACKGROUND
	/* Set "child_server_running" to FALSE before forking off child. Wait for it to be set to TRUE by the child. */
	gtmsource_local = jnlpool.gtmsource_local;
	gtmsource_local->child_server_running = FALSE;
	FORK(pid);
	if (0 > pid)
	{
		save_errno = errno;
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0,
			ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not fork source server"), save_errno);
	} else if (0 < pid)
	{	/* Parent. Wait until child sets "child_server_running" to FALSE. That is an indication that the child
		 * source server has completed its initialization phase and is all set so the parent command can return.
		 */
		while (isalive = is_proc_alive(pid, 0))	/* note : intended assignment */
		{
			if (gtmsource_local->child_server_running)
				break;
			/* To take care of reassignment of PIDs, the while condition should be && with the condition
			 * (PPID of pid == process_id)
			 */
			SHORT_SLEEP(GTMSOURCE_WAIT_FOR_SRV_START);
			WAITPID(pid, &status, WNOHANG, waitpid_res); /* Release defunct child if dead */
		}
		if (isalive)
		{	/* Child process is alive and started with no issues */
			if (0 != (save_errno = rel_sem(SOURCE, JNL_POOL_ACCESS_SEM)))
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0,
					ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in rel_sem"), save_errno);
			ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
		} else
		{	/* Child source server process errored out at startup and is no longer alive.
			 * If we were the one who created the journal pool, let us clean it up.
			 */
			repl_log(stdout, TRUE, TRUE, "Source server startup failed. See source server log file\n");
			if (is_jnlpool_creator)
				status = gtmsource_shutdown(TRUE, NORMAL_SHUTDOWN);
		}
		/* If the parent is killed (or crashes) between the fork and exit, checkhealth may not detect that startup
		 * is in progress - parent forks and dies, the system will release sem 0 and 1, checkhealth might test the
		 * value of sem 1 before the child grabs sem 1.
		 */
		gtmsource_exit(isalive ? SRV_ALIVE : SRV_ERR);
	}
	/* Point stdin to /dev/null */
	OPENFILE("/dev/null", O_RDONLY, null_fd);
	if (0 > null_fd)
		rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to open /dev/null for read"), errno, 0);
	FCNTL3(null_fd, F_DUPFD, 0, rc);
	if (0 > rc)
		rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to set stdin to /dev/null"), errno, 0);
	CLOSEFILE(null_fd, rc);
	if (0 > rc)
		rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to close /dev/null"), errno, 0);
	/* The parent process (source server startup command) will be holding the ftok semaphore and jnlpool access semaphore
	 * at this point. The variables that indicate this would have been copied over to the child during the fork. This will
	 * make the child think it is actually holding them as well when actually it is not. Reset those variables in the child
	 * to ensure they do not misrepresent the holder of those semaphores.
	 */
	ftok_sem_reg = NULL;
	udi = FILE_INFO(jnlpool.jnlpool_dummy_reg);
	assert(udi->grabbed_ftok_sem);
	udi->grabbed_ftok_sem = FALSE;
	assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]);
	holds_sem[SOURCE][JNL_POOL_ACCESS_SEM] = FALSE;
	assert(!holds_sem[SOURCE][SRC_SERV_COUNT_SEM]);
	/* Start child source server initialization */
	is_src_server = TRUE;
	OPERATOR_LOG_MSG;
	process_id = getpid();
	/* Reinvoke secshr related initialization with the child's pid */
	INVOKE_INIT_SECSHR_ADDRS;
	/* Initialize mutex socket, memory semaphore etc. before any "grab_lock" is done by this process on the journal pool.
	 * Note that the initialization would already have been done by the parent receiver startup command but we need to
	 * redo the initialization with the child process id.
	 */
	assert(mutex_per_process_init_pid && (mutex_per_process_init_pid != process_id));
	mutex_per_process_init();
	START_HEARTBEAT_IF_NEEDED;
	ppid = getppid();
	log_init_status = repl_log_init(REPL_GENERAL_LOG, &gtmsource_log_fd, gtmsource_options.log_file);
	assert(SS_NORMAL == log_init_status);
	repl_log_fd2fp(&gtmsource_log_fp, gtmsource_log_fd);
	if (-1 == (procgp = setsid()))
		send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
				RTS_ERROR_LITERAL("Source server error in setsid"), errno);
#	endif /* REPL_DEBUG_NOBACKGROUND */
	if (ZLIB_CMPLVL_NONE != gtm_zlib_cmp_level)
		gtm_zlib_init();	/* Open zlib shared library for compression/decompression */
	REPL_DPRINT1("Setting up regions\n");
	gvinit();

	/* We use the same code dse uses to open all regions but we must make sure they are all open before proceeding. */
	all_files_open = region_init(FALSE);
	if (!all_files_open)
	{
		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTALLDBOPN);
		gtmsource_exit(ABNORMAL_SHUTDOWN);
	}
	/* Determine primary side null subscripts collation order */
	/* Also check whether all regions have same null collation order */
	this_side_std_null_coll = -1;
	for (reg = gd_header->regions, region_top = gd_header->regions + gd_header->n_regions; reg < region_top; reg++)
	{
		csa = &FILE_INFO(reg)->s_addrs;
		if (this_side_std_null_coll != csa->hdr->std_null_coll)
		{
			if (-1 == this_side_std_null_coll)
				this_side_std_null_coll = csa->hdr->std_null_coll;
			else
			{
				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NULLCOLLDIFF);
				gtmsource_exit(ABNORMAL_SHUTDOWN);
			}
		}
		if (!REPL_ALLOWED(csa) && JNL_ALLOWED(csa))
		{
			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REPLOFFJNLON, 2, DB_LEN_STR(reg));
			gtmsource_exit(ABNORMAL_SHUTDOWN);
		}
		if (reg->read_only && REPL_ALLOWED(csa))
		{
			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
				   RTS_ERROR_LITERAL("Source Server does not have write permissions to one or "
					             "more database files that are replicated"));
			gtmsource_exit(ABNORMAL_SHUTDOWN);
		}
	}
	/* Initialize source server alive/dead state related fields in "gtmsource_local" before the ftok semaphore is released */
	gtmsource_local->gtmsource_pid = process_id;
	gtmsource_local->gtmsource_state = GTMSOURCE_START;
	if (is_jnlpool_creator)
	{
		DEBUG_ONLY(jnlpool.jnlpool_ctl->jnlpool_creator_pid = process_id);
		gtmsource_seqno_init(this_side_std_null_coll);
		if (ROOTPRIMARY_SPECIFIED == gtmsource_options.rootprimary)
		{	/* Created the journal pool as a root primary. Append a history record to the replication instance file.
			 * Invoke the function "gtmsource_rootprimary_init" to do that.
			 */
			gtmsource_rootprimary_init(jnlpool.jnlpool_ctl->jnl_seqno);
		}
	}
	/* after this point we can no longer have the case where all the regions are unreplicated/non-journaled. */
#	ifndef REPL_DEBUG_NOBACKGROUND
	/* It is necessary for every process that is using the ftok semaphore to increment the counter by 1. This is used
	 * by the last process that shuts down to delete the ftok semaphore when it notices the counter to be 0.
	 * Note that the parent source server startup command would have done an increment of the ftok counter semaphore
	 * for the replication instance file. But the source server process (the child) that comes here would not have done
	 * that. Do that while the parent is still holding on to the ftok semaphore waiting for our okay.
	 */
	if (!ftok_sem_incrcnt(jnlpool.jnlpool_dummy_reg))
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP);
	/* Increment the source server count semaphore */
	status = incr_sem(SOURCE, SRC_SERV_COUNT_SEM);
	if (0 != status)
	{
		save_errno = errno;
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
			RTS_ERROR_LITERAL("Counter semaphore increment failure in child source server"), save_errno);
	}
#	else
	if (0 != (save_errno = rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM)))
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
			RTS_ERROR_LITERAL("Error in rel_sem_immediate"), save_errno);
	}
#	endif /* REPL_DEBUG_NOBACKGROUND */

	gtmsource_srv_count++;
	gtmsource_local->child_server_running = TRUE;	/* At this point, the parent startup command will stop waiting for child */
	gtm_event_log_init();
	/* Log source server startup command line first */
	SPRINTF(tmpmsg, "%s %s\n", cli_lex_in_ptr->argv[0], cli_lex_in_ptr->in_str);
	repl_log(gtmsource_log_fp, TRUE, TRUE, tmpmsg);

	SPRINTF(tmpmsg, "GTM Replication Source Server with Pid [%d] started for Secondary Instance [%s]",
		process_id, gtmsource_local->secondary_instname);
	sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2, LEN_AND_STR(tmpmsg));
	repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
	if (is_jnlpool_creator)
	{
		repl_log(gtmsource_log_fp, TRUE, TRUE, "Created jnlpool with shmid = [%d] and semid = [%d]\n",
			jnlpool.repl_inst_filehdr->jnlpool_shmid, jnlpool.repl_inst_filehdr->jnlpool_semid);
	} else
		repl_log(gtmsource_log_fp, TRUE, TRUE, "Attached to existing jnlpool with shmid = [%d] and semid = [%d]\n",
			jnlpool.repl_inst_filehdr->jnlpool_shmid, jnlpool.repl_inst_filehdr->jnlpool_semid);
	gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLINFO", print_msg);
#	ifdef GTM_TLS
	if (REPL_TLS_REQUESTED)
	{
		repl_do_tls_init(gtmsource_log_fp);
		assert(REPL_TLS_REQUESTED || PLAINTEXT_FALLBACK);
	}
#	endif
	if (jnlpool.jnlpool_ctl->freeze)
	{
		last_seen_freeze_flag = jnlpool.jnlpool_ctl->freeze;
		sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTFROZEN, 1, jnlpool.repl_inst_filehdr->inst_info.this_instname);
		repl_log(gtmsource_log_fp, TRUE, FALSE, print_msg);
		sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTFREEZECOMMENT, 1, jnlpool.jnlpool_ctl->freeze_comment);
		repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
	}
	gtmsource_local->jnlfileonly = gtmsource_options.jnlfileonly;
	do
	{ 	/* If mode is passive, go to sleep. Wakeup every now and then and check to see if I have to become active. */
		gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_START;
		if ((gtmsource_local->mode == GTMSOURCE_MODE_PASSIVE) && (gtmsource_local->shutdown == NO_SHUTDOWN))
		{
			gtmsource_poll_actions(FALSE);
			SHORT_SLEEP(GTMSOURCE_WAIT_FOR_MODE_CHANGE);
			continue;
		}
		if (GTMSOURCE_MODE_PASSIVE == gtmsource_local->mode)
		{	/* Shutdown initiated */
			assert(gtmsource_local->shutdown == SHUTDOWN);
			sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2,
				    RTS_ERROR_LITERAL("GTM Replication Source Server Shutdown signalled"));
			repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
			gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLINFO", print_msg);
			break;
		}
		gtmsource_poll_actions(FALSE);
		if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
			continue;
		if (GTMSOURCE_MODE_ACTIVE_REQUESTED == gtmsource_local->mode)
			gtmsource_local->mode = GTMSOURCE_MODE_ACTIVE;
		SPRINTF(tmpmsg, "GTM Replication Source Server now in ACTIVE mode using port %d", gtmsource_local->secondary_port);
		sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2, LEN_AND_STR(tmpmsg));
		repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
		gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLINFO", print_msg);
		DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;)
		assert(!repl_csa->hold_onto_crit);	/* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */
		grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
		if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
		{
			repl_log(gtmsource_log_fp, TRUE, TRUE, "Starting afresh due to ONLINE ROLLBACK\n");
			repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO - Current Jnlpool Seqno : %llu\n",
					jnlpool.jnlpool_ctl->jnl_seqno);
			continue;
		}
		QWASSIGN(gtmsource_local->read_addr, jnlpool.jnlpool_ctl->write_addr);
		gtmsource_local->read = jnlpool.jnlpool_ctl->write;
		gtmsource_local->read_state = gtmsource_local->jnlfileonly ? READ_FILE : READ_POOL;
		read_jnl_seqno = gtmsource_local->read_jnl_seqno;
		assert(read_jnl_seqno <= jnlpool.jnlpool_ctl->jnl_seqno);
		if (read_jnl_seqno < jnlpool.jnlpool_ctl->jnl_seqno)
		{
			gtmsource_local->read_state = READ_FILE;
			QWASSIGN(gtmsource_save_read_jnl_seqno, jnlpool.jnlpool_ctl->jnl_seqno);
			gtmsource_pool2file_transition = TRUE; /* so that we read the latest gener jnl files */
		}
		rel_lock(jnlpool.jnlpool_dummy_reg);
		if (SS_NORMAL != (status = gtmsource_alloc_tcombuff()))
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
				  RTS_ERROR_LITERAL("Error allocating initial tcom buffer space. Malloc error"), status);
		gtmsource_filter = NO_FILTER;
		if ('\0' != gtmsource_local->filter_cmd[0])
		{
			if (SS_NORMAL == (status = repl_filter_init(gtmsource_local->filter_cmd)))
				gtmsource_filter |= EXTERNAL_FILTER;
			else
				gtmsource_exit(ABNORMAL_SHUTDOWN);
		}
		gtmsource_process();
		/* gtmsource_process returns only when mode needs to be changed to PASSIVE */
		assert(gtmsource_state == GTMSOURCE_CHANGING_MODE);
		gtmsource_ctl_close();
		gtmsource_free_msgbuff();
		gtmsource_free_tcombuff();
		gtmsource_free_filter_buff();
		gtmsource_stop_heartbeat();
		if (FD_INVALID != gtmsource_sock_fd)
			repl_close(&gtmsource_sock_fd);
		if (gtmsource_filter & EXTERNAL_FILTER)
			repl_stop_filter();
	} while (TRUE);
Beispiel #10
0
int gtm_trigger_complink(gv_trigger_t *trigdsc, boolean_t dolink)
{
	char		rtnname[GTM_PATH_MAX + 1], rtnname_template[GTM_PATH_MAX + 1];
	char		objname[GTM_PATH_MAX + 1];
	char		zcomp_parms[(GTM_PATH_MAX * 2) + SIZEOF(mident_fixed) + SIZEOF(OBJECT_PARM) + SIZEOF(NAMEOFRTN_PARM)];
	mstr		save_zsource;
	int		rtnfd, rc, lenrtnname, lenobjname, len, alphnum_len, retry, save_errno;
	char		*mident_suffix_p1, *mident_suffix_p2, *mident_suffix_top, *namesub1, *namesub2, *zcomp_parms_ptr;
	mval		zlfile, zcompprm;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	DBGTRIGR_ONLY(memcpy(rtnname, trigdsc->rtn_desc.rt_name.addr, trigdsc->rtn_desc.rt_name.len));
	DBGTRIGR_ONLY(rtnname[trigdsc->rtn_desc.rt_name.len] = 0);
	DBGTRIGR((stderr, "gtm_trigger_complink: (Re)compiling trigger %s\n", rtnname));
	ESTABLISH_RET(gtm_trigger_complink_ch, ((0 == error_condition) ? TREF(dollar_zcstatus) : error_condition ));
	 /* Verify there are 2 available chars for uniqueness */
	assert((MAX_MIDENT_LEN - TRIGGER_NAME_RESERVED_SPACE) >= (trigdsc->rtn_desc.rt_name.len));
	assert(NULL == trigdsc->rtn_desc.rt_adr);
	gtm_trigger_comp_prev_run_time = run_time;
	run_time = TRUE;	/* Required by compiler */
	/* Verify the routine name set by MUPIP TRIGGER and read by gvtr_db_read_hasht() is not in use */
	if (NULL != find_rtn_hdr(&trigdsc->rtn_desc.rt_name))
	{	/* Ooops .. need name to be more unique.. */
		/* Though variable definitions are conventionally done at the function entry, the reason alphanumeric_table
		 * definition is done here is to minimize the time taken to initialize the below table in the most common case
		 * (i.e. no trigger name collisions).
		 */
		char 		alphanumeric_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
							'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
							'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
							't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
							'8', '9', '\0'};
		alphnum_len = STR_LIT_LEN(alphanumeric_table);
		namesub1 = trigdsc->rtn_desc.rt_name.addr + trigdsc->rtn_desc.rt_name.len++;
		/* If WBTEST_HELPOUT_TRIGNAMEUNIQ is defined, set alphnum_len to 1. This way, we make the maximum
		 * possible combinations for the uniqe trigger names to be 3 which is significantly lesser than
		 * the actual number of combinations (62x62 = 3844). For eg., if ^a is a global having triggers defined
		 * in 4 global directories, then the possible unique trigger names are a#1# ; a#1#A ; a#1#AA.
		 */
		GTM_WHITE_BOX_TEST(WBTEST_HELPOUT_TRIGNAMEUNIQ, alphnum_len, 1);
		mident_suffix_top = (char *)alphanumeric_table + alphnum_len;
		/* Phase 1. See if any single character can add uniqueness */
		for (mident_suffix_p1 = (char *)alphanumeric_table; mident_suffix_p1 < mident_suffix_top; mident_suffix_p1++)
		{
			*namesub1 = *mident_suffix_p1;
			if (NULL == find_rtn_hdr(&trigdsc->rtn_desc.rt_name))
				break;
		}
		if (mident_suffix_p1 == mident_suffix_top)
		{	/* Phase 2. Phase 1 could not find uniqueness .. Find it with 2 char variations */
			namesub2 = trigdsc->rtn_desc.rt_name.addr + trigdsc->rtn_desc.rt_name.len++;
			for (mident_suffix_p1 = (char *)alphanumeric_table; mident_suffix_p1 < mident_suffix_top;
			     mident_suffix_p1++)
			{	/* First char loop */
				for (mident_suffix_p2 = (char *)alphanumeric_table; mident_suffix_p2 < mident_suffix_top;
				     mident_suffix_p2++)
				{	/* 2nd char loop */
					*namesub1 = *mident_suffix_p1;
					*namesub2 = *mident_suffix_p2;
					if (NULL == find_rtn_hdr(&trigdsc->rtn_desc.rt_name))
					{
						mident_suffix_p1 = mident_suffix_top + 1;	/* Break out of both loops */
						break;
					}
				}
			}
			if (mident_suffix_p1 == mident_suffix_top)
			{	/* Phase 3: Punt */
				assert(WBTEST_HELPOUT_TRIGNAMEUNIQ == gtm_white_box_test_case_number);
				rts_error(VARLSTCNT(5) ERR_TRIGNAMEUNIQ, 3, trigdsc->rtn_desc.rt_name.len - 2,
					  trigdsc->rtn_desc.rt_name.addr, alphnum_len * alphnum_len);
			}
		}
	}
	/* Write trigger execute string out to temporary file and compile it */
	assert(MAX_XECUTE_LEN >= trigdsc->xecute_str.str.len);
	rc = SNPRINTF(rtnname_template, GTM_PATH_MAX, "%s/trgtmpXXXXXX", DEFAULT_GTM_TMP);
	assert(0 < rc);					/* Note rc is return code aka length - we expect a non-zero length */
	assert(GTM_PATH_MAX >= rc);
	/* The mkstemp() routine is known to bogus-fail for no apparent reason at all especially on AIX 6.1. In the event
	 * this shortcoming plagues other platforms as well, we add a low-cost retry wrapper.
	 */
	retry = MAX_MKSTEMP_RETRIES;
	do
	{
		strcpy(rtnname, rtnname_template);
		rtnfd = mkstemp(rtnname);
	} while ((-1 == rtnfd) && (EEXIST == errno) && (0 < --retry));
	if (-1 == rtnfd)
	{
		save_errno = errno;
		assert(FALSE);
		rts_error(VARLSTCNT(12) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("mkstemp()"), CALLFROM,
			  ERR_TEXT, 2, RTS_ERROR_TEXT(rtnname), save_errno);
	}
	assert(0 < rtnfd);	/* Verify file descriptor */
	rc = 0;
#	ifdef GEN_TRIGCOMPFAIL_ERROR
	{	/* Used ONLY to generate an error in a trigger compile by adding some junk in a previous line */
		DOWRITERC(rtnfd, ERROR_CAUSING_JUNK, strlen(ERROR_CAUSING_JUNK), rc); /* BYPASSOK */
		if (0 != rc)
		{
			UNLINK(rtnname);
			rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("write()"), CALLFROM, rc);
		}
	}
#	endif
	DOWRITERC(rtnfd, trigdsc->xecute_str.str.addr, trigdsc->xecute_str.str.len, rc);
	if (0 != rc)
	{
		UNLINK(rtnname);
		rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("write()"), CALLFROM, rc);
	}
	if (NULL == memchr(trigdsc->xecute_str.str.addr, '\n', trigdsc->xecute_str.str.len))
	{
		DOWRITERC(rtnfd, NEWLINE, strlen(NEWLINE), rc);			/* BYPASSOK */
		if (0 != rc)
		{
			UNLINK(rtnname);
			rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("write()"), CALLFROM, rc);
		}
	}
	CLOSEFILE(rtnfd, rc);
	if (0 != rc)
	{
		UNLINK(rtnname);
		rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("close()"), CALLFROM, rc);
	}
	assert(MAX_MIDENT_LEN > trigdsc->rtn_desc.rt_name.len);
	zcomp_parms_ptr = zcomp_parms;
	lenrtnname = STRLEN(rtnname);
	MEMCPY_LIT(zcomp_parms_ptr, NAMEOFRTN_PARM);
	zcomp_parms_ptr += STRLEN(NAMEOFRTN_PARM);
	memcpy(zcomp_parms_ptr, trigdsc->rtn_desc.rt_name.addr, trigdsc->rtn_desc.rt_name.len);
	zcomp_parms_ptr += trigdsc->rtn_desc.rt_name.len;
	MEMCPY_LIT(zcomp_parms_ptr, OBJECT_PARM);
	zcomp_parms_ptr += STRLEN(OBJECT_PARM);
	strcpy(objname, rtnname);		/* Make copy of rtnname to become object name */
	strcat(objname, OBJECT_FTYPE);		/* Turn into object file reference */
	lenobjname = lenrtnname + STRLEN(OBJECT_FTYPE);
	memcpy(zcomp_parms_ptr, objname, lenobjname);
	zcomp_parms_ptr += lenobjname;
	*zcomp_parms_ptr++ = ' ';
	memcpy(zcomp_parms_ptr, rtnname, lenrtnname);
	zcomp_parms_ptr += lenrtnname;
	*zcomp_parms_ptr = '\0';		/* Null tail */
	len = INTCAST(zcomp_parms_ptr - zcomp_parms);
	assert((SIZEOF(zcomp_parms) - 1) > len);	/* Verify no overflow */
	zcompprm.mvtype = MV_STR;
	zcompprm.str.addr = zcomp_parms;
	zcompprm.str.len = len;
	/* Backup dollar_zsource so trigger doesn't show */
	PUSH_MV_STENT(MVST_MSAV);
	mv_chain->mv_st_cont.mvs_msav.v = dollar_zsource;
	mv_chain->mv_st_cont.mvs_msav.addr = &dollar_zsource;
	TREF(trigger_compile) = TRUE;		/* Set flag so compiler knows this is a special trigger compile */
	op_zcompile(&zcompprm, FALSE);	/* Compile but don't require a .m file extension */
	TREF(trigger_compile) = FALSE;	/* compile_source_file() establishes handler so always returns */
	if (0 != TREF(dollar_zcstatus))
	{	/* Someone err'd.. */
		run_time = gtm_trigger_comp_prev_run_time;
		REVERT;
		UNLINK(objname);	/* Remove files before return error */
		UNLINK(rtnname);
		return ERR_TRIGCOMPFAIL;
	}
	if (dolink)
	{	/* Link is optional as MUPIP TRIGGER doesn't need link */
		zlfile.mvtype = MV_STR;
		zlfile.str.addr = objname;
		zlfile.str.len = lenobjname;
		/* Specifying literal_null for a second arg (as opposed to NULL or 0) allows us to specify
		 * linking the object file (no compilation or looking for source). The 2nd arg is parms for
		 * recompilation and is non-null in an explicit zlink which we need to emulate.
		 */
#		ifdef GEN_TRIGLINKFAIL_ERROR
		UNLINK(objname);				/* delete object before it can be used */
#		endif
		op_zlink(&zlfile, (mval *)&literal_null);	/* need cast due to "extern const" attributes */
		/* No return here if link fails for some reason */
		trigdsc->rtn_desc.rt_adr = find_rtn_hdr(&trigdsc->rtn_desc.rt_name);
		if (NULL == trigdsc->rtn_desc.rt_adr)
			GTMASSERT;	/* Can't find routine we just put there? Catastrophic if happens */
		/* Replace the randomly generated source name with the constant "GTM Trigger" */
		trigdsc->rtn_desc.rt_adr->src_full_name.addr = GTM_TRIGGER_SOURCE_NAME;
		trigdsc->rtn_desc.rt_adr->src_full_name.len = STRLEN(GTM_TRIGGER_SOURCE_NAME);
		trigdsc->rtn_desc.rt_adr->trigr_handle = trigdsc;       /* Back pointer to trig def */
	}
	if (MVST_MSAV == mv_chain->mv_st_type && &dollar_zsource == mv_chain->mv_st_cont.mvs_msav.addr)
	{       /* Top mv_stent is one we pushed on there - restore dollar_zsource and get rid of it */
		dollar_zsource = mv_chain->mv_st_cont.mvs_msav.v;
		POP_MV_STENT();
	} else
		assert(FALSE); 	/* This mv_stent should be the one we just pushed */
	/* Remove temporary files created */
	UNLINK(objname);	/* Delete the object file first since rtnname is the unique key */
	UNLINK(rtnname);	/* Delete the source file */
	run_time = gtm_trigger_comp_prev_run_time;
	REVERT;
	return 0;
}