1 1.74 rillig /* $NetBSD: nfsd.c,v 1.74 2021/11/27 22:30:25 rillig Exp $ */ 2 1.16 cgd 3 1.1 cgd /* 4 1.11 mycroft * Copyright (c) 1989, 1993, 1994 5 1.11 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Rick Macklem at The University of Guelph. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.43 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.23 lukem #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.54 lukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\ 38 1.54 lukem The Regents of the University of California. All rights reserved."); 39 1.35 cgd #endif /* not lint */ 40 1.1 cgd 41 1.1 cgd #ifndef lint 42 1.16 cgd #if 0 43 1.18 fvdl static char sccsid[] = "@(#)nfsd.c 8.9 (Berkeley) 3/29/95"; 44 1.16 cgd #else 45 1.74 rillig __RCSID("$NetBSD: nfsd.c,v 1.74 2021/11/27 22:30:25 rillig Exp $"); 46 1.16 cgd #endif 47 1.18 fvdl #endif /* not lint */ 48 1.1 cgd 49 1.11 mycroft #include <sys/param.h> 50 1.1 cgd #include <sys/ioctl.h> 51 1.1 cgd #include <sys/stat.h> 52 1.1 cgd #include <sys/wait.h> 53 1.11 mycroft #include <sys/uio.h> 54 1.11 mycroft #include <sys/ucred.h> 55 1.1 cgd #include <sys/mount.h> 56 1.1 cgd #include <sys/socket.h> 57 1.1 cgd #include <sys/socketvar.h> 58 1.39 itojun #include <poll.h> 59 1.11 mycroft 60 1.1 cgd #include <rpc/rpc.h> 61 1.1 cgd #include <rpc/pmap_clnt.h> 62 1.1 cgd #include <rpc/pmap_prot.h> 63 1.11 mycroft 64 1.1 cgd #include <nfs/rpcv2.h> 65 1.18 fvdl #include <nfs/nfsproto.h> 66 1.11 mycroft #include <nfs/nfs.h> 67 1.11 mycroft 68 1.11 mycroft #include <err.h> 69 1.11 mycroft #include <errno.h> 70 1.11 mycroft #include <fcntl.h> 71 1.11 mycroft #include <grp.h> 72 1.62 gson #include <paths.h> 73 1.11 mycroft #include <pwd.h> 74 1.50 yamt #include <pthread.h> 75 1.11 mycroft #include <signal.h> 76 1.11 mycroft #include <stdio.h> 77 1.11 mycroft #include <stdlib.h> 78 1.25 perry #include <string.h> 79 1.19 mycroft #include <syslog.h> 80 1.11 mycroft #include <unistd.h> 81 1.32 fvdl #include <netdb.h> 82 1.1 cgd 83 1.65 christos #ifdef NFSD_RUMP 84 1.65 christos #include <rump/rump.h> 85 1.69 kamil #include <rump/rump_syscallshotgun.h> 86 1.65 christos #include <rump/rump_syscalls.h> 87 1.65 christos 88 1.65 christos #define nfssvc(a, b) rump_sys_nfssvc((a), (b)) 89 1.65 christos #define close(a) rump_sys_close(a) 90 1.65 christos #define poll(a, b, c) rump_sys_poll((a), (b), (c)) 91 1.65 christos #if 0 92 1.65 christos #define socket(a, b, c) rump_sys_socket((a), (b), (c)) 93 1.65 christos #define setsockopt(a, b, c, d, e) rump_sys_setsockopt((a), (b), (c), (d), (e)) 94 1.65 christos #define bind(a, b, c) rump_sys_bind((a), (b), (c)) 95 1.65 christos #define listen(a, b) rump_sys_listen((a), (b)) 96 1.65 christos #define accept(a, b, c) rump_sys_accept((a), (b), (c)) 97 1.65 christos #endif 98 1.65 christos #define main nfsd_main 99 1.65 christos int nfsd_main(int, char *[]); 100 1.65 christos #endif 101 1.65 christos 102 1.1 cgd /* Global defs */ 103 1.65 christos #if defined(DEBUG) || defined(NFSD_RUMP) 104 1.58 joerg static int debug = 1; 105 1.1 cgd #else 106 1.58 joerg static int debug = 0; 107 1.1 cgd #endif 108 1.11 mycroft 109 1.66 christos #define logit(e, s, args...) \ 110 1.66 christos do { \ 111 1.66 christos if (debug) { \ 112 1.66 christos fprintf(stderr,(s), ## args); \ 113 1.66 christos fprintf(stderr, "\n"); \ 114 1.66 christos } else { \ 115 1.66 christos syslog(e, s, ## args); \ 116 1.66 christos } \ 117 1.74 rillig } while (0) 118 1.66 christos 119 1.58 joerg static void nonfs(int); 120 1.58 joerg __dead static void usage(void); 121 1.1 cgd 122 1.50 yamt static void * 123 1.56 pooka worker(void *dummy) 124 1.50 yamt { 125 1.50 yamt struct nfsd_srvargs nsd; 126 1.50 yamt int nfssvc_flag; 127 1.50 yamt 128 1.51 yamt pthread_setname_np(pthread_self(), "slave", NULL); 129 1.50 yamt nfssvc_flag = NFSSVC_NFSD; 130 1.50 yamt memset(&nsd, 0, sizeof(nsd)); 131 1.73 christos while (nfssvc(nfssvc_flag, &nsd) == -1) { 132 1.50 yamt if (errno != ENEEDAUTH) { 133 1.66 christos logit(LOG_ERR, "nfssvc: %s", strerror(errno)); 134 1.73 christos exit(EXIT_FAILURE); 135 1.50 yamt } 136 1.50 yamt nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL; 137 1.50 yamt } 138 1.50 yamt 139 1.50 yamt return NULL; 140 1.50 yamt } 141 1.50 yamt 142 1.59 christos struct conf { 143 1.59 christos struct addrinfo *ai; 144 1.59 christos struct netconfig *nc; 145 1.59 christos struct netbuf nb; 146 1.59 christos struct pollfd pfd; 147 1.59 christos }; 148 1.59 christos 149 1.59 christos #define NFS_UDP4 0 150 1.59 christos #define NFS_TCP4 1 151 1.59 christos #define NFS_UDP6 2 152 1.59 christos #define NFS_TCP6 3 153 1.59 christos 154 1.59 christos static int cfg_family[] = { PF_INET, PF_INET, PF_INET6, PF_INET6 }; 155 1.59 christos static const char *cfg_netconf[] = { "udp", "tcp", "udp6", "tcp6" }; 156 1.59 christos static int cfg_socktype[] = { 157 1.59 christos SOCK_DGRAM, SOCK_STREAM, SOCK_DGRAM, SOCK_STREAM }; 158 1.59 christos static int cfg_protocol[] = { 159 1.59 christos IPPROTO_UDP, IPPROTO_TCP, IPPROTO_UDP, IPPROTO_TCP }; 160 1.59 christos 161 1.59 christos static int 162 1.59 christos tryconf(struct conf *cfg, int t, int reregister) 163 1.59 christos { 164 1.59 christos struct addrinfo hints; 165 1.59 christos int ecode; 166 1.59 christos 167 1.59 christos memset(&hints, 0, sizeof hints); 168 1.59 christos hints.ai_flags = AI_PASSIVE; 169 1.59 christos hints.ai_family = cfg_family[t]; 170 1.59 christos hints.ai_socktype = cfg_socktype[t]; 171 1.59 christos hints.ai_protocol = cfg_protocol[t]; 172 1.59 christos 173 1.59 christos ecode = getaddrinfo(NULL, "nfs", &hints, &cfg->ai); 174 1.59 christos if (ecode != 0) { 175 1.66 christos logit(LOG_ERR, "getaddrinfo %s: %s", cfg_netconf[t], 176 1.59 christos gai_strerror(ecode)); 177 1.59 christos return -1; 178 1.59 christos } 179 1.59 christos 180 1.59 christos cfg->nc = getnetconfigent(cfg_netconf[t]); 181 1.59 christos 182 1.59 christos if (cfg->nc == NULL) { 183 1.66 christos logit(LOG_ERR, "getnetconfigent %s failed: %s", 184 1.65 christos cfg_netconf[t], strerror(errno)); 185 1.60 christos goto out; 186 1.59 christos } 187 1.59 christos 188 1.59 christos cfg->nb.buf = cfg->ai->ai_addr; 189 1.59 christos cfg->nb.len = cfg->nb.maxlen = cfg->ai->ai_addrlen; 190 1.59 christos if (reregister) 191 1.59 christos if (!rpcb_set(RPCPROG_NFS, 2, cfg->nc, &cfg->nb)) { 192 1.66 christos logit(LOG_ERR, "rpcb_set %s failed", cfg_netconf[t]); 193 1.60 christos goto out1; 194 1.59 christos } 195 1.59 christos return 0; 196 1.60 christos out1: 197 1.60 christos freenetconfigent(cfg->nc); 198 1.60 christos cfg->nc = NULL; 199 1.60 christos out: 200 1.60 christos freeaddrinfo(cfg->ai); 201 1.60 christos cfg->ai = NULL; 202 1.60 christos return -1; 203 1.59 christos } 204 1.59 christos 205 1.59 christos static int 206 1.59 christos setupsock(struct conf *cfg, struct pollfd *set, int p) 207 1.59 christos { 208 1.59 christos int sock; 209 1.59 christos struct nfsd_args nfsdargs; 210 1.59 christos struct addrinfo *ai = cfg->ai; 211 1.59 christos int on = 1; 212 1.59 christos 213 1.59 christos sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 214 1.59 christos 215 1.59 christos if (sock == -1) { 216 1.66 christos logit(LOG_ERR, "can't create %s socket: %s", cfg_netconf[p], 217 1.65 christos strerror(errno)); 218 1.59 christos return -1; 219 1.59 christos } 220 1.59 christos if (cfg_family[p] == PF_INET6) { 221 1.59 christos if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, 222 1.59 christos sizeof(on)) == -1) { 223 1.66 christos logit(LOG_ERR, "can't set v6-only binding for %s " 224 1.65 christos "socket: %s", cfg_netconf[p], strerror(errno)); 225 1.59 christos goto out; 226 1.59 christos } 227 1.59 christos } 228 1.59 christos 229 1.59 christos if (cfg_protocol[p] == IPPROTO_TCP) { 230 1.59 christos if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, 231 1.59 christos sizeof(on)) == -1) { 232 1.66 christos logit(LOG_ERR, "setsockopt SO_REUSEADDR for %s: %s", 233 1.65 christos cfg_netconf[p], strerror(errno)); 234 1.59 christos goto out; 235 1.59 christos } 236 1.59 christos } 237 1.59 christos 238 1.59 christos if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) { 239 1.66 christos logit(LOG_ERR, "can't bind %s addr: %s", cfg_netconf[p], 240 1.65 christos strerror(errno)); 241 1.59 christos goto out; 242 1.59 christos } 243 1.59 christos 244 1.59 christos if (cfg_protocol[p] == IPPROTO_TCP) { 245 1.59 christos if (listen(sock, 5) == -1) { 246 1.66 christos logit(LOG_ERR, "listen failed"); 247 1.59 christos goto out; 248 1.59 christos } 249 1.59 christos } 250 1.59 christos 251 1.59 christos if (!rpcb_set(RPCPROG_NFS, 2, cfg->nc, &cfg->nb) || 252 1.59 christos !rpcb_set(RPCPROG_NFS, 3, cfg->nc, &cfg->nb)) { 253 1.66 christos logit(LOG_ERR, "can't register with %s portmap", 254 1.59 christos cfg_netconf[p]); 255 1.59 christos goto out; 256 1.59 christos } 257 1.59 christos 258 1.59 christos 259 1.59 christos if (cfg_protocol[p] == IPPROTO_TCP) 260 1.59 christos set->fd = sock; 261 1.59 christos else { 262 1.59 christos nfsdargs.sock = sock; 263 1.59 christos nfsdargs.name = NULL; 264 1.59 christos nfsdargs.namelen = 0; 265 1.73 christos if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) == -1) { 266 1.66 christos logit(LOG_ERR, "can't add %s socket: %s", 267 1.65 christos cfg_netconf[p], strerror(errno)); 268 1.59 christos goto out; 269 1.59 christos } 270 1.59 christos (void)close(sock); 271 1.59 christos } 272 1.59 christos return 0; 273 1.59 christos out: 274 1.59 christos (void)close(sock); 275 1.59 christos return -1; 276 1.59 christos } 277 1.59 christos 278 1.1 cgd /* 279 1.62 gson * The functions daemon2_fork() and daemon2_detach() below provide 280 1.62 gson * functionality similar to daemon(3) but split into two phases. 281 1.62 gson * daemon2_fork() is called early, before creating resources that 282 1.62 gson * cannot be inherited across a fork, such as threads or kqueues. 283 1.62 gson * When the daemon is ready to provide service, daemon2_detach() 284 1.62 gson * is called to complete the daemonization and signal the parent 285 1.62 gson * process to exit. 286 1.62 gson * 287 1.71 gson * These functions could potentially be moved to a library and 288 1.62 gson * shared by other daemons. 289 1.62 gson * 290 1.62 gson * The return value from daemon2_fork() is a file descriptor to 291 1.62 gson * be passed as the first argument to daemon2_detach(). 292 1.62 gson */ 293 1.62 gson 294 1.62 gson static int 295 1.62 gson daemon2_fork(void) 296 1.62 gson { 297 1.62 gson int i; 298 1.62 gson int fd; 299 1.62 gson int r; 300 1.62 gson pid_t pid; 301 1.62 gson int detach_msg_pipe[2]; 302 1.62 gson 303 1.62 gson /* 304 1.64 joerg * Set up a pipe for signalling the parent, making sure the 305 1.62 gson * write end does not get allocated one of the file 306 1.62 gson * descriptors that may be closed in daemon2_detach(). The 307 1.62 gson * read end does not need such protection. 308 1.62 gson */ 309 1.62 gson for (i = 0; i < 3; i++) { 310 1.62 gson r = pipe2(detach_msg_pipe, O_CLOEXEC|O_NOSIGPIPE); 311 1.73 christos if (r == -1) 312 1.62 gson return -1; 313 1.62 gson if (detach_msg_pipe[1] <= STDERR_FILENO && 314 1.62 gson (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 315 1.62 gson (void)dup2(fd, detach_msg_pipe[0]); 316 1.62 gson (void)dup2(fd, detach_msg_pipe[1]); 317 1.62 gson if (fd > STDERR_FILENO) 318 1.62 gson (void)close(fd); 319 1.62 gson continue; 320 1.62 gson } 321 1.62 gson break; 322 1.62 gson } 323 1.62 gson 324 1.62 gson pid = fork(); 325 1.62 gson switch (pid) { 326 1.62 gson case -1: 327 1.67 christos return -1; 328 1.62 gson case 0: 329 1.67 christos /* child */ 330 1.67 christos (void)close(detach_msg_pipe[0]); 331 1.72 gson return detach_msg_pipe[1]; 332 1.62 gson default: 333 1.67 christos break; 334 1.62 gson } 335 1.62 gson 336 1.62 gson /* Parent */ 337 1.62 gson (void)close(detach_msg_pipe[1]); 338 1.62 gson 339 1.62 gson for (;;) { 340 1.62 gson ssize_t nread; 341 1.62 gson char dummy; 342 1.62 gson nread = read(detach_msg_pipe[0], &dummy, 1); 343 1.73 christos if (nread == -1) { 344 1.62 gson if (errno == EINTR) 345 1.62 gson continue; 346 1.73 christos _exit(EXIT_FAILURE); 347 1.62 gson } else if (nread == 0) { 348 1.73 christos _exit(EXIT_FAILURE); 349 1.62 gson } else { /* nread > 0 */ 350 1.73 christos _exit(EXIT_SUCCESS); 351 1.62 gson } 352 1.62 gson } 353 1.62 gson } 354 1.62 gson 355 1.62 gson static int 356 1.62 gson daemon2_detach(int parentfd, int nochdir, int noclose) 357 1.62 gson { 358 1.62 gson int fd; 359 1.62 gson 360 1.62 gson if (setsid() == -1) 361 1.62 gson return -1; 362 1.62 gson 363 1.62 gson if (!nochdir) 364 1.62 gson (void)chdir("/"); 365 1.62 gson 366 1.62 gson if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 367 1.62 gson (void)dup2(fd, STDIN_FILENO); 368 1.62 gson (void)dup2(fd, STDOUT_FILENO); 369 1.62 gson (void)dup2(fd, STDERR_FILENO); 370 1.62 gson if (fd > STDERR_FILENO) 371 1.62 gson (void)close(fd); 372 1.62 gson } 373 1.62 gson 374 1.62 gson while (1) { 375 1.62 gson ssize_t r = write(parentfd, "", 1); 376 1.73 christos if (r == -1) { 377 1.62 gson if (errno == EINTR) 378 1.62 gson continue; 379 1.62 gson else if (errno == EPIPE) 380 1.62 gson break; 381 1.62 gson else 382 1.62 gson return -1; 383 1.62 gson } else if (r == 0) { 384 1.62 gson /* Should not happen */ 385 1.62 gson return -1; 386 1.62 gson } else { 387 1.62 gson break; 388 1.62 gson } 389 1.62 gson } 390 1.62 gson 391 1.62 gson (void)close(parentfd); 392 1.62 gson 393 1.62 gson return 0; 394 1.62 gson } 395 1.62 gson 396 1.62 gson /* 397 1.1 cgd * Nfs server daemon mostly just a user context for nfssvc() 398 1.11 mycroft * 399 1.1 cgd * 1 - do file descriptor and signal cleanup 400 1.50 yamt * 2 - create the nfsd thread(s) 401 1.11 mycroft * 3 - create server socket(s) 402 1.11 mycroft * 4 - register socket with portmap 403 1.11 mycroft * 404 1.28 lukem * For connectionless protocols, just pass the socket into the kernel via 405 1.11 mycroft * nfssvc(). 406 1.11 mycroft * For connection based sockets, loop doing accepts. When you get a new 407 1.28 lukem * socket from accept, pass the msgsock into the kernel via nfssvc(). 408 1.1 cgd * The arguments are: 409 1.11 mycroft * -r - reregister with portmapper 410 1.59 christos * -t - support only tcp nfs clients 411 1.59 christos * -u - support only udp nfs clients 412 1.59 christos * -n num how many threads to create. 413 1.59 christos * -4 - use only ipv4 414 1.59 christos * -6 - use only ipv6 415 1.1 cgd */ 416 1.11 mycroft int 417 1.58 joerg main(int argc, char *argv[]) 418 1.1 cgd { 419 1.59 christos struct conf cfg[4]; 420 1.59 christos struct pollfd set[__arraycount(cfg)]; 421 1.59 christos int ch, connect_type_cnt; 422 1.59 christos size_t i, nfsdcnt; 423 1.59 christos int reregister; 424 1.59 christos int tcpflag, udpflag; 425 1.59 christos int ip6flag, ip4flag; 426 1.59 christos int s, compat; 427 1.62 gson int parent_fd = -1; 428 1.68 christos pthread_t *workers; 429 1.11 mycroft 430 1.11 mycroft #define DEFNFSDCNT 4 431 1.11 mycroft nfsdcnt = DEFNFSDCNT; 432 1.59 christos compat = reregister = 0; 433 1.59 christos tcpflag = udpflag = 1; 434 1.59 christos ip6flag = ip4flag = 1; 435 1.66 christos #define GETOPT "46dn:rtu" 436 1.66 christos #define USAGE "[-46drtu] [-n num_servers]" 437 1.30 thorpej while ((ch = getopt(argc, argv, GETOPT)) != -1) { 438 1.11 mycroft switch (ch) { 439 1.32 fvdl case '6': 440 1.32 fvdl ip6flag = 1; 441 1.59 christos ip4flag = 0; 442 1.32 fvdl s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); 443 1.73 christos if (s == -1 && (errno == EPROTONOSUPPORT || 444 1.32 fvdl errno == EPFNOSUPPORT || errno == EAFNOSUPPORT)) 445 1.32 fvdl ip6flag = 0; 446 1.32 fvdl else 447 1.32 fvdl close(s); 448 1.32 fvdl break; 449 1.59 christos case '4': 450 1.59 christos ip6flag = 0; 451 1.59 christos ip4flag = 1; 452 1.59 christos s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 453 1.73 christos if (s == -1 && (errno == EPROTONOSUPPORT || 454 1.59 christos errno == EPFNOSUPPORT || errno == EAFNOSUPPORT)) 455 1.59 christos ip4flag = 0; 456 1.59 christos else 457 1.59 christos close(s); 458 1.59 christos break; 459 1.66 christos case 'd': 460 1.66 christos debug++; 461 1.66 christos break; 462 1.11 mycroft case 'n': 463 1.11 mycroft nfsdcnt = atoi(optarg); 464 1.53 yamt if (nfsdcnt < 1) { 465 1.59 christos warnx("nfsd count %zu; reset to %d", nfsdcnt, 466 1.59 christos DEFNFSDCNT); 467 1.11 mycroft nfsdcnt = DEFNFSDCNT; 468 1.11 mycroft } 469 1.11 mycroft break; 470 1.1 cgd case 'r': 471 1.11 mycroft reregister = 1; 472 1.1 cgd break; 473 1.1 cgd case 't': 474 1.59 christos compat |= 2; 475 1.11 mycroft tcpflag = 1; 476 1.59 christos udpflag = 0; 477 1.1 cgd break; 478 1.1 cgd case 'u': 479 1.59 christos compat |= 1; 480 1.59 christos tcpflag = 0; 481 1.11 mycroft udpflag = 1; 482 1.11 mycroft break; 483 1.1 cgd default: 484 1.1 cgd case '?': 485 1.1 cgd usage(); 486 1.59 christos } 487 1.30 thorpej } 488 1.11 mycroft argv += optind; 489 1.11 mycroft argc -= optind; 490 1.1 cgd 491 1.59 christos if (compat == 3) { 492 1.59 christos warnx("Old -tu options detected; enabling both udp and tcp."); 493 1.59 christos warnx("This is the default behavior now and you can remove"); 494 1.59 christos warnx("all options."); 495 1.59 christos tcpflag = udpflag = 1; 496 1.59 christos if (ip6flag == 1 && ip4flag == 0) 497 1.59 christos ip4flag = 1; 498 1.1 cgd } 499 1.31 soren 500 1.1 cgd if (debug == 0) { 501 1.62 gson parent_fd = daemon2_fork(); 502 1.67 christos if (parent_fd == -1) 503 1.67 christos logit(LOG_ERR, "daemon2_fork failed"); 504 1.66 christos openlog("nfsd", LOG_PID, LOG_DAEMON); 505 1.1 cgd } 506 1.11 mycroft 507 1.32 fvdl 508 1.63 christos memset(cfg, 0, sizeof(cfg)); 509 1.59 christos for (i = 0; i < __arraycount(cfg); i++) { 510 1.59 christos if (ip4flag == 0 && cfg_family[i] == PF_INET) 511 1.59 christos continue; 512 1.59 christos if (ip6flag == 0 && cfg_family[i] == PF_INET6) 513 1.59 christos continue; 514 1.59 christos if (tcpflag == 0 && cfg_protocol[i] == IPPROTO_TCP) 515 1.59 christos continue; 516 1.59 christos if (udpflag == 0 && cfg_protocol[i] == IPPROTO_UDP) 517 1.59 christos continue; 518 1.59 christos tryconf(&cfg[i], i, reregister); 519 1.8 cgd } 520 1.32 fvdl 521 1.68 christos workers = calloc(nfsdcnt, sizeof(*workers)); 522 1.68 christos if (workers == NULL) { 523 1.68 christos logit(LOG_ERR, "thread alloc %s", strerror(errno)); 524 1.73 christos exit(EXIT_FAILURE); 525 1.68 christos } 526 1.68 christos 527 1.11 mycroft for (i = 0; i < nfsdcnt; i++) { 528 1.50 yamt int error; 529 1.50 yamt 530 1.68 christos error = pthread_create(&workers[i], NULL, worker, NULL); 531 1.50 yamt if (error) { 532 1.50 yamt errno = error; 533 1.66 christos logit(LOG_ERR, "pthread_create: %s", strerror(errno)); 534 1.73 christos exit(EXIT_FAILURE); 535 1.32 fvdl } 536 1.11 mycroft } 537 1.11 mycroft 538 1.11 mycroft connect_type_cnt = 0; 539 1.59 christos for (i = 0; i < __arraycount(cfg); i++) { 540 1.59 christos set[i].fd = -1; 541 1.59 christos set[i].events = POLLIN; 542 1.59 christos set[i].revents = 0; 543 1.59 christos 544 1.59 christos if (cfg[i].nc == NULL) 545 1.59 christos continue; 546 1.59 christos 547 1.59 christos setupsock(&cfg[i], &set[i], i); 548 1.59 christos if (set[i].fd != -1) 549 1.59 christos connect_type_cnt++; 550 1.59 christos } 551 1.11 mycroft 552 1.51 yamt pthread_setname_np(pthread_self(), "master", NULL); 553 1.11 mycroft 554 1.62 gson if (debug == 0) { 555 1.62 gson daemon2_detach(parent_fd, 0, 0); 556 1.62 gson (void)signal(SIGHUP, SIG_IGN); 557 1.62 gson (void)signal(SIGINT, SIG_IGN); 558 1.62 gson (void)signal(SIGQUIT, SIG_IGN); 559 1.62 gson (void)signal(SIGSYS, nonfs); 560 1.62 gson } 561 1.62 gson 562 1.68 christos if (connect_type_cnt == 0) { 563 1.68 christos for (i = 0; i < nfsdcnt; i++) 564 1.68 christos pthread_join(workers[i], NULL); 565 1.73 christos exit(EXIT_SUCCESS); 566 1.68 christos } 567 1.68 christos 568 1.11 mycroft /* 569 1.11 mycroft * Loop forever accepting connections and passing the sockets 570 1.11 mycroft * into the kernel for the mounts. 571 1.11 mycroft */ 572 1.11 mycroft for (;;) { 573 1.59 christos if (poll(set, __arraycount(set), INFTIM) == -1) { 574 1.66 christos logit(LOG_ERR, "poll failed: %s", strerror(errno)); 575 1.73 christos exit(EXIT_FAILURE); 576 1.11 mycroft } 577 1.38 mycroft 578 1.59 christos for (i = 0; i < __arraycount(set); i++) { 579 1.59 christos struct nfsd_args nfsdargs; 580 1.59 christos struct sockaddr_storage ss; 581 1.59 christos socklen_t len; 582 1.59 christos int msgsock; 583 1.59 christos int on = 1; 584 1.59 christos 585 1.59 christos if ((set[i].revents & POLLIN) == 0) 586 1.59 christos continue; 587 1.59 christos len = sizeof(ss); 588 1.59 christos if ((msgsock = accept(set[i].fd, 589 1.59 christos (struct sockaddr *)&ss, &len)) == -1) { 590 1.59 christos int serrno = errno; 591 1.66 christos logit(LOG_ERR, "accept failed: %s", 592 1.65 christos strerror(errno)); 593 1.57 christos if (serrno == EINTR || serrno == ECONNABORTED) 594 1.57 christos continue; 595 1.73 christos exit(EXIT_FAILURE); 596 1.1 cgd } 597 1.59 christos if (setsockopt(msgsock, SOL_SOCKET, SO_KEEPALIVE, &on, 598 1.59 christos sizeof(on)) == -1) 599 1.66 christos logit(LOG_ERR, "setsockopt SO_KEEPALIVE: %s", 600 1.65 christos strerror(errno)); 601 1.11 mycroft nfsdargs.sock = msgsock; 602 1.59 christos nfsdargs.name = (void *)&ss; 603 1.11 mycroft nfsdargs.namelen = len; 604 1.11 mycroft nfssvc(NFSSVC_ADDSOCK, &nfsdargs); 605 1.11 mycroft (void)close(msgsock); 606 1.1 cgd } 607 1.1 cgd } 608 1.1 cgd } 609 1.1 cgd 610 1.58 joerg static void 611 1.58 joerg usage(void) 612 1.1 cgd { 613 1.59 christos (void)fprintf(stderr, "Usage: %s %s\n", getprogname(), USAGE); 614 1.73 christos exit(EXIT_FAILURE); 615 1.1 cgd } 616 1.1 cgd 617 1.58 joerg static void 618 1.58 joerg nonfs(int signo) 619 1.1 cgd { 620 1.66 christos logit(LOG_ERR, "missing system call: NFS not available."); 621 1.1 cgd } 622