001 /*
002 * LAPIS lightweight structured text processing system
003 *
004 * Copyright (C) 1998-2002 Carnegie Mellon University,
005 * Copyright (C) 2003 Massachusetts Institute of Technology.
006 * All rights reserved.
007 *
008 * This library is free software; you can redistribute it
009 * and/or modify it under the terms of the GNU General
010 * Public License as published by the Free Software
011 * Foundation, version 2.
012 *
013 * LAPIS homepage: http://graphics.lcs.mit.edu/lapis/
014 */
015
016
017 package lapisx.util;
018
019 import java.io.*;
020
021 public abstract class Exec {
022 public static Debug debug = Debug.QUIET;
023
024 public static Process exec (String[] cmdarray) throws IOException {
025 return exec (cmdarray, null, null);
026 }
027
028 public static Process exec (String[] cmdarray, String[] envp) throws IOException {
029 return exec (cmdarray, envp, null);
030 }
031
032 public static Process exec (String[] cmdarray, String[] envp, File directory) throws IOException {
033 return
034 isWindows ()
035 ? execWindows (cmdarray, envp, directory)
036 : execUnix (cmdarray, envp, directory);
037 }
038
039 /*
040 * Unix
041 */
042
043 static Process execUnix (String[] cmdarray, String[] envp, File directory) throws IOException {
044 // instead of calling command directly, we'll call the shell to change
045 // directory and set environment variables.
046
047 // start constructing the sh command line.
048 StringBuffer buf = new StringBuffer ();
049
050 if (directory != null) {
051 // change to directory
052 buf.append ("cd '");
053 buf.append (escapeQuote (directory.toString ()));
054 buf.append ("'; ");
055 }
056
057 if (envp != null) {
058 // set environment variables. Quote the value (but not the name).
059 for (int i = 0; i < envp.length; ++i) {
060 String nameval = envp[i];
061 int equals = nameval.indexOf ('=');
062 if (equals == -1)
063 throw new IOException ("environment variable '" + nameval
064 + "' should have form NAME=VALUE");
065 buf.append (nameval.substring (0, equals+1));
066 buf.append ('\'');
067 buf.append (escapeQuote (nameval.substring (equals+1)));
068 buf.append ("\' ");
069 }
070 }
071
072 // now that we have the directory and environment, run "which"
073 // to test if the command name is found somewhere in the path.
074 // If "which" fails, throw an IOException.
075 String cmdname = escapeQuote (cmdarray[0]);
076 Runtime rt = Runtime.getRuntime ();
077 String[] sharray = new String[] { "sh", "-c", buf.toString () + " which \'" + cmdname + "\'" };
078 Process which = rt.exec (sharray);
079 try {
080 which.waitFor ();
081 } catch (InterruptedException e) {
082 throw new IOException ("interrupted");
083 }
084
085 if (which.exitValue () != 0)
086 throw new IOException ("can't execute " + cmdname + ": bad command or filename");
087
088 // finish in
089 buf.append ("exec \'");
090 buf.append (cmdname);
091 buf.append ("\' ");
092
093 // quote each argument in the command
094 for (int i = 1; i < cmdarray.length; ++i) {
095 buf.append ('\'');
096 buf.append (escapeQuote (cmdarray[i]));
097 buf.append ("\' ");
098 }
099
100 debug.println ("executing " + buf);
101 sharray[2] = buf.toString ();
102 return rt.exec (sharray);
103 }
104
105 static String escapeQuote (String s) {
106 // replace single quotes with a bit of magic (end-quote, escaped-quote, start-quote)
107 // that works in a single-quoted string in the Unix shell
108 if (s.indexOf ('\'') != -1) {
109 debug.println ("replacing single-quotes in " + s);
110 s = Str.replace (s, "'", "'\\''");
111 debug.println ("to get " + s);
112 }
113 return s;
114 }
115
116 /*
117 * Windows
118 */
119
120 static boolean isWindows () {
121 String os = System.getProperty ("os.name");
122 return (os != null && os.startsWith ("Windows"));
123 }
124
125 static boolean isJview () {
126 String vendor = System.getProperty ("java.vendor");
127 return (vendor != null && vendor.startsWith ("Microsoft"));
128 }
129
130 static Process execWindows (String[] cmdarray, String[] envp, File directory) throws IOException {
131 if (envp != null || directory != null) {
132 if (isJview ())
133 // jview doesn't support JNI, so can't call putenv/chdir
134 throw new IOException
135 ("can't use Exec.exec() under Microsoft JVM");
136
137 if (!linked) {
138 try {
139 debug.println ("loading win32exec");
140 System.loadLibrary ("win32exec");
141 linked = true;
142 } catch (LinkageError e) {
143 throw new IOException ("can't use Exec.exec(): "
144 + e.getMessage ());
145 }
146 }
147
148 if (envp != null) {
149 for (int i = 0; i < envp.length; ++i)
150 putenv (envp[i]);
151 }
152
153 if (directory != null)
154 chdir (directory.toString ());
155 }
156
157 return Runtime.getRuntime ().exec (cmdarray);
158 }
159
160 static boolean linked = false; // true after System.loadLibrary() is called
161 static native boolean putenv (String env);
162 static native boolean chdir (String dir);
163 }