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>
26 * IPv6 support for nfsd was finished before some of the other daemons (mountd
27 * and statd in particular). That could be a problem in the future if someone
28 * were to boot a kernel that supports IPv6 serving with an older nfs-utils. For
29 * now, hardcode the IPv6 switch into the off position until the other daemons
34 #define NFSD_PORTS_FILE "/proc/fs/nfsd/portlist"
35 #define NFSD_VERS_FILE "/proc/fs/nfsd/versions"
36 #define NFSD_THREAD_FILE "/proc/fs/nfsd/threads"
39 * declaring a common static scratch buffer here keeps us from having to
40 * continually thrash the stack. The value of 128 bytes here is really just a
41 * SWAG and can be increased if necessary. It ought to be enough for the
42 * routines below however.
47 * Are there already sockets configured? If not, then it is safe to try to
48 * open some and pass them through.
50 * Note: If the user explicitly asked for 'udp', then we should probably check
51 * if that is open, and should open it if not. However we don't yet. All
52 * sockets have to be opened when the first daemon is started.
59 fd = open(NFSD_PORTS_FILE, O_RDONLY);
61 /* problem opening file, assume that nothing is configured */
65 n = read(fd, buf, sizeof(buf));
68 xlog(D_GENERAL, "knfsd is currently %s", (n > 0) ? "up" : "down");
74 nfssvc_setfds(const struct addrinfo *hints, const char *node, const char *port)
76 int fd, on = 1, fac = L_ERROR;
77 int sockfd = -1, rc = 0;
78 struct addrinfo *addrhead = NULL, *addr;
82 * if file can't be opened, then assume that it's not available and
83 * that the caller should just fall back to the old nfsctl interface
85 fd = open(NFSD_PORTS_FILE, O_WRONLY);
89 switch(hints->ai_family) {
97 #endif /* IPV6_SUPPORTED */
99 xlog(L_ERROR, "Unknown address family specified: %d\n",
105 rc = getaddrinfo(node, port, hints, &addrhead);
106 if (rc == EAI_NONAME && !strcmp(port, "nfs")) {
107 snprintf(buf, sizeof(buf), "%d", NFS_PORT);
108 rc = getaddrinfo(node, buf, hints, &addrhead);
112 xlog(L_ERROR, "unable to resolve %s:%s to %s address: "
113 "%s", node ? node : "ANYADDR", port, family,
114 rc == EAI_SYSTEM ? strerror(errno) :
121 /* skip non-TCP / non-UDP sockets */
122 switch(addr->ai_protocol) {
130 addr = addr->ai_next;
134 xlog(D_GENERAL, "Creating %s %s socket.", family, proto);
136 /* open socket and prepare to hand it off to kernel */
137 sockfd = socket(addr->ai_family, addr->ai_socktype,
140 xlog(L_ERROR, "unable to create %s %s socket: "
141 "errno %d (%m)", family, proto, errno);
145 #ifdef IPV6_SUPPORTED
146 if (addr->ai_family == AF_INET6 &&
147 setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) {
148 xlog(L_ERROR, "unable to set IPV6_V6ONLY: "
149 "errno %d (%m)\n", errno);
153 #endif /* IPV6_SUPPORTED */
154 if (addr->ai_protocol == IPPROTO_TCP &&
155 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) {
156 xlog(L_ERROR, "unable to set SO_REUSEADDR on %s "
157 "socket: errno %d (%m)", family, errno);
161 if (bind(sockfd, addr->ai_addr, addr->ai_addrlen)) {
162 xlog(L_ERROR, "unable to bind %s %s socket: "
163 "errno %d (%m)", family, proto, errno);
167 if (addr->ai_protocol == IPPROTO_TCP && listen(sockfd, 64)) {
168 xlog(L_ERROR, "unable to create listening socket: "
169 "errno %d (%m)", errno);
175 fd = open(NFSD_PORTS_FILE, O_WRONLY);
178 xlog(L_ERROR, "couldn't open ports file: errno "
183 snprintf(buf, sizeof(buf), "%d\n", sockfd);
184 if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
186 * this error may be common on older kernels that don't
187 * support IPv6, so turn into a debug message.
189 if (errno == EAFNOSUPPORT)
191 xlog(fac, "writing fd to kernel failed: errno %d (%m)",
199 addr = addr->ai_next;
207 freeaddrinfo(addrhead);
212 nfssvc_set_sockets(const int family, const unsigned int protobits,
213 const char *host, const char *port)
215 struct addrinfo hints = { .ai_flags = AI_PASSIVE };
217 hints.ai_family = family;
219 if (!NFSCTL_ANYPROTO(protobits))
221 else if (!NFSCTL_UDPISSET(protobits))
222 hints.ai_protocol = IPPROTO_TCP;
223 else if (!NFSCTL_TCPISSET(protobits))
224 hints.ai_protocol = IPPROTO_UDP;
226 return nfssvc_setfds(&hints, host, port);
230 nfssvc_setvers(unsigned int ctlbits, int minorvers4)
237 fd = open(NFSD_VERS_FILE, O_WRONLY);
241 n = minorvers4 >= 0 ? minorvers4 : -minorvers4;
242 if (n >= NFSD_MINMINORVERS4 && n <= NFSD_MAXMINORVERS4)
243 off += snprintf(ptr+off, sizeof(buf) - off, "%c4.%d ",
244 minorvers4 > 0 ? '+' : '-',
246 for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) {
247 if (NFSCTL_VERISSET(ctlbits, n))
248 off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n);
250 off += snprintf(ptr+off, sizeof(buf) - off, "-%d ", n);
252 xlog(D_GENERAL, "Writing version string to kernel: %s", buf);
253 snprintf(ptr+off, sizeof(buf) - off, "\n");
254 if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
255 xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno);
263 nfssvc_threads(unsigned short port, const int nrservs)
265 struct nfsctl_arg arg;
270 fd = open(NFSD_THREAD_FILE, O_WRONLY);
272 fd = open("/proc/fs/nfs/threads", O_WRONLY);
274 /* 2.5+ kernel with nfsd filesystem mounted.
275 * Just write the number of threads.
277 snprintf(buf, sizeof(buf), "%d\n", nrservs);
278 n = write(fd, buf, strlen(buf));
280 if (n != (ssize_t)strlen(buf))
287 ent = getservbyname("nfs", "udp");
289 port = ntohs(ent->s_port);
294 arg.ca_version = NFSCTL_VERSION;
295 arg.ca_svc.svc_nthreads = nrservs;
296 arg.ca_svc.svc_port = port;
297 return nfsctl(NFSCTL_SVC, &arg, NULL);