Print this page
7569 statd support to run on a fixed port
Portions contributed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
@@ -18,12 +18,13 @@
*
* CDDL HEADER END
*/
/*
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
@@ -35,25 +36,23 @@
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
-/*
- * Copyright (c) 2012 by Delphix. All rights reserved.
- */
-
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <ftw.h>
#include <signal.h>
#include <string.h>
#include <syslog.h>
#include <netconfig.h>
+#include <netdir.h>
#include <unistd.h>
#include <netdb.h>
#include <rpc/rpc.h>
+#include <rpc/svc.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/file.h>
#include <sys/types.h>
@@ -67,10 +66,11 @@
#include <synch.h>
#include <net/if.h>
#include <limits.h>
#include <rpcsvc/daemon_utils.h>
#include <priv_utils.h>
+#include "smfcfg.h"
#include "sm_statd.h"
#define home0 "/var/statmon"
#define current0 "/var/statmon/sm"
@@ -97,10 +97,11 @@
char STATE[MAXPATHLEN], CURRENT[MAXPATHLEN], BACKUP[MAXPATHLEN];
static char statd_home[MAXPATHLEN];
int debug;
int regfiles_only = 0; /* 1 => use symlinks in statmon, 0 => don't */
+int statd_port = 0;
char hostname[MAXHOSTNAMELEN];
/*
* These variables will be used to store all the
* alias names for the host, as well as the -a
@@ -455,10 +456,82 @@
in_merges = B_FALSE;
(void) cond_broadcast(&merges_cond);
(void) mutex_unlock(&merges_lock);
}
+/*
+ * This function is called for each configured network type to
+ * bind and register our RPC service programs.
+ *
+ * On TCP or UDP, we may want to bind SM_PROG on a specific port
+ * (when statd_port is specified) in which case we'll use the
+ * variant of svc_tp_create() that lets us pass a bind address.
+ */
+static void
+sm_svc_tp_create(struct netconfig *nconf)
+{
+ char port_str[8];
+ struct nd_hostserv hs;
+ struct nd_addrlist *al = NULL;
+ SVCXPRT *xprt = NULL;
+
+ /*
+ * If statd_port is set and this is an inet transport,
+ * bind this service on the specified port. The TLI way
+ * to create such a bind address is netdir_getbyname()
+ * with the special "host" HOST_SELF_BIND. This builds
+ * an all-zeros IP address with the specified port.
+ */
+ if (statd_port != 0 &&
+ (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
+ strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
+ int err;
+
+ snprintf(port_str, sizeof (port_str), "%u",
+ (unsigned short)statd_port);
+
+ hs.h_host = HOST_SELF_BIND;
+ hs.h_serv = port_str;
+ err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
+ if (err == 0 && al != NULL) {
+ xprt = svc_tp_create_addr(sm_prog_1, SM_PROG, SM_VERS,
+ nconf, al->n_addrs);
+ netdir_free(al, ND_ADDRLIST);
+ }
+ if (xprt == NULL) {
+ syslog(LOG_ERR, "statd: unable to create "
+ "(SM_PROG, SM_VERS) on transport %s (port %d)",
+ nconf->nc_netid, statd_port);
+ }
+ /* fall-back to default bind */
+ }
+ if (xprt == NULL) {
+ /*
+ * Had statd_port=0, or non-inet transport,
+ * or the bind to a specific port failed.
+ * Do a default bind.
+ */
+ xprt = svc_tp_create(sm_prog_1, SM_PROG, SM_VERS, nconf);
+ }
+ if (xprt == NULL) {
+ syslog(LOG_ERR, "statd: unable to create "
+ "(SM_PROG, SM_VERS) for transport %s",
+ nconf->nc_netid);
+ return;
+ }
+
+ /*
+ * Also register the NSM_ADDR program on this
+ * transport handle (same dispatch function).
+ */
+ if (!svc_reg(xprt, NSM_ADDR_PROGRAM, NSM_ADDR_V1, sm_prog_1, nconf)) {
+ syslog(LOG_ERR, "statd: failed to register "
+ "(NSM_ADDR_PROGRAM, NSM_ADDR_V1) for "
+ "netconfig %s", nconf->nc_netid);
+ }
+}
+
int
main(int argc, char *argv[])
{
int c;
int ppid;
@@ -466,20 +539,30 @@
int choice = 0;
struct rlimit rl;
int mode;
int sz;
int pipe_fd = -1;
+ int ret;
int connmaxrec = RPC_MAXDATASIZE;
+ struct netconfig *nconf;
+ NCONF_HANDLE *nc;
addrix = 0;
pathix = 0;
(void) gethostname(hostname, MAXHOSTNAMELEN);
if (init_hostname() < 0)
exit(1);
- while ((c = getopt(argc, argv, "Dd:a:G:p:rU:")) != EOF)
+ ret = nfs_smf_get_iprop("statd_port", &statd_port,
+ DEFAULT_INSTANCE, SCF_TYPE_INTEGER, STATD);
+ if (ret != SA_OK) {
+ syslog(LOG_ERR, "Reading of statd_port from SMF "
+ "failed, using default value");
+ }
+
+ while ((c = getopt(argc, argv, "Dd:a:G:p:P:rU:")) != EOF)
switch (c) {
case 'd':
(void) sscanf(optarg, "%d", &debug);
break;
case 'D':
@@ -540,10 +623,18 @@
} else {
(void) fprintf(stderr,
"statd: -p pathname is too long.\n");
}
break;
+ case 'P':
+ (void) sscanf(optarg, "%d", &statd_port);
+ if (statd_port < 1 || statd_port > UINT16_MAX) {
+ (void) fprintf(stderr,
+ "statd: -P port invalid.\n");
+ statd_port = 0;
+ }
+ break;
case 'r':
regfiles_only = 1;
break;
default:
(void) fprintf(stderr,
@@ -634,20 +725,33 @@
*/
if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
syslog(LOG_INFO, "unable to set maximum RPC record size");
}
- if (!svc_create(sm_prog_1, SM_PROG, SM_VERS, "netpath")) {
- syslog(LOG_ERR, "statd: unable to create (SM_PROG, SM_VERS) "
- "for netpath.");
- exit(1);
+ /*
+ * Enumerate network transports and create service listeners
+ * as appropriate for each.
+ */
+ if ((nc = setnetconfig()) == NULL) {
+ syslog(LOG_ERR, "setnetconfig failed: %m");
+ return (-1);
}
+ while ((nconf = getnetconfig(nc)) != NULL) {
- if (!svc_create(sm_prog_1, NSM_ADDR_PROGRAM, NSM_ADDR_V1, "netpath")) {
- syslog(LOG_ERR, "statd: unable to create (NSM_ADDR_PROGRAM, "
- "NSM_ADDR_V1) for netpath.");
+ /*
+ * Skip things like tpi_raw, invisible...
+ */
+ if ((nconf->nc_flag & NC_VISIBLE) == 0)
+ continue;
+ if (nconf->nc_semantics != NC_TPI_CLTS &&
+ nconf->nc_semantics != NC_TPI_COTS &&
+ nconf->nc_semantics != NC_TPI_COTS_ORD)
+ continue;
+
+ sm_svc_tp_create(nconf);
}
+ (void) endnetconfig(nc);
/*
* Make sure /var/statmon and any alternate (-p) statmon
* directories exist and are owned by daemon. Then change our uid
* to daemon. The uid change is to prevent attacks against local