PDA

View Full Version : [SOLVED] Using bash to conditionally stop an application.



landstander
March 15th, 2012, 06:34 PM
Specs:
Ubuntu 11.04 64bit
2.6.38-13-generic #56-Ubuntu SMP Tue Feb 14 12:39:59 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
Using the Gnome desktop interface, and bash.

My skill level with Bash:
Somewhere between beginner and intermediate. I understand most of the basics, but not how to use all the basic concepts together very well.

Condition:
If VPN is active or inactive

Requirement:
If VPN is inactive, stop all programs that depend on the VPN being active.

1st problem:
If I start the programs that depend on the VPN from within the bash script the script essentially pauses until the program finishes or exits. This keeps me from being able to test whether the VPN is active or not.

Possible solutions:
I thought that maybe I could just make them separate processes and activate them manually once I was connected to the VPN. In this way I could run a script to check the connection status of the VPN and somehow trigger the programs to stop once the connection was lost but this raised a secondary problem.

2nd Problem and questions:
Once the VPN connection is lost, how can I tell a program to quit or exit nicely without killing it, and even if I have to kill it in order to stop it, how would I do that without being present since killing a program requires input from the user in the form of the super user password?


Here is an example of the code I've been attempting so far. It functions in its current state with myprogram01 commented out, but it doesn't solve the problems I've mentioned above.


#!/bin/bash
# The following might work as a conditional for programs that depend on the VPN in order to run or for programs that might need to stop running if the VPN is inactive.

nmcli -p con up uuid #insert_connection_id #Attempt a connection to the VPN

vpnstring=""
vpnstring=`nmcli -t -f VPN con status |grep yes`
if [ "$vpnstring" = "yes" ]; then
echo VPN connection is active #dependency can be run here.
sleep = 5
# myprogram01 #this line stops the bash script from continuing. Consider maybe using a "watch" command???
else
echo VPN connection is inactive #Possibly retry the connection in the loop below if not connected.
fi
#echo The contents of the vpn string are as follows.
#echo $vpnstring

while :
do
vpnstring=`nmcli -t -f VPN con status |grep yes` #Executed as long as condition is true and/or, up to a disaster-condition if any.
if [ "$vpnstring" = "yes" ]; then
echo VPN connection is still active
else
echo VPN not connected. #Possibly retry the VPN connection here.
break
fi
done


Any advice?
Thanks.

CynicRus
March 15th, 2012, 07:15 PM
#!/bin/bash
VPNNAME=VPN1
while true; do

vpnstring=$(nmcli con status|grep -c $VPNNAME)
program=programname

date
case $vpnstring in
"0")
echo "not connected"
kill -SIGSTOP $program
;;
"1")
echo "VPN seems to work"
kill -SIGCONT $program
;;

esac
sleep 30

done
Something like this should do what you want.If i understand the problem. Sorry, can't test this.

landstander
March 16th, 2012, 02:27 AM
CynicRus,

Thank you for the example it is very helpful and got me a lot farther towards getting this to work.

I now have 2 scripts; vpn1.sh, and vpn2.sh
(vpn1.sh): Attempt a connection until its successful then start a VPN dependant program.
(vpn2.sh): Check the connection status of the VPN until the connection fails then stop the VPN dependant program that was started in Script 1.

Error message generated by vpn2.sh:
./vpn2.sh: line 18: kill: myprogram01: arguments must be process or job IDs
Note: Line 18 is as follows:
kill -SIGCONT $program #Where $program is defined earlier in the code as myprogram01

Checking process results:
~$ ps -aef |grep myprogram01
13839 13789 1 18:06 pts/1 00:00:00 myprogram01
13902 12683 0 18:07 pts/0 00:00:00 grep --color=auto myprogram01
~$

Questions:
1.) Why is myprogram01 not being recognized as a process when it is listed as one by "ps" from the command line?
2.) How can I get around this problem, and is there a more elegant way other than parsing the job ID?

Vaphell
March 16th, 2012, 03:16 AM
doesn't kill require PIDs not program names?

you can try

kill -SIGCONT $(pgrep $program)

pgrep does the same as ps | grep | cut_proper_column, but better :)

CynicRus
March 16th, 2012, 04:13 AM
program=`pidof myprogram01`

kill -SIGCONT $program

UltimateCat
March 16th, 2012, 05:08 AM
Wish there was a more elegant way than

kill

Or as an example:

236 vi ~/. bashrc
or ! 236 to re-execute

Other than that yeah; the job # because it is possible to run multipule commands in the background at the same time.

Shame that the wildcards can't give us more functionalities or processes suitable for termination in a more ginger way- ( if I find anything; I'll post it )
It's worth investigating another way to exit a program or process.

Best regards

CynicRus
March 16th, 2012, 06:00 AM
For continue process after SIGSTOP, i think, use fg, because SIGCONT - run for daemon's only.

http://www.real-world-systems.com/docs/bashref_6.html

Vaphell
March 16th, 2012, 06:40 AM
i mentioned pgrep, but pkill accepts the same parameters (there are quite a few) and does the job directly
http://linux.die.net/man/1/pkill

landstander
March 16th, 2012, 01:13 PM
Update:
Thank you all very much for your input and your help. Giving the second script the PID number instead of the program name seems to allow it to continue to what looks like a completion.

Only two problems left.

1.) The VPN dependant program gives an "unable to load an environment variable" error when it starts, and it isn't making any connections so I'll need to test that further before I can continue finish bug testing the scripts.

2.) When I disconnected the VPN to test the scripts nothing seemed to happen. The second script brings me back to the command prompt ok, but it doesn't appear to stop the VPN dependant program.

If I am unable to solve #2 above I will come back and give more information about it and ask some follow up questions. I just want to give myself a chance to figure this out first. Thank you all again for your help so far.

landstander
March 17th, 2012, 12:06 AM
Ok the environment variable issue wasn't affecting things, and the other problem came from a syntax error in the code that was found and fixed.

In short the two scripts appear to be working well now with one minor annoyance.

Problem:
I would like to combine these two scripts into one script, but the problem is that starting a program inside a script causes the script to wait until the program finishes before the script can continue.

The annoyance:
I'm dealing with this problem by manually pressing CTRL+Z once to stop the VPN dependant program so the second script can take over starting and stopping it depending on the VPN connection status which it also takes control of.

Questions:
1.) Is there a way to start a program in -SIGSTOP mode? Or is there some other way around the problem described above? For example, would something like the following work to fork the process such as:


...previous part of script...
myprogram01 &
...script continues due to the "&"...

2.) If this works then will the -SIGSTOP and -SIGCONT still work even though myprogram01 would be running in the background or would I have to bring it to the forground first with fg? Seems like all of this is getting a bit excessive.
3.) Is there maybe something more simple I could do using the watch command in conjunction with cron?


Note: For reference, this is the single script version of the two scripts I've been working on so far.
It hasn't been tested yet due to the CTRL+Z issue described above.


#!/bin/bash
#This is part one of a two part script to secure VPN dependant traffic after a disconnect from the VPN.

#Attmept an initial connection until connected
while : #Executed as long as condition is true and/or, up to a disaster-condition if any.
do
connected=`nmcli -t -f VPN con status |grep yes` #Store the current state of the VPN connection.
if [ $connected = "yes" ]; then
echo VPN connection activated.
break
else
echo Attempting VPN connection.
nmcli -p con up uuid 07d345f0-3cb4-4b59-ba2b-7fdf9717e50a #Retry the VPN
fi
done

myprogram01 #[U]This is where I would have to press CTRL+Z to continue the script.
program=`pidof myprogram01`

#Monitor the connection.
while true; do
vpnstring=$(nmcli -t -f VPN con status|grep -c yes) #Define a string to test, 0 = no connection, 1 = connected.
date

case $vpnstring in #Test a string.
"0")

echo "VPN disconnected"
kill -SIGSTOP $program #Connection lost stop the VPN dependancy.

while : #The connection has been lost, try to reconnect then break out once connected.
do
connected=`nmcli -t -f VPN con status |grep yes` #Store the current state of the VPN connection.
if [ $connected = "yes" ]; then
echo VPN connection activated.
break
else
echo Attempting VPN connection.
nmcli -p con up uuid 07d345f0-3cb4-4b59-ba2b-7fdf9717e50a #Retry the VPN
fi
done
;;

"1")
echo "VPN connection active"
kill -SIGCONT $program
;;
esac

sleep 5
done


Thanks again for your patients and time.

CynicRus
March 17th, 2012, 05:06 AM
kill -SIGCONT $program
If you program is daemon, this work. But, if is not daemon - use:
jobs and bg - if you need backgroung prog running, or fg - if need foreground running. How?

cynic@ubuntu:~# jobs
[1]+ Stopped vim /etc/lighttpd/vhost.conf
cynic@ubuntu:~#
cynic@ubuntu:~# fg %1
vim /etc/lighttpd/vhost.conf



I think - you can put a flag in the first script, for example, AUTO = 0. If you send sigstop from a script - AUTO = 1, and then you can start from this option - check - whether manually shut down the program or script.

landstander
March 17th, 2012, 09:32 PM
Ok I think my problem needs to be simplified a bit more to make it clear.

Description of problem:
If I have simple a script does the following:


#!/bin/bash
myprogram01
echo This line of the script only occurs with user intervention.

It will never reach the the echo command on the second line because it is waiting for myprogram01 to be told to stop or exit by user input, and even if we fork the program into the background like this:


#!/bin/bash
myprogram01 &
echo This line of the script only occurs with user intervention.

It forks the program into the background but the bash script still waits for it to complete before executing the echo command on the next line, and so the same problem persists.

Question:
How can you get this simplified bash script to execute the echo command on the second line without manual intervention or input from a user after the first line is executed? For this question, you may replace myprogram01 with any program that does not exit without user input such as a web browser, or media player or another terminal session etc.

I really appreciate your input and I am learning a lot. Thank you again for taking the time to help.

CynicRus
March 18th, 2012, 06:19 AM
http://blog.dbotelho.com/2009/01/multithreading-with-bash-script/, but if you need multithread tasks run - write in C or python.

And...

#!/bin/bash

THREADS=15

while true
do
if [ `pgrep -f $1 | wc -l` -lt $THREADS ];
then
if read value;
then
$value &
echo ran instance $!
else
exit 0;
fi
else
sleep .5
fi
done

CynicRus
March 18th, 2012, 06:34 AM
And....
myprogram &|echo "mytext"

landstander
March 18th, 2012, 11:09 PM
CynicRus,


~$ myprogram01 &|echo "mytext"
bash: syntax error near unexpected token `|'

???

Thank you for the link. I'm reading some of it now. it looks a little over my head, but I'll keep looking things up until it starts to make some more sense. The man pages aren't helping much.

"...but if you need multithread tasks run - write in C or python."

Thank you for this tip as well. I hadn't thought of learning C or python to tackle this problem. Although if that's the only option I have left then it will be easier to go back to using two bash scripts instead of having to learn 2 more programming languages. I just don't have that much free time.

I will wait a few more days in case there are any more ideas, tips, or advice to get my previous post to work in a way that makes sense or is easy to learn. If not then I'll consider it as either to difficult to learn, or as a limitation of the bash scripting language, and mark the thread as solved.

landstander
March 18th, 2012, 11:53 PM
[Update:]

Ok I think I've misunderstood how bash works. What I see when I run vpn1.sh is that myprogram01 is the last thing displayed on stdout which made me think that bash was hanging or waiting for myprogram01 to finish before it continued.

I tested this by disconnecting the VPN to see if the script would stop myprogram01 and attempt a reconnect. Checking jobs from a separate terminal showed nothing, so I assumed that the script wasn't working.

After checking again I discovered that I can't click on the icon for myprogram01 and that it is unresponsive until the VPN is reconnected so it appears as though the script is stopping myprogram01 but I don't have a way to tell for sure since I can't check its stopped state using jobs. Further more the fact that the script is trying to reconnect shows me that bash is reading and executing the rest of the script after the ampersand so at least that part has the appearance of working.

In short I was confused in part by the output not reflecting the order the script is run in, and in part by not being able to check the job status. I'll try echoing a jobs list during the reconnection cycle to see if this helps.

landstander
March 20th, 2012, 12:54 AM
[Final Update:]
As far as I can tell the script seems to be working fine now.

There is still no way to check if it actually stops the program since "jobs" doesn't produce any output, but since the program appears to be frozen during the time period when it should be stopped I'm assuming its stopped.

Here is the final version of the script as a reference in case any one cares to use it:


#!/bin/bash
#This program stops a program when your VPN connection is lost then restarts it after the connection is re-established.

#Attmept an initial connection until connected
function connectVPN()
{
while : #If the connection is just started or lost, try to reconnect then break out once connected.
do
connected=`nmcli -t -f VPN con status |grep yes` #Store the current state of the VPN connection.
if [ "$connected" = "yes" ]; then
break
else
echo "Attempting VPN connection in 10 seconds."
sleep 10 #Give the VPN time to recover so we don't abuse it with reconnection requests.
nmcli -p con up uuid 07d345f0-3cb4-4b59-ba2b-7fdf9717e50a #Retry the VPN
fi
done
}
connectVPN

myprogram01 & #Note: can not use a string to represent the program because the name of the string will be stored as the job name instead of the program name.
programID=`pidof myprogram01`

#Monitor the connection for discconnections and secure VPN dependancies.
date
while true; do
vpnstring=$(nmcli -t -f VPN con status|grep -c yes) #Define a string to test, 0 = no connection, 1 = connected.
case $vpnstring in #Test the connection string.
"0")
date
echo "VPN disconnected. Stoping VPN dependancies"
kill -SIGSTOP $programID #Connection lost stop the VPN dependancy.
echo "VPN dependancies stopped."
jobs

connectVPN
echo "VPN dependencies restarted." #Placed here so it wont be endlessly repeated in the outer loop.
date
;;
"1")
kill -SIGCONT $programID
;;
esac
sleep 5
done


Note: if you use this code, just change myprogram01 to whatever program you want stopped when your VPN connection is lost, and change the UUID of the VPN connection to match whatever UUID your computer assigns to your VPN connection.

Thanks again to CynicRus and all the others who helped me on this project. It would have taken a lot longer to complete without your help. Thank you.

rbjscv
October 4th, 2012, 06:08 PM
No question. Solved myself.

rbjscv
October 24th, 2012, 09:11 PM
When ever I run this scrip I get: "Couldn't set environment variable."

I've searched everwhere but I have no knowledge of programming so I don't even know what I'm reading, much less how to apply it.

I copied the script exactly as it is and the only changes I made was to insert the program I wanted at both "myprogram01"'s and adding the uuid for my VPN.

Help would be greatly appreciated. It's over my head what to do.

Thank you.

squid636
November 21st, 2012, 03:47 AM
I just downloaded and ran your script and it worked with no problems. A big thank you to you and whom ever helped you on this.

sgleo87
February 4th, 2013, 04:48 PM
I copy and pasted the script, but even after correcting the single quotes ( ' ), I still got some strange error messages (Base connection for VPN connection not active). In short, the script did not recognize, that the VPN connection was already established and tried to reconnect the whole time.

So played around with the script and tried to simplify it. Now it is working correctly!

CHANGES:
- Fixed established VPN connection not being recognized.
- Program is not not started at the beginning of the script. However, it can be started independently at any time, since the script now continually checks, if it is running or not.



#!/bin/bash
#This program automatically re-establishes your VPN connection and pauses a predefined program.

#Monitor the VPN connection
date
while true; do
#Define a string to test VPN connection: 0 = no connection, 1 = connected.
programID=$(pidof PROGRAM)
connected=$(nmcli -t -f VPN con status|grep -c yes)
case $connected in
"0")
date
echo "VPN disconnected."
#Connection lost. Stop the VPN dependency, if running.
if [ "$programID" != "" ]; then
kill -SIGSTOP $programID
echo "Program stopped."
else
echo "Program not running."
fi
echo "Reconnecting VPN."
#Give the VPN time to recover.
sleep 15
#Retry the VPN
nmcli -p con up uuid CONNECTION-ID-NUMBER
;;
"1")
date
echo "VPN connected."
#Connection is fine. Restart the VPN dependency, if it was running.
if [ "$programID" != "" ]; then
kill -SIGCONT $programID
echo "Program running."
else
echo "Program not running."
fi
;;
esac
sleep 5
done


Note: As in the original script, please replace PROGRAM with the application name (e.g. transmission-gtk) and the CONNECTION-ID-NUMBER with the uuid of your vpn connection (e.g. 83335b7a-789a-411e-8140-135126fa4701)

bmcgonag
May 18th, 2013, 04:03 PM
This is an Awesome scritpt. I tried the original, but it kept trying to kill the wrong PID, not sure why, and it was doing it when the VPN was connected.

This version works perfectly! Thanks so much!

tiaret
June 23rd, 2013, 01:55 PM
If I understand this script correctly it waits 5 seconds after checking the vpn and then checks again. Won't the program that is supposed to be stopped from leaking my isp ip be able to leak my ip in the time between vpn failure and next vpn check? If so, using this script only, to protect against vpn failure seems reckless.

Am I wrong?

rnerwein
June 24th, 2013, 09:11 PM
hi folks
there was given a nice solution but !!!!!!
i figured out (poor experince) - singnal handling in linux is not every time the butter on the bead. sure it happens me (seldom) that the SIGCONT, wasn't afer a SIGSTOP (that means that the process is never come back - try again in your script -> hint is --> just give'm 2 or three CONT after stop - computer are hig speed idots - told my students long time ago)
you can see this in a "ps" command with staus "T" (or check the /proc/.... for status) . seldom but it can happen - for sure !
be careful
ciao
richi

landstander
November 19th, 2013, 06:45 PM
tiaret,

You bring up a great point. I've tested this script by manually stopping the VPN to see how the script would react and from what I've seen the program appears to be stopped very quickly (as in not 5 seconds later). However I'm not sure how long it actually takes because I'm not sure how to use code to test the latency between when the VPN looses its connection and when the "program being monitored by this script" is stopped.

As such you are correct in posting this cautionary observation, but it is not clear weather or not the observation is correct.
Does any one know how to test tiaret's observations of the code?

landstander
November 19th, 2013, 06:53 PM
hi folks
there was given a nice solution but !!!!!!
i figured out (poor experince) - singnal handling in linux is not every time the butter on the bead. sure it happens me (seldom) that the SIGCONT, wasn't afer a SIGSTOP (that means that the process is never come back - try again in your script -> hint is --> just give'm 2 or three CONT after stop - computer are hig speed idots - told my students long time ago)
you can see this in a "ps" command with staus "T" (or check the /proc/.... for status) . seldom but it can happen - for sure !
be careful
ciao
richi

I apologize for this, but it is difficult for me to understand your use of the English language. Where you state "seldom but it can happen - for sure !" I'm not clear on what "it" is that you are referring to.
I think what your saying is that SIGCONT is sometimes happening before the SIGSTOP occurs.
Is that a correct understanding of what you're conveying?

If so, I'm not sure why that matters. If the program is already running and we tell it to continue running, why does that cause a problem?

landstander
November 19th, 2013, 07:26 PM
I copy and pasted the script, but even after correcting the single quotes ( ' ), I still got some strange error messages (Base connection for VPN connection not active). In short, the script did not recognize, that the VPN connection was already established and tried to reconnect the whole time.

So played around with the script and tried to simplify it. Now it is working correctly!


Very good point. I'm sorry I didn't respond sooner. I had gotten the impression that this thread was dead after I posted my last version of the script which is why I wasn't checking it any more.

As far as single quotes go, the script uses two different types of single quotes. One is the kind you find on the upper left hand side of a standard US keyboard just above the TAB key (on the same key with the character ~ on it) and the other is to the right of the semicolon ; key (on the same key with the double quote " on it). So for example to input a program name into a variable I use the single quote that is on the same key as the double quote " key on the keyboard.
Example:

progID='qbittorrent'
This takes the command line input [qbittorrent] and passes it to the variable progID which can now be called as $progID anywhere else in the script.

...but for a command line output I will use the single quote on the same key as the ~ key on the keyboard such as:

btID=`pgrep $progID` #Where pgrep has changed from 'pidof' because 'pidof' appears to have quit working.
This takes the output of the command [pgrep $progID] which gives the programs job process number, and passes it into btID which can now be called as $btID any where else in the script.

I forgot to mention this in my original post because I was under the impression that these nuances were preserved when copying and pasting the code that I had posted. I also was under the impression that a bash script written for one Linux environment would also work exactly the same in another Linux environment. For example, I wrote this script for use in the terminal running bash as its command interpreter on a computer running Ubuntu as its OS and Gnome as its desktop, and I was under the impression that someone else would be equally able to run this script in a terminal that was using bash as its command interpreter if they were running Fedora, or Mint, or Arch or whatever OS, but from the feedback I've seen on this thread I'm not so sure thats true any more...

As far as the code you have posted is concerned, it looks as if you are only looping to see if the VPN has been lost and to stop a program if the connection is lost. The intention of the original scrip was to make it so you could use a single click to start the VPN and the program you wanted to depend on that VPN as well as to manage how the two play with each other. In you're script, do you have to manually start the program that depends on the VPN being connected?

I appreciate you're input and contributions. Really cool! :)

landstander
November 19th, 2013, 08:58 PM
[UPDATE]
Here is the latest incarnation of the script. It will now automatically determine the VPN UUID for you (provided you only have one VPN setup on you're system, see lines 12 through 15 if you have more then one VPN).
Now the only thing you will need to change in this script is line 8, where you would replace "myprogram" with whatever program you want to be stopped when the VPN looses its connection.
I've also added more comments (lines preceded with a # symbol are comments) in the script to try and help explain some things as best I can given my current low skill level.

Caution: As previous poster's have pointed out, please use this script at your own discretion as I am a novice at writing scripts and do not know how to check for latencies in this script between when the VPN fails and when the program that depends on that vpn is stopped. It has been my experience that this script "appears" to stop the program instantly (via manual visual inspection) when the VPN looses its connection. However as stated I'm not sure how to test this aspect of the script using code to get an accurate measure of any latency that might be present. If any one knows how to test this please provide a comment.

To use this script:
1.) Copy the code below into a file and name it whatever you want with an extention ".sh", for example "vpnmon.sh"
2.) Open a text editor and replace the word "myprogram" on line 8 with the name of the program you wish to have stopped when the VPN fails or looses its connection.
Example: If using qbittorrent, then line 8 would look like this:
progID='qbittorrent'
3.) Save and close the file.
4.) To run it from the command line, type bash "pathtofile/filename.sh" where pahttofile is the path to your file, and filename.sh is the name of the file you gave in step 1.
Example: If you named your file vpnmon.sh and placed it in a directory called Programs which resides in your home directory then you would execute the script by the following on a command line:
bash "~/Programs/vpnmon.sh"

Script:


#!/bin/bash
# This script monitors a VPN connection and stops a program when that connection
# is lost, then restarts that program when the connecton is re-established.

#Attmept an initial connection until connected
#------------------------------------------------------------------------------
# Set progID to whatever program you need stopped when VPN fails.
progID='myprogram'

# Get the UUID of the only vpn on the system.
# Note if you have more then one VPN configured on your system, you will need to
# comment out line 14 and uncomment line 15 replacing "your-vpn-name-here" with
# the name of the vpn you want to use with this script.
uuid_str=`nmcli -t -f TYPE,UUID con list |grep vpn |sed s/vpn://g`
# `nmcli -t -f NAME,UUID con list |grep your-vpn-name-here |sed s/your-vpn-name-here://g`

function connectVPN()
{
# If the connection is just started or lost, try to reconnect then break out once connected.
while :
do
connected=`nmcli -t -f VPN con status |grep yes` #Store the current state of the VPN connection.
if [ "$connected" = "yes" ]; then
# echo "VPN connection active"
break
else
echo "Attempting VPN connection in 5 seconds."
sleep 5 #Give the VPN time to recover so we don't abuse it with reconnection requests.
nmcli -p con up uuid $uuid_str #Retry the VPN
fi
done
}
connectVPN
sleep 5 #Give the connection time to stabelize before continueing.


# Run the program and get its process ID number.
#------------------------------------------------------------------------------
# Note: Here a string can not be used to represent the program because the name
# of the string will be stored as the job name instead of the program name. So
# instead a variable is used to store the name of the program (see line 8).
$progID &
sleep 5
btID=`pgrep $progID` #changed from 'pidof' because 'pidof' quit working.
sleep 2


date
#Monitor the connection for discconnections and secure VPN dependancies.
#------------------------------------------------------------------------------
while true; do
vpnstring=$(nmcli -t -f VPN con status|grep -c yes) #Define a string to test, 0 = no connection, 1 = connected.

case $vpnstring in #Test the connection string.
"0")
date
echo "VPN disconnected. Stoping VPN dependancies"
kill -SIGSTOP $btID #Connection lost stop the VPN dependancy.
echo "VPN dependancies stopped."
jobs

connectVPN
echo "VPN dependencies restarted." #Placed here so it wont be endlessly repeated in the outer loop.
date
;;
"1")
kill -SIGCONT $btID
;;
esac

sleep 5
done


Notes:
Each section of the above code is delimited by a commented out dashed line as:
#------------------------------------------------------------------------------
There are 3 sections in the above code:
1.) The VPN is connected if it isn't connected already.
2.) The program that is dependent on the VPN's connection status is started and its process ID is captured.
3.) The VPNs connection status is monitored via a simple loop, and if it ever looses the connection, the dependent program is stopped until the connection can be re-established.
Also note there are two different types of single quotes being used in this script as stated in an earlier post.

In earlier comments it was reported that this code throws an environment variable error message. I'm not sure why that would happen. I have a default Ubuntu 12.04 system and this code works fine when I tested it in terminal. If you're testing this script and you get an error, can you please include how you were using the script and what command interpreter your terminal is using?

To find out what command interpreter you are using you could try doing the following from a command line:
ps h -p $$ -o args='' | cut -f1 -d' '

The above command was obtained from: "How to detect command interpreter from within a shell" (http://unix.stackexchange.com/questions/37809/how-to-detect-command-interpreter-from-within-a-shell-script)
Here is a description of each part of the above command (there is probably a much faster / more simple to do this query but, I just grabbed one of the first google results which worked for me):
ps: gives a process list
h: do not print column headers
-p: list only the process id (PID) of each program that is running.
$$: replaced by the shell with current PID
-o args: print the command line, no other information
cut: cut the output into parts
-f1: print only the first field
-d' ': use a space as a field separator

If you get "bash" as the output of the command described above then the script in this post should work.
I'm not familiar with other command interpreters so I can't be sure as to how this script will behave when used with anything other then bash.

Launcher Icon Creation: (very step by step instructions for Gnome3).
If you are using Ubuntu with a Gnome3 desktop (or possibly any other OS with a Gnome3 desktop) here are the steps I used to create an icon to launch this script in a terminal with one click.
You should only do this step if you have determined that this script will work for you. (Check "To use this script" earlier in this post to see if it will work).
1.) I did a search for an icon for the program that depends on the VPN connection.
2.) I opened up gimp and edited this icon to look the way I wanted it to look.
3.) I saved the program someplace logical where I could find it if I thought to look for it again later.
4.) I opened up Alacarte ([sudo apt-get install alacarte] if you don't have it installed already, or [ALT+F2] then "alacarte" if you already have it installed).
5.) Select an appropriate group to place the launcher in (in my case I selected the "Internet" group (left hand panel)).
6.) Select [New Item] button (second button down from the top, on the right hand side of the window).
7.) In the window that opens there is an icon in the upper left. Clicking on this allows you to select an icon to associate with the program. Here I selected the icon that was saved in step 3 above.
8.) Type: "Application in Terminal".
9.) Name: Here I used whatever name I wanted to associate with the script. So for example if you are using a bit torrent client you could type "qbtscript" or something like this for the name here.
10.) Command: Here we enter what we used for step 4 from "To use this script" earlier in this post.
11.) Comment: This is optional and just serves as a short description of the icon.
12.) Click save and close alacarte.
13.) Open the overview screen (again this short tutorial is for Gnome3, moving the mouse to the upper left corner opens the overview screen).
14.) Type the name you gave in step 9. You should see the icon you created and saved in steps 2 and 3 of this list of steps. Click hold, drag, and drop this icon into your list of favorites (left hand side of the screen for a default Gnome3 desktop in Ubuntu 12.04) and from this point on all you need to do is click on this icon, to start the script. A terminal window will automatically open and run the script.

Thanks again for all you're comments and help in creating this script.

famewolf
November 17th, 2014, 10:43 AM
[Final Update:]
As far as I can tell the script seems to be working fine now.

There is still no way to check if it actually stops the program since "jobs" doesn't produce any output, but since the program appears to be frozen during the time period when it should be stopped I'm assuming its stopped.

Here is the final version of the script as a reference in case any one cares to use it:


#!/bin/bash
#This program stops a program when your VPN connection is lost then restarts it after the connection is re-established.

#Attmept an initial connection until connected
function connectVPN()
{
while : #If the connection is just started or lost, try to reconnect then break out once connected.
do
connected=`nmcli -t -f VPN con status |grep yes` #Store the current state of the VPN connection.
if [ "$connected" = "yes" ]; then
break
else
echo "Attempting VPN connection in 10 seconds."
sleep 10 #Give the VPN time to recover so we don't abuse it with reconnection requests.
nmcli -p con up uuid 07d345f0-3cb4-4b59-ba2b-7fdf9717e50a #Retry the VPN
fi
done
}
connectVPN

myprogram01 & #Note: can not use a string to represent the program because the name of the string will be stored as the job name instead of the program name.
programID=`pidof myprogram01`

#Monitor the connection for discconnections and secure VPN dependancies.
date
while true; do
vpnstring=$(nmcli -t -f VPN con status|grep -c yes) #Define a string to test, 0 = no connection, 1 = connected.
case $vpnstring in #Test the connection string.
"0")
date
echo "VPN disconnected. Stoping VPN dependancies"
kill -SIGSTOP $programID #Connection lost stop the VPN dependancy.
echo "VPN dependancies stopped."
jobs

connectVPN
echo "VPN dependencies restarted." #Placed here so it wont be endlessly repeated in the outer loop.
date
;;
"1")
kill -SIGCONT $programID
;;
esac
sleep 5
done


Note: if you use this code, just change myprogram01 to whatever program you want stopped when your VPN connection is lost, and change the UUID of the VPN connection to match whatever UUID your computer assigns to your VPN connection.

Thanks again to CynicRus and all the others who helped me on this project. It would have taken a lot longer to complete without your help. Thank you.


While "pidof transmission-gtk" works just fine "pidof btsync-gui" fails because in a ps aux it shows up as "python /usr/bin/btsync-gui" so how do I get it to give me the correct pid to kill the task?

spjackson
November 17th, 2014, 11:06 AM
While "pidof transmission-gtk" works just fine "pidof btsync-gui" fails because in a ps aux it shows up as "python /usr/bin/btsync-gui" so how do I get it to give me the correct pid to kill the task?
"pidof -x btsync-gui" should do it.