Prevent user processes from running away with all system resources
Whether intentionally or accidentally, it is entirely possible for a single user to use up all system resources, leading to poor performance or outright system failure. One frequently overlooked way to deal with resource hogs is to use the ulimit functionality of bash.
To prevent a process (or any of its children) from creating enormous files, try specifying a ulimit -f (with the maximum file size specified in kilobytes).
rob@catlin:/tmp$ ulimit -f 100 rob@catlin:/tmp$ yes 'Spam spam spam spam SPAM!' > spam.txt File size limit exceeded rob@catlin:/tmp$ ls -l spam.txt -rw-r--r-- 1 rob users 102400 Sep 4 17:05 spam.txt rob@catlin:/tmp$
Users can decrease their own limits, but not increase them (as with nice and renice). This means that ulimits set in /etc/profile cannot be increased later by users other than root:
rob@catlin:/tmp$ ulimit -f unlimited bash: ulimit: cannot modify limit: Operation not permitted
Note that nothing is preventing a user from creating many files, all as big as their ulimit allows. Users with this particular temperament should be escorted to a back room and introduced to your favorite LART. Or alternately, you could look into introducing disk quotas (although this is usually less than fun to implement, if a simple stern talking to will fix the problem).
Likewise, ulimit can limit the maximum number of children that a single user can spawn:
rob@catlin:~$ cat > lots-o-procs #!/bin/bash export RUN=$((RUN + 1)) echo $RUN... $0 ^D rob@catlin:~$ ulimit -u 10 rob@catlin:~$ ./lots-o-procs 1... 2... 3... 4... 5... 6... 7... 8... 9... ./lots-o-procs: fork: Resource temporarily unavailable rob@catlin:~$
This limits the number of processes for a single user across all terminals (and back grounded processes). It has to be this way, because once a process is forked, it disassociates itself from the controlling terminal. (And how would you count it against a given subshell then?)
One other very useful ulimit option is -v, maximum virtual memory size. Once this ceiling is reached, processes will exit with Segmentation fault (which isn't ideal, but will keep the system from crashing as it runs out of RAM and swap). If you have a particularly badly behaving process that shows significant bloat (like Apache + mod_perl and poorly written CGI code, for example) you could set a ulimit to act as an "emergency brake" while debugging the real source of the trouble. Again, specify the limit in kilobytes.
To see all available ulimit settings, use -a:
rob@catlin:~$ ulimit -a core file size (blocks) 0 data seg size (kbytes) unlimited file size (blocks) unlimited max locked memory (kbytes) unlimited max memory size (kbytes) unlimited open files 1024 pipe size (512 bytes) 8 stack size (kbytes) 8192 cpu time (seconds) unlimited max user processes 1536 virtual memory (kbytes) unlimited
You can see that before setting system-wide hard limits, user processes can grow to be quite large. In tcsh, the analogous command you're after is limit:
rob@catlin:~> limit cputime unlimited filesize unlimited datasize unlimited stacksize 8192 kbytes coredumpsize 0 kbytes memoryuse unlimited descriptors 1024 memorylocked unlimited maxproc 1536 openfiles 1024
Setting system resource limits may sound draconian but is a much better alternative to the downward spiral of a user process gone amok.