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