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
48int debug = 0;
49
50static void bootparamprog_1(struct svc_req *, register SVCXPRT *);
51static void closedown(int);
52
53static int server_child = 0;	/* program was started by another server */
54static int _rpcsvcdirty;	/* Still serving ? */
55
56int
57main(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
169static void
170bootparamprog_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*/
222void
223msgout(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 */
243static void
244closedown(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