xref: /titanic_41/usr/src/cmd/lvm/rpc.mdcommd/mdmn_commd_service.c (revision d583b39bfb4e2571d3e41097c5c357ffe353ad45)
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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/lvm/mdmn_commd.h>
28 #include <stdio.h>
29 #include <stdlib.h> /* getenv, exit */
30 #include <signal.h>
31 #include <unistd.h>
32 #include <sys/types.h>
33 #include <memory.h>
34 #include <stropts.h>
35 #include <netconfig.h>
36 #include <sys/resource.h> /* rlimit */
37 #include <syslog.h>
38 #include <meta.h>
39 
40 #ifdef DEBUG
41 #define	RPC_SVC_FG
42 #endif
43 
44 /*
45  * This means we shutdown rpc.mdcommd at some time in the window
46  * after 1201 seconds and before 2400 seconds of inactivity.
47  */
48 #define	_RPCSVC_CLOSEDOWN 2400
49 
50 #ifdef RPC_SVC_FG
51 static int _rpcpmstart;		/* Started by a port monitor ? */
52 #endif /* RPC_SVC_FG */
53 /* States a server can be in wrt request */
54 
55 #define	_IDLE 0
56 #define	_SERVED 1
57 
58 static int _rpcsvcstate = _IDLE;	/* Set when a request is serviced */
59 static int _rpcsvccount = 0;		/* Number of requests being serviced */
60 
61 extern  int		mdmn_send_svc_2();
62 extern  int		*mdmn_work_svc_2();
63 extern  int		*mdmn_wakeup_initiator_svc_2();
64 extern  int		*mdmn_wakeup_master_svc_2();
65 extern  int		*mdmn_comm_lock_svc_2();
66 extern  int		*mdmn_comm_unlock_svc_2();
67 extern  int		*mdmn_comm_suspend_svc_2();
68 extern  int		*mdmn_comm_resume_svc_2();
69 extern  int		*mdmn_comm_reinit_set_svc_2();
70 extern  int		*mdmn_comm_msglock_svc_2();
71 
72 
73 static void
74 _msgout(msg)
75 	char *msg;
76 {
77 #ifdef RPC_SVC_FG
78 	if (_rpcpmstart)
79 		syslog(LOG_ERR, "%s", msg);
80 	else
81 		(void) fprintf(stderr, "%s\n", msg);
82 #else
83 	syslog(LOG_ERR, "%s", msg);
84 #endif
85 }
86 
87 static void
88 closedown(void)
89 {
90 	if (_rpcsvcstate == _IDLE && _rpcsvccount == 0) {
91 		int size;
92 		int i, openfd = 0;
93 
94 		size = svc_max_pollfd;
95 		for (i = 0; i < size && openfd < 2; i++)
96 			if (svc_pollfd[i].fd >= 0)
97 				openfd++;
98 		if (openfd <= 1)
99 			exit(0);
100 	} else
101 		_rpcsvcstate = _IDLE;
102 
103 	(void) signal(SIGALRM, (void(*)()) closedown);
104 	(void) alarm(_RPCSVC_CLOSEDOWN/2);
105 }
106 
107 static void
108 mdmn_commd_2(rqstp, transp)
109 	struct svc_req *rqstp;
110 	register SVCXPRT *transp;
111 {
112 	union {
113 		md_mn_msg_t mdmn_send_1_arg;
114 		md_mn_msg_t mdmn_work_1_arg;
115 		md_mn_result_t mdmn_wakeup_1_arg;
116 		md_mn_msgclass_t mdmn_comm_lock_1_arg;
117 		md_mn_msgclass_t mdmn_comm_unlock_1_arg;
118 		uint_t mdmn_comm_reinit_1_arg;
119 	} argument;
120 	char *result;
121 	bool_t (*_xdr_argument)(), (*_xdr_result)();
122 	char *(*local)();
123 	int free_result = 0;
124 
125 	_rpcsvccount++;
126 	switch (rqstp->rq_proc) {
127 	case NULLPROC:
128 		(void) svc_sendreply(transp, xdr_void,
129 			(char *)NULL);
130 		_rpcsvccount--;
131 		_rpcsvcstate = _SERVED;
132 		svc_done(transp);
133 		return;
134 
135 	case mdmn_send:
136 		_xdr_argument = xdr_md_mn_msg_t;
137 		_xdr_result = xdr_md_mn_result_t;
138 		(void) memset((char *)&argument, 0, sizeof (argument));
139 		if (!svc_getargs(transp, _xdr_argument, (caddr_t)&argument)) {
140 			svcerr_decode(transp);
141 			svc_done(transp);
142 			_rpcsvccount--;
143 			_rpcsvcstate = _SERVED;
144 			return;
145 		}
146 		/*
147 		 * mdmn_send_2 will not always do a sendreply.
148 		 * it will register in a table and let the mdmn_wakeup1
149 		 * do the sendreply for that call.
150 		 * in order to register properly we need the transp handle
151 		 * If we get a 0 back from mdmn_send_svc_2() we have no pending
152 		 * RPC in-flight, so we drop the service count.
153 		 */
154 		if (mdmn_send_svc_2((md_mn_msg_t *)&argument, rqstp) == 0) {
155 			_rpcsvccount--;
156 			_rpcsvcstate = _SERVED;
157 			svc_done(rqstp->rq_xprt);
158 		}
159 
160 		return; /* xdr_free is called by mdmn_wakeup_initiator_svc_2 */
161 
162 	case mdmn_work:
163 		_xdr_argument = xdr_md_mn_msg_t;
164 		_xdr_result = xdr_int;
165 		local = (char *(*)()) mdmn_work_svc_2;
166 		free_result = 1;
167 		break;
168 
169 	case mdmn_wakeup_master:
170 		_xdr_argument = xdr_md_mn_result_t;
171 		_xdr_result = xdr_int;
172 		local = (char *(*)()) mdmn_wakeup_master_svc_2;
173 		free_result = 1;
174 		break;
175 
176 	case mdmn_wakeup_initiator:
177 		/*
178 		 * We must have had an in-flight RPC request to get here,
179 		 * so drop the in-flight count.
180 		 */
181 		_xdr_argument = xdr_md_mn_result_t;
182 		_xdr_result = xdr_int;
183 		local = (char *(*)()) mdmn_wakeup_initiator_svc_2;
184 		free_result = 1;
185 		_rpcsvccount--;
186 		break;
187 
188 	case mdmn_comm_lock:
189 		_xdr_argument = xdr_md_mn_set_and_class_t;
190 		_xdr_result = xdr_int;
191 		local = (char *(*)()) mdmn_comm_lock_svc_2;
192 		break;
193 
194 	case mdmn_comm_unlock:
195 		_xdr_argument = xdr_md_mn_set_and_class_t;
196 		_xdr_result = xdr_int;
197 		local = (char *(*)()) mdmn_comm_unlock_svc_2;
198 		break;
199 
200 	case mdmn_comm_suspend:
201 		_xdr_argument = xdr_md_mn_set_and_class_t;
202 		_xdr_result = xdr_int;
203 		local = (char *(*)()) mdmn_comm_suspend_svc_2;
204 		break;
205 
206 	case mdmn_comm_resume:
207 		_xdr_argument = xdr_md_mn_set_and_class_t;
208 		_xdr_result = xdr_int;
209 		local = (char *(*)()) mdmn_comm_resume_svc_2;
210 		break;
211 
212 	case mdmn_comm_reinit_set:
213 		_xdr_argument = xdr_u_int;
214 		_xdr_result = xdr_int;
215 		local = (char *(*)()) mdmn_comm_reinit_set_svc_2;
216 		break;
217 
218 	case mdmn_comm_msglock:
219 		_xdr_argument = xdr_md_mn_type_and_lock_t;
220 		_xdr_result = xdr_int;
221 		local = (char *(*)()) mdmn_comm_msglock_svc_2;
222 		break;
223 
224 	default:
225 		svcerr_noproc(transp);
226 		_rpcsvccount--;
227 		_rpcsvcstate = _SERVED;
228 		svc_done(transp);
229 		return;
230 	}
231 	(void) memset((char *)&argument, 0, sizeof (argument));
232 	if (!svc_getargs(transp, _xdr_argument, (caddr_t)&argument)) {
233 		svcerr_decode(transp);
234 		_rpcsvccount--;
235 		_rpcsvcstate = _SERVED;
236 		svc_done(transp);
237 		return;
238 	}
239 	result = (*local)(&argument, rqstp);
240 	if (_xdr_result && result != NULL &&
241 	    !svc_sendreply(transp, _xdr_result, result)) {
242 		svcerr_systemerr(transp);
243 	}
244 	if (!svc_freeargs(transp, _xdr_argument, (caddr_t)&argument)) {
245 		_msgout(gettext("unable to free arguments"));
246 		svc_done(transp);
247 		exit(1);
248 	}
249 
250 	if (free_result == 1) {
251 		free(result);
252 	}
253 
254 	svc_done(transp);
255 	_rpcsvccount--;
256 	_rpcsvcstate = _SERVED;
257 }
258 
259 /*
260  * atexit handler to flag the lack of commd to the kernel so that we don't
261  * panic due to RPC failures when the commd has been killed.
262  */
263 static void
264 exit_commd()
265 {
266 	md_error_t	ep = mdnullerror;
267 	syslog(LOG_DAEMON | LOG_DEBUG, gettext("mdcommd exiting"));
268 	(void) metaioctl(MD_MN_SET_COMMD_RUNNING, 0, &ep, "rpc.mdcommd");
269 }
270 
271 /* ARGSUSED */
272 int
273 main()
274 {
275 	pid_t pid;
276 	int i;
277 	md_error_t	ep = mdnullerror;
278 	int		mode = RPC_SVC_MT_USER;
279 
280 	(void) sigset(SIGPIPE, SIG_IGN);
281 
282 	/*
283 	 * Attempt to set MT_USER behaviour for mdcommd service routines.
284 	 * If this isn't done, there is a possibility that the transport
285 	 * handle might be freed before the thread created by mdmn_send_svc_2
286 	 * can use it.  A consequence of this is that svc_done() must be
287 	 * called on the handle when it's no longer needed.
288 	 */
289 	if (rpc_control(RPC_SVC_MTMODE_SET, &mode) == FALSE) {
290 		_msgout(gettext("cannot set MT_USER mode for RPC service"));
291 		exit(1);
292 	}
293 
294 	/*
295 	 * If stdin looks like a TLI endpoint, we assume
296 	 * that we were started by a port monitor. If
297 	 * t_getstate fails with TBADF, this is not a
298 	 * TLI endpoint.
299 	 */
300 	if (t_getstate(0) != -1 || t_errno != TBADF) {
301 		char *netid;
302 		struct netconfig *nconf = NULL;
303 		SVCXPRT *transp;
304 		int pmclose;
305 
306 #ifdef RPC_SVC_FG
307 		_rpcpmstart = 1;
308 #endif /* RPC_SVC_FG */
309 		openlog("mdmn_commd", LOG_PID, LOG_DAEMON);
310 
311 		if ((netid = getenv("NLSPROVIDER")) == NULL) {
312 		/* started from inetd */
313 			pmclose = 1;
314 		} else {
315 			if ((nconf = getnetconfigent(netid)) == NULL)
316 				_msgout(gettext("cannot get transport info"));
317 
318 			pmclose = (t_getstate(0) != T_DATAXFER);
319 		}
320 		if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
321 			_msgout(gettext("cannot create server handle"));
322 			exit(1);
323 		}
324 		if (nconf)
325 			freenetconfigent(nconf);
326 		if (!svc_reg(transp, MDMN_COMMD, TWO, mdmn_commd_2, 0)) {
327 			_msgout(gettext(
328 			    "unable to register (MDMN_COMMD, TWO)."));
329 			exit(1);
330 		}
331 
332 		(void) atexit(exit_commd);
333 
334 		if (pmclose) {
335 			(void) signal(SIGALRM, (void(*)()) closedown);
336 			(void) alarm(_RPCSVC_CLOSEDOWN/2);
337 		}
338 
339 		pid = getpid();
340 		(void) metaioctl(MD_MN_SET_COMMD_RUNNING, (void *)pid, &ep,
341 		    "rpc.mdcommd");
342 		svc_run();
343 		exit(1);
344 		/* NOTREACHED */
345 	}	else {
346 #ifndef RPC_SVC_FG
347 #pragma weak closefrom
348 		/* LINTED */
349 		extern void closefrom();
350 		int size;
351 		struct rlimit rl;
352 		pid = fork();
353 		if (pid < 0) {
354 			perror(gettext("cannot fork"));
355 			exit(1);
356 		}
357 		if (pid)
358 			exit(0);
359 		if (closefrom != NULL)
360 			closefrom(0);
361 		else {
362 			rl.rlim_max = 0;
363 			(void) getrlimit(RLIMIT_NOFILE, &rl);
364 			if ((size = rl.rlim_max) == 0)
365 				exit(1);
366 			for (i = 0; i < size; i++)
367 				(void) close(i);
368 		}
369 		i = open("/dev/null", 2);
370 		(void) dup2(i, 1);
371 		(void) dup2(i, 2);
372 		(void) setsid();
373 		openlog("mdmn_commd", LOG_PID, LOG_DAEMON);
374 #endif
375 	}
376 	if (!svc_create(mdmn_commd_2, MDMN_COMMD, TWO, "tcp")) {
377 		_msgout(gettext("unable to create (MDMN_COMMD, TWO) for tcp."));
378 		exit(1);
379 	}
380 
381 	(void) atexit(exit_commd);
382 	(void) metaioctl(MD_MN_SET_COMMD_RUNNING, (void *)1, &ep,
383 	    "rpc.mdcommd");
384 
385 	svc_run();
386 	_msgout(gettext("svc_run returned"));
387 	return (1);
388 }
389