]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/nfsd/nfssvc.c
7ecaea9e76cc26eee99037a9897794ceafbe4017
[nfs-utils.git] / utils / nfsd / nfssvc.c
1 /*
2  * utils/nfsd/nfssvc.c
3  *
4  * Run an NFS daemon.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <errno.h>
19
20 #include "nfslib.h"
21 #include "xlog.h"
22
23 #define NFSD_PORTS_FILE     "/proc/fs/nfsd/portlist"
24 #define NFSD_VERS_FILE    "/proc/fs/nfsd/versions"
25 #define NFSD_THREAD_FILE  "/proc/fs/nfsd/threads"
26
27 /*
28  * declaring a common static scratch buffer here keeps us from having to
29  * continually thrash the stack. The value of 128 bytes here is really just a
30  * SWAG and can be increased if necessary. It ought to be enough for the
31  * routines below however.
32  */
33 char buf[128];
34
35 /*
36  * Are there already sockets configured? If not, then it is safe to try to
37  * open some and pass them through.
38  *
39  * Note: If the user explicitly asked for 'udp', then we should probably check
40  * if that is open, and should open it if not. However we don't yet. All
41  * sockets have to be opened when the first daemon is started.
42  */
43 int
44 nfssvc_inuse(void)
45 {
46         int fd, n;
47
48         fd = open(NFSD_PORTS_FILE, O_RDONLY);
49
50         /* problem opening file, assume that nothing is configured */
51         if (fd < 0)
52                 return 0;
53
54         n = read(fd, buf, sizeof(buf));
55         close(fd);
56
57         xlog(D_GENERAL, "knfsd is currently %s", (n > 0) ? "up" : "down");
58
59         return (n > 0);
60 }
61
62 static void
63 nfssvc_setfds(int port, unsigned int ctlbits, char *haddr)
64 {
65         int fd, on=1;
66         int udpfd = -1, tcpfd = -1;
67         struct sockaddr_in sin;
68
69         if (nfssvc_inuse())
70                 return;
71
72         fd = open(NFSD_PORTS_FILE, O_WRONLY);
73         if (fd < 0)
74                 return;
75         sin.sin_family = AF_INET;
76         sin.sin_port   = htons(port);
77         sin.sin_addr.s_addr =  inet_addr(haddr);
78
79         if (NFSCTL_UDPISSET(ctlbits)) {
80                 udpfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
81                 if (udpfd < 0) {
82                         xlog(L_ERROR, "unable to create UDP socket: "
83                                 "errno %d (%m)", errno);
84                         exit(1);
85                 }
86                 if (bind(udpfd, (struct  sockaddr  *)&sin, sizeof(sin)) < 0){
87                         xlog(L_ERROR, "unable to bind UDP socket: "
88                                 "errno %d (%m)", errno);
89                         exit(1);
90                 }
91         }
92
93         if (NFSCTL_TCPISSET(ctlbits)) {
94                 tcpfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
95                 if (tcpfd < 0) {
96                         xlog(L_ERROR, "unable to create TCP socket: "
97                                 "errno %d (%m)", errno);
98                         exit(1);
99                 }
100                 if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
101                         xlog(L_ERROR, "unable to set SO_REUSEADDR: "
102                                 "errno %d (%m)", errno);
103                         exit(1);
104                 }
105                 if (bind(tcpfd, (struct  sockaddr  *)&sin, sizeof(sin)) < 0){
106                         xlog(L_ERROR, "unable to bind TCP socket: "
107                                 "errno %d (%m)", errno);
108                         exit(1);
109                 }
110                 if (listen(tcpfd, 64) < 0){
111                         xlog(L_ERROR, "unable to create listening socket: "
112                                 "errno %d (%m)", errno);
113                         exit(1);
114                 }
115         }
116         if (udpfd >= 0) {
117                 snprintf(buf, sizeof(buf), "%d\n", udpfd); 
118                 if (write(fd, buf, strlen(buf)) != strlen(buf)) {
119                         xlog(L_ERROR, 
120                                "writing fds to kernel failed: errno %d (%m)", 
121                                errno);
122                 }
123                 close(fd);
124                 fd = -1;
125         }
126         if (tcpfd >= 0) {
127                 if (fd < 0)
128                         fd = open(NFSD_PORTS_FILE, O_WRONLY);
129                 snprintf(buf, sizeof(buf), "%d\n", tcpfd); 
130                 if (write(fd, buf, strlen(buf)) != strlen(buf)) {
131                         xlog(L_ERROR, 
132                                "writing fds to kernel failed: errno %d (%m)", 
133                                errno);
134                 }
135         }
136         close(fd);
137
138         return;
139 }
140 static void
141 nfssvc_versbits(unsigned int ctlbits, int minorvers4)
142 {
143         int fd, n, off;
144         char *ptr;
145
146         ptr = buf;
147         off = 0;
148         fd = open(NFSD_VERS_FILE, O_WRONLY);
149         if (fd < 0)
150                 return;
151
152         for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) {
153                 if (NFSCTL_VERISSET(ctlbits, n))
154                     off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n);
155                 else
156                     off += snprintf(ptr+off, sizeof(buf) - off, "-%d ", n);
157         }
158         n = minorvers4 >= 0 ? minorvers4 : -minorvers4;
159         if (n >= NFSD_MINMINORVERS4 && n <= NFSD_MAXMINORVERS4)
160                     off += snprintf(ptr+off, sizeof(buf) - off, "%c4.%d",
161                                     minorvers4 > 0 ? '+' : '-',
162                                     n);
163         xlog(D_GENERAL, "Writing version string to kernel: %s", buf);
164         snprintf(ptr+off, sizeof(buf) - off, "\n");
165         if (write(fd, buf, strlen(buf)) != strlen(buf))
166                 xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno);
167
168         close(fd);
169
170         return;
171 }
172 int
173 nfssvc(int port, int nrservs, unsigned int versbits, int minorvers4,
174         unsigned protobits, char *haddr)
175 {
176         struct nfsctl_arg       arg;
177         int fd;
178
179         /* Note: must set versions before fds so that
180          * the ports get registered with portmap against correct
181          * versions
182          */
183         nfssvc_versbits(versbits, minorvers4);
184         nfssvc_setfds(port, protobits, haddr);
185
186         fd = open(NFSD_THREAD_FILE, O_WRONLY);
187         if (fd < 0)
188                 fd = open("/proc/fs/nfs/threads", O_WRONLY);
189         if (fd >= 0) {
190                 /* 2.5+ kernel with nfsd filesystem mounted.
191                  * Just write the number in.
192                  * Cannot handle port number yet, but does anyone care?
193                  */
194                 int n;
195                 snprintf(buf, sizeof(buf), "%d\n", nrservs);
196                 n = write(fd, buf, strlen(buf));
197                 close(fd);
198                 if (n != strlen(buf))
199                         return -1;
200                 else
201                         return 0;
202         }
203
204         arg.ca_version = NFSCTL_VERSION;
205         arg.ca_svc.svc_nthreads = nrservs;
206         arg.ca_svc.svc_port = port;
207         return nfsctl(NFSCTL_SVC, &arg, NULL);
208 }