]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/nfsd/nfsd.c
nfs-utils: Fix source code character encoding
[nfs-utils.git] / utils / nfsd / nfsd.c
1 /*
2  * nfsd
3  *
4  * This is the user level part of nfsd. This is very primitive, because
5  * all the work is now done in the kernel module.
6  *
7  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
8  */
9
10 #ifdef HAVE_CONFIG_H
11 #include <config.h>
12 #endif
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <getopt.h>
21 #include <netdb.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25
26 #include "nfslib.h"
27 #include "nfssvc.h"
28 #include "xlog.h"
29
30 /*
31  * IPv6 support for nfsd was finished before some of the other daemons (mountd
32  * and statd in particular). That could be a problem in the future if someone
33  * were to boot a kernel that supports IPv6 serving with  an older nfs-utils. For
34  * now, hardcode the IPv6 switch into the off position until the other daemons
35  * are functional.
36  */
37 #undef IPV6_SUPPORTED
38
39 static void     usage(const char *);
40
41 static struct option longopts[] =
42 {
43         { "host", 1, 0, 'H' },
44         { "help", 0, 0, 'h' },
45         { "no-nfs-version", 1, 0, 'N' },
46         { "no-tcp", 0, 0, 'T' },
47         { "no-udp", 0, 0, 'U' },
48         { "port", 1, 0, 'P' },
49         { "port", 1, 0, 'p' },
50         { "debug", 0, 0, 'd' },
51         { "syslog", 0, 0, 's' },
52         { NULL, 0, 0, 0 }
53 };
54
55 /* given a family and ctlbits, disable any that aren't listed in netconfig */
56 #ifdef HAVE_LIBTIRPC
57 static void
58 nfsd_enable_protos(unsigned int *proto4, unsigned int *proto6)
59 {
60         struct netconfig *nconf;
61         unsigned int *famproto;
62         void *handle;
63
64         xlog(D_GENERAL, "Checking netconfig for visible protocols.");
65
66         handle = setnetconfig();
67         while((nconf = getnetconfig(handle))) {
68                 if (!(nconf->nc_flag & NC_VISIBLE))
69                         continue;
70
71                 if (!strcmp(nconf->nc_protofmly, NC_INET))
72                         famproto = proto4;
73                 else if (!strcmp(nconf->nc_protofmly, NC_INET6))
74                         famproto = proto6;
75                 else
76                         continue;
77
78                 if (!strcmp(nconf->nc_proto, NC_TCP))
79                         NFSCTL_TCPSET(*famproto);
80                 else if (!strcmp(nconf->nc_proto, NC_UDP))
81                         NFSCTL_UDPSET(*famproto);
82
83                 xlog(D_GENERAL, "Enabling %s %s.", nconf->nc_protofmly,
84                         nconf->nc_proto);
85         }
86         endnetconfig(handle);
87         return;
88 }
89 #else /* HAVE_LIBTIRPC */
90 static void
91 nfsd_enable_protos(unsigned int *proto4, unsigned int *proto6)
92 {
93         /* Enable all IPv4 protocols if no TIRPC support */
94         *proto4 = NFSCTL_ALLBITS;
95         *proto6 = 0;
96 }
97 #endif /* HAVE_LIBTIRPC */
98
99 int
100 main(int argc, char **argv)
101 {
102         int     count = 1, c, error = 0, portnum = 0, fd, found_one;
103         char *p, *progname, *port;
104         char *haddr = NULL;
105         int     socket_up = 0;
106         int minorvers4 = NFSD_MAXMINORVERS4;    /* nfsv4 minor version */
107         unsigned int versbits = NFSCTL_ALLBITS;
108         unsigned int protobits = NFSCTL_ALLBITS;
109         unsigned int proto4 = 0;
110         unsigned int proto6 = 0;
111
112         progname = strdup(basename(argv[0]));
113         if (!progname) {
114                 fprintf(stderr, "%s: unable to allocate memory.\n", argv[0]);
115                 exit(1);
116         }
117
118         port = strdup("nfs");
119         if (!port) {
120                 fprintf(stderr, "%s: unable to allocate memory.\n", progname);
121                 exit(1);
122         }
123
124         xlog_syslog(0);
125         xlog_stderr(1);
126
127         while ((c = getopt_long(argc, argv, "dH:hN:p:P:sTU", longopts, NULL)) != EOF) {
128                 switch(c) {
129                 case 'd':
130                         xlog_config(D_ALL, 1);
131                         break;
132                 case 'H':
133                         /*
134                          * for now, this only handles one -H option. Use the
135                          * last one specified.
136                          */
137                         free(haddr);
138                         haddr = strdup(optarg);
139                         if (!haddr) {
140                                 fprintf(stderr, "%s: unable to allocate "
141                                         "memory.\n", progname);
142                                 exit(1);
143                         }
144                         break;
145                 case 'P':       /* XXX for nfs-server compatibility */
146                 case 'p':
147                         /* only the last -p option has any effect */
148                         portnum = atoi(optarg);
149                         if (portnum <= 0 || portnum > 65535) {
150                                 fprintf(stderr, "%s: bad port number: %s\n",
151                                         progname, optarg);
152                                 usage(progname);
153                         }
154                         free(port);
155                         port = strdup(optarg);
156                         if (!port) {
157                                 fprintf(stderr, "%s: unable to allocate "
158                                                 "memory.\n", progname);
159                                 exit(1);
160                         }
161                         break;
162                 case 'N':
163                         switch((c = strtol(optarg, &p, 0))) {
164                         case 4:
165                                 if (*p == '.') {
166                                         minorvers4 = -atoi(p + 1);
167                                         break;
168                                 }
169                         case 3:
170                         case 2:
171                                 NFSCTL_VERUNSET(versbits, c);
172                                 break;
173                         default:
174                                 fprintf(stderr, "%s: Unsupported version\n", optarg);
175                                 exit(1);
176                         }
177                         break;
178                 case 's':
179                         xlog_syslog(1);
180                         xlog_stderr(0);
181                         break;
182                 case 'T':
183                         NFSCTL_TCPUNSET(protobits);
184                         break;
185                 case 'U':
186                         NFSCTL_UDPUNSET(protobits);
187                         break;
188                 default:
189                         fprintf(stderr, "Invalid argument: '%c'\n", c);
190                 case 'h':
191                         usage(progname);
192                 }
193         }
194
195         if (optind < argc) {
196                 if ((count = atoi(argv[optind])) < 0) {
197                         /* insane # of servers */
198                         fprintf(stderr,
199                                 "%s: invalid server count (%d), using 1\n",
200                                 argv[0], count);
201                         count = 1;
202                 } else if (count == 0) {
203                         /*
204                          * don't bother setting anything else if the threads
205                          * are coming down anyway.
206                          */
207                         socket_up = 1;
208                         goto set_threads;
209                 }
210         }
211
212         xlog_open(progname);
213
214         nfsd_enable_protos(&proto4, &proto6);
215
216         if (!NFSCTL_TCPISSET(protobits)) {
217                 NFSCTL_TCPUNSET(proto4);
218                 NFSCTL_TCPUNSET(proto6);
219         }
220
221         if (!NFSCTL_UDPISSET(protobits)) {
222                 NFSCTL_UDPUNSET(proto4);
223                 NFSCTL_UDPUNSET(proto6);
224         }
225
226         /* make sure that at least one version is enabled */
227         found_one = 0;
228         for (c = NFSD_MINVERS; c <= NFSD_MAXVERS; c++) {
229                 if (NFSCTL_VERISSET(versbits, c))
230                         found_one = 1;
231         }
232         if (!found_one) {
233                 xlog(L_ERROR, "no version specified");
234                 exit(1);
235         }                       
236
237         if (NFSCTL_VERISSET(versbits, 4) &&
238             !NFSCTL_TCPISSET(proto4) &&
239             !NFSCTL_TCPISSET(proto6)) {
240                 xlog(L_ERROR, "version 4 requires the TCP protocol");
241                 exit(1);
242         }
243
244         if (chdir(NFS_STATEDIR)) {
245                 xlog(L_ERROR, "chdir(%s) failed: %m", NFS_STATEDIR);
246                 exit(1);
247         }
248
249         /* make sure nfsdfs is mounted if it's available */
250         nfssvc_mount_nfsdfs(progname);
251
252         /* can only change number of threads if nfsd is already up */
253         if (nfssvc_inuse()) {
254                 socket_up = 1;
255                 goto set_threads;
256         }
257
258         /*
259          * must set versions before the fd's so that the right versions get
260          * registered with rpcbind. Note that on older kernels w/o the right
261          * interfaces, these are a no-op.
262          */
263         nfssvc_setvers(versbits, minorvers4);
264  
265         error = nfssvc_set_sockets(AF_INET, proto4, haddr, port);
266         if (!error)
267                 socket_up = 1;
268
269 #ifdef IPV6_SUPPORTED
270         error = nfssvc_set_sockets(AF_INET6, proto6, haddr, port);
271         if (!error)
272                 socket_up = 1;
273 #endif /* IPV6_SUPPORTED */
274
275 set_threads:
276         /* don't start any threads if unable to hand off any sockets */
277         if (!socket_up) {
278                 xlog(L_ERROR, "unable to set any sockets for nfsd");
279                 goto out;
280         }
281         error = 0;
282
283         /*
284          * KLUDGE ALERT:
285          * Some kernels let nfsd kernel threads inherit open files
286          * from the program that spawns them (i.e. us).  So close
287          * everything before spawning kernel threads.  --Chip
288          */
289         fd = open("/dev/null", O_RDWR);
290         if (fd == -1)
291                 xlog(L_ERROR, "Unable to open /dev/null: %m");
292         else {
293                 /* switch xlog output to syslog since stderr is being closed */
294                 xlog_syslog(1);
295                 xlog_stderr(0);
296                 (void) dup2(fd, 0);
297                 (void) dup2(fd, 1);
298                 (void) dup2(fd, 2);
299         }
300         closeall(3);
301
302         if ((error = nfssvc_threads(portnum, count)) < 0)
303                 xlog(L_ERROR, "error starting threads: errno %d (%m)", errno);
304 out:
305         free(port);
306         free(haddr);
307         free(progname);
308         return (error != 0);
309 }
310
311 static void
312 usage(const char *prog)
313 {
314         fprintf(stderr, "Usage:\n"
315                 "%s [-d|--debug] [-H hostname] [-p|-P|--port port] [-N|--no-nfs-version version ] [-s|--syslog] [-T|--no-tcp] [-U|--no-udp] nrservs\n", 
316                 prog);
317         exit(2);
318 }