From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11284 invoked by alias); 21 May 2008 18:41:58 -0000 Received: (qmail 11258 invoked by uid 367); 21 May 2008 18:41:57 -0000 Date: Wed, 21 May 2008 18:41:00 -0000 Message-ID: <20080521184157.11243.qmail@sourceware.org> From: cagney@sourceware.org To: frysk-cvs@sourceware.org Subject: [SCM] master: Prototype jni/PseudoTerminal. X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: ac46ba63440998b66f7038c8fe0efad8036186ff X-Git-Newrev: bca04cf8014a6ab4995b3af8abef6e2bf0d5a797 Mailing-List: contact frysk-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: frysk-cvs-owner@sourceware.org Reply-To: frysk@sourceware.org X-SW-Source: 2008-q2/txt/msg00261.txt.bz2 The branch, master has been updated via bca04cf8014a6ab4995b3af8abef6e2bf0d5a797 (commit) via 68963650f864c770ab27f1f8caae53f07c33c974 (commit) from ac46ba63440998b66f7038c8fe0efad8036186ff (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email. - Log ----------------------------------------------------------------- commit bca04cf8014a6ab4995b3af8abef6e2bf0d5a797 Author: Andrew Cagney Date: Wed May 21 14:40:14 2008 -0400 Prototype jni/PseudoTerminal. frysk-sys/frysk/sys/ChangeLog 2008-05-21 Andrew Cagney * cni/Fork.cxx (class redirect_stdio): Fix typo out->err. * jni/PseudoTerminal.cxx: Implement. * jni/Fork.hxx: New. * jni/Fork.cxx: Merge in cni/Fork.cxx changes. commit 68963650f864c770ab27f1f8caae53f07c33c974 Author: Andrew Cagney Date: Tue May 20 21:24:08 2008 -0400 Re-implement PseudoTerminal using Fork. frysk-sys/frysk/sys/ChangeLog 2008-05-20 Andrew Cagney * cni/PseudoTerminal.cxx (PseudoTerminal::child): Implement. (PseudoTerminal::daemon): Implement. * cni/Fork.hxx: New. * PseudoTerminal.java (RedirectStdio): Delete. (addChild, addDaemon): Implement as natives. * cni/Fork.cxx (spawn): New. ----------------------------------------------------------------------- Summary of changes: frysk-sys/frysk/sys/ChangeLog | 12 ++ frysk-sys/frysk/sys/PseudoTerminal.java | 36 +---- frysk-sys/frysk/sys/cni/Fork.cxx | 127 +++++++--------- .../sys/{jni/PseudoTerminal.cxx => cni/Fork.hxx} | 72 +++++++--- frysk-sys/frysk/sys/cni/PseudoTerminal.cxx | 140 ++++++++++------- frysk-sys/frysk/sys/jni/Fork.cxx | 159 +++++++++----------- .../frysk/sys/jni/{PseudoTerminal.cxx => Fork.hxx} | 79 ++++++++--- frysk-sys/frysk/sys/jni/PseudoTerminal.cxx | 138 ++++++++++++++++- 8 files changed, 474 insertions(+), 289 deletions(-) copy frysk-sys/frysk/sys/{jni/PseudoTerminal.cxx => cni/Fork.hxx} (64%) copy frysk-sys/frysk/sys/jni/{PseudoTerminal.cxx => Fork.hxx} (58%) First 500 lines of diff: diff --git a/frysk-sys/frysk/sys/ChangeLog b/frysk-sys/frysk/sys/ChangeLog index c6f46b9..4a39196 100644 --- a/frysk-sys/frysk/sys/ChangeLog +++ b/frysk-sys/frysk/sys/ChangeLog @@ -1,10 +1,22 @@ 2008-05-21 Andrew Cagney + * cni/Fork.cxx (class redirect_stdio): Fix typo out->err. + * jni/PseudoTerminal.cxx: Implement. + * jni/Fork.hxx: New. + * jni/Fork.cxx: Merge in cni/Fork.cxx changes. + * jni/Fork.cxx (spawn): Use elements(), not .p. * jni/Signal.cxx-sh (frysk): Ditto. 2008-05-20 Andrew Cagney + * cni/PseudoTerminal.cxx (PseudoTerminal::child): Implement. + (PseudoTerminal::daemon): Implement. + * cni/Fork.hxx: New. + * PseudoTerminal.java (RedirectStdio): Delete. + (addChild, addDaemon): Implement as natives. + * cni/Fork.cxx (spawn): New. + * jni/Signal.cxx-sh: Don't leak JNI string pointers. * jni/DaemonFactory.cxx: Implement. diff --git a/frysk-sys/frysk/sys/PseudoTerminal.java b/frysk-sys/frysk/sys/PseudoTerminal.java index d53457b..8f3262d 100755 --- a/frysk-sys/frysk/sys/PseudoTerminal.java +++ b/frysk-sys/frysk/sys/PseudoTerminal.java @@ -77,51 +77,25 @@ public class PseudoTerminal extends FileDescriptor { /** * Return the path of the pseudo-terminal's slave. */ - public File getFile () - { + public File getFile() { return file; } /** - * Redirect stdin, stdout, and stderr to this PseudoTerminal. - * - * The file descriptors are created in the parent process so that - * child does not need to run the risk of running out of - * descriptors et.al. and recover from that. - */ - static private class RedirectStdio - extends Redirect - { - protected final String name; - RedirectStdio (String name) - { - this.name = name; - } - /** - * Execute in context of child. - */ - public native void reopen (); - /** - * Executed in context of parent. - */ - public void close () - { - } - } - - /** * Convenience method, adds a child process bound to this * pseudo-terminal. */ public ProcessIdentifier addChild(String[] args) { - return ChildFactory.create(new RedirectStdio (name), new Exec (args)); + return ProcessIdentifierFactory.create(child(args[0], args, name)); } + private static native int child(String exe, String[] args, String name); /** * Convenience method, adds a daemon process bound to this * pseudo-terminal. */ public ProcessIdentifier addDaemon(String[] args) { - return DaemonFactory.create(new RedirectStdio (name), new Exec (args)); + return ProcessIdentifierFactory.create(daemon(args[0], args, name)); } + private static native int daemon(String exe, String[] args, String name); } diff --git a/frysk-sys/frysk/sys/cni/Fork.cxx b/frysk-sys/frysk/sys/cni/Fork.cxx index 74db54c..d8806e2 100644 --- a/frysk-sys/frysk/sys/cni/Fork.cxx +++ b/frysk-sys/frysk/sys/cni/Fork.cxx @@ -49,38 +49,15 @@ #include "java/io/File.h" #include "frysk/sys/Fork.h" #include "frysk/sys/cni/Errno.hxx" - +#include "frysk/sys/cni/Fork.hxx" #include "frysk/sys/ProcessIdentifier.h" #include "frysk/sys/ProcessIdentifierFactory.h" -enum tracing { - DAEMON, - NO_TRACE, - PTRACE, - UTRACE, -}; - -static void -reopen(const char* file, const char* mode, FILE *stream) { - if (file == NULL) - return; - errno = 0; - ::freopen(file, mode, stream); - if (errno != 0) { - // Should not happen! - ::perror("freopen"); - ::_exit(errno); - } -} - /** - * Spawn a child, return the PID or the -ERROR. + * Spawn a child, return the PID or throw the error. */ -static int -spawn(const char* exePath, - const char* inPath, const char* outPath, const char* errPath, - int argc, char** argv, char** environ, tracing trace) { - +int +spawn(tracing trace, redirect& redirection, exec& execute) { if (trace == DAEMON) { // Do a vfork(), fork(), exec() which lets the top level process // capture the middle level fork()'s return value in a volatile. @@ -92,22 +69,24 @@ spawn(const char* exePath, case 0: // This is executed by the child with the parent blocked, the // final process id ends up in PID. - pid = ::spawn(exePath, inPath, outPath, errPath, argc, argv, 0, NO_TRACE); + pid = ::spawn(CHILD, redirection, execute); _exit (0); case -1: // This is executed after a vfork barfs. - return -errno; + throwErrno(errno, "vfork"); default: // This is executed after the child has set PID with a FORK and // then exited (which helps guarentee that the waitpid, below, // doesn't block. - if (pid < 0) - return -errno; + if (pid < 0) { + throwErrno(errno, "vfork/fork"); + } // Consume the middle players wait. int status; errno = 0; - if (waitpid (v, &status, 0) < 0) - return -errno; + if (waitpid(v, &status, 0) < 0) { + throwErrno(errno, "waitpid"); + } return pid; } } @@ -117,7 +96,7 @@ spawn(const char* exePath, pid_t pid = fork (); switch (pid) { case -1: // Fork failed. - return -errno; + throwErrno(errno, "fork"); default: // Parent return pid; case 0: // Child @@ -126,9 +105,7 @@ spawn(const char* exePath, sigfillset(&mask); ::sigprocmask(SIG_UNBLOCK, &mask, NULL); // Redirect stdio. - reopen(inPath, "r", stdin); - reopen(outPath, "w", stdout); - reopen(errPath, "w", stderr); + redirection.reopen(); switch (trace) { case PTRACE: errno = 0; @@ -141,21 +118,50 @@ spawn(const char* exePath, case UTRACE: fprintf(stderr, "\n\n>>>>> in spawn(...utrace)\n\n"); break; - case NO_TRACE: + case CHILD: break; case DAEMON: break; } - if (environ != NULL) { - ::execve(exePath, argv, environ); - } else - ::execv(exePath, argv); - // This should not happen. - ::perror("execvp"); - ::_exit (errno); + execute.execute(); + ::_exit(errno); } } +class redirect_stdio : public redirect { +private: + void reopen(const char* file, const char* mode, FILE *stream) { + if (file == NULL) + return; + errno = 0; + ::freopen(file, mode, stream); + if (errno != 0) { + // Should not happen! + ::perror("freopen"); + ::_exit(errno); + } + } + char* in; + char* out; + char* err; +public: + redirect_stdio(jstring in, jstring out, jstring err) { + this->in = MALLOC_STRING(in); + this->out = MALLOC_STRING(out); + this->err = MALLOC_STRING(err); + } + void reopen() { + reopen(in, "r", stdin); + reopen(out, "w", stdout); + reopen(err, "w", stderr); + } + ~redirect_stdio() { + JvFree(in); + JvFree(out); + JvFree(err); + } +}; + /** * Convert convert to native and then spawn. */ @@ -163,39 +169,16 @@ static int spawn(java::io::File* exe, jstring in, jstring out, jstring err, jstringArray args, jlong environ, tracing trace) { - char* exePath = MALLOC_STRING(exe->getPath()); - char* inPath = MALLOC_STRING(in); - char* outPath = MALLOC_STRING(out); - char* errPath = MALLOC_STRING(err); - int argc = args->length; - char** argv = MALLOC_ARGV(args); - int pid = ::spawn(exePath, inPath, outPath, errPath, - argc, argv, (char**)environ, trace); - JvFree(exePath); - JvFree(inPath); - JvFree(outPath); - JvFree(errPath); - JvFree(argv); - if (pid < 0) { - switch (trace) { - case NO_TRACE: - throwErrno(-pid, "fork/exec"); - case DAEMON: - throwErrno(-pid, "vfork/wait"); - case PTRACE: - throwErrno(-pid, "fork/ptrace/exec"); - case UTRACE: - throwErrno(-pid, "utrace"); - } - } - return pid; + redirect_stdio io = redirect_stdio(in, out, err); + exec_program program = exec_program(exe->getPath(), args, environ); + return ::spawn(trace, io, program); } jint frysk::sys::Fork::spawn(java::io::File* exe, jstring in, jstring out, jstring err, jstringArray args, jlong environ) { - return ::spawn(exe, in, out, err, args, environ, NO_TRACE); + return ::spawn(exe, in, out, err, args, environ, CHILD); } jint diff --git a/frysk-sys/frysk/sys/jni/PseudoTerminal.cxx b/frysk-sys/frysk/sys/cni/Fork.hxx similarity index 64% copy from frysk-sys/frysk/sys/jni/PseudoTerminal.cxx copy to frysk-sys/frysk/sys/cni/Fork.hxx index 2ae7e72..11137d8 100644 --- a/frysk-sys/frysk/sys/jni/PseudoTerminal.cxx +++ b/frysk-sys/frysk/sys/cni/Fork.hxx @@ -1,6 +1,6 @@ // This file is part of the program FRYSK. // -// Copyright 2008, Red Hat Inc. +// Copyright 2005, 2007, 2008, Red Hat Inc. // // FRYSK is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by @@ -37,24 +37,60 @@ // version and license this file solely under the GPL without // exception. -#include -#include +enum tracing { + CHILD, + DAEMON, + PTRACE, + UTRACE, +}; -#include "jni.hxx" +/** + * Class to redirect a child's stdio; the destructor should clean up + * the parent resources. + */ +class redirect { +public: + virtual void reopen() = 0; + virtual ~redirect() { + // where the close code goes. + } +}; -#include "jnixx/exceptions.hxx" +class exec { +public: + virtual void execute() = 0; + virtual ~exec() { + // where the close code goes. + } +}; -using namespace java::lang; +class exec_program : public exec { + char* exePath; + char** argv; + char** environ; +public: + exec_program(jstring exe, jstringArray args, jlong environ) { + this->exePath = MALLOC_STRING(exe); + this->argv = MALLOC_ARGV(args); + this->environ = (char**)(long)environ; + } + void execute() { + if (environ != NULL) { + ::execve(exePath, argv, environ); + ::perror("execve"); + } else { + ::execv(exePath, argv); + ::perror("execv"); + } + ::_exit(errno); + } + ~exec_program() { + JvFree(exePath); + JvFree(argv); + } +}; -::String -frysk::sys::PseudoTerminal::getName(::jnixx::env env, jint pty) { - const char *name = ::ptsname(pty); - if (name == NULL) - errnoException(env, errno, "ptsname"); - return String::NewStringUTF(env, name); -} - -jint -frysk::sys::PseudoTerminal::open(::jnixx::env env, bool) { - return -1; -} +/** + * Spawn a child, return the PID, or throw an error. + */ +extern int spawn(tracing trace, redirect& redirection, exec& execute); diff --git a/frysk-sys/frysk/sys/cni/PseudoTerminal.cxx b/frysk-sys/frysk/sys/cni/PseudoTerminal.cxx index 7d17563..63ec20b 100755 --- a/frysk-sys/frysk/sys/cni/PseudoTerminal.cxx +++ b/frysk-sys/frysk/sys/cni/PseudoTerminal.cxx @@ -48,13 +48,13 @@ #include +#include "frysk/sys/cni/Errno.hxx" +#include "frysk/sys/cni/Fork.hxx" #include "frysk/sys/PseudoTerminal.h" #include "frysk/sys/PseudoTerminal$RedirectStdio.h" -#include "frysk/sys/cni/Errno.hxx" jint -frysk::sys::PseudoTerminal::open (jboolean controllingTerminal) -{ +frysk::sys::PseudoTerminal::open(jboolean controllingTerminal) { int master; int flags = O_RDWR | (controllingTerminal ? O_NOCTTY : 0); @@ -80,73 +80,99 @@ frysk::sys::PseudoTerminal::open (jboolean controllingTerminal) } jstring -frysk::sys::PseudoTerminal::getName(jint fd) -{ +frysk::sys::PseudoTerminal::getName(jint fd) { char* pts_name = ::ptsname(fd); if (pts_name == NULL) throwErrno (errno, "ptsname"); return JvNewStringUTF (pts_name); } -void -frysk::sys::PseudoTerminal$RedirectStdio::reopen () -{ - // Detach from the existing controlling terminal. NOTE: Do not use - // tryOpen() here, this is running in a child process. - int fd = ::open ("/dev/tty", O_RDWR|O_NOCTTY); // ::open ok - if (fd >= 0) { - if (::ioctl (fd, TIOCNOTTY, NULL) < 0) - ::perror ("ioctl (/dev/tty, TIOCNOTTY)"); - ::close (fd); - - // Verify that the detach worked, this open should fail. NOTE: Do - // not use tryOpen() here, this is running in a child process. - fd = ::open ("/dev/tty", O_RDWR|O_NOCTTY); // ::open ok +class redirect_tty : public redirect { + char* pty; +public: + redirect_tty(jstring name) { + pty = MALLOC_STRING(name); + } + ~redirect_tty() { + JvFree(pty); + } + void reopen() { + // Detach from the existing controlling terminal. NOTE: Do not + // use tryOpen() here, this is running in a child process. + int fd = ::open ("/dev/tty", O_RDWR|O_NOCTTY); // ::open ok if (fd >= 0) { - ::perror ("open (re-open old controlling terminal)"); - ::exit (1); + if (::ioctl (fd, TIOCNOTTY, NULL) < 0) + ::perror ("ioctl (/dev/tty, TIOCNOTTY)"); + ::close (fd); + + // Verify that the detach worked, this open should fail. NOTE: + // Do not use tryOpen() here, this is running in a child + // process. + fd = ::open ("/dev/tty", O_RDWR|O_NOCTTY); // ::open ok + if (fd >= 0) { + ::perror ("open (re-open old controlling terminal)"); + ::exit (1); + } } - } - // Make this process the session leader. - if (::setsid () < 0) { - ::perror ("setsid"); - } + // Make this process the session leader. + if (::setsid () < 0) { + ::perror ("setsid"); + } - if (::getpgrp () != ::getpid ()) { - perror ("grp and pid differ"); - exit (1); - } + if (::getpgrp () != ::getpid ()) { + perror ("grp and pid differ"); + exit (1); + } -// // Move this to the session's process group. -// if (::setpgid (0, getpid ()) < 0) { -// perror ("setpgrp"); -// } - - // Open the new pty. - char *pty = ALLOCA_STRING (name); - int tty = open (pty, O_RDWR|O_NOCTTY); - if (tty < 0) { - perror ("open.pty"); - exit (1); - } + // // Move this to the session's process group. + // if (::setpgid (0, getpid ()) < 0) { + // perror ("setpgrp"); + // } - // Make the pty's tty the new controlling terminal. - if (::ioctl (tty, TIOCSCTTY, NULL) < 0) { - ::perror ("ioctl.TIOSCTTY"); - exit (1); hooks/post-receive -- frysk system monitor/debugger