6 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
13 #include <sys/types.h>
14 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
28 * IPv6 support for nfsd was finished before some of the other daemons (mountd
29 * and statd in particular). That could be a problem in the future if someone
30 * were to boot a kernel that supports IPv6 serving with an older nfs-utils. For
31 * now, hardcode the IPv6 switch into the off position until the other daemons
37 #define NFSD_FS_DIR "/proc/fs/nfsd"
40 #define NFSD_PORTS_FILE NFSD_FS_DIR "/portlist"
41 #define NFSD_VERS_FILE NFSD_FS_DIR "/versions"
42 #define NFSD_THREAD_FILE NFSD_FS_DIR "/threads"
45 * declaring a common static scratch buffer here keeps us from having to
46 * continually thrash the stack. The value of 128 bytes here is really just a
47 * SWAG and can be increased if necessary. It ought to be enough for the
48 * routines below however.
53 * Using the "new" interfaces for nfsd requires that /proc/fs/nfsd is
54 * actually mounted. Make an attempt to mount it here if it doesn't appear
55 * to be. If the mount attempt fails, no big deal -- fall back to using nfsctl
59 nfssvc_mount_nfsdfs(char *progname)
64 err = stat(NFSD_THREAD_FILE, &statbuf);
68 if (errno != ENOENT) {
69 xlog(L_ERROR, "Unable to stat %s: errno %d (%m)",
70 NFSD_THREAD_FILE, errno);
75 * this call can return an error if modprobe is set up to automatically
76 * mount nfsdfs when nfsd.ko is plugged in. So, ignore the return
77 * code from it and just check for the "threads" file afterward.
79 system("/bin/mount -t nfsd nfsd " NFSD_FS_DIR " >/dev/null 2>&1");
81 err = stat(NFSD_THREAD_FILE, &statbuf);
85 xlog(L_WARNING, "Unable to access " NFSD_FS_DIR " errno %d (%m)."
86 "\nPlease try, as root, 'mount -t nfsd nfsd " NFSD_FS_DIR
87 "' and then restart %s to correct the problem", errno, progname);
93 * Are there already sockets configured? If not, then it is safe to try to
94 * open some and pass them through.
96 * Note: If the user explicitly asked for 'udp', then we should probably check
97 * if that is open, and should open it if not. However we don't yet. All
98 * sockets have to be opened when the first daemon is started.
105 fd = open(NFSD_PORTS_FILE, O_RDONLY);
107 /* problem opening file, assume that nothing is configured */
111 n = read(fd, buf, sizeof(buf));
114 xlog(D_GENERAL, "knfsd is currently %s", (n > 0) ? "up" : "down");
120 nfssvc_setfds(const struct addrinfo *hints, const char *node, const char *port)
122 int fd, on = 1, fac = L_ERROR;
123 int sockfd = -1, rc = 0;
124 struct addrinfo *addrhead = NULL, *addr;
125 char *proto, *family;
128 * if file can't be opened, then assume that it's not available and
129 * that the caller should just fall back to the old nfsctl interface
131 fd = open(NFSD_PORTS_FILE, O_WRONLY);
135 switch(hints->ai_family) {
139 #ifdef IPV6_SUPPORTED
143 #endif /* IPV6_SUPPORTED */
145 xlog(L_ERROR, "Unknown address family specified: %d\n",
151 rc = getaddrinfo(node, port, hints, &addrhead);
152 if (rc == EAI_NONAME && !strcmp(port, "nfs")) {
153 snprintf(buf, sizeof(buf), "%d", NFS_PORT);
154 rc = getaddrinfo(node, buf, hints, &addrhead);
158 xlog(L_ERROR, "unable to resolve %s:%s to %s address: "
159 "%s", node ? node : "ANYADDR", port, family,
160 rc == EAI_SYSTEM ? strerror(errno) :
167 /* skip non-TCP / non-UDP sockets */
168 switch(addr->ai_protocol) {
176 addr = addr->ai_next;
180 xlog(D_GENERAL, "Creating %s %s socket.", family, proto);
182 /* open socket and prepare to hand it off to kernel */
183 sockfd = socket(addr->ai_family, addr->ai_socktype,
186 xlog(L_ERROR, "unable to create %s %s socket: "
187 "errno %d (%m)", family, proto, errno);
191 #ifdef IPV6_SUPPORTED
192 if (addr->ai_family == AF_INET6 &&
193 setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) {
194 xlog(L_ERROR, "unable to set IPV6_V6ONLY: "
195 "errno %d (%m)\n", errno);
199 #endif /* IPV6_SUPPORTED */
200 if (addr->ai_protocol == IPPROTO_TCP &&
201 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) {
202 xlog(L_ERROR, "unable to set SO_REUSEADDR on %s "
203 "socket: errno %d (%m)", family, errno);
207 if (bind(sockfd, addr->ai_addr, addr->ai_addrlen)) {
208 xlog(L_ERROR, "unable to bind %s %s socket: "
209 "errno %d (%m)", family, proto, errno);
213 if (addr->ai_protocol == IPPROTO_TCP && listen(sockfd, 64)) {
214 xlog(L_ERROR, "unable to create listening socket: "
215 "errno %d (%m)", errno);
221 fd = open(NFSD_PORTS_FILE, O_WRONLY);
224 xlog(L_ERROR, "couldn't open ports file: errno "
229 snprintf(buf, sizeof(buf), "%d\n", sockfd);
230 if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
232 * this error may be common on older kernels that don't
233 * support IPv6, so turn into a debug message.
235 if (errno == EAFNOSUPPORT)
237 xlog(fac, "writing fd to kernel failed: errno %d (%m)",
245 addr = addr->ai_next;
253 freeaddrinfo(addrhead);
258 nfssvc_set_sockets(const int family, const unsigned int protobits,
259 const char *host, const char *port)
261 struct addrinfo hints = { .ai_flags = AI_PASSIVE };
263 hints.ai_family = family;
265 if (!NFSCTL_ANYPROTO(protobits))
267 else if (!NFSCTL_UDPISSET(protobits))
268 hints.ai_protocol = IPPROTO_TCP;
269 else if (!NFSCTL_TCPISSET(protobits))
270 hints.ai_protocol = IPPROTO_UDP;
272 return nfssvc_setfds(&hints, host, port);
276 nfssvc_setvers(unsigned int ctlbits, int minorvers4)
283 fd = open(NFSD_VERS_FILE, O_WRONLY);
287 n = minorvers4 >= 0 ? minorvers4 : -minorvers4;
288 if (n >= NFSD_MINMINORVERS4 && n <= NFSD_MAXMINORVERS4)
289 off += snprintf(ptr+off, sizeof(buf) - off, "%c4.%d ",
290 minorvers4 > 0 ? '+' : '-',
292 for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) {
293 if (NFSCTL_VERISSET(ctlbits, n))
294 off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n);
296 off += snprintf(ptr+off, sizeof(buf) - off, "-%d ", n);
298 xlog(D_GENERAL, "Writing version string to kernel: %s", buf);
299 snprintf(ptr+off, sizeof(buf) - off, "\n");
300 if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
301 xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno);
309 nfssvc_threads(unsigned short port, const int nrservs)
311 struct nfsctl_arg arg;
316 fd = open(NFSD_THREAD_FILE, O_WRONLY);
318 fd = open("/proc/fs/nfs/threads", O_WRONLY);
320 /* 2.5+ kernel with nfsd filesystem mounted.
321 * Just write the number of threads.
323 snprintf(buf, sizeof(buf), "%d\n", nrservs);
324 n = write(fd, buf, strlen(buf));
326 if (n != (ssize_t)strlen(buf))
333 ent = getservbyname("nfs", "udp");
335 port = ntohs(ent->s_port);
340 arg.ca_version = NFSCTL_VERSION;
341 arg.ca_svc.svc_nthreads = nrservs;
342 arg.ca_svc.svc_port = port;
343 return nfsctl(NFSCTL_SVC, &arg, NULL);