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