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 (c) 1998-2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 30 #include <stdarg.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <signal.h> 34 #include <unistd.h> 35 #include <rpc/rpc.h> 36 #include <memory.h> 37 #include <stropts.h> 38 #include <netconfig.h> 39 #include <stropts.h> 40 #include <sys/termios.h> 41 #include <syslog.h> 42 #include <rpcsvc/bootparam_prot.h> 43 44 #include "bootparam_private.h" 45 46 #define _RPCSVC_CLOSEDOWN 120 47 48 int debug = 0; 49 50 static void bootparamprog_1(struct svc_req *, register SVCXPRT *); 51 static void closedown(int); 52 53 static int server_child = 0; /* program was started by another server */ 54 static int _rpcsvcdirty; /* Still serving ? */ 55 56 int 57 main(int argc, char *argv[]) 58 { 59 pid_t pid; 60 int c; 61 char *progname = argv[0]; 62 int connmaxrec = RPC_MAXDATASIZE; 63 64 while ((c = getopt(argc, argv, "d")) != -1) 65 switch ((char)c) { 66 case 'd': 67 debug++; 68 break; 69 default: 70 (void) fprintf(stderr, "usage: %s [-d]\n", progname); 71 exit(EXIT_FAILURE); 72 } 73 74 75 /* 76 * Set non-blocking mode and maximum record size for 77 * connection oriented RPC transports. 78 */ 79 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) { 80 msgout("unable to set maximum RPC record size"); 81 } 82 83 /* 84 * If stdin looks like a TLI endpoint, we assume 85 * that we were started by a port monitor. If 86 * t_getstate fails with TBADF, this is not a 87 * TLI endpoint. 88 */ 89 if (t_getstate(0) != -1 || t_errno != TBADF) { 90 char *netid; 91 struct netconfig *nconf = NULL; 92 SVCXPRT *transp; 93 int pmclose; 94 95 if ((netid = getenv("NLSPROVIDER")) == NULL) { 96 if (debug) 97 msgout("cannot get transport name"); 98 } else if ((nconf = getnetconfigent(netid)) == NULL) { 99 if (debug) 100 msgout("cannot get transport info"); 101 } 102 pmclose = (t_getstate(0) != T_DATAXFER); 103 if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { 104 msgout("cannot create server handle"); 105 exit(EXIT_FAILURE); 106 } 107 if (nconf) 108 freenetconfigent(nconf); 109 if (!svc_reg(transp, BOOTPARAMPROG, BOOTPARAMVERS, 110 bootparamprog_1, 0)) { 111 msgout("unable to register (BOOTPARAMPROG, " 112 "BOOTPARAMVERS)."); 113 exit(EXIT_FAILURE); 114 } 115 if (pmclose) { 116 (void) signal(SIGALRM, closedown); 117 (void) alarm(_RPCSVC_CLOSEDOWN); 118 } 119 120 svc_run(); 121 exit(EXIT_FAILURE); 122 /* NOTREACHED */ 123 } 124 125 /* 126 * run this process in the background only if it was started from 127 * a shell and the debug flag was not given. 128 */ 129 if (!server_child && !debug) { 130 pid = fork(); 131 if (pid < 0) { 132 perror("cannot fork"); 133 exit(EXIT_FAILURE); 134 } 135 if (pid) 136 exit(EXIT_SUCCESS); 137 138 closefrom(0); 139 (void) setsid(); 140 } 141 142 /* 143 * messges go to syslog if the program was started by 144 * another server, or if it was run from the command line without 145 * the debug flag. 146 */ 147 if (server_child || !debug) 148 openlog("bootparam_prot", LOG_PID, LOG_DAEMON); 149 150 if (debug) { 151 if (debug == 1) 152 msgout("in debug mode."); 153 else 154 msgout("in debug mode (level %d).", debug); 155 } 156 157 if (!svc_create(bootparamprog_1, BOOTPARAMPROG, BOOTPARAMVERS, 158 "netpath")) { 159 msgout("unable to create (BOOTPARAMPROG, BOOTPARAMVERS) " 160 "for netpath."); 161 exit(EXIT_FAILURE); 162 } 163 164 svc_run(); 165 msgout("svc_run returned"); 166 return (EXIT_FAILURE); 167 } 168 169 static void 170 bootparamprog_1(struct svc_req *rqstp, register SVCXPRT *transp) 171 { 172 union { 173 bp_whoami_arg bootparamproc_whoami_1_arg; 174 bp_getfile_arg bootparamproc_getfile_1_arg; 175 } argument; 176 char *result; 177 bool_t (*xdr_argument)(), (*xdr_result)(); 178 char *(*local)(); 179 180 _rpcsvcdirty = 1; 181 switch (rqstp->rq_proc) { 182 case NULLPROC: 183 (void) svc_sendreply(transp, xdr_void, (char *)NULL); 184 _rpcsvcdirty = 0; 185 return; 186 187 case BOOTPARAMPROC_WHOAMI: 188 xdr_argument = xdr_bp_whoami_arg; 189 xdr_result = xdr_bp_whoami_res; 190 local = (char *(*)()) bootparamproc_whoami_1; 191 break; 192 193 case BOOTPARAMPROC_GETFILE: 194 xdr_argument = xdr_bp_getfile_arg; 195 xdr_result = xdr_bp_getfile_res; 196 local = (char *(*)()) bootparamproc_getfile_1; 197 break; 198 199 default: 200 svcerr_noproc(transp); 201 _rpcsvcdirty = 0; 202 return; 203 } 204 (void) memset((char *)&argument, 0, sizeof (argument)); 205 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 206 svcerr_decode(transp); 207 _rpcsvcdirty = 0; 208 return; 209 } 210 result = (*local)(&argument, rqstp); 211 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 212 svcerr_systemerr(transp); 213 } 214 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 215 msgout("unable to free arguments"); 216 exit(EXIT_FAILURE); 217 } 218 _rpcsvcdirty = 0; 219 } 220 221 /*PRINTFLIKE1*/ 222 void 223 msgout(char *fmt, ...) 224 { 225 va_list ap; 226 227 va_start(ap, fmt); 228 /* 229 * messges go to syslog if the program was started by 230 * another server, or if it was run from the command line without 231 * the debug flag. 232 */ 233 if (server_child || !debug) 234 vsyslog(LOG_ERR, fmt, ap); 235 else { 236 (void) vfprintf(stderr, fmt, ap); 237 (void) fputc('\n', stderr); 238 } 239 va_end(ap); 240 } 241 242 /* ARGSUSED */ 243 static void 244 closedown(int sig) 245 { 246 if (_rpcsvcdirty == 0) { 247 int size; 248 int i, openfd; 249 struct t_info tinfo; 250 251 if (!t_getinfo(0, &tinfo) && (tinfo.servtype == T_CLTS)) 252 exit(EXIT_SUCCESS); 253 size = svc_max_pollfd; 254 for (i = 0, openfd = 0; i < size && openfd < 2; i++) 255 if (svc_pollfd[i].fd >= 0) 256 openfd++; 257 if (openfd <= 1) 258 exit(EXIT_SUCCESS); 259 } 260 (void) alarm(_RPCSVC_CLOSEDOWN); 261 } 262