/* we keep a list of opened transports. The atransport struct knows to which * local transport it is connected. The list is used to detect when we're * trying to connect twice to a given local transport. */ #define SDB_LOCAL_TRANSPORT_MAX 16 SDB_MUTEX_DEFINE( local_transports_lock ); static atransport* local_transports[ SDB_LOCAL_TRANSPORT_MAX ]; #endif /* SDB_HOST */ static int remote_read(apacket *p, atransport *t) { if(readx(t->sfd, &p->msg, sizeof(amessage))){ D("remote local: read terminated (message)\n"); return -1; } fix_endians(p); #if 0 && defined __ppc__ D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); #endif if(check_header(p)) { D("bad header: terminated (data)\n"); return -1; } if(readx(t->sfd, p->data, p->msg.data_length)){ D("remote local: terminated (data)\n"); return -1; } if(check_data(p)) { D("bad data: terminated (data)\n"); return -1; } return 0; } static int remote_write(apacket *p, atransport *t) { int length = p->msg.data_length; fix_endians(p); #if 0 && defined __ppc__ D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); #endif if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) { D("remote local: write terminated\n"); return -1; } return 0; } int local_connect(int port, const char *device_name) { return local_connect_arbitrary_ports(port-1, port, device_name); } int local_connect_arbitrary_ports(int console_port, int sdb_port, const char *device_name) { char buf[64]; int fd = -1; #if SDB_HOST const char *host = getenv("SDBHOST"); if (host) { fd = socket_network_client(host, sdb_port, SOCK_STREAM); } #endif if (fd < 0) { fd = socket_loopback_client(sdb_port, SOCK_STREAM); } if (fd >= 0) { D("client: connected on remote on fd %d\n", fd); close_on_exec(fd); disable_tcp_nagle(fd); snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port); register_socket_transport(fd, buf, sdb_port, 1, device_name); return 0; } return -1; } #if SDB_HOST /* tizen specific */ int get_devicename(int port, char *device_name) { int fd; char buffer[MAX_PAYLOAD]; char *tok = NULL; int found = 0; fd = unix_open(DEVICEMAP_FILENAME, O_RDONLY); if (fd > 0) { for(;;) { if(read_line(fd, buffer, MAX_PAYLOAD) < 0) break; tok = strtok(buffer, DEVICEMAP_SEPARATOR); if (tok != NULL) { strncpy(device_name, tok, DEVICENAME_MAX); tok = strtok(NULL, DEVICEMAP_SEPARATOR); if (tok != NULL) { if (port == atoi(tok)) { found = 1; break; } } } } sdb_close(fd); } if (found != 1) strncpy(device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX); D("init device name %s on port %d\n", device_name, port); return found; }
static void sdb_close_conn(void *conn) { if (conn == NULL) return; sdb_close(conn); }
void remount_service(int fd, void *cookie) { int ret = remount_system(); if (!ret) write_string(fd, "remount succeeded\n"); else { char buffer[200]; snprintf(buffer, sizeof(buffer), "remount failed: %s\n", strerror(errno)); write_string(fd, buffer); } sdb_close(fd); }
static void remote_kick(atransport *t) { int fd = t->sfd; t->sfd = -1; sdb_shutdown(fd); sdb_close(fd); #if SDB_HOST if(HOST) { int nn; sdb_mutex_lock( &local_transports_lock ); for (nn = 0; nn < SDB_LOCAL_TRANSPORT_MAX; nn++) { if (local_transports[nn] == t) { local_transports[nn] = NULL; break; } } sdb_mutex_unlock( &local_transports_lock ); } #endif }
int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie) { syncmsg msg; char buf[257]; int len; len = strlen(path); if(len > 1024) goto fail; msg.req.id = ID_LIST; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, path, len)) { goto fail; } for(;;) { if(readx(fd, &msg.dent, sizeof(msg.dent))) break; if(msg.dent.id == ID_DONE) return 0; if(msg.dent.id != ID_DENT) break; len = ltohl(msg.dent.namelen); if(len > 256) break; if(readx(fd, buf, len)) break; buf[len] = 0; func(ltohl(msg.dent.mode), ltohl(msg.dent.size), ltohl(msg.dent.time), buf, cookie); } fail: sdb_close(fd); return -1; }
/* Returns the device used to mount a directory in /proc/mounts */ static char *find_mount(const char *dir) { int fd; int res; int size; char *token = NULL; const char delims[] = "\n"; char buf[4096]; fd = unix_open("/proc/mounts", O_RDONLY); if (fd < 0) return NULL; buf[sizeof(buf) - 1] = '\0'; size = sdb_read(fd, buf, sizeof(buf) - 1); sdb_close(fd); token = strtok(buf, delims); while (token) { char mount_dev[256]; char mount_dir[256]; int mount_freq; int mount_passno; res = sscanf(token, "%255s %255s %*s %*s %d %d\n", mount_dev, mount_dir, &mount_freq, &mount_passno); mount_dev[255] = 0; mount_dir[255] = 0; if (res == 4 && (strcmp(dir, mount_dir) == 0)) return strdup(mount_dev); token = strtok(NULL, delims); } return NULL; }
static int write_data_file(int fd, const char *path, syncsendbuf *sbuf) { int lfd, err = 0; lfd = sdb_open(path, O_RDONLY); if(lfd < 0) { fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno)); return -1; } sbuf->id = ID_DATA; for(;;) { int ret; ret = sdb_read(lfd, sbuf->data, SYNC_DATA_MAX); if(!ret) break; if(ret < 0) { if(errno == EINTR) continue; fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno)); break; } sbuf->size = htoll(ret); if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){ err = -1; break; } total_bytes += ret; } sdb_close(lfd); return err; }
static void remote_close(atransport *t) { sdb_close(t->fd); }
R_API bool r_syscall_setup(RSyscall *s, const char *arch, const char *os, int bits) { const char *file; if (!os || !*os) { os = R_SYS_OS; } if (!arch) { arch = R_SYS_ARCH; } free (s->os); s->os = strdup (os); if (!strcmp (os, "any")) { // ignored return true; } if (!strcmp (arch, "mips")) { s->regs = fastcall_mips; } else if (!strcmp (arch,"avr")) { s->sysport = sysport_avr; } else if (!strcmp (arch,"sh")) { s->regs = fastcall_sh; } else if (!strcmp (arch, "arm")) { switch (bits) { case 16: case 32: s->regs = fastcall_arm; break; case 64: s->regs = fastcall_arm64; break; } } else if (!strcmp (arch, "x86")) { s->sysport = sysport_x86; switch (bits) { case 8: s->regs = fastcall_x86_8; break; case 32: s->regs = fastcall_x86_32; break; case 64: s->regs = fastcall_x86_64; break; } } #define SYSCALLPATH R2_PREFIX "/share/radare2/" R2_VERSION "/syscall" file = sdb_fmt (0, "%s/%s-%s-%d.sdb", SYSCALLPATH, os, arch, bits); if (!r_file_exists (file)) { // eprintf ("r_syscall_setup: Cannot find '%s'\n", file); return false; } //eprintf ("DBG098: syscall->db must be reindexed for k\n"); sdb_close (s->db); sdb_reset (s->db); sdb_open (s->db, file); // s->db = sdb_new (0, file, 0); #if 1 if (s->fd) { fclose (s->fd); } s->fd = NULL; #endif return true; }
static int cmd_type(void *data, const char *input) { RCore *core = (RCore *)data; switch (input[0]) { // t [typename] - show given type in C syntax case 'u': // "tu" switch (input[1]) { case '?': { const char *help_message[] = { "USAGE tu[...]", "", "", "tu", "", "List all loaded unions", "tu?", "", "show this help", NULL }; r_core_cmd_help (core, help_message); } break; case 0: sdb_foreach (core->anal->sdb_types, stdprintifunion, core); break; } break; case 'k': // "tk" if (input[1] == ' ') { sdb_query (core->anal->sdb_types, input + 2); } else sdb_query (core->anal->sdb_types, "*"); fflush (stdout); break; case 's': // "ts" switch (input[1]) { case '?': { const char *help_message[] = { "USAGE ts[...]", "", "", "ts", "", "List all loaded structs", "ts?", "", "show this help", NULL }; r_core_cmd_help (core, help_message); } break; case 0: sdb_foreach (core->anal->sdb_types, stdprintifstruct, core); break; } break; case 'b': { char *p, *s = (strlen (input) > 1)? strdup (input + 2): NULL; const char *isenum; p = s? strchr (s, ' '): NULL; if (p) { *p++ = 0; // dupp in core.c (see getbitfield()) isenum = sdb_const_get (core->anal->sdb_types, s, 0); if (isenum && !strcmp (isenum, "enum")) { *--p = '.'; const char *res = sdb_const_get (core->anal->sdb_types, s, 0); if (res) r_cons_println (res); else eprintf ("Invalid enum member\n"); } else { eprintf ("This is not an enum\n"); } } else { eprintf ("Missing value\n"); } free (s); } break; case 'e': { if (!input[1]) { char *name = NULL; SdbKv *kv; SdbListIter *iter; SdbList *l = sdb_foreach_list (core->anal->sdb_types); ls_foreach (l, iter, kv) { if (!strcmp (kv->value, "enum")) { if (!name || strcmp (kv->value, name)) { free (name); name = strdup (kv->key); r_cons_println (name); } } } free (name); ls_free (l); break; } if (input[1] == '?') { const char *help_message[] = { "USAGE te[...]", "", "", "te", "", "List all loaded enums", "te", " <enum> <value>", "Show name for given enum number", "te?", "", "show this help", NULL }; r_core_cmd_help (core, help_message); break; } char *p, *s = strdup (input + 2); const char *isenum; p = strchr (s, ' '); if (p) { *p++ = 0; isenum = sdb_const_get (core->anal->sdb_types, s, 0); if (isenum && !strncmp (isenum, "enum", 4)) { const char *q = sdb_fmt (0, "%s.0x%x", s, (ut32)r_num_math (core->num, p)); const char *res = sdb_const_get (core->anal->sdb_types, q, 0); if (res) r_cons_println (res); } else { eprintf ("This is not an enum\n"); } } else { //eprintf ("Missing value\n"); r_core_cmdf (core, "t~&%s,=0x", s); } free (s); } break; case ' ': { const char *isenum = sdb_const_get (core->anal->sdb_types, input + 1, 0); if (isenum && !strcmp (isenum, "enum")) { eprintf ("IS ENUM! \n"); } else { char *fmt = r_anal_type_format (core->anal, input + 1); if (fmt) { r_str_chop (fmt); r_cons_printf ("pf %s\n", fmt); free (fmt); } else eprintf ("Cannot find '%s' type\n", input + 1); } } break; // t* - list all types in 'pf' syntax case '*': sdb_foreach (core->anal->sdb_types, typelist, core); break; case 0: sdb_foreach (core->anal->sdb_types, sdbforcb, core); break; case 'o': if (!r_sandbox_enable (0)) { if (input[1] == ' ') { const char *filename = input + 2; char *homefile = NULL; if (*filename == '~') { if (filename[1] && filename[2]) { homefile = r_str_home (filename + 2); filename = homefile; } } if (!strcmp (filename, "-")) { char *out, *tmp; tmp = r_core_editor (core, NULL, ""); if (tmp) { out = r_parse_c_string (tmp); if (out) { // r_cons_strcat (out); save_parsed_type (core, out); free (out); } free (tmp); } } else { char *out = r_parse_c_file (filename); if (out) { //r_cons_strcat (out); save_parsed_type (core, out); free (out); } //r_anal_type_loadfile (core->anal, filename); } free (homefile); } else if (input[1] == 's') { const char *dbpath = input + 3; if (r_file_exists (dbpath)) { Sdb *db_tmp = sdb_new (0, dbpath, 0); sdb_merge (core->anal->sdb_types, db_tmp); sdb_close (db_tmp); sdb_free (db_tmp); } } } else { eprintf ("Sandbox: system call disabled\n"); } break; // td - parse string with cparse engine and load types from it case 'd': if (input[1] == '?') { const char *help_message[] = { "Usage:", "\"td [...]\"", "", "td", "[string]", "Load types from string", NULL }; r_core_cmd_help (core, help_message); r_cons_printf ("Note: The td command should be put between double quotes\n" "Example: \" td struct foo {int bar;int cow};\"" "\nt"); } else if (input[1] == ' ') { char tmp[8192]; snprintf (tmp, sizeof (tmp) - 1, "%s;", input + 2); //const char *string = input + 2; //r_anal_str_to_type (core->anal, string); char *out = r_parse_c_string (tmp); if (out) { //r_cons_strcat (out); save_parsed_type (core, out); free (out); } } else { eprintf ("Invalid use of td. See td? for help\n"); } break; // tl - link a type to an address case 'l': switch (input[1]) { case '?': { const char *help_message[] = { "Usage:", "", "", "tl", "", "list all links in readable format", "tl", "[typename]", "link a type to current adress.", "tl", "[typename] = [address]", "link type to given address.", "tls", "[address]", "show link at given address", "tl-*", "", "delete all links.", "tl-", "[address]", "delete link at given address.", "tl*", "", "list all links in radare2 command format", "tl?", "", "print this help.", NULL }; r_core_cmd_help (core, help_message); } break; case ' ': { char *type = strdup (input + 2); char *ptr = strchr (type, '='); ut64 addr; if (ptr) { *ptr++ = 0; r_str_chop (ptr); if (ptr && *ptr) { addr = r_num_math (core->num, ptr); } else { eprintf ("address is unvalid\n"); free (type); break; } } else { addr = core->offset; } r_str_chop (type); char *tmp = sdb_get (core->anal->sdb_types, type, 0); if (tmp && *tmp) { r_anal_type_link (core->anal, type, addr); free (tmp); } else { eprintf ("unknown type %s\n", type); } free (type); } break; case 's': { int ptr; char *addr = strdup (input + 2); SdbKv *kv; SdbListIter *sdb_iter; SdbList *sdb_list = sdb_foreach_list (core->anal->sdb_types); r_str_chop (addr); ptr = r_num_math (NULL, addr); //r_core_cmdf (core, "tl~0x%08"PFMT64x" = ", addr); ls_foreach (sdb_list, sdb_iter, kv) { char *linkptr; if (strncmp (kv->key, "link.", strlen ("link."))) { continue; } linkptr = sdb_fmt (-1,"0x%s", kv->key + strlen ("link.")); if (ptr == r_num_math (NULL, linkptr)) { linklist_readable (core, kv->key, kv->value); } } free (addr); ls_free (sdb_list); } break; case '-': switch (input[2]) { case '*': sdb_foreach (core->anal->sdb_types, sdbdeletelink, core); break; case ' ': { const char *ptr = input + 3; ut64 addr = r_num_math (core->num, ptr); r_anal_type_unlink (core->anal, addr); } break; } break; case '*': sdb_foreach (core->anal->sdb_types, linklist, core); break; case '\0': sdb_foreach (core->anal->sdb_types, linklist_readable, core); break; }
// mysdb :close() static int api_close( lua_State *L) { sdb_close( lua_sdb_checktable( L, 1)); lua_pushboolean( L, 1); return 1; }
/* sdb :newconsolidation(id, storage, { col1=CM1, ..., coln=CMn }) * sdb :newconsolidation(id, storage, { <columnspec>, ... }) * CM are Consolidation Methods. <columnspec> are standard column * specifications with the `consolidation` field set. * * Column names are shared between src and dst: the column src.foobar, * if it is consolidated, is consolidated in dst.foobar. * * The dst consolidation table is created on the fly, rather than passed * as a parameter. */ static int api_newconsolidation( lua_State *L) { struct sdb_table_t *src, *dst; const char *id; enum sdb_storage_kind_t storage; int r, i, ncolumns; // src, id, storage, columns src = lua_sdb_checktable( L, 1); id = luaL_checkstring( L, 2); storage = luaL_checkoption( L, 3, NULL, storage_options); ncolumns = gettablencolumns( L, 4); dst = lua_newuserdata( L, sizeof( *dst)); // src, id, storage, columns, dst r = sdb_initwithoutcolumns( dst, id, ncolumns, storage); if( r) { lua_pushnil( L); lua_pushinteger( L, r); return 2; } lua_getfield( L, LUA_REGISTRYINDEX, MT_NAME); // id, storage, columns, udata, mt lua_setmetatable( L, -2); // id, storage, columns, udata luaL_checktype( L, 4, LUA_TTABLE); r = sdb_setconstable( src, dst); if( r) { sdb_close( dst); return push_sdb_error( L, r); } if( lua_objlen(L, 4) == ncolumns) { // full column description sequence for(i=1, lua_rawgeti( L, 4, 1); !lua_isnil( L, -1); lua_rawgeti( L, 4, ++i)) { // src, id, storage, columns, dst, val const char *colname; enum sdb_serialization_method_t s_method; enum sdb_consolidation_method_t c_method; double arg; sdb_ncolumn_t src_col; lua_sdb_getcolumnspec( L, &arg, &s_method, &c_method, 4, i); // src, id, storage, columns, dst, colname colname = lua_tostring( L, -1); src_col = sdb_getcolnum( src, colname); if( SDB_NCOLUMN_INVALID == src_col) { lua_sdb_fargerror( L, 4, "Unknown column %s.", colname); } r = sdb_setcolumn( dst, colname, s_method, arg); if( r) { sdb_close( dst); return push_sdb_error( L, r); } r = sdb_setconscolumn( src, src_col, c_method); if( r) { sdb_close( dst); return push_sdb_error( L, r); } lua_pop( L, 1); // src, id, storage, columns, dst } // src, id, storage, columns, dst, nil lua_pop( L, 1); // src, id, storage, columns, dst } else { // short colname/consolidation method mapping for( lua_pushnil( L); lua_next( L, 4);) { // src, id, storage, columns, dst, key, val if( !lua_isstring(L, -2)) lua_sdb_fargerror( L, 4, "Expected string for columns names, got %s", lua_typename( L, lua_type( L, -1))); const char *colname = luaL_checkstring( L, -2); enum sdb_serialization_method_t s_method = SDB_DEFAULT_SERIALIZATION_METHOD; enum sdb_consolidation_method_t c_method = lua_sdb_getoption( L, -1, consolidation_methods); if( !consolidation_methods[c_method]) { lua_sdb_fargerror( L, 4, "Invalid consolidation method for %s", colname); } sdb_ncolumn_t src_col = sdb_getcolnum( src, colname); if( SDB_NCOLUMN_INVALID == src_col) { lua_sdb_fargerror( L, 4, "Unknown column %s", colname); } r = sdb_setcolumn( dst, colname, s_method, 0.0); if( r) { sdb_close( dst); return push_sdb_error( L, r); } r = sdb_setconscolumn( src, src_col, c_method); if( r) { sdb_close( dst); return push_sdb_error( L, r); } lua_pop( L, 1); // src, id, storage, columns, dst } } // src, id, storage, columns, dst return 1; }
int sync_recv(int fd, const char *rpath, const char *lpath) { syncmsg msg; int len; int lfd = -1; char *buffer = send_buffer.data; unsigned id; len = strlen(rpath); if(len > 1024) return -1; msg.req.id = ID_RECV; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, rpath, len)) { return -1; } if(readx(fd, &msg.data, sizeof(msg.data))) { return -1; } id = msg.data.id; if((id == ID_DATA) || (id == ID_DONE)) { sdb_unlink(lpath); mkdirs((char *)lpath); lfd = sdb_creat(lpath, 0644); if(lfd < 0) { fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno)); return -1; } goto handle_data; } else { goto remote_error; } for(;;) { if(readx(fd, &msg.data, sizeof(msg.data))) { return -1; } id = msg.data.id; handle_data: len = ltohl(msg.data.size); if(id == ID_DONE) break; if(id != ID_DATA) goto remote_error; if(len > SYNC_DATA_MAX) { fprintf(stderr,"data overrun\n"); sdb_close(lfd); return -1; } if(readx(fd, buffer, len)) { sdb_close(lfd); return -1; } if(writex(lfd, buffer, len)) { fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno)); sdb_close(lfd); return -1; } total_bytes += len; } sdb_close(lfd); return 0; remote_error: sdb_close(lfd); sdb_unlink(lpath); if(id == ID_FAIL) { len = ltohl(msg.data.size); if(len > 256) len = 256; if(readx(fd, buffer, len)) { return -1; } buffer[len] = 0; } else { memcpy(buffer, &id, 4); buffer[4] = 0; // strcpy(buffer,"unknown reason"); } fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer); return 0; }
static int sync_send(int fd, const char *lpath, const char *rpath, unsigned mtime, mode_t mode, int verifyApk) { syncmsg msg; int len, r; syncsendbuf *sbuf = &send_buffer; char* file_buffer = NULL; int size = 0; char tmp[64]; len = strlen(rpath); if(len > 1024) goto fail; snprintf(tmp, sizeof(tmp), ",%d", mode); r = strlen(tmp); if (verifyApk) { #if 0 //eric int lfd; zipfile_t zip; zipentry_t entry; int amt; // if we are transferring an APK file, then sanity check to make sure // we have a real zip file that contains an AndroidManifest.xml // this requires that we read the entire file into memory. lfd = sdb_open(lpath, O_RDONLY); if(lfd < 0) { fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno)); return -1; } size = sdb_lseek(lfd, 0, SEEK_END); if (size == -1 || -1 == sdb_lseek(lfd, 0, SEEK_SET)) { fprintf(stderr, "error seeking in file '%s'\n", lpath); sdb_close(lfd); return 1; } file_buffer = (char *)malloc(size); if (file_buffer == NULL) { fprintf(stderr, "could not allocate buffer for '%s'\n", lpath); sdb_close(lfd); return 1; } amt = sdb_read(lfd, file_buffer, size); if (amt != size) { fprintf(stderr, "error reading from file: '%s'\n", lpath); sdb_close(lfd); free(file_buffer); return 1; } sdb_close(lfd); zip = init_zipfile(file_buffer, size); if (zip == NULL) { fprintf(stderr, "file '%s' is not a valid zip file\n", lpath); free(file_buffer); return 1; } entry = lookup_zipentry(zip, "AndroidManifest.xml"); release_zipfile(zip); if (entry == NULL) { fprintf(stderr, "file '%s' does not contain AndroidManifest.xml\n", lpath); free(file_buffer); return 1; } #endif } msg.req.id = ID_SEND; msg.req.namelen = htoll(len + r); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, rpath, len) || writex(fd, tmp, r)) { free(file_buffer); goto fail; } if (file_buffer) { write_data_buffer(fd, file_buffer, size, sbuf); free(file_buffer); } else if (S_ISREG(mode)) write_data_file(fd, lpath, sbuf); #ifdef HAVE_SYMLINKS else if (S_ISLNK(mode)) write_data_link(fd, lpath, sbuf); #endif else goto fail; msg.data.id = ID_DONE; msg.data.size = htoll(mtime); if(writex(fd, &msg.data, sizeof(msg.data))) goto fail; if(readx(fd, &msg.status, sizeof(msg.status))) return -1; if(msg.status.id != ID_OKAY) { if(msg.status.id == ID_FAIL) { len = ltohl(msg.status.msglen); if(len > 256) len = 256; if(readx(fd, sbuf->data, len)) { return -1; } sbuf->data[len] = 0; } else strcpy(sbuf->data, "unknown reason"); fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data); return -1; } return 0; fail: fprintf(stderr,"protocol failure\n"); sdb_close(fd); return -1; }