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 }