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