5

I'm trying to write a shell script that automates certain startup tasks based on my location (home/campusA/campusB). I go to University and take classes in two different campuses (hence campusA/campusB). My location is determined by which wireless network I'm connected to. For the purposes of this script, we can assume that I will be connected to one of these networks when the script is called and my script knows which one I'm connected to based on a call to iwconfig.

This is what I want it to do:

cat file1 > file2 # always do this, regardless of where I am
if Im at home:
    start tweetdeck, thunderbird, skype

else if Im at campusA:
    activate the login script # I need to login on a webform before I get internet access. 
                              # I have written a script to automate this. 
                              # Wait for this script to finish before doing anything else
    myProg2 & # I want myProg2 running in the background until I shutdown my computer.

else if Im at campusB:
    ssh username@domain # this is the problematic line
    myProg2 & # I want myProg2 running in the background until I shutdown my computer.

start tweetdeck, thunderbird
close the terminal with the "exit" command

The problem is that campusB's wireless network is behind a firewall, which grants me internet access ONLY after I successfully ssh by username@domain. After a successful ssh, I need to keep the terminal window active in order to hold keep the internet access. If I close the terminal window, I lose internet access (this is bad).

When I try doing just ssh username@domain, the script stops because I don't exit the ssh command. I can't ^C out of it, which means that the rest of the script is never executed. I also have the same problem if I just close the terminal window in an attempt to kill the ssh session.

Some googling brought me to subshell, which I'm either using wrong or can't use to solve my problem. So how should I go about solving this problem? I'd appreciate any help - I've been at this for a while now and am unable to find anything helpful. If it makes a difference, I'd rather not store my ssh password in the script

Further, ampersanding the ssh call (ssh username@domain &) doesn't seem to do any good (can anyone explain why?)

Thank you in advance

EDIT

I must clarify, that the ssh connection has to be active in order for me to have internet access. Thus, when I close the terminal window, I need the ssh connection to still be active.

codeforester
  • 39,467
  • 16
  • 112
  • 140
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
  • wu-hu! Thanks. I haven't looked at this in a while. There's a lot of other good answers here. Feel free to accept the best, as there are several good explanations that I still couldn't make. Good luck to all! – shellter Feb 04 '14 at 12:15

7 Answers7

7

I had a script that looped on 6 servers, calling via ssh in the background. In 1 part of the script, there was a mis-behaving vendor application; the application didn't 'let go' of the connection properly. (other parts of the script using ssh in background worked fine).

I found that using ssh -t -t cured the problem. Maybe this can help you too. (a teammate found this on the web, and we had spent so much time, I never went back to read the article that suggested this. The man page on our system gave no hint that such a thing was possible)

Hope this helps.

shellter
  • 36,525
  • 7
  • 83
  • 90
2

Having a ssh with pseudy tty on background shell

In addition to @shellter's answer, I would like make some precision:

where @shelter said:

The man page on our system gave no hint that such a thing was possible

On my system (Debian 7 GNU/Linux), if I hit:

man -Pcol\ -b ssh| grep -A3 '^ *-t '

I could read:

     -t      Force pseudo-tty allocation.  This can be used to execute arbi‐
             trary screen-based programs on a remote machine, which can be
             very useful, e.g. when implementing menu services.  Multiple -t
             options force tty allocation, even if ssh has no local tty.

Yes: Multiple -t options force tty allocation, even if ssh has no local tty.

This mean: If you remotely run a tool that require access to pseudo terminal ( pty like /dev/pts/0), you could run them by using -t switch.

But this would work only if ssh is run from a shell console (aka having his own pty). If you plan to run them is shell session without console, like background scripts, you may use Multiple -t to enforce pseudo tty allocation from ssh.

Multiple ssh shell on one ssh connection

In addition to answers from @tommy and @geekosaur, I would make some precision:

@tommy point to a very intersting feature of ssh. Not sure this have a lot to do with answer, but speaking around long time connection, this feature has to be clearly understood.

Once a connection is established, ssh could (and know how to) use them to drive a lot of thing in this one connection:

  • -L let you drive remote TCP connections to local machines/network. (full syntax is: -L localip:localport:distip:distport) where localip could be specified to permit other hosts from same local domain to access same tcp bind, and distip could by any host from distant network ( not only localhost ) sample: -L192.168.1.31:8443:google.com:443 permit any host from local domain to reach google through your host: http://192.168.1.31:8443

  • -R Same remarks in reverse way!

  • -M Tell ssh to open a local unix socket for bindind next ssh consoles. Simply open two terminal window. First in both window, hit: ssh somewhere than hit netstat -tan | grep :22 or netstat -tan | grep 192.168.1.31:22 (assuming 192.168.1.31 is your onw host's ip)

    Than compare close all your ssh session and in first terminal, hit: ssh -M somewhere and in second, simply ssh somewhere. you may see in second terminal:

    $ ssh somewhere
    + ssh somewhere
    Last login: Mon Feb  3 08:58:01 2014 from elsewhere
    

    If now you hit netstat -tan | grep 192.168.1.31:22 (on any of two oppened ssh session;) you must see that there is only one tcp connection.

    This kind of features could be used in combination with -L and maybe some sleep 86399...

    To work around a tcp killer router that close every inactive TCP connection from more than 120 seconds, I run:

    ssh -M somewhere 'while :;do uptime;sleep 60;done'
    

    This ensure connection stay up even if I dont hit a key for more than two minutes.

F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137
2

Here's a few thoughts that might help.

Sub-shells

Sub-shells fork new processes, but don't return control to the calling shell. If you want to fork a sub-shell to do the work for you, then you'll need to append a & to the line.

(ssh username@domain) &

But this doesn't look like a compelling reason to use a sub-shell. If you had a number commands you wanted to execute in order from each other, yet in parallel from the calling shell, then maybe it would be worth it. For example...

(dothis.sh; thenthis.sh; andthislastthingtoo.sh) &

Forking

I'm not sure why & isn't working for you, but it may be worth looking into nohup as well. This makes the command "immune" to hang up signals.

nohup ssh username@domain (try with and without the & at the end)

Passwords

Not storing passwords in the script is essential for any ssh automation. You can accomplish that using public key cryptography which is an inherent feature of ssh. I wont go into the details here because there are a number of great resources all across the interwebs on setting this up. I strongly suggest investigating this further.

If you do go this route, I also suggest running ssh in "batch mode" which will disable password querying and will automatically disconnect from the server if it becomes unresponsive after 5 minutes.

ssh -o 'BatchMode=yes' username@domain

Persistence

Then if you want to persist the connection, run some silly loop in bash! :)

ssh -o 'BatchMode=yes' username@domain "while (( 1 == 1 )); do sleep 60; done"

F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137
perden
  • 647
  • 5
  • 20
  • In all these cases, I'm able to input my password, but the ssh connection doesn't persist. I need the connection to be active in order to have internet access - logging in just once doesn't grant me access (I realized that my question wasn't clear on this and have made an edit to clarify this). – inspectorG4dget Mar 08 '11 at 20:31
  • 1
    If you need persistence, you could try running a silly loop... :) I updated my answer, but it looks like you've found what you're looking for! – perden Mar 09 '11 at 19:58
  • +1 @perden for making it work, but that seems much more hacky than it needs to be – inspectorG4dget Mar 10 '11 at 05:35
  • Fine answer, but why did you *obfuscate* the reference list!? – F. Hauri - Give Up GitHub Feb 03 '14 at 08:48
2

You may want to try to double background myProg2 to detach it from the tty:

# cf. "Wizard Boot Camp, Part Six: Daemons & Subshells",
# http://www.linux-mag.com/id/5981
(myProg2 &) &

Another option may be to use the daemon tool from the libslack package:

http://ingvar.blog.linpro.no/2009/05/18/todays-sysadmin-tip-using-libslack-daemon-to-daemonize-a-script/

gerd
  • 21
  • 1
  • Double backgrounding works in so far as it asks me for my password. I can't make the connection persist beyond the exiting of the shell. My question wasn't super clear about this at first (I just realized), so I've clarified it in the edit – inspectorG4dget Mar 08 '11 at 20:32
  • +1 for introducing me to daemonize. It taught me something new, even though it's not the solution I'm after – inspectorG4dget Mar 08 '11 at 20:36
1

The problem with & is that ssh loses access to its standard input (the terminal), so when it goes to read something to send to the other side it either gets an error and exits, or is killed by the system with SIGTTIN which will implicitly suspend it. The -n and -f options are used to deal with this: -n tells it not to use standard input, -f tells it to set up any necessary tunnels etc., then close the terminal stream.

So the best way to do this is probably to do

ssh -L 9999:localhost:9999 -f host & # for some random unused port

and then manually kill the ssh before logout. Alternately,

ssh -L 9999:localhost:9999 -n host 'while :; do sleep 86400; done' </dev/null &

(The redirection is to make sure the SIGTTIN doesn't happen anyway.)

While you're at it, you may want to save the process ID and shut it down from your .logout/.bash_logout:

ssh -L 9999:localhost:9999 -n host 'while :; do sleep 86400; done' < /dev/null & echo $! >~.ssh_pid; chmod 0600 ~/.ssh_pid

and in .bash_logout:

if test -f ~/.ssh_pid; then
  set -- $(sed -n 's/^\([0-9][0-9]*\)$/\1/p' ~/.ssh_pid)
  if [ $# = 1 ]; then
    kill $1 >/dev/null 2>&1
  fi
  rm ~/.ssh_pid
fi

The extra code there attempts to avoid someone sabotaging your ~/.ssh_pid, because I'm a professional paranoid.

(Code untested and may have typoes)

geekosaur
  • 59,309
  • 11
  • 123
  • 114
  • This answer is interesting to me. Could you please explain in detail what `ssh -L 9999:localhost:9999 -f host &` does? Also, in that code, will replacing `host` with `user@domain` work like I would expect it to? – inspectorG4dget Mar 08 '11 at 20:39
  • 1
    The `-L local:host:remote` option tells `ssh` to listen on port `local` on the local host, and forward any conneections to it to the remote `sshd` to open a connection to `host` on port `remote`. Most commonly the `host` is `localhost`. The `-f` option tells `ssh` that it is *only* doing port forwarding, so don't run a command or start a session. (It may still need a dummy command like `sleep 30` to keep the tunnel around long enough for something to connect to it.) – geekosaur Mar 08 '11 at 20:47
0

It's been a while since I've used ssh, and I can't test it right now, but have you tried the -f switch?

ssh -f username@domain

The man page says it backgrounds ssh. Not sure why & wouldn't work, but I guess it's interpreting it as a command to be run on the remote machine.

OpenSauce
  • 8,533
  • 1
  • 24
  • 29
  • 1
    `ssh -f` doesn't work, because I ultimately close the terminal. The ssh doesn't seem to get backgrounded properly. So the connection doesn't persist. – inspectorG4dget Mar 08 '11 at 19:20
  • @inspectorG4dget I am having the same problem that `-f` doesn't seem to background ssh properly and disallows me from closing the terminal, even though that should work. Have you ever found out why? – Adrian Frühwirth Oct 10 '13 at 11:30
  • @AdrianFrühwirth: I never found out why, but the accepted answer in this thread has a solution that did work for me – inspectorG4dget Oct 10 '13 at 15:32
0

Maybe screen + ssh would fit the bill as well?

Something like:

screen -d -m -S sessionName cmd

screen -d -m -S sessionName cmd &

# reconnect with
screen -r sessionName
tommy
  • 1