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 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Main routines for cachefs daemon. 30 */ 31 32 #include <stdio.h> 33 #include <stdio_ext.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <errno.h> 37 #include <rpc/rpc.h> 38 #include <rpc/pmap_clnt.h> /* for pmap_unset */ 39 #include <string.h> /* strcmp */ 40 #include <signal.h> 41 #include <unistd.h> /* setsid */ 42 #include <sys/types.h> 43 #include <memory.h> 44 #include <stropts.h> 45 #include <netconfig.h> 46 #include <libintl.h> 47 #include <locale.h> 48 #include <thread.h> 49 #include <sys/resource.h> /* rlimit */ 50 #include <synch.h> 51 #include <mdbug/mdbug.h> 52 #include <common/cachefsd.h> 53 #include <sys/fs/cachefs_fs.h> 54 #include <sys/fs/cachefs_dlog.h> 55 #include <sys/fs/cachefs_ioctl.h> 56 #include "cfsd.h" 57 #include "cfsd_kmod.h" 58 #include "cfsd_maptbl.h" 59 #include "cfsd_logfile.h" 60 #include "cfsd_fscache.h" 61 #include "cfsd_cache.h" 62 #include "cfsd_all.h" 63 #include "cfsd_subr.h" 64 65 #define RPCGEN_ACTION(X) X 66 #include "cachefsd_tbl.i" 67 68 #ifndef SIG_PF 69 #define SIG_PF void(*)(int) 70 #endif 71 72 typedef bool_t (* LOCAL)(void *, void *, struct svc_req *); 73 74 /* global definitions */ 75 cfsd_all_object_t *all_object_p = NULL; 76 77 /* forward references */ 78 void msgout(char *msgp); 79 void cachefsdprog_1(struct svc_req *rqstp, register SVCXPRT *transp); 80 void sigusr1_handler(int, siginfo_t *, void *); 81 static int void_close(void *, int); 82 83 /* 84 * ----------------------------------------------------------------- 85 * main 86 * 87 * Description: 88 * main routine for the chart daemon. 89 * Arguments: 90 * argc 91 * argv 92 * Returns: 93 * Returns 0 for a normal exit, !0 if an error occurred. 94 * Preconditions: 95 * precond(argv) 96 */ 97 98 int 99 main(int argc, char **argv) 100 { 101 pid_t pid; 102 int xx; 103 char mname[FMNAMESZ + 1]; 104 int opt_fork = 0; 105 int opt_mt = 0; 106 char *opt_root = NULL; 107 int c; 108 char *msgp; 109 int size; 110 struct rlimit rl; 111 struct sigaction nact; 112 int ofd = -1; 113 char *netid; 114 struct netconfig *nconf = NULL; 115 SVCXPRT *transp; 116 cfsd_fscache_object_t *fscache_object_p; 117 int mode; 118 /* selectable maximum RPC request record size */ 119 int maxrecsz = RPC_MAXDATASIZE; 120 121 dbug_enter("main"); 122 dbug_process("cfsadmin"); 123 124 (void) setlocale(LC_ALL, ""); 125 #if !defined(TEXT_DOMAIN) 126 #define TEXT_DOMAIN "SYS_TEST" 127 #endif 128 (void) textdomain(TEXT_DOMAIN); 129 130 /* verify root */ 131 if (getuid() != 0) { 132 fprintf(stderr, gettext("%s: must be run by root\n"), argv[0]); 133 dbug_leave("main"); 134 return (1); 135 } 136 137 /* Increase number of file descriptors to maximum allowable */ 138 xx = getrlimit(RLIMIT_NOFILE, &rl); 139 if (xx < 0) { 140 dbug_print(("error", 141 "getrlimit/RLIMIT_NOFILE failed %d", errno)); 142 dbug_leave("main"); 143 return (1); 144 } 145 rl.rlim_cur = rl.rlim_max; 146 xx = setrlimit(RLIMIT_NOFILE, &rl); 147 if (xx < 0) { 148 dbug_print(("error", 149 "setrlimit/RLIMIT_NOFILE failed %d", errno)); 150 dbug_leave("main"); 151 return (1); 152 } 153 (void) enable_extended_FILE_stdio(-1, -1); 154 155 while ((c = getopt(argc, argv, "fmr:#:")) != EOF) { 156 switch (c) { 157 case 'f': 158 opt_fork = 1; 159 break; 160 161 case 'm': 162 /* 163 * XXX don't use this until race between mount 164 * and umount is fixed. 165 */ 166 opt_mt = 1; 167 break; 168 169 case 'r': 170 opt_root = optarg; 171 break; 172 173 case '#': /* dbug args */ 174 msgp = dbug_push(optarg); 175 if (msgp) { 176 printf("dbug_push failed \"%s\"\n", msgp); 177 dbug_leave("main"); 178 return (1); 179 } 180 ofd = db_getfd(); 181 break; 182 183 default: 184 printf(gettext("illegal switch\n")); 185 dbug_leave("main"); 186 return (1); 187 } 188 } 189 190 /* XXX need some way to prevent multiple daemons from running */ 191 192 dbug_print(("info", "cachefsd started...")); 193 194 if (opt_mt) { 195 dbug_print(("info", "MT_AUTO mode set")); 196 mode = RPC_SVC_MT_AUTO; 197 if (!rpc_control(RPC_SVC_MTMODE_SET, &mode)) { 198 msgout(gettext("unable to set automatic MT mode.")); 199 dbug_leave("main"); 200 return (1); 201 } 202 } 203 204 /* 205 * Enable non-blocking mode and maximum record size checks for 206 * connection oriented transports. 207 */ 208 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) { 209 msgout(gettext("unable to set max RPC record size")); 210 } 211 212 /* ignore sigpipe */ 213 nact.sa_handler = SIG_IGN; 214 nact.sa_sigaction = NULL; 215 sigemptyset(&nact.sa_mask); 216 nact.sa_flags = 0; 217 xx = sigaction(SIGPIPE, &nact, NULL); 218 if (xx) { 219 dbug_print(("error", "sigaction/SIGPIPE failed %d", errno)); 220 } 221 222 /* catch sigusr1 signals, used to wake up threads */ 223 nact.sa_handler = NULL; 224 nact.sa_sigaction = sigusr1_handler; 225 sigemptyset(&nact.sa_mask); 226 nact.sa_flags = SA_SIGINFO; 227 xx = sigaction(SIGUSR1, &nact, NULL); 228 if (xx) { 229 dbug_print(("error", "sigaction failed %d", errno)); 230 } 231 232 /* do not set up rpc services if just taking care of root */ 233 if (opt_root) { 234 dbug_print(("info", "handling just root")); 235 236 /* make the fscache object */ 237 fscache_object_p = 238 cfsd_fscache_create("rootcache", opt_root, 1); 239 240 /* init the fscache object with mount information */ 241 fscache_lock(fscache_object_p); 242 fscache_object_p->i_refcnt++; 243 fscache_setup(fscache_object_p); 244 fscache_object_p->i_mounted = 1; 245 fscache_unlock(fscache_object_p); 246 247 if (fscache_object_p->i_disconnectable && 248 fscache_object_p->i_mounted) { 249 pid = fork(); 250 if (pid < 0) { 251 perror(gettext("cannot fork")); 252 cfsd_fscache_destroy(fscache_object_p); 253 dbug_leave("main"); 254 return (1); 255 } 256 if (pid) { 257 cfsd_fscache_destroy(fscache_object_p); 258 dbug_leave("main"); 259 return (0); 260 } 261 (void) fdwalk(void_close, &ofd); 262 xx = open("/dev/sysmsg", O_RDWR); 263 (void) dup2(xx, 1); 264 (void) dup2(xx, 2); 265 setsid(); 266 267 fscache_process(fscache_object_p); 268 } else { 269 /* not disconnectable */ 270 cfsd_fscache_destroy(fscache_object_p); 271 dbug_leave("main"); 272 return (1); 273 } 274 cfsd_fscache_destroy(fscache_object_p); 275 dbug_leave("main"); 276 return (0); 277 } 278 279 /* if a inetd started us */ 280 else if (!ioctl(0, I_LOOK, mname) && 281 ((strcmp(mname, "sockmod") == 0) || 282 (strcmp(mname, "timod") == 0))) { 283 dbug_print(("info", "started by inetd")); 284 285 if (freopen("/dev/null", "w", stderr) == NULL) 286 return (1); 287 288 /* started from inetd */ 289 if ((netid = getenv("NLSPROVIDER")) == NULL) 290 netid = "ticotsord"; 291 if ((nconf = getnetconfigent(netid)) == NULL) 292 msgout(gettext("cannot get transport info")); 293 294 if (strcmp(mname, "sockmod") == 0) { 295 if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) { 296 msgout( 297 gettext("could not get the right module")); 298 dbug_leave("main"); 299 return (1); 300 } 301 } 302 if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { 303 msgout(gettext("cannot create server handle")); 304 dbug_leave("main"); 305 return (1); 306 } 307 if (nconf) 308 freenetconfigent(nconf); 309 xx = svc_reg(transp, CACHEFSDPROG, CACHEFSDVERS, 310 cachefsdprog_1, 0); 311 if (!xx) { 312 msgout(gettext( 313 "unable to reg (CACHEFSDPROG, CACHEFSDVERS).")); 314 dbug_leave("main"); 315 return (1); 316 } 317 } 318 319 /* else if started by hand */ 320 else { 321 /* if we should fork */ 322 if (opt_fork) { 323 dbug_print(("info", "forking")); 324 pid = fork(); 325 if (pid < 0) { 326 perror(gettext("cannot fork")); 327 dbug_leave("main"); 328 return (1); 329 } 330 if (pid) { 331 dbug_leave("main"); 332 return (0); 333 } 334 (void) fdwalk(void_close, &ofd); 335 xx = open("/dev/sysmsg", 2); 336 (void) dup2(xx, 1); 337 (void) dup2(xx, 2); 338 setsid(); 339 } 340 341 /* connect to *ANY* local loopback transport provider */ 342 xx = svc_create(cachefsdprog_1, CACHEFSDPROG, CACHEFSDVERS, 343 "local"); 344 if (!xx) { 345 msgout(gettext("unable to create (CACHEFSDPROG, " 346 "CACHEFSDVERS) for netpath.")); 347 dbug_leave("main"); 348 return (1); 349 } 350 } 351 352 /* find existing caches and mounted file systems */ 353 all_object_p = cfsd_all_create(); 354 subr_cache_setup(all_object_p); 355 356 /* process requests */ 357 svc_run(); 358 359 msgout(gettext("svc_run returned")); 360 cfsd_all_destroy(all_object_p); 361 dbug_leave("main"); 362 return (1); 363 } 364 365 /* 366 * Callback function for fdwalk() to close all files. 367 */ 368 static int 369 void_close(void *ofdp, int fd) 370 { 371 if (fd != *(int *)ofdp) { 372 if (close(fd) != 0) 373 dbug_print(("err", 374 "cannot close fd %d, %d", fd, errno)); 375 } 376 return (0); 377 } 378 379 /* 380 * ----------------------------------------------------------------- 381 * msgout 382 * 383 * Description: 384 * Outputs an error message to stderr. 385 * Arguments: 386 * msgp 387 * Returns: 388 * Preconditions: 389 * precond(msgp) 390 */ 391 392 void 393 msgout(char *msgp) 394 { 395 dbug_enter("msgout"); 396 dbug_precond(msgp); 397 398 (void) fprintf(stderr, "%s\n", msgp); 399 dbug_leave("msgout"); 400 } 401 402 403 /* 404 * ----------------------------------------------------------------- 405 * cachefsdprog_1 406 * 407 * Description: 408 * Arguments: 409 * rqstp 410 * transp 411 * Returns: 412 * Preconditions: 413 * precond(rqstp) 414 * precond(transp) 415 */ 416 void 417 cachefsdprog_1(struct svc_req *rqstp, register SVCXPRT *transp) 418 { 419 int index; 420 struct rpcgen_table *rtp; 421 void *argumentp = NULL; 422 void *resultp = NULL; 423 LOCAL local; 424 int xx; 425 426 dbug_enter("cachefsdprog_1"); 427 428 dbug_precond(rqstp); 429 dbug_precond(transp); 430 431 /* make sure a valid command number */ 432 index = rqstp->rq_proc; 433 if ((index < 0) || (cachefsdprog_1_nproc <= index)) { 434 msgout(gettext("bad message")); 435 svcerr_noproc(transp); 436 dbug_leave("cachefsdprog_1"); 437 return; 438 } 439 440 /* get command information */ 441 rtp = &cachefsdprog_1_table[index]; 442 443 /* get memory for the arguments */ 444 if (rtp->len_arg != 0) 445 argumentp = (void *)cfsd_calloc(rtp->len_arg); 446 447 /* get memory for the results */ 448 if (rtp->len_res != 0) 449 resultp = (void *)cfsd_calloc(rtp->len_res); 450 451 /* get the arguments */ 452 if (rtp->xdr_arg && argumentp) { 453 if (!svc_getargs(transp, rtp->xdr_arg, (caddr_t)argumentp)) { 454 svcerr_decode(transp); 455 cfsd_free(argumentp); 456 cfsd_free(resultp); 457 dbug_leave("cachefsdprog_1"); 458 return; 459 } 460 } 461 462 /* call the routine to process the command */ 463 local = (LOCAL)rtp->proc; 464 xx = (*local)(argumentp, resultp, rqstp); 465 466 /* if the command could not be processed */ 467 if (xx == 0) { 468 svcerr_systemerr(transp); 469 } 470 471 /* else send the results back to the caller */ 472 else { 473 xx = svc_sendreply(transp, rtp->xdr_res, (caddr_t)resultp); 474 if (!xx) 475 svcerr_systemerr(transp); 476 477 /* free the results */ 478 xx = cachefsdprog_1_freeresult(transp, rtp->xdr_res, 479 (caddr_t)resultp); 480 if (xx == 0) 481 msgout(gettext("unable to free results")); 482 } 483 484 /* free the passed in arguments */ 485 if (!svc_freeargs(transp, rtp->xdr_arg, (caddr_t)argumentp)) { 486 msgout(gettext("unable to free arguments")); 487 abort(); 488 } 489 490 if (argumentp) 491 cfsd_free(argumentp); 492 if (resultp) 493 cfsd_free(resultp); 494 dbug_leave("cachefsdprog_1"); 495 } 496 497 /* 498 * sigusr1_handler 499 * 500 * Description: 501 * Catches sigusr1 signal so threads wake up. 502 * Arguments: 503 * Returns: 504 * Preconditions: 505 */ 506 void 507 sigusr1_handler(int sig, siginfo_t *sp, void *vp) 508 { 509 } 510