63 #include <sys/types.h>
64 #include <sys/socket.h>
66 #include <sys/select.h>
68 #ifdef HAVE_SYS_IOCTL_H
69 #include <sys/ioctl.h>
71 #include <sys/param.h>
72 #ifdef HAVE_SYS_MOUNT_H
73 #include <sys/mount.h>
77 #include <netinet/tcp.h>
78 #include <netinet/in.h>
88 #include <linux/falloc.h>
90 #include <arpa/inet.h>
102 #define MY_NAME "nbd_server"
106 #include <sdp_inet.h>
111 #define SYSCONFDIR "/etc"
113 #define CFILE SYSCONFDIR "/nbd-server/config"
130 #define msg2(a,b) syslog(a,b)
131 #define msg3(a,b,c) syslog(a,b,c)
132 #define msg4(a,b,c,d) syslog(a,b,c,d)
134 #define msg2(a,b) g_message((char*)b)
135 #define msg3(a,b,c) g_message((char*)b,c)
136 #define msg4(a,b,c,d) g_message((char*)b,c,d)
142 #define DEBUG(...) printf(__VA_ARGS__)
146 #ifndef PACKAGE_VERSION
147 #define PACKAGE_VERSION ""
153 #define OFFT_MAX ~((off_t)1<<(sizeof(off_t)*8-1))
156 #define BUFSIZE ((1024*1024)+sizeof(struct nbd_reply))
157 #define DIFFPAGESIZE 4096
161 #define F_MULTIFILE 2
162 #define F_COPYONWRITE 4
164 #define F_AUTOREADONLY 8
170 #define F_ROTATIONAL 512
171 #define F_TEMPORARY 1024
183 #define NEG_INIT (1 << 0)
184 #define NEG_OLD (1 << 1)
185 #define NEG_MODERN (1 << 2)
298 return "NBD_CMD_READ";
300 return "NBD_CMD_WRITE";
302 return "NBD_CMD_DISC";
304 return "NBD_CMD_FLUSH";
319 const char *ERRMSG=
"Invalid entry '%s' in authfile '%s', so, refusing all connections.";
324 struct in_addr client;
325 struct in_addr cltemp;
329 msg4(LOG_INFO,
"Can't open authorization file %s (%s).",
335 while (fgets(line,
LINELEN,f)!=NULL) {
336 if((tmp=strchr(line,
'/'))) {
337 if(strlen(line)<=tmp-line) {
342 if(!inet_aton(line,&addr)) {
346 len=strtol(tmp, NULL, 0);
347 addr.s_addr>>=32-
len;
348 addr.s_addr<<=32-
len;
349 memcpy(&cltemp,&client,
sizeof(client));
350 cltemp.s_addr>>=32-
len;
351 cltemp.s_addr<<=32-
len;
352 if(addr.s_addr == cltemp.s_addr) {
372 static inline void readit(
int f,
void *buf,
size_t len) {
376 if ((res = read(f, buf, len)) <= 0) {
377 if(errno != EAGAIN) {
378 err(
"Read failed: %m");
395 static inline void consume(
int f,
void * buf,
size_t len,
size_t bufsiz) {
398 curlen = (len>bufsiz)?bufsiz:len;
416 if ((res = write(f, buf, len)) <= 0)
417 err(
"Send failed: %m");
428 printf(
"This is nbd-server version " VERSION "\n");
429 printf(
"Usage: [ip:|ip6@]port file_to_export [size][kKmM] [-l authorize_file] [-r] [-m] [-c] [-C configuration file] [-p PID file name] [-o section name] [-M max connections]\n"
430 "\t-r|--read-only\t\tread only\n"
431 "\t-m|--multi-file\t\tmultiple file\n"
432 "\t-c|--copy-on-write\tcopy on write\n"
433 "\t-C|--config-file\tspecify an alternate configuration file\n"
434 "\t-l|--authorize-file\tfile with list of hosts that are allowed to\n\t\t\t\tconnect.\n"
435 "\t-p|--pid-file\t\tspecify a filename to write our PID to\n"
436 "\t-o|--output-config\toutput a config file section for what you\n\t\t\t\tspecified on the command line, with the\n\t\t\t\tspecified section name\n"
437 "\t-M|--max-connections\tspecify the maximum number of opened connections\n\n"
438 "\tif port is set to 0, stdin is used (for running from inetd).\n"
439 "\tif file_to_export contains '%%s', it is substituted with the IP\n"
440 "\t\taddress of the machine trying to connect\n"
441 "\tif ip is set, it contains the local IP address on which we're listening.\n\tif not, the server will listen on all local IP addresses\n");
442 printf(
"Using configuration file %s\n",
CFILE);
447 printf(
"[%s]\n", section_header);
448 printf(
"\texportname = %s\n", serve->
exportname);
449 printf(
"\tlistenaddr = %s\n", serve->
listenaddr);
450 printf(
"\tport = %d\n", serve->
port);
452 printf(
"\treadonly = true\n");
455 printf(
"\tmultifile = true\n");
458 printf(
"\tcopyonwrite = true\n");
461 printf(
"\tfilesize = %lld\n", (
long long int)serve->
expected_size);
464 printf(
"\tauthfile = %s\n", serve->
authname);
479 struct option long_options[] = {
480 {
"read-only", no_argument, NULL,
'r'},
481 {
"multi-file", no_argument, NULL,
'm'},
482 {
"copy-on-write", no_argument, NULL,
'c'},
483 {
"dont-fork", no_argument, NULL,
'd'},
484 {
"authorize-file", required_argument, NULL,
'l'},
485 {
"config-file", required_argument, NULL,
'C'},
486 {
"pid-file", required_argument, NULL,
'p'},
487 {
"output-config", required_argument, NULL,
'o'},
488 {
"max-connection", required_argument, NULL,
'M'},
495 gboolean do_output=FALSE;
496 gchar* section_header=
"";
505 while((c=getopt_long(argc, argv,
"-C:cdl:mo:rp:M:", long_options, &i))>=0) {
509 switch(nonspecial++) {
511 if(strchr(optarg,
':') == strrchr(optarg,
':')) {
512 addr_port=g_strsplit(optarg,
":", 2);
517 g_strfreev(addr_port);
518 addr_port=g_strsplit(optarg,
"@", 2);
521 addr_port=g_strsplit(optarg,
"@", 2);
525 serve->
port=strtol(addr_port[1], NULL, 0);
529 serve->
port=strtol(addr_port[0], NULL, 0);
531 g_strfreev(addr_port);
536 fprintf(stderr,
"E: The to be exported file needs to be an absolute filename!\n");
541 last=strlen(optarg)-1;
543 if (suffix ==
'k' || suffix ==
'K' ||
544 suffix ==
'm' || suffix ==
'M')
546 es = (off_t)atoll(optarg);
566 section_header = g_strdup(optarg);
604 g_critical(
"Need a complete configuration on the command line to output a config file section!");
707 struct addrinfo hints;
708 struct addrinfo *ai = NULL;
709 struct addrinfo *rp = NULL;
710 char host[NI_MAXHOST];
716 err(
"Invalid parsing server");
720 port = g_strdup_printf(
"%d", s->
port);
722 memset(&hints,
'\0',
sizeof(hints));
723 hints.ai_family = AF_UNSPEC;
724 hints.ai_socktype = SOCK_STREAM;
725 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
726 hints.ai_protocol = IPPROTO_TCP;
728 e = getaddrinfo(s->
listenaddr, port, &hints, &ai);
734 for (rp = ai; rp != NULL; rp = rp->ai_next) {
735 e = getnameinfo(rp->ai_addr, rp->ai_addrlen, host,
sizeof(host), NULL, 0, NI_NUMERICHOST);
738 fprintf(stderr,
"getnameinfo: %s\n", gai_strerror(e));
747 g_array_append_val(a, *ns);
755 fprintf(stderr,
"getaddrinfo failed on listen host/address: %s (%s)\n", s->
listenaddr ? s->
listenaddr :
"any", gai_strerror(e));
766 GArray*
parse_cfile(gchar* f,
bool have_global, GError** e);
774 DIR* dirh = opendir(dir);
775 GQuark errdomain = g_quark_from_string(
"do_cfile_dir");
778 GArray* retval = NULL;
783 g_set_error(e, errdomain,
CFILE_DIR_UNKNOWN,
"Invalid directory specified: %s", strerror(errno));
787 while((de = readdir(dirh))) {
788 int saved_errno=errno;
789 fname = g_build_filename(dir, de->d_name, NULL);
795 if(stat(fname, &stbuf)) {
799 if (!S_ISREG(stbuf.st_mode)) {
804 if(strcmp((de->d_name + strlen(de->d_name) - 5),
".conf")) {
813 retval = g_array_new(FALSE, TRUE,
sizeof(
SERVER));
814 retval = g_array_append_vals(retval, tmp->data, tmp->len);
815 g_array_free(tmp, TRUE);
823 g_set_error(e, errdomain,
CFILE_READDIR_ERR,
"Error trying to read directory: %s", strerror(errno));
826 g_array_free(retval, TRUE);
843 const char* DEFAULT_ERROR =
"Could not parse %s in group %s: %s";
844 const char* MISSING_REQUIRED_ERROR =
"Could not find required value %s in group %s: %s";
847 gchar *virtstyle=NULL;
871 const int lp_size=
sizeof(lp)/
sizeof(
PARAM);
882 int p_size=
sizeof(gp)/
sizeof(
PARAM);
885 const char *err_msg=NULL;
897 errdomain = g_quark_from_string(
"parse_cfile");
898 cfile = g_key_file_new();
899 retval = g_array_new(FALSE, TRUE,
sizeof(
SERVER));
900 if(!g_key_file_load_from_file(cfile, f, G_KEY_FILE_KEEP_COMMENTS |
901 G_KEY_FILE_KEEP_TRANSLATIONS, &err)) {
902 g_set_error(e, errdomain,
CFILE_NOTFOUND,
"Could not open config file %s.", f);
903 g_key_file_free(cfile);
906 startgroup = g_key_file_get_start_group(cfile);
907 if((!startgroup || strcmp(startgroup,
"generic")) && have_global) {
908 g_set_error(e, errdomain,
CFILE_MISSING_GENERIC,
"Config file does not contain the [generic] group!");
909 g_key_file_free(cfile);
912 groups = g_key_file_get_groups(cfile, NULL);
913 for(i=0;groups[i];i++) {
914 memset(&s,
'\0',
sizeof(
SERVER));
918 if(i==1 || !have_global) {
925 for(j=0;j<p_size;j++) {
926 assert(p[j].target != NULL);
927 assert(p[j].ptype==PARAM_INT||p[j].ptype==PARAM_STRING||p[j].ptype==PARAM_BOOL||p[j].ptype==
PARAM_INT64);
930 ival = g_key_file_get_integer(cfile,
935 *((gint*)p[j].target) = ival;
939 i64val = g_key_file_get_int64(cfile,
944 *((gint64*)p[j].target) = i64val;
948 sval = g_key_file_get_string(cfile,
953 *((gchar**)p[j].target) = sval;
957 bval = g_key_file_get_boolean(cfile,
959 p[j].paramname, &err);
962 *((gint*)p[j].target) |= p[j].
flagval;
964 *((gint*)p[j].target) &= ~(p[j].
flagval);
970 if(err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
976 err_msg = MISSING_REQUIRED_ERROR;
979 err_msg = DEFAULT_ERROR;
981 g_set_error(e, errdomain,
CFILE_VALUE_INVALID, err_msg, p[j].paramname, groups[i], err->message);
982 g_array_free(retval, TRUE);
984 g_key_file_free(cfile);
989 if(!strncmp(virtstyle,
"none", 4)) {
991 }
else if(!strncmp(virtstyle,
"ipliteral", 9)) {
993 }
else if(!strncmp(virtstyle,
"iphash", 6)) {
995 }
else if(!strncmp(virtstyle,
"cidrhash", 8)) {
997 if(strlen(virtstyle)<10) {
998 g_set_error(e, errdomain,
CFILE_VALUE_INVALID,
"Invalid value %s for parameter virtstyle in group %s: missing length", virtstyle, groups[i]);
999 g_array_free(retval, TRUE);
1000 g_key_file_free(cfile);
1003 s.
cidrlen=strtol(virtstyle+8, NULL, 0);
1005 g_set_error(e, errdomain,
CFILE_VALUE_INVALID,
"Invalid value %s for parameter virtstyle in group %s", virtstyle, groups[i]);
1006 g_array_free(retval, TRUE);
1007 g_key_file_free(cfile);
1014 g_warning(
"A port was specified, but oldstyle exports were not requested. This may not do what you expect.");
1015 g_warning(
"Please read 'man 5 nbd-server' and search for oldstyle for more info");
1020 if(i>0 || !have_global) {
1028 g_set_error(e, errdomain,
CFILE_VALUE_UNSUPPORTED,
"This nbd-server was built without support for SDP, yet group %s uses it", groups[i]);
1029 g_array_free(retval, TRUE);
1030 g_key_file_free(cfile);
1035 g_key_file_free(cfile);
1039 retval = g_array_append_vals(retval, extra->data, extra->len);
1041 g_array_free(extra, TRUE);
1044 g_array_free(retval, TRUE);
1049 if(i==1 && have_global) {
1050 g_set_error(e, errdomain,
CFILE_NO_EXPORTS,
"The config file does not specify any exports");
1065 while((pid=waitpid(-1, &status, WNOHANG)) > 0) {
1066 if(WIFEXITED(status)) {
1067 msg3(LOG_INFO,
"Child exited with %d", WEXITSTATUS(status));
1069 i=g_hash_table_lookup(
children, &pid);
1071 msg3(LOG_INFO,
"SIGCHLD received for an unknown child with PID %ld", (
long)pid);
1073 DEBUG(
"Removing %d from the list of children", pid);
1074 g_hash_table_remove(
children, &pid);
1087 void killchild(gpointer key, gpointer value, gpointer user_data) {
1089 int *parent=user_data;
1091 kill(*pid, SIGTERM);
1122 struct stat stat_buf;
1125 #ifdef HAVE_SYS_MOUNT_H
1126 #ifdef HAVE_SYS_IOCTL_H
1128 DEBUG(
"looking for export size with ioctl BLKGETSIZE64\n");
1129 if (!ioctl(fhandle, BLKGETSIZE64, &bytes) && bytes) {
1130 return (off_t)bytes;
1136 DEBUG(
"looking for fhandle size with fstat\n");
1137 stat_buf.st_size = 0;
1138 error = fstat(fhandle, &stat_buf);
1142 if (S_ISREG(stat_buf.st_mode) || (stat_buf.st_size > 0))
1143 return (off_t)stat_buf.st_size;
1145 err(
"fstat failed: %m");
1148 DEBUG(
"looking for fhandle size with lseek SEEK_END\n");
1149 es = lseek(fhandle, (off_t)0, SEEK_END);
1150 if (es > ((off_t)0)) {
1153 DEBUG(
"lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
1156 err(
"Could not find size of exported block device: %m");
1171 int get_filepos(GArray* export, off_t a,
int* fhandle, off_t* foffset,
size_t* maxbytes ) {
1179 int end = export->len - 1;
1180 while( start <= end ) {
1181 int mid = (start + end) / 2;
1182 fi = g_array_index(export,
FILE_INFO, mid);
1196 fi = g_array_index(export,
FILE_INFO, end);
1200 if( end+1 < export->len ) {
1217 if (lseek(handle, a, SEEK_SET) < 0) {
1218 err(
"Can not seek locally!\n");
1241 if(maxbytes && len > maxbytes)
1244 DEBUG(
"(WRITE to fd %d offset %llu len %u fua %d), ", fhandle, (
long long unsigned)foffset, (
unsigned int)len, fua);
1246 myseek(fhandle, foffset);
1247 retval = write(fhandle, buf, len);
1283 sync_file_range(fhandle, foffset, len,
1284 SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE |
1285 SYNC_FILE_RANGE_WAIT_AFTER);
1306 while(len > 0 && (ret=
rawexpwrite(a, buf, len, client, fua)) > 0 ) {
1311 return (ret < 0 || len != 0);
1332 if(maxbytes && len > maxbytes)
1335 DEBUG(
"(READ from fd %d offset %llu len %u), ", fhandle, (
long long unsigned int)foffset, (
unsigned int)len);
1337 myseek(fhandle, foffset);
1338 return read(fhandle, buf, len);
1348 while(len > 0 && (ret=
rawexpread(a, buf, len, client)) > 0 ) {
1353 return (ret < 0 || len != 0);
1367 off_t rdlen, offset;
1368 off_t mapcnt, mapl, maph, pagestart;
1372 DEBUG(
"Asked to read %u bytes at %llu.\n", (
unsigned int)len, (
unsigned long long)a);
1376 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1379 rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1380 len : (
size_t)DIFFPAGESIZE-offset;
1381 if (client->
difmap[mapcnt]!=(u32)(-1)) {
1382 DEBUG(
"Page %llu is at %lu\n", (
unsigned long long)mapcnt,
1383 (
unsigned long)(client->
difmap[mapcnt]));
1385 if (read(client->
difffile, buf, rdlen) != rdlen)
return -1;
1387 DEBUG(
"Page %llu is not here, we read the original one\n",
1388 (
unsigned long long)mapcnt);
1391 len-=rdlen; a+=rdlen; buf+=rdlen;
1410 off_t mapcnt,mapl,maph;
1417 DEBUG(
"Asked to write %u bytes at %llu.\n", (
unsigned int)len, (
unsigned long long)a);
1421 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1423 offset=a-pagestart ;
1424 wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1425 len : (
size_t)DIFFPAGESIZE-offset;
1427 if (client->
difmap[mapcnt]!=(u32)(-1)) {
1428 DEBUG(
"Page %llu is at %lu\n", (
unsigned long long)mapcnt,
1429 (
unsigned long)(client->
difmap[mapcnt])) ;
1431 client->
difmap[mapcnt]*DIFFPAGESIZE+offset);
1432 if (write(client->
difffile, buf, wrlen) != wrlen)
return -1 ;
1436 DEBUG(
"Page %llu is not here, we put it at %lu\n",
1437 (
unsigned long long)mapcnt,
1438 (
unsigned long)(client->
difmap[mapcnt]));
1442 memcpy(pagebuf+offset,buf,wrlen) ;
1443 if (write(client->
difffile, pagebuf, DIFFPAGESIZE) !=
1447 len-=wrlen ; a+=wrlen ; buf+=wrlen ;
1473 for (i = 0; i < client->
export->len; i++) {
1494 if(i<client->export->len) {
1500 fallocate(prev.
fhandle, FALLOC_FL_PUNCH_HOLE, curoff, curlen);
1503 }
while(i < client->export->len && cur.
startoff < (req->
from + req->
len));
1504 DEBUG(
"Performed TRIM request from %llu to %llu", (
unsigned long long) req->
from, (
unsigned long long) req->
len);
1506 DEBUG(
"Ignoring TRIM request (not supported on current platform");
1511 static void send_reply(uint32_t opt,
int net, uint32_t reply_type,
size_t datasize,
void* data) {
1513 reply_type = htonl(reply_type);
1514 uint32_t datsize = htonl(datasize);
1515 struct iovec v_data[] = {
1517 { &opt,
sizeof(opt) },
1518 { &reply_type,
sizeof(reply_type) },
1519 { &datsize,
sizeof(datsize) },
1522 writev(net, v_data, 5);
1530 if (read(net, &namelen,
sizeof(namelen)) < 0)
1531 err(
"Negotiation failed/7: %m");
1532 namelen = ntohl(namelen);
1533 name = malloc(namelen+1);
1535 if (read(net, name, namelen) < 0)
1536 err(
"Negotiation failed/8: %m");
1537 for(i=0; i<servers->len; i++) {
1555 static void handle_list(uint32_t opt,
int net, GArray* servers, uint32_t cflags) {
1559 char *ptr = buf +
sizeof(
len);
1561 if (read(net, &len,
sizeof(len)) < 0)
1562 err(
"Negotiation failed/8: %m");
1572 for(i=0; i<servers->len; i++) {
1575 memcpy(buf, &len,
sizeof(len));
1591 uint16_t smallflags = 0;
1594 memset(zeros,
'\0',
sizeof(zeros));
1596 if(phase & NEG_MODERN) {
1599 if(phase & NEG_INIT) {
1606 if(phase & NEG_MODERN) {
1613 if (write(net, &magic,
sizeof(magic)) < 0) {
1619 if ((phase & NEG_MODERN) && (phase & NEG_INIT)) {
1625 err(
"programmer error");
1626 smallflags = htons(smallflags);
1627 if (write(net, &smallflags,
sizeof(uint16_t)) < 0)
1629 if (read(net, &cflags,
sizeof(cflags)) < 0)
1631 cflags = htonl(cflags);
1633 if (read(net, &magic,
sizeof(magic)) < 0)
1640 if (read(net, &opt,
sizeof(opt)) < 0)
1668 if (write(net, &size_host, 8) < 0)
1669 err(
"Negotiation failed/9: %m");
1682 flags = htonl(flags);
1683 if (write(client->
net, &flags, 4) < 0)
1684 err(
"Negotiation failed/10: %m");
1687 smallflags = (uint16_t)(flags & ~((uint16_t)0));
1688 smallflags = htons(smallflags);
1689 if (write(client->
net, &smallflags,
sizeof(smallflags)) < 0) {
1690 err(
"Negotiation failed/11: %m");
1694 if (write(client->
net, zeros, 124) < 0)
1695 err(
"Negotiation failed/12: %m");
1700 #define SEND(net,reply) { writeit( net, &reply, sizeof( reply )); \
1701 if (client->transactionlogfd != -1) \
1702 writeit(client->transactionlogfd, &reply, sizeof(reply)); }
1704 #define ERROR(client,reply,errcode) { reply.error = htonl(errcode); SEND(client->net,reply); reply.error = 0; }
1717 gboolean go_on=TRUE;
1722 DEBUG(
"Entering request loop!\n");
1736 readit(client->
net, &request,
sizeof(request));
1741 request.
type = ntohl(request.
type);
1743 len = ntohl(request.
len);
1746 (
unsigned long long)request.
from,
1747 (
unsigned long long)request.
from / 512, (
unsigned int)len);
1750 err(
"Not enough magic.");
1756 DEBUG(
"[Number too large!]");
1757 ERROR(client, reply, EINVAL);
1761 if (((ssize_t)((off_t)request.
from + len) > client->
exportsize)) {
1763 ERROR(client, reply, EINVAL);
1771 msg2(LOG_DEBUG,
"oversized request (this is not a problem)");
1780 msg2(LOG_INFO,
"Disconnect request received.");
1791 DEBUG(
"wr: net->buf, ");
1794 DEBUG(
"buf->exp, ");
1797 DEBUG(
"[WRITE to READONLY!]");
1798 ERROR(client, reply, EPERM);
1804 DEBUG(
"Write failed: %m" );
1805 ERROR(client, reply, errno);
1810 request.
from += currlen;
1820 DEBUG(
"Flush failed: %m");
1821 ERROR(client, reply, errno);
1829 DEBUG(
"exp->buf, ");
1830 memcpy(buf, &reply,
sizeof(
struct nbd_reply));
1834 writelen = currlen +
sizeof(
struct nbd_reply);
1837 DEBUG(
"Read failed: %m");
1838 ERROR(client, reply, errno);
1842 DEBUG(
"buf->net, ");
1845 request.
from += currlen;
1856 if (
exptrim(&request, client)) {
1857 DEBUG(
"Trim failed: %m");
1858 ERROR(client, reply, errno);
1865 DEBUG (
"Ignoring unknown command\n");
1879 off_t laststartoff = 0, lastsize = 0;
1892 gchar* error_string;
1898 O_RDONLY : (O_RDWR | (cancreate?O_CREAT:0));
1901 tmpname=g_strdup_printf(
"%s.%d-XXXXXX", client->
exportname, i);
1902 DEBUG(
"Opening %s\n", tmpname );
1903 fi.
fhandle = mkstemp(tmpname);
1906 tmpname=g_strdup_printf(
"%s.%d", client->
exportname, i);
1910 DEBUG(
"Opening %s\n", tmpname );
1911 fi.
fhandle = open(tmpname, mode, 0x600);
1912 if(fi.
fhandle == -1 && mode == O_RDWR) {
1914 fi.
fhandle = open(tmpname, O_RDONLY);
1926 if(multifile && i>0)
1928 error_string=g_strdup_printf(
1929 "Could not open exported file %s: %%m",
1937 fi.
startoff = laststartoff + lastsize;
1938 g_array_append_val(client->
export, fi);
1947 if (!lastsize && cancreate) {
1950 err(
"Could not expand file: %m");
1956 if(!multifile || temporary)
1961 client->
exportsize = laststartoff + lastsize;
1967 err(
"Size of exported file is too big\n");
1973 msg3(LOG_INFO,
"Size of exported file/device is %llu", (
unsigned long long)client->
exportsize);
1975 msg3(LOG_INFO,
"Total number of files: %d", i);
1982 err(
"Failed to allocate string for diff file name");
1986 msg3(LOG_INFO,
"About to create map and diff file %s",client->
difffilename) ;
1988 if (client->
difffile<0)
err(
"Could not create diff file (%m)") ;
1990 err(
"Could not allocate memory") ;
2007 if(command && *command) {
2008 cmd = g_strdup_printf(command, file);
2028 S_IRUSR | S_IWUSR)))
2029 g_warning(
"Could not open transaction log %s",
2066 struct sockaddr_storage addrin;
2067 struct sockaddr_storage netaddr;
2068 struct sockaddr_in *netaddr4 = NULL;
2069 struct sockaddr_in6 *netaddr6 = NULL;
2070 socklen_t addrinlen =
sizeof( addrin );
2071 struct addrinfo hints;
2072 struct addrinfo *ai = NULL;
2073 char peername[NI_MAXHOST];
2074 char netname[NI_MAXHOST];
2080 if (getpeername(net, (
struct sockaddr *) &addrin, &addrinlen) < 0)
2081 err(
"getpeername failed: %m");
2083 if((e = getnameinfo((
struct sockaddr *)&addrin, addrinlen,
2084 peername,
sizeof (peername), NULL, 0, NI_NUMERICHOST))) {
2085 msg3(LOG_INFO,
"getnameinfo failed: %s", gai_strerror(e));
2089 memset(&hints,
'\0',
sizeof (hints));
2090 hints.ai_flags = AI_ADDRCONFIG;
2091 e = getaddrinfo(peername, NULL, &hints, &ai);
2094 msg3(LOG_INFO,
"getaddrinfo failed: %s", gai_strerror(e));
2104 for(i=0;i<strlen(peername);i++) {
2105 if(peername[i]==
'.') {
2113 memcpy(&netaddr, &addrin, addrinlen);
2114 if(ai->ai_family == AF_INET) {
2115 netaddr4 = (
struct sockaddr_in *)&netaddr;
2119 getnameinfo((
struct sockaddr *) netaddr4, addrinlen,
2120 netname,
sizeof (netname), NULL, 0, NI_NUMERICHOST);
2121 tmp=g_strdup_printf(
"%s/%s", netname, peername);
2122 }
else if(ai->ai_family == AF_INET6) {
2123 netaddr6 = (
struct sockaddr_in6 *)&netaddr;
2128 ((netaddr6->sin6_addr).s6_addr[i])=0;
2132 (netaddr6->sin6_addr).s6_addr[i]>>=shift;
2133 (netaddr6->sin6_addr).s6_addr[i]<<=shift;
2135 getnameinfo((
struct sockaddr *)netaddr6, addrinlen,
2136 netname,
sizeof(netname), NULL, 0, NI_NUMERICHOST);
2137 tmp=g_strdup_printf(
"%s/%s", netname, peername);
2147 msg4(LOG_INFO,
"connect from %s, assigned file is %s",
2164 struct sockaddr_storage addrin;
2165 socklen_t addrinlen=
sizeof(addrin);
2181 for(i=0;i<servers->len;i++) {
2182 if((sock=(g_array_index(servers,
SERVER, i)).socket)) {
2183 FD_SET(sock, &mset);
2184 max=sock>max?sock:max;
2195 memcpy(&rset, &mset,
sizeof(fd_set));
2196 if(select(max+1, &rset, NULL, NULL, NULL)>0) {
2202 if((net=accept(
modernsock, (
struct sockaddr *) &addrin, &addrinlen)) < 0)
2213 for(i=0;i<servers->len && !net;i++) {
2214 serve=&(g_array_index(servers,
SERVER, i));
2215 if(FD_ISSET(serve->
socket, &rset)) {
2216 if ((net=accept(serve->
socket, (
struct sockaddr *) &addrin, &addrinlen)) < 0)
2225 msg2(LOG_INFO,
"Max connections reached");
2229 if((sock_flags = fcntl(net, F_GETFL, 0))==-1) {
2230 err(
"fcntl F_GETFL");
2232 if(fcntl(net, F_SETFL, sock_flags &~O_NONBLOCK)==-1) {
2233 err(
"fcntl F_SETFL ~O_NONBLOCK");
2236 client = g_new0(
CLIENT, 1);
2244 msg2(LOG_INFO,
"Unauthorized client") ;
2248 msg2(LOG_INFO,
"Authorized client") ;
2249 pid=g_malloc(
sizeof(pid_t));
2252 if ((*pid=fork())<0) {
2253 msg3(LOG_INFO,
"Could not fork (%s)",strerror(errno)) ;
2259 g_hash_table_insert(
children, pid, pid);
2264 for(i=0;i<servers->len;i++) {
2265 serve=&g_array_index(servers,
SERVER, i);
2274 g_array_free(servers, FALSE);
2277 msg2(LOG_INFO,
"Starting to serve");
2296 if (setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,
sizeof(
int)) == -1) {
2297 err(
"setsockopt SO_REUSEADDR");
2301 if (setsockopt(socket,SOL_SOCKET,SO_LINGER,&l,
sizeof(l)) == -1) {
2302 perror(
"setsockopt SO_LINGER");
2305 if (setsockopt(socket,SOL_SOCKET,SO_KEEPALIVE,&yes,
sizeof(
int)) == -1) {
2306 err(
"setsockopt SO_KEEPALIVE");
2324 struct addrinfo hints;
2325 struct addrinfo *ai = NULL;
2332 memset(&hints,
'\0',
sizeof(hints));
2333 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV;
2334 hints.ai_socktype = SOCK_STREAM;
2337 port = g_strdup_printf (
"%d", serve->
port);
2341 e = getaddrinfo(serve->
listenaddr,port,&hints,&ai);
2346 fprintf(stderr,
"getaddrinfo failed: %s\n", gai_strerror(e));
2357 if (ai->ai_family == AF_INET)
2358 ai->ai_family = AF_INET_SDP;
2359 else (ai->ai_family == AF_INET6)
2360 ai->ai_family = AF_INET6_SDP;
2363 if ((serve->
socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
2368 DEBUG(
"Waiting for connections... bind, ");
2369 e = bind(serve->
socket, ai->ai_addr, ai->ai_addrlen);
2370 if (e != 0 && errno != EADDRINUSE)
2373 if (listen(serve->
socket, 1) < 0)
2385 struct addrinfo hints;
2386 struct addrinfo* ai = NULL;
2390 memset(&hints,
'\0',
sizeof(hints));
2391 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
2392 hints.ai_socktype = SOCK_STREAM;
2393 hints.ai_family = AF_UNSPEC;
2394 hints.ai_protocol = IPPROTO_TCP;
2397 fprintf(stderr,
"getaddrinfo failed: %s\n", gai_strerror(e));
2400 if((
modernsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))<0) {
2406 if(bind(
modernsock, ai->ai_addr, ai->ai_addrlen)) {
2421 struct sigaction sa;
2424 for(i=0;i<servers->len;i++) {
2433 sigemptyset(&sa.sa_mask);
2434 sa.sa_flags = SA_RESTART;
2435 if(sigaction(SIGCHLD, &sa, NULL) == -1)
2436 err(
"sigaction: %m");
2438 sigemptyset(&sa.sa_mask);
2439 sa.sa_flags = SA_RESTART;
2440 if(sigaction(SIGTERM, &sa, NULL) == -1)
2441 err(
"sigaction: %m");
2451 #if !defined(NODAEMON)
2455 if(serve && !(serve->
port)) {
2463 strncpy(
pidftemplate,
"/var/run/nbd-server.%d.pid", 255);
2471 fprintf(pidf,
"%d\n", (
int)getpid());
2475 fprintf(stderr,
"Not fatal; continuing");
2479 #define daemonize(serve)
2490 g_message(
"Export of %s on port %d failed:", serve->
exportname,
2505 str = g_strdup_printf(
"Invalid group name: %s",
rungroup);
2508 if(setgid(gr->gr_gid)<0) {
2509 err(
"Could not set GID: %m");
2515 str = g_strdup_printf(
"Invalid user name: %s",
runuser);
2518 if(setuid(pw->pw_uid)<0) {
2519 err(
"Could not set UID: %m");
2526 GLogLevelFlags log_level,
2527 const gchar *message,
2530 int level=LOG_DEBUG;
2534 case G_LOG_FLAG_FATAL:
2535 case G_LOG_LEVEL_CRITICAL:
2536 case G_LOG_LEVEL_ERROR:
2539 case G_LOG_LEVEL_WARNING:
2542 case G_LOG_LEVEL_MESSAGE:
2543 case G_LOG_LEVEL_INFO:
2546 case G_LOG_LEVEL_DEBUG:
2552 syslog(level,
"%s", message);
2565 fprintf(stderr,
"Bad size of structure. Alignment problems?\n");
2566 exit(EXIT_FAILURE) ;
2581 if (!(serve->
port)) {
2590 open(
"/dev/null", O_WRONLY);
2591 open(
"/dev/null", O_WRONLY);
2594 client=g_malloc(
sizeof(
CLIENT));
2604 if(!servers || !servers->len) {
2605 if(err && !(err->domain == g_quark_from_string(
"parse_cfile")
2607 g_warning(
"Could not parse config file: %s",
2608 err ? err->message :
"Unknown error");
2612 g_warning(
"Specifying an export on the command line is deprecated.");
2613 g_warning(
"Please use a configuration file instead.");
2616 if((!serve) && (!servers||!servers->len)) {
2617 g_message(
"No configured exports; quitting.");