void diskbase_debug(dbref player) { double ph, pm; ph = propcache_hits; pm = propcache_misses; notify(player, "Cache info:"); notifyf(player, "Propcache hit ratio: %.3f%% (%ld hits / %ld fetches)", (100.0 * ph / (ph + pm)), propcache_hits, propcache_misses); report_fetchstats(player); notifyf(player, "PropLoaded count: %d", proploaded_Q.count); notifyf(player, "PropPriority count: %d", proppri_Q.count); notifyf(player, "PropChanged count: %d", propchanged_Q.count); report_cachestats(player); notify(player, "Done."); }
void do_restrict(dbref player, const char *arg) { if (!strcmp(arg, "on")) { wizonly_mode = 1; notify(player, "Login access is now restricted to wizards only."); } else if (!strcmp(arg, "off")) { wizonly_mode = 0; notify(player, "Login access is now unrestricted."); } else { notifyf(player, "Restricted connection mode is currently %s.", wizonly_mode ? "on" : "off" ); } }
void report_cachestats(dbref player) { dbref obj; int count, total, checked, gap, ipct; time_t when, now; double pct; notify(player, "LRU proploaded cache time distribution graph."); total = proploaded_Q.count; checked = 0; gap = 0; when = now = time(NULL); notify(player, "Mins Objs (%of db) Graph of #objs vs. age."); for (; checked < total; when -= 60) { count = 0; obj = first_ringqueue_obj(&proploaded_Q); while (obj != NOTHING) { if (DBFETCH(obj)->propstime > (when - 60) && DBFETCH(obj)->propstime <= when) count++; obj = next_ringqueue_obj(&proploaded_Q, obj); } checked += count; pct = count * 100.0 / total; ipct = count * 100 / total; if (ipct > 50) ipct = 50; if (count) { if (gap) notify(player, "[gap]"); notifyf(player, "%3ld:%6d (%5.2f%%) %*s", ((now - when) / 60), count, pct, ipct, "*"); gap = 0; } else { gap = 1; } } }
static void index_file(dbref player, const char *onwhat, const char *file) { FILE *f; char buf[BUFFER_LEN]; char topic[BUFFER_LEN]; char *p; size_t arglen; int found; *topic = '\0'; strcpyn(topic, sizeof(topic), onwhat); if (*onwhat) { strcatn(topic, sizeof(topic), "|"); } if ((f = fopen(file, "rb")) == NULL) { notifyf(player, "Sorry, %s is missing. Management has been notified.", file); fprintf(stderr, "help: No file %s!\n", file); } else { if (*topic) { arglen = strlen(topic); do { do { if (!(fgets(buf, sizeof buf, f))) { notifyf(player, "Sorry, no help available on topic \"%s\"", onwhat); fclose(f); return; } } while (*buf != '~'); do { if (!(fgets(buf, sizeof buf, f))) { notifyf(player, "Sorry, no help available on topic \"%s\"", onwhat); fclose(f); return; } } while (*buf == '~'); p = buf; found = 0; buf[strlen(buf) - 1] = '|'; while (*p && !found) { if (strncasecmp(p, topic, arglen)) { while (*p && (*p != '|')) p++; if (*p) p++; } else { found = 1; } } } while (!found); } while (fgets(buf, sizeof buf, f)) { if (*buf == '~') break; for (p = buf; *p; p++) { if (*p == '\n' || *p == '\r') { *p = '\0'; break; } } if (*buf) { notify(player, buf); } else { notify(player, " "); } } fclose(f); } }
/** * Implementation of the MUF debugger * * This implements the command parsing for the MUF debugger. It also clears * temporary bookmarks if this was triggered from a temporary one. * * This relies on some static globals, so it is not threadsafe. If the * 'prim' debugger command is ever used to trigger the MUF debugger somehow * in a recursive fashion, and then you call 'prim' again, it will probably * cause havock. * * @param descr the descriptor of the debugging player * @param player the debugging player * @param program the program we are debugging * @param text the input text from the user * @param fr the current frame pointer * @return boolean true if the program should exit, false if not */ int muf_debugger(int descr, dbref player, dbref program, const char *text, struct frame *fr) { char cmd[BUFFER_LEN]; char buf[BUFFER_LEN]; char buf2[BUFFER_LEN]; char *ptr, *ptr2, *arg; struct inst *pinst; int i, j, cnt; static struct inst primset[5]; static struct muf_proc_data temp_muf_proc_data = { "__Temp_Debugger_Proc", 0, 0, NULL }; /* * Basic massaging of the input - clearing spaces, finding the * argument. */ skip_whitespace(&text); strcpyn(cmd, sizeof(cmd), text); ptr = cmd; remove_ending_whitespace(&ptr); for (arg = cmd; *arg && !isspace(*arg); arg++) ; if (*arg) *arg++ = '\0'; /* Empty command means repeat last command, if available */ if (!*cmd && fr->brkpt.lastcmd) { strcpyn(cmd, sizeof(cmd), fr->brkpt.lastcmd); } else { free(fr->brkpt.lastcmd); if (*cmd) fr->brkpt.lastcmd = strdup(cmd); } /* delete triggering breakpoint, if it's only temp. */ j = fr->brkpt.breaknum; if (j >= 0 && fr->brkpt.temp[j]) { for (j++; j < fr->brkpt.count; j++) { fr->brkpt.temp[j - 1] = fr->brkpt.temp[j]; fr->brkpt.level[j - 1] = fr->brkpt.level[j]; fr->brkpt.line[j - 1] = fr->brkpt.line[j]; fr->brkpt.linecount[j - 1] = fr->brkpt.linecount[j]; fr->brkpt.pc[j - 1] = fr->brkpt.pc[j]; fr->brkpt.pccount[j - 1] = fr->brkpt.pccount[j]; fr->brkpt.prog[j - 1] = fr->brkpt.prog[j]; } fr->brkpt.count--; } fr->brkpt.breaknum = -1; /** * @TODO This giant if statement is pretty gnarly; we'd be better * of looping over an array of callbacks to break this up * nicer and make it more extensible. */ if (!strcasecmp(cmd, "cont")) { /* Nothing to do -- this will continue to next breakpoint */ } else if (!strcasecmp(cmd, "finish")) { if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "Cannot finish because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = fr->system.top - 1; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = -2; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = -2; fr->brkpt.prog[j] = program; fr->brkpt.bypass = 1; return 0; } else if (!strcasecmp(cmd, "stepi")) { i = atoi(arg); if (!i) i = 1; if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "Cannot stepi because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = -1; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = -2; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = i; fr->brkpt.prog[j] = NOTHING; fr->brkpt.bypass = 1; return 0; } else if (!strcasecmp(cmd, "step")) { i = atoi(arg); if (!i) i = 1; if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "Cannot step because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = -1; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = i; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = -2; fr->brkpt.prog[j] = NOTHING; fr->brkpt.bypass = 1; return 0; } else if (!strcasecmp(cmd, "nexti")) { i = atoi(arg); if (!i) i = 1; if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "Cannot nexti because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = fr->system.top; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = -2; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = i; fr->brkpt.prog[j] = program; fr->brkpt.bypass = 1; return 0; } else if (!strcasecmp(cmd, "next")) { i = atoi(arg); if (!i) i = 1; if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "Cannot next because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = fr->system.top; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = i; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = -2; fr->brkpt.prog[j] = program; fr->brkpt.bypass = 1; return 0; } else if (!strcasecmp(cmd, "exec")) { if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "Cannot finish because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } if (!(pinst = funcname_to_pc(program, arg))) { notify_nolisten(player, "I don't know a function by that name.", 1); add_muf_read_event(descr, player, program, fr); return 0; } if (fr->system.top >= STACK_SIZE) { notify_nolisten(player, "That would exceed the system stack size for this program.", 1); add_muf_read_event(descr, player, program, fr); return 0; } fr->system.st[fr->system.top].progref = program; fr->system.st[fr->system.top++].offset = fr->pc; fr->pc = pinst; j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = fr->system.top - 1; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = -2; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = -2; fr->brkpt.prog[j] = program; fr->brkpt.bypass = 1; return 0; } else if (!strcasecmp(cmd, "prim")) { /* * @TODO The way this works is a little funky. It looks like * it would be possible to cause some weird havoc if we * manage to run a primitive that in turn triggers muf_debugger * * I am uncertain if this is possible; looks like the only * way it could happen is by typing 'prim debugger_break' * but I don't know much about about how muf_debugger is * triggered. Some digging should be done to make this * safe. * * Even better would be to not use statics for this somehow * without introducing a memory leak. (tanabi) */ if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "Cannot finish because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } if (!primitive(arg)) { notify_nolisten(player, "I don't recognize that primitive.", 1); add_muf_read_event(descr, player, program, fr); return 0; } if (fr->system.top >= STACK_SIZE) { notify_nolisten(player, "That would exceed the system stack size for this program.", 1); add_muf_read_event(descr, player, program, fr); return 0; } primset[0].type = PROG_FUNCTION; primset[0].line = 0; primset[0].data.mufproc = &temp_muf_proc_data; primset[0].data.mufproc->vars = 0; primset[0].data.mufproc->args = 0; primset[0].data.mufproc->varnames = NULL; primset[1].type = PROG_PRIMITIVE; primset[1].line = 0; primset[1].data.number = get_primitive(arg); primset[2].type = PROG_PRIMITIVE; primset[2].line = 0; primset[2].data.number = IN_RET; /* primset[3].data.number = primitive("EXIT"); */ fr->system.st[fr->system.top].progref = program; fr->system.st[fr->system.top++].offset = fr->pc; fr->pc = &primset[1]; j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = -1; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = -2; fr->brkpt.pc[j] = &primset[2]; fr->brkpt.pccount[j] = -2; fr->brkpt.prog[j] = program; fr->brkpt.bypass = 1; fr->brkpt.dosyspop = 1; return 0; } else if (!strcasecmp(cmd, "break")) { add_muf_read_event(descr, player, program, fr); if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "Too many breakpoints set.", 1); return 0; } if (number(arg)) { i = atoi(arg); } else { if (!(pinst = funcname_to_pc(program, arg))) { notify_nolisten(player, "I don't know a function by that name.", 1); return 0; } else { i = pinst->line; } } if (!i) i = fr->pc->line; j = fr->brkpt.count++; fr->brkpt.temp[j] = 0; fr->brkpt.level[j] = -1; fr->brkpt.line[j] = i; fr->brkpt.linecount[j] = -2; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = -2; fr->brkpt.prog[j] = program; notify_nolisten(player, "Breakpoint set.", 1); return 0; } else if (!strcasecmp(cmd, "delete")) { add_muf_read_event(descr, player, program, fr); i = atoi(arg); if (!i) { notify_nolisten(player, "Which breakpoint did you want to delete?", 1); return 0; } if (i < 1 || i > fr->brkpt.count) { notify_nolisten(player, "No such breakpoint.", 1); return 0; } j = i - 1; for (j++; j < fr->brkpt.count; j++) { fr->brkpt.temp[j - 1] = fr->brkpt.temp[j]; fr->brkpt.level[j - 1] = fr->brkpt.level[j]; fr->brkpt.line[j - 1] = fr->brkpt.line[j]; fr->brkpt.linecount[j - 1] = fr->brkpt.linecount[j]; fr->brkpt.pc[j - 1] = fr->brkpt.pc[j]; fr->brkpt.pccount[j - 1] = fr->brkpt.pccount[j]; fr->brkpt.prog[j - 1] = fr->brkpt.prog[j]; } fr->brkpt.count--; notify_nolisten(player, "Breakpoint deleted.", 1); return 0; } else if (!strcasecmp(cmd, "breaks")) { notify_nolisten(player, "Breakpoints:", 1); for (i = 0; i < fr->brkpt.count; i++) { ptr = unparse_breakpoint(fr, i); notify_nolisten(player, ptr, 1); } notify_nolisten(player, "*done*", 1); add_muf_read_event(descr, player, program, fr); return 0; } else if (!strcasecmp(cmd, "where")) { i = atoi(arg); muf_backtrace(player, program, i, fr); add_muf_read_event(descr, player, program, fr); return 0; } else if (!strcasecmp(cmd, "stack")) { notify_nolisten(player, "*Argument stack top*", 1); i = atoi(arg); if (!i) i = STACK_SIZE; ptr = ""; for (j = fr->argument.top; j > 0 && i-- > 0;) { cnt = 0; do { strcpyn(buf, sizeof(buf), ptr); ptr = insttotext(NULL, 0, &fr->argument.st[--j], buf2, sizeof(buf2), 4000, program, 1); cnt++; } while (!strcasecmp(ptr, buf) && j > 0); if (cnt > 1) notifyf(player, " [repeats %d times]", cnt); if (strcasecmp(ptr, buf)) notifyf(player, "%3d) %s", j + 1, ptr); } notify_nolisten(player, "*done*", 1); add_muf_read_event(descr, player, program, fr); return 0; } else if (!strcasecmp(cmd, "list") || !strcasecmp(cmd, "listi")) { int startline, endline; add_muf_read_event(descr, player, program, fr); if ((ptr2 = (char *) strchr(arg, ','))) { *ptr2++ = '\0'; } else { ptr2 = ""; } if (!*arg) { if (fr->brkpt.lastlisted) { startline = fr->brkpt.lastlisted + 1; } else { startline = fr->pc->line; } endline = startline + 15; } else { if (!number(arg)) { if (!(pinst = funcname_to_pc(program, arg))) { notify_nolisten(player, "I don't know a function by that name. (starting arg, 1)", 1); return 0; } else { startline = pinst->line; endline = startline + 15; } } else { if (*ptr2) { endline = startline = atoi(arg); } else { startline = atoi(arg) - 7; endline = startline + 15; } } } if (*ptr2) { if (!number(ptr2)) { if (!(pinst = funcname_to_pc(program, ptr2))) { notify_nolisten(player, "I don't know a function by that name. (ending arg, 1)", 1); return 0; } else { endline = pinst->line; } } else { endline = atoi(ptr2); } } i = (PROGRAM_CODE(program) + PROGRAM_SIZ(program) - 1)->line; if (startline > i) { notify_nolisten(player, "Starting line is beyond end of program.", 1); return 0; } if (startline < 1) startline = 1; if (endline > i) endline = i; if (endline < startline) endline = startline; notify_nolisten(player, "Listing:", 1); if (!strcasecmp(cmd, "listi")) { for (i = startline; i <= endline; i++) { pinst = linenum_to_pc(program, i); if (pinst) { notifyf_nolisten(player, "line %d: %s", i, (i == fr->pc->line) ? show_line_prims(program, fr->pc, STACK_SIZE, 1) : show_line_prims(program, pinst, STACK_SIZE, 0)); } } } else { list_proglines(player, program, fr, startline, endline); } fr->brkpt.lastlisted = endline; notify_nolisten(player, "*done*", 1); return 0; } else if (!strcasecmp(cmd, "quit")) { notify_nolisten(player, "Halting execution.", 1); return 1; } else if (!strcasecmp(cmd, "trace")) { add_muf_read_event(descr, player, program, fr); if (!strcasecmp(arg, "on")) { fr->brkpt.showstack = 1; notify_nolisten(player, "Trace turned on.", 1); } else if (!strcasecmp(arg, "off")) { fr->brkpt.showstack = 0; notify_nolisten(player, "Trace turned off.", 1); } else { notifyf_nolisten(player, "Trace is currently %s.", fr->brkpt.showstack ? "on" : "off"); } return 0; } else if (!strcasecmp(cmd, "words")) { list_program_functions(player, program, arg); add_muf_read_event(descr, player, program, fr); return 0; } else if (!strcasecmp(cmd, "print")) { debug_printvar(player, program, fr, arg); add_muf_read_event(descr, player, program, fr); return 0; } else if (!strcasecmp(cmd, "push")) { push_arg(player, fr, arg); add_muf_read_event(descr, player, program, fr); return 0; } else if (!strcasecmp(cmd, "pop")) { add_muf_read_event(descr, player, program, fr); if (fr->argument.top < 1) { notify_nolisten(player, "Nothing to pop.", 1); return 0; } fr->argument.top--; CLEAR(fr->argument.st + fr->argument.top); notify_nolisten(player, "Stack item popped.", 1); return 0; } else if (!strcasecmp(cmd, "help")) { do_helpfile(player, tp_file_man_dir, tp_file_man, "debugger_commands", ""); return 0; } else { notify_nolisten(player, "I don't understand that debugger command. Type 'help' for help.", 1); add_muf_read_event(descr, player, program, fr); return 0; } return 0; }
void report_fetchstats(dbref player) { int i, count, slot; double sum, minv, maxv; time_t now; now = time(NULL); i = slot = ((now / FETCHSTATS_SLOT_TIME) % FETCHSTATS_SLOTS); while (lastfetchslot != slot) { lastfetchslot = ((lastfetchslot + 1) % FETCHSTATS_SLOTS); fetchstats[lastfetchslot] = 0; } sum = maxv = 0.0; minv = fetchstats[i]; count = 0; for (; count < (FETCHSTATS_INTERVAL1 / FETCHSTATS_SLOT_TIME); count++) { if (fetchstats[i] == -1) break; sum += fetchstats[i]; if (fetchstats[i] < minv) minv = fetchstats[i]; if (fetchstats[i] > maxv) maxv = fetchstats[i]; i = ((i + FETCHSTATS_SLOTS - 1) % FETCHSTATS_SLOTS); } notifyf(player, "Disk Fetches %2g minute min/avg/max: %.2f/%.2f/%.2f", (FETCHSTATS_INTERVAL1 / 60.0), (minv * 60.0 / FETCHSTATS_SLOT_TIME), (sum * 60.0 / (FETCHSTATS_SLOT_TIME * count)), (maxv * 60.0 / FETCHSTATS_SLOT_TIME)); for (; count < (FETCHSTATS_INTERVAL2 / FETCHSTATS_SLOT_TIME); count++) { if (fetchstats[i] == -1) break; sum += fetchstats[i]; if (fetchstats[i] < minv) minv = fetchstats[i]; if (fetchstats[i] > maxv) maxv = fetchstats[i]; i = ((i + FETCHSTATS_SLOTS - 1) % FETCHSTATS_SLOTS); } notifyf(player, "Disk Fetches %2g minute min/avg/max: %.2f/%.2f/%.2f", (FETCHSTATS_INTERVAL2 / 60.0), (minv * 60.0 / FETCHSTATS_SLOT_TIME), (sum * 60.0 / (FETCHSTATS_SLOT_TIME * count)), (maxv * 60.0 / FETCHSTATS_SLOT_TIME)); for (; count < (FETCHSTATS_INTERVAL3 / FETCHSTATS_SLOT_TIME); count++) { if (fetchstats[i] == -1) break; sum += fetchstats[i]; if (fetchstats[i] < minv) minv = fetchstats[i]; if (fetchstats[i] > maxv) maxv = fetchstats[i]; i = ((i + FETCHSTATS_SLOTS - 1) % FETCHSTATS_SLOTS); } notifyf(player, "Disk Fetches %2g minute min/avg/max: %.2f/%.2f/%.2f", (FETCHSTATS_INTERVAL3 / 60.0), (minv * 60.0 / FETCHSTATS_SLOT_TIME), (sum * 60.0 / (FETCHSTATS_SLOT_TIME * count)), (maxv * 60.0 / FETCHSTATS_SLOT_TIME)); }