📄 dev_vtty.c
字号:
u_char c; if (read(vtty->fd,&c,1) == 1) return(c); perror("read from vtty failed"); return(-1);}/* * Read a character from the TCP connection. */static int vtty_tcp_read(vtty_t *vtty){ u_char c; switch(vtty->state) { case VTTY_STATE_TCP_RUNNING: if (read(vtty->fd,&c,1) == 1) return(c); /* Problem with the connection: Re-enter wait mode */ shutdown(vtty->fd,2); fclose(vtty->fstream); close(vtty->fd); vtty->fstream = NULL; vtty->fd = -1; vtty->select_fd = &vtty->accept_fd; vtty->state = VTTY_STATE_TCP_WAITING; return(-1); case VTTY_STATE_TCP_WAITING: /* A new connection has arrived */ vtty_tcp_conn_accept(vtty); return(-1); } /* Shouldn't happen... */ return(-1);}/* * Read a character from the virtual TTY. * * If the VTTY is a TCP connection, restart it in case of error. */static int vtty_read(vtty_t *vtty){ switch(vtty->type) { case VTTY_TYPE_TERM: case VTTY_TYPE_SERIAL: return(vtty_term_read(vtty)); case VTTY_TYPE_TCP: return(vtty_tcp_read(vtty)); default: fprintf(stderr,"vtty_read: bad vtty type %d\n",vtty->type); return(-1); } /* NOTREACHED */ return(-1);}/* Process remote control char */static void remote_control(vtty_t *vtty,u_char c){ vm_instance_t *vm = vtty->vm; cpu_mips_t *cpu0 = cpu_group_find_id(vm->cpu_group,0); switch(c) { /* Show the object list */ case 'o': vm_object_dump(vm); break; /* Stop the MIPS VM */ case 'q': vm->status = VM_STATUS_SHUTDOWN; break; /* Reboot the C7200 */ case 'k': if (vm->type == VM_TYPE_C7200) c7200_boot_ios(VM_C7200(vm)); break; /* Show the device list */ case 'd': dev_show_list(vm); pci_dev_show_list(vm->pci_bus[0]); pci_dev_show_list(vm->pci_bus[1]); break; /* Show info about Port Adapters or Network Modules */ case 'p': switch(vm->type) { case VM_TYPE_C3600: c3600_nm_show_all_info(VM_C3600(vm)); break; case VM_TYPE_C7200: c7200_pa_show_all_info(VM_C7200(vm)); break; } break; /* Dump the MIPS registers */ case 'r': if (cpu0) mips64_dump_regs(cpu0); break; /* Dump the latest memory accesses */ case 'm': if (cpu0) memlog_dump(cpu0); break; /* Suspend CPU emulation */ case 's': vm_suspend(vm); break; /* Resume CPU emulation */ case 'u': vm_resume(vm); break; /* Dump the MIPS TLB */ case 't': if (cpu0) tlb_dump(cpu0); break; /* Dump the MIPS TLB (raw mode) */ case 'z': if (cpu0) tlb_raw_dump(cpu0); break; /* Show information about JIT compiled pages */ case 'b': if (cpu0) { printf("\nCPU0: %u JIT compiled pages " "[Exec Area Pages: %lu/%lu]\n", cpu0->compiled_pages, (u_long)cpu0->exec_page_alloc, (u_long)cpu0->exec_page_count); } break; /* MTS64 cache statistics */ case 'l': if (cpu0) { cpu0->mts_show_stats(cpu0); } break; /* Extract the configuration from the NVRAM */ case 'c': vm_ios_save_config(vm); break; /* Non-JIT mode statistics */ case 'j': if (cpu0) mips64_dump_stats(cpu0); break; /* Determine an idle pointer counter */ case 'i': if (cpu0) { mips64_get_idling_pc(cpu0); } break; /* Experimentations / Tests */ case 'x': if (cpu0) { /* IRQ triggering */ mips64_set_irq(cpu0,2/*C7200_PA_MGMT_IRQ*/); //mips64_set_irq(cpu0,3/*C7200_PA_MGMT_IRQ*/); //mips64_set_irq(cpu0,C7200_PA_MGMT_IRQ); } break; /* Twice Ctrl + ']' (0x1d, 29), or Alt-Gr + '*' (0xb3, 179) */ case 0x1d: case 0xb3: vtty_store(vtty,c); break; default: printf("\n\nInstance %s (ID %d)\n\n",vm->name,vm->instance_id); printf("o - Show the VM object list\n" "d - Show the device list\n" "r - Dump MIPS CPU registers\n" "t - Dump MIPS TLB entries\n" "z - Dump MIPS TLB entries (raw mode)\n" "m - Dump the latest memory accesses\n" "s - Suspend CPU emulation\n" "u - Resume CPU emulation\n" "q - Quit the emulator\n" "k - Reboot the virtual machine\n" "b - Show info about JIT compiled pages\n" "l - MTS64 cache statistics\n" "c - Write IOS configuration to disk\n" "j - Non-JIT mode statistics\n" "i - Determine an idling pointer counter\n" "x - Experimentations (can crash the box!)\n" "^] - Send ^]\n" "Other - This help\n"); }} /* Read a character (until one is available) and store it in buffer */static void vtty_read_and_store(vtty_t *vtty){ int c; /* wait until we get a character input */ c = vtty_read(vtty); /* if read error, do nothing */ if (c < 0) return; if (!vtty->terminal_support) { vtty_store(vtty,c); return; } switch(vtty->input_state) { case VTTY_INPUT_TEXT : switch(c) { case 0x1b: vtty->input_state = VTTY_INPUT_VT1; return; /* Ctrl + ']' (0x1d, 29), or Alt-Gr + '*' (0xb3, 179) */ case 0x1d: case 0xb3: vtty->input_state = VTTY_INPUT_REMOTE; return; case IAC : vtty->input_state = VTTY_INPUT_TELNET; return; case 0: /* NULL - Must be ignored - generated by Linux telnet */ case 10: /* LF (Line Feed) - Must be ignored on Windows platform */ return; default: /* Store a standard character */ vtty_store(vtty,c); return; } case VTTY_INPUT_VT1 : switch(c) { case 0x5b: vtty->input_state = VTTY_INPUT_VT2; return; default: vtty_store(vtty,0x1b); vtty_store(vtty,c); } vtty->input_state = VTTY_INPUT_TEXT; return; case VTTY_INPUT_VT2 : switch(c) { case 0x41: /* Up Arrow */ vtty_store(vtty,16); break; case 0x42: /* Down Arrow */ vtty_store(vtty,14); break; case 0x43: /* Right Arrow */ vtty_store(vtty,6); break; case 0x44: /* Left Arrow */ vtty_store(vtty,2); break; default: vtty_store(vtty,0x5b); vtty_store(vtty,0x1b); vtty_store(vtty,c); break; } vtty->input_state = VTTY_INPUT_TEXT; return; case VTTY_INPUT_REMOTE : remote_control(vtty, c); vtty->input_state = VTTY_INPUT_TEXT; return; case VTTY_INPUT_TELNET : vtty->telnet_cmd = c; switch(c) { case WILL: case WONT: case DO: case DONT: vtty->input_state = VTTY_INPUT_TELNET_IYOU; return; case SB : vtty->telnet_cmd = c; vtty->input_state = VTTY_INPUT_TELNET_SB1; return; case SE: break; case IAC : vtty_store(vtty, IAC); break; } vtty->input_state = VTTY_INPUT_TEXT; return; case VTTY_INPUT_TELNET_IYOU : vtty->telnet_opt = c; /* if telnet client can support ttype, ask it to send ttype string */ if ((vtty->telnet_cmd == WILL) && (vtty->telnet_opt == TELOPT_TTYPE)) { vtty_put_char(vtty, IAC); vtty_put_char(vtty, SB); vtty_put_char(vtty, TELOPT_TTYPE); vtty_put_char(vtty, TELQUAL_SEND); vtty_put_char(vtty, IAC); vtty_put_char(vtty, SE); } vtty->input_state = VTTY_INPUT_TEXT; return; case VTTY_INPUT_TELNET_SB1 : vtty->telnet_opt = c; vtty->input_state = VTTY_INPUT_TELNET_SB2; return; case VTTY_INPUT_TELNET_SB2 : vtty->telnet_qual = c; if ((vtty->telnet_opt == TELOPT_TTYPE) && (vtty->telnet_qual == TELQUAL_IS)) vtty->input_state = VTTY_INPUT_TELNET_SB_TTYPE; else vtty->input_state = VTTY_INPUT_TELNET_NEXT; return; case VTTY_INPUT_TELNET_SB_TTYPE : /* parse ttype string: first char is sufficient */ /* if client is xterm or vt, set the title bar */ if ((c == 'x') || (c == 'X') || (c == 'v') || (c == 'V')) { fprintf(vtty->fstream, "\033]0;Dynamips(%i): %s, %s\07", vtty->vm->instance_id, vtty->vm->name, vtty->name); } vtty->input_state = VTTY_INPUT_TELNET_NEXT; return; case VTTY_INPUT_TELNET_NEXT : /* ignore all chars until next IAC */ if (c == IAC) vtty->input_state = VTTY_INPUT_TELNET; return; }}/* Read a character from the buffer (-1 if the buffer is empty) */int vtty_get_char(vtty_t *vtty){ u_char c; VTTY_LOCK(vtty); if (vtty->read_ptr == vtty->write_ptr) { VTTY_UNLOCK(vtty); return(-1); } c = vtty->buffer[vtty->read_ptr++]; if (vtty->read_ptr == VTTY_BUFFER_SIZE) vtty->read_ptr = 0; VTTY_UNLOCK(vtty); return(c);}/* Returns TRUE if a character is available in buffer */int vtty_is_char_avail(vtty_t *vtty){ int res; VTTY_LOCK(vtty); res = (vtty->read_ptr != vtty->write_ptr); VTTY_UNLOCK(vtty); return(res);}/* put char to vtty */void vtty_put_char(vtty_t *vtty, char ch){ switch(vtty->type) { case VTTY_TYPE_NONE: break; case VTTY_TYPE_TERM: fwrite(&ch, 1, 1, vtty->fstream); break; case VTTY_TYPE_TCP: if ((vtty->state == VTTY_STATE_TCP_RUNNING) && (fwrite(&ch, 1, 1, vtty->fstream) != 1)) { vm_log(vtty->vm,"VTTY","%s: put char %d failed (%s)\n", vtty->name,(int)ch,strerror(errno)); } break; case VTTY_TYPE_SERIAL: if (write(vtty->fd,&ch,1) != 1) { vm_log(vtty->vm,"VTTY","%s: put char 0x%x failed (%s)\n", vtty->name,(int)ch,strerror(errno)); } break; default: fprintf(stderr,"vtty_put_char: bad vtty type %d\n",vtty->type); exit(1); }}/* Flush VTTY output */void vtty_flush(vtty_t *vtty){ switch(vtty->type) { case VTTY_TYPE_TERM: case VTTY_TYPE_TCP: if (vtty->fstream) fflush(vtty->fstream); break; case VTTY_TYPE_SERIAL: fsync(vtty->fd); break; }}/* VTTY thread */static void *vtty_thread_main(void *arg){ vtty_t *vtty; struct timeval tv; int fd,fd_max,res; fd_set rfds; for(;;) { VTTY_LIST_LOCK(); /* Build the FD set */ FD_ZERO(&rfds); fd_max = -1; for(vtty=vtty_list;vtty;vtty=vtty->next) { if (!vtty->select_fd) continue; if ((fd = *vtty->select_fd) < 0) continue; if (fd > fd_max) fd_max = fd; FD_SET(fd,&rfds); } VTTY_LIST_UNLOCK(); /* Wait for incoming data */ tv.tv_sec = 0; tv.tv_usec = 50 * 1000; /* 50 ms */ res = select(fd_max+1,&rfds,NULL,NULL,&tv); if (res == -1) { if (errno != EINTR) { perror("vtty_thread: select"); for(vtty=vtty_list;vtty;vtty=vtty->next) { fprintf(stderr," %-15s: %s, FD %d\n", vtty->vm->name,vtty->name,vtty->fd); } } continue; } /* Examine active FDs and call user handlers */ VTTY_LIST_LOCK(); for(vtty=vtty_list;vtty;vtty=vtty->next) { if (!vtty->select_fd) continue; if ((fd = *vtty->select_fd) < 0) continue; if (FD_ISSET(fd,&rfds)) { vtty_read_and_store(vtty); vtty->input_pending = TRUE; } if (vtty->input_pending) { if (vtty->read_notifier != NULL) vtty->read_notifier(vtty); vtty->input_pending = FALSE; } /* Flush any pending output */ if (!vtty->managed_flush) vtty_flush(vtty); } VTTY_LIST_UNLOCK(); } return NULL;}/* Initialize the VTTY thread */int vtty_init(void){ if (pthread_create(&vtty_thread,NULL,vtty_thread_main,NULL)) { perror("vtty: pthread_create"); return(-1); } return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -