1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 /* LINTLIBRARY */ 40 /* PROTOLIB1 */ 41 42 #pragma ident "%Z%%M% %I% %E% SMI" 43 44 /* NFS server */ 45 46 #include <sys/param.h> 47 #include <sys/types.h> 48 #include <syslog.h> 49 #include <tiuser.h> 50 #include <rpc/rpc.h> 51 #include <errno.h> 52 #include <thread.h> 53 #include <sys/resource.h> 54 #include <sys/time.h> 55 #include <sys/file.h> 56 #include <nfs/nfs.h> 57 #include <nfs/nfs_acl.h> 58 #include <nfs/nfssys.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <signal.h> 62 #include <netconfig.h> 63 #include <netdir.h> 64 #include <string.h> 65 #include <unistd.h> 66 #include <stropts.h> 67 #include <sys/tihdr.h> 68 #include <poll.h> 69 #include <priv_utils.h> 70 #include <sys/tiuser.h> 71 #include <netinet/tcp.h> 72 #include <deflt.h> 73 #include <rpcsvc/daemon_utils.h> 74 #include <rpcsvc/nfs4_prot.h> 75 #include "nfs_tbind.h" 76 #include "thrpool.h" 77 78 /* quiesce requests will be ignored if nfs_server_vers_max < QUIESCE_VERSMIN */ 79 #define QUIESCE_VERSMIN 4 80 81 static int nfssvc(int, struct netbuf, struct netconfig *); 82 static int nfssvcpool(int maxservers); 83 static void usage(void); 84 85 extern int _nfssys(int, void *); 86 87 /* signal handlers */ 88 static void sigflush(int); 89 static void quiesce(int); 90 91 static char *MyName; 92 static NETSELDECL(defaultproviders)[] = { "/dev/tcp6", "/dev/tcp", "/dev/udp", 93 "/dev/udp6", NULL }; 94 /* static NETSELDECL(defaultprotos)[] = { NC_UDP, NC_TCP, NULL }; */ 95 /* 96 * The following are all globals used by routines in nfs_tbind.c. 97 */ 98 size_t end_listen_fds; /* used by conn_close_oldest() */ 99 size_t num_fds = 0; /* used by multiple routines */ 100 int listen_backlog = 32; /* used by bind_to_{provider,proto}() */ 101 int num_servers; /* used by cots_listen_event() */ 102 int (*Mysvc)(int, struct netbuf, struct netconfig *) = nfssvc; 103 /* used by cots_listen_event() */ 104 int max_conns_allowed = -1; /* used by cots_listen_event() */ 105 106 /* 107 * Keep track of min/max versions of NFS protocol to be started. 108 * Start with the defaults (min == 2, max == 3). We have the 109 * capability of starting vers=4 but only if the user requests it. 110 */ 111 int nfs_server_vers_min = NFS_VERSMIN_DEFAULT; 112 int nfs_server_vers_max = NFS_VERSMAX_DEFAULT; 113 114 /* 115 * Set the default for server delegation enablement and set per 116 * /etc/default/nfs configuration (if present). 117 */ 118 int nfs_server_delegation = NFS_SERVER_DELEGATION_DEFAULT; 119 120 int 121 main(int ac, char *av[]) 122 { 123 char *dir = "/"; 124 int allflag = 0; 125 int df_allflag = 0; 126 int opt_cnt = 0; 127 int maxservers = 1; /* zero allows inifinte number of threads */ 128 int maxservers_set = 0; 129 int logmaxservers = 0; 130 int pid; 131 int i; 132 char *provider = (char *)NULL; 133 char *df_provider = (char *)NULL; 134 struct protob *protobp0, *protobp; 135 NETSELDECL(proto) = NULL; 136 NETSELDECL(df_proto) = NULL; 137 NETSELPDECL(providerp); 138 char *defval; 139 boolean_t can_do_mlp; 140 141 MyName = *av; 142 143 /* 144 * Initializations that require more privileges than we need to run. 145 */ 146 (void) _create_daemon_lock(NFSD, DAEMON_UID, DAEMON_GID); 147 svcsetprio(); 148 149 can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP); 150 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 151 DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS, 152 can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) { 153 (void) fprintf(stderr, "%s should be run with" 154 " sufficient privileges\n", av[0]); 155 exit(1); 156 } 157 158 /* 159 * Read in the values from config file first before we check 160 * commandline options so the options override the file. 161 */ 162 if ((defopen(NFSADMIN)) == 0) { 163 if ((defval = defread("NFSD_MAX_CONNECTIONS=")) != NULL) { 164 errno = 0; 165 max_conns_allowed = strtol(defval, (char **)NULL, 10); 166 if (errno != 0) { 167 max_conns_allowed = -1; 168 } 169 } 170 if ((defval = defread("NFSD_LISTEN_BACKLOG=")) != NULL) { 171 errno = 0; 172 listen_backlog = strtol(defval, (char **)NULL, 10); 173 if (errno != 0) { 174 listen_backlog = 32; 175 } 176 } 177 if ((defval = defread("NFSD_PROTOCOL=")) != NULL) { 178 df_proto = strdup(defval); 179 opt_cnt++; 180 if (strncasecmp("ALL", defval, 3) == 0) { 181 free(df_proto); 182 df_proto = NULL; 183 df_allflag = 1; 184 } 185 } 186 if ((defval = defread("NFSD_DEVICE=")) != NULL) { 187 df_provider = strdup(defval); 188 opt_cnt++; 189 } 190 if ((defval = defread("NFSD_SERVERS=")) != NULL) { 191 errno = 0; 192 maxservers = strtol(defval, (char **)NULL, 10); 193 if (errno != 0) { 194 maxservers = 1; 195 } else { 196 maxservers_set = 1; 197 } 198 } 199 if ((defval = defread("NFS_SERVER_VERSMIN=")) != NULL) { 200 errno = 0; 201 nfs_server_vers_min = 202 strtol(defval, (char **)NULL, 10); 203 if (errno != 0) { 204 nfs_server_vers_min = NFS_VERSMIN_DEFAULT; 205 } 206 } 207 if ((defval = defread("NFS_SERVER_VERSMAX=")) != NULL) { 208 errno = 0; 209 nfs_server_vers_max = 210 strtol(defval, (char **)NULL, 10); 211 if (errno != 0) { 212 nfs_server_vers_max = NFS_VERSMAX_DEFAULT; 213 } 214 } 215 if ((defval = defread("NFS_SERVER_DELEGATION=")) != NULL) { 216 if (strcmp(defval, "off") == 0) { 217 nfs_server_delegation = FALSE; 218 } 219 } 220 221 /* close defaults file */ 222 defopen(NULL); 223 } 224 225 /* 226 * Conflict options error messages. 227 */ 228 if (opt_cnt > 1) { 229 (void) fprintf(stderr, "\nConflicting options, only one of " 230 "the following options can be specified\n" 231 "in " NFSADMIN ":\n" 232 "\tNFSD_PROTOCOL=ALL\n" 233 "\tNFSD_PROTOCOL=protocol\n" 234 "\tNFSD_DEVICE=device\n\n"); 235 usage(); 236 } 237 opt_cnt = 0; 238 239 while ((i = getopt(ac, av, "ac:p:t:l:")) != EOF) { 240 switch (i) { 241 case 'a': 242 free(df_proto); 243 df_proto = NULL; 244 free(df_provider); 245 df_provider = NULL; 246 247 allflag = 1; 248 opt_cnt++; 249 break; 250 251 case 'c': 252 max_conns_allowed = atoi(optarg); 253 break; 254 255 case 'p': 256 proto = optarg; 257 df_allflag = 0; 258 opt_cnt++; 259 break; 260 261 case 't': 262 provider = optarg; 263 df_allflag = 0; 264 opt_cnt++; 265 break; 266 267 case 'l': 268 listen_backlog = atoi(optarg); 269 break; 270 271 case '?': 272 usage(); 273 /* NOTREACHED */ 274 } 275 } 276 277 allflag = df_allflag; 278 if (proto == NULL) 279 proto = df_proto; 280 if (provider == NULL) 281 provider = df_provider; 282 283 /* 284 * Conflict options error messages. 285 */ 286 if (opt_cnt > 1) { 287 (void) fprintf(stderr, "\nConflicting options, only one of " 288 "the following options can be specified\n" 289 "on the command line:\n" 290 "\t-a\n" 291 "\t-p protocol\n" 292 "\t-t transport\n\n"); 293 usage(); 294 } 295 296 if (proto != NULL && 297 strncasecmp(proto, NC_UDP, strlen(NC_UDP)) == 0) { 298 if (nfs_server_vers_max == NFS_V4) { 299 if (nfs_server_vers_min == NFS_V4) { 300 syslog(LOG_ERR, 301 "NFS version 4 is not supported " 302 "with the UDP protocol. Exiting\n"); 303 fprintf(stderr, 304 "NFS version 4 is not supported " 305 "with the UDP protocol. Exiting\n"); 306 exit(3); 307 } else { 308 fprintf(stderr, 309 "NFS version 4 is not supported " 310 "with the UDP protocol.\n"); 311 } 312 } 313 } 314 315 /* 316 * If there is exactly one more argument, it is the number of 317 * servers. 318 */ 319 if (optind == ac - 1) { 320 maxservers = atoi(av[optind]); 321 maxservers_set = 1; 322 } 323 /* 324 * If there are two or more arguments, then this is a usage error. 325 */ 326 else if (optind < ac - 1) 327 usage(); 328 /* 329 * Check the ranges for min/max version specified 330 */ 331 else if ((nfs_server_vers_min > nfs_server_vers_max) || 332 (nfs_server_vers_min < NFS_VERSMIN) || 333 (nfs_server_vers_max > NFS_VERSMAX)) 334 usage(); 335 /* 336 * There are no additional arguments, and we haven't set maxservers 337 * explicitly via the config file, we use a default number of 338 * servers. We will log this. 339 */ 340 else if (maxservers_set == 0) 341 logmaxservers = 1; 342 343 /* 344 * Basic Sanity checks on options 345 * 346 * max_conns_allowed must be positive, except for the special 347 * value of -1 which is used internally to mean unlimited, -1 isn't 348 * documented but we allow it anyway. 349 * 350 * maxservers must be positive 351 * listen_backlog must be positive or zero 352 */ 353 if (((max_conns_allowed != -1) && (max_conns_allowed <= 0)) || 354 (listen_backlog < 0) || (maxservers <= 0)) { 355 usage(); 356 } 357 358 /* 359 * Set current dir to server root 360 */ 361 if (chdir(dir) < 0) { 362 (void) fprintf(stderr, "%s: ", MyName); 363 perror(dir); 364 exit(1); 365 } 366 367 #ifndef DEBUG 368 /* 369 * Background 370 */ 371 pid = fork(); 372 if (pid < 0) { 373 perror("nfsd: fork"); 374 exit(1); 375 } 376 if (pid != 0) 377 exit(0); 378 379 /* 380 * Close existing file descriptors, open "/dev/null" as 381 * standard input, output, and error, and detach from 382 * controlling terminal. 383 */ 384 closefrom(0); 385 (void) open("/dev/null", O_RDONLY); 386 (void) open("/dev/null", O_WRONLY); 387 (void) dup(1); 388 (void) setsid(); 389 #endif 390 openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON); 391 392 /* 393 * establish our lock on the lock file and write our pid to it. 394 * exit if some other process holds the lock, or if there's any 395 * error in writing/locking the file. 396 */ 397 pid = _enter_daemon_lock(NFSD); 398 switch (pid) { 399 case 0: 400 break; 401 case -1: 402 syslog(LOG_ERR, "error locking for %s: %s", NFSD, 403 strerror(errno)); 404 exit(2); 405 default: 406 /* daemon was already running */ 407 exit(0); 408 } 409 410 sigset(SIGTERM, sigflush); 411 sigset(SIGUSR1, quiesce); 412 413 if (logmaxservers) { 414 (void) syslog(LOG_INFO, 415 "Number of servers not specified. Using default of %d.", 416 maxservers); 417 } 418 419 /* 420 * Make sure to unregister any previous versions in case the 421 * user is reconfiguring the server in interesting ways. 422 */ 423 svc_unreg(NFS_PROGRAM, NFS_VERSION); 424 svc_unreg(NFS_PROGRAM, NFS_V3); 425 svc_unreg(NFS_PROGRAM, NFS_V4); 426 svc_unreg(NFS_ACL_PROGRAM, NFS_ACL_V2); 427 svc_unreg(NFS_ACL_PROGRAM, NFS_ACL_V3); 428 429 /* 430 * Set up kernel RPC thread pool for the NFS server. 431 */ 432 if (nfssvcpool(maxservers)) { 433 (void) syslog(LOG_ERR, 434 "Can't set up kernel NFS service: %m. Exiting"); 435 exit(1); 436 } 437 438 439 /* 440 * Set up blocked thread to do LWP creation on behalf of the kernel. 441 */ 442 if (svcwait(NFS_SVCPOOL_ID)) { 443 (void) syslog(LOG_ERR, 444 "Can't set up NFS pool creator: %m, Exiting"); 445 exit(1); 446 } 447 448 /* 449 * RDMA start and stop thread. 450 * Per pool RDMA listener creation and 451 * destructor thread. 452 * 453 * start rdma services and block in the kernel. 454 */ 455 if (svcrdma(NFS_SVCPOOL_ID, nfs_server_vers_min, nfs_server_vers_max, 456 nfs_server_delegation)) { 457 (void) syslog(LOG_ERR, 458 "Can't set up RDMA creator thread : %m."); 459 } 460 461 /* 462 * Build a protocol block list for registration. 463 */ 464 protobp0 = protobp = (struct protob *)malloc(sizeof (struct protob)); 465 protobp->serv = "NFS"; 466 protobp->versmin = nfs_server_vers_min; 467 protobp->versmax = nfs_server_vers_max; 468 protobp->program = NFS_PROGRAM; 469 470 protobp->next = (struct protob *)malloc(sizeof (struct protob)); 471 protobp = protobp->next; 472 protobp->serv = "NFS_ACL"; /* not used */ 473 protobp->versmin = nfs_server_vers_min; 474 /* XXX - this needs work to get the version just right */ 475 protobp->versmax = (nfs_server_vers_max > NFS_ACL_V3) ? 476 NFS_ACL_V3 : nfs_server_vers_max; 477 protobp->program = NFS_ACL_PROGRAM; 478 protobp->next = (struct protob *)NULL; 479 480 if (allflag) { 481 if (do_all(protobp0, nfssvc) == -1) 482 exit(1); 483 } else if (proto) { 484 /* there's more than one match for the same protocol */ 485 struct netconfig *nconf; 486 NCONF_HANDLE *nc; 487 bool_t protoFound = FALSE; 488 if ((nc = setnetconfig()) == (NCONF_HANDLE *) NULL) { 489 syslog(LOG_ERR, "setnetconfig failed: %m"); 490 goto done; 491 } 492 while (nconf = getnetconfig(nc)) { 493 if (strcmp(nconf->nc_proto, proto) == 0) { 494 protoFound = TRUE; 495 do_one(nconf->nc_device, NULL, 496 protobp0, nfssvc); 497 } 498 } 499 (void) endnetconfig(nc); 500 if (protoFound == FALSE) 501 syslog(LOG_ERR, "couldn't find netconfig entry \ 502 for protocol %s", proto); 503 504 } else if (provider) 505 do_one(provider, proto, protobp0, nfssvc); 506 else { 507 for (providerp = defaultproviders; 508 *providerp != NULL; providerp++) { 509 provider = *providerp; 510 do_one(provider, NULL, protobp0, nfssvc); 511 } 512 } 513 done: 514 515 free(protobp); 516 free(protobp0); 517 518 if (num_fds == 0) { 519 (void) syslog(LOG_ERR, 520 "Could not start NFS service for any protocol. Exiting."); 521 exit(1); 522 } 523 524 end_listen_fds = num_fds; 525 526 /* 527 * Get rid of unneeded privileges. 528 */ 529 __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION, 530 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); 531 532 /* 533 * Poll for non-data control events on the transport descriptors. 534 */ 535 poll_for_action(); 536 537 /* 538 * If we get here, something failed in poll_for_action(). 539 */ 540 return (1); 541 } 542 543 static int 544 nfssvcpool(int maxservers) 545 { 546 struct svcpool_args npa; 547 548 npa.id = NFS_SVCPOOL_ID; 549 npa.maxthreads = maxservers; 550 npa.redline = 0; 551 npa.qsize = 0; 552 npa.timeout = 0; 553 npa.stksize = 0; 554 npa.max_same_xprt = 0; 555 return (_nfssys(SVCPOOL_CREATE, &npa)); 556 } 557 558 /* 559 * Establish NFS service thread. 560 */ 561 static int 562 nfssvc(int fd, struct netbuf addrmask, struct netconfig *nconf) 563 { 564 struct nfs_svc_args nsa; 565 566 nsa.fd = fd; 567 nsa.netid = nconf->nc_netid; 568 nsa.addrmask = addrmask; 569 if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0) { 570 nsa.versmax = (nfs_server_vers_max > NFS_V3) ? 571 NFS_V3 : nfs_server_vers_max; 572 nsa.versmin = nfs_server_vers_min; 573 /* 574 * If no version left, silently do nothing, previous 575 * checks will have assured at least TCP is available. 576 */ 577 if (nsa.versmin > nsa.versmax) 578 return (0); 579 } else { 580 nsa.versmax = nfs_server_vers_max; 581 nsa.versmin = nfs_server_vers_min; 582 } 583 nsa.delegation = nfs_server_delegation; 584 return (_nfssys(NFS_SVC, &nsa)); 585 } 586 587 static void 588 usage(void) 589 { 590 (void) fprintf(stderr, 591 "usage: %s [ -a ] [ -c max_conns ] [ -p protocol ] [ -t transport ] ", MyName); 592 (void) fprintf(stderr, "\n[ -l listen_backlog ] [ nservers ]\n"); 593 (void) fprintf(stderr, 594 "\twhere -a causes <nservers> to be started on each appropriate transport,\n"); 595 (void) fprintf(stderr, 596 "\tmax_conns is the maximum number of concurrent connections allowed,\n"); 597 (void) fprintf(stderr, "\t\tand max_conns must be a decimal number"); 598 (void) fprintf(stderr, "> zero,\n"); 599 (void) fprintf(stderr, "\tprotocol is a protocol identifier,\n"); 600 (void) fprintf(stderr, 601 "\ttransport is a transport provider name (i.e. device),\n"); 602 (void) fprintf(stderr, 603 "\tlisten_backlog is the TCP listen backlog,\n"); 604 (void) fprintf(stderr, 605 "\tand <nservers> must be a decimal number > zero.\n"); 606 exit(1); 607 } 608 609 /* 610 * Issue nfssys system call to flush all logging buffers asynchronously. 611 * 612 * NOTICE: It is extremely important to flush NFS logging buffers when 613 * nfsd exits. When the system is halted or rebooted nfslogd 614 * may not have an opportunity to flush the buffers. 615 */ 616 static void 617 nfsl_flush() 618 { 619 struct nfsl_flush_args nfa; 620 621 memset((void *)&nfa, 0, sizeof (nfa)); 622 nfa.version = NFSL_FLUSH_ARGS_VERS; 623 nfa.directive = NFSL_ALL; /* flush all asynchronously */ 624 625 if (_nfssys(LOG_FLUSH, &nfa) < 0) 626 syslog(LOG_ERR, "_nfssys(LOG_FLUSH) failed: %s\n", 627 strerror(errno)); 628 } 629 630 /* 631 * SIGTERM handler. 632 * Flush logging buffers and exit. 633 */ 634 static void 635 sigflush(int sig) 636 { 637 nfsl_flush(); 638 exit(0); 639 } 640 641 /* 642 * SIGUSR1 handler. 643 * Request server quiesce, then exit. For subsequent warm start. 644 * Equivalent to SIGTERM handler if nfs_server_vers_max < QUIESCE_VERSMIN. 645 */ 646 static void 647 quiesce(int sig) 648 { 649 int error; 650 int id = NFS_SVCPOOL_ID; 651 652 if (nfs_server_vers_max >= QUIESCE_VERSMIN) { 653 /* Request server quiesce at next shutdown */ 654 error = _nfssys(NFS_SVC_REQUEST_QUIESCE, &id); 655 if (error) { 656 syslog(LOG_ERR, 657 "_nfssys(NFS_SVC_REQUEST_QUIESCE) failed: %s\n", 658 strerror(errno)); 659 return; 660 } 661 } 662 663 /* Flush logging buffers */ 664 nfsl_flush(); 665 666 exit(0); 667 } 668