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