int interactive_shell(void) { adb_thread_t thr; int fdi, fd; int *fds; fd = adb_connect("shell:"); if(fd < 0) { fprintf(stderr,"error: %s\n", adb_error()); return 1; } fdi = 0; //dup(0); fds = malloc(sizeof(int) * 2); fds[0] = fd; fds[1] = fdi; #ifdef HAVE_TERMIO_H stdin_raw_init(fdi); #endif adb_thread_create(&thr, stdin_read_thread, fds); read_and_dump(fd); #ifdef HAVE_TERMIO_H stdin_raw_restore(fdi); #endif return 0; }
static void *stdin_read_thread(void *x) { int fd, fdi; unsigned char buf[1024]; int r, n; int state = 0; int *fds = (int*) x; fd = fds[0]; fdi = fds[1]; free(fds); for(;;) { /* fdi is really the client's stdin, so use read, not adb_read here */ D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi); r = unix_read(fdi, buf, 1024); D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi); if(r == 0) break; if(r < 0) { if(errno == EINTR) continue; break; } for(n = 0; n < r; n++){ switch(buf[n]) { case '\n': state = 1; break; case '\r': state = 1; break; case '~': if(state == 1) state++; break; case '.': if(state == 2) { fprintf(stderr,"\n* disconnect *\n"); #ifdef HAVE_TERMIO_H stdin_raw_restore(fdi); #endif exit(0); } default: state = 0; } } r = adb_write(fd, buf, r); if(r <= 0) { break; } } return 0; }
static void *stdin_read_thread(void *x) { int fd, fdi; unsigned char buf[1024]; #ifdef SH_HISTORY unsigned char realbuf[1024], *buf_ptr; SHLIST history; SHLIST *item = &history; int cmdlen = 0, ins_flag = 0; #endif int r, n; int state = 0; int *fds = (int*) x; fd = fds[0]; fdi = fds[1]; free(fds); #ifdef SH_HISTORY shListInitList( &history ); #endif for(;;) { /* fdi is really the client's stdin, so use read, not adb_read here */ r = unix_read(fdi, buf, 1024); if(r == 0) break; if(r < 0) { if(errno == EINTR) continue; break; } #ifdef SH_HISTORY if( (r == 3) && /* Arrow processing */ (memcmp( (void *)buf, SH_ARROW_ANY, 2 ) == 0) ) { switch( buf[2] ) { case SH_ARROW_UP: item = shListGetNextItem( &history, item ); break; case SH_ARROW_DOWN: item = shListGetPrevItem( &history, item ); break; default: item = NULL; break; } memset( buf, SH_DEL_CHAR, cmdlen ); if( item != NULL ) { n = snprintf( (char *)(&buf[cmdlen]), sizeof buf - cmdlen, "%s", (char *)(item->data) ); memcpy( realbuf, item->data, n ); } else { /* Clean buffer */ item = &history; n = 0; } r = n + cmdlen; cmdlen = n; ins_flag = 0; if( r == 0 ) continue; } else { #endif for(n = 0; n < r; n++){ switch(buf[n]) { case '\n': #ifdef SH_HISTORY if( ins_flag && (SH_BLANK_CHAR <= realbuf[0]) ) { buf_ptr = malloc(cmdlen + 1); if( buf_ptr != NULL ) { memcpy( buf_ptr, realbuf, cmdlen ); buf_ptr[cmdlen] = '\0'; if( (item = shListFindItem( &history, (void *)buf_ptr, shItemCmp )) == NULL ) { shListInsFirstItem( &history, (void *)buf_ptr ); item = &history; } } } cmdlen = 0; ins_flag = 0; #endif state = 1; break; case '\r': state = 1; break; case '~': if(state == 1) state++; break; case '.': if(state == 2) { fprintf(stderr,"\n* disconnect *\n"); #ifdef HAVE_TERMIO_H stdin_raw_restore(fdi); #endif exit(0); } default: #ifdef SH_HISTORY if( buf[n] == SH_DEL_CHAR ) { if( cmdlen > 0 ) cmdlen--; } else { realbuf[cmdlen] = buf[n]; cmdlen++; } ins_flag = 1; #endif state = 0; } } #ifdef SH_HISTORY } #endif r = adb_write(fd, buf, r); if(r <= 0) { break; } } #ifdef SH_HISTORY shListDelAllItems( &history, (shListFree)free ); #endif return 0; }