a6ea410226f193d5f22def299ff9d9a57914682a
[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, 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_WRONLY);
37         if (fd < 0)
38                 return;
39         sin.sin_family = AF_INET;
40         sin.sin_port   = htons(port);
41         sin.sin_addr.s_addr =  inet_addr(haddr);
42
43         if (NFSCTL_UDPISSET(ctlbits)) {
44                 udpfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
45                 if (udpfd < 0) {
46                         syslog(LOG_ERR, "nfssvc: unable to create UPD socket: "
47                                 "errno %d (%s)\n", errno, strerror(errno));
48                         exit(1);
49                 }
50                 if (bind(udpfd, (struct  sockaddr  *)&sin, sizeof(sin)) < 0){
51                         syslog(LOG_ERR, "nfssvc: unable to bind UPD socket: "
52                                 "errno %d (%s)\n", errno, strerror(errno));
53                         exit(1);
54                 }
55         }
56
57         if (NFSCTL_TCPISSET(ctlbits)) {
58                 tcpfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
59                 if (tcpfd < 0) {
60                         syslog(LOG_ERR, "nfssvc: unable to createt tcp socket: "
61                                 "errno %d (%s)\n", errno, strerror(errno));
62                         exit(1);
63                 }
64                 if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
65                         syslog(LOG_ERR, "nfssvc: unable to set SO_REUSEADDR: "
66                                 "errno %d (%s)\n", errno, strerror(errno));
67                         exit(1);
68                 }
69                 if (bind(tcpfd, (struct  sockaddr  *)&sin, sizeof(sin)) < 0){
70                         syslog(LOG_ERR, "nfssvc: unable to bind TCP socket: "
71                                 "errno %d (%s)\n", errno, strerror(errno));
72                         exit(1);
73                 }
74                 if (listen(tcpfd, 64) < 0){
75                         syslog(LOG_ERR, "nfssvc: unable to create listening socket: "
76                                 "errno %d (%s)\n", errno, strerror(errno));
77                         exit(1);
78                 }
79         }
80         if (udpfd >= 0) {
81                 snprintf(buf, BUFSIZ,"%d\n", udpfd); 
82                 if (write(fd, buf, strlen(buf)) != strlen(buf)) {
83                         syslog(LOG_ERR, 
84                                "nfssvc: writting fds to kernel failed: errno %d (%s)", 
85                                errno, strerror(errno));
86                 }
87                 close(fd);
88                 fd = -1;
89         }
90         if (tcpfd >= 0) {
91                 if (fd < 0)
92                         fd = open(NFSD_PORTS_FILE, O_WRONLY);
93                 snprintf(buf, BUFSIZ,"%d\n", tcpfd); 
94                 if (write(fd, buf, strlen(buf)) != strlen(buf)) {
95                         syslog(LOG_ERR, 
96                                "nfssvc: writting fds to kernel failed: errno %d (%s)", 
97                                errno, strerror(errno));
98                 }
99         }
100         close(fd);
101
102         return;
103 }
104 static void
105 nfssvc_versbits(unsigned int ctlbits)
106 {
107         int fd, n, off;
108         char buf[BUFSIZ], *ptr;
109
110         ptr = buf;
111         off = 0;
112         fd = open(NFSD_VERS_FILE, O_WRONLY);
113         if (fd < 0)
114                 return;
115
116         for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) {
117                 if (NFSCTL_VERISSET(ctlbits, n))
118                     off += snprintf(ptr+off, BUFSIZ - off, "+%d ", n);
119                 else
120                     off += snprintf(ptr+off, BUFSIZ - off, "-%d ", n);
121         }
122         snprintf(ptr+off, BUFSIZ - off, "\n");
123         if (write(fd, buf, strlen(buf)) != strlen(buf)) {
124                 syslog(LOG_ERR, "nfssvc: Setting version failed: errno %d (%s)", 
125                         errno, strerror(errno));
126         }
127         close(fd);
128
129         return;
130 }
131 int
132 nfssvc(int port, int nrservs, unsigned int versbits, unsigned protobits,
133         char *haddr)
134 {
135         struct nfsctl_arg       arg;
136         int fd;
137
138         nfssvc_setfds(port, protobits, haddr);
139
140         nfssvc_versbits(versbits);
141
142         fd = open(NFSD_THREAD_FILE, O_WRONLY);
143         if (fd < 0)
144                 fd = open("/proc/fs/nfs/threads", O_WRONLY);
145         if (fd >= 0) {
146                 /* 2.5+ kernel with nfsd filesystem mounted.
147                  * Just write the number in.
148                  * Cannot handle port number yet, but does anyone care?
149                  */
150                 char buf[20];
151                 int n;
152                 snprintf(buf, 20,"%d\n", nrservs);
153                 n = write(fd, buf, strlen(buf));
154                 close(fd);
155                 if (n != strlen(buf))
156                         return -1;
157                 else
158                         return 0;
159         }
160
161         arg.ca_version = NFSCTL_VERSION;
162         arg.ca_svc.svc_nthreads = nrservs;
163         arg.ca_svc.svc_port = port;
164         return nfsctl(NFSCTL_SVC, &arg, NULL);
165 }