Version increased to unfs3_0.9.22+dfsg-1maemo3
[unfs3] / unfs3 / daemon.c
1
2 /*
3  * UNFS3 server framework
4  * Originally generated using rpcgen
5  * Portions (C) 2004, Pascal Schmidt
6  * see file LICENSE for license details
7  */
8
9 #include "config.h"
10
11 #include <sys/file.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <rpc/rpc.h>
15 #include <rpc/pmap_clnt.h>
16
17 #ifndef WIN32
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <syslog.h>
22 #else                                  /* WIN32 */
23 #include <winsock.h>
24 #endif                                 /* WIN32 */
25
26 #include <fcntl.h>
27 #include <memory.h>
28 #include <signal.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <time.h>
34 #include <unistd.h>
35 #include <errno.h>
36
37 #if HAVE_RPC_SVC_SOC_H == 1
38 # include <rpc/svc_soc.h>
39 #endif
40
41 #include "nfs.h"
42 #include "mount.h"
43 #include "xdr.h"
44 #include "fh.h"
45 #include "fh_cache.h"
46 #include "fd_cache.h"
47 #include "user.h"
48 #include "daemon.h"
49 #include "backend.h"
50 #include "Config/exports.h"
51
52 #ifndef SIG_PF
53 #define SIG_PF void(*)(int)
54 #endif
55
56 #define UNFS_NAME "UNFS3 unfsd " PACKAGE_VERSION " (C) 2006, Pascal Schmidt <unfs3-server@ewetel.net>\n"
57
58 /* write verifier */
59 writeverf3 wverf;
60
61 /* readdir cookie */
62 cookie3 rcookie = 0;
63
64 /* options and default values */
65 int opt_detach = TRUE;
66 char *opt_exports = "/etc/exports";
67 int opt_cluster = FALSE;
68 char *opt_cluster_path = "/";
69 int opt_tcponly = FALSE;
70 unsigned int opt_nfs_port = NFS_PORT;   /* 0 means RPC_ANYSOCK */
71 unsigned int opt_mount_port = NFS_PORT;
72 int opt_singleuser = FALSE;
73 int opt_brute_force = FALSE;
74 int opt_testconfig = FALSE;
75 struct in_addr opt_bind_addr;
76 int opt_readable_executables = FALSE;
77 char *opt_pid_file = NULL;
78
79 /* Register with portmapper? */
80 int opt_portmapper = TRUE;
81
82 /*
83  * output message to syslog or stdout
84  */
85 void logmsg(int prio, const char *fmt, ...)
86 {
87     va_list ap;
88
89 #if HAVE_VSYSLOG == 0
90     char mesg[1024];
91 #endif
92
93     va_start(ap, fmt);
94     if (opt_detach) {
95 #if HAVE_VSYSLOG == 1
96         vsyslog(prio, fmt, ap);
97 #else
98         vsnprintf(mesg, 1024, fmt, ap);
99         syslog(prio, mesg, 1024);
100 #endif
101     } else {
102         vprintf(fmt, ap);
103         putchar('\n');
104     }
105     va_end(ap);
106 }
107
108 /*
109  * return remote address from svc_req structure
110  */
111 struct in_addr get_remote(struct svc_req *rqstp)
112 {
113     return (svc_getcaller(rqstp->rq_xprt))->sin_addr;
114 }
115
116 /*
117  * return remote port from svc_req structure
118  */
119 short get_port(struct svc_req *rqstp)
120 {
121     return (svc_getcaller(rqstp->rq_xprt))->sin_port;
122 }
123
124 /*
125  * return the socket type of the request (SOCK_STREAM or SOCK_DGRAM)
126  */
127 int get_socket_type(struct svc_req *rqstp)
128 {
129     int v, res;
130     socklen_t l;
131
132     l = sizeof(v);
133
134 #if HAVE_STRUCT___RPC_SVCXPRT_XP_FD == 1
135     res = getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET, SO_TYPE, &v, &l);
136 #else
137     res = getsockopt(rqstp->rq_xprt->xp_sock, SOL_SOCKET, SO_TYPE, &v, &l);
138 #endif
139
140     if (res < 0) {
141         logmsg(LOG_CRIT, "unable to determine socket type");
142         return -1;
143     }
144
145     return v;
146 }
147
148 /*
149  * write current pid to a file
150  */
151 static void create_pid_file(void)
152 {
153     char buf[16];
154     int fd, res, len;
155
156     if (!opt_pid_file)
157         return;
158
159     fd = backend_open_create(opt_pid_file, O_RDWR | O_CREAT | O_TRUNC, 0644);
160     if (fd == -1) {
161         logmsg(LOG_WARNING, "failed to create pid file `%s'", opt_pid_file);
162         return;
163     }
164 #if defined(LOCK_EX) && defined(LOCK_NB)
165     res = backend_flock(fd, LOCK_EX | LOCK_NB);
166     if (res == -1) {
167         logmsg(LOG_WARNING, "failed to lock pid file `%s'", opt_pid_file);
168         backend_close(fd);
169         return;
170     }
171 #endif
172
173     sprintf(buf, "%i\n", backend_getpid());
174     len = strlen(buf);
175
176     res = backend_pwrite(fd, buf, len, 0);
177     backend_close(fd);
178     if (res != len) {
179         logmsg(LOG_WARNING, "failed to write pid file `%s'", opt_pid_file);
180     }
181 }
182
183 /*
184  * remove pid file
185  */
186 static void remove_pid_file(void)
187 {
188     int res;
189
190     if (!opt_pid_file)
191         return;
192
193     res = backend_remove(opt_pid_file);
194     if (res == -1 && errno != ENOENT) {
195         logmsg(LOG_WARNING, "failed to remove pid file `%s'", opt_pid_file);
196     }
197 }
198
199 /*
200  * parse command line options
201  */
202 static void parse_options(int argc, char **argv)
203 {
204     int opt = 0;
205     char *optstring = "bcC:de:hl:m:n:prstTuwi:";
206
207     while (opt != -1) {
208         opt = getopt(argc, argv, optstring);
209         switch (opt) {
210             case 'b':
211                 opt_brute_force = TRUE;
212                 break;
213 #ifdef WANT_CLUSTER
214             case 'c':
215                 opt_cluster = TRUE;
216                 break;
217             case 'C':
218                 opt_cluster_path = optarg;
219                 break;
220 #endif
221             case 'd':
222                 printf(UNFS_NAME);
223                 opt_detach = FALSE;
224                 break;
225             case 'e':
226 #ifndef WIN32
227                 if (optarg[0] != '/') {
228                     /* A relative path won't work for re-reading the exports
229                        file on SIGHUP, since we are changing directory */
230                     fprintf(stderr, "Error: relative path to exports file\n");
231                     exit(1);
232                 }
233 #endif
234                 opt_exports = optarg;
235                 break;
236             case 'h':
237                 printf(UNFS_NAME);
238                 printf("Usage: %s [options]\n", argv[0]);
239                 printf("\t-h          display this short option summary\n");
240                 printf("\t-u          use unprivileged port for services\n");
241                 printf("\t-d          do not detach from terminal\n");
242                 printf("\t-e <file>   file to use instead of /etc/exports\n");
243                 printf("\t-i <file>   write daemon pid to given file\n");
244 #ifdef WANT_CLUSTER
245                 printf("\t-c          enable cluster extensions\n");
246                 printf("\t-C <path>   set path for cluster extensions\n");
247 #endif
248                 printf("\t-n <port>   port to use for NFS service\n");
249                 printf("\t-m <port>   port to use for MOUNT service\n");
250                 printf
251                     ("\t-t          TCP only, do not listen on UDP ports\n");
252                 printf("\t-p          do not register with the portmapper\n");
253                 printf("\t-s          single user mode\n");
254                 printf("\t-b          enable brute force file searching\n");
255                 printf
256                     ("\t-l <addr>   bind to interface with specified address\n");
257                 printf
258                     ("\t-r          report unreadable executables as readable\n");
259                 printf("\t-T          test exports file and exit\n");
260                 exit(0);
261                 break;
262             case 'l':
263                 opt_bind_addr.s_addr = inet_addr(optarg);
264                 if (opt_bind_addr.s_addr == (unsigned) -1) {
265                     fprintf(stderr, "Invalid bind address\n");
266                     exit(1);
267                 }
268                 break;
269             case 'm':
270                 opt_mount_port = strtol(optarg, NULL, 10);
271                 if (opt_mount_port == 0) {
272                     fprintf(stderr, "Invalid port\n");
273                     exit(1);
274                 }
275                 break;
276             case 'n':
277                 opt_nfs_port = strtol(optarg, NULL, 10);
278                 if (opt_nfs_port == 0) {
279                     fprintf(stderr, "Invalid port\n");
280                     exit(1);
281                 }
282                 break;
283             case 'p':
284                 opt_portmapper = FALSE;
285                 break;
286             case 'r':
287                 opt_readable_executables = TRUE;
288                 break;
289             case 's':
290                 opt_singleuser = TRUE;
291 #ifndef WIN32
292                 if (backend_getuid() == 0) {
293                     logmsg(LOG_WARNING,
294                            "Warning: running as root with -s is dangerous");
295                     logmsg(LOG_WARNING,
296                            "All clients will have root access to all exported files!");
297                 }
298 #endif
299                 break;
300             case 't':
301                 opt_tcponly = TRUE;
302                 break;
303             case 'T':
304                 opt_testconfig = TRUE;
305                 break;
306             case 'u':
307                 opt_nfs_port = 0;
308                 opt_mount_port = 0;
309                 break;
310             case 'i':
311                 opt_pid_file = optarg;
312                 break;
313             case '?':
314                 exit(1);
315                 break;
316         }
317     }
318 }
319
320 /*
321  * signal handler and error exit function
322  */
323 void daemon_exit(int error)
324 {
325 #ifndef WIN32
326     if (error == SIGHUP) {
327         get_squash_ids();
328         exports_parse();
329         return;
330     }
331
332     if (error == SIGUSR1) {
333         if (fh_cache_use > 0)
334             logmsg(LOG_INFO, "fh entries %i access %i hit %i miss %i",
335                    fh_cache_max, fh_cache_use, fh_cache_hit,
336                    fh_cache_use - fh_cache_hit);
337         else
338             logmsg(LOG_INFO, "fh cache unused");
339         logmsg(LOG_INFO, "open file descriptors: read %i, write %i",
340                fd_cache_readers, fd_cache_writers);
341         return;
342     }
343 #endif                                 /* WIN32 */
344
345     if (opt_portmapper) {
346         svc_unregister(MOUNTPROG, MOUNTVERS1);
347         svc_unregister(MOUNTPROG, MOUNTVERS3);
348     }
349
350     if (opt_portmapper) {
351         svc_unregister(NFS3_PROGRAM, NFS_V3);
352     }
353
354     if (error == SIGSEGV)
355         logmsg(LOG_EMERG, "segmentation fault");
356
357     fd_cache_purge();
358
359     if (opt_detach)
360         closelog();
361
362     remove_pid_file();
363     backend_shutdown();
364
365     exit(1);
366 }
367
368 /*
369  * NFS service dispatch function
370  * generated by rpcgen
371  */
372 static void nfs3_program_3(struct svc_req *rqstp, register SVCXPRT * transp)
373 {
374     union {
375         GETATTR3args nfsproc3_getattr_3_arg;
376         SETATTR3args nfsproc3_setattr_3_arg;
377         LOOKUP3args nfsproc3_lookup_3_arg;
378         ACCESS3args nfsproc3_access_3_arg;
379         READLINK3args nfsproc3_readlink_3_arg;
380         READ3args nfsproc3_read_3_arg;
381         WRITE3args nfsproc3_write_3_arg;
382         CREATE3args nfsproc3_create_3_arg;
383         MKDIR3args nfsproc3_mkdir_3_arg;
384         SYMLINK3args nfsproc3_symlink_3_arg;
385         MKNOD3args nfsproc3_mknod_3_arg;
386         REMOVE3args nfsproc3_remove_3_arg;
387         RMDIR3args nfsproc3_rmdir_3_arg;
388         RENAME3args nfsproc3_rename_3_arg;
389         LINK3args nfsproc3_link_3_arg;
390         READDIR3args nfsproc3_readdir_3_arg;
391         READDIRPLUS3args nfsproc3_readdirplus_3_arg;
392         FSSTAT3args nfsproc3_fsstat_3_arg;
393         FSINFO3args nfsproc3_fsinfo_3_arg;
394         PATHCONF3args nfsproc3_pathconf_3_arg;
395         COMMIT3args nfsproc3_commit_3_arg;
396     } argument;
397     char *result;
398     xdrproc_t _xdr_argument, _xdr_result;
399     char *(*local) (char *, struct svc_req *);
400
401     switch (rqstp->rq_proc) {
402         case NFSPROC3_NULL:
403             _xdr_argument = (xdrproc_t) xdr_void;
404             _xdr_result = (xdrproc_t) xdr_void;
405             local = (char *(*)(char *, struct svc_req *)) nfsproc3_null_3_svc;
406             break;
407
408         case NFSPROC3_GETATTR:
409             _xdr_argument = (xdrproc_t) xdr_GETATTR3args;
410             _xdr_result = (xdrproc_t) xdr_GETATTR3res;
411             local =
412                 (char *(*)(char *, struct svc_req *)) nfsproc3_getattr_3_svc;
413             break;
414
415         case NFSPROC3_SETATTR:
416             _xdr_argument = (xdrproc_t) xdr_SETATTR3args;
417             _xdr_result = (xdrproc_t) xdr_SETATTR3res;
418             local =
419                 (char *(*)(char *, struct svc_req *)) nfsproc3_setattr_3_svc;
420             break;
421
422         case NFSPROC3_LOOKUP:
423             _xdr_argument = (xdrproc_t) xdr_LOOKUP3args;
424             _xdr_result = (xdrproc_t) xdr_LOOKUP3res;
425             local =
426                 (char *(*)(char *, struct svc_req *)) nfsproc3_lookup_3_svc;
427             break;
428
429         case NFSPROC3_ACCESS:
430             _xdr_argument = (xdrproc_t) xdr_ACCESS3args;
431             _xdr_result = (xdrproc_t) xdr_ACCESS3res;
432             local =
433                 (char *(*)(char *, struct svc_req *)) nfsproc3_access_3_svc;
434             break;
435
436         case NFSPROC3_READLINK:
437             _xdr_argument = (xdrproc_t) xdr_READLINK3args;
438             _xdr_result = (xdrproc_t) xdr_READLINK3res;
439             local =
440                 (char *(*)(char *, struct svc_req *)) nfsproc3_readlink_3_svc;
441             break;
442
443         case NFSPROC3_READ:
444             _xdr_argument = (xdrproc_t) xdr_READ3args;
445             _xdr_result = (xdrproc_t) xdr_READ3res;
446             local = (char *(*)(char *, struct svc_req *)) nfsproc3_read_3_svc;
447             break;
448
449         case NFSPROC3_WRITE:
450             _xdr_argument = (xdrproc_t) xdr_WRITE3args;
451             _xdr_result = (xdrproc_t) xdr_WRITE3res;
452             local =
453                 (char *(*)(char *, struct svc_req *)) nfsproc3_write_3_svc;
454             break;
455
456         case NFSPROC3_CREATE:
457             _xdr_argument = (xdrproc_t) xdr_CREATE3args;
458             _xdr_result = (xdrproc_t) xdr_CREATE3res;
459             local =
460                 (char *(*)(char *, struct svc_req *)) nfsproc3_create_3_svc;
461             break;
462
463         case NFSPROC3_MKDIR:
464             _xdr_argument = (xdrproc_t) xdr_MKDIR3args;
465             _xdr_result = (xdrproc_t) xdr_MKDIR3res;
466             local =
467                 (char *(*)(char *, struct svc_req *)) nfsproc3_mkdir_3_svc;
468             break;
469
470         case NFSPROC3_SYMLINK:
471             _xdr_argument = (xdrproc_t) xdr_SYMLINK3args;
472             _xdr_result = (xdrproc_t) xdr_SYMLINK3res;
473             local =
474                 (char *(*)(char *, struct svc_req *)) nfsproc3_symlink_3_svc;
475             break;
476
477         case NFSPROC3_MKNOD:
478             _xdr_argument = (xdrproc_t) xdr_MKNOD3args;
479             _xdr_result = (xdrproc_t) xdr_MKNOD3res;
480             local =
481                 (char *(*)(char *, struct svc_req *)) nfsproc3_mknod_3_svc;
482             break;
483
484         case NFSPROC3_REMOVE:
485             _xdr_argument = (xdrproc_t) xdr_REMOVE3args;
486             _xdr_result = (xdrproc_t) xdr_REMOVE3res;
487             local =
488                 (char *(*)(char *, struct svc_req *)) nfsproc3_remove_3_svc;
489             break;
490
491         case NFSPROC3_RMDIR:
492             _xdr_argument = (xdrproc_t) xdr_RMDIR3args;
493             _xdr_result = (xdrproc_t) xdr_RMDIR3res;
494             local =
495                 (char *(*)(char *, struct svc_req *)) nfsproc3_rmdir_3_svc;
496             break;
497
498         case NFSPROC3_RENAME:
499             _xdr_argument = (xdrproc_t) xdr_RENAME3args;
500             _xdr_result = (xdrproc_t) xdr_RENAME3res;
501             local =
502                 (char *(*)(char *, struct svc_req *)) nfsproc3_rename_3_svc;
503             break;
504
505         case NFSPROC3_LINK:
506             _xdr_argument = (xdrproc_t) xdr_LINK3args;
507             _xdr_result = (xdrproc_t) xdr_LINK3res;
508             local = (char *(*)(char *, struct svc_req *)) nfsproc3_link_3_svc;
509             break;
510
511         case NFSPROC3_READDIR:
512             _xdr_argument = (xdrproc_t) xdr_READDIR3args;
513             _xdr_result = (xdrproc_t) xdr_READDIR3res;
514             local =
515                 (char *(*)(char *, struct svc_req *)) nfsproc3_readdir_3_svc;
516             break;
517
518         case NFSPROC3_READDIRPLUS:
519             _xdr_argument = (xdrproc_t) xdr_READDIRPLUS3args;
520             _xdr_result = (xdrproc_t) xdr_READDIRPLUS3res;
521             local = (char *(*)(char *, struct svc_req *))
522                 nfsproc3_readdirplus_3_svc;
523             break;
524
525         case NFSPROC3_FSSTAT:
526             _xdr_argument = (xdrproc_t) xdr_FSSTAT3args;
527             _xdr_result = (xdrproc_t) xdr_FSSTAT3res;
528             local =
529                 (char *(*)(char *, struct svc_req *)) nfsproc3_fsstat_3_svc;
530             break;
531
532         case NFSPROC3_FSINFO:
533             _xdr_argument = (xdrproc_t) xdr_FSINFO3args;
534             _xdr_result = (xdrproc_t) xdr_FSINFO3res;
535             local =
536                 (char *(*)(char *, struct svc_req *)) nfsproc3_fsinfo_3_svc;
537             break;
538
539         case NFSPROC3_PATHCONF:
540             _xdr_argument = (xdrproc_t) xdr_PATHCONF3args;
541             _xdr_result = (xdrproc_t) xdr_PATHCONF3res;
542             local =
543                 (char *(*)(char *, struct svc_req *)) nfsproc3_pathconf_3_svc;
544             break;
545
546         case NFSPROC3_COMMIT:
547             _xdr_argument = (xdrproc_t) xdr_COMMIT3args;
548             _xdr_result = (xdrproc_t) xdr_COMMIT3res;
549             local =
550                 (char *(*)(char *, struct svc_req *)) nfsproc3_commit_3_svc;
551             break;
552
553         default:
554             svcerr_noproc(transp);
555             return;
556     }
557     memset((char *) &argument, 0, sizeof(argument));
558     if (!svc_getargs(transp, (xdrproc_t) _xdr_argument, (caddr_t) & argument)) {
559         svcerr_decode(transp);
560         return;
561     }
562     result = (*local) ((char *) &argument, rqstp);
563     if (result != NULL &&
564         !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
565         svcerr_systemerr(transp);
566         logmsg(LOG_CRIT, "unable to send RPC reply");
567     }
568     if (!svc_freeargs
569         (transp, (xdrproc_t) _xdr_argument, (caddr_t) & argument)) {
570         logmsg(LOG_CRIT, "unable to free XDR arguments");
571     }
572     return;
573 }
574
575 /*
576  * mount protocol dispatcher
577  * generated by rpcgen
578  */
579 static void mountprog_3(struct svc_req *rqstp, register SVCXPRT * transp)
580 {
581     union {
582         dirpath mountproc_mnt_3_arg;
583         dirpath mountproc_umnt_3_arg;
584     } argument;
585     char *result;
586     xdrproc_t _xdr_argument, _xdr_result;
587     char *(*local) (char *, struct svc_req *);
588
589     switch (rqstp->rq_proc) {
590         case MOUNTPROC_NULL:
591             _xdr_argument = (xdrproc_t) xdr_void;
592             _xdr_result = (xdrproc_t) xdr_void;
593             local =
594                 (char *(*)(char *, struct svc_req *)) mountproc_null_3_svc;
595             break;
596
597         case MOUNTPROC_MNT:
598             _xdr_argument = (xdrproc_t) xdr_dirpath;
599             _xdr_result = (xdrproc_t) xdr_mountres3;
600             local = (char *(*)(char *, struct svc_req *)) mountproc_mnt_3_svc;
601             break;
602
603         case MOUNTPROC_DUMP:
604             _xdr_argument = (xdrproc_t) xdr_void;
605             _xdr_result = (xdrproc_t) xdr_mountlist;
606             local =
607                 (char *(*)(char *, struct svc_req *)) mountproc_dump_3_svc;
608             break;
609
610         case MOUNTPROC_UMNT:
611             _xdr_argument = (xdrproc_t) xdr_dirpath;
612             _xdr_result = (xdrproc_t) xdr_void;
613             local =
614                 (char *(*)(char *, struct svc_req *)) mountproc_umnt_3_svc;
615             break;
616
617         case MOUNTPROC_UMNTALL:
618             _xdr_argument = (xdrproc_t) xdr_void;
619             _xdr_result = (xdrproc_t) xdr_void;
620             local =
621                 (char *(*)(char *, struct svc_req *)) mountproc_umntall_3_svc;
622             break;
623
624         case MOUNTPROC_EXPORT:
625             _xdr_argument = (xdrproc_t) xdr_void;
626             _xdr_result = (xdrproc_t) xdr_exports;
627             local =
628                 (char *(*)(char *, struct svc_req *)) mountproc_export_3_svc;
629             break;
630
631         default:
632             svcerr_noproc(transp);
633             return;
634     }
635     memset((char *) &argument, 0, sizeof(argument));
636     if (!svc_getargs(transp, (xdrproc_t) _xdr_argument, (caddr_t) & argument)) {
637         svcerr_decode(transp);
638         return;
639     }
640     result = (*local) ((char *) &argument, rqstp);
641     if (result != NULL &&
642         !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
643         svcerr_systemerr(transp);
644         logmsg(LOG_CRIT, "unable to send RPC reply");
645     }
646     if (!svc_freeargs
647         (transp, (xdrproc_t) _xdr_argument, (caddr_t) & argument)) {
648         logmsg(LOG_CRIT, "unable to free XDR arguments");
649     }
650     return;
651 }
652
653 static void register_nfs_service(SVCXPRT * udptransp, SVCXPRT * tcptransp)
654 {
655     if (opt_portmapper) {
656         pmap_unset(NFS3_PROGRAM, NFS_V3);
657     }
658
659     if (udptransp != NULL) {
660         /* Register NFS service for UDP */
661         if (!svc_register
662             (udptransp, NFS3_PROGRAM, NFS_V3, nfs3_program_3,
663              opt_portmapper ? IPPROTO_UDP : 0)) {
664             fprintf(stderr, "%s\n",
665                     "unable to register (NFS3_PROGRAM, NFS_V3, udp).");
666             daemon_exit(0);
667         }
668     }
669
670     if (tcptransp != NULL) {
671         /* Register NFS service for TCP */
672         if (!svc_register
673             (tcptransp, NFS3_PROGRAM, NFS_V3, nfs3_program_3,
674              opt_portmapper ? IPPROTO_TCP : 0)) {
675             fprintf(stderr, "%s\n",
676                     "unable to register (NFS3_PROGRAM, NFS_V3, tcp).");
677             daemon_exit(0);
678         }
679     }
680 }
681
682 static void register_mount_service(SVCXPRT * udptransp, SVCXPRT * tcptransp)
683 {
684     if (opt_portmapper) {
685         pmap_unset(MOUNTPROG, MOUNTVERS1);
686         pmap_unset(MOUNTPROG, MOUNTVERS3);
687     }
688
689     if (udptransp != NULL) {
690         /* Register MOUNT service (v1) for UDP */
691         if (!svc_register
692             (udptransp, MOUNTPROG, MOUNTVERS1, mountprog_3,
693              opt_portmapper ? IPPROTO_UDP : 0)) {
694             fprintf(stderr, "%s\n",
695                     "unable to register (MOUNTPROG, MOUNTVERS1, udp).");
696             daemon_exit(0);
697         }
698
699         /* Register MOUNT service (v3) for UDP */
700         if (!svc_register
701             (udptransp, MOUNTPROG, MOUNTVERS3, mountprog_3,
702              opt_portmapper ? IPPROTO_UDP : 0)) {
703             fprintf(stderr, "%s\n",
704                     "unable to register (MOUNTPROG, MOUNTVERS3, udp).");
705             daemon_exit(0);
706         }
707     }
708
709     if (tcptransp != NULL) {
710         /* Register MOUNT service (v1) for TCP */
711         if (!svc_register
712             (tcptransp, MOUNTPROG, MOUNTVERS1, mountprog_3,
713              opt_portmapper ? IPPROTO_TCP : 0)) {
714             fprintf(stderr, "%s\n",
715                     "unable to register (MOUNTPROG, MOUNTVERS1, tcp).");
716             daemon_exit(0);
717         }
718
719         /* Register MOUNT service (v3) for TCP */
720         if (!svc_register
721             (tcptransp, MOUNTPROG, MOUNTVERS3, mountprog_3,
722              opt_portmapper ? IPPROTO_TCP : 0)) {
723             fprintf(stderr, "%s\n",
724                     "unable to register (MOUNTPROG, MOUNTVERS3, tcp).");
725             daemon_exit(0);
726         }
727     }
728 }
729
730 static SVCXPRT *create_udp_transport(unsigned int port)
731 {
732     SVCXPRT *transp = NULL;
733     struct sockaddr_in sin;
734     int sock;
735     const int on = 1;
736
737     if (port == 0)
738         sock = RPC_ANYSOCK;
739     else {
740         sin.sin_family = AF_INET;
741         sin.sin_port = htons(port);
742         sin.sin_addr.s_addr = opt_bind_addr.s_addr;
743         sock = socket(PF_INET, SOCK_DGRAM, 0);
744         setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
745         if (bind(sock, (struct sockaddr *) &sin, sizeof(struct sockaddr))) {
746             perror("bind");
747             fprintf(stderr, "Couldn't bind to udp port %d\n", port);
748             exit(1);
749         }
750     }
751
752     transp = svcudp_bufcreate(sock, NFS_MAX_UDP_PACKET, NFS_MAX_UDP_PACKET);
753
754     if (transp == NULL) {
755         fprintf(stderr, "%s\n", "cannot create udp service.");
756         daemon_exit(0);
757     }
758
759     return transp;
760 }
761
762 static SVCXPRT *create_tcp_transport(unsigned int port)
763 {
764     SVCXPRT *transp = NULL;
765     struct sockaddr_in sin;
766     int sock;
767     const int on = 1;
768
769     if (port == 0)
770         sock = RPC_ANYSOCK;
771     else {
772         sin.sin_family = AF_INET;
773         sin.sin_port = htons(port);
774         sin.sin_addr.s_addr = opt_bind_addr.s_addr;
775         sock = socket(PF_INET, SOCK_STREAM, 0);
776         setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
777         if (bind(sock, (struct sockaddr *) &sin, sizeof(struct sockaddr))) {
778             perror("bind");
779             fprintf(stderr, "Couldn't bind to tcp port %d\n", port);
780             exit(1);
781         }
782     }
783
784     transp = svctcp_create(sock, 0, 0);
785
786     if (transp == NULL) {
787         fprintf(stderr, "%s\n", "cannot create tcp service.");
788         daemon_exit(0);
789     }
790
791     return transp;
792 }
793
794 /* Run RPC service. This is our own implementation of svc_run(), which
795    allows us to handle other events as well. */
796 static void unfs3_svc_run()
797 {
798     fd_set readfds;
799     struct timeval tv;
800
801     for (;;) {
802         fd_cache_close_inactive();
803         readfds = svc_fdset;
804         tv.tv_sec = 1;
805         tv.tv_usec = 0;
806         /* Note: On Windows, it's not possible to call select with all sets
807            empty; to use it as a sleep function. In our case, however,
808            readfds should never be empty, since we always have our listen
809            socket. Well, at least hope that our Windows RPC library works
810            like that. oncrpc-ms does. */
811         switch (select(FD_SETSIZE, &readfds, NULL, NULL, &tv)) {
812             case -1:
813                 if (errno == EINTR) {
814                     continue;
815                 }
816                 perror("unfs3_svc_run: select failed");
817                 return;
818             case 0:
819                 /* timeout */
820                 continue;
821             default:
822                 svc_getreqset(&readfds);
823         }
824     }
825 }
826
827 /*
828  * Generate write verifier based on PID and current time
829  */
830 void regenerate_write_verifier(void)
831 {
832     *(wverf + 0) = (uint32) getpid();
833     *(wverf + 0) ^= rand();
834     *(wverf + 4) = (uint32) time(NULL);
835 }
836
837 /*
838  * Change readdir cookie value
839  */
840 void change_readdir_cookie(void)
841 {
842     rcookie = rcookie >> 32;
843     ++rcookie;
844     rcookie = rcookie << 32;
845 }
846
847 /*
848  * NFSD main function
849  * originally generated by rpcgen
850  * forking, logging, options, and signal handler stuff added
851  */
852 int main(int argc, char **argv)
853 {
854     register SVCXPRT *tcptransp = NULL, *udptransp = NULL;
855     pid_t pid = 0;
856
857 #ifndef WIN32
858     struct sigaction act;
859     sigset_t actset;
860 #endif                                 /* WIN32 */
861     int res;
862
863     opt_bind_addr.s_addr = INADDR_ANY;
864
865     parse_options(argc, argv);
866     if (optind < argc) {
867         fprintf(stderr, "Error: extra arguments on command line\n");
868         exit(1);
869     }
870
871     /* init write verifier */
872     regenerate_write_verifier();
873
874     res = backend_init();
875     if (res == -1) {
876         fprintf(stderr, "backend initialization failed\n");
877         daemon_exit(0);
878     }
879
880     /* config test mode */
881     if (opt_testconfig) {
882         res = exports_parse();
883         if (res) {
884             exit(0);
885         } else {
886             fprintf(stderr, "Parse error in `%s'\n", opt_exports);
887             exit(1);
888         }
889     }
890
891     if (opt_detach) {
892         /* prepare syslog access */
893         openlog("unfsd", LOG_CONS | LOG_PID, LOG_DAEMON);
894     } else {
895         /* flush stdout after each newline */
896         setvbuf(stdout, NULL, _IOLBF, 0);
897     }
898
899     /* NFS transports */
900     if (!opt_tcponly)
901         udptransp = create_udp_transport(opt_nfs_port);
902     tcptransp = create_tcp_transport(opt_nfs_port);
903
904     register_nfs_service(udptransp, tcptransp);
905
906     /* MOUNT transports. If ports are equal, then the MOUNT service can reuse 
907        the NFS transports. */
908     if (opt_mount_port != opt_nfs_port) {
909         if (!opt_tcponly)
910             udptransp = create_udp_transport(opt_mount_port);
911         tcptransp = create_tcp_transport(opt_mount_port);
912     }
913
914     register_mount_service(udptransp, tcptransp);
915
916 #ifndef WIN32
917     if (opt_detach) {
918         pid = fork();
919         if (pid == -1) {
920             fprintf(stderr, "could not fork into background\n");
921             daemon_exit(0);
922         }
923     }
924 #endif                                 /* WIN32 */
925
926     if (!opt_detach || pid == 0) {
927 #ifndef WIN32
928         sigemptyset(&actset);
929         act.sa_handler = daemon_exit;
930         act.sa_mask = actset;
931         act.sa_flags = 0;
932         sigaction(SIGHUP, &act, NULL);
933         sigaction(SIGTERM, &act, NULL);
934         sigaction(SIGINT, &act, NULL);
935         sigaction(SIGQUIT, &act, NULL);
936         sigaction(SIGSEGV, &act, NULL);
937         sigaction(SIGUSR1, &act, NULL);
938
939         act.sa_handler = SIG_IGN;
940         sigaction(SIGPIPE, &act, NULL);
941         sigaction(SIGUSR2, &act, NULL);
942         sigaction(SIGALRM, &act, NULL);
943
944         /* don't make directory we started in busy */
945         chdir("/");
946
947         /* detach from terminal */
948         if (opt_detach) {
949             setsid();
950             fclose(stdin);
951             fclose(stdout);
952             fclose(stderr);
953         }
954 #endif                                 /* WIN32 */
955
956         /* no umask to not screw up create modes */
957         umask(0);
958
959         /* create pid file if wanted */
960         create_pid_file();
961
962         /* initialize internal stuff */
963         fh_cache_init();
964         fd_cache_init();
965         get_squash_ids();
966         exports_parse();
967
968         unfs3_svc_run();
969         exit(1);
970         /* NOTREACHED */
971     }
972
973     return 0;
974 }