00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 #include "lfs.h"
00061
00062 #include <sys/types.h>
00063 #include <sys/socket.h>
00064 #include <sys/stat.h>
00065 #include <sys/select.h>
00066 #include <sys/wait.h>
00067 #ifdef HAVE_SYS_IOCTL_H
00068 #include <sys/ioctl.h>
00069 #endif
00070 #include <sys/param.h>
00071 #ifdef HAVE_SYS_MOUNT_H
00072 #include <sys/mount.h>
00073 #endif
00074 #include <signal.h>
00075 #include <errno.h>
00076 #include <netinet/tcp.h>
00077 #include <netinet/in.h>
00078 #include <netdb.h>
00079 #include <syslog.h>
00080 #include <unistd.h>
00081 #include <stdio.h>
00082 #include <stdlib.h>
00083 #include <string.h>
00084 #include <fcntl.h>
00085 #include <arpa/inet.h>
00086 #include <strings.h>
00087 #include <dirent.h>
00088 #include <unistd.h>
00089 #include <getopt.h>
00090 #include <pwd.h>
00091 #include <grp.h>
00092
00093 #include <glib.h>
00094
00095
00096 #define MY_NAME "nbd_server"
00097 #include "cliserv.h"
00098
00099 #ifdef WITH_SDP
00100 #include <sdp_inet.h>
00101 #endif
00102
00103
00104 #ifndef SYSCONFDIR
00105 #define SYSCONFDIR "/etc"
00106 #endif
00107 #define CFILE SYSCONFDIR "/nbd-server/config"
00108
00109
00110 gchar* config_file_pos;
00111
00112
00113 gchar* runuser=NULL;
00114
00115 gchar* rungroup=NULL;
00116
00117 gboolean do_oldstyle=FALSE;
00118
00119
00120 #ifdef ISSERVER
00121 #define msg2(a,b) syslog(a,b)
00122 #define msg3(a,b,c) syslog(a,b,c)
00123 #define msg4(a,b,c,d) syslog(a,b,c,d)
00124 #else
00125 #define msg2(a,b) g_message(b)
00126 #define msg3(a,b,c) g_message(b,c)
00127 #define msg4(a,b,c,d) g_message(b,c,d)
00128 #endif
00129
00130
00131
00132 #ifdef DODBG
00133 #define DEBUG( a ) printf( a )
00134 #define DEBUG2( a,b ) printf( a,b )
00135 #define DEBUG3( a,b,c ) printf( a,b,c )
00136 #define DEBUG4( a,b,c,d ) printf( a,b,c,d )
00137 #else
00138 #define DEBUG( a )
00139 #define DEBUG2( a,b )
00140 #define DEBUG3( a,b,c )
00141 #define DEBUG4( a,b,c,d )
00142 #endif
00143 #ifndef PACKAGE_VERSION
00144 #define PACKAGE_VERSION ""
00145 #endif
00146
00147
00148
00149
00150 #define OFFT_MAX ~((off_t)1<<(sizeof(off_t)*8-1))
00151 #define LINELEN 256
00152
00153 #define BUFSIZE ((1024*1024)+sizeof(struct nbd_reply))
00154 #define DIFFPAGESIZE 4096
00155 #define F_READONLY 1
00156 #define F_MULTIFILE 2
00157 #define F_COPYONWRITE 4
00158
00159 #define F_AUTOREADONLY 8
00160 #define F_SPARSE 16
00161 #define F_SDP 32
00162 #define F_SYNC 64
00163 GHashTable *children;
00164 char pidfname[256];
00165 char pidftemplate[256];
00166 char default_authname[] = SYSCONFDIR "/nbd-server/allow";
00167
00168 int modernsock=0;
00169
00170
00171
00172
00173 char* modern_listen;
00174
00175
00176
00177
00178 typedef enum {
00179 VIRT_NONE=0,
00180 VIRT_IPLIT,
00181 VIRT_IPHASH,
00182
00183 VIRT_CIDR,
00184 } VIRT_STYLE;
00185
00186
00187
00188
00189 typedef struct {
00190 gchar* exportname;
00191 off_t expected_size;
00192
00193 gchar* listenaddr;
00194 unsigned int port;
00195 char* authname;
00196 int flags;
00197 int socket;
00198 int socket_family;
00199 VIRT_STYLE virtstyle;
00200 uint8_t cidrlen;
00201
00202 gchar* prerun;
00203
00204 gchar* postrun;
00205
00206 gchar* servename;
00207 int max_connections;
00208 } SERVER;
00209
00210
00211
00212
00213 typedef struct {
00214 int fhandle;
00215 off_t startoff;
00216 } FILE_INFO;
00217
00218 typedef struct {
00219 off_t exportsize;
00220 char *clientname;
00221 char *exportname;
00222 GArray *export;
00223
00224
00225 int net;
00226 SERVER *server;
00227 char* difffilename;
00228 int difffile;
00229
00230
00231 u32 difffilelen;
00232 u32 *difmap;
00233 gboolean modern;
00234 } CLIENT;
00235
00236
00237
00238
00239 typedef enum {
00240 PARAM_INT,
00241 PARAM_STRING,
00242 PARAM_BOOL,
00243 } PARAM_TYPE;
00244
00245
00246
00247
00248 typedef struct {
00249 gchar *paramname;
00250
00251 gboolean required;
00252
00253 PARAM_TYPE ptype;
00254 gpointer target;
00255
00256
00257
00258 gint flagval;
00259
00260 } PARAM;
00261
00262
00263
00264
00265
00266
00267
00268
00269 int authorized_client(CLIENT *opts) {
00270 const char *ERRMSG="Invalid entry '%s' in authfile '%s', so, refusing all connections.";
00271 FILE *f ;
00272 char line[LINELEN];
00273 char *tmp;
00274 struct in_addr addr;
00275 struct in_addr client;
00276 struct in_addr cltemp;
00277 int len;
00278
00279 if ((f=fopen(opts->server->authname,"r"))==NULL) {
00280 msg4(LOG_INFO,"Can't open authorization file %s (%s).",
00281 opts->server->authname,strerror(errno)) ;
00282 return 1 ;
00283 }
00284
00285 inet_aton(opts->clientname, &client);
00286 while (fgets(line,LINELEN,f)!=NULL) {
00287 if((tmp=index(line, '/'))) {
00288 if(strlen(line)<=tmp-line) {
00289 msg4(LOG_CRIT, ERRMSG, line, opts->server->authname);
00290 return 0;
00291 }
00292 *(tmp++)=0;
00293 if(!inet_aton(line,&addr)) {
00294 msg4(LOG_CRIT, ERRMSG, line, opts->server->authname);
00295 return 0;
00296 }
00297 len=strtol(tmp, NULL, 0);
00298 addr.s_addr>>=32-len;
00299 addr.s_addr<<=32-len;
00300 memcpy(&cltemp,&client,sizeof(client));
00301 cltemp.s_addr>>=32-len;
00302 cltemp.s_addr<<=32-len;
00303 if(addr.s_addr == cltemp.s_addr) {
00304 return 1;
00305 }
00306 }
00307 if (strncmp(line,opts->clientname,strlen(opts->clientname))==0) {
00308 fclose(f);
00309 return 1;
00310 }
00311 }
00312 fclose(f);
00313 return 0;
00314 }
00315
00316
00317
00318
00319
00320
00321
00322
00323 inline void readit(int f, void *buf, size_t len) {
00324 ssize_t res;
00325 while (len > 0) {
00326 DEBUG("*");
00327 if ((res = read(f, buf, len)) <= 0) {
00328 if(errno != EAGAIN) {
00329 err("Read failed: %m");
00330 }
00331 } else {
00332 len -= res;
00333 buf += res;
00334 }
00335 }
00336 }
00337
00338
00339
00340
00341
00342
00343
00344
00345 inline void writeit(int f, void *buf, size_t len) {
00346 ssize_t res;
00347 while (len > 0) {
00348 DEBUG("+");
00349 if ((res = write(f, buf, len)) <= 0)
00350 err("Send failed: %m");
00351 len -= res;
00352 buf += res;
00353 }
00354 }
00355
00356
00357
00358
00359
00360 void usage() {
00361 printf("This is nbd-server version " VERSION "\n");
00362 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"
00363 "\t-r|--read-only\t\tread only\n"
00364 "\t-m|--multi-file\t\tmultiple file\n"
00365 "\t-c|--copy-on-write\tcopy on write\n"
00366 "\t-C|--config-file\tspecify an alternate configuration file\n"
00367 "\t-l|--authorize-file\tfile with list of hosts that are allowed to\n\t\t\t\tconnect.\n"
00368 "\t-p|--pid-file\t\tspecify a filename to write our PID to\n"
00369 "\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"
00370 "\t-M|--max-connections\tspecify the maximum number of opened connections\n\n"
00371 "\tif port is set to 0, stdin is used (for running from inetd)\n"
00372 "\tif file_to_export contains '%%s', it is substituted with the IP\n"
00373 "\t\taddress of the machine trying to connect\n"
00374 "\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");
00375 printf("Using configuration file %s\n", CFILE);
00376 }
00377
00378
00379 void dump_section(SERVER* serve, gchar* section_header) {
00380 printf("[%s]\n", section_header);
00381 printf("\texportname = %s\n", serve->exportname);
00382 printf("\tlistenaddr = %s\n", serve->listenaddr);
00383 printf("\tport = %d\n", serve->port);
00384 if(serve->flags & F_READONLY) {
00385 printf("\treadonly = true\n");
00386 }
00387 if(serve->flags & F_MULTIFILE) {
00388 printf("\tmultifile = true\n");
00389 }
00390 if(serve->flags & F_COPYONWRITE) {
00391 printf("\tcopyonwrite = true\n");
00392 }
00393 if(serve->expected_size) {
00394 printf("\tfilesize = %lld\n", (long long int)serve->expected_size);
00395 }
00396 if(serve->authname) {
00397 printf("\tauthfile = %s\n", serve->authname);
00398 }
00399 exit(EXIT_SUCCESS);
00400 }
00401
00402
00403
00404
00405
00406
00407
00408 SERVER* cmdline(int argc, char *argv[]) {
00409 int i=0;
00410 int nonspecial=0;
00411 int c;
00412 struct option long_options[] = {
00413 {"read-only", no_argument, NULL, 'r'},
00414 {"multi-file", no_argument, NULL, 'm'},
00415 {"copy-on-write", no_argument, NULL, 'c'},
00416 {"authorize-file", required_argument, NULL, 'l'},
00417 {"config-file", required_argument, NULL, 'C'},
00418 {"pid-file", required_argument, NULL, 'p'},
00419 {"output-config", required_argument, NULL, 'o'},
00420 {"max-connection", required_argument, NULL, 'M'},
00421 {0,0,0,0}
00422 };
00423 SERVER *serve;
00424 off_t es;
00425 size_t last;
00426 char suffix;
00427 gboolean do_output=FALSE;
00428 gchar* section_header="";
00429 gchar** addr_port;
00430
00431 if(argc==1) {
00432 return NULL;
00433 }
00434 serve=g_new0(SERVER, 1);
00435 serve->authname = g_strdup(default_authname);
00436 serve->virtstyle=VIRT_IPLIT;
00437 while((c=getopt_long(argc, argv, "-C:cl:mo:rp:M:", long_options, &i))>=0) {
00438 switch (c) {
00439 case 1:
00440
00441 switch(nonspecial++) {
00442 case 0:
00443 if(strchr(optarg, ':') == strrchr(optarg, ':')) {
00444 addr_port=g_strsplit(optarg, ":", 2);
00445
00446
00447
00448 if(!addr_port[1]) {
00449 g_strfreev(addr_port);
00450 addr_port=g_strsplit(optarg, "@", 2);
00451 }
00452 } else {
00453 addr_port=g_strsplit(optarg, "@", 2);
00454 }
00455
00456 if(addr_port[1]) {
00457 serve->port=strtol(addr_port[1], NULL, 0);
00458 serve->listenaddr=g_strdup(addr_port[0]);
00459 } else {
00460 serve->listenaddr=NULL;
00461 serve->port=strtol(addr_port[0], NULL, 0);
00462 }
00463 g_strfreev(addr_port);
00464 break;
00465 case 1:
00466 serve->exportname = g_strdup(optarg);
00467 if(serve->exportname[0] != '/') {
00468 fprintf(stderr, "E: The to be exported file needs to be an absolute filename!\n");
00469 exit(EXIT_FAILURE);
00470 }
00471 break;
00472 case 2:
00473 last=strlen(optarg)-1;
00474 suffix=optarg[last];
00475 if (suffix == 'k' || suffix == 'K' ||
00476 suffix == 'm' || suffix == 'M')
00477 optarg[last] = '\0';
00478 es = (off_t)atoll(optarg);
00479 switch (suffix) {
00480 case 'm':
00481 case 'M': es <<= 10;
00482 case 'k':
00483 case 'K': es <<= 10;
00484 default : break;
00485 }
00486 serve->expected_size = es;
00487 break;
00488 }
00489 break;
00490 case 'r':
00491 serve->flags |= F_READONLY;
00492 break;
00493 case 'm':
00494 serve->flags |= F_MULTIFILE;
00495 break;
00496 case 'o':
00497 do_output = TRUE;
00498 section_header = g_strdup(optarg);
00499 break;
00500 case 'p':
00501 strncpy(pidftemplate, optarg, 256);
00502 break;
00503 case 'c':
00504 serve->flags |=F_COPYONWRITE;
00505 break;
00506 case 'C':
00507 g_free(config_file_pos);
00508 config_file_pos=g_strdup(optarg);
00509 break;
00510 case 'l':
00511 g_free(serve->authname);
00512 serve->authname=g_strdup(optarg);
00513 break;
00514 case 'M':
00515 serve->max_connections = strtol(optarg, NULL, 0);
00516 break;
00517 default:
00518 usage();
00519 exit(EXIT_FAILURE);
00520 break;
00521 }
00522 }
00523
00524
00525 if(nonspecial<2) {
00526 g_free(serve);
00527 serve=NULL;
00528 } else {
00529 do_oldstyle = TRUE;
00530 }
00531 if(do_output) {
00532 if(!serve) {
00533 g_critical("Need a complete configuration on the command line to output a config file section!");
00534 exit(EXIT_FAILURE);
00535 }
00536 dump_section(serve, section_header);
00537 }
00538 return serve;
00539 }
00540
00541
00542
00543
00544 typedef enum {
00545 CFILE_NOTFOUND,
00546 CFILE_MISSING_GENERIC,
00547 CFILE_KEY_MISSING,
00548 CFILE_VALUE_INVALID,
00549 CFILE_VALUE_UNSUPPORTED,
00550 CFILE_PROGERR,
00551 CFILE_NO_EXPORTS,
00552
00553 CFILE_INCORRECT_PORT,
00554
00555 } CFILE_ERRORS;
00556
00557
00558
00559
00560 void remove_server(gpointer s) {
00561 SERVER *server;
00562
00563 server=(SERVER*)s;
00564 g_free(server->exportname);
00565 if(server->authname)
00566 g_free(server->authname);
00567 if(server->listenaddr)
00568 g_free(server->listenaddr);
00569 if(server->prerun)
00570 g_free(server->prerun);
00571 if(server->postrun)
00572 g_free(server->postrun);
00573 g_free(server);
00574 }
00575
00576
00577
00578
00579
00580
00581 SERVER* dup_serve(SERVER *s) {
00582 SERVER *serve = NULL;
00583
00584 serve=g_new0(SERVER, 1);
00585 if(serve == NULL)
00586 return NULL;
00587
00588 if(s->exportname)
00589 serve->exportname = g_strdup(s->exportname);
00590
00591 serve->expected_size = s->expected_size;
00592
00593 if(s->listenaddr)
00594 serve->listenaddr = g_strdup(s->listenaddr);
00595
00596 serve->port = s->port;
00597
00598 if(s->authname)
00599 serve->authname = strdup(s->authname);
00600
00601 serve->flags = s->flags;
00602 serve->socket = serve->socket;
00603 serve->socket_family = serve->socket_family;
00604 serve->cidrlen = s->cidrlen;
00605
00606 if(s->prerun)
00607 serve->prerun = g_strdup(s->prerun);
00608
00609 if(s->postrun)
00610 serve->postrun = g_strdup(s->postrun);
00611
00612 if(s->servename)
00613 serve->servename = g_strdup(s->servename);
00614
00615 serve->max_connections = s->max_connections;
00616
00617 return serve;
00618 }
00619
00620
00621
00622
00623
00624
00625
00626 int append_serve(SERVER *s, GArray *a) {
00627 SERVER *ns = NULL;
00628 struct addrinfo hints;
00629 struct addrinfo *ai = NULL;
00630 struct addrinfo *rp = NULL;
00631 char host[NI_MAXHOST];
00632 gchar *port = NULL;
00633 int e;
00634 int ret;
00635
00636 if(!s) {
00637 err("Invalid parsing server");
00638 return -1;
00639 }
00640
00641 port = g_strdup_printf("%d", s->port);
00642
00643 memset(&hints,'\0',sizeof(hints));
00644 hints.ai_family = AF_UNSPEC;
00645 hints.ai_socktype = SOCK_STREAM;
00646 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
00647 hints.ai_protocol = IPPROTO_TCP;
00648
00649 e = getaddrinfo(s->listenaddr, port, &hints, &ai);
00650
00651 if (port)
00652 g_free(port);
00653
00654 if(e == 0) {
00655 for (rp = ai; rp != NULL; rp = rp->ai_next) {
00656 e = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
00657
00658 if (e != 0) {
00659 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(e));
00660 continue;
00661 }
00662
00663
00664 ns = dup_serve (s);
00665 if (ns) {
00666 ns->listenaddr = g_strdup(host);
00667 ns->socket_family = rp->ai_family;
00668 g_array_append_val(a, *ns);
00669 free(ns);
00670 ns = NULL;
00671 }
00672 }
00673
00674 ret = 0;
00675 } else {
00676 fprintf(stderr, "getaddrinfo failed on listen host/address: %s (%s)\n", s->listenaddr ? s->listenaddr : "any", gai_strerror(e));
00677 ret = -1;
00678 }
00679
00680 if (ai)
00681 freeaddrinfo(ai);
00682
00683 return ret;
00684 }
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696 GArray* parse_cfile(gchar* f, GError** e) {
00697 const char* DEFAULT_ERROR = "Could not parse %s in group %s: %s";
00698 const char* MISSING_REQUIRED_ERROR = "Could not find required value %s in group %s: %s";
00699 SERVER s;
00700 gchar *virtstyle=NULL;
00701 PARAM lp[] = {
00702 { "exportname", TRUE, PARAM_STRING, NULL, 0 },
00703 { "port", TRUE, PARAM_INT, NULL, 0 },
00704 { "authfile", FALSE, PARAM_STRING, NULL, 0 },
00705 { "filesize", FALSE, PARAM_INT, NULL, 0 },
00706 { "virtstyle", FALSE, PARAM_STRING, NULL, 0 },
00707 { "prerun", FALSE, PARAM_STRING, NULL, 0 },
00708 { "postrun", FALSE, PARAM_STRING, NULL, 0 },
00709 { "readonly", FALSE, PARAM_BOOL, NULL, F_READONLY },
00710 { "multifile", FALSE, PARAM_BOOL, NULL, F_MULTIFILE },
00711 { "copyonwrite", FALSE, PARAM_BOOL, NULL, F_COPYONWRITE },
00712 { "sparse_cow", FALSE, PARAM_BOOL, NULL, F_SPARSE },
00713 { "sdp", FALSE, PARAM_BOOL, NULL, F_SDP },
00714 { "sync", FALSE, PARAM_BOOL, NULL, F_SYNC },
00715 { "listenaddr", FALSE, PARAM_STRING, NULL, 0 },
00716 { "maxconnections", FALSE, PARAM_INT, NULL, 0 },
00717 };
00718 const int lp_size=sizeof(lp)/sizeof(PARAM);
00719 PARAM gp[] = {
00720 { "user", FALSE, PARAM_STRING, &runuser, 0 },
00721 { "group", FALSE, PARAM_STRING, &rungroup, 0 },
00722 { "oldstyle", FALSE, PARAM_BOOL, &do_oldstyle, 1 },
00723 { "listenaddr", FALSE, PARAM_STRING, &modern_listen, 0 },
00724 };
00725 PARAM* p=gp;
00726 int p_size=sizeof(gp)/sizeof(PARAM);
00727 GKeyFile *cfile;
00728 GError *err = NULL;
00729 const char *err_msg=NULL;
00730 GQuark errdomain;
00731 GArray *retval=NULL;
00732 gchar **groups;
00733 gboolean value;
00734 gchar* startgroup;
00735 gint i;
00736 gint j;
00737
00738 errdomain = g_quark_from_string("parse_cfile");
00739 cfile = g_key_file_new();
00740 retval = g_array_new(FALSE, TRUE, sizeof(SERVER));
00741 if(!g_key_file_load_from_file(cfile, f, G_KEY_FILE_KEEP_COMMENTS |
00742 G_KEY_FILE_KEEP_TRANSLATIONS, &err)) {
00743 g_set_error(e, errdomain, CFILE_NOTFOUND, "Could not open config file %s.", f);
00744 g_key_file_free(cfile);
00745 return retval;
00746 }
00747 startgroup = g_key_file_get_start_group(cfile);
00748 if(!startgroup || strcmp(startgroup, "generic")) {
00749 g_set_error(e, errdomain, CFILE_MISSING_GENERIC, "Config file does not contain the [generic] group!");
00750 g_key_file_free(cfile);
00751 return NULL;
00752 }
00753 groups = g_key_file_get_groups(cfile, NULL);
00754 for(i=0;groups[i];i++) {
00755 memset(&s, '\0', sizeof(SERVER));
00756 lp[0].target=&(s.exportname);
00757 lp[1].target=&(s.port);
00758 lp[2].target=&(s.authname);
00759 lp[3].target=&(s.expected_size);
00760 lp[4].target=&(virtstyle);
00761 lp[5].target=&(s.prerun);
00762 lp[6].target=&(s.postrun);
00763 lp[7].target=lp[8].target=lp[9].target=
00764 lp[10].target=lp[11].target=
00765 lp[12].target=&(s.flags);
00766 lp[13].target=&(s.listenaddr);
00767 lp[14].target=&(s.max_connections);
00768
00769
00770 if(i==1) {
00771 p=lp;
00772 p_size=lp_size;
00773 }
00774 for(j=0;j<p_size;j++) {
00775 g_assert(p[j].target != NULL);
00776 g_assert(p[j].ptype==PARAM_INT||p[j].ptype==PARAM_STRING||p[j].ptype==PARAM_BOOL);
00777 switch(p[j].ptype) {
00778 case PARAM_INT:
00779 *((gint*)p[j].target) =
00780 g_key_file_get_integer(cfile,
00781 groups[i],
00782 p[j].paramname,
00783 &err);
00784 break;
00785 case PARAM_STRING:
00786 *((gchar**)p[j].target) =
00787 g_key_file_get_string(cfile,
00788 groups[i],
00789 p[j].paramname,
00790 &err);
00791 break;
00792 case PARAM_BOOL:
00793 value = g_key_file_get_boolean(cfile,
00794 groups[i],
00795 p[j].paramname, &err);
00796 if(!err) {
00797 if(value) {
00798 *((gint*)p[j].target) |= p[j].flagval;
00799 } else {
00800 *((gint*)p[j].target) &= ~(p[j].flagval);
00801 }
00802 }
00803 break;
00804 }
00805 if(!strcmp(p[j].paramname, "port") && !strcmp(p[j].target, NBD_DEFAULT_PORT)) {
00806 g_set_error(e, errdomain, CFILE_INCORRECT_PORT, "Config file specifies default port for oldstyle export");
00807 g_key_file_free(cfile);
00808 return NULL;
00809 }
00810 if(err) {
00811 if(err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
00812 if(!p[j].required) {
00813
00814 g_clear_error(&err);
00815 continue;
00816 } else {
00817 err_msg = MISSING_REQUIRED_ERROR;
00818 }
00819 } else {
00820 err_msg = DEFAULT_ERROR;
00821 }
00822 g_set_error(e, errdomain, CFILE_VALUE_INVALID, err_msg, p[j].paramname, groups[i], err->message);
00823 g_array_free(retval, TRUE);
00824 g_error_free(err);
00825 g_key_file_free(cfile);
00826 return NULL;
00827 }
00828 }
00829 if(virtstyle) {
00830 if(!strncmp(virtstyle, "none", 4)) {
00831 s.virtstyle=VIRT_NONE;
00832 } else if(!strncmp(virtstyle, "ipliteral", 9)) {
00833 s.virtstyle=VIRT_IPLIT;
00834 } else if(!strncmp(virtstyle, "iphash", 6)) {
00835 s.virtstyle=VIRT_IPHASH;
00836 } else if(!strncmp(virtstyle, "cidrhash", 8)) {
00837 s.virtstyle=VIRT_CIDR;
00838 if(strlen(virtstyle)<10) {
00839 g_set_error(e, errdomain, CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s: missing length", virtstyle, groups[i]);
00840 g_array_free(retval, TRUE);
00841 g_key_file_free(cfile);
00842 return NULL;
00843 }
00844 s.cidrlen=strtol(virtstyle+8, NULL, 0);
00845 } else {
00846 g_set_error(e, errdomain, CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s", virtstyle, groups[i]);
00847 g_array_free(retval, TRUE);
00848 g_key_file_free(cfile);
00849 return NULL;
00850 }
00851 if(s.port && !do_oldstyle) {
00852 g_warning("A port was specified, but oldstyle exports were not requested. This may not do what you expect.");
00853 g_warning("Please read 'man 5 nbd-server' and search for oldstyle for more info");
00854 }
00855 } else {
00856 s.virtstyle=VIRT_IPLIT;
00857 }
00858
00859 virtstyle=NULL;
00860
00861 if(i>0) {
00862 s.socket_family = AF_UNSPEC;
00863 s.servename = groups[i];
00864
00865 append_serve(&s, retval);
00866 } else {
00867 if(!do_oldstyle) {
00868 lp[1].required = 0;
00869 }
00870 }
00871 #ifndef WITH_SDP
00872 if(s.flags & F_SDP) {
00873 g_set_error(e, errdomain, CFILE_VALUE_UNSUPPORTED, "This nbd-server was built without support for SDP, yet group %s uses it", groups[i]);
00874 g_array_free(retval, TRUE);
00875 g_key_file_free(cfile);
00876 return NULL;
00877 }
00878 #endif
00879 }
00880 if(i==1) {
00881 g_set_error(e, errdomain, CFILE_NO_EXPORTS, "The config file does not specify any exports");
00882 }
00883 g_key_file_free(cfile);
00884 return retval;
00885 }
00886
00887
00888
00889
00890
00891
00892 void sigchld_handler(int s) {
00893 int status;
00894 int* i;
00895 pid_t pid;
00896
00897 while((pid=waitpid(-1, &status, WNOHANG)) > 0) {
00898 if(WIFEXITED(status)) {
00899 msg3(LOG_INFO, "Child exited with %d", WEXITSTATUS(status));
00900 }
00901 i=g_hash_table_lookup(children, &pid);
00902 if(!i) {
00903 msg3(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld", (long)pid);
00904 } else {
00905 DEBUG2("Removing %d from the list of children", pid);
00906 g_hash_table_remove(children, &pid);
00907 }
00908 }
00909 }
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919 void killchild(gpointer key, gpointer value, gpointer user_data) {
00920 pid_t *pid=value;
00921 int *parent=user_data;
00922
00923 kill(*pid, SIGTERM);
00924 *parent=1;
00925 }
00926
00927
00928
00929
00930
00931
00932 void sigterm_handler(int s) {
00933 int parent=0;
00934
00935 g_hash_table_foreach(children, killchild, &parent);
00936
00937 if(parent) {
00938 unlink(pidfname);
00939 }
00940
00941 exit(EXIT_SUCCESS);
00942 }
00943
00944
00945
00946
00947
00948
00949
00950
00951 off_t size_autodetect(int fhandle) {
00952 off_t es;
00953 u64 bytes;
00954 struct stat stat_buf;
00955 int error;
00956
00957 #ifdef HAVE_SYS_MOUNT_H
00958 #ifdef HAVE_SYS_IOCTL_H
00959 #ifdef BLKGETSIZE64
00960 DEBUG("looking for export size with ioctl BLKGETSIZE64\n");
00961 if (!ioctl(fhandle, BLKGETSIZE64, &bytes) && bytes) {
00962 return (off_t)bytes;
00963 }
00964 #endif
00965 #endif
00966 #endif
00967
00968 DEBUG("looking for fhandle size with fstat\n");
00969 stat_buf.st_size = 0;
00970 error = fstat(fhandle, &stat_buf);
00971 if (!error) {
00972 if(stat_buf.st_size > 0)
00973 return (off_t)stat_buf.st_size;
00974 } else {
00975 err("fstat failed: %m");
00976 }
00977
00978 DEBUG("looking for fhandle size with lseek SEEK_END\n");
00979 es = lseek(fhandle, (off_t)0, SEEK_END);
00980 if (es > ((off_t)0)) {
00981 return es;
00982 } else {
00983 DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
00984 }
00985
00986 err("Could not find size of exported block device: %m");
00987 return OFFT_MAX;
00988 }
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001 int get_filepos(GArray* export, off_t a, int* fhandle, off_t* foffset, size_t* maxbytes ) {
01002
01003 if(a < 0)
01004 return -1;
01005
01006
01007 FILE_INFO fi;
01008 int start = 0;
01009 int end = export->len - 1;
01010 while( start <= end ) {
01011 int mid = (start + end) / 2;
01012 fi = g_array_index(export, FILE_INFO, mid);
01013 if( fi.startoff < a ) {
01014 start = mid + 1;
01015 } else if( fi.startoff > a ) {
01016 end = mid - 1;
01017 } else {
01018 start = end = mid;
01019 break;
01020 }
01021 }
01022
01023
01024 g_assert(end >= 0);
01025
01026 fi = g_array_index(export, FILE_INFO, end);
01027 *fhandle = fi.fhandle;
01028 *foffset = a - fi.startoff;
01029 *maxbytes = 0;
01030 if( end+1 < export->len ) {
01031 FILE_INFO fi_next = g_array_index(export, FILE_INFO, end+1);
01032 *maxbytes = fi_next.startoff - a;
01033 }
01034
01035 return 0;
01036 }
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046 void myseek(int handle,off_t a) {
01047 if (lseek(handle, a, SEEK_SET) < 0) {
01048 err("Can not seek locally!\n");
01049 }
01050 }
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062 ssize_t rawexpwrite(off_t a, char *buf, size_t len, CLIENT *client) {
01063 int fhandle;
01064 off_t foffset;
01065 size_t maxbytes;
01066 ssize_t retval;
01067
01068 if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
01069 return -1;
01070 if(maxbytes && len > maxbytes)
01071 len = maxbytes;
01072
01073 DEBUG4("(WRITE to fd %d offset %llu len %u), ", fhandle, foffset, len);
01074
01075 myseek(fhandle, foffset);
01076 retval = write(fhandle, buf, len);
01077 if(client->server->flags & F_SYNC) {
01078 fsync(fhandle);
01079 }
01080 return retval;
01081 }
01082
01083
01084
01085
01086
01087 int rawexpwrite_fully(off_t a, char *buf, size_t len, CLIENT *client) {
01088 ssize_t ret=0;
01089
01090 while(len > 0 && (ret=rawexpwrite(a, buf, len, client)) > 0 ) {
01091 a += ret;
01092 buf += ret;
01093 len -= ret;
01094 }
01095 return (ret < 0 || len != 0);
01096 }
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109 ssize_t rawexpread(off_t a, char *buf, size_t len, CLIENT *client) {
01110 int fhandle;
01111 off_t foffset;
01112 size_t maxbytes;
01113
01114 if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
01115 return -1;
01116 if(maxbytes && len > maxbytes)
01117 len = maxbytes;
01118
01119 DEBUG4("(READ from fd %d offset %llu len %u), ", fhandle, foffset, len);
01120
01121 myseek(fhandle, foffset);
01122 return read(fhandle, buf, len);
01123 }
01124
01125
01126
01127
01128
01129 int rawexpread_fully(off_t a, char *buf, size_t len, CLIENT *client) {
01130 ssize_t ret=0;
01131
01132 while(len > 0 && (ret=rawexpread(a, buf, len, client)) > 0 ) {
01133 a += ret;
01134 buf += ret;
01135 len -= ret;
01136 }
01137 return (ret < 0 || len != 0);
01138 }
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150 int expread(off_t a, char *buf, size_t len, CLIENT *client) {
01151 off_t rdlen, offset;
01152 off_t mapcnt, mapl, maph, pagestart;
01153
01154 if (!(client->server->flags & F_COPYONWRITE))
01155 return(rawexpread_fully(a, buf, len, client));
01156 DEBUG3("Asked to read %d bytes at %llu.\n", len, (unsigned long long)a);
01157
01158 mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
01159
01160 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
01161 pagestart=mapcnt*DIFFPAGESIZE;
01162 offset=a-pagestart;
01163 rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
01164 len : (size_t)DIFFPAGESIZE-offset;
01165 if (client->difmap[mapcnt]!=(u32)(-1)) {
01166 DEBUG3("Page %llu is at %lu\n", (unsigned long long)mapcnt,
01167 (unsigned long)(client->difmap[mapcnt]));
01168 myseek(client->difffile, client->difmap[mapcnt]*DIFFPAGESIZE+offset);
01169 if (read(client->difffile, buf, rdlen) != rdlen) return -1;
01170 } else {
01171 DEBUG2("Page %llu is not here, we read the original one\n",
01172 (unsigned long long)mapcnt);
01173 if(rawexpread_fully(a, buf, rdlen, client)) return -1;
01174 }
01175 len-=rdlen; a+=rdlen; buf+=rdlen;
01176 }
01177 return 0;
01178 }
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191 int expwrite(off_t a, char *buf, size_t len, CLIENT *client) {
01192 char pagebuf[DIFFPAGESIZE];
01193 off_t mapcnt,mapl,maph;
01194 off_t wrlen,rdlen;
01195 off_t pagestart;
01196 off_t offset;
01197
01198 if (!(client->server->flags & F_COPYONWRITE))
01199 return(rawexpwrite_fully(a, buf, len, client));
01200 DEBUG3("Asked to write %d bytes at %llu.\n", len, (unsigned long long)a);
01201
01202 mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
01203
01204 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
01205 pagestart=mapcnt*DIFFPAGESIZE ;
01206 offset=a-pagestart ;
01207 wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
01208 len : (size_t)DIFFPAGESIZE-offset;
01209
01210 if (client->difmap[mapcnt]!=(u32)(-1)) {
01211 DEBUG3("Page %llu is at %lu\n", (unsigned long long)mapcnt,
01212 (unsigned long)(client->difmap[mapcnt])) ;
01213 myseek(client->difffile,
01214 client->difmap[mapcnt]*DIFFPAGESIZE+offset);
01215 if (write(client->difffile, buf, wrlen) != wrlen) return -1 ;
01216 } else {
01217 myseek(client->difffile,client->difffilelen*DIFFPAGESIZE) ;
01218 client->difmap[mapcnt]=(client->server->flags&F_SPARSE)?mapcnt:client->difffilelen++;
01219 DEBUG3("Page %llu is not here, we put it at %lu\n",
01220 (unsigned long long)mapcnt,
01221 (unsigned long)(client->difmap[mapcnt]));
01222 rdlen=DIFFPAGESIZE ;
01223 if (rawexpread_fully(pagestart, pagebuf, rdlen, client))
01224 return -1;
01225 memcpy(pagebuf+offset,buf,wrlen) ;
01226 if (write(client->difffile, pagebuf, DIFFPAGESIZE) !=
01227 DIFFPAGESIZE)
01228 return -1;
01229 }
01230 len-=wrlen ; a+=wrlen ; buf+=wrlen ;
01231 }
01232 return 0;
01233 }
01234
01235
01236
01237
01238
01239
01240 CLIENT* negotiate(int net, CLIENT *client, GArray* servers) {
01241 char zeros[128];
01242 uint64_t size_host;
01243 uint32_t flags = NBD_FLAG_HAS_FLAGS;
01244 uint16_t smallflags = 0;
01245 uint64_t magic;
01246
01247 memset(zeros, '\0', sizeof(zeros));
01248 if(!client || !client->modern) {
01249
01250 if (write(net, INIT_PASSWD, 8) < 0) {
01251 err_nonfatal("Negotiation failed: %m");
01252 if(client)
01253 exit(EXIT_FAILURE);
01254 }
01255 if(!client || client->modern) {
01256
01257 magic = htonll(opts_magic);
01258 } else {
01259
01260 magic = htonll(cliserv_magic);
01261 }
01262 if (write(net, &magic, sizeof(magic)) < 0) {
01263 err_nonfatal("Negotiation failed: %m");
01264 if(client)
01265 exit(EXIT_FAILURE);
01266 }
01267 }
01268 if(!client) {
01269
01270 uint32_t reserved;
01271 uint32_t opt;
01272 uint32_t namelen;
01273 char* name;
01274 int i;
01275
01276 if(!servers)
01277 err("programmer error");
01278 if (write(net, &smallflags, sizeof(uint16_t)) < 0)
01279 err("Negotiation failed: %m");
01280 if (read(net, &reserved, sizeof(reserved)) < 0)
01281 err("Negotiation failed: %m");
01282 if (read(net, &magic, sizeof(magic)) < 0)
01283 err("Negotiation failed: %m");
01284 magic = ntohll(magic);
01285 if(magic != opts_magic) {
01286 close(net);
01287 return NULL;
01288 }
01289 if (read(net, &opt, sizeof(opt)) < 0)
01290 err("Negotiation failed: %m");
01291 opt = ntohl(opt);
01292 if(opt != NBD_OPT_EXPORT_NAME) {
01293 close(net);
01294 return NULL;
01295 }
01296 if (read(net, &namelen, sizeof(namelen)) < 0)
01297 err("Negotiation failed: %m");
01298 namelen = ntohl(namelen);
01299 name = malloc(namelen+1);
01300 name[namelen]=0;
01301 if (read(net, name, namelen) < 0)
01302 err("Negotiation failed: %m");
01303 for(i=0; i<servers->len; i++) {
01304 SERVER* serve = &(g_array_index(servers, SERVER, i));
01305 if(!strcmp(serve->servename, name)) {
01306 CLIENT* client = g_new0(CLIENT, 1);
01307 client->server = serve;
01308 client->exportsize = OFFT_MAX;
01309 client->net = net;
01310 client->modern = TRUE;
01311 return client;
01312 }
01313 }
01314 return NULL;
01315 }
01316
01317 size_host = htonll((u64)(client->exportsize));
01318 if (write(net, &size_host, 8) < 0)
01319 err("Negotiation failed: %m");
01320 if (client->server->flags & F_READONLY)
01321 flags |= NBD_FLAG_READ_ONLY;
01322 if (!client->modern) {
01323
01324 flags = htonl(flags);
01325 if (write(client->net, &flags, 4) < 0)
01326 err("Negotiation failed: %m");
01327 } else {
01328
01329 smallflags = (uint16_t)(flags & ~((uint16_t)0));
01330 smallflags = htons(smallflags);
01331 if (write(client->net, &smallflags, sizeof(smallflags)) < 0) {
01332 err("Negotiation failed: %m");
01333 }
01334 }
01335
01336 if (write(client->net, zeros, 124) < 0)
01337 err("Negotiation failed: %m");
01338 return NULL;
01339 }
01340
01341
01342 #define SEND(net,reply) writeit( net, &reply, sizeof( reply ));
01343
01344 #define ERROR(client,reply,errcode) { reply.error = htonl(errcode); SEND(client->net,reply); reply.error = 0; }
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354 int mainloop(CLIENT *client) {
01355 struct nbd_request request;
01356 struct nbd_reply reply;
01357 gboolean go_on=TRUE;
01358 #ifdef DODBG
01359 int i = 0;
01360 #endif
01361 negotiate(client->net, client, NULL);
01362 DEBUG("Entering request loop!\n");
01363 reply.magic = htonl(NBD_REPLY_MAGIC);
01364 reply.error = 0;
01365 while (go_on) {
01366 char buf[BUFSIZE];
01367 char* p;
01368 size_t len;
01369 size_t currlen;
01370 size_t writelen;
01371 #ifdef DODBG
01372 i++;
01373 printf("%d: ", i);
01374 #endif
01375 readit(client->net, &request, sizeof(request));
01376 request.from = ntohll(request.from);
01377 request.type = ntohl(request.type);
01378
01379 if (request.type==NBD_CMD_DISC) {
01380 msg2(LOG_INFO, "Disconnect request received.");
01381 if (client->server->flags & F_COPYONWRITE) {
01382 if (client->difmap) g_free(client->difmap) ;
01383 close(client->difffile);
01384 unlink(client->difffilename);
01385 free(client->difffilename);
01386 }
01387 go_on=FALSE;
01388 continue;
01389 }
01390
01391 len = ntohl(request.len);
01392
01393 if (request.magic != htonl(NBD_REQUEST_MAGIC))
01394 err("Not enough magic.");
01395 if (len > BUFSIZE - sizeof(struct nbd_reply)) {
01396 currlen = BUFSIZE - sizeof(struct nbd_reply);
01397 msg2(LOG_INFO, "oversized request (this is not a problem)");
01398 } else {
01399 currlen = len;
01400 }
01401 #ifdef DODBG
01402 printf("%s from %llu (%llu) len %d, ", request.type ? "WRITE" :
01403 "READ", (unsigned long long)request.from,
01404 (unsigned long long)request.from / 512, len);
01405 #endif
01406 memcpy(reply.handle, request.handle, sizeof(reply.handle));
01407 if ((request.from + len) > (OFFT_MAX)) {
01408 DEBUG("[Number too large!]");
01409 ERROR(client, reply, EINVAL);
01410 continue;
01411 }
01412
01413 if (((ssize_t)((off_t)request.from + len) > client->exportsize)) {
01414 DEBUG("[RANGE!]");
01415 ERROR(client, reply, EINVAL);
01416 continue;
01417 }
01418
01419 if (request.type==NBD_CMD_WRITE) {
01420 DEBUG("wr: net->buf, ");
01421 while(len > 0) {
01422 readit(client->net, buf, currlen);
01423 DEBUG("buf->exp, ");
01424 if ((client->server->flags & F_READONLY) ||
01425 (client->server->flags & F_AUTOREADONLY)) {
01426 DEBUG("[WRITE to READONLY!]");
01427 ERROR(client, reply, EPERM);
01428 continue;
01429 }
01430 if (expwrite(request.from, buf, len, client)) {
01431 DEBUG("Write failed: %m" );
01432 ERROR(client, reply, errno);
01433 continue;
01434 }
01435 SEND(client->net, reply);
01436 DEBUG("OK!\n");
01437 len -= currlen;
01438 currlen = (len < BUFSIZE) ? len : BUFSIZE;
01439 }
01440 continue;
01441 }
01442
01443
01444 DEBUG("exp->buf, ");
01445 memcpy(buf, &reply, sizeof(struct nbd_reply));
01446 p = buf + sizeof(struct nbd_reply);
01447 writelen = currlen + sizeof(struct nbd_reply);
01448 while(len > 0) {
01449 if (expread(request.from, p, currlen, client)) {
01450 DEBUG("Read failed: %m");
01451 ERROR(client, reply, errno);
01452 continue;
01453 }
01454
01455 DEBUG("buf->net, ");
01456 writeit(client->net, buf, writelen);
01457 len -= currlen;
01458 currlen = (len < BUFSIZE) ? len : BUFSIZE;
01459 p = buf;
01460 writelen = currlen;
01461 }
01462 DEBUG("OK!\n");
01463 }
01464 return 0;
01465 }
01466
01467
01468
01469
01470
01471
01472 void setupexport(CLIENT* client) {
01473 int i;
01474 off_t laststartoff = 0, lastsize = 0;
01475 int multifile = (client->server->flags & F_MULTIFILE);
01476
01477 client->export = g_array_new(TRUE, TRUE, sizeof(FILE_INFO));
01478
01479
01480
01481
01482 for(i=0; ; i++) {
01483 FILE_INFO fi;
01484 gchar *tmpname;
01485 gchar* error_string;
01486 mode_t mode = (client->server->flags & F_READONLY) ? O_RDONLY : O_RDWR;
01487
01488 if(multifile) {
01489 tmpname=g_strdup_printf("%s.%d", client->exportname, i);
01490 } else {
01491 tmpname=g_strdup(client->exportname);
01492 }
01493 DEBUG2( "Opening %s\n", tmpname );
01494 fi.fhandle = open(tmpname, mode);
01495 if(fi.fhandle == -1 && mode == O_RDWR) {
01496
01497 fi.fhandle = open(tmpname, O_RDONLY);
01498 if(fi.fhandle != -1) {
01499
01500
01501 if(!(client->server->flags & F_COPYONWRITE)) {
01502 client->server->flags |= F_AUTOREADONLY;
01503 client->server->flags |= F_READONLY;
01504 }
01505 }
01506 }
01507 if(fi.fhandle == -1) {
01508 if(multifile && i>0)
01509 break;
01510 error_string=g_strdup_printf(
01511 "Could not open exported file %s: %%m",
01512 tmpname);
01513 err(error_string);
01514 }
01515 fi.startoff = laststartoff + lastsize;
01516 g_array_append_val(client->export, fi);
01517 g_free(tmpname);
01518
01519
01520
01521 laststartoff = fi.startoff;
01522 lastsize = size_autodetect(fi.fhandle);
01523
01524 if(!multifile)
01525 break;
01526 }
01527
01528
01529 client->exportsize = laststartoff + lastsize;
01530
01531
01532 if(client->server->expected_size) {
01533
01534 if(client->server->expected_size > client->exportsize) {
01535 err("Size of exported file is too big\n");
01536 }
01537
01538 client->exportsize = client->server->expected_size;
01539 }
01540
01541 msg3(LOG_INFO, "Size of exported file/device is %llu", (unsigned long long)client->exportsize);
01542 if(multifile) {
01543 msg3(LOG_INFO, "Total number of files: %d", i);
01544 }
01545 }
01546
01547 int copyonwrite_prepare(CLIENT* client) {
01548 off_t i;
01549 if ((client->difffilename = malloc(1024))==NULL)
01550 err("Failed to allocate string for diff file name");
01551 snprintf(client->difffilename, 1024, "%s-%s-%d.diff",client->exportname,client->clientname,
01552 (int)getpid()) ;
01553 client->difffilename[1023]='\0';
01554 msg3(LOG_INFO,"About to create map and diff file %s",client->difffilename) ;
01555 client->difffile=open(client->difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
01556 if (client->difffile<0) err("Could not create diff file (%m)") ;
01557 if ((client->difmap=calloc(client->exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
01558 err("Could not allocate memory") ;
01559 for (i=0;i<client->exportsize/DIFFPAGESIZE;i++) client->difmap[i]=(u32)-1 ;
01560
01561 return 0;
01562 }
01563
01564
01565
01566
01567
01568
01569
01570
01571 int do_run(gchar* command, gchar* file) {
01572 gchar* cmd;
01573 int retval=0;
01574
01575 if(command && *command) {
01576 cmd = g_strdup_printf(command, file);
01577 retval=system(cmd);
01578 g_free(cmd);
01579 }
01580 return retval;
01581 }
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591 void serveconnection(CLIENT *client) {
01592 if(do_run(client->server->prerun, client->exportname)) {
01593 exit(EXIT_FAILURE);
01594 }
01595 setupexport(client);
01596
01597 if (client->server->flags & F_COPYONWRITE) {
01598 copyonwrite_prepare(client);
01599 }
01600
01601 setmysockopt(client->net);
01602
01603 mainloop(client);
01604 do_run(client->server->postrun, client->exportname);
01605 }
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618 void set_peername(int net, CLIENT *client) {
01619 struct sockaddr_storage addrin;
01620 struct sockaddr_storage netaddr;
01621 struct sockaddr_in *netaddr4 = NULL;
01622 struct sockaddr_in6 *netaddr6 = NULL;
01623 socklen_t addrinlen = sizeof( addrin );
01624 struct addrinfo hints;
01625 struct addrinfo *ai = NULL;
01626 char peername[NI_MAXHOST];
01627 char netname[NI_MAXHOST];
01628 char *tmp = NULL;
01629 int i;
01630 int e;
01631 int shift;
01632
01633 if (getpeername(net, (struct sockaddr *) &addrin, &addrinlen) < 0)
01634 err("getsockname failed: %m");
01635
01636 getnameinfo((struct sockaddr *)&addrin, addrinlen,
01637 peername, sizeof (peername), NULL, 0, NI_NUMERICHOST);
01638
01639 memset(&hints, '\0', sizeof (hints));
01640 hints.ai_flags = AI_ADDRCONFIG;
01641 e = getaddrinfo(peername, NULL, &hints, &ai);
01642
01643 if(e != 0) {
01644 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
01645 freeaddrinfo(ai);
01646 return;
01647 }
01648
01649 switch(client->server->virtstyle) {
01650 case VIRT_NONE:
01651 client->exportname=g_strdup(client->server->exportname);
01652 break;
01653 case VIRT_IPHASH:
01654 for(i=0;i<strlen(peername);i++) {
01655 if(peername[i]=='.') {
01656 peername[i]='/';
01657 }
01658 }
01659 case VIRT_IPLIT:
01660 client->exportname=g_strdup_printf(client->server->exportname, peername);
01661 break;
01662 case VIRT_CIDR:
01663 memcpy(&netaddr, &addrin, addrinlen);
01664 if(ai->ai_family == AF_INET) {
01665 netaddr4 = (struct sockaddr_in *)&netaddr;
01666 (netaddr4->sin_addr).s_addr>>=32-(client->server->cidrlen);
01667 (netaddr4->sin_addr).s_addr<<=32-(client->server->cidrlen);
01668
01669 getnameinfo((struct sockaddr *) netaddr4, addrinlen,
01670 netname, sizeof (netname), NULL, 0, NI_NUMERICHOST);
01671 tmp=g_strdup_printf("%s/%s", netname, peername);
01672 }else if(ai->ai_family == AF_INET6) {
01673 netaddr6 = (struct sockaddr_in6 *)&netaddr;
01674
01675 shift = 128-(client->server->cidrlen);
01676 i = 3;
01677 while(shift >= 32) {
01678 ((netaddr6->sin6_addr).s6_addr32[i])=0;
01679 shift-=32;
01680 i--;
01681 }
01682 (netaddr6->sin6_addr).s6_addr32[i]>>=shift;
01683 (netaddr6->sin6_addr).s6_addr32[i]<<=shift;
01684
01685 getnameinfo((struct sockaddr *)netaddr6, addrinlen,
01686 netname, sizeof(netname), NULL, 0, NI_NUMERICHOST);
01687 tmp=g_strdup_printf("%s/%s", netname, peername);
01688 }
01689
01690 if(tmp != NULL)
01691 client->exportname=g_strdup_printf(client->server->exportname, tmp);
01692
01693 break;
01694 }
01695
01696 freeaddrinfo(ai);
01697 msg4(LOG_INFO, "connect from %s, assigned file is %s",
01698 peername, client->exportname);
01699 client->clientname=g_strdup(peername);
01700 }
01701
01702
01703
01704
01705
01706 void destroy_pid_t(gpointer data) {
01707 g_free(data);
01708 }
01709
01710
01711
01712
01713 int serveloop(GArray* servers) {
01714 struct sockaddr_storage addrin;
01715 socklen_t addrinlen=sizeof(addrin);
01716 int i;
01717 int max;
01718 int sock;
01719 fd_set mset;
01720 fd_set rset;
01721
01722
01723
01724
01725
01726
01727
01728
01729 max=0;
01730 FD_ZERO(&mset);
01731 for(i=0;i<servers->len;i++) {
01732 if((sock=(g_array_index(servers, SERVER, i)).socket)) {
01733 FD_SET(sock, &mset);
01734 max=sock>max?sock:max;
01735 }
01736 }
01737 if(modernsock) {
01738 FD_SET(modernsock, &mset);
01739 max=modernsock>max?modernsock:max;
01740 }
01741 for(;;) {
01742 CLIENT *client = NULL;
01743 pid_t *pid;
01744
01745 memcpy(&rset, &mset, sizeof(fd_set));
01746 if(select(max+1, &rset, NULL, NULL, NULL)>0) {
01747 int net = 0;
01748 SERVER* serve;
01749
01750 DEBUG("accept, ");
01751 if(FD_ISSET(modernsock, &rset)) {
01752 if((net=accept(modernsock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
01753 err("accept: %m");
01754 client = negotiate(net, NULL, servers);
01755 if(!client) {
01756 err_nonfatal("negotiation failed");
01757 close(net);
01758 net=0;
01759 }
01760 }
01761 for(i=0;i<servers->len && !net;i++) {
01762 serve=&(g_array_index(servers, SERVER, i));
01763 if(FD_ISSET(serve->socket, &rset)) {
01764 if ((net=accept(serve->socket, (struct sockaddr *) &addrin, &addrinlen)) < 0)
01765 err("accept: %m");
01766 }
01767 }
01768 if(net) {
01769 int sock_flags;
01770
01771 if(serve->max_connections > 0 &&
01772 g_hash_table_size(children) >= serve->max_connections) {
01773 msg2(LOG_INFO, "Max connections reached");
01774 close(net);
01775 continue;
01776 }
01777 if((sock_flags = fcntl(net, F_GETFL, 0))==-1) {
01778 err("fcntl F_GETFL");
01779 }
01780 if(fcntl(net, F_SETFL, sock_flags &~O_NONBLOCK)==-1) {
01781 err("fcntl F_SETFL ~O_NONBLOCK");
01782 }
01783 if(!client) {
01784 client = g_new0(CLIENT, 1);
01785 client->server=serve;
01786 client->exportsize=OFFT_MAX;
01787 client->net=net;
01788 }
01789 set_peername(net, client);
01790 if (!authorized_client(client)) {
01791 msg2(LOG_INFO,"Unauthorized client") ;
01792 close(net);
01793 continue;
01794 }
01795 msg2(LOG_INFO,"Authorized client") ;
01796 pid=g_malloc(sizeof(pid_t));
01797 #ifndef NOFORK
01798 if ((*pid=fork())<0) {
01799 msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
01800 close(net);
01801 continue;
01802 }
01803 if (*pid>0) {
01804 close(net);
01805 g_hash_table_insert(children, pid, pid);
01806 continue;
01807 }
01808
01809 g_hash_table_destroy(children);
01810 for(i=0;i<servers->len;i++) {
01811 serve=&g_array_index(servers, SERVER, i);
01812 close(serve->socket);
01813 }
01814
01815
01816
01817
01818
01819
01820 g_array_free(servers, FALSE);
01821 #endif // NOFORK
01822 msg2(LOG_INFO,"Starting to serve");
01823 serveconnection(client);
01824 exit(EXIT_SUCCESS);
01825 }
01826 }
01827 }
01828 }
01829
01830 void dosockopts(int socket) {
01831 #ifndef sun
01832 int yes=1;
01833 #else
01834 char yes='1';
01835 #endif
01836 int sock_flags;
01837
01838
01839 if (setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
01840 err("setsockopt SO_REUSEADDR");
01841 }
01842 if (setsockopt(socket,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
01843 err("setsockopt SO_KEEPALIVE");
01844 }
01845
01846
01847 if ((sock_flags = fcntl(socket, F_GETFL, 0)) == -1) {
01848 err("fcntl F_GETFL");
01849 }
01850 if (fcntl(socket, F_SETFL, sock_flags | O_NONBLOCK) == -1) {
01851 err("fcntl F_SETFL O_NONBLOCK");
01852 }
01853 }
01854
01855
01856
01857
01858
01859
01860 int setup_serve(SERVER *serve) {
01861 struct addrinfo hints;
01862 struct addrinfo *ai = NULL;
01863 gchar *port = NULL;
01864 int e;
01865
01866 if(!do_oldstyle) {
01867 return serve->servename ? 1 : 0;
01868 }
01869 memset(&hints,'\0',sizeof(hints));
01870 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV;
01871 hints.ai_socktype = SOCK_STREAM;
01872 hints.ai_family = serve->socket_family;
01873
01874 port = g_strdup_printf ("%d", serve->port);
01875 if (port == NULL)
01876 return 0;
01877
01878 e = getaddrinfo(serve->listenaddr,port,&hints,&ai);
01879
01880 g_free(port);
01881
01882 if(e != 0) {
01883 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
01884 serve->socket = -1;
01885 freeaddrinfo(ai);
01886 exit(EXIT_FAILURE);
01887 }
01888
01889 if(serve->socket_family == AF_UNSPEC)
01890 serve->socket_family = ai->ai_family;
01891
01892 #ifdef WITH_SDP
01893 if ((serve->flags) && F_SDP) {
01894 if (ai->ai_family == AF_INET)
01895 ai->ai_family = AF_INET_SDP;
01896 else (ai->ai_family == AF_INET6)
01897 ai->ai_family = AF_INET6_SDP;
01898 }
01899 #endif
01900 if ((serve->socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
01901 err("socket: %m");
01902
01903 dosockopts(serve->socket);
01904
01905 DEBUG("Waiting for connections... bind, ");
01906 e = bind(serve->socket, ai->ai_addr, ai->ai_addrlen);
01907 if (e != 0 && errno != EADDRINUSE)
01908 err("bind: %m");
01909 DEBUG("listen, ");
01910 if (listen(serve->socket, 1) < 0)
01911 err("listen: %m");
01912
01913 freeaddrinfo (ai);
01914 if(serve->servename) {
01915 return 1;
01916 } else {
01917 return 0;
01918 }
01919 }
01920
01921 void open_modern(void) {
01922 struct addrinfo hints;
01923 struct addrinfo* ai = NULL;
01924 struct sock_flags;
01925 int e;
01926
01927 memset(&hints, '\0', sizeof(hints));
01928 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
01929 hints.ai_socktype = SOCK_STREAM;
01930 hints.ai_family = AF_UNSPEC;
01931 hints.ai_protocol = IPPROTO_TCP;
01932 e = getaddrinfo(modern_listen, NBD_DEFAULT_PORT, &hints, &ai);
01933 if(e != 0) {
01934 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
01935 exit(EXIT_FAILURE);
01936 }
01937 if((modernsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))<0) {
01938 err("socket: %m");
01939 }
01940
01941 dosockopts(modernsock);
01942
01943 if(bind(modernsock, ai->ai_addr, ai->ai_addrlen)) {
01944 err("bind: %m");
01945 }
01946 if(listen(modernsock, 10) <0) {
01947 err("listen: %m");
01948 }
01949
01950 freeaddrinfo(ai);
01951 }
01952
01953
01954
01955
01956 void setup_servers(GArray* servers) {
01957 int i;
01958 struct sigaction sa;
01959 int want_modern=0;
01960
01961 for(i=0;i<servers->len;i++) {
01962 want_modern |= setup_serve(&(g_array_index(servers, SERVER, i)));
01963 }
01964 if(want_modern) {
01965 open_modern();
01966 }
01967 children=g_hash_table_new_full(g_int_hash, g_int_equal, NULL, destroy_pid_t);
01968
01969 sa.sa_handler = sigchld_handler;
01970 sigemptyset(&sa.sa_mask);
01971 sa.sa_flags = SA_RESTART;
01972 if(sigaction(SIGCHLD, &sa, NULL) == -1)
01973 err("sigaction: %m");
01974 sa.sa_handler = sigterm_handler;
01975 sigemptyset(&sa.sa_mask);
01976 sa.sa_flags = SA_RESTART;
01977 if(sigaction(SIGTERM, &sa, NULL) == -1)
01978 err("sigaction: %m");
01979 }
01980
01981
01982
01983
01984
01985
01986
01987
01988 #if !defined(NODAEMON) && !defined(NOFORK)
01989 void daemonize(SERVER* serve) {
01990 FILE*pidf;
01991
01992 if(serve && !(serve->port)) {
01993 return;
01994 }
01995 if(daemon(0,0)<0) {
01996 err("daemon");
01997 }
01998 if(!*pidftemplate) {
01999 if(serve) {
02000 strncpy(pidftemplate, "/var/run/nbd-server.%d.pid", 255);
02001 } else {
02002 strncpy(pidftemplate, "/var/run/nbd-server.pid", 255);
02003 }
02004 }
02005 snprintf(pidfname, 255, pidftemplate, serve ? serve->port : 0);
02006 pidf=fopen(pidfname, "w");
02007 if(pidf) {
02008 fprintf(pidf,"%d\n", (int)getpid());
02009 fclose(pidf);
02010 } else {
02011 perror("fopen");
02012 fprintf(stderr, "Not fatal; continuing");
02013 }
02014 }
02015 #else
02016 #define daemonize(serve)
02017 #endif
02018
02019
02020
02021
02022
02023
02024 void serve_err(SERVER* serve, const char* msg) G_GNUC_NORETURN;
02025
02026 void serve_err(SERVER* serve, const char* msg) {
02027 g_message("Export of %s on port %d failed:", serve->exportname,
02028 serve->port);
02029 err(msg);
02030 }
02031
02032
02033
02034
02035 void dousers(void) {
02036 struct passwd *pw;
02037 struct group *gr;
02038 gchar* str;
02039 if(rungroup) {
02040 gr=getgrnam(rungroup);
02041 if(!gr) {
02042 str = g_strdup_printf("Invalid group name: %s", rungroup);
02043 err(str);
02044 }
02045 if(setgid(gr->gr_gid)<0) {
02046 err("Could not set GID: %m");
02047 }
02048 }
02049 if(runuser) {
02050 pw=getpwnam(runuser);
02051 if(!pw) {
02052 str = g_strdup_printf("Invalid user name: %s", runuser);
02053 err(str);
02054 }
02055 if(setuid(pw->pw_uid)<0) {
02056 err("Could not set UID: %m");
02057 }
02058 }
02059 }
02060
02061 #ifndef ISSERVER
02062 void glib_message_syslog_redirect(const gchar *log_domain,
02063 GLogLevelFlags log_level,
02064 const gchar *message,
02065 gpointer user_data)
02066 {
02067 int level=LOG_DEBUG;
02068
02069 switch( log_level )
02070 {
02071 case G_LOG_FLAG_FATAL:
02072 case G_LOG_LEVEL_CRITICAL:
02073 case G_LOG_LEVEL_ERROR:
02074 level=LOG_ERR;
02075 break;
02076 case G_LOG_LEVEL_WARNING:
02077 level=LOG_WARNING;
02078 break;
02079 case G_LOG_LEVEL_MESSAGE:
02080 case G_LOG_LEVEL_INFO:
02081 level=LOG_INFO;
02082 break;
02083 case G_LOG_LEVEL_DEBUG:
02084 level=LOG_DEBUG;
02085 default:
02086 level=LOG_ERR;
02087 }
02088 syslog(level, "%s", message);
02089 }
02090 #endif
02091
02092
02093
02094
02095 int main(int argc, char *argv[]) {
02096 SERVER *serve;
02097 GArray *servers;
02098 GError *err=NULL;
02099
02100 if (sizeof( struct nbd_request )!=28) {
02101 fprintf(stderr,"Bad size of structure. Alignment problems?\n");
02102 exit(EXIT_FAILURE) ;
02103 }
02104
02105 memset(pidftemplate, '\0', 256);
02106
02107 logging();
02108 config_file_pos = g_strdup(CFILE);
02109 serve=cmdline(argc, argv);
02110 servers = parse_cfile(config_file_pos, &err);
02111
02112 if(serve) {
02113 serve->socket_family = AF_UNSPEC;
02114
02115 append_serve(serve, servers);
02116
02117 if (!(serve->port)) {
02118 CLIENT *client;
02119 #ifndef ISSERVER
02120
02121
02122
02123
02124 close(1);
02125 close(2);
02126 open("/dev/null", O_WRONLY);
02127 open("/dev/null", O_WRONLY);
02128 g_log_set_default_handler( glib_message_syslog_redirect, NULL );
02129 #endif
02130 client=g_malloc(sizeof(CLIENT));
02131 client->server=serve;
02132 client->net=0;
02133 client->exportsize=OFFT_MAX;
02134 set_peername(0,client);
02135 serveconnection(client);
02136 return 0;
02137 }
02138 }
02139
02140 if(!servers || !servers->len) {
02141 if(err && !(err->domain == g_quark_from_string("parse_cfile")
02142 && err->code == CFILE_NOTFOUND)) {
02143 g_warning("Could not parse config file: %s",
02144 err ? err->message : "Unknown error");
02145 }
02146 }
02147 if(serve) {
02148 g_warning("Specifying an export on the command line is deprecated.");
02149 g_warning("Please use a configuration file instead.");
02150 }
02151
02152 if((!serve) && (!servers||!servers->len)) {
02153 g_message("No configured exports; quitting.");
02154 exit(EXIT_FAILURE);
02155 }
02156 daemonize(serve);
02157 setup_servers(servers);
02158 dousers();
02159 serveloop(servers);
02160 return 0 ;
02161 }