3

This question is related to: How to execute a windows command from firefox addon?

I am developing an addon for thunderbird/firefox. Basically, I want to run an executable and get the stdout of this executable. To do so, the answer of the above stackoverflow post indicates, it is necessary to pipe the output of the program to an tmp file, which may be read in the end of the execution.

To run an external command I had a look at https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIProcess. At the end there's a little example which I adopted to run any program with arguments.

To create the tmp file I knock this code from different sources:

// create a new tmp file
var ds = Components.classes["@mozilla.org/file/directory_service;1"].getService();
var dsprops = ds.QueryInterface(Components.interfaces.nsIProperties);
var tmpFile = dsprops.get("TmpD", Components.interfaces.nsIFile);
tmpFile.append("Query.tmp");
tmpFile.createUnique(tmpFile.NORMAL_FILE_TYPE, 0600);

To pipe the output of the executing file to the tmpfile, I append a pipe to the arguments to run:

args.push("> " + tmpFile.path);

And in the end I read the whole file content with the function readFile, which don't seem to be the problem.

In total the code looks like this until now:

// read the content of a file
function readFile(file) {
    var ioServ = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
    var fileURI = ioServ.newFileURI(file);
    var fileChannel = ioServ.newChannel(fileURI.asciiSpec, null, null);
    var rawInStream = fileChannel.open();
    var scriptableInStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
    scriptableInStream.init(rawInStream);
    var available = scriptableInStream.available();
    var fileContents = scriptableInStream.read(available);
    scriptableInStream.close();
}

// run an external command from inside an addon
function runCMD(cmd, args) {
    // see: https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIProcess
    // create an nsIFile for the executable
    var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile);
    file.initWithPath(cmd);
    // create an nsIProcess
    var process = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
    process.init(file);
    // create a new tmp file
    var ds = Components.classes["@mozilla.org/file/directory_service;1"].getService();
    var dsprops = ds.QueryInterface(Components.interfaces.nsIProperties);
    var tmpFile = dsprops.get("TmpD", Components.interfaces.nsIFile);
    tmpFile.append("Query.tmp");
    tmpFile.createUnique(tmpFile.NORMAL_FILE_TYPE, 0600);
    // append the tmp file to the parameters
    args.push("> " + tmpFile.path);
    // Run the process.
    // If first param is true, calling thread will be blocked until called process terminates.
    // Second and third params are used to pass command-line arguments to the process.
    process.run(true, args, args.length);
    // ok, now get the content of the tmp file
    if (tmpFile.exists()) {
        var outStr = readFile(tmpFile);
        tmpFile.remove(false);
        return outStr;
    }
    return null
}

However I keep getting an empty line, while executing

runCMD("/usr/bin/env", ["echo", "foobar"]);

any ideas?

Community
  • 1
  • 1
quant
  • 2,184
  • 2
  • 19
  • 29
  • Have you checked what the value of `args` is just before `process.run()` ? – Uli Köhler Jan 29 '14 at 22:06
  • adding alert(args) before the executing step, will result in echo,foobar,> /tmp/Query.tmp which seems totally legal to me. – quant Jan 29 '14 at 22:10
  • 1
    Have you any reasons to assume that runCMD executes via a shell and not via `system()` ? Because only shells understand the `>` operator. – Uli Köhler Jan 29 '14 at 22:43
  • 1
    In other words, try `bash -c 'youroriginalcommand'` instead of executing it directly. – Uli Köhler Jan 29 '14 at 22:46
  • Hmm, this solution would have the drawnback, that it would not run under anything else than Linux. As well as runCMD("/usr/bin/env", ["bash", "-c", "echo", "foobar"]); still don't work. – quant Jan 29 '14 at 22:49
  • `/usr/bin/env` also only runs under Linux. You need to use `runCMD("/bin/bash", ["-c", "echo foobar > /tmp/barfoo"]);` – Uli Köhler Jan 29 '14 at 23:09
  • @UliKöhler what should be the difference between runCMD("/usr/bin/env", ["bash", "-c", "echo", "foobar"]); and runCMD("/bin/bash", ["-c", "echo foobar > /tmp/barfoo"]); in the case, that bash is located at /bin/bash? env then calls bash – quant Jan 29 '14 at 23:15
  • 1
    `bash -c` only takes one argument. `/bin/bash` should be OK IMO, see LSB standard. – Uli Köhler Jan 29 '14 at 23:52

0 Answers0