nfs-utils: clean up option parsing in nfsd.c
[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 <syslog.h>
22 #include <netdb.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26
27 #include "nfslib.h"
28 #include "nfssvc.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         { NULL, 0, 0, 0 }
42 };
43 unsigned int protobits = NFSCTL_ALLBITS;
44 unsigned int versbits = NFSCTL_ALLBITS;
45 int minorvers4 = NFSD_MAXMINORVERS4;            /* nfsv4 minor version */
46 char *haddr = NULL;
47
48 int
49 main(int argc, char **argv)
50 {
51         int     count = 1, c, error, port, fd, found_one;
52         struct servent *ent;
53         struct hostent *hp;
54         char *p;
55
56         ent = getservbyname ("nfs", "udp");
57         if (ent != NULL)
58                 port = ntohs (ent->s_port);
59         else
60                 port = 2049;
61
62         while ((c = getopt_long(argc, argv, "H:hN:p:P:TU", longopts, NULL)) != EOF) {
63                 switch(c) {
64                 case 'H':
65                         if (inet_addr(optarg) != INADDR_NONE) {
66                                 haddr = strdup(optarg);
67                         } else if ((hp = gethostbyname(optarg)) != NULL) {
68                                 haddr = inet_ntoa((*(struct in_addr*)(hp->h_addr_list[0])));
69                         } else {
70                                 fprintf(stderr, "%s: Unknown hostname: %s\n",
71                                         argv[0], optarg);
72                                 usage(argv [0]);
73                         }
74                         break;
75                 case 'P':       /* XXX for nfs-server compatibility */
76                 case 'p':
77                         port = atoi(optarg);
78                         if (port <= 0 || port > 65535) {
79                                 fprintf(stderr, "%s: bad port number: %s\n",
80                                         argv[0], optarg);
81                                 usage(argv [0]);
82                         }
83                         break;
84                 case 'N':
85                         switch((c = strtol(optarg, &p, 0))) {
86                         case 4:
87                                 if (*p == '.') {
88                                         minorvers4 = -atoi(p + 1);
89                                         break;
90                                 }
91                         case 3:
92                         case 2:
93                                 NFSCTL_VERUNSET(versbits, c);
94                                 break;
95                         default:
96                                 fprintf(stderr, "%s: Unsupported version\n", optarg);
97                                 exit(1);
98                         }
99                         break;
100                 case 'T':
101                         NFSCTL_TCPUNSET(protobits);
102                         break;
103                 case 'U':
104                         NFSCTL_UDPUNSET(protobits);
105                         break;
106                 default:
107                         fprintf(stderr, "Invalid argument: '%c'\n", c);
108                 case 'h':
109                         usage(argv[0]);
110                 }
111         }
112         /*
113          * Do some sanity checking, if the ctlbits are set
114          */
115         if (!NFSCTL_UDPISSET(protobits) && !NFSCTL_TCPISSET(protobits)) {
116                 fprintf(stderr, "invalid protocol specified\n");
117                 exit(1);
118         }
119         found_one = 0;
120         for (c = NFSD_MINVERS; c <= NFSD_MAXVERS; c++) {
121                 if (NFSCTL_VERISSET(versbits, c))
122                         found_one = 1;
123         }
124         if (!found_one) {
125                 fprintf(stderr, "no version specified\n");
126                 exit(1);
127         }                       
128
129         if (NFSCTL_VERISSET(versbits, 4) && !NFSCTL_TCPISSET(protobits)) {
130                 fprintf(stderr, "version 4 requires the TCP protocol\n");
131                 exit(1);
132         }
133         if (haddr == NULL) {
134                 struct in_addr in = {INADDR_ANY}; 
135                 haddr = strdup(inet_ntoa(in));
136         }
137
138         if (chdir(NFS_STATEDIR)) {
139                 fprintf(stderr, "%s: chdir(%s) failed: %s\n",
140                         argv [0], NFS_STATEDIR, strerror(errno));
141                 exit(1);
142         }
143
144         if (optind < argc) {
145                 if ((count = atoi(argv[optind])) < 0) {
146                         /* insane # of servers */
147                         fprintf(stderr,
148                                 "%s: invalid server count (%d), using 1\n",
149                                 argv[0], count);
150                         count = 1;
151                 }
152         }
153         /* KLUDGE ALERT:
154            Some kernels let nfsd kernel threads inherit open files
155            from the program that spawns them (i.e. us).  So close
156            everything before spawning kernel threads.  --Chip */
157         fd = open("/dev/null", O_RDWR);
158         if (fd == -1)
159                 perror("/dev/null");
160         else {
161                 (void) dup2(fd, 0);
162                 (void) dup2(fd, 1);
163                 (void) dup2(fd, 2);
164         }
165         closeall(3);
166
167         openlog("nfsd", LOG_PID, LOG_DAEMON);
168         if ((error = nfssvc(port, count, versbits, minorvers4, protobits, haddr)) < 0) {
169                 int e = errno;
170                 syslog(LOG_ERR, "nfssvc: %s", strerror(e));
171                 closelog();
172         }
173
174         return (error != 0);
175 }
176
177 static void
178 usage(const char *prog)
179 {
180         fprintf(stderr, "Usage:\n"
181                 "%s [-H hostname] [-p|-P|--port port] [-N|--no-nfs-version version ] [-T|--no-tcp] [-U|--no-udp] nrservs\n", 
182                 prog);
183         exit(2);
184 }