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
main(int argc,char ** argv)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
void_close(void * ofdp,int fd)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
msgout(char * msgp)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
cachefsdprog_1(struct svc_req * rqstp,register SVCXPRT * transp)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
sigusr1_handler(int sig,siginfo_t * sp,void * vp)507 sigusr1_handler(int sig, siginfo_t *sp, void *vp)
508 {
509 }
510