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