]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/nfsd/nfsd.c
nfs-utils: convert nfssvc_setfds to use getaddrinfo
[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 static void     usage(const char *);
31
32 static struct option longopts[] =
33 {
34         { "host", 1, 0, 'H' },
35         { "help", 0, 0, 'h' },
36         { "no-nfs-version", 1, 0, 'N' },
37         { "no-tcp", 0, 0, 'T' },
38         { "no-udp", 0, 0, 'U' },
39         { "port", 1, 0, 'P' },
40         { "port", 1, 0, 'p' },
41         { "debug", 0, 0, 'd' },
42         { "syslog", 0, 0, 's' },
43         { NULL, 0, 0, 0 }
44 };
45 unsigned int protobits = NFSCTL_ALLBITS;
46 unsigned int versbits = NFSCTL_ALLBITS;
47 int minorvers4 = NFSD_MAXMINORVERS4;            /* nfsv4 minor version */
48
49 int
50 main(int argc, char **argv)
51 {
52         int     count = 1, c, error, portnum = 0, fd, found_one;
53         char *p, *progname, *port;
54         char *haddr = NULL;
55         int     socket_up = 0;
56
57         progname = strdup(basename(argv[0]));
58         if (!progname) {
59                 fprintf(stderr, "%s: unable to allocate memory.\n", argv[0]);
60                 exit(1);
61         }
62
63         port = strdup("nfs");
64         if (!port) {
65                 fprintf(stderr, "%s: unable to allocate memory.\n", progname);
66                 exit(1);
67         }
68
69         xlog_syslog(0);
70         xlog_stderr(1);
71
72         while ((c = getopt_long(argc, argv, "dH:hN:p:P:sTU", longopts, NULL)) != EOF) {
73                 switch(c) {
74                 case 'd':
75                         xlog_config(D_ALL, 1);
76                         break;
77                 case 'H':
78                         /*
79                          * for now, this only handles one -H option. Use the
80                          * last one specified.
81                          */
82                         free(haddr);
83                         haddr = strdup(optarg);
84                         if (!haddr) {
85                                 fprintf(stderr, "%s: unable to allocate "
86                                         "memory.\n", progname);
87                                 exit(1);
88                         }
89                         break;
90                 case 'P':       /* XXX for nfs-server compatibility */
91                 case 'p':
92                         /* only the last -p option has any effect */
93                         portnum = atoi(optarg);
94                         if (portnum <= 0 || portnum > 65535) {
95                                 fprintf(stderr, "%s: bad port number: %s\n",
96                                         progname, optarg);
97                                 usage(progname);
98                         }
99                         free(port);
100                         port = strdup(optarg);
101                         if (!port) {
102                                 fprintf(stderr, "%s: unable to allocate "
103                                                 "memory.\n", progname);
104                                 exit(1);
105                         }
106                         break;
107                 case 'N':
108                         switch((c = strtol(optarg, &p, 0))) {
109                         case 4:
110                                 if (*p == '.') {
111                                         minorvers4 = -atoi(p + 1);
112                                         break;
113                                 }
114                         case 3:
115                         case 2:
116                                 NFSCTL_VERUNSET(versbits, c);
117                                 break;
118                         default:
119                                 fprintf(stderr, "%s: Unsupported version\n", optarg);
120                                 exit(1);
121                         }
122                         break;
123                 case 's':
124                         xlog_syslog(1);
125                         xlog_stderr(0);
126                         break;
127                 case 'T':
128                         NFSCTL_TCPUNSET(protobits);
129                         break;
130                 case 'U':
131                         NFSCTL_UDPUNSET(protobits);
132                         break;
133                 default:
134                         fprintf(stderr, "Invalid argument: '%c'\n", c);
135                 case 'h':
136                         usage(progname);
137                 }
138         }
139
140         xlog_open(progname);
141
142         /*
143          * Do some sanity checking, if the ctlbits are set
144          */
145         if (!NFSCTL_UDPISSET(protobits) && !NFSCTL_TCPISSET(protobits)) {
146                 xlog(L_ERROR, "invalid protocol specified");
147                 exit(1);
148         }
149         found_one = 0;
150         for (c = NFSD_MINVERS; c <= NFSD_MAXVERS; c++) {
151                 if (NFSCTL_VERISSET(versbits, c))
152                         found_one = 1;
153         }
154         if (!found_one) {
155                 xlog(L_ERROR, "no version specified");
156                 exit(1);
157         }                       
158
159         if (NFSCTL_VERISSET(versbits, 4) && !NFSCTL_TCPISSET(protobits)) {
160                 xlog(L_ERROR, "version 4 requires the TCP protocol");
161                 exit(1);
162         }
163         if (haddr == NULL) {
164                 struct in_addr in = {INADDR_ANY}; 
165                 haddr = strdup(inet_ntoa(in));
166         }
167
168         if (chdir(NFS_STATEDIR)) {
169                 xlog(L_ERROR, "chdir(%s) failed: %m", NFS_STATEDIR);
170                 exit(1);
171         }
172
173         if (optind < argc) {
174                 if ((count = atoi(argv[optind])) < 0) {
175                         /* insane # of servers */
176                         xlog(L_ERROR, "invalid server count (%d), using 1",
177                                       count);
178                         count = 1;
179                 }
180         }
181
182         /* can only change number of threads if nfsd is already up */
183         if (nfssvc_inuse()) {
184                 socket_up = 1;
185                 goto set_threads;
186         }
187
188         /*
189          * must set versions before the fd's so that the right versions get
190          * registered with rpcbind. Note that on older kernels w/o the right
191          * interfaces, these are a no-op.
192          */
193         nfssvc_setvers(versbits, minorvers4);
194
195         error = nfssvc_set_sockets(AF_INET, protobits, haddr, port);
196         if (!error)
197                 socket_up = 1;
198
199 set_threads:
200         /* don't start any threads if unable to hand off any sockets */
201         if (!socket_up) {
202                 xlog(L_ERROR, "unable to set any sockets for nfsd");
203                 goto out;
204         }
205         error = 0;
206
207         /*
208          * KLUDGE ALERT:
209          * Some kernels let nfsd kernel threads inherit open files
210          * from the program that spawns them (i.e. us).  So close
211          * everything before spawning kernel threads.  --Chip
212          */
213         fd = open("/dev/null", O_RDWR);
214         if (fd == -1)
215                 xlog(L_ERROR, "Unable to open /dev/null: %m");
216         else {
217                 /* switch xlog output to syslog since stderr is being closed */
218                 xlog_syslog(1);
219                 xlog_stderr(0);
220                 (void) dup2(fd, 0);
221                 (void) dup2(fd, 1);
222                 (void) dup2(fd, 2);
223         }
224         closeall(3);
225
226         if ((error = nfssvc_threads(portnum, count)) < 0)
227                 xlog(L_ERROR, "error starting threads: errno %d (%m)", errno);
228 out:
229         free(port);
230         free(haddr);
231         free(progname);
232         return (error != 0);
233 }
234
235 static void
236 usage(const char *prog)
237 {
238         fprintf(stderr, "Usage:\n"
239                 "%s [-d|--debug] [-H hostname] [-p|-P|--port port] [-N|--no-nfs-version version ] [-s|--syslog] [-T|--no-tcp] [-U|--no-udp] nrservs\n", 
240                 prog);
241         exit(2);
242 }