63 #include <sys/types.h>
64 #include <sys/socket.h>
66 #include <sys/select.h>
69 #ifdef HAVE_SYS_IOCTL_H
70 #include <sys/ioctl.h>
72 #include <sys/param.h>
73 #ifdef HAVE_SYS_MOUNT_H
74 #include <sys/mount.h>
79 #include <netinet/tcp.h>
80 #include <netinet/in.h>
90 #include <linux/falloc.h>
92 #include <arpa/inet.h>
105 #define MY_NAME "nbd_server"
111 #include <sdp_inet.h>
116 #define SYSCONFDIR "/etc"
118 #define CFILE SYSCONFDIR "/nbd-server/config"
133 #define OFFT_MAX ~((off_t)1<<(sizeof(off_t)*8-1))
134 #define BUFSIZE ((1024*1024)+sizeof(struct nbd_reply))
135 #define DIFFPAGESIZE 4096
136 #define TREEPAGESIZE 4096
137 #define TREEDIRSIZE 1024
141 #define F_MULTIFILE 2
142 #define F_COPYONWRITE 4
144 #define F_AUTOREADONLY 8
150 #define F_ROTATIONAL 512
151 #define F_TEMPORARY 1024
154 #define F_TREEFILES 8192
159 #define F_NO_ZEROES 4
165 #define NEG_INIT (1 << 0)
166 #define NEG_OLD (1 << 1)
167 #define NEG_MODERN (1 << 2)
254 return "NBD_CMD_READ";
256 return "NBD_CMD_WRITE";
258 return "NBD_CMD_DISC";
260 return "NBD_CMD_FLUSH";
262 return "NBD_CMD_TRIM";
275 static inline void readit(
int f,
void *buf,
size_t len) {
279 if ((res = read(f, buf, len)) <= 0) {
280 if(errno != EAGAIN) {
281 err(
"Read failed: %m");
298 static inline void consume(
int f,
void * buf,
size_t len,
size_t bufsiz) {
301 curlen = (len>bufsiz)?bufsiz:len;
318 if ((res = write(f, buf, len)) <= 0)
319 err(
"Send failed: %m");
331 static void construct_path(
char* name,
int lenmax,off_t size, off_t pos, off_t * ppos) {
333 err(
"Char buffer overflow. This is likely a bug.");
337 snprintf(name,lenmax,
"/FILE%04X",(pos/TREEPAGESIZE) %
TREEDIRSIZE);
342 snprintf(buffer,
sizeof(buffer),
"/TREE%04X",*ppos %
TREEDIRSIZE);
343 memcpy(name,buffer,9);
349 char *subpath=path+1;
350 while (subpath=strchr(subpath,
'/')) {
352 if (mkdir(path,0700)==-1) {
354 err(
"Path access error! %m");
362 char filename[256+strlen(name)];
363 strcpy(filename,name);
367 DEBUG(
"Accessing treefile %s ( offset %llu of %llu)",filename,(
unsigned long long)pos,(
unsigned long long)size);
369 int handle=open(filename, mode, 0600);
370 if (handle<0 && errno==ENOENT) {
373 DEBUG(
"Creating new treepath");
376 handle=open(filename, O_RDWR|O_CREAT, 0600);
378 err(
"Error opening tree block file %m");
382 DEBUG(
"Creating a dummy tempfile for reading");
384 tmpname = g_strdup_printf(
"dummy-XXXXXX");
385 handle = mkstemp(tmpname);
389 err(
"Error opening tree block file %m");
395 ssize_t c = write(handle,n,1);
397 err(
"Error setting tree block file size %m");
404 char filename[256+strlen(name)];
405 strcpy(filename,name);
410 DEBUG(
"Deleting treefile: %s",filename);
412 if (unlink(filename)==-1)
413 DEBUG(
"Deleting failed : %s",strerror(errno));
422 printf(
"This is nbd-server version " VERSION "\n");
423 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] [-V]\n"
424 "\t-r|--read-only\t\tread only\n"
425 "\t-m|--multi-file\t\tmultiple file\n"
426 "\t-c|--copy-on-write\tcopy on write\n"
427 "\t-C|--config-file\tspecify an alternate configuration file\n"
428 "\t-l|--authorize-file\tfile with list of hosts that are allowed to\n\t\t\t\tconnect.\n"
429 "\t-p|--pid-file\t\tspecify a filename to write our PID to\n"
430 "\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"
431 "\t-M|--max-connections\tspecify the maximum number of opened connections\n"
432 "\t-V|--version\toutput the version and exit\n\n"
433 "\tif port is set to 0, stdin is used (for running from inetd).\n"
434 "\tif file_to_export contains '%%s', it is substituted with the IP\n"
435 "\t\taddress of the machine trying to connect\n"
436 "\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");
437 printf(
"Using configuration file %s\n",
CFILE);
442 printf(
"[%s]\n", section_header);
443 printf(
"\texportname = %s\n", serve->
exportname);
444 printf(
"\tlistenaddr = %s\n", serve->
listenaddr);
445 printf(
"\tport = %d\n", serve->
port);
447 printf(
"\treadonly = true\n");
450 printf(
"\tmultifile = true\n");
453 printf(
"\ttreefiles = true\n");
456 printf(
"\tcopyonwrite = true\n");
459 printf(
"\tfilesize = %lld\n", (
long long int)serve->
expected_size);
462 printf(
"\tauthfile = %s\n", serve->
authname);
477 struct option long_options[] = {
478 {
"read-only", no_argument, NULL,
'r'},
479 {
"multi-file", no_argument, NULL,
'm'},
480 {
"copy-on-write", no_argument, NULL,
'c'},
481 {
"dont-fork", no_argument, NULL,
'd'},
482 {
"authorize-file", required_argument, NULL,
'l'},
483 {
"config-file", required_argument, NULL,
'C'},
484 {
"pid-file", required_argument, NULL,
'p'},
485 {
"output-config", required_argument, NULL,
'o'},
486 {
"max-connection", required_argument, NULL,
'M'},
487 {
"version", no_argument, NULL,
'V'},
494 gboolean do_output=FALSE;
495 gchar* section_header=
"";
504 while((c=getopt_long(argc, argv,
"-C:cdl:mo:rp:M:V", long_options, &i))>=0) {
508 switch(nonspecial++) {
510 if(strchr(optarg,
':') == strrchr(optarg,
':')) {
511 addr_port=g_strsplit(optarg,
":", 2);
516 g_strfreev(addr_port);
517 addr_port=g_strsplit(optarg,
"@", 2);
520 addr_port=g_strsplit(optarg,
"@", 2);
524 serve->
port=strtol(addr_port[1], NULL, 0);
528 serve->
port=strtol(addr_port[0], NULL, 0);
530 g_strfreev(addr_port);
535 fprintf(stderr,
"E: The to be exported file needs to be an absolute filename!\n");
540 last=strlen(optarg)-1;
542 if (suffix ==
'k' || suffix ==
'K' ||
543 suffix ==
'm' || suffix ==
'M')
545 es = (off_t)atoll(optarg);
565 section_header = g_strdup(optarg);
589 printf(
"This is nbd-server version " VERSION "\n");
608 g_critical(
"Need a complete configuration on the command line to output a config file section!");
619 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
620 #define NBD_D_TYPE de->d_type
633 DIR* dirh = opendir(dir);
636 GArray* retval = NULL;
645 while((de = readdir(dirh))) {
646 int saved_errno=errno;
647 fname = g_build_filename(dir, de->d_name, NULL);
653 if(stat(fname, &stbuf)) {
657 if (!S_ISREG(stbuf.st_mode)) {
662 if(strcmp((de->d_name + strlen(de->d_name) - 5),
".conf")) {
671 retval = g_array_new(FALSE, TRUE,
sizeof(
SERVER));
672 retval = g_array_append_vals(retval, tmp->data, tmp->len);
673 g_array_free(tmp, TRUE);
684 g_array_free(retval, TRUE);
714 const char* DEFAULT_ERROR =
"Could not parse %s in group %s: %s";
715 const char* MISSING_REQUIRED_ERROR =
"Could not find required value %s in group %s: %s";
718 gchar *virtstyle=NULL;
743 const int lp_size=
sizeof(lp)/
sizeof(
PARAM);
756 int p_size=
sizeof(gp)/
sizeof(
PARAM);
759 const char *err_msg=NULL;
776 memcpy(&genconftmp, genconf,
sizeof(
struct generic_conf));
779 cfile = g_key_file_new();
780 retval = g_array_new(FALSE, TRUE,
sizeof(
SERVER));
781 if(!g_key_file_load_from_file(cfile, f, G_KEY_FILE_KEEP_COMMENTS |
782 G_KEY_FILE_KEEP_TRANSLATIONS, &err)) {
785 g_key_file_free(cfile);
788 startgroup = g_key_file_get_start_group(cfile);
789 if((!startgroup || strcmp(startgroup,
"generic")) && expect_generic) {
791 g_key_file_free(cfile);
794 groups = g_key_file_get_groups(cfile, NULL);
795 for(i=0;groups[i];i++) {
796 memset(&s,
'\0',
sizeof(
SERVER));
800 if(i==1 || !expect_generic) {
804 for(j=0;j<p_size;j++) {
805 assert(p[j].target != NULL);
806 assert(p[j].ptype==PARAM_INT||p[j].ptype==PARAM_STRING||p[j].ptype==PARAM_BOOL||p[j].ptype==
PARAM_INT64);
809 ival = g_key_file_get_integer(cfile,
814 *((gint*)p[j].target) = ival;
818 i64val = g_key_file_get_int64(cfile,
823 *((gint64*)p[j].target) = i64val;
827 sval = g_key_file_get_string(cfile,
832 *((gchar**)p[j].target) = sval;
836 bval = g_key_file_get_boolean(cfile,
838 p[j].paramname, &err);
841 *((gint*)p[j].target) |= p[j].flagval;
843 *((gint*)p[j].target) &= ~(p[j].flagval);
849 if(err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
855 err_msg = MISSING_REQUIRED_ERROR;
858 err_msg = DEFAULT_ERROR;
861 g_array_free(retval, TRUE);
863 g_key_file_free(cfile);
868 if(!strncmp(virtstyle,
"none", 4)) {
870 }
else if(!strncmp(virtstyle,
"ipliteral", 9)) {
872 }
else if(!strncmp(virtstyle,
"iphash", 6)) {
874 }
else if(!strncmp(virtstyle,
"cidrhash", 8)) {
876 if(strlen(virtstyle)<10) {
878 g_array_free(retval, TRUE);
879 g_key_file_free(cfile);
882 s.
cidrlen=strtol(virtstyle+8, NULL, 0);
885 g_array_free(retval, TRUE);
886 g_key_file_free(cfile);
893 g_message(
"Since 3.10, the oldstyle protocol is no longer supported. Please migrate to the newstyle protocol.");
894 g_message(
"Exiting.");
900 if(i>0 || !expect_generic) {
909 g_array_free(retval, TRUE);
910 g_key_file_free(cfile);
915 g_key_file_free(cfile);
919 retval = g_array_append_vals(retval, extra->data, extra->len);
921 g_array_free(extra, TRUE);
924 g_array_free(retval, TRUE);
929 if(i==1 && expect_generic) {
936 memcpy(genconf, &genconftmp,
sizeof(
struct generic_conf));
963 void killchild(gpointer key, gpointer value, gpointer user_data) {
1008 GArray *
const export = client->
export;
1025 int end = export->len - 1;
1026 while( start <= end ) {
1027 int mid = (start + end) / 2;
1028 fi = g_array_index(export,
FILE_INFO, mid);
1042 fi = g_array_index(export,
FILE_INFO, end);
1046 if( end+1 < export->len ) {
1061 if (lseek(handle, a, SEEK_SET) < 0) {
1062 err(
"Can not seek locally!\n");
1083 if(
get_filepos(client, a, &fhandle, &foffset, &maxbytes))
1085 if(maxbytes && len > maxbytes)
1088 DEBUG(
"(WRITE to fd %d offset %llu len %u fua %d), ", fhandle, (
long long unsigned)foffset, (
unsigned int)len, fua);
1090 myseek(fhandle, foffset);
1091 retval = write(fhandle, buf, len);
1127 sync_file_range(fhandle, foffset, len,
1128 SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE |
1129 SYNC_FILE_RANGE_WAIT_AFTER);
1154 while(len > 0 && (ret=
rawexpwrite(a, buf, len, client, fua)) > 0 ) {
1159 return (ret < 0 || len != 0);
1179 if(
get_filepos(client, a, &fhandle, &foffset, &maxbytes))
1181 if(maxbytes && len > maxbytes)
1184 DEBUG(
"(READ from fd %d offset %llu len %u), ", fhandle, (
long long unsigned int)foffset, (
unsigned int)len);
1186 myseek(fhandle, foffset);
1187 retval = read(fhandle, buf, len);
1201 while(len > 0 && (ret=
rawexpread(a, buf, len, client)) > 0 ) {
1206 return (ret < 0 || len != 0);
1220 off_t rdlen, offset;
1221 off_t mapcnt, mapl, maph, pagestart;
1225 DEBUG(
"Asked to read %u bytes at %llu.\n", (
unsigned int)len, (
unsigned long long)a);
1229 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1232 rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1233 len : (
size_t)DIFFPAGESIZE-offset;
1234 if (client->
difmap[mapcnt]!=(u32)(-1)) {
1235 DEBUG(
"Page %llu is at %lu\n", (
unsigned long long)mapcnt,
1236 (
unsigned long)(client->
difmap[mapcnt]));
1238 if (read(client->
difffile, buf, rdlen) != rdlen)
return -1;
1240 DEBUG(
"Page %llu is not here, we read the original one\n",
1241 (
unsigned long long)mapcnt);
1244 len-=rdlen; a+=rdlen; buf+=rdlen;
1263 off_t mapcnt,mapl,maph;
1270 DEBUG(
"Asked to write %u bytes at %llu.\n", (
unsigned int)len, (
unsigned long long)a);
1274 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1276 offset=a-pagestart ;
1277 wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1278 len : (
size_t)DIFFPAGESIZE-offset;
1280 if (client->
difmap[mapcnt]!=(u32)(-1)) {
1281 DEBUG(
"Page %llu is at %lu\n", (
unsigned long long)mapcnt,
1282 (
unsigned long)(client->
difmap[mapcnt])) ;
1284 client->
difmap[mapcnt]*DIFFPAGESIZE+offset);
1285 if (write(client->
difffile, buf, wrlen) != wrlen)
return -1 ;
1289 DEBUG(
"Page %llu is not here, we put it at %lu\n",
1290 (
unsigned long long)mapcnt,
1291 (
unsigned long)(client->
difmap[mapcnt]));
1295 memcpy(pagebuf+offset,buf,wrlen) ;
1296 if (write(client->
difffile, pagebuf, DIFFPAGESIZE) !=
1300 len-=wrlen ; a+=wrlen ; buf+=wrlen ;
1334 for (i = 0; i < client->
export->len; i++) {
1358 DEBUG(
"Performed TRIM request on TREE structure from %llu to %llu", (
unsigned long long) req->
from, (
unsigned long long) req->
len);
1368 if(i<client->export->len) {
1374 fallocate(prev.
fhandle, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, curoff, curlen);
1377 }
while(i < client->export->len && cur.
startoff < (req->
from + req->
len));
1378 DEBUG(
"Performed TRIM request from %llu to %llu", (
unsigned long long) req->
from, (
unsigned long long) req->
len);
1380 DEBUG(
"Ignoring TRIM request (not supported on current platform");
1385 static void send_reply(uint32_t opt,
int net, uint32_t reply_type,
size_t datasize,
void* data) {
1387 reply_type = htonl(reply_type);
1388 uint32_t datsize = htonl(datasize);
1390 struct iovec v_data[] = {
1392 { &opt,
sizeof(opt) },
1393 { &reply_type,
sizeof(reply_type) },
1394 { &datsize,
sizeof(datsize) },
1397 size_t total =
sizeof(
magic) +
sizeof(opt) +
sizeof(reply_type) +
sizeof(datsize) + datasize;
1398 ssize_t sent = writev(net, v_data, 5);
1400 perror(
"E: couldn't write enough data:");
1409 if (read(net, &namelen,
sizeof(namelen)) < 0) {
1410 err(
"Negotiation failed/7: %m");
1413 namelen = ntohl(namelen);
1414 name = malloc(namelen+1);
1416 if (read(net, name, namelen) < 0) {
1417 err(
"Negotiation failed/8: %m");
1421 for(i=0; i<servers->len; i++) {
1435 err(
"Negotiation failed/8a: Requested export not found");
1440 static void handle_list(uint32_t opt,
int net, GArray* servers, uint32_t cflags) {
1444 char *ptr = buf +
sizeof(
len);
1446 if (read(net, &len,
sizeof(len)) < 0)
1447 err(
"Negotiation failed/8: %m");
1457 for(i=0; i<servers->len; i++) {
1460 memcpy(buf, &len,
sizeof(len));
1476 uint32_t cflags = 0;
1479 assert(servers != NULL);
1483 if (write(net, &magic,
sizeof(magic)) < 0)
1486 smallflags = htons(smallflags);
1487 if (write(net, &smallflags,
sizeof(uint16_t)) < 0)
1489 if (read(net, &cflags,
sizeof(cflags)) < 0)
1491 cflags = htonl(cflags);
1496 if (read(net, &magic,
sizeof(magic)) < 0)
1503 if (read(net, &opt,
sizeof(opt)) < 0)
1535 if (write(client->
net, &size_host, 8) < 0)
1536 err(
"Negotiation failed/9: %m");
1547 flags = htons(flags);
1548 if (write(client->
net, &flags,
sizeof(flags)) < 0)
1549 err(
"Negotiation failed/11: %m");
1552 memset(zeros,
'\0',
sizeof(zeros));
1553 if (write(client->
net, zeros, 124) < 0)
1554 err(
"Negotiation failed/12: %m");
1580 #define SEND(net,reply) { writeit( net, &reply, sizeof( reply )); \
1581 if (client->transactionlogfd != -1) \
1582 writeit(client->transactionlogfd, &reply, sizeof(reply)); }
1584 #define ERROR(client,reply,errcode) { reply.error = nbd_errno(errcode); SEND(client->net,reply); reply.error = 0; }
1597 gboolean go_on=TRUE;
1602 DEBUG(
"Entering request loop!\n");
1616 readit(client->
net, &request,
sizeof(request));
1621 request.
type = ntohl(request.
type);
1623 len = ntohl(request.
len);
1626 (
unsigned long long)request.
from,
1627 (
unsigned long long)request.
from / 512, len);
1630 err(
"Not enough magic.");
1636 if (request.
from + len < request.
from) {
1637 DEBUG(
"[Number too large!]");
1638 ERROR(client, reply, EINVAL);
1652 msg(LOG_DEBUG,
"oversized request (this is not a problem)");
1661 msg(LOG_INFO,
"Disconnect request received.");
1672 DEBUG(
"wr: net->buf, ");
1675 DEBUG(
"buf->exp, ");
1678 DEBUG(
"[WRITE to READONLY!]");
1679 ERROR(client, reply, EPERM);
1685 DEBUG(
"Write failed: %m" );
1686 ERROR(client, reply, errno);
1691 request.
from += currlen;
1701 DEBUG(
"Flush failed: %m");
1702 ERROR(client, reply, errno);
1710 DEBUG(
"exp->buf, ");
1718 DEBUG(
"Read failed: %m");
1719 ERROR(client, reply, errno);
1723 DEBUG(
"buf->net, ");
1726 request.
from += currlen;
1739 DEBUG(
"[TRIM to READONLY!]");
1740 ERROR(client, reply, EPERM);
1743 if (
exptrim(&request, client)) {
1744 DEBUG(
"Trim failed: %m");
1745 ERROR(client, reply, errno);
1752 DEBUG (
"Ignoring unknown command\n");
1766 off_t laststartoff = 0, lastsize = 0;
1785 gchar* error_string;
1791 O_RDONLY : (O_RDWR | (cancreate?O_CREAT:0));
1794 tmpname=g_strdup_printf(
"%s.%d-XXXXXX", client->
exportname, i);
1795 DEBUG(
"Opening %s\n", tmpname );
1796 fi.
fhandle = mkstemp(tmpname);
1799 tmpname=g_strdup_printf(
"%s.%d", client->
exportname, i);
1803 DEBUG(
"Opening %s\n", tmpname );
1804 fi.
fhandle = open(tmpname, mode, 0600);
1805 if(fi.
fhandle == -1 && mode == O_RDWR) {
1807 fi.
fhandle = open(tmpname, O_RDONLY);
1819 if(multifile && i>0)
1821 error_string=g_strdup_printf(
1822 "Could not open exported file %s: %%m",
1830 fi.
startoff = laststartoff + lastsize;
1831 g_array_append_val(client->
export, fi);
1840 if (!lastsize && cancreate) {
1843 err(
"Could not expand file: %m");
1849 if(!multifile || temporary)
1854 client->
exportsize = laststartoff + lastsize;
1860 err(
"Size of exported file is too big\n");
1867 msg(LOG_INFO,
"Size of exported file/device is %llu", (
unsigned long long)client->
exportsize);
1869 msg(LOG_INFO,
"Total number of files: %d", i);
1885 export_base = g_strdup(basename(client->
exportname));
1889 g_free(export_base);
1890 msg(LOG_INFO,
"About to create map and diff file %s", client->
difffilename) ;
1892 if (client->
difffile<0)
err(
"Could not create diff file (%m)") ;
1894 err(
"Could not allocate memory") ;
1911 if(command && *command) {
1912 cmd = g_strdup_printf(command, file);
1932 S_IRUSR | S_IWUSR)))
1933 g_warning(
"Could not open transaction log %s",
1971 struct sockaddr_storage netaddr;
1972 struct sockaddr* addr = (
struct sockaddr*)&netaddr;
1973 socklen_t addrinlen =
sizeof(
struct sockaddr_storage );
1974 struct addrinfo hints;
1975 struct addrinfo *ai = NULL;
1976 char peername[NI_MAXHOST];
1977 char netname[NI_MAXHOST];
1982 if (getpeername(net, (
struct sockaddr *) &(client->
clientaddr), &addrinlen) < 0) {
1983 msg(LOG_INFO,
"getpeername failed: %m");
1987 if(addr->sa_family == AF_UNIX) {
1988 strcpy(peername,
"unix");
1990 if((e = getnameinfo((
struct sockaddr *)&(client->
clientaddr), addrinlen,
1991 peername, sizeof (peername), NULL, 0, NI_NUMERICHOST))) {
1992 msg(LOG_INFO,
"getnameinfo failed: %s", gai_strerror(e));
1996 memset(&hints,
'\0',
sizeof (hints));
1997 hints.ai_flags = AI_ADDRCONFIG;
1998 e = getaddrinfo(peername, NULL, &hints, &ai);
2001 msg(LOG_INFO,
"getaddrinfo failed: %s", gai_strerror(e));
2009 msg(LOG_DEBUG,
"virtualization is off");
2013 msg(LOG_DEBUG,
"virtstyle iphash");
2014 for(i=0;i<strlen(peername);i++) {
2015 if(peername[i]==
'.') {
2020 msg(LOG_DEBUG,
"virtstyle ipliteral");
2025 memcpy(&netaddr, &(client->
clientaddr), addrinlen);
2027 if(addr->sa_family == AF_UNIX) {
2028 tmp = g_strdup(peername);
2030 assert((ai->ai_family == AF_INET) || (ai->ai_family == AF_INET6));
2031 if(ai->ai_family == AF_INET) {
2033 }
else if(ai->ai_family == AF_INET6) {
2036 uint8_t* addrptr = (uint8_t*)(((
struct sockaddr*)&netaddr)->sa_data);
2037 for(
int i = 0; i < addrbits; i+=8) {
2039 masklen = masklen > 0 ? masklen : 0;
2044 getnameinfo((
struct sockaddr *) &netaddr, addrinlen,
2045 netname,
sizeof (netname), NULL, 0, NI_NUMERICHOST);
2046 tmp=g_strdup_printf(
"%s/%s", netname, peername);
2058 msg(LOG_INFO,
"connect from %s, assigned file is %s",
2079 sigemptyset(&newset);
2080 sigaddset(&newset, SIGCHLD);
2081 sigaddset(&newset, SIGTERM);
2082 sigprocmask(SIG_BLOCK, &newset, &oldset);
2085 msg(LOG_ERR,
"Could not fork (%s)", strerror(errno));
2091 pidp = g_malloc(
sizeof(pid_t));
2093 g_hash_table_insert(
children, pidp, pidp);
2099 signal(SIGCHLD, SIG_DFL);
2100 signal(SIGTERM, SIG_DFL);
2101 signal(SIGHUP, SIG_DFL);
2102 sigemptyset(&oldset);
2104 sigprocmask(SIG_SETMASK, &oldset, NULL);
2111 struct sockaddr_storage addrin;
2112 socklen_t addrinlen =
sizeof(addrin);
2115 net = accept(sock, (
struct sockaddr *) &addrin, &addrinlen);
2117 err_nonfatal(
"Failed to accept socket connection: %m");
2140 msg(LOG_INFO,
"Spawned a child process");
2142 msg(LOG_ERR,
"Failed to spawn a child process");
2151 msg(LOG_ERR,
"Modern initial negotiation failed");
2157 msg(LOG_ERR,
"Max connections (%d) reached",
2162 sock_flags_old = fcntl(net, F_GETFL, 0);
2163 if (sock_flags_old == -1) {
2164 msg(LOG_ERR,
"Failed to get socket flags");
2168 sock_flags_new = sock_flags_old & ~O_NONBLOCK;
2169 if (sock_flags_new != sock_flags_old &&
2170 fcntl(net, F_SETFL, sock_flags_new) == -1) {
2171 msg(LOG_ERR,
"Failed to set socket to blocking mode");
2176 msg(LOG_ERR,
"Failed to set peername");
2181 msg(LOG_INFO,
"Client '%s' is not authorized to access",
2203 for (i = 0; i < servers->len; i++) {
2204 const SERVER *
const server = &g_array_index(servers,
SERVER, i);
2214 g_array_free(servers, FALSE);
2217 msg(LOG_INFO,
"Starting to serve");
2244 msg(LOG_INFO,
"Max connections reached");
2245 goto handle_connection_out;
2247 if((sock_flags_old = fcntl(net, F_GETFL, 0)) == -1) {
2248 err(
"fcntl F_GETFL");
2250 sock_flags_new = sock_flags_old & ~O_NONBLOCK;
2251 if (sock_flags_new != sock_flags_old &&
2252 fcntl(net, F_SETFL, sock_flags_new) == -1) {
2253 err(
"fcntl F_SETFL ~O_NONBLOCK");
2256 client = g_new0(
CLIENT, 1);
2263 goto handle_connection_out;
2266 msg(LOG_INFO,
"Unauthorized client");
2267 goto handle_connection_out;
2269 msg(LOG_INFO,
"Authorized client");
2277 sigemptyset(&newset);
2278 sigaddset(&newset, SIGCHLD);
2279 sigaddset(&newset, SIGTERM);
2280 sigprocmask(SIG_BLOCK, &newset, &oldset);
2281 if ((pid = fork()) < 0) {
2282 msg(LOG_INFO,
"Could not fork (%s)", strerror(errno));
2283 sigprocmask(SIG_SETMASK, &oldset, NULL);
2284 goto handle_connection_out;
2289 pidp = g_malloc(
sizeof(pid_t));
2291 g_hash_table_insert(
children, pidp, pidp);
2292 sigprocmask(SIG_SETMASK, &oldset, NULL);
2293 goto handle_connection_out;
2298 signal(SIGCHLD, SIG_DFL);
2299 signal(SIGTERM, SIG_DFL);
2300 signal(SIGHUP, SIG_DFL);
2301 sigemptyset(&oldset);
2302 sigprocmask(SIG_SETMASK, &oldset, NULL);
2306 for(i=0;i<servers->len;i++) {
2307 close(g_array_index(servers,
SERVER, i).socket);
2315 g_array_free(servers, FALSE);
2322 msg(LOG_INFO,
"Starting to serve");
2326 handle_connection_out:
2341 const GArray *
const servers) {
2344 for (i = 0; i < servers->len; ++i) {
2345 const SERVER server = g_array_index(servers,
SERVER, i);
2347 if (strcmp(servename, server.
servename) == 0)
2368 GArray *new_servers;
2369 const int old_len = servers->len;
2377 for (i = 0; i < new_servers->len; ++i) {
2378 SERVER new_server = g_array_index(new_servers,
SERVER, i);
2390 retval = servers->len - old_len;
2392 g_array_free(new_servers, TRUE);
2405 sigset_t blocking_mask;
2406 sigset_t original_mask;
2417 for(i=0;i<servers->len;i++) {
2419 if((sock=(g_array_index(servers,
SERVER, i)).socket) >= 0) {
2420 FD_SET(sock, &mset);
2421 max=sock>max?sock:max;
2426 FD_SET(sock, &mset);
2427 max=sock>max?sock:max;
2433 if (sigemptyset(&blocking_mask) == -1)
2434 err(
"failed to initialize blocking_mask: %m");
2436 if (sigaddset(&blocking_mask, SIGCHLD) == -1)
2437 err(
"failed to add SIGCHLD to blocking_mask: %m");
2439 if (sigaddset(&blocking_mask, SIGHUP) == -1)
2440 err(
"failed to add SIGHUP to blocking_mask: %m");
2442 if (sigaddset(&blocking_mask, SIGTERM) == -1)
2443 err(
"failed to add SIGTERM to blocking_mask: %m");
2445 if (sigprocmask(SIG_BLOCK, &blocking_mask, &original_mask) == -1)
2446 err(
"failed to block signals: %m");
2465 while ((pid=waitpid(-1, &status, WNOHANG)) > 0) {
2466 if (WIFEXITED(status)) {
2467 msg(LOG_INFO,
"Child exited with %d", WEXITSTATUS(status));
2469 i = g_hash_table_lookup(
children, &pid);
2471 msg(LOG_INFO,
"SIGCHLD received for an unknown child with PID %ld", (
long)pid);
2473 DEBUG(
"Removing %d from the list of children", pid);
2474 g_hash_table_remove(
children, &pid);
2487 GError *gerror = NULL;
2489 msg(LOG_INFO,
"reconfiguration request received");
2495 msg(LOG_ERR,
"failed to append new servers: %s",
2498 for (i = servers->len - n; i < servers->
len; ++i) {
2499 const SERVER server = g_array_index(servers,
2502 if (server.
socket >= 0) {
2503 FD_SET(server.
socket, &mset);
2507 msg(LOG_INFO,
"reconfigured new server: %s",
2512 memcpy(&rset, &mset,
sizeof(fd_set));
2513 if (pselect(max + 1, &rset, NULL, NULL, NULL, &original_mask) > 0) {
2517 if(!FD_ISSET(sock, &rset)) {
2523 for(i=0; i < servers->len; i++) {
2526 serve=&(g_array_index(servers,
SERVER, i));
2530 if(FD_ISSET(serve->
socket, &rset)) {
2559 if (setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,
sizeof(
int)) == -1) {
2561 "failed to set socket option SO_REUSEADDR: %s",
2567 if (setsockopt(socket,SOL_SOCKET,SO_LINGER,&l,
sizeof(l)) == -1) {
2569 "failed to set socket option SO_LINGER: %s",
2573 if (setsockopt(socket,SOL_SOCKET,SO_KEEPALIVE,&yes,
sizeof(
int)) == -1) {
2575 "failed to set socket option SO_KEEPALIVE: %s",
2589 struct addrinfo hints;
2590 struct addrinfo *ai = NULL;
2614 memset(&hints,
'\0',
sizeof(hints));
2616 hints.ai_socktype = SOCK_STREAM;
2619 port = g_strdup_printf(
"%d", serve->
port);
2622 "failed to open an export socket: "
2623 "failed to convert a port number to a string: %s",
2628 e = getaddrinfo(serve->
listenaddr,port,&hints,&ai);
2634 "failed to open an export socket: "
2635 "failed to get address info: %s",
2645 if (ai->ai_family == AF_INET)
2646 ai->ai_family = AF_INET_SDP;
2647 else (ai->ai_family == AF_INET6)
2648 ai->ai_family = AF_INET6_SDP;
2651 if ((serve->
socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
2653 "failed to open an export socket: "
2654 "failed to create a socket: %s",
2660 g_prefix_error(gerror,
"failed to open an export socket: ");
2664 DEBUG(
"Waiting for connections... bind, ");
2665 e = bind(serve->
socket, ai->ai_addr, ai->ai_addrlen);
2666 if (e != 0 && errno != EADDRINUSE) {
2668 "failed to open an export socket: "
2669 "failed to bind an address to a socket: %s",
2674 if (listen(serve->
socket, 1) < 0) {
2676 "failed to open an export socket: "
2677 "failed to start listening on a socket: %s",
2685 if (retval == -1 && serve->
socket >= 0) {
2694 int open_unix(
const gchar *
const sockname, GError **
const gerror) {
2695 struct sockaddr_un sa;
2699 memset(&sa, 0,
sizeof(
struct sockaddr_un));
2700 sa.sun_family = AF_UNIX;
2701 strncpy(sa.sun_path, sockname, 107);
2702 sock = socket(AF_UNIX, SOCK_STREAM, 0);
2705 "failed to open a unix socket: "
2706 "failed to create socket: %s",
2710 if(bind(sock, (
struct sockaddr*)&sa,
sizeof(
struct sockaddr_un))<0) {
2712 "failed to open a unix socket: "
2713 "failed to bind to address %s: %s",
2714 sockname, strerror(errno));
2717 if(listen(sock, 10)<0) {
2719 "failed to open a unix socket: "
2720 "failed to start listening: %s",
2727 if(retval<0 && sock >= 0) {
2735 GError **
const gerror) {
2736 struct addrinfo hints;
2737 struct addrinfo* ai = NULL;
2738 struct addrinfo* ai_bak;
2744 memset(&hints,
'\0',
sizeof(hints));
2745 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
2746 hints.ai_socktype = SOCK_STREAM;
2747 hints.ai_family = AF_UNSPEC;
2748 hints.ai_protocol = IPPROTO_TCP;
2753 "failed to open a modern socket: "
2754 "failed to get address info: %s",
2762 if((sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))<0) {
2764 "failed to open a modern socket: "
2765 "failed to create a socket: %s",
2771 g_prefix_error(gerror,
"failed to open a modern socket: ");
2775 if(bind(sock, ai->ai_addr, ai->ai_addrlen)) {
2792 "failed to open a modern socket: "
2793 "failed to bind an address to a socket: %s",
2798 if(listen(sock, 10) <0) {
2800 "failed to open a modern socket: "
2801 "failed to start listening on a socket: %s",
2813 if (retval == -1 && sock >= 0) {
2817 freeaddrinfo(ai_bak);
2826 const gchar *
const modernport,
const gchar* unixsock) {
2828 struct sigaction sa;
2831 for(i=0;i<servers->len;i++) {
2832 GError *gerror = NULL;
2838 msg(LOG_ERR,
"failed to setup servers: %s",
2840 g_clear_error(&gerror);
2846 GError *gerror = NULL;
2847 if (
open_modern(modernaddr, modernport, &gerror) == -1) {
2848 msg(LOG_ERR,
"failed to setup servers: %s",
2850 g_clear_error(&gerror);
2854 if(unixsock != NULL) {
2855 GError* gerror = NULL;
2856 if(
open_unix(unixsock, &gerror) == -1) {
2857 msg(LOG_ERR,
"failed to setup servers: %s",
2859 g_clear_error(&gerror);
2866 sigemptyset(&sa.sa_mask);
2867 sigaddset(&sa.sa_mask, SIGTERM);
2868 sa.sa_flags = SA_RESTART;
2869 if(sigaction(SIGCHLD, &sa, NULL) == -1)
2870 err(
"sigaction: %m");
2873 sigemptyset(&sa.sa_mask);
2874 sigaddset(&sa.sa_mask, SIGCHLD);
2875 sa.sa_flags = SA_RESTART;
2876 if(sigaction(SIGTERM, &sa, NULL) == -1)
2877 err(
"sigaction: %m");
2880 sigemptyset(&sa.sa_mask);
2881 sa.sa_flags = SA_RESTART;
2882 if(sigaction(SIGHUP, &sa, NULL) == -1)
2883 err(
"sigaction: %m");
2893 #if !defined(NODAEMON)
2897 if(serve && !(serve->
port)) {
2905 strncpy(
pidftemplate,
"/var/run/nbd-server.%d.pid", 255);
2913 fprintf(pidf,
"%d\n", (
int)getpid());
2917 fprintf(stderr,
"Not fatal; continuing");
2921 #define daemonize(serve)
2932 void dousers(
const gchar *
const username,
const gchar *
const groupname) {
2937 gr = getgrnam(groupname);
2939 str = g_strdup_printf(
"Invalid group name: %s", groupname);
2942 if(setgid(gr->gr_gid)<0) {
2943 err(
"Could not set GID: %m");
2947 pw = getpwnam(username);
2949 str = g_strdup_printf(
"Invalid user name: %s", username);
2952 if(setuid(pw->pw_uid)<0) {
2953 err(
"Could not set UID: %m");
2960 GLogLevelFlags log_level,
2961 const gchar *message,
2964 int level=LOG_DEBUG;
2968 case G_LOG_FLAG_FATAL:
2969 case G_LOG_LEVEL_CRITICAL:
2970 case G_LOG_LEVEL_ERROR:
2973 case G_LOG_LEVEL_WARNING:
2976 case G_LOG_LEVEL_MESSAGE:
2977 case G_LOG_LEVEL_INFO:
2980 case G_LOG_LEVEL_DEBUG:
2986 syslog(level,
"%s", message);
3002 fprintf(stderr,
"Bad size of structure. Alignment problems?\n");
3003 exit(EXIT_FAILURE) ;
3008 modernsocks = g_array_new(FALSE, FALSE,
sizeof(
int));
3025 if (!(serve->
port)) {
3034 open(
"/dev/null", O_WRONLY);
3035 open(
"/dev/null", O_WRONLY);
3038 client=g_malloc(
sizeof(
CLIENT));
3049 if(!servers || !servers->len) {
3050 if(err && !(err->domain ==
NBDS_ERR
3052 g_warning(
"Could not parse config file: %s",
3053 err ? err->message :
"Unknown error");
3057 g_warning(
"Specifying an export on the command line is deprecated.");
3058 g_warning(
"Please use a configuration file instead.");
3061 if((!serve) && (!servers||!servers->len)) {
3063 g_message(
"No configured exports; quitting.");
The (required) group "generic" is missing.
int expread(off_t a, char *buf, size_t len, CLIENT *client)
Read an amount of bytes at a given offset from the right file.
int setup_serve(SERVER *const serve, GError **const gerror)
Connect a server's socket.
static void consume(int f, void *buf, size_t len, size_t bufsiz)
Consume data from an FD that we don't want.
int get_filepos(CLIENT *client, off_t a, int *fhandle, off_t *foffset, size_t *maxbytes)
Get the file handle and offset, given an export offset.
This parameter is a string.
gchar * servename
name of the export as selected by nbd-client
gint flagval
Flag mask for this parameter in case ptype is PARAM_BOOL.
void glib_message_syslog_redirect(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
PARAM_TYPE ptype
Type of the parameter.
GArray * export
array of FILE_INFO of exported files; array size is always 1 unless we're doing the multiple file opt...
Variables associated with a server.
uint8_t getmaskbyte(int masklen)
Gets a byte to allow for address masking.
void destroy_pid_t(gpointer data)
Destroy a pid_t*.
void setup_servers(GArray *const servers, const gchar *const modernaddr, const gchar *const modernport, const gchar *unixsock)
Connect our servers.
void usage()
Print out a message about how to use nbd-server.
#define TREEPAGESIZE
tree (block) files uses those chunks
uint32_t difffilelen
number of pages in difffile
#define NBD_FLAG_SEND_FUA
#define SEND(net, reply)
sending macro.
#define NBD_FLAG_C_NO_ZEROES
#define NBD_FLAG_NO_ZEROES
int rawexpread_fully(off_t a, char *buf, size_t len, CLIENT *client)
Call rawexpread repeatedly until all data has been read.
int glob_flags
global flags
gchar * config_file_pos
Where our config file actually is.
#define SYSCONFDIR
Default position of the config file.
#define F_COPYONWRITE
flag to tell us a file is exported using copyonwrite
SERVER * server
The server this client is getting data from.
static void handle_oldstyle_connection(GArray *const servers, SERVER *const serve)
#define F_FLUSH
Whether server wants FLUSH to be sent by the client.
int copyonwrite_prepare(CLIENT *client)
Failed to set SO_LINGER to a socket.
gchar * postrun
command that will be ran after the client disconnects
int clientfeats
Features supported by this client.
int rawexpwrite_fully(off_t a, char *buf, size_t len, CLIENT *client, int fua)
Call rawexpwrite repeatedly until all data has been written.
gchar * paramname
Name of the parameter, as it appears in the config file.
void dump_section(SERVER *serve, gchar *section_header)
static int socket_accept(const int sock)
This parameter is a boolean.
#define F_SDP
flag to tell us the export should be done using the Socket Direct Protocol for RDMA ...
Failed to bind an address to socket.
void serveloop(GArray *servers)
Loop through the available servers, and serve them.
#define msg(prio,...)
Logging macros.
static void handle_modern_connection(GArray *const servers, const int sock)
Error occurred during readdir()
int fhandle
file descriptor
int dosockopts(const int socket, GError **const gerror)
Set server socket options.
static int get_index_by_servename(const gchar *const servename, const GArray *const servers)
Return the index of the server whose servename matches the given name.
gchar * modernport
port of the modern socket
gchar * user
user we run the server as
#define NBD_REP_ERR_INVALID
int open_unix(const gchar *const sockname, GError **const gerror)
off_t startoff
starting offset of this file
The configuration file is not found.
#define F_TEMPORARY
Whether the backing file is temporary and should be created then unlinked.
char pidftemplate[256]
template to be used for the filename of the PID file
#define NBD_REP_ERR_POLICY
static pid_t spawn_child()
static volatile sig_atomic_t is_sigchld_caught
Flag set by SIGCHLD handler to mark a child exit.
gchar * cowdir
directory for copy-on-write diff files.
static int append_new_servers(GArray *const servers, GError **const gerror)
Parse configuration files and add servers to the array if they don't already exist there...
int expflush(CLIENT *client)
Flush data to a client.
struct sockaddr_storage clientaddr
peer, in binary format, network byte order
int flags
flags associated with this exported file
This parameter is an integer.
#define F_LIST
Allow clients to list the exports on a server.
void serveconnection(CLIENT *client)
Serve a connection.
GArray * modernsocks
Sockets for the modern handler.
int exptrim(struct nbd_request *req, CLIENT *client)
void killchild(gpointer key, gpointer value, gpointer user_data)
Kill a child.
gchar * exportname
(unprocessed) filename of the file we're exporting
int net
The actual client socket.
#define NBD_FLAG_SEND_FLUSH
static void sigchld_handler(const int s G_GNUC_UNUSED)
Handle SIGCHLD by setting atomically a flag which will be evaluated in the main loop of the root serv...
static void construct_path(char *name, int lenmax, off_t size, off_t pos, off_t *ppos)
Tree structure helper functions.
#define F_AUTOREADONLY
flag to tell us a file is set to autoreadonly
gpointer target
Pointer to where the data of this parameter should be written.
int do_run(gchar *command, gchar *file)
Run a command.
static volatile sig_atomic_t is_sigterm_caught
Flag set by SIGTERM handler to mark a exit request.
#define NBD_OPT_EXPORT_NAME
void setmysockopt(int sock)
Underlying system call or library error.
int open_modern(const gchar *const addr, const gchar *const port, GError **const gerror)
unsigned int port
port we're exporting this file at
gboolean required
Whether this is a required (as opposed to optional) parameter.
void err_nonfatal(const char *s)
#define F_TRIM
Whether server wants TRIM (discard) to be sent by the client.
gchar * transactionlog
filename for transaction log
Every subnet in its own directory.
gchar * listenaddr
The IP address we're listening on.
#define F_OLDSTYLE
Global flags:
Failed to set SO_KEEPALIVE to a socket.
CLIENT * negotiate(int net, GArray *servers)
Do the initial negotiation.
char * clientname
peer, in human-readable format
static void send_reply(uint32_t opt, int net, uint32_t reply_type, size_t datasize, void *data)
static const char * getcommandname(uint64_t command)
Translate a command name into human readable form.
GArray * do_cfile_dir(gchar *dir, struct generic_conf *const genconf, GError **e)
Parse config file snippets in a directory.
int socket
The socket of this server.
Variables associated with a client connection.
gchar * modernaddr
address of the modern socket
bool logged_oversized
whether we logged oversized requests already
int difffile
filedescriptor of copyonwrite file.
SERVER * cmdline(int argc, char *argv[])
Parse the command line.
#define OFFT_MAX
The highest value a variable of type off_t can reach.
int set_peername(int net, CLIENT *client)
Find the name of the file we have to serve.
static int open_treefile(char *name, mode_t mode, off_t size, off_t pos)
#define NBD_FLAG_HAS_FLAGS
static void readit(int f, void *buf, size_t len)
Read data from a file descriptor into a buffer.
char pidfname[256]
name of our PID file
Failed to get address info.
Variables associated with an open file.
uint32_t * difmap
see comment on the global difmap for this one
static void sighup_handler(const int s G_GNUC_UNUSED)
Handle SIGHUP by setting atomically a flag which will be evaluated in the main loop of the root serve...
static void handle_list(uint32_t opt, int net, GArray *servers, uint32_t cflags)
void daemonize(SERVER *serve)
Go daemon (unless we specified at compile time that we didn't want this)
static CLIENT * handle_export_name(uint32_t opt, int net, GArray *servers, uint32_t cflags)
uint64_t size_autodetect(int fhandle)
Detect the size of a file.
#define F_SPARSE
flag to tell us copyronwrite should use a sparse file
PARAM_TYPE
Type of configuration file values.
ssize_t rawexpread(off_t a, char *buf, size_t len, CLIENT *client)
Read an amount of bytes at a given offset from the right file.
Literal IP address as part of the filename.
#define TREEDIRSIZE
number of files per subdirectory (or subdirs per subdirectory)
int transactionlogfd
fd for transaction log
void myseek(int handle, off_t a)
seek to a position in a file, with error handling.
#define F_TREEFILES
flag to tell us a file is exported using -t
int max_connections
maximum number of opened connections
VIRT_STYLE virtstyle
The style of virtualization, if any.
#define NBD_FLAG_READ_ONLY
static volatile sig_atomic_t is_sighup_caught
Flag set by SIGHUP handler to mark a reconfiguration request.
GArray * parse_cfile(gchar *f, struct generic_conf *genconf, bool expect_generic, GError **e)
Parse the config file.
Failed to set SO_REUSEADDR to a socket.
int append_serve(const SERVER *const s, GArray *const a)
append new server to array
ssize_t rawexpwrite(off_t a, char *buf, size_t len, CLIENT *client, int fua)
Write an amount of bytes at a given offset to the right file.
#define BUFSIZE
Size of buffer that can hold requests.
int socket_family
family of the socket
uint64_t expected_size
size of the exported file as it was told to us through configuration
gchar * prerun
command to be ran after connecting a client, but before starting to serve
#define NBD_FLAG_SEND_TRIM
This parameter is an integer.
gchar * unixsock
file name of the unix domain socket
#define NBD_CMD_MASK_COMMAND
gchar * group
group we run running as
uint64_t exportsize
size of the file we're exporting
#define F_SYNC
Whether to fsync() after a write.
static int nbd_errno(int errcode)
char * authname
filename of the authorization file
int main(int argc, char *argv[])
Main entry point...
static void writeit(int f, void *buf, size_t len)
Write data from a buffer into a filedescriptor.
static void mkdir_path(char *path)
gboolean modern
client was negotiated using modern negotiation protocol
#define F_FUA
Whether server wants FUA to be sent by the client.
void setupexport(CLIENT *client)
Set up client export array, which is an array of FILE_INFO.
A config file was specified that does not define any exports.
#define NBD_REQUEST_MAGIC
char * difffilename
filename of the copy-on-write file, if any
void dousers(const gchar *const username, const gchar *const groupname)
Set up user-ID and/or group-ID.
#define NBDS_ERR
Error domain common for all NBD server errors.
char default_authname[]
default name of allow file
#define DIFFPAGESIZE
diff file uses those chunks
Replacing all dots in an ip address by a / before doing the same as in IPLIT.
uint8_t cidrlen
The length of the mask when we use CIDR-style virtualization.
static void sigterm_handler(const int s G_GNUC_UNUSED)
Handle SIGTERM by setting atomically a flag which will be evaluated in the main loop of the root serv...
#define NBD_FLAG_FIXED_NEWSTYLE
static void delete_treefile(char *name, off_t size, off_t pos)
#define F_READONLY
Per-export flags:
A value is not supported in this build.
#define NBD_FLAG_ROTATIONAL
A directory requested does not exist.
int expwrite(off_t a, char *buf, size_t len, CLIENT *client, int fua)
Write an amount of bytes at a given offset to the right file.
char * exportname
(processed) filename of the file we're exporting
#define ERROR(client, reply, errcode)
error macro.
Configuration file values of the "generic" section.
void send_export_info(CLIENT *client)
Configuration file values.
#define F_ROTATIONAL
Whether server wants the client to implement the elevator algorithm.
A value is syntactically invalid.
int mainloop(CLIENT *client)
Serve a file to a single client.
#define F_MULTIFILE
flag to tell us a file is exported using -m
void logging(const char *name)
#define F_NO_ZEROES
Do not send zeros to client.
Failed to create a socket.
int authorized_client(CLIENT *opts)
Check whether a client is allowed to connect.
#define NBD_REP_ERR_UNSUP