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