#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
+#include <stdlib.h>
#include "nfslib.h"
#include "xlog.h"
-#define NFSD_PORTS_FILE "/proc/fs/nfsd/portlist"
-#define NFSD_VERS_FILE "/proc/fs/nfsd/versions"
-#define NFSD_THREAD_FILE "/proc/fs/nfsd/threads"
+#ifndef NFSD_FS_DIR
+#define NFSD_FS_DIR "/proc/fs/nfsd"
+#endif
+
+#define NFSD_PORTS_FILE NFSD_FS_DIR "/portlist"
+#define NFSD_VERS_FILE NFSD_FS_DIR "/versions"
+#define NFSD_THREAD_FILE NFSD_FS_DIR "/threads"
/*
* declaring a common static scratch buffer here keeps us from having to
*/
char buf[128];
+/*
+ * Using the "new" interfaces for nfsd requires that /proc/fs/nfsd is
+ * actually mounted. Make an attempt to mount it here if it doesn't appear
+ * to be. If the mount attempt fails, no big deal -- fall back to using nfsctl
+ * instead.
+ */
+void
+nfssvc_mount_nfsdfs(char *progname)
+{
+ int err;
+ struct stat statbuf;
+
+ err = stat(NFSD_THREAD_FILE, &statbuf);
+ if (err == 0)
+ return;
+
+ if (errno != ENOENT) {
+ xlog(L_ERROR, "Unable to stat %s: errno %d (%m)",
+ NFSD_THREAD_FILE, errno);
+ return;
+ }
+
+ /*
+ * this call can return an error if modprobe is set up to automatically
+ * mount nfsdfs when nfsd.ko is plugged in. So, ignore the return
+ * code from it and just check for the "threads" file afterward.
+ */
+ system("/bin/mount -t nfsd nfsd " NFSD_FS_DIR " >/dev/null 2>&1");
+
+ err = stat(NFSD_THREAD_FILE, &statbuf);
+ if (err == 0)
+ return;
+
+ xlog(L_WARNING, "Unable to access " NFSD_FS_DIR " errno %d (%m)."
+ "\nPlease try, as root, 'mount -t nfsd nfsd " NFSD_FS_DIR
+ "' and then restart %s to correct the problem", errno, progname);
+
+ return;
+}
+
/*
* Are there already sockets configured? If not, then it is safe to try to
* open some and pass them through.
sockfd = socket(addr->ai_family, addr->ai_socktype,
addr->ai_protocol);
if (sockfd < 0) {
- xlog(L_ERROR, "unable to create %s %s socket: "
- "errno %d (%m)", family, proto, errno);
+ if (errno == EAFNOSUPPORT)
+ xlog(L_NOTICE, "address family %s not "
+ "supported by protocol %s",
+ family, proto);
+ else
+ xlog(L_ERROR, "unable to create %s %s socket: "
+ "errno %d (%m)", family, proto, errno);
rc = errno;
goto error;
}
}
snprintf(buf, sizeof(buf), "%d\n", sockfd);
- if (write(fd, buf, strlen(buf)) != strlen(buf)) {
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
/*
* this error may be common on older kernels that don't
* support IPv6, so turn into a debug message.
nfssvc_set_sockets(const int family, const unsigned int protobits,
const char *host, const char *port)
{
- struct addrinfo hints = { .ai_flags = AI_PASSIVE | AI_ADDRCONFIG };
+ struct addrinfo hints = { .ai_flags = AI_PASSIVE };
hints.ai_family = family;
if (fd < 0)
return;
+ n = minorvers4 >= 0 ? minorvers4 : -minorvers4;
+ if (n >= NFSD_MINMINORVERS4 && n <= NFSD_MAXMINORVERS4)
+ off += snprintf(ptr+off, sizeof(buf) - off, "%c4.%d ",
+ minorvers4 > 0 ? '+' : '-',
+ n);
for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) {
if (NFSCTL_VERISSET(ctlbits, n))
off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n);
else
off += snprintf(ptr+off, sizeof(buf) - off, "-%d ", n);
}
- n = minorvers4 >= 0 ? minorvers4 : -minorvers4;
- if (n >= NFSD_MINMINORVERS4 && n <= NFSD_MAXMINORVERS4)
- off += snprintf(ptr+off, sizeof(buf) - off, "%c4.%d",
- minorvers4 > 0 ? '+' : '-',
- n);
xlog(D_GENERAL, "Writing version string to kernel: %s", buf);
snprintf(ptr+off, sizeof(buf) - off, "\n");
- if (write(fd, buf, strlen(buf)) != strlen(buf))
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno);
close(fd);
snprintf(buf, sizeof(buf), "%d\n", nrservs);
n = write(fd, buf, strlen(buf));
close(fd);
- if (n != strlen(buf))
+ if (n != (ssize_t)strlen(buf))
return -1;
else
return 0;