Exemplo n.º 1
0
/*
 *---------------------------------------------------------------------------
 *
 * SetupStdFile --
 *
 *	Set up stdio file handles for the child process, using the
 *	current standard channels if no other files are specified.
 *	If no standard channel is defined, or if no file is associated
 *	with the channel, then the corresponding standard fd is closed.
 *
 * Results:
 *	Returns 1 on success, or 0 on failure.
 *
 * Side effects:
 *	Replaces stdio fds.
 *
 *---------------------------------------------------------------------------
 */
static int
SetupStdFile(
    int fd,				/* File descriptor to dup, or -1. */
    int type)				/* One of TCL_STDIN, TCL_STDOUT,
					 * TCL_STDERR */
{
    int targetFd = 0;			/* Initializations here needed only
					 * to */
    int direction = 0;			/* Prevent warnings about using
					 * uninitialized variables. */
    switch (type) {
    case TCL_STDIN:
	targetFd = 0;
	direction = TCL_READABLE;
	break;
    case TCL_STDOUT:
	targetFd = 1;
	direction = TCL_WRITABLE;
	break;
    case TCL_STDERR:
	targetFd = 2;
	direction = TCL_WRITABLE;
	break;
    }
    if (fd < 0) {
	Tcl_Channel channel;

	channel = Tcl_GetStdChannel(type);
	if (channel) {
	    fd = GetFdFromChannel(channel, direction);
	}
    }
    if (fd >= 0) {
	if (fd != targetFd) {
	    if (dup2(fd, targetFd) == -1) {
		return 0;
	    }
	    /*
             * Must clear the close-on-exec flag for the target FD, since some
             * systems (e.g. Ultrix) do not clear the CLOEXEC flag on the
             * target FD.
             */

	    fcntl(targetFd, F_SETFD, 0);
	} else {
	    /*
	     * Since we aren't dup'ing the file, we need to explicitly clear
	     * the close-on-exec flag.
	     */
	    fcntl(fd, F_SETFD, 0);
	}
    } else {
	close(targetFd);
    }
    return 1;
}
Exemplo n.º 2
0
/* Disambiguating from multiple types, to the child types we need; in a single place */
static int GetFdFromUnknown(JNIEnv *env, jobject obj)
{
  if( IsInstanceOf(env, obj, "java/io/FileDescriptor") )
    return GetFdFromFileDescriptor(env, obj);
  else if( IsInstanceOf(env, obj, "java/nio/channels/spi/AbstractSelectableChannel") )
    return GetFdFromChannel(env, obj);
  else if( IsInstanceOf(env, obj, "java/net/DatagramSocket") )
    return GetFdFromObject(env, obj, "()Ljava/net/DatagramSocketImpl;",
                             "()Ljava/nio/channels/DatagramChannel;");
  else if( IsInstanceOf(env, obj, "java/net/Socket") )
    return GetFdFromObject(env, obj, "()Ljava/net/SocketImpl;",
                             "()Ljava/nio/channels/SocketChannel;");
  else if( IsInstanceOf(env, obj, "java/net/ServerSocket") )
    return GetFdFromObject(env, obj, "()Ljava/net/SocketImpl;",
                             "()Ljava/nio/channels/ServerSocketChannel;");
  /* Can add more socket types here as needed */
  return -EINVAL;
}
Exemplo n.º 3
0
static int GetFdFromObject(JNIEnv *env, jobject obj, char const *implType,
                           char const *channelType)
{
  jobject impl;
  jobject desc;
  jint fd;

  /* Prefer getChannel as getImpl can implicitly create a new socket */
  impl = RunMethodOnObject(env, obj, "getChannel", channelType);
  fd = GetFdFromChannel(env, impl);
  if ( fd < 0 ) {
    /* Channel method has failed, fall back to getImpl */
    impl = RunMethodOnObject(env, obj, "getImpl", implType);
    desc = RunMethodOnObject(env, impl, "getFileDescriptor",
                             "()Ljava/io/FileDescriptor;");
    fd = GetFdFromFileDescriptor(env, desc);
  }
  return fd;
}
Exemplo n.º 4
0
static int
FileForRedirect(
    Tcl_Interp *interp,		/* Intepreter to use for error reporting. */
    char *spec,			/* Points to character just after redirection
				 * character. */
    char *arg,			/* Pointer to entire argument containing spec:
				 * used for error reporting. */
    int atOK,			/* Non-zero means that '@' notation can be
				 * used to specify a channel, zero means that
				 * it isn't. */
    char *nextArg,		/* Next argument in argc/argv array, if needed
				 * for file name or channel name.  May be
				 * NULL. */
    int flags,			/* Flags to use for opening file or to specify
				 * mode for channel. */
    int *skipPtr,		/* (out) Filled with 1 if redirection target
				 * was in spec, 2 if it was in nextArg. */
    int *closePtr)		/* (out) Filled with one if the caller should
				 * close the file when done with it, zero
				 * otherwise. */
{
    int writing = (flags & O_WRONLY);
    int fd;

    *skipPtr = 1;
    if ((atOK != 0) && (*spec == '@')) {
	int direction;
	Tcl_Channel chan;

	spec++;
	if (*spec == '\0') {
	    spec = nextArg;
	    if (spec == NULL) {
		goto badLastArg;
	    }
	    *skipPtr = 2;
	}
	chan = Tcl_GetChannel(interp, spec, NULL);
	if (chan == NULL) {
	    return -1;
	}
	direction = (writing) ? TCL_WRITABLE : TCL_READABLE;
	fd = GetFdFromChannel(chan, direction);
	if (fd < 0) {
	    Tcl_AppendResult(interp, "channel \"", Tcl_GetChannelName(chan),
		"\" wasn't opened for ",
		((writing) ? "writing" : "reading"), (char *)NULL);
	    return -1;
	}
	if (writing) {
	    /*
	     * Be sure to flush output to the file, so that anything
	     * written by the child appears after stuff we've already
	     * written.
	     */
	    Tcl_Flush(chan);
	}
    } else {
	char *name;
	Tcl_DString nameString;

	if (*spec == '\0') {
	    spec = nextArg;
	    if (spec == NULL) {
		goto badLastArg;
	    }
	    *skipPtr = 2;
	}
	name = Tcl_TranslateFileName(interp, spec, &nameString);

	if (name != NULL) {
	    fd = OpenFile(name, flags);
	} else {
	    fd = -1;
	}
	Tcl_DStringFree(&nameString);
	if (fd < 0) {
	    Tcl_AppendResult(interp, "can't ",
		((writing) ? "write" : "read"), " file \"", spec, "\": ",
		Tcl_PosixError(interp), (char *)NULL);
	    return -1;
	}
	*closePtr = TRUE;
    }
    return fd;

  badLastArg:
    Tcl_AppendResult(interp, "can't specify \"", arg,
	"\" as last word in command", (char *)NULL);
    return -1;
}