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 2008 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 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 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 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 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