How to use Process() with an argument containing a semicolon?

Hi!

I have an issue calling mount_smbfs with a user from a specific domain. A sample shell call is

mount_smbfs -N -o nodev,nosuid "//DOMAIN;USER:PASS@SERVER_ADDRESS" /SOMEPATH

Using the code below I get an invalid command because the semicolon ends the command in shell.

var server     = "//DOMAIN;USER:PASS@SERVER_ADDRESS"
let remotePath = "/REMOTEPATH"
let localPath  = "/LOCALPATH"
let cmd  = Process()

cmd.executableURL = URL(fileURLWithPath: "/sbin/mount_smbfs")
cmd.arguments     = ["-N", "-o nodev,nosuid", "\(server)\(remotePath)", localPath]

Using a quoted semicolon

var server     = "//DOMAIN\;USER:PASS@SERVER_ADDRESS"

does also not work, because the backslash is quoted to DOMAIN\\;USER automatically via Process class. So I end up with two backslash.

Using quotes did also not work for me.

Any clue how to solve this issue?

Answered by DTS Engineer in 707367022

Process doesn’t run a shell. Rather, the arguments you pass to it get sent directly to the kernel which passes them verbatim to the child process. For example, this code:

import Foundation

func main() throws {
    let p = Process()
    p.executableURL = URL(fileURLWithPath: "/Users/quinn/echo.sh")
    p.arguments = [ "Hello;Goodbye", "~/Cruel", "World", "!" ]
    try p.run()
    p.waitUntilExit()
}

try! main()

running this script:

% cat echo.sh
#! /bin/sh

while [ $# -gt 0 ]
do
    echo $1
    shift
done

prints:

Hello;Goodbye
~/Cruel
World
!

Note that the semicolon is passed through, there’s no expansion of ~, and the ! isn’t interpreted.

The problem with your Process code is that you’re passing -o nodev,nosuid as one argument, whereas the shell passes it as two. Consider this:

% /Users/quinn/echo.sh -o nodev,nosuid "//DOMAIN;USER:PASS@SERVER_ADDRESS" /SOMEPATH
-o
nodev,nosuid
//DOMAIN;USER:PASS@SERVER_ADDRESS
/SOMEPATH

As to how you get mount_smbfs to do what you want, that’s not really my area of expertise. However, if you can get it working from the shell then I can explain how to achieve the same result using Process.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Have you tried to escape the semi colon (replacing with its % equivalent) ?

No. I tried backslash quoting and quotes.

Unfortunately it does not work using percent encoding. In Terminal I get this error:

$ mount_smbfs -N -o nodev,nosuid "//DOMAIN%59USER:PASS@SERVER_ADDRESS/REMOTEPATH" /LOCALPATH
mount_smbfs: server rejected the connection: Authentication error

Also it does not work in my application.

Oops. The code has to be Hex encoded. It does also not work:

$ mount_smbfs -N -o nodev,nosuid "//DOMAIN%3BUSER:PASS@SERVER_ADDRESS/REMOTEPATH" /LOCALPATH
mount_smbfs: server rejected the connection: Authentication error
Accepted Answer

Process doesn’t run a shell. Rather, the arguments you pass to it get sent directly to the kernel which passes them verbatim to the child process. For example, this code:

import Foundation

func main() throws {
    let p = Process()
    p.executableURL = URL(fileURLWithPath: "/Users/quinn/echo.sh")
    p.arguments = [ "Hello;Goodbye", "~/Cruel", "World", "!" ]
    try p.run()
    p.waitUntilExit()
}

try! main()

running this script:

% cat echo.sh
#! /bin/sh

while [ $# -gt 0 ]
do
    echo $1
    shift
done

prints:

Hello;Goodbye
~/Cruel
World
!

Note that the semicolon is passed through, there’s no expansion of ~, and the ! isn’t interpreted.

The problem with your Process code is that you’re passing -o nodev,nosuid as one argument, whereas the shell passes it as two. Consider this:

% /Users/quinn/echo.sh -o nodev,nosuid "//DOMAIN;USER:PASS@SERVER_ADDRESS" /SOMEPATH
-o
nodev,nosuid
//DOMAIN;USER:PASS@SERVER_ADDRESS
/SOMEPATH

As to how you get mount_smbfs to do what you want, that’s not really my area of expertise. However, if you can get it working from the shell then I can explain how to achieve the same result using Process.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for your explanation. My assumption was obviously wrong.

In fact the command

mount_smbfs -onodev,nosuid "//DOMAIN;USER:PASS@SERVER_ADDRESS/REMOTEPATH" /SOMEPATH

works well in shell. Note: The password needs a HTML like % encoding for funny chars, e.g. "my%23pass" for "my#pass".

I use a similar call already with sshfs on a Linux server. Now I will perform some more debugging to get a clue what's wrong. I will post a reply with my discoveries.

Now I got it working. I fixed the "-o" option by removing the space and removed all additional quoting.

Many thanks for your help (again).

How to use Process() with an argument containing a semicolon?
 
 
Q