xref: /titanic_41/usr/src/cmd/fs.d/cachefs/cfsd/cfsd_main.c (revision 45916cd2fec6e79bca5dee0421bd39e3c2910d1e)
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