Managing PennMUSH

Managing PennMUSH javelin Wed, 2004-03-17 16:22

This book will replace the Guide for Gods "Running PennMUSH" section.


Backups javelin Sat, 2007-11-03 13:36

The God who didn't make backups: A parable (by Rhyanna)
Once upon a time, there was a God of a MUSH. It was a pleasant MUSH, of a medium size. It had just recently passed 5000 objects, and he was very proud. This God, though, was not taking backups of his database.

One day, then, calamity struck in the form of a socket programming project when required many people to use the MUSH's host and use many processes apiece. The MUSH crashed, and because there were no available processes, it truncated both the maildb and the indb to length 0.

That's the way it was told to me, but it was never very clear. But for ther purposes of the parable, it doesn't matter. Perhaps the disk head swung too close and plowed up slivers of aluminum from the spinning platter. Perhaps he ran afoul of a subtle and malignant bug with compression. The point is that he had not been making backups, and a stray accident had destroyed every copy of the database.

This would have spelled the death of many MUSHes. Many MUSHes that experience such a catastrophe never return at all. This one decided to try to rebuild, but even so, two of the wizards and far more of the players never returned, and the structure of the physical building and the roleplaying environment of the MUSH were never the same as they had been before.

The moral is left as an exercise for the reader.

A useful perl script: dated db-backups (Westley)

# external db file management for MU*
# Designed to be called by cron and make
# a backup of the db tagged with the date.
# Any given backup will be held for 7 days
# before being deleted by this program.
# usage: dbchk [-d(data directory)] [-s(save directory)] [-f(filename)]
# By Michael Baker (Inigo,,
# Modified by Chris Hardy (Westley), modified slightly by Alan Schwartz

# Set usage for use in error messages.
$usage = "dbchk [-d(data directory)] [-s(save directory)] [-f(filename)]\n";

# require/include the program
# to handle switch type arguments.
require '';

# Set default variables for db location
$directory = "~/game/data";
$savedir = "~/game/save";
$filename = "minimal.db.Z";

# Call Getopts (included earlier) to handle -d and -f switches
# the ':' following indicates that data follows the switch.
# Then process the data via if's.
&Getopts('d:f:s:') || die "$usage";

if ($opt_d) { $directory = $opt_d; }
if ($opt_f) { $filename = $opt_f; }
if ($opt_s) { $savedir = $opt_s; }

# Get the current time to stamp the backup with.
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time());
$filestamp = join("",$mon,$mday,$year);

# Make the backup of the db
system("cp $directory/$filename $savedir/$filename.$filestamp");

# This section removes the saves over 7 days old.
opendir(DATED,$savedir) || die "Unable to remove old backups.\n";
@files = readdir(DATED);
@files = grep(/$filename\./,@files);

while (shift(@files)) {
if (-M > 7) {
unlink($_) || warn "Unable to remove $_!\n";
exit 0;

Code management (by Talek)

Code management (by Talek) javelin Sat, 2007-11-03 13:30

Keeping track of code and all the modifications that have been done to it is an important part of maintaining any large system. I cannot overstress the importance of using a revision management system like RCS or SCCS for both the server and all important MUSHcode systems you have. The ability to easily undo a change can save you days of painful bughunting.

Editor's note: Or CVS, or prcs, or svn...

Converting a database from another server to PennMUSH

Converting a database from another server to PennMUSH javelin Wed, 2004-03-17 16:18

Moe from ChicagoMUSH writes:

I once did a rather elaborate conversion using @decomp to move from TM3.1 to Penn...It worked pretty well, here's a rough breakdown of what I did:

On the TM3.1 game, I did an @decomp of every object in the db,
sequentially, logging the WHOLE thing out. This way, the whole thing
would be recreated, in order, preserving dbrefs. And all the commands
that I 'created' the output for would get quoted in as commands to the
Penn game.

I then ran several @dol's to accomplish the following things:

  1. To create a series of commands that would relocate and re-link all exits:
    @dol search(type=exit)=think @tel ##=[home(##)];think @link ##=[loc(##)]        
  2. To create a series of commands that would relocate all objects and
    @dol search(type=player) [search(type=thing)]=think @tel ##=[loc(##)]
  3. To create a series of commands to correctly re-chown everything (I
    think TM3.1 has stats()):
    @dol lnum(0,first(stats()))=think @chown ##=[owner(##)];think @set ##=!halt     

I then did a bit of editing on the big flatfile with all of the output
of the above @dol's, so that flags/powers were appropriately renamed to
be reset, obvious function inconsistencies were corrected, etc. I also
compressed a lot of things so that multiple consecutive @set lines were
put into one @dol. Room #0 was redesc'ed off the bat.
Then, I started up a brutally vanilla Penn game, logged in with #1, and
quoted the flatfile of @decomp commands in. (Yay tf)

Truthfully, it took about a half hour to quote in a 3k-object db
flatfile. And truthfully, it took three tries, as I found little oops'es
that I hadn't caught in the editing of the flatfile. Whenever I caught
an oops, I would just /kill the tf quote, @shutdown the Penn game and
restart with the minimal.db.

One of the few things I found as a problem was the case of garbage
objects. In my original sequential @decomp of the TM3.1 db, I tested the
type of each object. If it was of type Garbage, I @created an object as
a dbref 'placeholder'. Then one of my last commands in the flatfile was
to @search for all 'thing' objects named 'Garbage' and nuke them.

After this whole process, there was about two or three days for the
staffers of the game to smooth over a few very small
inconsistencies (Channels, for instance), but on the whole, the game was
ported VERY smoothly using this method.

File descriptors and login limits

File descriptors and login limits javelin Thu, 2004-03-18 13:38

How many players can be connected to a MUSH at once? There are 3 factors which affect the answer to this question.

The operating system

Each player connection comes in over a TCP/IP socket, and each socket require that the operating system allocate it a "file descriptor", a number which refers to that socket. In addition, each file which is opened by the MUSH process (standard input, standard output, standard error, one for each log file, one reserved for reading help/news/events files, one to accept connections) requires a file descriptor.

Most operating systems have limits on how many file descriptors a user's process can open. Some typical limits are 64, 128, 256, or 1024. Sometimes there will be a 'soft limit', which is lower than the maximum, and which you can increase (via the 'unlimit' or 'ulimit' commands) up to the 'hard limit', or system maximum. The hard limit can only be raised by the system adminstrator recompiling the system's kernel. This is not too bad to do when you have kernel source. Note: SunOS 4.1.x systems have (by default) a limit of 256 descriptors, but there's a bug in the stdio code which prevents descriptors after the first 128 from working correctly. :(

When you run out of descriptors and the MUSH tries to open another one, it will likely either crash or hang. Since the MUSH requires about 10 descriptors for itself (6 if you define SINGLE_LOGFILE), subtract that from the hard limit to figure out how many players you can support.

CPU/memory/network bandwidth

There's also a practical limit. The more players you have connected, the more work the CPU has to do to service the process, the more memory will be used (for player objects and for all those queued commands), and the more load will be placed on your network connection. At some point, your game will begin to lag increasingly. Once again, little can be done unless you have a budget for better hardware.

Setting login limits

Finally, you can set a limit on how many players your MUSH will accept in your mush.cnf file. Usually, you just want to set your login limit at the highest practical value, taking the above things into consideration. So, if you've got a max of 64 file descriptors, and you don't define SINGLE_LOGFILE, figure you can have 54 players connected, and set login_limit accordingly. Remember, however, that your admin and players with the login @power can connect even over your login_limit, and if they run out your file descriptors, expect bad things to happen.


Lag javelin Thu, 2004-03-18 13:45

One of the most pernicious problems common to MUSHes is lag, the condition in which the MUSH feels slow in responding to player input. There are a number of things which contribute to lag, and once you identify the culprit, you can decide if you can improve the situation.

Network lag

Network lag is caused by difficulties in the network connection between the player and the MUSH host machine. For example, a router on the internet between the two might be dropping packets, or a segment of the network might be overloaded with packets.

The characteristic property of netlag is that you won't experience it if you're connecting to the MUSH from the MUSH machine itself. If you can get a lagless connection by doing a 'telnet localhost ', netlag is responsible.

If your host has the ping command (most do), you can test how long it takes a packet to travel between your host and another machine, and try to identify how slow things are going to be. If you happen to have the traceroute command, you can see exactly where (between which routers) the network is lagged.

Unless you happen to be a network administrator of the problem stretch of network (or if it's just the local connection to your machine), there's not much you can do. If the problem is your particular net connection, you can probably spend more money and get one with a higher bandwidth, or reduce other things your machine does that requires the net (email, etc.), but neither of these are really worth it for a MUSH, usually. :(

DNS and IDENT lag

Another network-related source of lag involves domain name service lookups. When a player connects to the MUSH, the MUSH knows the player's IP address, and queries the DNS to get the player's hostname. This is called a "reverse hostname lookup".

Some hosts, however, have very slow nameservers. Sometimes this is because the nameservers are behind slow internet connections with heavy traffic. The MUSH stops while a reverse hostname lookup is going on, so if it takes more than a second, you will feel lag.

If you've got your MUSH configured to use IDENT lookups, the same kind of problem applies. In addition, IDENT lookups of non-unix systems can hang until the lookup times out.

There are a few ways you might deal with this problem:

  • #define INFO_SLAVE in options.h. This creates a separate process that handles lookups, so your MUSH won't have to. This doesn't work well on win32 systems.
  • Turn off ident or reduce the ident_timeout value in mush.cnf
  • If you don't need hostnames, set use_dns to "no" in mush.cnf and no reverse hostname lookups will be performed.
  • If there are particular sites that are causing you trouble, and if you have access to your system's hosts file (/etc/hosts on most Unix systems), you could try making an entry for the troublesome system in the hosts file. Many DNS setups will check the hosts file before asking the nameserver.

CPU lag

CPU lag is caused when the MUSH machine is having to split its time doing many tasks or tasks which require a lot of running time spent in the CPU. If your MUSH is on a machine which has a lot of users, this is more likely. If the users are programmers who run things like compilers regularly, this becomes much more likely.

You can examine the CPU load in a few ways. The uptime command will display an interesting, if non-objective statistic called "load average", measured over the last minute, 5 minutes, and 15 minutes. If you know what typical load average looks like, you'll be able to recognize abnormally high load. Loads over 3, especially in the 5/15 minute entries, tend to make for a slow game.

But what's causing the load? Here you can use ps -auxw (BSD) or ps -elf (SysV) to see all the running processes and how much CPU time they're getting at that moment. This static picture can be deceiving, but is a good start. Read the man page for details.

If you're responsible for the load due to your own compiling and such (or if you need to decrease the CPU load your MUSH puts on the machine), read the man page for the nice and renice commands, which let you tell the system that your compilation (or MUSH process) should be nice about using CPU, and the CPU should give it lower priority.

Disk swapping

Unix systems have a limited amount of memory in which to run their programs. Memory is also expensive. So unix systems use a part of the disk as "virtual memory" or "swap space". Processes send parts of their memory that haven't been accessed in a while off to virtual memory, a process called paging. Paging helps make all the programs work together gracefully.

MUSHes can be pretty big programs, though, and sometimes another program (some compilers and editors, as well as statistical software and other such things, for example) has to be granted more memory than can be recovered even with paging. In these situations, the whole MUSH process may be "swapped out" to the disk, temporarily put on hold until it can be swapped back into memory. While the MUSH is swapped out, the game is frozen, and if it stays swapped long enough and often enough, you experience lag.

Dealing with swapping and paging is beyond the scope of this guide. Read the man pages for ps, vmstat, pstat, and iostat, or pick up a book on Unix System Administration or Performance Tuning (say, the O'Reilly Handbooks, which are great) if you're the system administrator of your MUSH machine. If not, purge unused objects from your database and hope.

Because PennMUSH now performs its own swapping of certain parts of memory out to disk (attribte values, locks, and mail texts), the operating system is less likely to need to page or swap the MUSH process. On the other hand, because PennMUSH is itself using disk, the speed of disk I/O is still important. On a machine with lots of memory and slow disks, turning off Penn's own chunk swapping may be a good thing, and is done by setting the 'chunk_cache_memory' define in mush.cnf to a very high number (2000000000 is recommended).

Queue lag

Queue lag occurs when the MUSH's queue becomes clogged, and the MUSH can no longer keep up with servicing the queue and player input. Players get priority, so keyboard response will be good, but if they try to use $commands, which go on the object queue, they won't get response for some time.

@kick can be used as a temporary fix for this, though see the concerns above in the section on Wizcommands. A more permanent solution might be to adjust the values of queue_chunk and (especially) active_queue_chunk in the mush.cnf file. This will make keyboard response slighly worse, but will usually fix the queue clogging.

MUSH crashes

MUSH crashes javelin Thu, 2004-03-18 13:41

Ok, your MUSH crashed. It happens. The good news is that if you compiled with debugging enabled (-g, and this is usually the default), you can usually figure out *where* in the code it crashed and *why*. Even if you personally can't correct the problem, such information is exactly what you'd want to post/mail if you were asking for help.

In order to get debugging information, your MUSH crash must have produced a core dump, which is a file called 'core' or 'netmud.core' or something similar in your game directory. This file is usually quite large. On some systems, you must be sure that your MUSH restart script does an 'ulimit -c unlimited' or you won't get complete core files.

You also need a debugger. Most systems have one of the following debugging programs: gdb (ideal), dbx (a good second choice), sdb (ick), adb (very ick). You (or your sysadmin) can ftp the source code for gdb from the GNU ftp site.

Using the gdb or dbx debugger

gdb and dbx are similar, so in the following examples I'll use them interchangably. If you'll be needing a copy of your debugging session to mail out, use the unix 'script' command to log everything ('script buglog', do your debugger stuff, then 'exit').

To run the debugger, go into your MUSH game directory and type:

gdb netmush core

The debugger will tell you how the process died, and what function it was executing at the time.

Getting and using a stack trace

That alone can be useful, but far more useful is a stack trace, which shows not only the function it was executing that caused it to crash, but which function called that fatal function (and with what parameters), which function called that, and so forth, back up to the very top function, main().

The command 'where' will print out a stack trace. The commands 'up' and 'down' will walk you up and down through the stack, showing the values of parameters that are being passed. You can also use the 'p' (print) command to print the values of other variables in each function.

Running the MUSH under gdb

If the crash occurs during the MUSH startup process (when analyzing or loading the db, for example), and doesn't leave a core dump, you have another option if you have gdb. You can actually run the MUSH from within the gdb debugger by going to the game directory and doing:

    gdb netmush
    run mush.cnf log/netmush.log

(According to Rhyanna, on some operating systems, typing 'handle SIGPIPE nostop' before running the mud will prevent the debugger from reporting SIGPIPE signals when players connect.)

When the MUSH crashes, you'll be told how and where, and be returned to gdb to analyze the crash. Gdb and dbx can do much more - you can tell them to run the MUSH until they hit a certain function and then wait for further instructions, step through code one line at a time, etc. Read the manual pages if you need to do these things.

Trashed stacks

Some crashes, alas, overwrite the memory containing the function stack, and produce a totally unhelpful core file. The only help I've found for this is to cross my fingers and run the MUSH again, hoping that the next crash will pick a different memory location to overwrite. In some cases, 'touch'ing all the MUSH source files (touch *.c) and recompiling can help, as can using 'make clean; make', but it's mostly superstition.

MUSH security tips (by Ashen-Shugar)

MUSH security tips (by Ashen-Shugar) javelin Sat, 2007-11-03 13:42

Ashen-Shugar's MUSH security tips

Editor's note: This information applies to all MUSH servers

Security is a growing concern on MUD's (mush, mux, penn, etc) today because of the constantly growing experience and abilities of the player base on it and, let's face it, because of the growing number of twinks on these platforms.

The largest concern, and easiest to exploit, area to be aware of is master room code. This is the number one attack point of twinks. Twinks go to extreme efforts to find out both where the master room is, and what functions or attributes exist on objects inside there. They can do this a number of ways.


Any softcode that stores %N or %0-%9 directly to attribute is very very wrong. Why? This allows the twink to be able to design their own command for abuse. I will not explain how it's done (for obvious reasons) but I will show you a few ways it can be avoided.

1. Store a %b before the attribute. i.e.: &attribute thing=%b
2. escape out the string. i.e.: &attribute thing=[escape(stuff)]
3. use secure to strip out nasties: &attribute thing=[secure(stuff)]
4. Put any type of string before the percent substitution.

Basically, for any situation where the user is allowed to store text, you should go to extreme lengths to secure it out. And never NEVER store the name unless it's under controlled situations. The dbref# (%#) should work for most of your needs and can't be abused like %N can.


Actually, I consider side effects to be Satan's spawn. Why? Because they are the easiest thing to abuse on any server. Because of how MUSH parses, it is possible, with code that hasn't been totally gone over, to execute side-effects arbitrarily and gain access and/or set information that wasn't intended.

The use of side-effects without proper reasoning can also choke the CPU. Side-effects bypass the queue of their matching @commands and in so doing, poorly written code can process everything immediately thereby eating up large amounts of system resources. You can code switchless without using side-effects and manage not choking the cpu as badly, but like any piece of code, you need to weigh the benefits verse the costs. The CPU being one of the costs to be concerned with.

It is generally wise to disable side-effects unless absolutely needed, but if you do plan to use them, make SURE to adjust your code so that players can't embed side-effects into functionality or commands that would enable them improper access. Code well, code wisely.


Generally, when you set up your master room, you should NEVER have the master room in the first 20 or so rooms of the mush. On mushes I run, as soon as the DB hits over 1000, I re-set the master room to one of those dbref#'s. It's harder for twink players to find a room when it's not in the first 100 or so rooms. Players generally give up after that (twinks are generally lazy) and it takes very little time on your part to do it. [ Editorial note: This advice isn't very useful on PennMUSH, where any player can type '@config master_room' and find the dbref. - Javelin ]

Master Rooms should also NEVER be named 'Master Room' for obvious reasons (like it being easy to identify by the name for instance). Call it Jane's Jungle Gym if you want. The name does not effect anything but if it's something innocuous it's harder to find and again, takes little time to do.

Unlike MUX, TinyMUSH or it's derivatives, PENN checks $commands on parent objects on the master room. Therefore, for the master room, NOTHING should be parented as it does a check on every single attribute on every single parent in the master room for every single command typed. This is a lot of unnecessary overhead. Again, this only effects PENN. For all other servers, you may @parent w/o it going through and checking all attributes of all parents. [Editor's note: the cpu overhead isn't really an issue with modern servers.]

Any attribute on any object in the master room should ONLY have $commands on them (or listens if they were hacked to do so). For every object in the master room, and for every attribute on every object in the master room, it will be parsed for $commands. This can be an ENORMOUS amount of overhead. To get around this, store any 'functionality' or other non-$command on separate objects OUTSIDE the master room (or inside objects in the master room) so that they will not be parsed for $commands. This will increase the overall performance of the mush, and also remove extra possibilities for twinks to hack your master room.

The master room should only have access to people you want to hack the master room. Even if other wizards have access to it, you should make it clear that they are not to mess with it if you don't want them to. Remember, too many hands in the cookie jar means more crumbs to clean up.


Parenting objects actually is a very good thing. It takes up far less in memory, far less in data storage, and the evaluation time it takes is next to nil for the work of it. It's also very handy in organizing data. However, parenting does have some problems. And yes, all of these are user errors.

When you are a player, before you parent something make ABSOLUTELY sure that the parent in question is TOTALLY secure and can't be changed on a whim. Why? Because you will be executing commands that can, at any time, be changed/modified/added that will effect you in a unfavorable way. Let's say that there's a simple command that shows who's on. The code will look something like:

&CMD_WHO parent=$+whoon:@pemit %#=[iter(lwho(),name(##))].

There, that's very simple. Well, let's say the person in question decides to be abusive, and makes a change to the command and does this:

&CMD_WHO parent=$+whoon:@pemit %#=[iter(lwho(),name(##))].;&ABUSE me=$fo *:@fo owner(me)=%0;@unlock/use me;@set loc(me)=enter_ok; @unlock/enter loc(me)

You still get the same results, but now, the object is unlocked, has a command that will let ANYTHING force you to do anything, and makes it so anything can enter you. And you would be totally oblivious to this as the output as far as you were concerned did exactly the same thing it did before. This is why you *ALWAYS* examine/parent and NEVER set your object inherit (or on penn wizard/royalty/etc) without first being absolutely sure the parent is secure and incorruptible.

For wizards, this is a BIG taboo. In the above example the player in question could just have easily done @dolist search(type=player)=@nuke ## Then congratulations, you do +whoon, and you now have no players. Time to restore the database. For this reason, wizards should NEVER under ANY circumstance have parents that are NOT wizard owned. If you want to parent something to something not wizard owned, get permission from the author first then @clone it for your own use. This way you have control of it. If you still decide to have parents owned by mortals when you are a wizard, you're asking for trouble and expect to have problems. People, as a whole, are not trustworthy, especially when power is in question. Be smart, don't do it.


A problem that has been creeping up again is command catchers. This is done when a player has a command of $*:@pemit me=%0. Thereby making it so any command that is mistyped OR any command that's from the master room will be issued to the player instead. This can be bad especially with soft coded mail systems as it allows the player to see private information. This is the primary reason why commands on players are disabled on mushes I run. It makes it difficult for players to make macros, but is generally more secure than hoping players remember to uselock themselves. Likewise, similar can be done with objects or rooms and on some systems, exits. This is, at least to me, highly abusive and grounds for some serious punishment, but should at the very least, be taken care of when discovered.

If you have a problem with this on your mushes, you may wish to notify to the players to type gibberish before doing something that will require some privacy. For example type 'jrtjso'. I doubt there'll be a command with that name and it should return a huh? message. If it doesn't, then someone is logging commands. Listening things are harder to detect this way, but if enabled and allowed, just @sweep for them. It'll find most of the annoyances so you can be relatively safe.

Privacy is always an issue on mushes, but you need to keep in mind. NOTHING on the internet is 100% private and secure. Someone (most likely the fbi or other government agency) is seeing everything you do and type anyway. What you should do is follow simple advise. Never do anything that you'd not want to see on the 6 o'clock news. If you do, then just be careful and also prepared incase it finds itself in the open. Lots of sick individuals log personal information and put it on public web pages. They do this for two reasons. First, that they could and it gives them a twisted form of thrill, and second, because they may or may not have something against you. When you do anything on the internet, always be prepared for the consequences for any action you do, and take responsibility for it. It not only keeps yourself safe, but keeps others safe, too.


Quota is generally a good thing to install. Even if you give people a ridiculously large amount of quota, you should still have limits. This keeps some twink from making the great rabbit farm that constantly triggers rabbits to be made which can, in just a few short hours, bring your entire mush to it's knees and force a recovery to an older database. And the twink, being clever, may make it a trojan so it would exist in prior databases as well. With the quota limit, they'd still have a bunch of rabbits, but it'd stop at the maximum quota you set up for that player, thus, saving your database from the great '/home/mush/blah' device full message.


Yes, actually, money is very important. Money controls how much a person can queue and how many db-intensive functions and commands that can be issued. If you give someone a few million mush credits (or whatever you call it on your server) you basically hand them the key to the code as they can essentially do everything they want and not worry about the code auto-halting because of lack of money. Yes, function limits and queue limits are still in effect, but money is a very good way to keep twinks from pounding the queue endlessly (and also to avoid those constantly moving puppets that people seem to love to make and let loose). There's generally no reason to give people more than a thousand gold at any given time, but again, use your own judgement.


The queue is a big issue with security as well. This is the main reason I am heavily against any code with nested @switches or other queue parsed commands. The more the code is executed, the more it tosses it into the queue. If it's something that's rapidly executed, it has the possibility to really hit the queue hard. I have seen systems with queue's filled with THOUSANDS of requests. Needless to say, the queue was pretty slammed causing the mush to lag terribly.

There are a few solutions to this. First, code wisely. You can get away with fewer waits, triggers, switches, or other queued code and have the same functionality. Second, consolidate the code. For area effects like birds chirping or singing, have a centralized object do the triggering. Myrddin has a wonderful cron system that can be used on every flavor of mush (mux, penn etc) that is very useful for scheduling jobs. Only one thing will sit on the queue no matter how many entries that you have. TinyMUSH 3.0 also has a hardcoded @cron. It's a very nice idea, but in all honesty it buys you little in performance compared to a softcode alternative which Myrddin has made available. Besides, I get nervous when something is scheduled and you can't eyeball it with @ps.


Every server but PENN allows you to list the current allocations. [Editorial note: God in PennMUSH can use @uptime to get this information] As a wizard, @list alloc shows you the current allocations of resources. Keep an eye in the 'in use' section. If you see that growing at a constant rate and never decrease, you have a memory leak somewhere and you need to alert your hardcode hack (or the development team of that mush code) and tell them they have a leak somewhere. It's always best if you can identify the command/function that is causing the leak, but generally the developers are bright enough individuals to find it relatively quickly. For PENN (and yes the other servers as well) you can check the process size of the mush on the platform you're running. Do a ps on the process and check the memory and resource as well as the CPU. The CPU shouldn't ever go much above 1 or 2 percent for any period of time (for slower boxes), and memory growth shouldn't grow that much (no more than a few megs at most from when it started). If it does, you need to keep an eye on processes in the queue, and what is ran. It could mean two things.

First, it could mean that the mush server that you are currently running has some really bad memory leaks. TinyMUX 1.5 is bad for this for instance. It also could mean that someone is trying to grow your process size by adding a lot of code or queued information. To verify this, check the database size and make sure the database doesn't grow too fast. If it does, you need to immediately take care of it as someone obviously has put an effort to bring your mush down. Best way is to immediately do a @halt/all, @wall a message of logins being disabled for the next 10 minutes, record everyone on, @boot everyone but the wizzes, and disable logins for 5 minutes or so to collect yourself and identify the source of problems. Yes, this is for a 'oh hell, my db is growing a meg a second' type of situations. For anything less major, you can take your time and identify the problem w/o alerting the twink in question then nail them after you garnish the facts.

Second, you could have a form of corruption. I have recently alerted the various development staff of a very major problem with attribute handling that will result in servers being heavily corrupted. This type of corruption can cause random effects, including major memory growth and/or database growth. There is no ready way to check for this type of corruption on any server except RhostMUSH currently but signs of effects are random SIGSEGV's, especially when accessing objects/players with examine, @destroy, nuke, etc. Worse case signs will be the changing of types (like players being turned into exits) or attributes changing objects or just disappearing altogether. If you see any of these signs, and can verify that it was not user-caused, then you need to definitely look into fixing it as soon as you can. It will most definitely require a fall back to a previous database but the sooner you catch it, the better you'll be at having a cleaner database. Anything that sets a large number of attributes on items (or that uses extensive ANSI on large number of attributes) are the most likely causes of this. Major problem points are brandy's mail system, amberyl's mail system, and myrddin's bbs system (but only if used extensively w/o clearing out old messages).


Another way a player can really cause problems is by hosing your hash table. They can do this by making a ton of attributes on an item. The larger the hash table gets, the slower the overall performance of your server is. MUX has a @dbclean that cleans up unused attributes (as does MUSH 3.0). And MUX 2.0 has an enhanced version that not only cleans it, but renumbers the attributes. A definite speed boost. You should always keep an eye on this as much as you can and make sure it stays relatively small as much as possible. [Editorial note: PennMUSH doesn't have a disk-based hash table, so this doesn't apply.]


Whenever you load code into your system, make sure that it comes from a reliable source. There is a LOT of stolen code floating around that people illegally have (a VERY bad thing to do that I tend to nuke people over, no questions asked) or that is very poorly done. Whenever you port code in, make SURE that the code is properly credited. If not, don't use it. You save yourself a lot of problems. Secondly, make sure the code you port in is secure. Make sure it doesn't use side-effects badly, that it doesn't allow the players to store attributes, that it handles the queue nicely, and everything else mentioned in this document. If it passes the general guidelines and if you feel comfortable with it, use at your leisure. If not, you're again, asking for some major headaches. When your mush invariably crashes or is compromised because of bad code, remember that you were the one that had a chance to fix it at the start.


When you are ever unsure about a piece of code, or about how something should be done, ask around. There are a lot of people out in the mush community who are more than intimate with the parser and functionality and could help you. These people are also generally easy to get along with and will help you as long as you made some effort to find the problem. Please, for our own sakes, take time to learn and figure things out on your own first. If you don't, people start to feel used and that really annoys people. Trust me, it's happened to me more than I would care to count.

Likewise, word to those brilliant code people out there. Do what I do. When people come to you for an answer, don't just tell them. Don't just show them, have THEM do it and walk them through it. That way, they not only learn how to do it, but they, in turn, are now able to help others. You're just helping yourself by doing it this way. One less person that'll ask us for future issues, and it also helps interpersonal relationships. Always a good thing. Remember, we all started as newbies as well, but we didn't always have the knowledgeable that people today have.

I can be reached as Ashen-Shugar on Rhostshyl ( 4201), Underground ( 7000) and M*U*S*H ( 4201). If I'm not around, you may email me as well.

Moving to a new site (by Rhyanna)

Moving to a new site (by Rhyanna) javelin Sat, 2007-11-03 13:34

Moving to a New Site (Rhyanna)
Sometimes it becomes necessary for a MUSH to move to a new site. These are some of the common reasons:

* The site gets taken offline because of host problems.
* The site provider graduates / flunks out / otherwise loses their account.
* The MUSH starts taking up too much memory, disk space, or CPU time.
* The sysadmin of the site realizes that a MUSH is being run without permission. (This is far more common than it ought to be. Always get permission before running a MUSH.)

In my time, I have participated in two atrociously handled moves, and one move that seems to have been relatively successful. Based on that experience, here are my tips for moving.

1. Move as seamlessly as possible. Ideally, you would @wall about the move at the old site, shut it down, ftp the database to the new site (where you've already compiled and tested the code), and restart, with a total elapsed time of ten minutes or less. This is feasible, if you have planned ahead, compiled and tested the code at the new site, and so forth.

One atrocious move of my experience involved having two copies of a MUSH up at different sites for a period of more than a week, each with a MOTD that said the other MUSH was the 'official' MUSH. Another atrocious move involved the MUSH being down at one site for two weeks before coming up at the new site.

In the successful move, on the other hand, we had been testing the new site for anomalies for a few days, and we had declared a time when the database would move from the old site to the new site. Even though the move didn't happen at exactly the time we had declared, because the new site was down for maintenance, the move was a success, in large part because we came as close as possible to always having one and only one 'official' version of the MUSH around.

2) Leave a forwarder on the old site and port. This is extremely important.

Unfortunately, a large number of players don't pay close attention to the MOTD or to any other announcement ahead of time. No matter how much publicity you try to create for a move, there will be a large number of players who don't know anything about it until they try to connect to the old site and fail. This is why you need a port forwarder on the old site.

Almost all of the reasons why a legitimately running MUSH would need to move can be worked around for a port forwarder:

* A port forwarder is very small (portmsg.c compiles to 32K on a SunOS 4.1.1 system) and takes an insignificant amount of CPU time.
* If the host computer itself is going down, it is often possible to coax your friendly neighborhood sysadmin to remap the old name to a new computer. This is fairly standard practice anyway, to keep e-mail from bouncing and so forth. If the name gets remapped, it's often possible to run the port forwarder on the new host.
* If you are losing your account on the site, you can often coax a friendly sysadmin or another person with an account on that host to run a port forwarder for you, because it is such a small program with low cost in resources.
* If the MUSH is being evicted because of its drain on system resources, a port forwarder should be acceptable as a non-draining alternative. If even a port forwarder is a significant drain on the system, it begs the question of how you ever got a MUSH to run on a Vic-20 in the first place.

All of these require some planning and require that you be on relatively good terms with your sysadmins. (It's worthwhile to be on good terms with your sysadmins even if you're not running a MUSH.) From this, a corollary follows:

3) Move well before it is absolutely necessary to move.

Many times, it is possible to have ample forewarning before a move is going to be required. A machine may fail with increasing frequency before it goes down for the last time. Graduation is usually not a surprise, either. A kindly sysadmin can tell you ahead of time when a MUSH is starting to consume too many resources. (Note: If you ask to be notified if the MUSH starts to become a drain on system resources when you get permission to run your MUSH, you can save yourself a world of grief.)

You need to run a port forwarder after the MUSH moves. You may need to do some negotiation to get the port forwarder to run. Therefore, you should move as soon as you have a new site upon which you have compiled and tested the code. You should not wait until the last minute; the more critical your need to move, the more trouble you will have moving without losing many of your players.

Optimizing PennMUSH

Optimizing PennMUSH raevnos Mon, 2007-01-29 11:33

Penn isn't typically a performance hog, especially on modern computers. Even older ones from the mid-90's are more than powerful enough to run a decent-sized game on. The major constraints with those older computers is hard drive space and memory. This document has some hints for those times when performance is a factor, or for those who just like to tweak.

Generally, network transmission times are long enough that they're the major factor in lag or slowdown. You can tell if it's the mush process itself that's causing problems by looking at @uptime to see how much processor time the game is using, and, from a shell, using top to find out what's using the largest percentages of CPU time. Problems could very well be caused by an unrelated program and an OS with a scheduler that starves other processes of CPU cycles. The traceroute and ping programs can be used to time how long it takes network traffic to reach a host and where slow spots are.

Compiler options

If Penn itself is running slow after all, the big step to improving it is to recompile it with optimizations. Edit pennmush/Makefile to add to the CCFLAGS line. -ON turns on basic optimizations, where N is 1 to 3. The higher the number, the more optimizations, but the longer it takes to compile. After editing, do a 'make clean; make' to rebuild the server.

Other optimization options of note (Assuming you're using gcc):

  • -march=X -mcpu=X

    This tunes the outputted binary for a particular processor type's instructions and scheduling. For the typical x86 system, you can use 'pentium4', 'athlon-xp', and so on. (On PowerPC systems, and newer GCCs, use -mtune instead of -march). The complete list of known processors is in the gcc documentation, as well as more architecture-dependent options.

  • If you have a processor with a large cache, -funroll-loops will help.
  • The game doesn't have any floating-point intensive parts, so -ffast-math's benefit is limited. If you're using a processor with Intel's SSE instructions, try -mfpmath=sse. This is the default on x86_64.
  • If you don't care about debugging, remove the -g option, and add -fomit-frame-pointer to give gcc another register to work with — especially useful on x86.
  • With gcc 4 and higher, compile with -fprofile-generate, run the mush with normal activity for a few days, and recompile using -fprofile-use instead, with all other options the same. This'll give the scheduling and branch prediction algorithms real-world data to use to make better choices.


If memory is an issue (Older machines, and/or huge databases), there are a few steps you can take.

  • Fiddle with the attribute compression choices in options.h. Huffman or word-based might be better for a particular game depending on the contents of the database
  • Tweak the chunk swapfile options in game/mush.cnf. Infrequently-used attributes and mail messages get swapped out to disk. You can increase the size of the swapfile, and how much data gets moved every second. See the relevant section of the 'Hacking PennMUSH' book for details on this.
  • Increase the OS's swap space. Increasing or adding additional swap partitions can help.

Disk space/speed tradeoffs

When compressing databases, you have to choose between speed and compression efficiency. bzip2, for example, will produce the smallest database file, but take the longest. Using no compression will result in the fastest dump, but the largest file on disk.

If you're using forking dumps, this isn't an issue, of course.

Other considerations

If you use SQL, take a close look at any SELECTs. Each one pauses the mush until it finishes, so doing complex joins or talking to a SQL server across a slow network will cause problems.

Internally, the developers try to use algorithms with good big-O performance (A measure of how the time increases as the amount of data increases). If you know of a better one than what we're using for something, let us know.


Security javelin Thu, 2004-03-18 13:50

Security on a MUSH (which many feel is an oxymoron already) addresses the needs of the game to provide four or five crucial factors:

Stable service
Players should be able to play the game - it should be up reliably.
Database control
Players should not be able to modify objects belonging to other players.
Private player information (email addresses, sites, private conversations) should be inaccessible by unprivileged players.
Freedom from harassment
Players should be free of harassment from other players (gross spamming, for example.)
A fair game
Players should not be able to use MUSH knowledge to cheat in any game run on the MUSH, particularly if the game is the point of the MUSH.

Unwelcome players can generally be broken down into two major categories: crackers, who threaten stable service and database control, and twinks, who threaten privacy, freedom from harassment, and game fairness. A cracker seeks to destroy the integrity of the game by making it unusable. A twink seeks to destroy the integrity of the game by making it unenjoyable or unfair.

Handling crackers: a philosophy

Some people who try to compromise MUSH security claim that they're doing you a service, by showing you where you MUSH needs shoring up. As Amberyl once put it, this is akin to someone breaking into your house (unasked, of course) to show you that your locks should be repaired.

These folks not only put your game and database at risk, not only might become privy to sensitive information (player email addresses, etc), but destroy the trust which generally exists within the internet and MUSH community. It's no service.

Unfortunately, the crackers usually win, because they have a lot of time to spend trying to compromise your security, while you and your Wizards have more to do than just continually improve it. The goal here, therefore, is to emphasis some easy measures that you can take to deal with attacks on your MUSH.

Handling twinks: a philosophy

While the goal in dealing with crackers is to keep them away from your MUSH or minimize the damage they can do, twinks come in many flavors and require individual response. Many twinks are misguided newbies who, once set straight, become valuable players. Others merely seek to disrupt the game, creating dozens of characters and paging regular players with annoying messages. As Gilbert and Sullivan put it, with twinks it's often best to "let the punishment fit the crime."


The suspect flag makes an excellent first line of defense against suspected problem players. In addition to allowing you to tell when a SUSPECT player connects, disconnects, or changes their name, all actions by SUSPECT players are logged in the MUSH's command.log file, so you can decide if they really pose a threat.

The mugshot script ( processes command.log and creates individual suspect files, one per player (by db#), which can be read or searched for keywords or whatnot.

By the way, I think it's good policy for every MUSH to place a statement in news ('news policy' perhaps) noting that while every attempt is made to preserve privacy, you reserve the right to log commands executed in order to maintain MUSH security and/or to fix bugs.

Registration and lockout

Site registration, and site lockout, are strong measures which can be effective in preventing twink invasions. The key to site-based access control is the access.cnf file.

You can control the following aspects of access:

  • Whether or not a site can connect to guests
  • Whether or not a site can connect to non-guest characters
  • Whether or not a site can create characters at the login screen
  • Whether denied connections will be logged or not
  • Whether or not a site can use the "register" command at the login screen, to request that a character be created and its password be emailed to the player.
  • Whether or not a site is suspect. Players who connect from suspect sites are automatically set SUSPECT.
  • Which of the above your Wizards can override using @sitelock, and which are set in stone.

access.cnf (in the game directory) is a list of sites and their access control options. When someone connects, the file is read through in order, and the first line which matches their site is used to determine their access options. Order of the file is thus critical.

A line in the file looks like this:

   [  ...] [# Comment]

Host patterns may contain the wildcard "*" which will match any number of characters. Patterns can match individual users from sites which run ident servers, but because ident relies on trusting the server and a reasonably speedy network, it's best avoided. Using "*" as the host pattern matches all hosts, and really only makes sense as the last line of the file.

A host which does not match any line in the file is allowed complete access. A host which matches a line with no options listed is banned completely; connections will dropped before the login screen.

There is also a special line in the file:


The "@sitelock" line marks where new additions to the file via the @sitelock command will be added (if your file doesn't contain one, one will be added at the end of the file when someone uses @sitelock). Any lines listed above the @sitelock line can not be overriddent by @sitelock; those listed below can. This allows you to decide which access control rules your Wizards should be able to override.

The available options include:

allow players from this site to use the 'create' command
don't allow players from this site to use the 'create' command
allow players from this site to connect to non-guest characters
don't allow players from this site to connect to non-guest characters
allow players from this site to connect to guests
don't allow players from this site to connect to guests.
enable the 'register' command at the connection screen. Players may type 'register ' to create a new character and have its (randomly generated) password emailed to the player. Note that this does not disable 'create', so you'll probably want to use this option along with the !create option.
cause all players connecting from this site to be set SUSPECT. Unless you want SUSPECT guests, you'll probably want to include !guest as well.
prevents connection denials from being logged to connect.log. This is useful if a cracker is attempting a connection flood, and prevents your logfile from overfilling your disk

The @sitelock command sets the optional comment to inform you of who performed the @sitelock and when.

access.cnf is re-read when the MUSH receives a HUP signal or @readcache is run.
It is updated whenever someone uses @sitelock.

The file game/access.README contains examples of using access.cnf to enforce a variety of different access control policies.

Gagging, booting, guesting, newpasswording and nuking

There are a wide variety of things you can do to discipline a twink player. Amberyl's wiz-ethics lecture discusses many of these, and I, like her, believe that one should "let the punishment fit the crime" which choosing which command to use:

The GAG flag
Prevents the player from speaking, a handy response to spammers and those who page obscenities.
The Guest power
Restricts a number of commands players can use, depending how how you've set up the command restrictions in mush.cnf. Often prevents any building or attribute-setting.
The FIXED flag
This flag prevents the player from using the @tel and home commands. Handy if they keep @tel'ing where they're not wanted.
Disconnects the player from the MUSH. Nothing, of course, prevents them from reconnecting, unless you lock their site or install a global @aconnect to listen for them connecting and boot them again.
Changes a player's password. This is the proper way for non-Gods to "nuke" a player, as it doesn't actually result in any data loss, and can be reversed if the twink makes amends. This does no good against twinks who are just creating scratch characters they don't care about. God can also re-name a player without knowing/changing their password, which can have similar effects.
This is how God cleans players from the database. It's also an appropriate response (along with a sitelock) against crackers.

Coded attacks on the MUSH (privacy, denial of service)

Most twinks just want to rise to ultimate power in your game. But some crackers are interested only in compromising your security in order to destroy and deny the game to others.

Admin passwords must be protected. A cracker who can log in as a Wizard can destroy your database in one command.

Players should not be given wizard-bitted objects if at all possible. Wizard-bitted global commands should be carefully checked for security. One important check is to try calling the command with arguments like "[set(me,visual)]" and "\[set(me,visual)\]" - if the function results in the wizobject becoming visual, it's not secure! (And Wizard globals shouldn't be visual anyway, just in case.) Best is if you can run without FUNCTION_SIDE_EFFECTS.

Be very careful of zones. My policy is that nothing owned by an admin should ever be zoned to a ZMO which has non-admin on the elock. Instead, it should be @chowned to a mortal builder-character and then zoned. You can find ZMO's without elocks by logging in as a mortal and running an @find to see what you control.

In the worst-case scenario, if you somehow lost your entire database, you'd still be okay if you've been making backups of your database every now and then (how often and how many depend on your disk space.) Always have at least one working backup somewhere. And chmod a=r it, too, so you don't accidentally overwrite it! If you really want disaster-recovery, you should keep a database backup on another machine as well, in case your host should crash.

Shutdowns and dumps

Shutdowns and dumps javelin Thu, 2004-03-18 13:33

What's a dump?

A database dump is the process of making a copy of the MUSH's database (which is mostly in memory when the MUSH is running) on the machine's disk. This is absolutely necessary when the MUSH is shut down, so that it can be restarted in the same state it was in when it was shut down. In addition, "checkpoint dumps" are performed by the MUSH at regular intervals (e.g. every hour, every 3 hours, every day, or however you configure it in mush.cnf). If the MUSH should crash, it can be restarted from a checkpoint dump, and data loss will be restricted to changes made in the last interval. Finally, a dump can be performed by a wizard using the @dump command.

What's a forking dump?

In mush.cnf, you can decide if your MUSH should fork when it dumps. "Forking" means that the MUSH makes an identical copy of itself in memory, and that copy runs the dump and then exits, while the original copy continues doing MUSH things. This means that players won't even notice when your MUSH dumps, which is nice. Forking doesn't work on Win32.

There's a downside, however. When the MUSH forks, there are basically two MUSH processes running. That means durnig the dump, your MUSH is using twice the CPU (roughly) and twice the memory that it normally would. If your machine is low on memory, this can cause the MUSH to swap, and lag everyone badly.

The alternative is to dump without forking. While the MUSH is dumping, it can do nothing else in this case, so the game will pause until the dump is complete. It gives the players a message to let them know that there will be a pause.

What happens on a shutdown dump?

A shutdown dump is just like any other dump, but it occurs at shutdown. :)

What's a paranoid dump?

A paranoid dump is performed by a Wizard typing @dump/paranoid. A paranoid dump differs from a normal dump in that it automatically corrects certain kinds of database corruption, writing out a non-corrupt database to disk. This is often useful when your database is corrupted in such a way that normal dumps crash (if you're forking, a dump crash only crashes the dump process). You can @dump/paranoid, kill -9 the MUSH process (DON'T @shutdown, which will overwrite the paranoid dump with a corrupt one), and then restart from the paranoid dump.

What exactly does a paranoid dump try to fix?

  • Bad attribute names: Unprintable characters or spaces in names of attributes will be replaced with a '!' character.
  • Bad attribute owners: If the attribute is owned by an invalid db#, its owner will be set to God.
  • Bad attribute text: If the attribute's text contains unprintable characters or hard newlines (\r's and \n's), they will be replaced with '!' characters. The fixing of hard newlines used to be important, but is actually now more of a hassle since MUSH can now deal with \r\n's in dbs.

What's a debug dump?

A debug dump is performed by a Wizard typing @dump/debug. It's a paranoid dump that also tries to repair some of the problems it finds on the in-memory (running) copy of the database, as well as writing out a clean database. It only corrects bad attribute owners (but these are the most common corruptions that cause crashing on dump).

What's a panic dump?

A panic dump occurs when the MUSH process is terminated with a signal 15 (SIGTERM) (there may one day be a @dump/panic command as well). This is a pretty unusual thing, but if someone accidentally kills your MUSH process somehow, it'll attempt to save a copy of the database, together with the mail and chat databases (if any) before it dies. The copy will be stored in game/data/PANIC.db, will be uncompressed, and will contain all of the dumped databases in one file. You can tell if the dump was successful by examining the last line of that file. If it's ***END OF DUMP***, it was successful. The restart script knows about panic dumps, and will try to restart from a panic dump if it can find a successful one.

Tricks with core dumps (by Rhyanna)

Tricks with core dumps (by Rhyanna) javelin Sat, 2007-11-03 13:32

Recovering a db from a core dump
I have recently managed to recover a PennMUSH 1.50 database from a core file. I will explain what I did, in the hopes that this technique may be useful to others.

I will assume that at the beginning, you are in the game/ directory, and that your core file is in the same file, named core. You should also have a debugger available. I only know gdb, so I can't give directions for using debuggers other than gdb.

1. First, copy the core file to a safe place so that you won't accidentally overwrite it. Therefore, if something goes wrong, you'll still be able to try again.
2. If you are currently trying to run the MUSH with an old database while you restore another database from the core file, make a backup copy of outdb.Z. Also connect to it and use @uptime to make sure that it will not save for a while. Personally, I would be paranoid and wait until I had at least 40 minutes before it saved again.
3. Next, get and install undump. It might possibly be installed on your system; more likely, it won't be. You can get it by anonymous FTP as part of the TeX distribution; one site, for example, is, in the directory /pub/wuarchive/packages/TeX/support/undump/. Undump, it should be noted, is about as system-dependent as a program can possibly be, and there's an excellent chance that there won't be an undump available for your system. In that case, you won't be able to use this method.
4. From the game/ directory, do this: undump core.netmush netmush core
5. Load it up in your favorite debugger. For concreteness, I am using gdb: gdb core.netmush
6. If your core dump was caused by data corruption, you should fix that data corruption now.
7. Then, from the (gdb) prompt, type: print dump_database()

If there is no data corruption, this will write out a copy of the database as it was at the time the core dump was generated.

This database will be generated as outdb.Z (or whatever your standard output database is). If you are currently running the MUSH, you should immediately rename this outdb.Z so that it does not get overwritten the next time the running MUSH saves.

Working with a corrupt core file (Penn-specific)
Suppose you are in my situation: you are an avid server-hacker, but often you get core dumps that are inconveniently truncated, so that a core file that should be 21M long ends up being from 300K to 900K long.

You can still get very useful debugging information out of even a partial core file with your favorite debugger:

Open up the core file in your favorite debugger and look at the variables ccom, cplr, wenv, and renv. These are all global variables; they have the following meanings:

* ccom is the last command that was run.
* cplr is the dbref of the object doing the command.
* wenv is the values for %0-%9.
* renv is the values for %q0-%q9.

These variables get set just before every call to process_command(), which is the procedure that handles all the command parsing. In my experience, they're low enough in memory that they can usually be recovered from some of the most truncated core dumps around. And they provide an .enormous. aid to diagnosing where a problem may lie.

Using #1

Using #1 javelin Thu, 2004-03-18 13:27

God, player #1, is a very special Wizard, and a very useful tool. God can do some things that no other Wizard can, and some commands function differently for God. Because of these powers, it's wise to safegaurd God's password at least as well as you would the MUSH account's password. While the same can be said about any Wizard password, it goes doubly for God.

Making wizards

God is the only thing in the game which can set a WIZARD bit on a player. When you recruit Wizards for your MUSH, you'll have to log in as God to grant them the bit. For that matter, only God can remove a wizard bit or @nuke a wizard player, a definite safety feature.

Malloc stats

If you have MEM_CHECK defined, running @stat/table as God will give you a dump of memory allocation information internal to the game. This can be useful in debugging memory leaks and the like.

@startup for @functions

When the MUSH starts up, the @startup attribs on all objects are triggered, in ascending order of db#. This means that God's @startup is the first one triggered, which makes it ideal for doing @function commands, since later @startup's may rely on your @functions being installed.

Note that if you do your @function calls in a @dolist, they will get queued after all the other @startups run, so you probably want to spell them out explicitly if timing is important to you.


  • Only God can use the @poor and @allquota commands.
  • Only God can use @log/wipe to erase a game log, and this additionally requires the password given in mush.cnf.
  • God may @chown a player, which should only be used if, due to some corruption, a player ends up not owning themselves. God can also @boot players who the game lists as not connected. Don't do it.
  • God can @wipe wizard-only attributes on things. Even wizards can not (using @wipe - they can clear them manually).
  • Only God may @set, @edit, @tel, @force, or @trigger God.
  • Only God can do @mail/nuke and wipe all @mail.

Recovering from a lost God password (1.8.0+)

Recovering from a lost God password (1.8.0+) Tyr Tue, 2005-01-04 15:22

Having forgotten the god pw on my tinkering site, I went into the db to hack it out...and lo and behold, the instructions in the Guide for 1.7.x no longer applied! The new db format deprecated them. With Jav's help, I figured out how to do it with the new format.

Instructions are as follows:
Decompress your outdb and open it in your favorite editor. Look for an attribute resembling this:

attrcount 10

Reduce it by one.
Then look for something like this:

 name "XYXXY"
  owner #1
  flags "no_command wizard locked internal"
  derefs 0
  value "XX13793169753747280487"

Delete everything between the end of the previous attribute and the !2 (signifying the start of #2). Save. Re-compress, restart your game, et voilà! You've just hacked #1's pw.

A tool to recover a lost #1 password

A tool to recover a lost #1 password javelin Sat, 2010-07-31 21:48

Brazil of TinyMUX fame has written Omega, a flatfile converter that can remove #1's password attribute on PennMUSH as well as other server flavors. Check it out at

Run as: omega -1 mydb mydb.out

He suggests that you examine a diff between the original and omegafied db to make sure it's only changed what you wanted it to, just in case.