]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/nfsd/nfssvc.c
nfs-utils: convert rpc.nfsd to use xlog()
[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 static void
28 nfssvc_setfds(int port, unsigned int ctlbits, char *haddr)
29 {
30         int fd, n, on=1;
31         char buf[BUFSIZ];
32         int udpfd = -1, tcpfd = -1;
33         struct sockaddr_in sin;
34
35         fd = open(NFSD_PORTS_FILE, O_RDONLY);
36         if (fd < 0)
37                 return;
38         n = read(fd, buf, BUFSIZ);
39         close(fd);
40         if (n != 0)
41                 return;
42         /* there are no ports currently open, so it is safe to
43          * try to open some and pass them through.
44          * Note: If the user explicitly asked for 'udp', then
45          * we should probably check if that is open, and should
46          * open it if not.  However we don't yet.  All sockets
47          * have to be opened when the first daemon is started.
48          */
49         fd = open(NFSD_PORTS_FILE, O_WRONLY);
50         if (fd < 0)
51                 return;
52         sin.sin_family = AF_INET;
53         sin.sin_port   = htons(port);
54         sin.sin_addr.s_addr =  inet_addr(haddr);
55
56         if (NFSCTL_UDPISSET(ctlbits)) {
57                 udpfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
58                 if (udpfd < 0) {
59                         xlog(L_ERROR, "unable to create UDP socket: "
60                                 "errno %d (%m)", errno);
61                         exit(1);
62                 }
63                 if (bind(udpfd, (struct  sockaddr  *)&sin, sizeof(sin)) < 0){
64                         xlog(L_ERROR, "unable to bind UDP socket: "
65                                 "errno %d (%m)", errno);
66                         exit(1);
67                 }
68         }
69
70         if (NFSCTL_TCPISSET(ctlbits)) {
71                 tcpfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
72                 if (tcpfd < 0) {
73                         xlog(L_ERROR, "unable to create TCP socket: "
74                                 "errno %d (%m)", errno);
75                         exit(1);
76                 }
77                 if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
78                         xlog(L_ERROR, "unable to set SO_REUSEADDR: "
79                                 "errno %d (%m)", errno);
80                         exit(1);
81                 }
82                 if (bind(tcpfd, (struct  sockaddr  *)&sin, sizeof(sin)) < 0){
83                         xlog(L_ERROR, "unable to bind TCP socket: "
84                                 "errno %d (%m)", errno);
85                         exit(1);
86                 }
87                 if (listen(tcpfd, 64) < 0){
88                         xlog(L_ERROR, "unable to create listening socket: "
89                                 "errno %d (%m)", errno);
90                         exit(1);
91                 }
92         }
93         if (udpfd >= 0) {
94                 snprintf(buf, BUFSIZ,"%d\n", udpfd); 
95                 if (write(fd, buf, strlen(buf)) != strlen(buf)) {
96                         xlog(L_ERROR, 
97                                "writing fds to kernel failed: errno %d (%m)", 
98                                errno);
99                 }
100                 close(fd);
101                 fd = -1;
102         }
103         if (tcpfd >= 0) {
104                 if (fd < 0)
105                         fd = open(NFSD_PORTS_FILE, O_WRONLY);
106                 snprintf(buf, BUFSIZ,"%d\n", tcpfd); 
107                 if (write(fd, buf, strlen(buf)) != strlen(buf)) {
108                         xlog(L_ERROR, 
109                                "writing fds to kernel failed: errno %d (%m)", 
110                                errno);
111                 }
112         }
113         close(fd);
114
115         return;
116 }
117 static void
118 nfssvc_versbits(unsigned int ctlbits, int minorvers4)
119 {
120         int fd, n, off;
121         char buf[BUFSIZ], *ptr;
122
123         ptr = buf;
124         off = 0;
125         fd = open(NFSD_VERS_FILE, O_WRONLY);
126         if (fd < 0)
127                 return;
128
129         for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) {
130                 if (NFSCTL_VERISSET(ctlbits, n))
131                     off += snprintf(ptr+off, BUFSIZ - off, "+%d ", n);
132                 else
133                     off += snprintf(ptr+off, BUFSIZ - off, "-%d ", n);
134         }
135         n = minorvers4 >= 0 ? minorvers4 : -minorvers4;
136         if (n >= NFSD_MINMINORVERS4 && n <= NFSD_MAXMINORVERS4)
137                     off += snprintf(ptr+off, BUFSIZ - off, "%c4.%d",
138                                     minorvers4 > 0 ? '+' : '-',
139                                     n);
140         xlog(D_GENERAL, "Writing version string to kernel: %s", buf);
141         snprintf(ptr+off, BUFSIZ - off, "\n");
142         if (write(fd, buf, strlen(buf)) != strlen(buf))
143                 xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno);
144
145         close(fd);
146
147         return;
148 }
149 int
150 nfssvc(int port, int nrservs, unsigned int versbits, int minorvers4,
151         unsigned protobits, char *haddr)
152 {
153         struct nfsctl_arg       arg;
154         int fd;
155
156         /* Note: must set versions before fds so that
157          * the ports get registered with portmap against correct
158          * versions
159          */
160         nfssvc_versbits(versbits, minorvers4);
161         nfssvc_setfds(port, protobits, haddr);
162
163         fd = open(NFSD_THREAD_FILE, O_WRONLY);
164         if (fd < 0)
165                 fd = open("/proc/fs/nfs/threads", O_WRONLY);
166         if (fd >= 0) {
167                 /* 2.5+ kernel with nfsd filesystem mounted.
168                  * Just write the number in.
169                  * Cannot handle port number yet, but does anyone care?
170                  */
171                 char buf[20];
172                 int n;
173                 snprintf(buf, 20,"%d\n", nrservs);
174                 n = write(fd, buf, strlen(buf));
175                 close(fd);
176                 if (n != strlen(buf))
177                         return -1;
178                 else
179                         return 0;
180         }
181
182         arg.ca_version = NFSCTL_VERSION;
183         arg.ca_svc.svc_nthreads = nrservs;
184         arg.ca_svc.svc_port = port;
185         return nfsctl(NFSCTL_SVC, &arg, NULL);
186 }