1 /****************************************************************************** 2 * 3 * Copyright (C) 2009-2012 Broadcom Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 #include <stdio.h> 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <sys/types.h> 23 #include <sys/stat.h> 24 #include <sys/statfs.h> 25 #include <sys/vfs.h> 26 #include <unistd.h> 27 #include <dirent.h> 28 #include <limits.h> 29 #include <sys/file.h> 30 #include <sys/mman.h> 31 32 #include "btif_config.h" 33 #include "btif_config_util.h" 34 #ifndef ANDROID_NDK 35 #define ANDROID_NDK 36 #endif 37 #include "tinyxml2.h" 38 #ifndef FALSE 39 #define TRUE 1 40 #define FALSE 0 41 #endif 42 #define LOG_TAG "btif_config_util" 43 extern "C" { 44 #include "btif_sock_util.h" 45 } 46 #include <stdlib.h> 47 #include <cutils/log.h> 48 #define info(fmt, ...) ALOGI ("%s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__) 49 #define debug(fmt, ...) ALOGD ("%s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__) 50 #define warn(fmt, ...) ALOGW ("## WARNING : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__) 51 #define error(fmt, ...) ALOGE ("## ERROR : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__) 52 #define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__) 53 54 #define BLUEDROID_ROOT "Bluedroid" 55 #define BLUEDROID_NAME_TAG "Tag" 56 #define BLUEDROID_VALUE_TYPE "Type" 57 #define BLUEDROID_TAG_REMOTE_DEVICE "Remote Devices" 58 59 using namespace tinyxml2; 60 struct enum_user_data 61 { 62 const char* sn; //current section name 63 const char* kn; //current key name 64 const char* vn; //current value name 65 int si, ki, vi; 66 XMLDocument* xml; 67 XMLElement* se; 68 XMLElement* ke; 69 XMLElement* ve; 70 }; 71 72 73 static int type_str2int(const char* type); 74 static const char* type_int2str(int type); 75 static inline void create_ele_name(int index, char* element, int len); 76 static inline int validate_ele_name(const char* key); 77 static int parse_sections(const char* section_name, const XMLElement* section); 78 static void enum_config(void* user_data, const char* section, const char* key, const char* name, 79 const char* value, int bytes, int type); 80 static inline void bytes2hex(const char* data, int bytes, char* str) 81 { 82 static const char* hex_table = "0123456789abcdef"; 83 for(int i = 0; i < bytes; i++) 84 { 85 *str = hex_table[(data[i] >> 4) & 0xf]; 86 ++str; 87 *str = hex_table[data[i] & 0xf]; 88 ++str; 89 } 90 *str = 0; 91 } 92 static inline int hex2byte(char hex) 93 { 94 if('0' <= hex && hex <= '9') 95 return hex - '0'; 96 if('a' <= hex && hex <= 'z') 97 return hex - 'a' + 0xa; 98 if('A' <= hex && hex <= 'Z') 99 return hex - 'A' + 0xa; 100 return -1; 101 } 102 static inline int trim_bin_str_value(const char** str) 103 { 104 while(**str == ' ' || **str == '\r' || **str == '\t' || **str == '\n') 105 (*str)++; 106 int len = 0; 107 const char* s = *str; 108 while(*s && *s != ' ' && *s != '\r' && *s != '\t' && *s != '\n') 109 { 110 len++; 111 s++; 112 } 113 return len; 114 } 115 static inline bool hex2bytes(const char* str, int len, char* data) 116 { 117 if(len % 2) 118 { 119 error("cannot convert odd len hex str: %s, len:%d to binary", str, len); 120 return false; 121 } 122 for(int i = 0; i < len; i+= 2) 123 { 124 int d = hex2byte(str[i]); 125 if(d < 0) 126 { 127 error("cannot convert hex: %s, len:%d to binary", str, len); 128 return false; 129 } 130 *data = (char)(d << 4); 131 d = hex2byte(str[i+1]); 132 if(d < 0) 133 { 134 error("cannot convert hex: %s, len:%d to binary", str, len); 135 return false; 136 } 137 *data++ |= (char)d; 138 } 139 return true; 140 } 141 static inline void reverse_bin(char *bin, int size) 142 { 143 for(int i = 0; i < size /2; i++) 144 { 145 int b = bin[i]; 146 bin[i] = bin[size - i - 1]; 147 bin[size -i - 1] = b; 148 } 149 } 150 //////////////////////////////////////////////////////////////////////////////////////////////////////// 151 int btif_config_save_file(const char* file_name) 152 { 153 debug("in file name:%s", file_name); 154 XMLDocument xml; 155 XMLElement* root = xml.NewElement(BLUEDROID_ROOT); 156 xml.InsertFirstChild(root); 157 int ret = FALSE; 158 enum_user_data data; 159 memset(&data, 0, sizeof(data)); 160 data.xml = &xml; 161 if(btif_config_enum(enum_config, &data)) 162 ret = xml.SaveFile(file_name) == XML_SUCCESS; 163 return ret; 164 } 165 int btif_config_load_file(const char* file_name) 166 { 167 //if(access(file_name, 0) != 0) 168 // return XML_ERROR_FILE_NOT_FOUND; 169 XMLDocument xml; 170 int err = xml.LoadFile(file_name); 171 const XMLElement* root = xml.RootElement(); 172 int ret = FALSE; 173 if(err == XML_SUCCESS && root && strcmp(root->Name(), BLUEDROID_ROOT) == 0) 174 { 175 const XMLElement* section; 176 for(section = root->FirstChildElement(); section; section = section->NextSiblingElement()) 177 { 178 //debug("section tag:%s", section->Name()); 179 if(validate_ele_name(section->Name())) 180 { 181 const char* section_name = section->Attribute(BLUEDROID_NAME_TAG); 182 if(section_name && *section_name) 183 if(parse_sections(section_name, section)) 184 ret = TRUE; 185 } 186 } 187 } 188 return ret; 189 } 190 ////////////////////////////////////////////////////////////////////////////////////////////////////////// 191 static int parse_sections(const char* section_name, const XMLElement* section) 192 { 193 const XMLElement* key; 194 //debug("in"); 195 for(key = section->FirstChildElement(); key; key = key->NextSiblingElement()) 196 { 197 //debug("key tag:%s", key->Name()); 198 if(validate_ele_name(key->Name())) 199 { 200 const char* key_name = key->Attribute(BLUEDROID_NAME_TAG); 201 //debug("key name:%s", key_name); 202 if(key_name && *key_name) 203 { 204 const XMLElement* value; 205 for(value = key->FirstChildElement(); value; value = value->NextSiblingElement()) 206 { 207 const char* value_name = value->Attribute(BLUEDROID_NAME_TAG); 208 const char* value_type = value->Attribute(BLUEDROID_VALUE_TYPE); 209 //debug("value ele name:%s, section name:%s, key name:%s, value name:%s, value type:%s", 210 // value->Name(), section_name, key_name, value_name, value_type); 211 int type = type_str2int(value_type); 212 if(value_name && *value_name && type != BTIF_CFG_TYPE_INVALID) 213 { 214 const char* value_str = value->GetText() ? value->GetText() : ""; 215 //debug("value_name:%s, value_str:%s, value_type:%s, type:%x", 216 // value_name, value_str, value_type, type); 217 if(type & BTIF_CFG_TYPE_STR) 218 btif_config_set_str(section_name, key_name, value_name, value_str); 219 else if(type & BTIF_CFG_TYPE_INT) 220 { 221 if(*value_str) 222 { 223 int v = atoi(value_str); 224 btif_config_set_int(section_name, key_name, value_name, v); 225 } 226 } 227 else if(type & BTIF_CFG_TYPE_BIN) 228 { 229 int len = trim_bin_str_value(&value_str); 230 if(len > 0 && len % 2 == 0) 231 { 232 char *bin = (char*)alloca(len / 2); 233 if(hex2bytes(value_str, len, bin)) 234 btif_config_set(section_name, key_name, value_name, bin, len/2, BTIF_CFG_TYPE_BIN); 235 } 236 } 237 else error("Unsupported value:%s, type:%s not loaded", value_name, value_type); 238 } 239 } 240 } 241 } 242 } 243 //debug("out"); 244 return TRUE; 245 } 246 static inline XMLElement* add_ele(XMLDocument* xml, XMLElement* p, int index, 247 const char* name_tag, const char* value_type = NULL) 248 { 249 //debug("in, tag:%s", name_tag); 250 char ele_name[128] = {0}; 251 create_ele_name(index, ele_name, sizeof(ele_name)); 252 XMLElement* ele = xml->NewElement(ele_name); 253 //debug("ele name:%s, tag:%s, index:%d, value type:%s", ele_name, name_tag, index, value_type); 254 ele->SetAttribute(BLUEDROID_NAME_TAG, name_tag); 255 if(value_type && *value_type) 256 ele->SetAttribute(BLUEDROID_VALUE_TYPE, value_type); 257 p->InsertEndChild(ele); 258 //debug("out, tag:%s", name_tag); 259 return ele; 260 } 261 static void enum_config(void* user_data, const char* section_name, const char* key_name, const char* value_name, 262 const char* value, int bytes, int type) 263 { 264 enum_user_data& d = *(enum_user_data*)user_data; 265 //debug("in, key:%s, value:%s", key_name, value_name); 266 //debug("section name:%s, key name:%s, value name:%s, value type:%s", 267 // section_name, key_name, value_name, type_int2str(type)); 268 if(type & BTIF_CFG_TYPE_VOLATILE) 269 return; //skip any volatile value 270 if(d.sn != section_name) 271 { 272 d.sn = section_name; 273 d.se = add_ele(d.xml, d.xml->RootElement(), ++d.si, section_name); 274 d.ki = 0; 275 } 276 if(d.kn != key_name) 277 { 278 d.kn = key_name; 279 d.ke = add_ele(d.xml, d.se, ++d.ki, key_name); 280 d.vi = 0; 281 } 282 if(d.vn != value_name) 283 { 284 if(type & BTIF_CFG_TYPE_STR) 285 { 286 d.vn = value_name; 287 d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type)); 288 d.ve->InsertFirstChild(d.xml->NewText(value)); 289 } 290 else if(type & BTIF_CFG_TYPE_INT) 291 { 292 d.vn = value_name; 293 d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type)); 294 char value_str[64] = {0}; 295 snprintf(value_str, sizeof(value_str), "%d", *(int*)value); 296 d.ve->InsertFirstChild(d.xml->NewText(value_str)); 297 } 298 else if(type & BTIF_CFG_TYPE_BIN) 299 { 300 d.vn = value_name; 301 d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type)); 302 char* value_str = (char*)alloca(bytes*2 + 1); 303 bytes2hex(value, bytes, value_str); 304 d.ve->InsertFirstChild(d.xml->NewText(value_str)); 305 } 306 else error("unsupported config value name:%s, type:%s not saved", d.vn, type_int2str(type)); 307 } 308 //debug("out, key:%s, value:%s", key_name, value_name); 309 } 310 311 static int type_str2int(const char* type) 312 { 313 if(strcmp(type, "int") == 0) 314 return BTIF_CFG_TYPE_INT; 315 if(strcmp(type, "binary") == 0) 316 return BTIF_CFG_TYPE_BIN; 317 if(type == 0 || *type == 0 || strcmp(type, "string") == 0) 318 return BTIF_CFG_TYPE_STR; 319 error("unknown value type:%s", type); 320 return BTIF_CFG_TYPE_INVALID; 321 } 322 static const char* type_int2str(int type) 323 { 324 switch(type) 325 { 326 case BTIF_CFG_TYPE_INT: 327 return "int"; 328 case BTIF_CFG_TYPE_BIN: 329 return "binary"; 330 case BTIF_CFG_TYPE_STR: 331 return "string"; 332 default: 333 error("unknown type:%d", type); 334 break; 335 } 336 return NULL; 337 } 338 339 static inline void create_ele_name(int index, char* element, int len) 340 { 341 snprintf(element, len, "N%d", index); 342 } 343 static inline int validate_ele_name(const char* key) 344 { 345 //must be 'N' followed with numbers 346 if(key && *key == 'N' && *++key) 347 { 348 while(*key) 349 { 350 if(*key < '0' || *key > '9') 351 return FALSE; 352 ++key; 353 } 354 return TRUE; 355 } 356 return FALSE; 357 } 358 static int open_file_map(const char *pathname, const char**map, int* size) 359 { 360 struct stat st; 361 st.st_size = 0; 362 int fd; 363 //debug("in"); 364 if((fd = open(pathname, O_RDONLY)) >= 0) 365 { 366 //debug("fd:%d", fd); 367 if(fstat(fd, &st) == 0 && st.st_size) 368 { 369 *size = st.st_size; 370 *map = (const char*)mmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0); 371 if(*map && *map != MAP_FAILED) 372 { 373 //debug("out map:%p, size:%d", *map, *size); 374 return fd; 375 } 376 } 377 close(fd); 378 } 379 //debug("out, failed"); 380 return -1; 381 } 382 static void close_file_map(int fd, const char* map, int size) 383 { 384 munmap((void*)map, size); 385 close(fd); 386 } 387 static int read_file_line(const char* map, int start_pos, int size, int* line_size) 388 { 389 *line_size = 0; 390 //debug("in, start pos:%d, size:%d", start_pos, size); 391 int i; 392 for(i = start_pos; i < size; i++) 393 { 394 if(map[i] == '\r' || map[i] == '\n') 395 break; 396 ++*line_size; 397 } 398 //debug("out, ret:%d, start pos:%d, size:%d, line_size:%d", i, start_pos, size, *line_size); 399 return i + 1; 400 } 401 static const char* find_value_line(const char* map, int size, const char *key, int* value_size) 402 { 403 int key_len = strlen(key); 404 int i; 405 for(i = 0; i < size; i++) 406 { 407 if(map[i] == *key) 408 { 409 if(i + key_len + 1 > size) 410 return NULL; 411 if(memcmp(map + i, key, key_len) == 0) 412 { 413 read_file_line(map, i + key_len + 1, size, value_size); 414 if(*value_size) 415 return map + i + key_len + 1; 416 break; 417 } 418 } 419 } 420 return NULL; 421 } 422 static int read_line_word(const char* line, int start_pos, int line_size, char* word, int *word_size, bool lower_case = false) 423 { 424 int i; 425 //skip space 426 //debug("in, line start_pos:%d, line_size:%d", start_pos, line_size); 427 for(i = start_pos; i < line_size; i++) 428 { 429 //debug("skip space loop, line[%d]:%c", i, line[i]); 430 if(line[i] != ' ' && line[i] != '\t' && line[i] != '\r' && line[i] !='\n') 431 break; 432 } 433 *word_size = 0; 434 for(; i < line_size; i++) 435 { 436 //debug("add word loop, line[%d]:%c", i, line[i]); 437 if(line[i] != ' ' && line[i] != '\t' && line[i] != '\r' && line[i] !='\n') 438 { 439 ++*word_size; 440 if(lower_case && 'A' <= line[i] && line[i] <= 'Z') 441 *word++ = 'a' - 'A' + line[i]; 442 else 443 *word++ = line[i]; 444 } 445 else break; 446 } 447 *word = 0; 448 //debug("out, ret:%d, word:%s, word_size:%d, line start_pos:%d, line_size:%d", 449 // i, word, *word_size, start_pos, line_size); 450 return i; 451 } 452 static int is_valid_bd_addr(const char* addr) 453 { 454 int len = strlen(addr); 455 //debug("addr: %s, len:%d", addr, len); 456 return len == 17 && addr[2] == ':' && addr[5] == ':' && addr[14] == ':'; 457 } 458 static int load_bluez_cfg_value(const char* adapter_path, const char* file_name) 459 { 460 //debug("in"); 461 462 const char* map = NULL; 463 int size = 0; 464 int ret = FALSE; 465 char path[256]; 466 snprintf(path, sizeof(path), "%s/%s", adapter_path, file_name); 467 int fd = open_file_map(path, &map, &size); 468 //debug("in, path:%s, fd:%d, size:%d", path, fd, size); 469 if(fd < 0 || size == 0) 470 { 471 error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size); 472 //debug("out"); 473 return FALSE; 474 } 475 //get local bt device name from bluez config 476 int line_size = 0; 477 const char *value_line = find_value_line(map, size, "name", &line_size); 478 if(value_line && line_size > 0) 479 { 480 char value[line_size + 1]; 481 memcpy(value, value_line, line_size); 482 value[line_size] = 0; 483 //debug("import local bt dev names:%s", value); 484 btif_config_set_str("Local", "Adapter", "Name", value); 485 ret = TRUE; 486 } 487 488 close_file_map(fd, map, size); 489 //debug("out, ret:%d", ret); 490 return ret; 491 } 492 493 int load_bluez_adapter_info(char* adapter_path, int size) 494 { 495 struct dirent *dptr; 496 DIR *dirp; 497 int ret = FALSE; 498 if((dirp = opendir(BLUEZ_PATH)) != NULL) 499 { 500 while((dptr = readdir(dirp)) != NULL) 501 { 502 //debug("readdir: %s",dptr->d_name); 503 if(is_valid_bd_addr(dptr->d_name)) 504 { 505 snprintf(adapter_path, size, "%s%s", BLUEZ_PATH, dptr->d_name); 506 btif_config_set_str("Local", "Adapter", "Address", dptr->d_name); 507 load_bluez_cfg_value(adapter_path, BLUEZ_CONFIG); 508 ret = TRUE; 509 break; 510 } 511 } 512 closedir(dirp); 513 } 514 return ret; 515 } 516 static inline void upcase_addr(const char* laddr, char* uaddr, int size) 517 { 518 int i; 519 for(i = 0; i < size && laddr[i]; i++) 520 uaddr[i] = ('a' <= laddr[i] && laddr[i] <= 'z') ? 521 laddr[i] - ('a' - 'A') : laddr[i]; 522 uaddr[i] = 0; 523 } 524 static int load_bluez_dev_value(const char* adapter_path, const char* bd_addr, 525 const char* file_name, const char* cfg_value_name, int type) 526 { 527 //debug("in"); 528 char addr[32]; 529 upcase_addr(bd_addr, addr, sizeof(addr)); 530 531 const char* map = NULL; 532 int size = 0; 533 int ret = FALSE; 534 char path[256]; 535 snprintf(path, sizeof(path), "%s/%s", adapter_path, file_name); 536 int fd = open_file_map(path, &map, &size); 537 //debug("in, path:%s, addr:%s, fd:%d, size:%d", path, addr, fd, size); 538 if(fd < 0 || size == 0) 539 { 540 error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size); 541 //debug("out"); 542 return FALSE; 543 } 544 int line_size = 0; 545 const char *value_line = find_value_line(map, size, addr, &line_size); 546 if(value_line && line_size) 547 { 548 char line[line_size + 1]; 549 memcpy(line, value_line, line_size); 550 line[line_size] = 0; 551 //debug("addr:%s, Names:%s", bd_addr, line); 552 if(type == BTIF_CFG_TYPE_STR) 553 btif_config_set_str("Remote", bd_addr, cfg_value_name, line); 554 else if(type == BTIF_CFG_TYPE_INT) 555 { 556 int v = strtol(line, NULL, 16); 557 //filter out unspported devices by its class 558 if(strcmp(file_name, BLUEZ_CLASSES) == 0) 559 { 560 switch((v & 0x1f00) >> 8) 561 { 562 case 0x5: //hid device 563 error("skip paired hid devices"); 564 close_file_map(fd, map, size); 565 return FALSE; 566 } 567 } 568 btif_config_set_int("Remote", bd_addr, cfg_value_name, v); 569 } 570 ret = TRUE; 571 } 572 close_file_map(fd, map, size); 573 //debug("out, ret:%d", ret); 574 return ret; 575 } 576 static inline int bz2bd_linkkeytype(int type) 577 { 578 #if 1 579 return type; 580 #else 581 int table[5] = {0, 0, 0, 0, 0}; 582 if(0 <= type && type < (int)(sizeof(table)/sizeof(int))) 583 return table[type]; 584 return 0; 585 #endif 586 } 587 int load_bluez_linkkeys(const char* adapter_path) 588 { 589 const char* map = NULL; 590 int size = 0; 591 int ret = FALSE; 592 char path[256]; 593 //debug("in"); 594 snprintf(path, sizeof(path), "%s/%s", adapter_path, BLUEZ_LINKKEY); 595 int fd = open_file_map(path, &map, &size); 596 if(fd < 0 || size == 0) 597 { 598 error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size); 599 //debug("out"); 600 return FALSE; 601 } 602 int pos = 0; 603 //debug("path:%s, size:%d", path, size); 604 while(pos < size) 605 { 606 int line_size = 0; 607 int next_pos = read_file_line(map, pos, size, &line_size); 608 //debug("pos:%d, next_pos:%d, size:%d, line_size:%d", pos, next_pos, size, line_size); 609 if(line_size) 610 { 611 const char* line = map + pos; 612 char addr[line_size + 1]; 613 int word_pos = 0; 614 int addr_size = 0; 615 word_pos = read_line_word(line, word_pos, line_size, addr, &addr_size, true); 616 //debug("read_line_word addr:%s, addr_size:%d", addr, addr_size); 617 if(*addr) 618 { 619 char value[line_size + 1]; 620 int value_size = 0; 621 //read link key 622 word_pos = read_line_word(line, word_pos, line_size, value, &value_size); 623 //debug("read_line_word linkkey:%s, size:%d", value, value_size); 624 if(*value) 625 { 626 int linkkey_size = value_size / 2; 627 char linkkey[linkkey_size]; 628 if(hex2bytes(value, value_size, linkkey)) 629 { //read link key type 630 //bluez save the linkkey in reversed order 631 reverse_bin(linkkey, linkkey_size); 632 word_pos = read_line_word(line, word_pos, 633 line_size, value, &value_size); 634 if(*value) 635 { 636 if(load_bluez_dev_value(adapter_path, addr, 637 BLUEZ_CLASSES, "DevClass", BTIF_CFG_TYPE_INT) && 638 load_bluez_dev_value(adapter_path, addr, 639 BLUEZ_NAMES, "Name", BTIF_CFG_TYPE_STR) && 640 load_bluez_dev_value(adapter_path, addr, 641 BLUEZ_TYPES, "DevType", BTIF_CFG_TYPE_INT) && 642 load_bluez_dev_value(adapter_path, addr, 643 BLUEZ_PROFILES, "Service", BTIF_CFG_TYPE_STR)) 644 { 645 load_bluez_dev_value(adapter_path, addr, 646 BLUEZ_ALIASES, "Aliase", BTIF_CFG_TYPE_STR); 647 int key_type = bz2bd_linkkeytype(atoi(value)); 648 649 //read pin len 650 word_pos = read_line_word(line, word_pos, line_size, value, &value_size); 651 if(*value) 652 { 653 int pin_len = atoi(value); 654 ret = TRUE; 655 btif_config_set("Remote", addr, "LinkKey", linkkey, 656 linkkey_size, BTIF_CFG_TYPE_BIN); 657 //dump_bin("import bluez linkkey", linkkey, linkkey_size); 658 btif_config_set_int("Remote", addr, "LinkKeyType", key_type); 659 btif_config_set_int("Remote", addr, "PinLength", pin_len); 660 } 661 } 662 } 663 } 664 } 665 } 666 } 667 //debug("pos:%d, next_pos:%d, size:%d, line_size:%d", pos, next_pos, size, line_size); 668 pos = next_pos; 669 } 670 close_file_map(fd, map, size); 671 //debug("out, ret:%d", ret); 672 return ret; 673 } 674 675