/* This software is Copyright 1989, 1990, 1992, 1993 by various individuals. Please see the accompanying file COPYRIGHT for details. */ #include #include "db.h" #include "defs.h" #include "match.h" #include "prims.h" #include "config.h" #include "params.h" #include "externs.h" #include "property.h" #include "interface.h" #include "unused-arg.h" dbref head_daemon = NOTHING; dbref tail_daemon = NOTHING; #define EXPIRED(x) (curtm() >= DBFETCH(x)->sp.daemon.cycles) void add_daemon(dbref daemon) { if (head_daemon != NOTHING) { DBSTORE(tail_daemon,next,daemon); } else { head_daemon = daemon; } tail_daemon = daemon; DBSTORE(tail_daemon,next,NOTHING); } void remove_daemon(dbref daemon) { if (head_daemon == NOTHING) return; if (head_daemon == daemon) { head_daemon = DBFETCH(daemon)->next; if (head_daemon == NOTHING) tail_daemon = NOTHING; } else { dbref last; dbref tmp; last = head_daemon; while (1) { tmp = DBFETCH(last)->next; if (tmp == NOTHING) return; if (tmp == daemon) break; last = tmp; } DBSTORE(last,next,DBFETCH(tmp)->next); if (tmp == tail_daemon) { tail_daemon = last; DBSTORE(tail_daemon,next,NOTHING); } } if (DBFETCH(daemon)->sp.daemon.sleepobj != NOTHING) { wakeup_sleepers(DBFETCH(daemon)->sp.daemon.sleepobj); } DBSTORE(OWNER(daemon),sp.player.daemons,DBFETCH(OWNER(daemon))->sp.player.daemons-1); if (DBFETCH(daemon)->sp.daemon.run) prog_abort(daemon); recycle(OWNER(daemon),daemon,1); } void do_daemon_go(dbref player, const char *what) { dbref thing; struct match_data md; init_match_check_keys(player,what,TYPE_THING,&md); match_neighbor(&md); if (Wizard(player)) match_absolute(&md); /* the wizard has long fingers */ thing = noisy_match_result(&md); if (thing == NOTHING) return; if (Typeof(thing) != TYPE_DAEMON) { notify(player,"Take off eh? That's not a daemon!"); return; } if ((OWNER(thing) != player) && !Wizard(player)) { notify(player,"You can't make that daemon go!"); return; } interp_resume(thing); if (! (FLAGS(thing) & INTERACTIVE)) remove_daemon(thing); } void daemon_set_time(dbref daemon, int cycles) { DBSTORE(daemon,sp.daemon.cycles, (cycles >= 0) ? (cycles + curtm()) : ((~(unsigned long int)0) >> 1) ); } dbref new_daemon(dbref player, dbref program, int cycles) { dbref daemon; char buf[BUFSIZ]; /* don't check quota_room here 'cause this is a "can't fail" routine; db spamming via daemons is not, in practice, a problem, and the daemon will count against the quota anyway for future checks. */ daemon = new_object(TYPE_DAEMON); sprintf(buf,"%s daemon",NAME(program)); NAME(daemon) = dup_string(buf); sprintf(buf,"A wild-eyed screaming %s daemon conjured by %s.",NAME(program),NAME(player)); DBSTORE(daemon,description,store_str(buf)); DBSTORE(daemon,location,NOTHING); DBSTORE(daemon,owner,player); FLAGS(daemon) = (( (FLAGS(program) & SETUID) ? FLAGS(OWNER(program)) : FLAGS(player) ) & ~(TYPE_MASK|UNSEEN|HAVEN)) | TYPE_DAEMON | INTERACTIVE; daemon_set_time(daemon,cycles); DBSTORE(daemon,sp.daemon.run,0); DBSTORE(daemon,sp.daemon.proglocks,0); DBSTORE(daemon,sp.daemon.proglock_type,0); DBSTORE(daemon,sp.daemon.sleepobj,NOTHING); add_ownerlist(daemon); DBDIRTY(daemon); add_daemon(daemon); DBSTORE(player,sp.player.daemons,DBFETCH(player)->sp.player.daemons+1); return(daemon); } void wakeup_sleepers(dbref obj) { struct dbref_list *drl; struct dbref_list *ndrl; for (drl=DBFETCH(obj)->sleepers;drl;drl=ndrl) { ndrl = drl->next; DBSTORE(drl->object,sp.daemon.sleepobj,NOTHING); daemon_set_time(drl->object,0); free(drl); } DBSTORE(obj,sleepers,0); } void daemon_sleep(dbref daemon, dbref obj) { struct dbref_list *drl; DBSTORE(daemon,sp.daemon.sleepobj,obj); drl = (struct dbref_list *) malloc(sizeof(struct dbref_list)); drl->object = daemon; drl->next = DBFETCH(obj)->sleepers; DBSTORE(obj,sleepers,drl); } void launch_daemons() { dbref i; int done; extern int big_fat_descripto_lock; if (big_fat_descripto_lock) return; big_fat_descripto_lock = 1; done = 0; while ((head_daemon != NOTHING) && !done) { if (EXPIRED(head_daemon)) interp_resume(head_daemon); if (! (FLAGS(head_daemon)&INTERACTIVE)) { remove_daemon(head_daemon); } else { done = 1; } } for (i=head_daemon;(i!=NOTHING)&&(DBFETCH(i)->next!=NOTHING);i=DBFETCH(i)->next) { SERIAL iser; done = 0; iser = DBFETCH(i)->serial; while ( !done && (Typeof(i) == TYPE_DAEMON) && (DBFETCH(i)->next != NOTHING) ) { done = 1; if (EXPIRED(DBFETCH(i)->next)) { dbref t; SERIAL tser; t = DBFETCH(i)->next; tser = DBFETCH(t)->serial; interp_resume(t); if ( (Typeof(i) != TYPE_DAEMON) || (DBFETCH(i)->serial != iser) ) return; if ( (Typeof(t) != TYPE_DAEMON) || (DBFETCH(t)->serial != tser) || !(FLAGS(t)&INTERACTIVE) ) { remove_daemon(t); done = 0; } } } } } extern int alarm_interval; void do_daemon_ps(dbref player, UNUSED_ARG(const char *name)) { dbref i; int s; int c; int n; char buf[BUFFER_LEN]; char tbuf[20]; if (alarm_interval == 1) { notify(player,"Daemons are being refreshed every second."); } else { sprintf(&buf[0],"Daemons are being refreshed every %d second%s.",alarm_interval,(alarm_interval==1)?"":"s"); notify(player,&buf[0]); } if (head_daemon != NOTHING) { for (i=head_daemon;i!=NOTHING;i=DBFETCH(i)->next) { if (Typeof(i) == TYPE_DAEMON) { if ((player == OWNER(i)) || Wizard(player)) { c = 0; strcpy(&buf[c],NAME(i)); c += strlen(&buf[c]); while (c < 25) buf[c++] = ' '; sprintf(&buf[c],"(#%6d)",(int)i); c += strlen(&buf[c]); s = DBFETCH(i)->sp.daemon.cycles - curtm(); if (s < 0) { tbuf[0] = '-'; tbuf[1] = '\0'; s = - s; } else { tbuf[0] = '\0'; } sprintf(&tbuf[strlen(&tbuf[0])],"%dd%02d:%02d:%02d",s/86400,(s%86400)/3600,(s%3600)/60,s%60); n = strlen(&tbuf[0]); while (c+n < 55) buf[c++] = ' '; strcpy(&buf[c],&tbuf[0]); c += strlen(&buf[c]); if (Wizard(player)) { strcpy(&buf[c]," "); c += 4; strcpy(&buf[c],NAME(OWNER(i))); } notify(player,&buf[0]); } } } sprintf(&buf[0],"You currently have %d daemon%s running.",DBFETCH(player)->sp.player.daemons,(DBFETCH(player)->sp.player.daemons==1)?"":"s"); notify(player,&buf[0]); } } void do_daemon_kill(dbref player, char *num) { dbref daemon; char buf[BUFFER_LEN]; if (num[0] == '#') num[0] = '0'; daemon = (dbref) atoi(num); if ((daemon < 0) || (daemon >= db_top)) { notify(player,"Invalid obj #"); return; } if (Typeof(daemon) != TYPE_DAEMON) { notify(player,"That's not a daemon."); return; } if ( !Wizard(player) && ( (player != OWNER(daemon)) || (FLAGS(daemon) & UNKILLABLE) ) ) { notify(player,"Permission denied."); return; } sprintf(buf,"Daemon #%d killed.",daemon); remove_daemon(daemon); notify(player,buf); } static void autostart_err(dbref player, dbref thing, const char *msg) { char buf[256]; sprintf(&buf[0],"Autostart error for #%d: %s\n",(int)thing,msg); notify(player,&buf[0]); log_status("Autostart error (player=#%d thing=#%d): %s",(int)player,(int)thing,msg); } void do_autostart_exits(void) { dbref thing; dbref player; dbref i; struct propref *pr; char *p; for (thing=0;thingsp.exit.dest[0]; if (i < 0) { autostart_err(player,thing,"link-to is < 0"); } else if (i >= db_top) { autostart_err(player,thing,"link-to is >= db_top"); } else if (Typeof(i) != TYPE_PROGRAM) { autostart_err(player,thing,"link-to isn't a program"); } else if (DBFETCH(player)->sp.player.run) { autostart_err(player,thing,"player.sp.run is busy"); } else { pr = lookup_property(thing,"_autostart",0); p = (pr && ((propref_get_attr(pr) & PATTR_TYPE) == PTYPE_STRING)) ? propref_get_string(pr) : 0; interp(player,i,thing,DoNullInd(p),makearray(1,makeinst(PROG_STRING,dup_string("autostart")))); if (p) free(p); if (pr) propref_done(pr); } } } } void run_dropto(dbref loc, dbref pgm, dbref arg) { dbref newdaemon; struct frame *fr; if (Typeof(pgm) != TYPE_PROGRAM) return; if (DBFETCH(GOD_DBREF)->sp.player.daemons >= MAX_WIZ_DAEMONS) return; if (DBFETCH(pgm)->sp.program.start == 0) { DBSTORE(pgm,sp.program.first,read_program(pgm)); do_compile(NOTHING,pgm,NOTHING); free_prog_text(DBFETCH(pgm)->sp.program.first); } if (DBFETCH(pgm)->sp.program.start == 0) return; fr = new_frame(); fr->systop = 0; fr->pc = DBFETCH(pgm)->sp.program.start; fr->writeonly = 1; fr->reading = 0; init_variables( fr, makeinst(PROG_OBJECT,arg), makeinst(PROG_OBJECT,loc), makeinst(PROG_OBJECT,arg), makeinst(PROG_OBJECT,loc) ); fr->caller = malloc(sizeof(struct dbref_list)); fr->caller->next = 0; fr->caller->object = GOD_DBREF; fr->trigger = arg; fr->startcaller = GOD_DBREF; fr->prog = pgm; push(fr->argument.st,&fr->argument.top,PROG_OBJECT,arg); newdaemon = new_daemon(GOD_DBREF,pgm,0); fr->daemon = newdaemon; DBSTORE(newdaemon,sp.daemon.run,fr); add_proglock(pgm,newdaemon,PROGLOCK_READ); }