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
main(int argc,char * argv[])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
bootparamprog_1(struct svc_req * rqstp,register SVCXPRT * transp)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
msgout(char * fmt,...)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
closedown(int sig)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