X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fstatd%2Fsm-notify.c;h=462ba7987fef96036ba79f7662694787e37fac76;hp=e49c72259e1b9a64231224d90c8e9dc24fb34f1f;hb=56f9d50712481ed0f84f26e3a9f9dd012cf1995f;hpb=4f3f745c172202bf3846f8f1ee5d0a430b6014af diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c index e49c722..462ba79 100644 --- a/utils/statd/sm-notify.c +++ b/utils/statd/sm-notify.c @@ -55,7 +55,7 @@ static unsigned int opt_max_retry = 15 * 60; static char * opt_srcaddr = 0; static uint16_t opt_srcport = 0; -static void notify(void); +static void notify(const int sock); static int notify_host(int, struct nsm_host *); static void recv_reply(int); static void insert_host(struct nsm_host *); @@ -141,11 +141,76 @@ smn_get_host(const char *hostname, return 1; } +/* + * Prepare a socket for sending RPC requests + * + * Returns a bound datagram socket file descriptor, or -1 if + * an error occurs. + */ +static int +smn_create_socket(const char *srcaddr, const uint16_t srcport) +{ + struct sockaddr_storage address; + struct sockaddr *local_addr = (struct sockaddr *)&address; + int sock, retry_cnt = 0; + +retry: + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + xlog(L_ERROR, "Failed to create RPC socket: %m"); + return -1; + } + fcntl(sock, F_SETFL, O_NONBLOCK); + + memset(&address, 0, sizeof(address)); + local_addr->sa_family = AF_INET; /* Default to IPv4 */ + + /* Bind source IP if provided on command line */ + if (srcaddr) { + struct addrinfo *ai = smn_lookup(srcaddr); + if (!ai) { + xlog(L_ERROR, + "Not a valid hostname or address: \"%s\"", + srcaddr); + (void)close(sock); + return -1; + } + + /* We know it's IPv4 at this point */ + memcpy(local_addr, ai->ai_addr, ai->ai_addrlen); + + freeaddrinfo(ai); + } + + /* Use source port if provided on the command line, + * otherwise use bindresvport */ + if (srcport) { + nfs_set_port(local_addr, srcport); + if (bind(sock, local_addr, sizeof(struct sockaddr_in)) < 0) { + xlog(L_ERROR, "Failed to bind RPC socket: %m"); + (void)close(sock); + return -1; + } + } else { + struct servent *se; + struct sockaddr_in *sin = (struct sockaddr_in *)local_addr; + (void) bindresvport(sock, sin); + /* try to avoid known ports */ + se = getservbyport(sin->sin_port, "udp"); + if (se && retry_cnt < 100) { + retry_cnt++; + close(sock); + goto retry; + } + } + + return sock; +} + int main(int argc, char **argv) { - int c; - int force = 0; + int c, sock, force = 0; char * progname; progname = strrchr(argv[0], '/'); @@ -242,7 +307,14 @@ usage: fprintf(stderr, close(2); } - notify(); + sock = smn_create_socket(opt_srcaddr, opt_srcport); + if (sock == -1) + exit(1); + + if (!nsm_drop_privileges(-1)) + exit(1); + + notify(sock); if (hosts) { struct nsm_host *hp; @@ -262,68 +334,13 @@ usage: fprintf(stderr, * Notify hosts */ static void -notify(void) +notify(const int sock) { - struct sockaddr_storage address; - struct sockaddr *local_addr = (struct sockaddr *)&address; time_t failtime = 0; - int sock = -1; - int retry_cnt = 0; - - retry: - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - xlog(L_ERROR, "Failed to create RPC socket: %m"); - exit(1); - } - fcntl(sock, F_SETFL, O_NONBLOCK); - - memset(&address, 0, sizeof(address)); - local_addr->sa_family = AF_INET; /* Default to IPv4 */ - - /* Bind source IP if provided on command line */ - if (opt_srcaddr) { - struct addrinfo *ai = smn_lookup(opt_srcaddr); - if (!ai) { - xlog(L_ERROR, - "Not a valid hostname or address: \"%s\"", - opt_srcaddr); - exit(1); - } - - /* We know it's IPv4 at this point */ - memcpy(local_addr, ai->ai_addr, ai->ai_addrlen); - - freeaddrinfo(ai); - } - - /* Use source port if provided on the command line, - * otherwise use bindresvport */ - if (opt_srcport) { - nfs_set_port(local_addr, opt_srcport); - if (bind(sock, local_addr, sizeof(struct sockaddr_in)) < 0) { - xlog(L_ERROR, "Failed to bind RPC socket: %m"); - exit(1); - } - } else { - struct servent *se; - struct sockaddr_in *sin = (struct sockaddr_in *)local_addr; - (void) bindresvport(sock, sin); - /* try to avoid known ports */ - se = getservbyport(sin->sin_port, "udp"); - if (se && retry_cnt < 100) { - retry_cnt++; - close(sock); - goto retry; - } - } if (opt_max_retry) failtime = time(NULL) + opt_max_retry; - if (!nsm_drop_privileges(-1)) - exit(1); - while (hosts) { struct pollfd pfd; time_t now = time(NULL);