I have coded a small script (a few thousand lines) which some of my friends use to do a few things on their computers. Since I update the script at least once a month, I realize that it is quite difficult to distribute a new version of my script to everyone who is using an older version. Hence, I would like to add a method to do the following:
Script checks for Internet connection (prompts error if not available, the quits)
If Internet connection is avaialble, it checks for a new version of my script (non-public URL)
If a new version of the script is available, it overwrites itself with the new version and tells the user
If no newer version exists, it tells the user that it is the latest version and continues as usual
I know, I could just try for hours to code that now. And I could even crawl the interwebz for a few days. But maybe you’re so kind to just tell me?
Personally, I would be very reluctant to use such a script. If I had to use it, then I would probably edit it, and remove the self-upgrading part first before I could trust it.
Assuming that the script is on a public site, you could presumably use “wget” to fetch the new version. But you should then check a gpg signature or similar, before installing.
Ok, fair. I understand your security concerns, but people that do use my script know it is trustable. Now back to the hard stuff: How to accomplish all of the things mentioned within the OP? Of course it would be awesome if I could add some sort of self-check into the script which compares its own checksum against a value that I previously defined. Please send some code!
IMO you’re asking about a very common type of app…
Just substitute “app” for your specifying “bash” and it’s one of the most common functions you’ll find everywhere, the need for apps to be updated in a trusted way.
You’ll find that although you can roll your own, if you have limited experience in designing this type of thing you may make mistakes and as nrickert suggests, the consequnces can be horrendous… you could provide a malware vector on your client’s/friends’ machines and your reputation would be crushed.
If you decided to use a pre-built system, I’d recommend you look at various packaging systems… Some (admittedly not the majority) will have it built in. Mobile app build systems (particularly online) often offer this as an optional service.
If you roll your own, there are examples all around you… Take for instance the Linux package management/repo system. Observe what happens when Apper or “zypper up” runs. In general, you need
A way to authenticate and authorize the proposed app update. Nowadays, certificates are commonly used.
If your updates are large, you may want to look into incremental differences instead of replacing the entire app’s code. This cuts down on bandwidth usage and disk usage, but can be complex.
A more advanced approach (like Microsoft’s BITS) which AFAICSee isn’t implemented in Linux distros is to run the process as a background, low priority service so that you can automate while also be unobtrusive.
Depending on how critical the app is and the method of file transfer, you may want to checksum the file for integrity before you install the new file.
Thanks, don’t worry about all that. All that I’m asking for is a simple way of letting my script check for newer versions and if one exists overwrite and re-start itself. Please don’t give any more security concerns or things I shall worry about. I take full responsibility for what I do. Please just post a few lines of code that I can plug into my script so that it updates itself. THANKS!
On 2014-06-30 11:56, SecUpwN wrote:
>
> tsu2;2651430 Wrote:
>>
>> …
>> You’ll find that although you can roll your own, if you have limited
>> experience in designing this type of thing you may make mistakes and as
>> nrickert suggests, the consequnces can be horrendous… you could
>> provide a malware vector on your client’s/friends’ machines and your
>> reputation would be crushed.
>> …
> Thanks, don’t worry about all that. All that I’m asking for is a simple
> way of letting my script check for newer versions and if one exists
> overwrite and re-start itself. Please don’t give any more security
> concerns or things I shall worry about. I take full responsibility for
> what I do. Please just post a few lines of code that I can plug into my
> script so that it updates itself. THANKS!
I don’t have such a code. However, notice that replacing a script while
it is running can make it crash or execute the wrong things. You have
instead to call a second script which does it.
For instance, use a wrapper script that does the checking and
downloading, then calls the actual script.
If not… well, the main script can download the new version to another
name (perhaps the file with version appended). At the end, perhaps
change a symlink, or create a second script, transfer full control to it
(no return), and the second script does the old-new swapping, and calls
the new one (with no return).
But I would add some checksum or signature.
–
Cheers / Saludos,
Carlos E. R.
(from 13.1 x86_64 “Bottle” at Telcontar)
if curl -Lsf google.com >/dev/null; then
echo "Puh, its up!"
else
echo 'Cannot connect to the interwebz, Check your network settings.' >&2
exit 1
fi
see
curl --help
for the options, in your case you could add an elif and point curl to the url where your script resides. For the version check you can use wget as it was suggested to you but have a look at the
--spider
option. Also curl has a lot of options you just gonna have to dig through it ;).
Forgot to add that if you got an error running the first code in an interactive shell, meaning not using a script and the error says something like
bash: !": event not found
You can work around that by running
set +o histexpand
Then you can run that first code using your shell without having such error. Remember it will error out only on an interactive shell and not on script. History expansion is enabled by default on openSUSE and that is what triggering it.
if curl -Lsf google.com >/dev/null; then echo "Puh, its up!"; else echo 'Cannot connect to the interwebz, Check your network settings.' >&2; return 1; fi
bash: !": event not found
With histexpand disabled.
set +o histexpand
if curl -Lsf google.com >/dev/null; then echo "Puh, its up!"; else echo 'Cannot connect to the interwebz, Check your network settings.' >&2; return 1; fi
Puh, its up!
checkurl() {
command -p curl -Lsf "$1" >/dev/null
}
if checkurl google.com ; then
if checkurl **your-secret-url-here.com**; then
**FIGURE-OUT-HOWTO-CHECK-VERSION-AND-UPDATE-HERE**
else
echo 'secret-url.com seems to be down' >&2
exit $?
fi
else
echo 'Cannot connect to the interwebz, Check your network settings.' >&2
exit $?
fi
That is how i would do it, but some folks might have some better idea and this is probably sticks and stones compare to some existing tools out there :).
Not satisfied with my previous suggestion? I have some more idea :).
You can use the so called warn and die functions so you don’t need to process the if and statement and just exit immediately if there is no connection either on the interwebz or your own secret url.
warn() {
printf '%s
' "$@" >&2;
}
die() {
local st="$?"
warn "$@"
exit "$st"
}
checkurl() {
command -p curl -Lsf "$1" >/dev/null
}
checkurl google.com || die 'Cannot connect to the interwebz, Check your network settings!'
checkurl **your-secret-url-here** || die 'Your **your-secret-url**, seems to be down!'
For checking/comparing the version, you can probably put that value in a variable.
I might use the diff utility(My general approach has always been to consider if off the shelf building blocks exist before rolling my own).
Assuming that the file on the network is “latest” then it should be pretty simple…
Use whatever means you prefer to make a network connection to the file on the network.
Diff the remote and local copies
If not the same, then download and install the network file.
I doubt you need to look at other file attributes like date/time, whatever, particularly for a text file.
Do you need actual code? I’d assume that the above steps should give you plenty of leeway for choice as well as being fairly self-explanatory. I’d be surprised if a simple implementation would require more than about 6 lines of code.
Thanks for your awesome suggestions, jetchisel! You rock! I will incorporate them as fast as possible. Just another small question: Since some of my users are having a limited data plan and would like my script to only run once a certain speed is available, can we add some sort of speed-test which runs during the heck for an active internet connection?
> Just another small question: Since
> some of my users are having a limited data plan and would like my script
> to only run once a certain speed is available, can we add some sort of
> speed-test which runs during the heck for an active internet connection?
A speed test uses bandwidth. Ie, it is done by actually sending or
downloading something and timing it. And usually, these connections also
have a cap limit on the monthly amount of data they can download, so the
test uses some of that cap - meaning I would not do it.
What can be done is checking what is the internet interface in use, the
name. If you use a usb dongle while on a mobile data plan, vs a wifi or
eth connection at home or office, they are identifiable.
On other setups, the network IP changes, so detect that. I’m considering
on using this trick, while tethering to my mobile phone. The easiest, if
possible, would be to trick a script from the network manager, but I
don’t know how to do this.
If not, you have to ask those people to manually create a certain flag
file when the cap is active.
–
Cheers / Saludos,
Carlos E. R.
(from 13.1 x86_64 “Bottle” at Telcontar)
Us ping to send ICMP echo messages to a website (like yours,) when the script first starts itself for the first time. Have your script write out the round trip time to a file. Have the script read the file each time it starts and then ping the same host and compare the results. ping does not use much bandwidth so there should be no concerns there.
This is a quick hack, it will not always work and it will sometimes hang because your doing UDP.
if -f time-it-takes.txt ]; do
{
# MAy need to be sudo ping ...
ping -c 1 address | grep -E -o 'time :digit:]]+ ms' > tmp;
tmp=`grep -E -o ':digit:]]+' tmp`
time=`grep -E -o ':digit:]]+' time-it-takes.txt`
# Note that you should test for equality.
if $a > $b ]]; do
{
# Super update function
}
}
else
{
# Data file not there, assuming that this is the first run.
ping -c 1 address > time-it-takes.txt;
}
You DID ask for it! AND DO NOT forget the security concerns!