// SPDX-License-Identifier: GPL-2.0 #include #include #include #include #include #include #include #include "cliserv.h" #include "nbd-debug.h" const u64 cliserv_magic = 0x00420281861253LL; const u64 opts_magic = 0x49484156454F5054LL; const u64 rep_magic = 0x3e889045565a9LL; /** * Set a socket to blocking or non-blocking * * @param fd The socket's FD * @param nb nonzero to set to non-blocking, else 0 to set to blocking * @return 0 - OK, -1 failed */ int set_nonblocking(int fd, int nb) { int sf = fcntl (fd, F_GETFL, 0); if (sf == -1) return -1; return fcntl (fd, F_SETFL, nb ? (sf | O_NONBLOCK) : (sf & ~O_NONBLOCK)); } void setmysockopt(int sock) { int size = 1; #if 0 if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) INFO("(no sockopt/1: %m)"); #endif #ifdef IPPROTO_TCP size = 1; if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &size, sizeof(int)) < 0) INFO("(no sockopt/2: %m)"); #endif #if 0 size = 1024; if (setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &size, sizeof(int)) < 0) INFO("(no sockopt/3: %m)"); #endif } void err_nonfatal(const char *s) { char s1[150], *s2; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstringop-truncation" strncpy(s1, s, sizeof(s1)); #pragma GCC diagnostic pop if ((s2 = strstr(s, "%m"))) { strncpy(s1 + (s2 - s), strerror(errno), sizeof(s1) - (s2 - s)); s2 += 2; strncpy(s1 + strlen(s1), s2, sizeof(s1) - strlen(s1)); } #ifndef sun /* Solaris doesn't have %h in syslog */ else if ((s2 = strstr(s, "%h"))) { strncpy(s1 + (s2 - s), hstrerror(h_errno), sizeof(s1) - (s2 - s)); s2 += 2; strncpy(s1 + strlen(s1), s2, sizeof(s1) - strlen(s1)); } #endif s1[sizeof(s1)-1] = '\0'; #ifdef ISSERVER syslog(LOG_ERR, "%s", s1); syslog(LOG_ERR, "Exiting."); #endif fprintf(stderr, "Error: %s\n", s1); } void err(const char *s) { err_nonfatal(s); fprintf(stderr, "Exiting.\n"); exit(EXIT_FAILURE); } void logging(const char* name) { #ifdef ISSERVER openlog(name, LOG_PID, LOG_DAEMON); #endif setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); } #ifndef ntohll #ifdef WORDS_BIGENDIAN uint64_t ntohll(uint64_t a) { return a; } #else uint64_t ntohll(uint64_t a) { u32 lo = a & 0xffffffff; u32 hi = a >> 32U; lo = ntohl(lo); hi = ntohl(hi); return ((uint64_t) lo) << 32U | hi; } #endif #endif /** * Read data from a file descriptor into a buffer * * @param f a file descriptor * @param buf a buffer * @param len the number of bytes to be read * @return 0 on completion, or -1 on failure **/ int readit(int f, void *buf, size_t len) { ssize_t res; while (len > 0) { NBD_DEBUG("*"); res = read(f, buf, len); if (res > 0) { len -= res; buf += res; } else if (res < 0) { if(errno != EAGAIN) { err_nonfatal("Read failed: %m"); return -1; } } else { errno = ECONNRESET; return -1; } } return 0; } /** * Write data from a buffer into a filedescriptor * * @param f a file descriptor * @param buf a buffer containing data * @param len the number of bytes to be written * @return 0 on success, or -1 if the socket was closed **/ int writeit(int f, void *buf, size_t len) { ssize_t res; while (len > 0) { NBD_DEBUG("+"); if ((res = write(f, buf, len)) <= 0) { switch(errno) { case EAGAIN: break; default: err_nonfatal("Send failed: %m"); return -1; } } len -= res; buf += res; } return 0; }