From e7b20c2f281c814d5ab4cdd6e647f2a5c3525430 Mon Sep 17 00:00:00 2001 From: Wouter Verhelst Date: Mon, 26 Jul 2010 19:44:17 -0400 Subject: [PATCH] Initial implementation of named exports --- cliserv.h | 19 +++- nbd-client.c | 97 +++++++++++++---- nbd-server.c | 328 +++++++++++++++++++++++++++++++++++++++++----------------- nbd.h | 2 +- 4 files changed, 326 insertions(+), 120 deletions(-) diff --git a/cliserv.h b/cliserv.h index 649eb3e..67bac4b 100644 --- a/cliserv.h +++ b/cliserv.h @@ -45,6 +45,7 @@ typedef unsigned long long u64; #endif u64 cliserv_magic = 0x00420281861253LL; +u64 opts_magic = 0x49484156454F5054LL; #define INIT_PASSWD "NBDMAGIC" #define INFO(a) do { } while(0) @@ -75,9 +76,7 @@ void setmysockopt(int sock) { #endif #endif -void err(const char *s) G_GNUC_NORETURN; - -void err(const char *s) { +void err_nonfatal(const char *s) { const int maxlen = 150; char s1[maxlen], *s2; @@ -102,7 +101,13 @@ void err(const char *s) { syslog(LOG_ERR, "Exiting."); #endif fprintf(stderr, "Error: %s\nExiting.\n", s1); - exit(1); +} + +void err(const char *s) G_GNUC_NORETURN; + +void err(const char *s) { + err_nonfatal(s); + exit(EXIT_FAILURE); } void logging(void) { @@ -131,3 +136,9 @@ u64 ntohll(u64 a) { /* Flags used between the client and server */ #define NBD_FLAG_HAS_FLAGS (1 << 0) /* Flags are there */ #define NBD_FLAG_READ_ONLY (1 << 1) /* Device is read-only */ + +#define NBD_DEFAULT_PORT "12345" /* Port on which named exports are + * served */ + +/* Options that the client can select to the server */ +#define NBD_OPT_EXPORT_NAME (1 << 0) /* Client wants to select a named export (is followed by length and name of export) */ diff --git a/nbd-client.c b/nbd-client.c index c98446a..6e5225d 100644 --- a/nbd-client.c +++ b/nbd-client.c @@ -35,6 +35,7 @@ #include #include #include +#include #ifndef __GNUC__ #error I need GCC to work @@ -71,16 +72,13 @@ int check_conn(char* devname, int do_print) { return 0; } -int opennet(char *name, int port, int sdp) { +int opennet(char *name, char* portstr, int sdp) { int sock; - char portstr[6]; struct addrinfo hints; struct addrinfo *ai = NULL; struct addrinfo *rp = NULL; int e; - snprintf(portstr, sizeof(portstr), "%d", port); - memset(&hints,'\0',sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; @@ -125,8 +123,9 @@ int opennet(char *name, int port, int sdp) { return sock; } -void negotiate(int sock, u64 *rsize64, u32 *flags) { +void negotiate(int sock, u64 *rsize64, u32 *flags, char* name) { u64 magic, size64; + uint16_t tmp; char buf[256] = "\0\0\0\0\0\0\0\0\0"; printf("Negotiation: "); @@ -143,6 +142,29 @@ void negotiate(int sock, u64 *rsize64, u32 *flags) { if (magic != cliserv_magic) err("Not enough cliserv_magic"); printf("."); + if(name) { + uint32_t opt; + uint64_t namesize; + uint64_t reserved = 0; + + if(read(sock, &tmp, sizeof(uint16_t)) < 0) { + err("Failed reading flags: %m"); + } + *flags = ((u32)ntohs(tmp)) << 16; + + /* reserved for future use*/ + write(sock, &reserved, sizeof(reserved)); + + /* Write the export name that we're after */ + magic = ntohll(cliserv_magic); + write(sock, &magic, sizeof(magic)); + opt = ntohl(NBD_OPT_EXPORT_NAME); + write(sock, &opt, sizeof(opt)); + namesize = (u64)strlen(name); + namesize = ntohll(namesize); + write(sock, &namesize, sizeof(namesize)); + write(sock, name, strlen(name)); + } if (read(sock, &size64, sizeof(size64)) < 0) err("Failed/3: %m\n"); @@ -162,9 +184,15 @@ void negotiate(int sock, u64 *rsize64, u32 *flags) { printf("size = %lu", (unsigned long)(size64)); #endif - if (read(sock, flags, sizeof(*flags)) < 0) - err("Failed/4: %m\n"); - *flags = ntohl(*flags); + if(!name) { + if (read(sock, flags, sizeof(*flags)) < 0) + err("Failed/4: %m\n"); + *flags = ntohl(*flags); + } else { + if(read(sock, &tmp, sizeof(tmp)) < 0) + err("Failed/4: %m\n"); + *flags |= (uint32_t)ntohs(tmp); + } if (read(sock, &buf, 124) < 0) err("Failed/5: %m\n"); @@ -225,8 +253,17 @@ void finish_sock(int sock, int nbd, int swap) { mlockall(MCL_CURRENT | MCL_FUTURE); } -void usage(void) { - fprintf(stderr, "nbd-client version %s\n", PACKAGE_VERSION); +void usage(char* errmsg, ...) { + if(errmsg) { + char tmp[256]; + va_list ap; + va_start(ap, errmsg); + snprintf(tmp, 256, "ERROR: %s\n\n", errmsg); + vfprintf(stderr, errmsg, ap); + va_end(ap); + } else { + fprintf(stderr, "nbd-client version %s\n", PACKAGE_VERSION); + } fprintf(stderr, "Usage: nbd-client host port nbd_device [-block-size|-b block size] [-timeout|-t timeout] [-swap|-s] [-sdp|-S] [-persist|-p] [-nofork|-n]\n"); fprintf(stderr, "Or : nbd-client -d nbd_device\n"); fprintf(stderr, "Or : nbd-client -c nbd_device\n"); @@ -260,7 +297,7 @@ void disconnect(char* device) { } int main(int argc, char *argv[]) { - int port=0; + char* port=NULL; int sock, nbd; int blocksize=1024; char *hostname=NULL; @@ -274,11 +311,13 @@ int main(int argc, char *argv[]) { u32 flags; int c; int nonspecial=0; + char* name=NULL; struct option long_options[] = { { "block-size", required_argument, NULL, 'b' }, { "check", required_argument, NULL, 'c' }, { "disconnect", required_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, + { "name", required_argument, NULL, 'N' }, { "nofork", no_argument, NULL, 'n' }, { "persist", no_argument, NULL, 'p' }, { "sdp", no_argument, NULL, 'S' }, @@ -289,7 +328,7 @@ int main(int argc, char *argv[]) { logging(); - while((c=getopt_long_only(argc, argv, "-b:c:d:hnpSst:", long_options, NULL))>=0) { + while((c=getopt_long_only(argc, argv, "-b:c:d:hnN:pSst:", long_options, NULL))>=0) { switch(c) { case 1: // non-option argument @@ -305,7 +344,7 @@ int main(int argc, char *argv[]) { optarg+=8; goto timeout; } - fprintf(stderr, "ERROR: unknown option %s encountered\n", optarg); + usage("unknown option %s encountered", optarg); exit(EXIT_FAILURE); } switch(nonspecial++) { @@ -315,14 +354,24 @@ int main(int argc, char *argv[]) { break; case 1: // port - port = strtol(optarg, NULL, 0); + port = optarg; + if(!strtol(optarg, NULL, 0)) { + // not parseable as a number, assume it's the device and we have a name + nbddev = optarg; + nonspecial++; + } else { + if(name) { + usage("port and name specified at the same time. This is not supported."); + exit(EXIT_FAILURE); + } + } break; case 2: // device nbddev = optarg; break; default: - fprintf(stderr, "ERROR: too many non-option arguments specified\n"); + usage("too many non-option arguments specified"); exit(EXIT_FAILURE); } break; @@ -337,11 +386,19 @@ int main(int argc, char *argv[]) { disconnect(optarg); exit(EXIT_SUCCESS); case 'h': - usage(); + usage(NULL); exit(EXIT_SUCCESS); case 'n': nofork=1; break; + case 'N': + name=optarg; + if(port) { + usage("port and name specified at the same time. This is not supported."); + exit(EXIT_FAILURE); + } + port = NBD_DEFAULT_PORT; + break; case 'p': cont=1; break; @@ -361,8 +418,8 @@ int main(int argc, char *argv[]) { } } - if(!port || !hostname || !nbddev) { - usage(); + if((!port && !name) || !hostname || !nbddev) { + usage("not enough information specified"); exit(EXIT_FAILURE); } @@ -373,7 +430,7 @@ int main(int argc, char *argv[]) { sock = opennet(hostname, port, sdp); - negotiate(sock, &size64, &flags); + negotiate(sock, &size64, &flags, name); setsizes(nbd, size64, blocksize, flags); set_timeout(nbd, timeout); finish_sock(sock, nbd, swap); @@ -420,7 +477,7 @@ int main(int argc, char *argv[]) { close(sock); close(nbd); sock = opennet(hostname, port, sdp); nbd = open(nbddev, O_RDWR); - negotiate(sock, &new_size, &new_flags); + negotiate(sock, &new_size, &new_flags, name); if (size64 != new_size) { err("Size of the device changed. Bye"); } diff --git a/nbd-server.c b/nbd-server.c index 70db6d1..f07a29f 100644 --- a/nbd-server.c +++ b/nbd-server.c @@ -159,6 +159,13 @@ char pidfname[256]; /**< name of our PID file */ char pidftemplate[256]; /**< template to be used for the filename of the PID file */ char default_authname[] = SYSCONFDIR "/nbd-server/allow"; /**< default name of allow file */ +int modernsock=0; /**< Socket for the modern handler. Not used + if a client was only specified on the + command line; only port used if + oldstyle is set to false (and then the + command-line client isn't used, gna gna) */ +char* modern_listen; /**< listenaddr value for modernsock */ + /** * Types of virtuatlization **/ @@ -190,6 +197,7 @@ typedef struct { but before starting to serve */ gchar* postrun; /**< command that will be ran after the client disconnects */ + gchar* servename; /**< name of the export as selected by nbd-client */ } SERVER; /** @@ -215,6 +223,7 @@ typedef struct { make -m and -c mutually exclusive */ u32 difffilelen; /**< number of pages in difffile */ u32 *difmap; /**< see comment on the global difmap for this one */ + gboolean modern; /**< client was negotiated using modern negotiation protocol */ } CLIENT; /** @@ -525,8 +534,10 @@ typedef enum { CFILE_VALUE_INVALID, /**< A value is syntactically invalid */ CFILE_VALUE_UNSUPPORTED,/**< A value is not supported in this build */ CFILE_PROGERR, /**< Programmer error */ - CFILE_NO_EXPORTS /**< A config file was specified that does not + CFILE_NO_EXPORTS, /**< A config file was specified that does not define any exports */ + CFILE_INCORRECT_PORT, /**< The reserved port was specified for an + old-style export. */ } CFILE_ERRORS; /** @@ -593,8 +604,7 @@ SERVER* dup_serve(SERVER *s) { * @param a server array * @return 0 success, -1 error */ -int append_serve(SERVER *s, GArray *a) -{ +int append_serve(SERVER *s, GArray *a) { SERVER *ns = NULL; struct addrinfo hints; struct addrinfo *ai = NULL; @@ -686,9 +696,12 @@ GArray* parse_cfile(gchar* f, GError** e) { { "listenaddr", FALSE, PARAM_STRING, NULL, 0 }, }; const int lp_size=sizeof(lp)/sizeof(PARAM); + int do_oldstyle; PARAM gp[] = { { "user", FALSE, PARAM_STRING, &runuser, 0 }, { "group", FALSE, PARAM_STRING, &rungroup, 0 }, + { "oldstyle", FALSE, PARAM_BOOL, &do_oldstyle, 1 }, + { "listenaddr", FALSE, PARAM_STRING, &modern_listen, 0 }, }; PARAM* p=gp; int p_size=sizeof(gp)/sizeof(PARAM); @@ -769,6 +782,11 @@ GArray* parse_cfile(gchar* f, GError** e) { } break; } + if(!strcmp(p[j].paramname, "port") && !strcmp(p[j].target, NBD_DEFAULT_PORT)) { + g_set_error(e, errdomain, CFILE_INCORRECT_PORT, "Config file specifies default port for oldstyle export"); + g_key_file_free(cfile); + return NULL; + } if(err) { if(err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) { if(!p[j].required) { @@ -818,8 +836,13 @@ GArray* parse_cfile(gchar* f, GError** e) { /* Don't append values for the [generic] group */ if(i>0) { s.socket_family = AF_UNSPEC; + s.servename = groups[i]; append_serve(&s, retval); + } else { + if(!do_oldstyle) { + lp[1].required = 0; + } } #ifndef WITH_SDP if(s.flags & F_SDP) { @@ -1190,19 +1213,69 @@ int expwrite(off_t a, char *buf, size_t len, CLIENT *client) { * * @param client The client we're negotiating with. **/ -void negotiate(CLIENT *client) { +CLIENT* negotiate(int net, CLIENT *client, GArray* servers) { char zeros[128]; - u64 size_host; - u32 flags = NBD_FLAG_HAS_FLAGS; + uint64_t size_host; + uint32_t flags = NBD_FLAG_HAS_FLAGS; + uint16_t smallflags = 0; memset(zeros, '\0', sizeof(zeros)); - if (write(client->net, INIT_PASSWD, 8) < 0) - err("Negotiation failed: %m"); - cliserv_magic = htonll(cliserv_magic); - if (write(client->net, &cliserv_magic, sizeof(cliserv_magic)) < 0) - err("Negotiation failed: %m"); + if(!client || !client->modern) { + if (write(net, INIT_PASSWD, 8) < 0) { + err_nonfatal("Negotiation failed: %m"); + if(client) + exit(EXIT_FAILURE); + } + cliserv_magic = htonll(cliserv_magic); + if (write(net, &cliserv_magic, sizeof(cliserv_magic)) < 0) { + err_nonfatal("Negotiation failed: %m"); + if(client) + exit(EXIT_FAILURE); + } + } + if(!client) { + uint64_t reserved; + uint64_t magic; + uint32_t opt; + uint64_t namelen; + char* name; + int i; + + if(!servers) + err("programmer error"); + write(net, &smallflags, sizeof(uint16_t)); + read(net, &reserved, sizeof(reserved)); + read(net, &magic, sizeof(magic)); + magic = ntohll(magic); + if(magic != cliserv_magic) { + close(net); + return NULL; + } + read(net, &opt, sizeof(opt)); + opt = ntohl(opt); + if(opt != NBD_OPT_EXPORT_NAME) { + close(net); + return NULL; + } + read(net, &namelen, sizeof(namelen)); + namelen = ntohll(namelen); + name = malloc(namelen+1); + name[namelen+1]=0; + read(net, &name, namelen); + for(i=0; ilen; i++) { + SERVER* serve = &(g_array_index(servers, SERVER, i)); + if(!strcmp(serve->servename, name)) { + CLIENT* client = g_new0(CLIENT, 1); + client->server = serve; + client->exportsize = OFFT_MAX; + client->net = net; + client->modern = TRUE; + return client; + } + } + } size_host = htonll((u64)(client->exportsize)); - if (write(client->net, &size_host, 8) < 0) + if (write(net, &size_host, 8) < 0) err("Negotiation failed: %m"); if (client->server->flags & F_READONLY) flags |= NBD_FLAG_READ_ONLY; @@ -1211,6 +1284,7 @@ void negotiate(CLIENT *client) { err("Negotiation failed: %m"); if (write(client->net, zeros, 124) < 0) err("Negotiation failed: %m"); + return NULL; } /** sending macro. */ @@ -1233,7 +1307,7 @@ int mainloop(CLIENT *client) { #ifdef DODBG int i = 0; #endif - negotiate(client); + negotiate(client->net, client, NULL); DEBUG("Entering request loop!\n"); reply.magic = htonl(NBD_REPLY_MAGIC); reply.error = 0; @@ -1569,7 +1643,6 @@ void destroy_pid_t(gpointer data) { int serveloop(GArray* servers) { struct sockaddr_storage addrin; socklen_t addrinlen=sizeof(addrin); - SERVER *serve; int i; int max; int sock; @@ -1590,88 +1663,125 @@ int serveloop(GArray* servers) { FD_SET(sock, &mset); max=sock>max?sock:max; } + if(modernsock) { + FD_SET(modernsock, &mset); + max=modernsock>max?sock:max; + } for(;;) { - CLIENT *client; - int net; + CLIENT *client = NULL; pid_t *pid; memcpy(&rset, &mset, sizeof(fd_set)); if(select(max+1, &rset, NULL, NULL, NULL)>0) { + int net = 0; + SERVER* serve; + DEBUG("accept, "); - for(i=0;ilen;i++) { + if(FD_ISSET(modernsock, &rset)) { + if((net=accept(modernsock, (struct sockaddr *) &addrin, &addrinlen)) < 0) + err("accept: %m"); + client = negotiate(net, NULL, servers); + if(!client) { + err_nonfatal("negotiation failed"); + close(net); + } + } + for(i=0;ilen && !net;i++) { serve=&(g_array_index(servers, SERVER, i)); if(FD_ISSET(serve->socket, &rset)) { - int sock_flags; if ((net=accept(serve->socket, (struct sockaddr *) &addrin, &addrinlen)) < 0) err("accept: %m"); + } + } + if(net) { + int sock_flags; - if((sock_flags = fcntl(net, F_GETFL, 0))==-1) { - err("fcntl F_GETFL"); - } - if(fcntl(net, F_SETFL, sock_flags &~O_NONBLOCK)==-1) { - err("fcntl F_SETFL ~O_NONBLOCK"); - } - client = g_malloc(sizeof(CLIENT)); + if((sock_flags = fcntl(net, F_GETFL, 0))==-1) { + err("fcntl F_GETFL"); + } + if(fcntl(net, F_SETFL, sock_flags &~O_NONBLOCK)==-1) { + err("fcntl F_SETFL ~O_NONBLOCK"); + } + if(!client) { + client = g_new0(CLIENT, 1); client->server=serve; client->exportsize=OFFT_MAX; client->net=net; - set_peername(net, client); - if (!authorized_client(client)) { - msg2(LOG_INFO,"Unauthorized client") ; - close(net); - continue; - } - msg2(LOG_INFO,"Authorized client") ; - pid=g_malloc(sizeof(pid_t)); + } + set_peername(net, client); + if (!authorized_client(client)) { + msg2(LOG_INFO,"Unauthorized client") ; + close(net); + continue; + } + msg2(LOG_INFO,"Authorized client") ; + pid=g_malloc(sizeof(pid_t)); #ifndef NOFORK - if ((*pid=fork())<0) { - msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ; - close(net); - continue; - } - if (*pid>0) { /* parent */ - close(net); - g_hash_table_insert(children, pid, pid); - continue; - } - /* child */ - g_hash_table_destroy(children); - for(i=0;ilen;i++) { - serve=&g_array_index(servers, SERVER, i); - close(serve->socket); - } - /* FALSE does not free the - actual data. This is required, - because the client has a - direct reference into that - data, and otherwise we get a - segfault... */ - g_array_free(servers, FALSE); -#endif // NOFORK - msg2(LOG_INFO,"Starting to serve"); - serveconnection(client); - exit(EXIT_SUCCESS); + if ((*pid=fork())<0) { + msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ; + close(net); + continue; } + if (*pid>0) { /* parent */ + close(net); + g_hash_table_insert(children, pid, pid); + continue; + } + /* child */ + g_hash_table_destroy(children); + for(i=0;ilen;i++) { + serve=&g_array_index(servers, SERVER, i); + close(serve->socket); + } + /* FALSE does not free the + actual data. This is required, + because the client has a + direct reference into that + data, and otherwise we get a + segfault... */ + g_array_free(servers, FALSE); +#endif // NOFORK + msg2(LOG_INFO,"Starting to serve"); + serveconnection(client); + exit(EXIT_SUCCESS); } } } } +void dosockopts(int socket) { +#ifndef sun + int yes=1; +#else + char yes='1'; +#endif /* sun */ + int sock_flags; + + /* lose the pesky "Address already in use" error message */ + if (setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { + err("setsockopt SO_REUSEADDR"); + } + if (setsockopt(socket,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) { + err("setsockopt SO_KEEPALIVE"); + } + + /* make the listening socket non-blocking */ + if ((sock_flags = fcntl(socket, F_GETFL, 0)) == -1) { + err("fcntl F_GETFL"); + } + if (fcntl(socket, F_SETFL, sock_flags | O_NONBLOCK) == -1) { + err("fcntl F_SETFL O_NONBLOCK"); + } +} + /** * Connect a server's socket. * * @param serve the server we want to connect. **/ -void setup_serve(SERVER *serve) { +int setup_serve(SERVER *serve) { struct addrinfo hints; struct addrinfo *ai = NULL; - struct sigaction sa; - int sock_flags; -#ifndef sun - int yes=1; -#else - char yes='1'; -#endif /* sun */ gchar *port = NULL; int e; @@ -1682,7 +1792,7 @@ void setup_serve(SERVER *serve) { port = g_strdup_printf ("%d", serve->port); if (port == NULL) - return; + return 0; e = getaddrinfo(serve->listenaddr,port,&hints,&ai); @@ -1709,21 +1819,7 @@ void setup_serve(SERVER *serve) { if ((serve->socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) err("socket: %m"); - /* lose the pesky "Address already in use" error message */ - if (setsockopt(serve->socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { - err("setsockopt SO_REUSEADDR"); - } - if (setsockopt(serve->socket,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) { - err("setsockopt SO_KEEPALIVE"); - } - - /* make the listening socket non-blocking */ - if ((sock_flags = fcntl(serve->socket, F_GETFL, 0)) == -1) { - err("fcntl F_GETFL"); - } - if (fcntl(serve->socket, F_SETFL, sock_flags | O_NONBLOCK) == -1) { - err("fcntl F_SETFL O_NONBLOCK"); - } + dosockopts(serve->socket); DEBUG("Waiting for connections... bind, "); e = bind(serve->socket, ai->ai_addr, ai->ai_addrlen); @@ -1734,17 +1830,43 @@ void setup_serve(SERVER *serve) { err("listen: %m"); freeaddrinfo (ai); + if(serve->servename) { + return 1; + } else { + return 0; + } +} - sa.sa_handler = sigchld_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - if(sigaction(SIGCHLD, &sa, NULL) == -1) - err("sigaction: %m"); - sa.sa_handler = sigterm_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - if(sigaction(SIGTERM, &sa, NULL) == -1) - err("sigaction: %m"); +void open_modern(void) { + struct addrinfo hints; + struct addrinfo* ai = NULL; + struct sock_flags; + int e; + + memset(&hints, '\0', sizeof(hints)); + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; + hints.ai_protocol = IPPROTO_TCP; + e = getaddrinfo(modern_listen, NBD_DEFAULT_PORT, &hints, &ai); + if(e != 0) { + fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e)); + exit(EXIT_FAILURE); + } + if((modernsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))<0) { + err("socket: %m"); + } + + dosockopts(modernsock); + + if(bind(modernsock, ai->ai_addr, ai->ai_addrlen)) { + err("bind: %m"); + } + if(listen(modernsock, 10) <0) { + err("listen: %m"); + } + + freeaddrinfo(ai); } /** @@ -1752,11 +1874,27 @@ void setup_serve(SERVER *serve) { **/ void setup_servers(GArray* servers) { int i; + struct sigaction sa; + int want_modern=0; for(i=0;ilen;i++) { - setup_serve(&(g_array_index(servers, SERVER, i))); + want_modern |= setup_serve(&(g_array_index(servers, SERVER, i))); + } + if(want_modern) { + open_modern(); } children=g_hash_table_new_full(g_int_hash, g_int_equal, NULL, destroy_pid_t); + + sa.sa_handler = sigchld_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if(sigaction(SIGCHLD, &sa, NULL) == -1) + err("sigaction: %m"); + sa.sa_handler = sigterm_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if(sigaction(SIGTERM, &sa, NULL) == -1) + err("sigaction: %m"); } /** diff --git a/nbd.h b/nbd.h index 15b2d0a..082a55b 100644 --- a/nbd.h +++ b/nbd.h @@ -28,7 +28,7 @@ enum { NBD_CMD_READ = 0, NBD_CMD_WRITE = 1, - NBD_CMD_DISC = 2 + NBD_CMD_DISC = 2, }; #define nbd_cmd(req) ((req)->cmd[0]) -- 1.7.10.4