// ******************************************************************************** // // **Creator: Darien Licence: Diku Merc Terms ** // // **Difficulty: 1 hundred million Snippet: file descriptor .. stuff ** // // ******************************************************************************** // // ** Contact Information ** // // **Yahoo: ldevil.geo Msn: ldevil@hotmail.com ** // // **Aim: pocketweasle Email: ldevil@hotmail.com ** // // **Webpage: http://sandstorm.arthmoor.com ** // // ******************************************************************************** // // **Terms of Usage: ** // // **Follow the Diku, Merc Licences, also, if you have a snippet helpfile ** // // **Put my name in there, if not, leave my name in the source. ** // // **Also, this code is given AS-IS, straight from my mud, so there will be some ** // // **Effort required to make this work in your mud. ** // // **Install at your own risk, if you have any comments or questions on this ** // // **Visit the website mentioned above, and enter the forum, post and bugs or ** // // **suggestions there. ** // // ******************************************************************************** // First off, let me begin by telling you that this was more of a pain in the ass to create than any other piece of code i have recently done, i know, it may not look all that difficult to write, but when you get down to it, i had to go searching big-time on how todo this. So that alone gives me a golden star * see.. a star! Second off, what this code does is not limited to, displaying if a file-descriptor is open or closed, ney... You can view what info is infact, within said file-descriptor. So, all its pertinant data, essentaily, if you are in the shell.. and do a cd /proc/<pid>/fd then do a wonderful stat <some descriptor number> the information it would return, will be the same here, just, without the moot-point of doing that. This also contains a way to clean out 'dead' descriptors, ie, anything left hanging, and belongs to the UID of the mud, will be killed off. Personaly, i find that the info_desc command is doing just fine for me to view vital information. Now, a note on the socket's hanging, this system CHECKS the descriptor list. the IMC (if you have it) the internal webserver (if you have it.. again) and your connection ports, and leaves those alone. Ofcourse, if there is a socket hanging, but its not related to any of the above (and is not an open file ... checks that too) well, essentaily, if it doesn't have a safeguard to stop it from being 'closed/removed' it will be infact that, closed/removed So essentaily, this does what any immortal would want, clearing the descriptors that are fubaared, as we all know, if they add up too much, it can/will cause your mud to crash. So this is a 'safe-guard' there is no garuntee that it still won't crash, or that closing a file that isn't safe-guarded won't cause a crash. But its worth it. I have been running this on my mud for awhile now, no crash's, descriptors are being actively cleaned. I can get information about descriptors as i need it(though i never really do, but its fun to see the data anyways) so that being said, you'll need to add func_desc_check, func_info_desc, and func_clean_desc to your interpreter command call table (or your database for those whom have that) Aswell as to your interp.h you will want to throw a void clean_desc(void); to the top of your update.c And then put clean_desc(); at the bottom of your update_handler Simple to install that part. Now, in my main header, it says that you'll have to port data, and i'm not lying, you really do. this is straight from my mud, so everything will most likely need a change or two.. You will also need to include sys/stat.h for this to work. And if you don't have sys/stat.h Then you are SOL for using this system. /* Return the mode name*/ char *st_mode(mode_t mode) { if(S_ISSOCK(mode)) { return "Socket"; } else if(S_ISREG(mode)) { return "Regular File"; } else if(S_ISDIR(mode)) { return "Directory"; } else if(S_ISCHR(mode)) { return "character device"; } else if(S_ISBLK(mode)) { return "block device"; } else if(S_ISFIFO(mode)) { return "fifo(?)"; } else { return "Unknown/Error"; } // hit the end! return "(Unknown)/Error"; } // Command for checking descriptor information! MudCmd( func_desc_check ) { int desc; int counter = 0; int found = 0; struct stat bstat; BUFFER *output = NewBuf(); BufferF(output, "\n\r`*+`6-------------------------`^Displaying File Descriptors`6-------------------------`*+\n\r" ); for( desc = 0; desc < 300; desc++ ) { if( fstat( desc, &bstat ) < 0 ) { continue; } else { BufferF(output, "`#%3d`7: `!yes`` %30s ", desc, st_mode(bstat.st_mode) ); found++; counter++; if(counter == 2) { BufferF(output, "\n\r"); counter = 0; } } } BufferF(output, "\n\r" ); BufferF(output, "Found %d descriptors open\n\r", found); page_send(buf_string(output), ch); close_buffer(output); return; } // Command for infoing a 'said' desscriptor MudCmd( func_info_desc) { int desc; struct stat info; BUFFER *output = NewBuf(); if(!IsNumber(argument)) { ch->Send("Descriptor must be a number!\n\r"); close_buffer(output); return; } BufferF(output, "\n\r`*+`6-------------------------`^Displaying File Descriptor Information`6-------------------------`*+\n\r" ); for( desc = 0; desc < 300; desc++ ) { if((atoi(argument) == desc)) { if (fstat(desc, &info) != 0) BufferF(output, "Unable to gather information on file descriptor: %d\n\r", desc); else { BufferF(output, "`* inode `$: `!%d\n\r", (int) info.st_ino); BufferF(output, "`* dev id `$: `!%d\n\r", (int) info.st_dev); BufferF(output, "`* mode `$: `!%08x`*/`#%s\n\r", info.st_mode,st_mode(info.st_mode)); BufferF(output, "`* links `$: `!%d\n\r", info.st_nlink); BufferF(output, "`* uid `$: `!%d\n\r", (int) info.st_uid); BufferF(output, "`* gid `$: `!%d\n\r", (int) info.st_gid); BufferF(output, "`* size `$: `!%d\n\r", (int) info.st_size); BufferF(output, "`*block size `$: `!%d\n\r", (int) info.st_blksize); BufferF(output, "`*block count `$: `!%d\n\r", (int) info.st_blocks); BufferF(output, "`*Last Access `$: `!%s/%s\n\r", grab_time_log(info.st_atime), grab_date_log(info.st_atime)); BufferF(output, "`*Last Modification`$: `!%s/%s\n\r", grab_time_log(info.st_mtime), grab_date_log(info.st_mtime)); BufferF(output, "`*Last Change `$: `!%s/%s\n\r", grab_time_log(info.st_ctime), grab_date_log(info.st_ctime)); BufferF(output, "``\n\r"); } } } page_send(buf_string(output), ch); close_buffer(output); return; } // clean a selected descriptor MudCmd( func_clean_desc) { int desc = 0, cleaned = 0; struct stat info; BUFFER *output = NewBuf(); extern int sockfd; BufferF(output, "\n\r`*+`6-------------------------`^Cleaning File Descriptors `6-------------------------`*+\n\r" ); for( desc = 0; desc < 300; desc++ ) { list<descriptor_data *>::iterator dsc, dsc_next; bool no_remove = false; if (fstat(desc, &info) != 0) { continue; // Okay, nothing on this descriptor } else { if(info.st_uid != getuid ()) { continue; } if(S_ISSOCK(info.st_mode)) { // Are we the mud-control, web-control, and imc if(desc == mud_data.control || desc == mud_data.control_2 || desc == sockfd || desc == this_imcmud->desc) { no_remove = true; break; } // This evil method *SHOULD* kill the bad descriptors :) for(dsc = descriptor_list.begin(); dsc != descriptor_list.end(); dsc = dsc_next) { descriptor_data *d = (*dsc); dsc_next = ++dsc; // Found a potential! No need to clean! if(desc == d->descriptor) { no_remove = true; break; } if(no_remove =compare_web(desc)) { break; } } } else if(S_ISREG(info.st_mode)) { no_remove = true; } else if(S_ISDIR(info.st_mode)) { no_remove = true; } else if(S_ISCHR(info.st_mode)) { no_remove = true; } else if(S_ISBLK(info.st_mode)) { no_remove = true; } else if(S_ISFIFO(info.st_mode)) { no_remove = true; } else { no_remove = false; // Yuppers, kill this file! } if(!no_remove) { close(desc); // Close the descriptor desc = -1; // Ensure the descriptor is now -1 cleaned++; } } } BufferF(output, "Cleaned %d descriptors", cleaned); page_send(buf_string(output), ch); close_buffer(output); return; } // Update cleaner! void clean_desc(void) { int desc = 0, cleaned = 0; struct stat info; extern int sockfd; for( desc = 0; desc < 300; desc++ ) { list<descriptor_data *>::iterator dsc, dsc_next; bool no_remove = false; if (desc == 0 || desc == 1 || desc == 2 || desc == 3 || desc == 4 || desc == 5 || desc == 6) continue; if (fstat(desc, &info) != 0) { continue; // Okay, nothing on this descriptor } else { if(info.st_uid != getuid ()) { continue; } if(S_ISSOCK(info.st_mode)) { // Are we the mud-control, web-control, and imc if(desc == mud_data.control || desc == mud_data.control_2 || desc == sockfd || desc == this_imcmud->desc) { no_remove = true; break; } // This evil method *SHOULD* kill the bad descriptors :) for(dsc = descriptor_list.begin(); dsc != descriptor_list.end(); dsc = dsc_next) { descriptor_data *d = (*dsc); dsc_next = ++dsc; // Found a potential! No need to clean! if(desc == d->descriptor) { no_remove = true; break; } if(no_remove =compare_web(desc)) { break; } } } else if(S_ISREG(info.st_mode)) { no_remove = true; } else if(S_ISDIR(info.st_mode)) { no_remove = true; } else if(S_ISCHR(info.st_mode)) { no_remove = true; } else if(S_ISBLK(info.st_mode)) { no_remove = true; } else if(S_ISFIFO(info.st_mode)) { no_remove = true; } else { no_remove = false; // Yuppers, kill this file! } if(!no_remove) { sstm_log(LOG_BUG, "Cleaning Hanging Descriptor: %d st_mode: %s: %08x", desc, st_mode((mode_t)info.st_mode), info.st_mode); close(desc); // Close the descriptor desc = -1; // Ensure the descriptor is now -1 cleaned++; } } } return; }