     try
         result = fn args...
     catch error
-        printError error, description
-        process.exit exitCode if exit is yes
+        return handleError error, options
 
     result
 
 # Same as attempt, but calls the function with name 'fnName' of the module shelljs
-@attemptShell = (fnName, args = [], { exit = yes, exitCode = 1, description = "" } = {}) ->
+@attemptShell = (fnName, args = [], options) ->
     assert _.isFunction(shelljs[fnName]), "Invalid shell function name" # SANITY-CHECK
 
     args = [args] unless _.isArray args
 
     result = shelljs[fnName](args...)
 
-    if (error = shelljs.error())?
-        printError error, description
-        process.exit exitCode if exit is yes
+    return handleError error, options if (error = shelljs.error())?
 
     result
 
+# Gets the Stat information of the file in path 'path'.
+# If the file was successfully read, returns the Stat object
+# If there has been an error and it is not in onError.allowedErrors array,
+# returns an object with a property error containing the error
+# If an error that was in onError.allowedErrors occurs then null is returned
+# Otherwise, the process exits
+# Note that EACCESS and ENOENT errors are allowed by default
+@getFileInfo = (path, onError = {}) =>
+    onError.description ?= "Getting #{path} info"
+    onError.allowedErrors ?= ['EACCESS', 'ENOENT']
+
+    result = @attempt lstatSync, path, onError
+    if result?.isError?
+        { error: result }
+    else
+        result
+
 # Tells whether 'that' has a modification time older than 'other'
 # Assumes arguments are Stat objects unless they're strings
+# Prints an error message and exits if either of the arguments is a string
+# And an error occured when trying to read the file information via lstatSync
 @hasLaterModificationTime = (that, other) =>
     [that, other] = [that, other].map((file) =>
         if _.isString file
-            @attempt lstatSync, file, description: "Getting #{file} info"
+            @getFileInfo file, { allowedErrors: [] }
         else
             file
     )
 
-    assert _.every([that, other], (elem) -> elem instanceof Stats) # SANITY-CHECK
+    assert _.every([that, other], (elem) -> elem instanceof Stats),
+          "Some argument is not a stat object nor a string"
 
     thatDate  = new Date(that.mtime)
     otherDate = new Date(other.mtime)
     thatDate.getTime() > otherDate.getTime()
+
+@execSync = (command, options) ->
+    options ?= {}
+    options.encoding ?= 'utf-8'
+
+    previousStderr = process.stderr.write
+    stderr = ""
+
+    process.stderr.write = (s) -> stderr += s.toString()
+
+    try
+        result = execSync command, options
+    catch error
+        process.stderr.write = previousStderr
+        throw error
+
+    process.stderr.write = previousStderr
+    { stderr, stdout: result }
+
+@isBinaryExecutable = (path) =>
+    assert _.isString(path), "Argument must be file path (string)"
+
+    fileToolOutput = @attempt(@execSync, "file #{path}").stdout.toLowerCase()
+
+    fileToolOutput.indexOf('elf') >= 0 and
+    fileToolOutput.indexOf('executable') >= 0 and
+    isExe.sync path
+
+
+
 
 # Testing Code
 ###

assert = require 'assert'
{ lstatSync, Stats } = require 'fs'
_ = require 'lodash'

logger = require './logger'
styler = require './styler'

@attemptShell('rm', [''], exit: no, description: "Remove file without path")
@attemptShell('rm', [''], exit: no)
@attemptShell('ls')
console.log @getFileInfo('/dev/null')
console.log @getFileInfo('./dawdawa', { exit: no, printError: no })
console.log @getFileInfo('./dawdawa', { exit: no, printError: no, allowedErrors: [] }).error.toString()
console.log @hasLaterModificationTime('./utils.coffee', './logger.coffee')
console.log @hasLaterModificationTime('./utils.cofee', './logger.coffee')
###
