Loading fastboot/engine.cpp +4 −4 Original line number Diff line number Diff line Loading @@ -351,21 +351,21 @@ int fb_execute_queue(Transport* transport) } if (a->op == OP_DOWNLOAD) { status = fb_download_data(transport, a->data, a->size); status = a->func(a, status, status ? fb_get_error() : ""); status = a->func(a, status, status ? fb_get_error().c_str() : ""); if (status) break; } else if (a->op == OP_COMMAND) { status = fb_command(transport, a->cmd); status = a->func(a, status, status ? fb_get_error() : ""); status = a->func(a, status, status ? fb_get_error().c_str() : ""); if (status) break; } else if (a->op == OP_QUERY) { status = fb_command_response(transport, a->cmd, resp); status = a->func(a, status, status ? fb_get_error() : resp); status = a->func(a, status, status ? fb_get_error().c_str() : resp); if (status) break; } else if (a->op == OP_NOTICE) { fprintf(stderr,"%s\n",(char*)a->data); } else if (a->op == OP_DOWNLOAD_SPARSE) { status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data)); status = a->func(a, status, status ? fb_get_error() : ""); status = a->func(a, status, status ? fb_get_error().c_str() : ""); if (status) break; } else if (a->op == OP_WAIT_FOR_DISCONNECT) { transport->WaitForDisconnect(); Loading fastboot/fastboot.cpp +32 −35 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ #include <android-base/parseint.h> #include <android-base/parsenetaddress.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> #include <sparse/sparse.h> #include <ziparchive/zip_archive.h> Loading Loading @@ -108,11 +109,8 @@ static struct { {"vendor.img", "vendor.sig", "vendor", true}, }; static char* find_item(const char* item, const char* product) { char *dir; static std::string find_item(const char* item, const char* product) { const char *fn; char path[PATH_MAX + 128]; if (!strcmp(item,"boot")) { fn = "boot.img"; } else if(!strcmp(item,"recovery")) { Loading @@ -129,24 +127,22 @@ static char* find_item(const char* item, const char* product) { fn = "android-info.txt"; } else { fprintf(stderr,"unknown partition '%s'\n", item); return 0; return ""; } if (product) { get_my_path(path); sprintf(path + strlen(path), "../../../target/product/%s/%s", product, fn); return strdup(path); std::string path = get_my_path(); path.erase(path.find_last_of('/')); return android::base::StringPrintf("%s/../../../target/product/%s/%s", path.c_str(), product, fn); } dir = getenv("ANDROID_PRODUCT_OUT"); if((dir == 0) || (dir[0] == 0)) { char* dir = getenv("ANDROID_PRODUCT_OUT"); if (dir == nullptr || dir[0] == '\0') { die("neither -p product specified nor ANDROID_PRODUCT_OUT set"); return 0; } sprintf(path, "%s/%s", dir, fn); return strdup(path); return android::base::StringPrintf("%s/%s", dir, fn); } static int64_t get_file_size(int fd) { Loading Loading @@ -179,8 +175,8 @@ oops: return 0; } static void* load_file(const char* fn, int64_t* sz) { int fd = open(fn, O_RDONLY | O_BINARY); static void* load_file(const std::string& path, int64_t* sz) { int fd = open(path.c_str(), O_RDONLY | O_BINARY); if (fd == -1) return nullptr; return load_fd(fd, sz); } Loading Loading @@ -964,18 +960,19 @@ static void do_update(Transport* transport, const char* filename, const char* sl CloseArchive(zip); } static void do_send_signature(char* fn) { char* xtn = strrchr(fn, '.'); if (!xtn) return; if (strcmp(xtn, ".img")) return; static void do_send_signature(const char* filename) { if (android::base::EndsWith(filename, ".img") == false) { return; } strcpy(xtn, ".sig"); std::string sig_path = filename; sig_path.erase(sig_path.size() - 4); sig_path += ".sig"; int64_t sz; void* data = load_file(fn, &sz); strcpy(xtn, ".img"); void* data = load_file(sig_path, &sz); if (data == nullptr) return; fb_queue_download("signature", data, sz); fb_queue_command("signature", "installing signature"); } Loading @@ -985,8 +982,8 @@ static void do_flashall(Transport* transport, const char* slot_override, int era fb_queue_query_save("product", cur_product, sizeof(cur_product)); char* fname = find_item("info", product); if (fname == nullptr) die("cannot find android-info.txt"); std::string fname = find_item("info", product); if (fname.empty()) die("cannot find android-info.txt"); int64_t sz; void* data = load_file(fname, &sz); Loading @@ -997,14 +994,14 @@ static void do_flashall(Transport* transport, const char* slot_override, int era for (size_t i = 0; i < ARRAY_SIZE(images); i++) { fname = find_item(images[i].part_name, product); fastboot_buffer buf; if (load_buf(transport, fname, &buf)) { if (load_buf(transport, fname.c_str(), &buf)) { if (images[i].is_optional) continue; die("could not load %s\n", images[i].img_name); } auto flashall = [&](const std::string &partition) { do_send_signature(fname); do_send_signature(fname.c_str()); if (erase_first && needs_erase(transport, partition.c_str())) { fb_queue_erase(partition.c_str()); } Loading Loading @@ -1180,7 +1177,7 @@ failed: fprintf(stderr, "Erase successful, but not automatically formatting.\n"); if (errMsg) fprintf(stderr, "%s", errMsg); } fprintf(stderr,"FAILED (%s)\n", fb_get_error()); fprintf(stderr, "FAILED (%s)\n", fb_get_error().c_str()); } int main(int argc, char **argv) Loading Loading @@ -1442,7 +1439,7 @@ int main(int argc, char **argv) fb_queue_command("boot", "booting"); } else if(!strcmp(*argv, "flash")) { char* pname = argv[1]; char *fname = 0; std::string fname; require(2); if (argc > 2) { fname = argv[2]; Loading @@ -1451,13 +1448,13 @@ int main(int argc, char **argv) fname = find_item(pname, product); skip(2); } if (fname == 0) die("cannot determine image filename for '%s'", pname); if (fname.empty()) die("cannot determine image filename for '%s'", pname); auto flash = [&](const std::string &partition) { if (erase_first && needs_erase(transport, partition.c_str())) { fb_queue_erase(partition.c_str()); } do_flash(transport, partition.c_str(), fname); do_flash(transport, partition.c_str(), fname.c_str()); }; do_for_partitions(transport, pname, slot_override.c_str(), flash, true); } else if(!strcmp(*argv, "flash:raw")) { Loading fastboot/fastboot.h +2 −2 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ int fb_command(Transport* transport, const char* cmd); int fb_command_response(Transport* transport, const char* cmd, char* response); int fb_download_data(Transport* transport, const void* data, uint32_t size); int fb_download_data_sparse(Transport* transport, struct sparse_file* s); char *fb_get_error(void); const std::string fb_get_error(); #define FB_COMMAND_SZ 64 #define FB_RESPONSE_SZ 64 Loading Loading @@ -72,7 +72,7 @@ double now(); char *mkmsg(const char *fmt, ...); __attribute__((__noreturn__)) void die(const char *fmt, ...); void get_my_path(char *path); std::string get_my_path(); /* Current product */ extern char cur_product[FB_RESPONSE_SZ + 1]; Loading fastboot/protocol.cpp +16 −16 Original line number Diff line number Diff line Loading @@ -36,16 +36,16 @@ #include <algorithm> #include <android-base/stringprintf.h> #include <sparse/sparse.h> #include "fastboot.h" #include "transport.h" static char ERROR[128]; static std::string g_error; char *fb_get_error(void) { return ERROR; const std::string fb_get_error() { return g_error; } static int check_response(Transport* transport, uint32_t size, char* response) { Loading @@ -54,14 +54,14 @@ static int check_response(Transport* transport, uint32_t size, char* response) { while (true) { int r = transport->Read(status, 64); if (r < 0) { snprintf(ERROR, sizeof(ERROR), "status read failed (%s)", strerror(errno)); g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno)); transport->Close(); return -1; } status[r] = 0; if (r < 4) { snprintf(ERROR, sizeof(ERROR), "status malformed (%d bytes)", r); g_error = android::base::StringPrintf("status malformed (%d bytes)", r); transport->Close(); return -1; } Loading @@ -80,9 +80,9 @@ static int check_response(Transport* transport, uint32_t size, char* response) { if (!memcmp(status, "FAIL", 4)) { if (r > 4) { snprintf(ERROR, sizeof(ERROR), "remote: %s", status + 4); g_error = android::base::StringPrintf("remote: %s", status + 4); } else { strcpy(ERROR, "remote failure"); g_error = "remote failure"; } return -1; } Loading @@ -90,14 +90,14 @@ static int check_response(Transport* transport, uint32_t size, char* response) { if (!memcmp(status, "DATA", 4) && size > 0){ uint32_t dsize = strtol(status + 4, 0, 16); if (dsize > size) { strcpy(ERROR, "data size too large"); g_error = android::base::StringPrintf("data size too large (%d)", dsize); transport->Close(); return -1; } return dsize; } strcpy(ERROR,"unknown status code"); g_error = "unknown status code"; transport->Close(); break; } Loading @@ -108,7 +108,7 @@ static int check_response(Transport* transport, uint32_t size, char* response) { static int _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) { size_t cmdsize = strlen(cmd); if (cmdsize > 64) { snprintf(ERROR, sizeof(ERROR), "command too large"); g_error = android::base::StringPrintf("command too large (%zu)", cmdsize); return -1; } Loading @@ -117,7 +117,7 @@ static int _command_start(Transport* transport, const char* cmd, uint32_t size, } if (transport->Write(cmd, cmdsize) != static_cast<int>(cmdsize)) { snprintf(ERROR, sizeof(ERROR), "command write failed (%s)", strerror(errno)); g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno)); transport->Close(); return -1; } Loading @@ -128,12 +128,12 @@ static int _command_start(Transport* transport, const char* cmd, uint32_t size, static int _command_data(Transport* transport, const void* data, uint32_t size) { int r = transport->Write(data, size); if (r < 0) { snprintf(ERROR, sizeof(ERROR), "data transfer failure (%s)", strerror(errno)); g_error = android::base::StringPrintf("data transfer failure (%s)", strerror(errno)); transport->Close(); return -1; } if (r != ((int) size)) { snprintf(ERROR, sizeof(ERROR), "data transfer failure (short transfer)"); g_error = "data transfer failure (short transfer)"; transport->Close(); return -1; } Loading Loading @@ -216,7 +216,7 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len) if (len > TRANSPORT_BUF_SIZE) { if (transport_buf_len > 0) { snprintf(ERROR, sizeof(ERROR), "internal error: transport_buf not empty\n"); g_error = "internal error: transport_buf not empty"; return -1; } to_write = round_down(len, TRANSPORT_BUF_SIZE); Loading @@ -230,7 +230,7 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len) if (len > 0) { if (len > TRANSPORT_BUF_SIZE) { snprintf(ERROR, sizeof(ERROR), "internal error: too much left for transport_buf\n"); g_error = "internal error: too much left for transport_buf"; return -1; } memcpy(transport_buf, ptr, len); Loading fastboot/util_linux.cpp +8 −19 Original line number Diff line number Diff line Loading @@ -28,27 +28,16 @@ #include "fastboot.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <limits.h> void get_my_path(char *path) { char proc[64]; char *x; #include <android-base/stringprintf.h> sprintf(proc, "/proc/%d/exe", getpid()); int err = readlink(proc, path, PATH_MAX - 1); if(err <= 0) { path[0] = 0; } else { path[err] = 0; x = strrchr(path,'/'); if(x) x[1] = 0; } std::string get_my_path() { std::string proc = android::base::StringPrintf("/proc/%d/exe", getpid()); char path[PATH_MAX + 1]; int rc = readlink(proc.c_str(), path, sizeof(path) - 1); if (rc == -1) return ""; path[rc] = '\0'; return path; } Loading
fastboot/engine.cpp +4 −4 Original line number Diff line number Diff line Loading @@ -351,21 +351,21 @@ int fb_execute_queue(Transport* transport) } if (a->op == OP_DOWNLOAD) { status = fb_download_data(transport, a->data, a->size); status = a->func(a, status, status ? fb_get_error() : ""); status = a->func(a, status, status ? fb_get_error().c_str() : ""); if (status) break; } else if (a->op == OP_COMMAND) { status = fb_command(transport, a->cmd); status = a->func(a, status, status ? fb_get_error() : ""); status = a->func(a, status, status ? fb_get_error().c_str() : ""); if (status) break; } else if (a->op == OP_QUERY) { status = fb_command_response(transport, a->cmd, resp); status = a->func(a, status, status ? fb_get_error() : resp); status = a->func(a, status, status ? fb_get_error().c_str() : resp); if (status) break; } else if (a->op == OP_NOTICE) { fprintf(stderr,"%s\n",(char*)a->data); } else if (a->op == OP_DOWNLOAD_SPARSE) { status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data)); status = a->func(a, status, status ? fb_get_error() : ""); status = a->func(a, status, status ? fb_get_error().c_str() : ""); if (status) break; } else if (a->op == OP_WAIT_FOR_DISCONNECT) { transport->WaitForDisconnect(); Loading
fastboot/fastboot.cpp +32 −35 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ #include <android-base/parseint.h> #include <android-base/parsenetaddress.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> #include <sparse/sparse.h> #include <ziparchive/zip_archive.h> Loading Loading @@ -108,11 +109,8 @@ static struct { {"vendor.img", "vendor.sig", "vendor", true}, }; static char* find_item(const char* item, const char* product) { char *dir; static std::string find_item(const char* item, const char* product) { const char *fn; char path[PATH_MAX + 128]; if (!strcmp(item,"boot")) { fn = "boot.img"; } else if(!strcmp(item,"recovery")) { Loading @@ -129,24 +127,22 @@ static char* find_item(const char* item, const char* product) { fn = "android-info.txt"; } else { fprintf(stderr,"unknown partition '%s'\n", item); return 0; return ""; } if (product) { get_my_path(path); sprintf(path + strlen(path), "../../../target/product/%s/%s", product, fn); return strdup(path); std::string path = get_my_path(); path.erase(path.find_last_of('/')); return android::base::StringPrintf("%s/../../../target/product/%s/%s", path.c_str(), product, fn); } dir = getenv("ANDROID_PRODUCT_OUT"); if((dir == 0) || (dir[0] == 0)) { char* dir = getenv("ANDROID_PRODUCT_OUT"); if (dir == nullptr || dir[0] == '\0') { die("neither -p product specified nor ANDROID_PRODUCT_OUT set"); return 0; } sprintf(path, "%s/%s", dir, fn); return strdup(path); return android::base::StringPrintf("%s/%s", dir, fn); } static int64_t get_file_size(int fd) { Loading Loading @@ -179,8 +175,8 @@ oops: return 0; } static void* load_file(const char* fn, int64_t* sz) { int fd = open(fn, O_RDONLY | O_BINARY); static void* load_file(const std::string& path, int64_t* sz) { int fd = open(path.c_str(), O_RDONLY | O_BINARY); if (fd == -1) return nullptr; return load_fd(fd, sz); } Loading Loading @@ -964,18 +960,19 @@ static void do_update(Transport* transport, const char* filename, const char* sl CloseArchive(zip); } static void do_send_signature(char* fn) { char* xtn = strrchr(fn, '.'); if (!xtn) return; if (strcmp(xtn, ".img")) return; static void do_send_signature(const char* filename) { if (android::base::EndsWith(filename, ".img") == false) { return; } strcpy(xtn, ".sig"); std::string sig_path = filename; sig_path.erase(sig_path.size() - 4); sig_path += ".sig"; int64_t sz; void* data = load_file(fn, &sz); strcpy(xtn, ".img"); void* data = load_file(sig_path, &sz); if (data == nullptr) return; fb_queue_download("signature", data, sz); fb_queue_command("signature", "installing signature"); } Loading @@ -985,8 +982,8 @@ static void do_flashall(Transport* transport, const char* slot_override, int era fb_queue_query_save("product", cur_product, sizeof(cur_product)); char* fname = find_item("info", product); if (fname == nullptr) die("cannot find android-info.txt"); std::string fname = find_item("info", product); if (fname.empty()) die("cannot find android-info.txt"); int64_t sz; void* data = load_file(fname, &sz); Loading @@ -997,14 +994,14 @@ static void do_flashall(Transport* transport, const char* slot_override, int era for (size_t i = 0; i < ARRAY_SIZE(images); i++) { fname = find_item(images[i].part_name, product); fastboot_buffer buf; if (load_buf(transport, fname, &buf)) { if (load_buf(transport, fname.c_str(), &buf)) { if (images[i].is_optional) continue; die("could not load %s\n", images[i].img_name); } auto flashall = [&](const std::string &partition) { do_send_signature(fname); do_send_signature(fname.c_str()); if (erase_first && needs_erase(transport, partition.c_str())) { fb_queue_erase(partition.c_str()); } Loading Loading @@ -1180,7 +1177,7 @@ failed: fprintf(stderr, "Erase successful, but not automatically formatting.\n"); if (errMsg) fprintf(stderr, "%s", errMsg); } fprintf(stderr,"FAILED (%s)\n", fb_get_error()); fprintf(stderr, "FAILED (%s)\n", fb_get_error().c_str()); } int main(int argc, char **argv) Loading Loading @@ -1442,7 +1439,7 @@ int main(int argc, char **argv) fb_queue_command("boot", "booting"); } else if(!strcmp(*argv, "flash")) { char* pname = argv[1]; char *fname = 0; std::string fname; require(2); if (argc > 2) { fname = argv[2]; Loading @@ -1451,13 +1448,13 @@ int main(int argc, char **argv) fname = find_item(pname, product); skip(2); } if (fname == 0) die("cannot determine image filename for '%s'", pname); if (fname.empty()) die("cannot determine image filename for '%s'", pname); auto flash = [&](const std::string &partition) { if (erase_first && needs_erase(transport, partition.c_str())) { fb_queue_erase(partition.c_str()); } do_flash(transport, partition.c_str(), fname); do_flash(transport, partition.c_str(), fname.c_str()); }; do_for_partitions(transport, pname, slot_override.c_str(), flash, true); } else if(!strcmp(*argv, "flash:raw")) { Loading
fastboot/fastboot.h +2 −2 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ int fb_command(Transport* transport, const char* cmd); int fb_command_response(Transport* transport, const char* cmd, char* response); int fb_download_data(Transport* transport, const void* data, uint32_t size); int fb_download_data_sparse(Transport* transport, struct sparse_file* s); char *fb_get_error(void); const std::string fb_get_error(); #define FB_COMMAND_SZ 64 #define FB_RESPONSE_SZ 64 Loading Loading @@ -72,7 +72,7 @@ double now(); char *mkmsg(const char *fmt, ...); __attribute__((__noreturn__)) void die(const char *fmt, ...); void get_my_path(char *path); std::string get_my_path(); /* Current product */ extern char cur_product[FB_RESPONSE_SZ + 1]; Loading
fastboot/protocol.cpp +16 −16 Original line number Diff line number Diff line Loading @@ -36,16 +36,16 @@ #include <algorithm> #include <android-base/stringprintf.h> #include <sparse/sparse.h> #include "fastboot.h" #include "transport.h" static char ERROR[128]; static std::string g_error; char *fb_get_error(void) { return ERROR; const std::string fb_get_error() { return g_error; } static int check_response(Transport* transport, uint32_t size, char* response) { Loading @@ -54,14 +54,14 @@ static int check_response(Transport* transport, uint32_t size, char* response) { while (true) { int r = transport->Read(status, 64); if (r < 0) { snprintf(ERROR, sizeof(ERROR), "status read failed (%s)", strerror(errno)); g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno)); transport->Close(); return -1; } status[r] = 0; if (r < 4) { snprintf(ERROR, sizeof(ERROR), "status malformed (%d bytes)", r); g_error = android::base::StringPrintf("status malformed (%d bytes)", r); transport->Close(); return -1; } Loading @@ -80,9 +80,9 @@ static int check_response(Transport* transport, uint32_t size, char* response) { if (!memcmp(status, "FAIL", 4)) { if (r > 4) { snprintf(ERROR, sizeof(ERROR), "remote: %s", status + 4); g_error = android::base::StringPrintf("remote: %s", status + 4); } else { strcpy(ERROR, "remote failure"); g_error = "remote failure"; } return -1; } Loading @@ -90,14 +90,14 @@ static int check_response(Transport* transport, uint32_t size, char* response) { if (!memcmp(status, "DATA", 4) && size > 0){ uint32_t dsize = strtol(status + 4, 0, 16); if (dsize > size) { strcpy(ERROR, "data size too large"); g_error = android::base::StringPrintf("data size too large (%d)", dsize); transport->Close(); return -1; } return dsize; } strcpy(ERROR,"unknown status code"); g_error = "unknown status code"; transport->Close(); break; } Loading @@ -108,7 +108,7 @@ static int check_response(Transport* transport, uint32_t size, char* response) { static int _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) { size_t cmdsize = strlen(cmd); if (cmdsize > 64) { snprintf(ERROR, sizeof(ERROR), "command too large"); g_error = android::base::StringPrintf("command too large (%zu)", cmdsize); return -1; } Loading @@ -117,7 +117,7 @@ static int _command_start(Transport* transport, const char* cmd, uint32_t size, } if (transport->Write(cmd, cmdsize) != static_cast<int>(cmdsize)) { snprintf(ERROR, sizeof(ERROR), "command write failed (%s)", strerror(errno)); g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno)); transport->Close(); return -1; } Loading @@ -128,12 +128,12 @@ static int _command_start(Transport* transport, const char* cmd, uint32_t size, static int _command_data(Transport* transport, const void* data, uint32_t size) { int r = transport->Write(data, size); if (r < 0) { snprintf(ERROR, sizeof(ERROR), "data transfer failure (%s)", strerror(errno)); g_error = android::base::StringPrintf("data transfer failure (%s)", strerror(errno)); transport->Close(); return -1; } if (r != ((int) size)) { snprintf(ERROR, sizeof(ERROR), "data transfer failure (short transfer)"); g_error = "data transfer failure (short transfer)"; transport->Close(); return -1; } Loading Loading @@ -216,7 +216,7 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len) if (len > TRANSPORT_BUF_SIZE) { if (transport_buf_len > 0) { snprintf(ERROR, sizeof(ERROR), "internal error: transport_buf not empty\n"); g_error = "internal error: transport_buf not empty"; return -1; } to_write = round_down(len, TRANSPORT_BUF_SIZE); Loading @@ -230,7 +230,7 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len) if (len > 0) { if (len > TRANSPORT_BUF_SIZE) { snprintf(ERROR, sizeof(ERROR), "internal error: too much left for transport_buf\n"); g_error = "internal error: too much left for transport_buf"; return -1; } memcpy(transport_buf, ptr, len); Loading
fastboot/util_linux.cpp +8 −19 Original line number Diff line number Diff line Loading @@ -28,27 +28,16 @@ #include "fastboot.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <limits.h> void get_my_path(char *path) { char proc[64]; char *x; #include <android-base/stringprintf.h> sprintf(proc, "/proc/%d/exe", getpid()); int err = readlink(proc, path, PATH_MAX - 1); if(err <= 0) { path[0] = 0; } else { path[err] = 0; x = strrchr(path,'/'); if(x) x[1] = 0; } std::string get_my_path() { std::string proc = android::base::StringPrintf("/proc/%d/exe", getpid()); char path[PATH_MAX + 1]; int rc = readlink(proc.c_str(), path, sizeof(path) - 1); if (rc == -1) return ""; path[rc] = '\0'; return path; }