Иногда бывают такие ситуации, когда у нас есть доступ к СУБД, но нет доступа к операционной системе. А он нужен вот прям позарез, перенести какие-нибудь файлы или посмотреть структуру каталогов, например.
В такой ситуации на помощь может прийти хранимая процедура на Java.
В этой статье все действия выполняются от имени пользователя SYS. Если хотите повторить действия из под другого пользователя необходимо добавить ему разрешения:
begin
dbms_java.grant_permission(‘MYUSER’, ‘SYS:java.lang.RuntimePermission’, ‘writeFileDescriptor’, »);
dbms_java.grant_permission(‘MYUSER’, ‘SYS:java.lang.RuntimePermission’, ‘readFileDescriptor’, »);
dbms_java.grant_permission(‘MYUSER’, ‘SYS:java.io.FilePermission’, ‘/bin/sh’, ‘execute’);
end;
Для начала необходимо скомпилировать основной класс на Java:
create or replace and compile java source named host as import java.io.*; public class Host { public static String executeCommand(String command) { String buff = null; String tmp =""; try { String[] finalCommand; if (System.getProperty("os.name").toLowerCase().indexOf("windows") != -1) { finalCommand = new String[4]; finalCommand[0] = "C:\\winnt\\system32\\cmd.exe"; finalCommand[1] = "/y"; finalCommand[2] = "/c"; finalCommand[3] = command; } else { // Linux or Unix System finalCommand = new String[3]; finalCommand[0] = "/bin/sh"; //finalCommand[0] = ""; finalCommand[1] = "-c"; finalCommand[2] = command; } // Execute the command... final Process pr = Runtime.getRuntime().exec(finalCommand); // Capture output from STDOUT... BufferedReader br_in = null; try { br_in = new BufferedReader(new InputStreamReader(pr.getInputStream())); tmp =tmp+"STDOUT: "+"\n"; while ((buff = br_in.readLine()) != null) { //System.out.println("stdout: " + buff); tmp=tmp+buff+"\n"; try {Thread.sleep(100); } catch(Exception e) {} } br_in.close(); } catch (IOException ioe) { //System.out.println("Error printing process output."); tmp =tmp+ "Error printing process output."+"\n"; //ioe.printStackTrace(); } finally { try { br_in.close(); } catch (Exception ex) {} } // Capture output from STDERR... BufferedReader br_err = null; try { br_err = new BufferedReader(new InputStreamReader(pr.getErrorStream())); tmp =tmp+"\n"+"STDERR: "+"\n"; while ((buff = br_err.readLine()) != null) { //System.out.println("stderr: " + buff); tmp=tmp+buff+"\n"; try {Thread.sleep(100); } catch(Exception e) {} } br_err.close(); return tmp; } catch (IOException ioe) { //System.out.println("Error printing execution errors."); tmp =tmp+ "Error printing execution errors."+"\n"; //ioe.printStackTrace(); } finally { try { br_err.close(); } catch (Exception ex) {} } } catch (Exception ex) { tmp =tmp+ ex.getLocalizedMessage()+"\n"; } return tmp; } };
После этого необходимо развернуть обертку к нему на PL/SQL:
create or replace function host (p_command IN VARCHAR2) return varchar2 AS LANGUAGE JAVA NAME 'Host.executeCommand (java.lang.String) return String';
После чего можно приступать к выполнению команд на уровне ОС, например ls:
begin dbms_output.put_line(host('/bin/ls /opt')); end;