Swift 4 launchedProcess launch path not accessible - swift

I am writing a swift based macOS app in Xcode 9 to be used on my computer (not distributed). I have EXIFtool installed (independent of the app) in /usr/local/bin and can use it successfully from the Terminal app. I am trying to access EXIFtool from my app.
My app has a button that when clicked should run the EXIFtool command by executing this script.
#IBAction func arrowClicked(_ sender: Any) {
arrow.isEnabled = false
let task = Process.launchedProcess(launchPath: "/usr/local/bin/exiftool", arguments: [rawURL])
task.waitUntilExit()
arrow.isEnabled = true
}
The script fails with a "launch path not accessible" error. It doesn't matter what I enter as the arguments (in the above snippet, rawURL is a string that contains the path to a user identified image file.
The responses I have found for similar questions here focus on the format of the path (e.g., must be the full path, begin with /, etc). My launch path comes from what Terminal gives a response to "which exiftool", so I thought it was correct.
UPDATE: I followed the link Matt provided and rewrote the code to utilize a shell script. I made the script executable and successfully ran it through Terminal and TextWrangler. But accessing it within Xcode resulted in an "operation not permitted" message.

Turning off the App Sandbox resolves both the original "launch path not accessible" message and the revised attempt's "operation not permitted" message.

There are unfortunately numerous reasons why one binary may not run inside a sandboxed environment, whilst another binary may run just fine.
In your case you were able to disable sandboxing, so that was an easy (and sensible) fix, but for anyone without that luxury, below is some information that documents some relevant factors.
There is a question here which asks why /sbin/ping runs fine, yet /usr/sbin/traceroute does not.
From one of the answers there:
ping vs. traceroute - the former is a non-priviledged program, the latter is priviledged and runs as root
You can see the difference in their permissions:
$ ls /sbin/ping
-r-xr-xr-x 1 root wheel 41K 30 May 11:36 /sbin/ping
$ ls /usr/sbin/traceroute
-r-sr-xr-x 1 root wheel 37K 30 May 11:36 /usr/sbin/traceroute
The s on the trace route means it will be executed as root, which naturally is not going to be allowed inside a sandboxed environment. The following may be helpful, from https://coderanch.com/t/110770/os/permissions-meaning#558594:
"s", for files, means "setuid exec." If a file has s permission, then it's executable, and furthermore, the user id and/or group id of the process is set to the user or group id of the owner of the file, depending on whether it's the user or group "s" that's set. This is a way to give limited root powers to a user -- a program that runs as root when an ordinary user executes it.
Somewhat beyond my comprehension, but potentially also relevant is the following Apple Technical Q&A QA1773 called Common app sandboxing issues which discusses whether a binary is a Mach-O executable:
You can check if a binary is a Mach-O executable using the file command. If any slice of the binary identifies itself as Mach-O executable or Mach-O 64-bit executable, the binary must be sandboxed.
For ping that would look like:
$ file /sbin/ping
/sbin/ping: Mach-O 64-bit executable x86_64
My take is that if the binary is a Mach-O executable and you want to run it from a sandboxed app, you are going to have to either:
compile the binary yourself from source, giving it appropriate entitlements, or
import the code into your app and compile it directly into your app

Related

Get the same PATH environment variable from a terminal command when debugging an app from Xcode?

If I debug a command line app from Xcode, I get a different $PATH than if I run the same app from a terminal session.
For example, when run from a Terminal:
$env | grep "PATH="
//output: PATH=/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin
...
From an Xcode debug session:
let environment = ProcessInfo.processInfo.environment
print(environment["PATH"] ?? "No PATH found")
//output: /Applications/Xcode.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin
As a result, some command line apps are unavailable while debugging.
How do I get the terminal window $PATH environment variable within an Xcode debugging session?
As Martin R said in his comment, the environment passed to GUI programs is different than that used by shell applications.
I never found a simple solution to the problem. I suspect that the environment paths are set either with launchctl or a default is provided to GUI apps.
Finally, I ended up changing the environment used by class Process (Swift). Though not perfect (and certainly more complicated than I'd hoped), it works. You can find the entire implementation I used at: GitHub

get user machines current working directory from perl cgi

i am trying to get the current working directory path using Perl
when i execute from ubuntu: $root#ubuntu:/var/test/geek# firefox http:/localhost/test.html, i get /var/cgi-bin as output in perl cgi page instead of /var/test/geek.
used perl code:
my $pwd=cwd();
bla bla
print "<h1> pwd </h1>";
above code gives path of test.pl not users working directory path
Edit: When i run the script alone from the terminal it works fine. for example:
$root#ubuntu:/var/test/geek# /var/cgi-bin/test.pl
i get /var/test/geek. but when i call the script in html page using submit button it gives path of perl script.
Each process has its own working directory that it inherits from its parent when it gets created.
cwd() returns the current process's working directory.
For a CGI script, the browser doesn't pass its working directory to the server as part of the request. To obtain that, you need to have code running on the client system that submits it. That might be an application that the user download, or possibly, but unlikely, some in-browser code, like Javascript / a Java applet (This info is likely hidden from in-browser code for security reasons though).
(The rest assumes Linux, it will likely differ on other operating systems)
The part below assumes that you are looking for the working directory of a user on the server:
In order to get a specific shell for a specific user's working directory, you would need to identify the PID for the shell and get the working directory from the /proc/<pid>/cwd symlink (To read these, the process must belong to the user running the code, or the code must run as root (Which is a bad idea for a CGI script)...). To get the PID of the shell, you likely need to start from the w command output, or its data source, /var/run/utmp. Sys::Utmp might be useful for this... You might then also need to retreive a whole lot of extra info to find all the processes that might have the working directory that you are looking for.
I think you are mixing the web server and the local user. The web server has a working directory when you run the script, and that is the one that cwd() returns.

Opening a file in a Metro app from command line

I need a way to open a file in a Metro app from command line.
So far I've figured out how to start the app from command line without any third-party scripts
explorer shell:AppsFolder\Microsoft.Reader_8wekyb3d8bbwe!Microsoft.Reader
but I haven't been able to figure out how to include a file name yet.
Launching
explorer shell:AppsFolder\Microsoft.Reader_8wekyb3d8bbwe!Microsoft.Reader example.pdf
just opens up a default explorer window.
Any idea from Windows 8 experts on how to accomplish this without any third-party tools/cmdlets/etc.?
Note: In fact I'm using Windows 10 but I guess if there's a Windows 8 / 8.1 way to do it, it'll work for 10, too.
If you're still looking for the answer, the best way to open a file in a metro app is to use an execution string like a normal app protocol does. The execution string looks like this:
bingnews:[arguments, can be left blank.]
microsoftvideo:[arguments, can be left blank.]
netflix:[arguments, can be left blank.]
So, to start up netflix, it's as simple as typing in Start netflix: into the command line.
To find the execution string for an app, go here: Control Panel\Programs\Default Programs\Set Associations
More info and examples can be found here.
http://windowsitpro.com/windows-8/opening-windows-8-apps-command-prompt-or-script
http://www.itsjustwhatever.com/2012/10/28/launch-windows-8-metro-apps-from-a-desktop-shortcut-or-command-line/
PLEASE NOTE: To open an app WITHOUT A PROTOCOL (One not listed in the registry or under "Set Associations") use OP's method:
explorer shell:AppsFolder\[appuid]![appfullname]
The app UID is the folder name without the version number. For example,
4DF9E0F8.Netflix_2.11.0.8_x64__mcm4njqhnhss8
becomes
4DF9E0F8.Netflix_mcm4njqhnhss8
The app fullname is the [App author].[App name] For example, 4DF9E0F8.Netflix. 4DF9E0F8 is the author, and Netflix is the name.
Put it all together to get
explorer shell:AppsFolder\4DF9E0F8.Netflix_mcm4njqhnhss8!4DF9E0F8.Netflix
Store Apps can only be started by the shell. So try this:
explorer.exe shell:AppsFolder\Microsoft.WindowsAlarms_8wekyb3d8bbwe!App
Or from run (Win+R):
shell:AppsFolder\Microsoft.WindowsAlarms_8wekyb3d8bbwe!App
If the app is the default handler then you can just launch the file or protocol. There isn't a good in-box way to launch a file into a non-default handler from the command line.
Windows Store apps aren't designed to run from the command line and there isn't a straightforward way to launch them from the command line. Apps which handle specific files or protocols receive them through FileActivatedEventArgs or ProtocolActivatedEventArgs rather than command line arguments
You could write a launcher app which uses CLSID_ApplicationActivationManager's IApplicationActivationManager to ActivateForFile a specific app.
The best way I've found to pass command-line arguments to the executable targeted by the shell command is via the Windows start command.
Using your example, you would end up with this:
start "" shell:AppsFolder\Microsoft.Reader_8wekyb3d8bbwe!Microsoft.Reader example.pdf
I don't have Microsoft.Reader installed, so I can't test that. However, I can verify that this pattern works with Windows Terminal. In this case, I pass it a command-line argument to tell it which profile I want to open.
start "" shell:AppsFolder\Microsoft.WindowsTerminal_8wekyb3d8bbwe!App new-tab -p "GitBash"
The first argument to the start command here — the empty string — is just the title of the window.
You can also pair this with cmd /c, which I've found is necessary for some launcher applications, such as my personal favorite, SlickRun:
cmd /c start "" shell:AppsFolder\Microsoft.WindowsTerminal_8wekyb3d8bbwe!App new-tab -p "GitBash"
I have a blog post with more info on running Modern apps from the command line, which you might find helpful in constructing these ridiculously obtuse commands.
Not sure if it works on Windows 8, but on Windows 10 I use this:
cmd /C start <app-name>:
For example, to start Slack:
cmd /C start slack:

UIAutomation test invocation from the command line with Xcode 6

Running UIAutomation tests from the command line seems to break often with new Xcode releases (judging by past posts). Having never used the command line scripting for this, I found this post from 2012: Automation Instrument from the Command Line.
The Problem: My command returns without error, without output results and without anything logged to the system console. The simulator does not even launch!
Checking some of the paths for updates (notably, the Automation trace instrument path), I came up with this command. Note the path in the first parameter (it's different than in past Xcode releases):
instruments -t "/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/AutomationInstrument.xrplugin/Contents/Resources/Automation.tracetemplate"
"/Users/sohail/Library/Developer/CoreSimulator/Devices/7232A640-A9D2-4626-A2AD-37AFFF706718/data/Containers/Bundle/Application/D07FEC4B-76AD-4844-8362-08E771B81053/MyAppName.app"
-e UIASCRIPT "/Users/sohail/source/MyAppName/MyAppNameAutomationTests/TestRunner.js"
-e UIARESULTSPATH "Users/sohail/source/MyAppName/MyAppNameAutomationTests/TestResults"
This might be easier to read by selecting "raw" from this gist.
Of course:
I validated that the path specified to my .app actually exists; it came into being after a successful build and run.
I validated that in my specified output folder ("TestResults") that in fact, nothing got logged.
I validated that the aforementioned TestRunner.js file I specified, could be found at the path specified, and successfully runs in the Automation Instrument interactively with the Instruments app.
I've checked Apple's Xcode6/iOS8 pre-release documentation (login required; see section title, "Executing an Automation Instrument Script from the Command Line"), and nothing jumps out at me as wrong, since I'm just targeting the simulator.
My suspicion
I'm missing some flag or switch somewhere.
Thoughts anyone?
I saw the exact same issue, after explicitly provided -w $DEVICE parameter, my tests finally got started
instruments -t /Applications/Xcode6.app/Contents/Applications/Instruments.app/Contents/PlugIns/AutomationInstrument.xrplugin/Contents/Resources/Automation.tracetemplate
-w "iPhone 5s (8.0 Simulator)" /path/to/my/TestApp.app -e UIASCRIPT /tmp/script.js -e UIARESULTSPATH /tmp

Unrar script, error, in need of rar command for debian

I'm currently trying to get this script to work:
https://github.com/mj41/auto-unrar/blob/master/bin/unrar2.pl
The only problem is that I get the following error:
Entering directory 'Series'
Entering directory 'Series/SerieName'
Entering directory 'Series/SerieName/Season2'
Entering directory 'Series/SerieName/Season2/SerieNameS02E21.720p.HDTV.X264-DIMENSION'
Entering directory 'Series/SerieName/Season2/SerieNameS02E21.720p.HDTV.X264-DIMENSION/Sample'
Can't call method "List" on an undefined value at unrar2.pl line 973.
This line is rar_obj->List();
$rar_conf{'-verbose'} = $rar_ver if $rar_ver;
my $rar_obj = Archive::Rar->new( %rar_conf );
$rar_obj->List();
my #files_extracted = $rar_obj->GetBareList();
This is an old script, 3-4 years old and I changed a little like SHA1 to SHA and use Filesys::DfPortable; to Df
Does anyone know how I can fix this error :)?
EDIT:
I contacted the developer and he told me I needed to install a program that can handle rar commands. So how would I do that. I can't seem to be able to install unrar.
EDIT2:
What my problem is now, 2 of the 3 unrar packages aren't in my architecture, armhf.
To install the script yourself::::::::::::
https://github.com/jorricks/UNRAR
You need to pass the -archive parameter into the call to new() otherwise how will $rar_obj know which file it is supposed to be looking at?
I can't seem to be able to install unrar
That's not a particular good explanation of your problem. What did you try? What unexpected behaviour did you see?
From the tags on your question, it looks like you're running Debian. What do you see if you run sudo apt-get install unrar?
Update: My first comment was based on the code extract that you showed us. Looking at the full program code, I can see that %rar_conf has other values set in it (including the -archive option) before the section of code you gave us.
Looking at the source of the Archive::Rar module, it seems to assume that the program to use for dealing with the archives is called rar. So 7-Zip is not going to work.