static size_t format_transport(atransport *t, char *buf, size_t bufsize, int long_listing) { const char* serial = t->serial; if (!serial || !serial[0]) serial = "????????????"; if (!long_listing) { return snprintf(buf, bufsize, "%s\t%s\n", serial, statename(t)); } else { size_t len, remaining = bufsize; len = snprintf(buf, remaining, "%-22s %s", serial, statename(t)); remaining -= len; buf += len; add_qual(&buf, &remaining, " ", t->devpath, 0); add_qual(&buf, &remaining, " product:", t->product, 0); add_qual(&buf, &remaining, " model:", t->model, 1); add_qual(&buf, &remaining, " device:", t->device, 0); len = snprintf(buf, remaining, "\n"); remaining -= len; return bufsize - remaining; } }
/* Reevaluate the state machine based on the current state and flag settings */ void ifsm_flagpoll(struct if_info *info) { enum ifstate state = info->state; switch(info->state) { case ST_DOWN: if ((info->flags & (IFF_UP|IFF_RUNNING)) == 0) break; /* FALLTHROUGH */ case ST_INACTIVE: if (!(info->flags & IFF_UP)) { assert(info->worker == -1); info->worker = run_netplug_bg(info->name, "probe"); info->state = ST_PROBING; } else if (info->flags & IFF_RUNNING) { assert(info->worker == -1); info->worker = run_netplug_bg(info->name, "in"); info->state = ST_INNING; } break; case ST_PROBING: case ST_PROBING_UP: case ST_WAIT_IN: case ST_DOWNANDOUT: break; case ST_INNING: if (!(info->flags & IFF_RUNNING)) info->state = ST_WAIT_IN; break; case ST_ACTIVE: if (!(info->flags & IFF_RUNNING)) { assert(info->worker == -1); info->worker = run_netplug_bg(info->name, "out"); info->state = ST_OUTING; } break; case ST_OUTING: if (!(info->flags & IFF_UP)) info->state = ST_DOWNANDOUT; break; case ST_INSANE: break; } if (info->state != state) do_log(LOG_DEBUG, "ifsm_flagpoll %s: moved from state %s to %s", info->name, statename(state), statename(info->state)); }
int list_transports(char *buf, size_t bufsize) { char* p = buf; char* end = buf + bufsize; int len; atransport *t; /* XXX OVERRUN PROBLEMS XXX */ adb_mutex_lock(&transport_lock); for(t = transport_list.next; t != &transport_list; t = t->next) { const char* serial = t->serial; if (!serial || !serial[0]) serial = "????????????"; len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t)); if (p + len >= end) { /* discard last line if buffer is too short */ break; } p += len; } p[0] = 0; adb_mutex_unlock(&transport_lock); return p - buf; }
void GuiderStateMachine::configure() { if (!canConfigure()) { debug(LOG_ERR, DEBUG_LOG, 0, "cannot configured in state %s", statename()); throw BadState("cannot start calibration"); } _state = Guide::idle; }
void GuiderStateMachine::stopGuiding() { if (!canStopGuiding()) { debug(LOG_ERR, DEBUG_LOG, 0, "cannot stop guiding in state %s", statename()); throw BadState("cannot stop guiding in this state"); } _state = Guide::calibrated; }
void GuiderStateMachine::failCalibration() { if (!canFailCalibration()) { debug(LOG_ERR, DEBUG_LOG, 0, "cannot fail calibration in state %s", statename()); throw BadState("cannot fail calibration in this state"); } _state = Guide::idle; }
void GuiderStateMachine::addCalibration() { if (!canAcceptCalibration()) { debug(LOG_ERR, DEBUG_LOG, 0, "cannot accept calibration in state %s", statename()); throw BadState("cannot accept calibration in this state"); } _state = Guide::calibrated; }
void GuiderStateMachine::startCalibrating() { debug(LOG_DEBUG, DEBUG_LOG, 0, "start calibrating"); if (!canStartCalibrating()) { debug(LOG_ERR, DEBUG_LOG, 0, "cannot start calibrating in state %s", statename()); throw BadState("cannot start calibration"); } _state = Guide::calibrating; }
int ts_main(int argc, char *argv[]) { unsigned i, ntasks, n, skip; TaskInfo_t *ti, *info; bool enabled[NVCONS]; bool check_cons = false; // por defecto habilitar todas las consolas bool cursor; (getDriver(CONS_DRIVER)->ioctl_driver)(CONS_CURSOR,2,false,&cursor); memset(enabled, 0, sizeof enabled); for ( i = 1 ; i < argc ; i++ ) // habilitar las consolas especificadas { unsigned cons = atoi(argv[i]); if ( cons < NVCONS ) enabled[cons] = check_cons = true; } (getDriver(CONS_DRIVER)->ioctl_driver)(CONS_CLEAR,0); cprintk(WHITE, BLUE, "%s", title); (getDriver(CONS_DRIVER)->ioctl_driver)(CONS_GOTOXY,2,0,24); cprintk(WHITE, BLUE, "%s", foot); skip = 0; do { info = GetTasks(&ntasks); for ( n = 0, i = 1, ti = info ; i < 24 && ntasks-- ; ti++ ) { if ( (check_cons && !enabled[ti->consnum]) || n++ < skip ) continue; (getDriver(CONS_DRIVER)->ioctl_driver)(CONS_GOTOXY,2,0,i++); char namebuf[20]; sprintf(namebuf, ti->protected ? "[%.16s]" : "%.18s", name(ti->task)); cprintk(WHITE, BLACK, "%8x %-18s %u %10u %-9s %-18.18s", ti->task, namebuf, ti->consnum, ti->priority, statename(ti->state), name(ti->waiting)); if ( ti->is_timeout ) cprintk(WHITE, BLACK, " %10u", ti->timeout); else (getDriver(CONS_DRIVER)->ioctl_driver)(CONS_CLREOL,0); } while ( i < 24 ) { (getDriver(CONS_DRIVER)->ioctl_driver)(CONS_GOTOXY,2,0,i++); (getDriver(CONS_DRIVER)->ioctl_driver)(CONS_CLREOL,0); } Free(info); } while ( getuser(&skip) ); (getDriver(CONS_DRIVER)->ioctl_driver)(CONS_CLEAR,0); (getDriver(CONS_DRIVER)->ioctl_driver)(CONS_CURSOR,2,cursor,NULL); return 0; }
static bool debug_handler(struct le *le, void *arg) { struct sip_ctrans *ct = le->data; struct re_printf *pf = arg; (void)re_hprintf(pf, " %-10s %-10s %2llus (%s)\n", ct->met, statename(ct->state), tmr_get_expire(&ct->tmr)/1000, ct->branch); return false; }
int ts_main(int argc, char *argv[]) { unsigned i, ntasks, n, skip; TaskInfo_t *ti, *info; bool enabled[NVCONS]; bool check_cons = false; // por defecto habilitar todas las consolas bool cursor = mt_cons_cursor(false); memset(enabled, 0, sizeof enabled); for ( i = 1 ; i < argc ; i++ ) // habilitar las consolas especificadas { unsigned cons = atoi(argv[i]); if ( cons < NVCONS ) enabled[cons] = check_cons = true; } mt_cons_clear(); cprintk(WHITE, BLUE, "%s", title); // permite escribir con letra y fondo particular mt_cons_gotoxy(0, 24); // me ubica en un lugar en pantalla (X e Y) para deespues escribir. cprintk(WHITE, BLUE, "%s", foot); skip = 0; do { info = GetTasks(&ntasks); for ( n = 0, i = 1, ti = info ; i < 24 && ntasks-- ; ti++ ) { if ( (check_cons && !enabled[ti->consnum]) || n++ < skip ) continue; mt_cons_gotoxy(0, i++); char namebuf[20]; sprintf(namebuf, ti->protected ? "[%.16s]" : "%.18s", name(ti->task)); cprintk(WHITE, BLACK, "%8x %-18s %u %10u %-9s %-18.18s", ti->task, namebuf, ti->consnum, ti->priority, statename(ti->state), name(ti->waiting)); if ( ti->is_timeout ) cprintk(WHITE, BLACK, " %10u", ti->timeout); else mt_cons_clreol(); } while ( i < 24 ) { mt_cons_gotoxy(0, i++); mt_cons_clreol(); } Free(info); } while ( getuser(&skip) ); mt_cons_clear(); mt_cons_cursor(cursor); return 0; }
/** * \brief verify the current state of the step * * Derived classes may want to override this method to ensure that the are * always in state idle as long as they are not fully configured. Maybe we * could remove this requirement by adding an additional state unconfigured * below the idle level. */ ProcessingStep::state ProcessingStep::checkstate() { debug(LOG_DEBUG, DEBUG_LOG, 0, "checking state in %p", this); // find the smallest state that we should be in according to // our predecessors. We use a lambda comparator for this purpose state minstate = precursorstate(); debug(LOG_DEBUG, DEBUG_LOG, 0, "lowest precursor: %s", statename(minstate).c_str()); // if the state changes, signal to all our successors that we // have changed state, we again use a lambda for this state newstate = minstate; if (minstate == complete) { if (_status == idle) { newstate = needswork; } else { newstate = _status; } } else { newstate = idle; } // if the state does not change, return (this terminates the recursion) if (newstate == status()) { debug(LOG_DEBUG, DEBUG_LOG, 0, "no state change"); return status(); } // change state, and tell successors to check their state too debug(LOG_DEBUG, DEBUG_LOG, 0, "change state to %s", statename(minstate).c_str()); _status = newstate; std::for_each(_successors.begin(), _successors.end(), [](steps::value_type x) { x->checkstate(); }); // return the new state return status(); }
ProcessingStep::state ProcessingStep::precursorstate() const { // if there is no precursor, then we can consider them all complete if (_precursors.size() == 0) { return complete; } // if there are any precursors, we have to check their minimum state state minstate = (*std::min_element(_precursors.begin(), _precursors.end(), [](const ProcessingStep *a, const ProcessingStep *b) { return a->status() < b->status(); } ))->status(); debug(LOG_DEBUG, DEBUG_LOG, 0, "precursor state: %s", statename(minstate).c_str()); return minstate; }
/* endgame - checks if a constitutional amendment is ratified */ char ratify(int level,int lawview,int view,char congress,char canseethings) { if(canseethings) { music.play(MUSIC_ELECTIONS); erase(); set_color(COLOR_WHITE,COLOR_BLACK,1); move(0,0); addstr("The Ratification Process:"); } //THE STATE VOTE WILL BE BASED ON VIEW OF LAW int mood=publicmood(lawview); //OR OF A PARTICULAR ISSUE if(view>=0) mood=attitude[view]; //CONGRESS bool ratified=false; int y=0; if(congress) { ratified=true; if(canseethings) { move(0,62); addstr("House"); move(0,70); addstr("Senate"); move(24,0); addstr("Press any key to watch the Congressional votes unfold. "); getkey(); } bool yeswin_h=false,yeswin_s=false; int yesvotes_h=0,yesvotes_s=0,vote,s=0; for(int l=0;l<HOUSENUM;l++) { vote=house[l]; if(vote>=-1&&vote<=1) vote+=LCSrandom(3)-1; if(level==vote) yesvotes_h++; if(l==HOUSENUM-1) if(yesvotes_h>=HOUSESUPERMAJORITY) yeswin_h=true; if(canseethings) { if(l==HOUSENUM-1&&yeswin_h) set_color(COLOR_WHITE,COLOR_BLACK,1); else if(l==HOUSENUM-1) set_color(COLOR_BLACK,COLOR_BLACK,1); else set_color(COLOR_WHITE,COLOR_BLACK,0); move(2,62); addstr(yesvotes_h); addstr(" Yea"); if(l==HOUSENUM-1&&!yeswin_h) set_color(COLOR_WHITE,COLOR_BLACK,1); else if(l==HOUSENUM-1) set_color(COLOR_BLACK,COLOR_BLACK,1); else set_color(COLOR_WHITE,COLOR_BLACK,0); move(3,62); addstr(l+1-yesvotes_h); addstr(" Nay"); } if(l%4==0&&s<SENATENUM) { vote=senate[s++]; if(vote>=-1&&vote<=1) vote+=LCSrandom(3)-1; if(level==vote) yesvotes_s++; } if(l==HOUSENUM-1&&yesvotes_s>=SENATESUPERMAJORITY) yeswin_s=true; if(canseethings) { if(l==HOUSENUM-1&&yeswin_s) set_color(COLOR_WHITE,COLOR_BLACK,1); else if(l==HOUSENUM-1) set_color(COLOR_BLACK,COLOR_BLACK,1); else set_color(COLOR_WHITE,COLOR_BLACK,0); move(2,70); addstr(yesvotes_s); addstr(" Yea"); if(l==HOUSENUM-1&&!yeswin_s) set_color(COLOR_WHITE,COLOR_BLACK,1); else if(l==HOUSENUM-1) set_color(COLOR_BLACK,COLOR_BLACK,1); else set_color(COLOR_WHITE,COLOR_BLACK,0); move(3,70); addstr(s-yesvotes_s); addstr(" Nay"); if(l%5==0) pause_ms(10); } } if(!yeswin_h||!yeswin_s) ratified=false; y+=4; } else ratified=true; if(level==3) level=-2; // special case for Stalinists: do this after Congress but before the states //STATES if(ratified) { ratified=false; int yesstate=0; if(canseethings) { set_color(COLOR_WHITE,COLOR_BLACK,1); for(int s=0;s<50;s++) { if(s<17) move(5+s,0); else if(s<34) move(5+s-17,27); else move(5+s-34,54); addstr(statename(s)); } move(24,0); addstr("Press any key to watch the State votes unfold. "); getkey(); } int vote,smood; for(int s=0;s<STATENUM;s++) { smood=mood; // State biases. int multiplier = 5+LCSrandom(3); switch(s) { case 0:smood-=3*multiplier;break; // Alabama case 1:smood-=4*multiplier;break; // Alaska case 2:smood-=1*multiplier;break; // Arkansas case 3:smood-=2*multiplier;break; // Arizona case 4:smood+=4*multiplier;break; // California case 5:break; // Colorado case 6:smood+=3*multiplier;break; // Connecticut case 7:smood+=3*multiplier;break; // Delaware case 8:break; // Florida case 9:smood-=2*multiplier;break; // Georgia case 10:smood+=4*multiplier;break; // Hawaii case 11:smood-=5*multiplier;break; // Idaho case 12:smood+=4*multiplier;break; // Illinois case 13:smood-=1*multiplier;break; // Indiana case 14:smood+=1*multiplier;break; // Iowa case 15:smood-=3*multiplier;break; // Kansas case 16:smood-=3*multiplier;break; // Kentucky case 17:smood-=1*multiplier;break; // Louisiana case 18:smood+=2*multiplier;break; // Maine case 19:smood+=3*multiplier;break; // Maryland case 20:smood+=6*multiplier;break; // Massachusetts case 21:smood+=2*multiplier;break; // Michigan case 22:smood+=2*multiplier;break; // Minnesota case 23:smood-=4*multiplier;break; // Mississippi case 24:smood-=1*multiplier;break; // Missouri case 25:smood-=2*multiplier;break; // Montana case 26:smood-=3*multiplier;break; // Nebraska case 27:break; // Nevada case 28:smood+=1*multiplier;break; // New Hampshire case 29:smood+=3*multiplier;break; // New Jersey case 30:smood+=1*multiplier;break; // New Mexico case 31:smood+=5*multiplier;break; // New York case 32:smood-=1*multiplier;break; // North Carolina case 33:smood-=3*multiplier;break; // North Dakota case 34:break; // Ohio case 35:smood-=4*multiplier;break; // Oklahoma case 36:smood+=3*multiplier;break; // Oregon case 37:smood+=2*multiplier;break; // Pennsylvania case 38:smood+=4*multiplier;break; // Rhode Island case 39:smood-=5*multiplier;break; // South Carolina case 40:smood-=3*multiplier;break; // South Dakota case 41:smood-=2*multiplier;break; // Tennessee case 42:smood-=4*multiplier;break; // Texas case 43:smood-=6*multiplier;break; // Utah case 44:smood+=5*multiplier;break; // Vermont case 45:break; // Virginia case 46:smood+=3*multiplier;break; // Washington case 47:smood-=2*multiplier;break; // West Virginia case 48:smood+=2*multiplier;break; // Wisconsin case 49:smood-=5*multiplier;break; // Wyoming } vote=-2; if(LCSrandom(100)<smood)vote++; if(LCSrandom(100)<smood)vote++; if(LCSrandom(100)<smood)vote++; if(LCSrandom(100)<smood)vote++; if(vote==1&&!LCSrandom(2)) vote=2; if(vote==-1&&!LCSrandom(2)) vote=-2; if(canseethings) { set_color(COLOR_WHITE,COLOR_BLACK,1); if(s<17) move(5+s,22); else if(s<34) move(5+s-17,49); else move(5+s-34,76); } if(vote==level) { yesstate++; if(canseethings) addstr("Yea"); } else if(canseethings) addstr("Nay"); if(canseethings) { if(s==STATENUM-1&&yesstate>=STATESUPERMAJORITY) set_color(COLOR_WHITE,COLOR_BLACK,1); else if(s==STATENUM-1) set_color(COLOR_BLACK,COLOR_BLACK,1); else set_color(COLOR_WHITE,COLOR_BLACK,0); move(23,50); addstr(yesstate); addstr(" Yea"); if(s==STATENUM-1&&yesstate<STATESUPERMAJORITY) set_color(COLOR_WHITE,COLOR_BLACK,1); else if(s==STATENUM-1) set_color(COLOR_BLACK,COLOR_BLACK,1); else set_color(COLOR_WHITE,COLOR_BLACK,0); move(23,60); addstr(s+1-yesstate); addstr(" Nay"); pause_ms(50); } } if(yesstate>=STATESUPERMAJORITY) ratified=true; } if(canseethings) { set_color(COLOR_WHITE,COLOR_BLACK,1); move(23,0); if(ratified) addstr("AMENDMENT ADOPTED."); else addstr("AMENDMENT REJECTED."); } return ratified; }
static void replay_one_trace_frame(struct dbg_context* dbg, struct context* ctx) { struct dbg_request req; struct rep_trace_step step; int event = ctx->trace.stop_reason; int stop_sig = 0; debug("%d: replaying event %s, state %s", ctx->rec_tid, strevent(event), statename(ctx->trace.state)); if (ctx->syscallbuf_hdr) { debug(" (syscllbufsz:%u, abrtcmt:%u)", ctx->syscallbuf_hdr->num_rec_bytes, ctx->syscallbuf_hdr->abort_commit); } /* Advance the trace until we've exec()'d the tracee before * processing debugger requests. Otherwise the debugger host * will be confused about the initial executable image, * rr's. */ if (validate) { req = process_debugger_requests(dbg, ctx); assert(dbg_is_resume_request(&req)); } /* print some kind of progress */ if (ctx->trace.global_time % 10000 == 0) { fprintf(stderr, "time: %u\n",ctx->trace.global_time); } if (ctx->child_sig != 0) { assert(event == -ctx->child_sig || event == -(ctx->child_sig | DET_SIGNAL_BIT)); ctx->child_sig = 0; } /* Ask the trace-interpretation code what to do next in order * to retire the current frame. */ memset(&step, 0, sizeof(step)); switch (event) { case USR_INIT_SCRATCH_MEM: { /* for checksumming: make a note that this area is * scratch and need not be validated. */ struct mmapped_file file; read_next_mmapped_file_stats(&file); replay_init_scratch_memory(ctx, &file); add_scratch((void*)ctx->trace.recorded_regs.eax, file.end - file.start); step.action = TSTEP_RETIRE; break; } case USR_EXIT: rep_sched_deregister_thread(&ctx); /* Early-return because |ctx| is gone now. */ return; case USR_ARM_DESCHED: case USR_DISARM_DESCHED: rep_skip_desched_ioctl(ctx); /* TODO */ step.action = TSTEP_RETIRE; break; case USR_SYSCALLBUF_ABORT_COMMIT: ctx->syscallbuf_hdr->abort_commit = 1; step.action = TSTEP_RETIRE; break; case USR_SYSCALLBUF_FLUSH: rep_process_flush(ctx, rr_flags->redirect); /* TODO */ step.action = TSTEP_RETIRE; break; case USR_SYSCALLBUF_RESET: ctx->syscallbuf_hdr->num_rec_bytes = 0; step.action = TSTEP_RETIRE; break; case USR_SCHED: step.action = TSTEP_PROGRAM_ASYNC_SIGNAL_INTERRUPT; step.target.rcb = ctx->trace.rbc; step.target.regs = &ctx->trace.recorded_regs; step.target.signo = 0; break; case SIG_SEGV_RDTSC: step.action = TSTEP_DETERMINISTIC_SIGNAL; step.signo = SIGSEGV; break; default: /* Pseudosignals are handled above. */ assert(event > LAST_RR_PSEUDOSIGNAL); if (FIRST_DET_SIGNAL <= event && event <= LAST_DET_SIGNAL) { step.action = TSTEP_DETERMINISTIC_SIGNAL; step.signo = (-event & ~DET_SIGNAL_BIT); stop_sig = step.signo; } else if (event < 0) { assert(FIRST_ASYNC_SIGNAL <= event && event <= LAST_ASYNC_SIGNAL); step.action = TSTEP_PROGRAM_ASYNC_SIGNAL_INTERRUPT; step.target.rcb = ctx->trace.rbc; step.target.regs = &ctx->trace.recorded_regs; step.target.signo = -event; stop_sig = step.target.signo; } else { assert(event > 0); /* XXX not so pretty ... */ validate |= (ctx->trace.state == STATE_SYSCALL_EXIT && event == SYS_execve); rep_process_syscall(ctx, rr_flags->redirect, &step); } } /* See the comment below about *not* resetting the hpc for * buffer flushes. Here, we're processing the *other* event, * just after the buffer flush, where the rcb matters. To * simplify the advance-to-target code that follows (namely, * making debugger interrupts simpler), pretend like the * execution in the BUFFER_FLUSH didn't happen by resetting * the rbc and compensating down the target rcb. */ if (TSTEP_PROGRAM_ASYNC_SIGNAL_INTERRUPT == step.action) { uint64_t rcb_now = read_rbc(ctx->hpc); assert(step.target.rcb >= rcb_now); step.target.rcb -= rcb_now; reset_hpc(ctx, 0); } /* Advance until |step| has been fulfilled. */ while (try_one_trace_step(ctx, &step, &req)) { struct user_regs_struct regs; /* Currently we only understand software breakpoints * and successful stepi's. */ assert(SIGTRAP == ctx->child_sig && "Unknown trap"); read_child_registers(ctx->child_tid, ®s); if (ip_is_breakpoint((void*)regs.eip)) { /* SW breakpoint: $ip is just past the * breakpoint instruction. Move $ip back * right before it. */ regs.eip -= sizeof(int_3_insn); write_child_registers(ctx->child_tid, ®s); } else { /* Successful stepi. Nothing else to do. */ assert(DREQ_STEP == req.type && req.target == get_threadid(ctx)); } /* Don't restart with SIGTRAP anywhere. */ ctx->child_sig = 0; /* Notify the debugger and process any new requests * that might have triggered before resuming. */ dbg_notify_stop(dbg, get_threadid(ctx), 0x05/*gdb mandate*/); req = process_debugger_requests(dbg, ctx); assert(dbg_is_resume_request(&req)); } if (dbg && stop_sig) { dbg_notify_stop(dbg, get_threadid(ctx), stop_sig); } /* We flush the syscallbuf in response to detecting *other* * events, like signal delivery. Flushing the syscallbuf is a * sort of side-effect of reaching the other event. But once * we've flushed the syscallbuf during replay, we still must * reach the execution point of the *other* event. For async * signals, that requires us to have an "intact" rbc, with the * same value as it was when the last buffered syscall was * retired during replay. We'll be continuing from that rcb * to reach the rcb we recorded at signal delivery. So don't * reset the counter for buffer flushes. (It doesn't matter * for non-async-signal types, which are deterministic.) */ switch (ctx->trace.stop_reason) { case USR_SYSCALLBUF_ABORT_COMMIT: case USR_SYSCALLBUF_FLUSH: case USR_SYSCALLBUF_RESET: break; default: reset_hpc(ctx, 0); } debug_memory(ctx); }
/* handle a script termination and update the state accordingly */ void ifsm_scriptdone(pid_t pid, int exitstatus) { int exitok = WIFEXITED(exitstatus) && WEXITSTATUS(exitstatus) == 0; struct if_info *info; assert(WIFEXITED(exitstatus) || WIFSIGNALED(exitstatus)); int find_pid(struct if_info *i) { if (i->worker == pid) { info = i; return 1; } return 0; } info = NULL; for_each_iface(find_pid); if (info == NULL) { do_log(LOG_INFO, "Unexpected child %d exited with status %d", pid, exitstatus); return; } do_log(LOG_INFO, "%s: state %s pid %d exited status %d", info->name, statename(info->state), pid, exitstatus); info->worker = -1; switch(info->state) { case ST_PROBING: /* If we're still in PROBING state, then it means that the interface flags have not come up, even though the script finished. Go back to DOWN and wait for the UP flag setting. */ if (!exitok) do_log(LOG_WARNING, "Could not bring %s back up", info->name); info->state = ST_DOWN; break; case ST_PROBING_UP: /* regardless of script's exit status, the interface is actually up now, so just make it inactive */ info->state = ST_INACTIVE; break; case ST_DOWNANDOUT: /* we were just waiting for the out script to finish - start a probe script for this interface */ info->state = ST_PROBING; assert(info->worker == -1); info->worker = run_netplug_bg(info->name, "probe"); break; case ST_INNING: if (exitok) info->state = ST_ACTIVE; else info->state = ST_INSANE; /* ??? */ break; case ST_OUTING: /* What if !exitok? What if interface is still active? ->ST_INSANE? */ info->state = ST_INACTIVE; break; case ST_WAIT_IN: assert(info->worker == -1); info->worker = run_netplug_bg(info->name, "out"); info->state = ST_OUTING; break; case ST_INACTIVE: case ST_ACTIVE: case ST_INSANE: case ST_DOWN: do_log(LOG_ERR, "ifsm_scriptdone: %s: bad state %s for script termination", info->name, statename(info->state)); exit(1); } do_log(LOG_DEBUG, "%s: moved to state %s", info->name, statename(info->state)); }
/* if_info state machine transitions caused by interface flag changes (edge triggered) */ void ifsm_flagchange(struct if_info *info, unsigned int newflags) { unsigned int changed = (info->flags ^ newflags) & (IFF_RUNNING | IFF_UP); if (changed == 0) return; char buf1[512], buf2[512]; do_log(LOG_INFO, "%s: state %s flags 0x%08x %s -> 0x%08x %s", info->name, statename(info->state), info->flags, flags_str(buf1, info->flags), newflags, flags_str(buf2, newflags)); /* XXX put interface state-change rate limiting here */ if (0 /* flapping */) { info->state = ST_INSANE; } if (changed & IFF_UP) { if (newflags & IFF_UP) { switch(info->state) { case ST_DOWN: info->state = ST_INACTIVE; break; case ST_PROBING: info->state = ST_PROBING_UP; break; default: do_log(LOG_ERR, "%s: unexpected state %s for UP", info->name, statename(info->state)); exit(1); } } else { /* interface went down */ switch(info->state) { case ST_OUTING: /* went down during an OUT script - OK */ info->state = ST_DOWNANDOUT; break; case ST_DOWN: /* already down */ break; case ST_PROBING: /* already probing - don't do anything rash */ break; case ST_PROBING_UP: /* well, we were up, but now we're not */ info->state = ST_PROBING; break; default: /* All other states: kill off any scripts currently running, and go into the PROBING state, attempting to bring it up */ kill_script(info->worker); info->state = ST_PROBING; info->worker = run_netplug_bg(info->name, "probe"); } } } if (changed & IFF_RUNNING) { switch(info->state) { case ST_INACTIVE: assert(!(info->flags & IFF_RUNNING)); assert(info->worker == -1); info->worker = run_netplug_bg(info->name, "in"); info->state = ST_INNING; break; case ST_INNING: assert(info->flags & IFF_RUNNING); info->state = ST_WAIT_IN; break; case ST_WAIT_IN: /* unaffected by interface flag changing */ break; case ST_ACTIVE: assert(info->flags & IFF_RUNNING); assert(info->worker == -1); info->worker = run_netplug_bg(info->name, "out"); info->state = ST_OUTING; break; case ST_OUTING: /* always go to INACTIVE regardless of flag state */ break; case ST_PROBING: case ST_PROBING_UP: /* ignore running state */ break; case ST_INSANE: /* stay insane until there's been quiet for a while, then down interface and switch to ST_DOWN */ break; case ST_DOWN: case ST_DOWNANDOUT: /* badness: somehow interface became RUNNING without being UP - ignore it */ break; } } do_log(LOG_DEBUG, "%s: moved to state %s; worker %d", info->name, statename(info->state), info->worker); info->flags = newflags; info->lastchange = time(0); }