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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1998-2000, 2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Main routines for cachefs daemon. 31 */ 32 33 #include <stdio.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 154 while ((c = getopt(argc, argv, "fmr:#:")) != EOF) { 155 switch (c) { 156 case 'f': 157 opt_fork = 1; 158 break; 159 160 case 'm': 161 /* 162 * XXX don't use this until race between mount 163 * and umount is fixed. 164 */ 165 opt_mt = 1; 166 break; 167 168 case 'r': 169 opt_root = optarg; 170 break; 171 172 case '#': /* dbug args */ 173 msgp = dbug_push(optarg); 174 if (msgp) { 175 printf("dbug_push failed \"%s\"\n", msgp); 176 dbug_leave("main"); 177 return (1); 178 } 179 ofd = db_getfd(); 180 break; 181 182 default: 183 printf(gettext("illegal switch\n")); 184 dbug_leave("main"); 185 return (1); 186 } 187 } 188 189 /* XXX need some way to prevent multiple daemons from running */ 190 191 dbug_print(("info", "cachefsd started...")); 192 193 if (opt_mt) { 194 dbug_print(("info", "MT_AUTO mode set")); 195 mode = RPC_SVC_MT_AUTO; 196 if (!rpc_control(RPC_SVC_MTMODE_SET, &mode)) { 197 msgout(gettext("unable to set automatic MT mode.")); 198 dbug_leave("main"); 199 return (1); 200 } 201 } 202 203 /* 204 * Enable non-blocking mode and maximum record size checks for 205 * connection oriented transports. 206 */ 207 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) { 208 msgout(gettext("unable to set max RPC record size")); 209 } 210 211 /* ignore sigpipe */ 212 nact.sa_handler = SIG_IGN; 213 nact.sa_sigaction = NULL; 214 sigemptyset(&nact.sa_mask); 215 nact.sa_flags = 0; 216 xx = sigaction(SIGPIPE, &nact, NULL); 217 if (xx) { 218 dbug_print(("error", "sigaction/SIGPIPE failed %d", errno)); 219 } 220 221 /* catch sigusr1 signals, used to wake up threads */ 222 nact.sa_handler = NULL; 223 nact.sa_sigaction = sigusr1_handler; 224 sigemptyset(&nact.sa_mask); 225 nact.sa_flags = SA_SIGINFO; 226 xx = sigaction(SIGUSR1, &nact, NULL); 227 if (xx) { 228 dbug_print(("error", "sigaction failed %d", errno)); 229 } 230 231 /* do not set up rpc services if just taking care of root */ 232 if (opt_root) { 233 dbug_print(("info", "handling just root")); 234 235 /* make the fscache object */ 236 fscache_object_p = 237 cfsd_fscache_create("rootcache", opt_root, 1); 238 239 /* init the fscache object with mount information */ 240 fscache_lock(fscache_object_p); 241 fscache_object_p->i_refcnt++; 242 fscache_setup(fscache_object_p); 243 fscache_object_p->i_mounted = 1; 244 fscache_unlock(fscache_object_p); 245 246 if (fscache_object_p->i_disconnectable && 247 fscache_object_p->i_mounted) { 248 pid = fork(); 249 if (pid < 0) { 250 perror(gettext("cannot fork")); 251 cfsd_fscache_destroy(fscache_object_p); 252 dbug_leave("main"); 253 return (1); 254 } 255 if (pid) { 256 cfsd_fscache_destroy(fscache_object_p); 257 dbug_leave("main"); 258 return (0); 259 } 260 (void) fdwalk(void_close, &ofd); 261 xx = open("/dev/sysmsg", O_RDWR); 262 (void) dup2(xx, 1); 263 (void) dup2(xx, 2); 264 setsid(); 265 266 fscache_process(fscache_object_p); 267 } else { 268 /* not disconnectable */ 269 cfsd_fscache_destroy(fscache_object_p); 270 dbug_leave("main"); 271 return (1); 272 } 273 cfsd_fscache_destroy(fscache_object_p); 274 dbug_leave("main"); 275 return (0); 276 } 277 278 /* if a inetd started us */ 279 else if (!ioctl(0, I_LOOK, mname) && 280 ((strcmp(mname, "sockmod") == 0) || 281 (strcmp(mname, "timod") == 0))) { 282 dbug_print(("info", "started by inetd")); 283 284 if (freopen("/dev/null", "w", stderr) == NULL) 285 return (1); 286 287 /* started from inetd */ 288 if ((netid = getenv("NLSPROVIDER")) == NULL) 289 netid = "ticotsord"; 290 if ((nconf = getnetconfigent(netid)) == NULL) 291 msgout(gettext("cannot get transport info")); 292 293 if (strcmp(mname, "sockmod") == 0) { 294 if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) { 295 msgout( 296 gettext("could not get the right module")); 297 dbug_leave("main"); 298 return (1); 299 } 300 } 301 if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { 302 msgout(gettext("cannot create server handle")); 303 dbug_leave("main"); 304 return (1); 305 } 306 if (nconf) 307 freenetconfigent(nconf); 308 xx = svc_reg(transp, CACHEFSDPROG, CACHEFSDVERS, 309 cachefsdprog_1, 0); 310 if (!xx) { 311 msgout(gettext( 312 "unable to reg (CACHEFSDPROG, CACHEFSDVERS).")); 313 dbug_leave("main"); 314 return (1); 315 } 316 } 317 318 /* else if started by hand */ 319 else { 320 /* if we should fork */ 321 if (opt_fork) { 322 dbug_print(("info", "forking")); 323 pid = fork(); 324 if (pid < 0) { 325 perror(gettext("cannot fork")); 326 dbug_leave("main"); 327 return (1); 328 } 329 if (pid) { 330 dbug_leave("main"); 331 return (0); 332 } 333 (void) fdwalk(void_close, &ofd); 334 xx = open("/dev/sysmsg", 2); 335 (void) dup2(xx, 1); 336 (void) dup2(xx, 2); 337 setsid(); 338 } 339 340 /* connect to *ANY* local loopback transport provider */ 341 xx = svc_create(cachefsdprog_1, CACHEFSDPROG, CACHEFSDVERS, 342 "local"); 343 if (!xx) { 344 msgout(gettext("unable to create (CACHEFSDPROG, " 345 "CACHEFSDVERS) for netpath.")); 346 dbug_leave("main"); 347 return (1); 348 } 349 } 350 351 /* find existing caches and mounted file systems */ 352 all_object_p = cfsd_all_create(); 353 subr_cache_setup(all_object_p); 354 355 /* process requests */ 356 svc_run(); 357 358 msgout(gettext("svc_run returned")); 359 cfsd_all_destroy(all_object_p); 360 dbug_leave("main"); 361 return (1); 362 } 363 364 /* 365 * Callback function for fdwalk() to close all files. 366 */ 367 static int 368 void_close(void *ofdp, int fd) 369 { 370 if (fd != *(int *)ofdp) { 371 if (close(fd) != 0) 372 dbug_print(("err", 373 "cannot close fd %d, %d", fd, errno)); 374 } 375 return (0); 376 } 377 378 /* 379 * ----------------------------------------------------------------- 380 * msgout 381 * 382 * Description: 383 * Outputs an error message to stderr. 384 * Arguments: 385 * msgp 386 * Returns: 387 * Preconditions: 388 * precond(msgp) 389 */ 390 391 void 392 msgout(char *msgp) 393 { 394 dbug_enter("msgout"); 395 dbug_precond(msgp); 396 397 (void) fprintf(stderr, "%s\n", msgp); 398 dbug_leave("msgout"); 399 } 400 401 402 /* 403 * ----------------------------------------------------------------- 404 * cachefsdprog_1 405 * 406 * Description: 407 * Arguments: 408 * rqstp 409 * transp 410 * Returns: 411 * Preconditions: 412 * precond(rqstp) 413 * precond(transp) 414 */ 415 void 416 cachefsdprog_1(struct svc_req *rqstp, register SVCXPRT *transp) 417 { 418 int index; 419 struct rpcgen_table *rtp; 420 void *argumentp = NULL; 421 void *resultp = NULL; 422 LOCAL local; 423 int xx; 424 425 dbug_enter("cachefsdprog_1"); 426 427 dbug_precond(rqstp); 428 dbug_precond(transp); 429 430 /* make sure a valid command number */ 431 index = rqstp->rq_proc; 432 if ((index < 0) || (cachefsdprog_1_nproc <= index)) { 433 msgout(gettext("bad message")); 434 svcerr_noproc(transp); 435 dbug_leave("cachefsdprog_1"); 436 return; 437 } 438 439 /* get command information */ 440 rtp = &cachefsdprog_1_table[index]; 441 442 /* get memory for the arguments */ 443 if (rtp->len_arg != 0) 444 argumentp = (void *)cfsd_calloc(rtp->len_arg); 445 446 /* get memory for the results */ 447 if (rtp->len_res != 0) 448 resultp = (void *)cfsd_calloc(rtp->len_res); 449 450 /* get the arguments */ 451 if (rtp->xdr_arg && argumentp) { 452 if (!svc_getargs(transp, rtp->xdr_arg, (caddr_t)argumentp)) { 453 svcerr_decode(transp); 454 cfsd_free(argumentp); 455 cfsd_free(resultp); 456 dbug_leave("cachefsdprog_1"); 457 return; 458 } 459 } 460 461 /* call the routine to process the command */ 462 local = (LOCAL)rtp->proc; 463 xx = (*local)(argumentp, resultp, rqstp); 464 465 /* if the command could not be processed */ 466 if (xx == 0) { 467 svcerr_systemerr(transp); 468 } 469 470 /* else send the results back to the caller */ 471 else { 472 xx = svc_sendreply(transp, rtp->xdr_res, (caddr_t)resultp); 473 if (!xx) 474 svcerr_systemerr(transp); 475 476 /* free the results */ 477 xx = cachefsdprog_1_freeresult(transp, rtp->xdr_res, 478 (caddr_t)resultp); 479 if (xx == 0) 480 msgout(gettext("unable to free results")); 481 } 482 483 /* free the passed in arguments */ 484 if (!svc_freeargs(transp, rtp->xdr_arg, (caddr_t)argumentp)) { 485 msgout(gettext("unable to free arguments")); 486 abort(); 487 } 488 489 if (argumentp) 490 cfsd_free(argumentp); 491 if (resultp) 492 cfsd_free(resultp); 493 dbug_leave("cachefsdprog_1"); 494 } 495 496 /* 497 * sigusr1_handler 498 * 499 * Description: 500 * Catches sigusr1 signal so threads wake up. 501 * Arguments: 502 * Returns: 503 * Preconditions: 504 */ 505 void 506 sigusr1_handler(int sig, siginfo_t *sp, void *vp) 507 { 508 } 509