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