Steam For Linux Bug Wipes Out All of a User's Files 329
An anonymous reader sends a report of a bug in Steam's Linux client that will accidentally wipe all of a user's files if they move their Steam folder. According to the bug report:
I launched steam. It did not launch, it offered to let me browse, and still could not find it when I pointed to the new location. Steam crashed. I restarted it. It re-installed itself and everything looked great. Until I looked and saw that steam had apparently deleted everything owned by my user recursively from the root directory. Including my 3tb external drive I back everything up to that was mounted under /media.
Another user reported a similar problem — losing his home directory — and problems with the script were found: at some point, the Steam script sets $STEAMROOT as the directory containing all Steam's data, then runs rm -rf "$STEAMROOT/"* later on. If Steam has been moved, $STEAMROOT returns as empty, resulting in rm -rf "/"* which causes the unexpected deletion.
When I see that [literaly] textbook mistake.... (Score:5, Funny)
I can hear the Steam dev. shop manager:
Carl! Put the bullhorn down! Dave! Quit staring at Lucy and get back to wark! Kevin! We have to ship this code in TWO DAYS! Jerry! Don't point that over here!
Re:When I see that [literaly] textbook mistake.... (Score:5, Funny)
Larry! Quit sniffing glue and get back to writing that steam root mover script pronto!
Re:When I see that [literaly] textbook mistake.... (Score:5, Informative)
Really? Really doing a delete and you don't check the existence of the folder before you start? I am not a Unix/Linux scripting expert (just a very dangerous amateur), but, I always test to see if the directory is there before I even start my scripts. If the folder isn't there the script screams, rants and raves to the console and then stops before it even starts processing. Common code I do for most Z/OS BASH scripts at the start before I even run the rest of the script:
1. Is the folder(s) there that I need.
2. Do I have the proper access to the folder(s)/file(s).
If either two fail I dump to the console full information on what happened and what I think should be done to fix the problem.
It is a common set I use ->
Directory test:
if test -d $1
then
exit ;
else
uExit=128
fi;
File existence check:
if test -f $1
then
exit ;
else
uExit=128
fi;
Can I read the file:
if test -r $1
then
exit ;
else
uExit=128
fi;
Not pretty, probably can be coded better, but, this works for me and saved my ass a few times.
Comment removed (Score:5, Funny)
Re:When I see that [literaly] textbook mistake.... (Score:5, Insightful)
Yep, but, they should test to see if the variable has a value. I remember vaguely that I tested for something like that by appending a value to the end saving it to a new variable and then testing both the original and new and if the same it was null.
Re:When I see that [literaly] textbook mistake.... (Score:5, Insightful)
if [ -z "$STEAMROOT" ] ; then echo 'you fucking idiot what are you doing'; fi
Re:When I see that [literaly] textbook mistake.... (Score:4, Insightful)
Checking if STEAMROOT is an empty string is a good start, but it's still not enough. Anything that's unleashing something as dangerous as "rm -rf" should do a serious sanity check first. Looking at the text name of the directory, seeing if it's really a directory, or seeing if you can cd into it (and the output from pwd still matches) are all useful checks. But you will still find edge cases where they do terrible things in the real world.
As an example of something more robust, PostgreSQL does what it can to deal with this problem by having a file named PG_VERSION in every installed database directory tree. All utilities that do something scary take the directory provided and check to see if there's a PG_VERSION file in there. If not, abort, saying that the structure expected isn't there. Everything less complicated than that occasionally ate people's files. A common source of trouble here for database servers is when there was a race condition against a NFS mount, so that it showed up in the middle of when the script was running.
When you stare at that sort of problem long enough, no check for whether your incoming data is sensible is good enough. You must looking for a positive match on a "I see exactly the data I expect" test of the directory tree instead, before wiping out files in particular. Even the level of paranoia in Postgres is still not good enough in one case. It can wipe things if you run the new database initialization step and hit one of those mount race conditions. For that reason, the initialize database setup is never run in the init scripts anymore, no matter how many complaints we get that it should be automatic.
I first saw this class of bug in IBM's Directory software, in its RPM uninstaller. It asked RPM what directory the software was installed in, then ran "rm -rf $INSTALLDIR/data". Problem: RedHat 8.0 had a bug where that RPM query returned nothing. Guess what was in /data on the server? That's right, the 1TB of image data that server ran against. (And to put the scale of that into perspective...this was 2003, when 1TB was not a trivial amount)
Re:When I see that [literaly] textbook mistake.... (Score:5, Informative)
Re:When I see that [literaly] textbook mistake.... (Score:5, Interesting)
Does show a longstanding problem with the Unix security model, though: nothing more fine-grained than per-user permissions. There's no reason Steam should be able to delete (or even read) anything in my home directory other than its own files, but the only real way to keep it from doing so using straight Unix permissions is to create a new local user for every application.
Re:When I see that [literaly] textbook mistake.... (Score:5, Informative)
That's not a problem with the model, you should own everything in your home directory. One of the irritating things about Windows is that you can't necessarily delete all the files. Some of the files aren't deletable no matter what account you use, even being admin won't work.
In this case, giving the directory it's own Steam UID ownership would prevent Steam from deleting things that it shouldn't be deleting. You can then have the user be a member of the group that Steam belongs to and give that group the ability to change permissions. At which point, the desired behavior is easy and undesired behavior is much harder.
Why it is that people still have these kinds of issues is beyond me, the traditional model handles things like this without much trouble, as long as you actually know what you're doing.
Re: When I see that [literaly] textbook mistake... (Score:4, Interesting)
From what I understand, this is how Android works. Every app gets its own user and group.
It is also, sort of, how Docker works. Each app gets its own container, the app is completely bound to that container. Docker manages access to outside resources (like the network) for you, utilizing cgroups, and kernelspace drivers.
Re: When I see that [literaly] textbook mistake... (Score:4, Interesting)
I was hoping someone would mention Android.
Just a pity Android doesn't let you do anything meaningful with that well-designed permissions infrastructure...
For instance, you either trust an app with your entire contacts-list, or your contacts-list is out-of-bounds entirely. There no way to 'Add contact to app', and have that launch a trusted contact-selector utility.
Re:When I see that [literally] textbook mistake... (Score:3)
The better system is called capabilities. Think "everything is a file descriptor". You want to create a file, you get a file descriptor. You want to run most programs, you give them read-write scratch space, a place to find common library routines (that don't carry any rights by themselves), and probably a read-write access to some graphical interface window. You're a browser, your user clicks on a java applet? You download the applet into a descriptor from your scratch space, you run it, giving it a read-w
Re: When I see that [literaly] textbook mistake... (Score:5, Interesting)
That tends to be too restricted for things to actually run, alas. For example, something in a chroot can't even see libc or use standard Unix utilities on its own files, because /lib and /bin are outside of the chroot. You end up having to install a whole second copy of Linux inside the chroot...
Re: When I see that [literaly] textbook mistake... (Score:5, Funny)
Re:When I see that [literaly] textbook mistake.... (Score:5, Insightful)
OSX sandboxed apps cannot look outside of their own directories. However, when the user chooses a file via the "Open" dialog, the application is given a handle that allows it to open just that particular file. Sandboxing really is the solution to this kind of mess...
Re: (Score:2, Informative)
It also deleted everything on his mounted external hard drive.
Re: (Score:3)
Which is why always-online drives with no special protection are a dumb idea for backups.
Re: (Score:2)
how about:
if [ ! -z "$STEAMROOT" ]
then...
Re: (Score:3)
Re: (Score:2)
The only remedy would be to have a specific gaming account.
Then only files which that account had write access to would have been in danger.
Even better is to run under 'chroot' to protect from such mistakes. 'chroot' isn't perfect, but at least it makes it harder to mess up.
And that people... (Score:5, Insightful)
Re:And that people... (Score:5, Insightful)
And also, why redundancy is not backup. If your backup is plugged in and/or mounted, it's not a backup any more.
Re:And that people... (Score:5, Interesting)
It is. It just protects against fewer problems.
Every type of backup method has drawbacks and benefits.
If there existed a perfect backup method, we would have only that method.
Redundancy makes it very easy and fast to recover data, but lacks security against localized physical problems and malicious software. It would be a perfectly valid first layer of backup and sufficient for backing up reproducable information such as downloaded/scanned/ripped media. It protects against accidentally deleting files or hardware problems. For less easily reproducable information you probably want some additional backup layers.
Re: (Score:3)
That's not strictly true anymore. True, a RAID user would've been screwed in this scenario. But newer redundant filesystems like ZFS and btrfs support snapshots, which would in fact have made this situation recoverable. Provided you were generating snapshots at regular intervals.
Re:And that people... (Score:5, Insightful)
so if you have 1 you have 0.
Dude, what does that even mean? Backups have to be done intelligently based on your situation. In the summary, the user had an external hard disk on USB which would have protected against primary HD failure, but not against common mode failures such as a fire at home or a compromised PC. He didn't protect himself against malicious code, and got burned. The raw number of backups don't matter if you're not paying attention to what you are and are not protecting against.
Re: (Score:2)
Ah, but you're not factoring in the perversity of the universe - having absolutely critical files destroyed in one location increases the odds that an unrelated event will have destroyed your only backup by at least three and as many as seven orders of magnitude. Each additional backup reduces that chance (per backup) by one to two orders of magnitude, depending on the exact degree of reliability: higher reliability spits in the face of Fate, which pisses her off and increases the odds that she'll arrange
Re: (Score:2)
It obviously means "assume one backup is bad". Backup media fails too after all.
Sure that's not enough for a silver bullet. But can you really not understand that simple statement (you don't have to agree of course)?
Re:And that people... (Score:5, Insightful)
Did you read the part where it also erased his backups?
I think the moral here is, don't leave your backup drive plugged in when you're not running backups.
Re:And that people... (Score:5, Informative)
Re: (Score:3)
They were not backups. If they're plugged in, they're merely redundancy.
Re:And that people... (Score:5, Insightful)
Re: (Score:3)
You can use NFS to mount volumes readonly that are only writable by root when a backup is performed. That way the world rest of the users get continuous online access and the only way to accidentally delete is to have root privileges in a narrow window of time.
Re: (Score:3)
Re: (Score:3)
Nice setup. I'd go a step further and buy a HD for a trusted friend and rsync a snapshot of my home dir to their box, gnupg encrypted if you want.
There's also AWS Glacier that I use for semi-annual dumps for photo archives and other things that don't change. The SAGU java client is relatively straightforward, and I save the manifest in 1-2 cloud storage services. I think 10GB worth of stuff is costing me about 47 per month... most of the cost is just incurred during retrieval, so it's a pretty good deal
Re: (Score:2)
47 (cents), /. ate my unicode
Re: (Score:3)
So even though they are not unplugged, they are either read-only or not mounted. Also data is available on two devices. So even if one explodes, the other is still there. No, I do not do offsite backup. If my house burns down, I have bigger issues then data.
Depends what that data is -- when my sister lost her house in a fire (even the fire safe melted, all that was left was the fireplace and half of the 1920's era cast iron stove), she lost a *lot* of irreplaceable photos that she had scanned in over the years. Hundreds of old family photos dating back nearly 100 years -- she had the originals carefully packed away for safe keeping. Fortunately, most of her more recent photos were also stored in online photo albums so those were saved.
She was smart enough to k
Re:And that people... (Score:5, Funny)
Is why you have backups. You need to apply the rule Total Backups = Total Backups -1
so if you have 1 you have 0.
So...apparently I have -1 backups, does this mean I owe the universe a backup?
Re:And that people... (Score:5, Funny)
Or you have underflowed, and have 4,294,967,295 backups.
Re: (Score:2)
I have Linux. I use deja dupe :)
one month later (20 Tb)
I have Linux. I use deja dupe :(
Re: (Score:2)
One keeps backups to protect themselves against such horrible, very rookie mistakes. They happen. Yes we can rage about how it shouldn't have happened, and yes someone at steam should get slapped, and yes "everyone should have backups" doesn't lessen the reality of what happened here, but having backups is still a good idea and is the difference between an inconvenience and sobbing in the corner when something like this happens.
Gotta love Valve (Score:4, Funny)
Screw over people on Windows with micro-transactions and useless updates, screw over people on Mac with games that run poorly, screw over people on Linux by wiping files. It's like, the less popular your OS of choice, the more shafting you get.
All part of the Steam Doomsday Device (Score:5, Funny)
Attention user, Steam has detected unusual activity on your part that could be construed as part of an effort to hack Steam. Therefore, Steam has deployed the Doomsday Device on your machine. You now have 5 minutes to either comply with out request to restore Steam to its original folder or to send a bionic person to shut down the Doomsday Device at the source. Otherwise, your system will be wiped and FBI agents will be arriving at your home shortly. Please keep your hands in the yellow circles pending their arrival. And thank you for using Steam!
Re: (Score:2)
That just made my morning, ha.
Re:All part of the Steam Doomsday Device (Score:5, Funny)
Negative. I am a meat Popscicle.
The Steam user is one door down.
Re: (Score:2)
We must not allow a secrecy gap!
Wow (Score:2)
Wow! That is all.
I hope no one runs steam as root. (Score:2)
OTOH, running it on an SeLinux system would probably contain the damage.
Re:I hope no one runs steam as root. (Score:5, Insightful)
Who cares about root! My home directory is WAY more important than the system.
Re:I hope no one runs steam as root. (Score:4, Insightful)
Who cares about root! My home directory is WAY more important than the system.
This is a fairly serious hole in a lot of traditional security mechanisms, blowing away the entire OS is easy, replacing the documents that any process running as you can scribble on is hard; but SELinux could definitely be used to contain the damage in a situation like this.
With SELinux, even if Steam is running as the user, its process could run in a different domain, and have access exclusively to files in the appropriate security context(presumably only the ones it created in the first place).
You could also use the hackier; but simpler, method of running the steam process under a different user account; but(especially once X enters the picture and you want integration with your DE's menus and whatnot) that gets kind of gross.
Re: (Score:2)
Re: (Score:2)
How would that have contained the damage? His home directory files are what is important not the system files.
First day of *nix training... (Score:4, Informative)
Okay children, I'm going to teach you this command explicitly so that you know what you never, ever, EVER - wake up little Johnny - what was I saying? Oh yeah, ever, ever use it.
Seriously. Don't use it.
Re:First day of *nix training... (Score:5, Funny)
Has anyone actually gone into root and executed the command-that-shall-not-be-named? It's like being in a slow-motion train-wreck. I'd like to say I did it once just to see what would happen, but that would be a lie. I was a fresh-faced admin on a Solaris workstation with root access cleaning up the hard drive of extraneous data. Imagine the scene: the finger comes down in slow motion, the Enter key depresses and a few microseconds after, everything speeds up to real time as the brain realizes what just happened. That little bit of skin between your legs crushes up and you feel like your guts are falling out of your body. You rapidly try to find the process and kill it before those very commands get wiped, but it's too late....
Re: (Score:3)
The best part is that since the deletion normally runs alphabetically, one of the first files taken out is /bin/kill
m -rf "$STEAMROOT/"* ??? (Score:3, Informative)
But still for extra points the script should have asked to run as root...
And a little advice to Valve, next time have developers familiar with Linux working on your Linux client. That
Re: (Score:2)
Re: (Score:2)
Re: (Score:2)
Re: (Score:2)
I think the problem is that it's written in .NET and has to fire up the whole .NET environment, just like how a Java app has to fire up the JVM to start, which puts a (rather large) lower bound on the amount of resources an application needs.
Steam isn't written in .NET... I'm not sure where you would ever get the idea that it was.
As for the browser component, it uses Chromium Embedded Framework. However, I don't think it was ever upgraded to version 3.
Re: (Score:2)
And a little advice to Valve, next time have developers familiar with Linux working on your Linux client. That /* is how a Windows developer would write the command to delete a directory if they simply looked up the equivalent command for Linux.
A competent Windows developer would probably just write: /Q /S "%STEAMROOT%"
if exist "%STEAMROOT%" rmdir
no dangerous glob needed.
It kind of floors me that they aren't doing some kind of check that the directory tree they are about to delete actually looks like a Steam install before deleting it. e.g. check that ClientRegistry.blob file or SteamApps directory exists under $STEAMHOME.
Re: (Score:2)
It kind of floors me that they aren't doing some kind of check that the directory tree they are about to delete actually looks like a Steam install before deleting it. e.g. check that ClientRegistry.blob file or SteamApps directory exists under $STEAMHOME.
ClientRegistry.blob isn't used by Steam any more and thus won't exist if you've installed Steam in the past 9 months or so
Would the Steam directory even have a SteamApps directory if you're using Steam's library feature to install all games to a different path?
While we're at it, is it SteamApps, steamapps, or some other variation of capitalization? That kinda matters on Linux.
Re: (Score:2)
Why would you want to leave the directory?
Re: (Score:3)
Most folks don't take Linux seriously at all.
Not the first time (Score:5, Informative)
Apple had a bug like that in the iTunes installer sometime back that did exactly that: a rm -rf from root as root. Theirs came from if you had a space in your hard drive name.
Re: (Score:2)
Ohh, and isn't "Macintosh HD" the default name? Ouch!
Re:Not the first time (Score:5, Informative)
It was in the updater for iTunes 2, and if you a) had your library on a second hard drive and b) if the hard drive had a space for the *first character* of the name (eg, " Music") it would erase the drive.
http://www.xlr8yourmac.com/OSX... [xlr8yourmac.com]
A few if statements needed... (Score:5, Informative)
Something like this might have helped:
if [ "$STEAMROOT" != "" -a "$STEAMROOT" != "/" ] ...do your evil deletion of $STEAMROOT here
then
if [ -d "$STEAMROOT" ]
then
fi
fi
Should avoid at least a full deletion traversal of the filestore, but it's still got a risk that $STEAMROOT might be ~username (or /tmp, which is less critical).
Re: (Score:2)
#!/bin/bash
function getSedExtRegexArg()
{
if isMacOsX
then
# All I want to do is echo '-E', but echo is too clever for that.
printf '%s' '-E'
else
echo '-r'
fi
}
function isMacOsX()
{
[[ "$( uname )" == 'Darw
Simple fix (Score:2)
They just left out the ampersand.
Easy fix.
--no-preserve-root (Score:2)
I would figure that --no-preserve-root would be required to delete root directory?
Shades of Sierra (Score:3)
Remember back in the day when the Sierra uninstall utility could accidentally delete all your files? I think that was a result if you put it in a non-standard location, too.
Taking lessons from Intuit, I see (Score:3)
A few years ago, Inuit released an online update to Quickbooks for Mac that effed your entire partition. I happened to be away on a business trip when this happened and I had to have my backup drive FedExed to me. Did Intuit offer to pay for that? Hell no. Did anyone file a class action suit? Who knows, but even if they did, I'd have gotten discounts for coupons for cellphone cases or something equally useless.
man rm (Score:5, Interesting)
From the rm(1) man page on most Linux distros:
--no-preserve-root do not treat '/' specially (the default)
--preserve-root
fail to operate recursively on '/'
Why --preserve-root isn't the default is beyond me, since it would be generally faster to re-create the filesystem if that's what you _really_ wanted.
Re: (Score:3)
From Fedora 20:
--preserve-root
do not remove '/' (default)
Re: (Score:3, Insightful)
That doesn't matter in this case, since "rm -rf /*" is trying to delete all the subdirectories of /, not / itself.
The rm command sees the command as this (for my machine):
rm -rf /bin /boot /dev /etc /home /initrd.img /initrd.img.old /lib /lib32 /lib64 /libx32 /lost+found /media /mnt /opt /proc /root /run /sbin /srv /sys /tmp /usr /var /vmlinuz /vmlinuz.old
Re:man rm (Score:5, Informative)
Not that it would've helped in this case.
rm -rf $var/* has two flaws. The first is if $var is blank or undefined. The second is the extra unnecessary /* that circumvents --preserve-root.
Oooh, I almost caused this in a product once too. (Score:2, Interesting)
I had a similar situation in a product I was working on once where it was a PHP script with an undefined variable. It was the exactly same result: rm -rf /
Fortunately a QA guy caused it while testing. It was hell to figure out what happened because it was running as room and had wiped the entire system.
Re: (Score:2, Informative)
Rule #1, don't run as room. Room contains all the stuff.
A lesson. (Score:2)
Backup drive (Score:3)
> steam had apparently deleted everything owned by my user recursively from the root directory. Including my 3tb external drive I back everything up to that was mounted under /media.
All together now: This is why we disconnect our backup drive when we're not backing up the system!
set -o nounset (Score:2)
This is why you should have
set -o nounset
set -o errexit
at the top of every bash script. Also no one should be allowed to write a bash script unless they have read http://www.davidpashley.com/ar... [davidpashley.com]
Why is this not surprising? (Score:2)
When TF2 has critical bugs that are still in it after 7 years and issues like the Strange PDA Engie Upgrade Bug that has been in the product for over a year, it amazes me that these guys are still going.
It just looks like they are running by the skin of their teeth since there are FREQUENT issues that are dangerous as hell or that stay in the product for ages.
Every new release of TF2 seems to add new bugs and they spend more time putting in new hats than fixing outstanding issues. This reeks of shitty soft
What's a good approach... (Score:2)
OMG! (Score:2)
Re: (Score:2)
Files can be opened append only.
This involves writes on the underlying device.
Files can be deleted.
This involves writes on the underlying device.
Files can be overwritten with junk content.
This involves writes on the underlying device.
The underlying device has no concept of what it's actually DOING with the data it's given. That's up to the filesystem. So devices have precisely two "permissions". Read. Write.
The safeguards should be in the filesystem, but the filesystem people will tell you "That's what
some poor person... (Score:2)
This looks like a job for... (Score:2)
$ man rm
Where's "rm --preserve-root" when you need it?
Folder issue on OS X (Score:2)
I had a problem with th OS X version of steam. Client updates failed when placing the program in a different folder than applications.
My hack to rm.c (Score:3)
{
}
/* INSERT THIS */
if( x.interactive == RMI_NEVER && x.ignore_missing_files == true && x.recursive == true ) {
char *mayi = getenv("RM_ALLOWRF");
if(mayi && strcmp(mayi,"YES")) {
printf("rm -rf allowed\n");
} else {
printf("rm -rf not allowed (set RM_ALOWRF=YES to enable)\n");
exit(EXIT_FAILURE);
}
}
/* END INSERT */
if (argc <= optind)
{
...
Windows installer has a similar "feature" (Score:4, Insightful)
The Windows installer has a similar issue and apparently it is not even considered as a problem (red box):
https://support.steampowered.c... [steampowered.com]
This reeks of serious incompetence or negligence, in my opinion - writing installers that blindly mass-erase files instead of tracking which files did the software actually install and erase only those on uninstall/move is not acceptable in my book. Whether or not it is documented in some disclaimer that nobody reads or not is irrelevant. This really is asking for a lawsuit if someone gets seriously bitten by it.
I really wonder what the devs at Valve were smoking when they consider this as acceptable.
shell scripts (Score:4, Funny)
And yet some people still cling on to shell scripts for their boot system.
Re:unexpected deletion (Score:5, Funny)
They need to have system administrators working for them, apparently. Not using that command is so ingrained, that I have the nightmare where I type "rm -rf /" in a console instead of the dream where you are naked in front of the class, or the one where you didn't study for finals.
I also have the one where I run the endless loop of opening more and more xterms until my SPARCstation falls over.
Re: (Score:3)
Not using that command is so ingrained, that I have the nightmare where I type "rm -rf /" in a console instead of the dream where you are naked in front of the class, or the one where you didn't study for finals.
You could also do what I did once, and accidentally hit space in the command and not notice.
rm -rf a/bunch/of/local/junk /
Except that's not quite right. What I actually did was:
sudo rm -rf /usr/local/dontremember /bin
Re:unexpected deletion (Score:5, Funny)
rm -rf .*
The key fact is that .. matches .*
Re: (Score:2)
yet as a proprietary application expects in this case to invoke the GPL mantra of usability without warranty
If you think the GPL invented that mantra, you must be smoking the good stuff. All (normal COTS) software comes with the "we take as little legal responsibility as at all possible" and it's because of crackpot legal systems like the US. Be glad that you can just throw software out there, otherwise writing software would be high liability sport only for those with deep pockets or nothing to lose.
Re:arguably steam isnt for linux. (Score:5, Insightful)
You can get software that promises more; but it will cost you mightily.
Re:arguably steam isnt for linux. (Score:4, Insightful)
I could have sworn that that mantra appeared in BSD licenses well before the GPL was a twinkle in RMS' eye. Yep. [wikipedia.org]
If I cared to research it, I'm certain I would find similar language in proprietary licenses which predate even that.
Your distinction between "on" and "for" is equally myopic and artificial. Binaries "for" an operating system is used so commonly it is only questioned by ideological zealots, which most of us are not.
Re: (Score:2)
Steam is manythings including spyware, malware, and even a rootkit.
[Citation Needed]
Re: (Score:2)
"set -o nounset" at the top of your bash script. Then bash acts a bit more like a real programming language, and gives an error if a variable is not set. More tips (and by 'tip' i mean pretty much essential knowledge) at http://www.davidpashley.com/ar... [davidpashley.com]