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 #define NFSD_FS_DIR "/proc/fs/nfsd"
31 #define NFSD_PORTS_FILE NFSD_FS_DIR "/portlist"
32 #define NFSD_VERS_FILE NFSD_FS_DIR "/versions"
33 #define NFSD_THREAD_FILE NFSD_FS_DIR "/threads"
36 * declaring a common static scratch buffer here keeps us from having to
37 * continually thrash the stack. The value of 128 bytes here is really just a
38 * SWAG and can be increased if necessary. It ought to be enough for the
39 * routines below however.
44 * Using the "new" interfaces for nfsd requires that /proc/fs/nfsd is
45 * actually mounted. Make an attempt to mount it here if it doesn't appear
46 * to be. If the mount attempt fails, no big deal -- fall back to using nfsctl
50 nfssvc_mount_nfsdfs(char *progname)
55 err = stat(NFSD_THREAD_FILE, &statbuf);
59 if (errno != ENOENT) {
60 xlog(L_ERROR, "Unable to stat %s: errno %d (%m)",
61 NFSD_THREAD_FILE, errno);
66 * this call can return an error if modprobe is set up to automatically
67 * mount nfsdfs when nfsd.ko is plugged in. So, ignore the return
68 * code from it and just check for the "threads" file afterward.
70 system("/bin/mount -t nfsd nfsd " NFSD_FS_DIR " >/dev/null 2>&1");
72 err = stat(NFSD_THREAD_FILE, &statbuf);
76 xlog(L_WARNING, "Unable to access " NFSD_FS_DIR " errno %d (%m)."
77 "\nPlease try, as root, 'mount -t nfsd nfsd " NFSD_FS_DIR
78 "' and then restart %s to correct the problem", errno, progname);
84 * Are there already sockets configured? If not, then it is safe to try to
85 * open some and pass them through.
87 * Note: If the user explicitly asked for 'udp', then we should probably check
88 * if that is open, and should open it if not. However we don't yet. All
89 * sockets have to be opened when the first daemon is started.
96 fd = open(NFSD_PORTS_FILE, O_RDONLY);
98 /* problem opening file, assume that nothing is configured */
102 n = read(fd, buf, sizeof(buf));
105 xlog(D_GENERAL, "knfsd is currently %s", (n > 0) ? "up" : "down");
111 nfssvc_setfds(const struct addrinfo *hints, const char *node, const char *port)
113 int fd, on = 1, fac = L_ERROR;
114 int sockfd = -1, rc = 0;
115 struct addrinfo *addrhead = NULL, *addr;
116 char *proto, *family;
119 * if file can't be opened, then assume that it's not available and
120 * that the caller should just fall back to the old nfsctl interface
122 fd = open(NFSD_PORTS_FILE, O_WRONLY);
126 switch(hints->ai_family) {
130 #ifdef IPV6_SUPPORTED
134 #endif /* IPV6_SUPPORTED */
136 xlog(L_ERROR, "Unknown address family specified: %d\n",
142 rc = getaddrinfo(node, port, hints, &addrhead);
143 if (rc == EAI_NONAME && !strcmp(port, "nfs")) {
144 snprintf(buf, sizeof(buf), "%d", NFS_PORT);
145 rc = getaddrinfo(node, buf, hints, &addrhead);
149 xlog(L_ERROR, "unable to resolve %s:%s to %s address: "
150 "%s", node ? node : "ANYADDR", port, family,
151 rc == EAI_SYSTEM ? strerror(errno) :
158 /* skip non-TCP / non-UDP sockets */
159 switch(addr->ai_protocol) {
167 addr = addr->ai_next;
171 xlog(D_GENERAL, "Creating %s %s socket.", family, proto);
173 /* open socket and prepare to hand it off to kernel */
174 sockfd = socket(addr->ai_family, addr->ai_socktype,
177 if (errno == EAFNOSUPPORT)
178 xlog(L_NOTICE, "address family %s not "
179 "supported by protocol %s",
182 xlog(L_ERROR, "unable to create %s %s socket: "
183 "errno %d (%m)", family, proto, errno);
187 #ifdef IPV6_SUPPORTED
188 if (addr->ai_family == AF_INET6 &&
189 setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) {
190 xlog(L_ERROR, "unable to set IPV6_V6ONLY: "
191 "errno %d (%m)\n", errno);
195 #endif /* IPV6_SUPPORTED */
196 if (addr->ai_protocol == IPPROTO_TCP &&
197 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) {
198 xlog(L_ERROR, "unable to set SO_REUSEADDR on %s "
199 "socket: errno %d (%m)", family, errno);
203 if (bind(sockfd, addr->ai_addr, addr->ai_addrlen)) {
204 xlog(L_ERROR, "unable to bind %s %s socket: "
205 "errno %d (%m)", family, proto, errno);
209 if (addr->ai_protocol == IPPROTO_TCP && listen(sockfd, 64)) {
210 xlog(L_ERROR, "unable to create listening socket: "
211 "errno %d (%m)", errno);
217 fd = open(NFSD_PORTS_FILE, O_WRONLY);
220 xlog(L_ERROR, "couldn't open ports file: errno "
225 snprintf(buf, sizeof(buf), "%d\n", sockfd);
226 if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
228 * this error may be common on older kernels that don't
229 * support IPv6, so turn into a debug message.
231 if (errno == EAFNOSUPPORT)
233 xlog(fac, "writing fd to kernel failed: errno %d (%m)",
241 addr = addr->ai_next;
249 freeaddrinfo(addrhead);
254 nfssvc_set_sockets(const int family, const unsigned int protobits,
255 const char *host, const char *port)
257 struct addrinfo hints = { .ai_flags = AI_PASSIVE };
259 hints.ai_family = family;
261 if (!NFSCTL_ANYPROTO(protobits))
263 else if (!NFSCTL_UDPISSET(protobits))
264 hints.ai_protocol = IPPROTO_TCP;
265 else if (!NFSCTL_TCPISSET(protobits))
266 hints.ai_protocol = IPPROTO_UDP;
268 return nfssvc_setfds(&hints, host, port);
272 nfssvc_setvers(unsigned int ctlbits, int minorvers41)
279 fd = open(NFSD_VERS_FILE, O_WRONLY);
284 off += snprintf(ptr+off, sizeof(buf) - off, "%c4.1",
285 minorvers41 > 0 ? '+' : '-');
286 for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) {
287 if (NFSCTL_VERISSET(ctlbits, n))
288 off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n);
290 off += snprintf(ptr+off, sizeof(buf) - off, "-%d ", n);
292 xlog(D_GENERAL, "Writing version string to kernel: %s", buf);
293 snprintf(ptr+off, sizeof(buf) - off, "\n");
294 if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
295 xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno);
303 nfssvc_threads(unsigned short port, const int nrservs)
305 struct nfsctl_arg arg;
310 fd = open(NFSD_THREAD_FILE, O_WRONLY);
312 fd = open("/proc/fs/nfs/threads", O_WRONLY);
314 /* 2.5+ kernel with nfsd filesystem mounted.
315 * Just write the number of threads.
317 snprintf(buf, sizeof(buf), "%d\n", nrservs);
318 n = write(fd, buf, strlen(buf));
320 if (n != (ssize_t)strlen(buf))
327 ent = getservbyname("nfs", "udp");
329 port = ntohs(ent->s_port);
334 arg.ca_version = NFSCTL_VERSION;
335 arg.ca_svc.svc_nthreads = nrservs;
336 arg.ca_svc.svc_port = port;
337 return nfsctl(NFSCTL_SVC, &arg, NULL);