001: /*
002: * Copyright (c) 1998-2002 Carnegie Mellon University. All rights
003: * reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * 2. Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in
014: * the documentation and/or other materials provided with the
015: * distribution.
016: *
017: * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
018: * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
019: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
020: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
021: * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
022: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
023: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
024: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
025: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
027: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: *
029: */
030:
031: package rcm.util;
032:
033: import java.io.*;
034:
035: public abstract class Exec {
036: public static Debug debug = Debug.QUIET;
037:
038: public static Process exec(String[] cmdarray) throws IOException {
039: return exec(cmdarray, null, null);
040: }
041:
042: public static Process exec(String[] cmdarray, String[] envp)
043: throws IOException {
044: return exec(cmdarray, envp, null);
045: }
046:
047: public static Process exec(String[] cmdarray, String[] envp,
048: File directory) throws IOException {
049: return isWindows() ? execWindows(cmdarray, envp, directory)
050: : execUnix(cmdarray, envp, directory);
051: }
052:
053: /*
054: * Unix
055: */
056:
057: static Process execUnix(String[] cmdarray, String[] envp,
058: File directory) throws IOException {
059: // instead of calling command directly, we'll call the shell to change
060: // directory and set environment variables.
061:
062: // start constructing the sh command line.
063: StringBuffer buf = new StringBuffer();
064:
065: if (directory != null) {
066: // change to directory
067: buf.append("cd '");
068: buf.append(escapeQuote(directory.toString()));
069: buf.append("'; ");
070: }
071:
072: if (envp != null) {
073: // set environment variables. Quote the value (but not the name).
074: for (int i = 0; i < envp.length; ++i) {
075: String nameval = envp[i];
076: int equals = nameval.indexOf('=');
077: if (equals == -1)
078: throw new IOException("environment variable '"
079: + nameval + "' should have form NAME=VALUE");
080: buf.append(nameval.substring(0, equals + 1));
081: buf.append('\'');
082: buf.append(escapeQuote(nameval.substring(equals + 1)));
083: buf.append("\' ");
084: }
085: }
086:
087: // now that we have the directory and environment, run "which"
088: // to test if the command name is found somewhere in the path.
089: // If "which" fails, throw an IOException.
090: String cmdname = escapeQuote(cmdarray[0]);
091: Runtime rt = Runtime.getRuntime();
092: String[] sharray = new String[] { "sh", "-c",
093: buf.toString() + " which \'" + cmdname + "\'" };
094: Process which = rt.exec(sharray);
095: try {
096: which.waitFor();
097: } catch (InterruptedException e) {
098: throw new IOException("interrupted");
099: }
100:
101: if (which.exitValue() != 0)
102: throw new IOException("can't execute " + cmdname
103: + ": bad command or filename");
104:
105: // finish in
106: buf.append("exec \'");
107: buf.append(cmdname);
108: buf.append("\' ");
109:
110: // quote each argument in the command
111: for (int i = 1; i < cmdarray.length; ++i) {
112: buf.append('\'');
113: buf.append(escapeQuote(cmdarray[i]));
114: buf.append("\' ");
115: }
116:
117: debug.println("executing " + buf);
118: sharray[2] = buf.toString();
119: return rt.exec(sharray);
120: }
121:
122: static String escapeQuote(String s) {
123: // replace single quotes with a bit of magic (end-quote, escaped-quote, start-quote)
124: // that works in a single-quoted string in the Unix shell
125: if (s.indexOf('\'') != -1) {
126: debug.println("replacing single-quotes in " + s);
127: s = Str.replace(s, "'", "'\\''");
128: debug.println("to get " + s);
129: }
130: return s;
131: }
132:
133: /*
134: * Windows
135: */
136:
137: static boolean isWindows() {
138: String os = System.getProperty("os.name");
139: return (os != null && os.startsWith("Windows"));
140: }
141:
142: static boolean isJview() {
143: String vendor = System.getProperty("java.vendor");
144: return (vendor != null && vendor.startsWith("Microsoft"));
145: }
146:
147: static Process execWindows(String[] cmdarray, String[] envp,
148: File directory) throws IOException {
149: if (envp != null || directory != null) {
150: if (isJview())
151: // jview doesn't support JNI, so can't call putenv/chdir
152: throw new IOException(
153: "can't use Exec.exec() under Microsoft JVM");
154:
155: if (!linked) {
156: try {
157: System.loadLibrary("win32exec");
158: linked = true;
159: } catch (LinkageError e) {
160: throw new IOException("can't use Exec.exec(): "
161: + e.getMessage());
162: }
163: }
164:
165: if (envp != null) {
166: for (int i = 0; i < envp.length; ++i)
167: putenv(envp[i]);
168: }
169:
170: if (directory != null)
171: chdir(directory.toString());
172: }
173:
174: return Runtime.getRuntime().exec(cmdarray);
175: }
176:
177: static boolean linked = false; // true after System.loadLibrary() is called
178:
179: static native boolean putenv(String env);
180:
181: static native boolean chdir(String dir);
182: }
|