xref: /titanic_53/usr/src/cmd/ldmad/ldmad.c (revision 49bfb42b00abac0958a1308f4233e366fd083366)
1*49bfb42bSAlexandre Chartre /*
2*49bfb42bSAlexandre Chartre  * CDDL HEADER START
3*49bfb42bSAlexandre Chartre  *
4*49bfb42bSAlexandre Chartre  * The contents of this file are subject to the terms of the
5*49bfb42bSAlexandre Chartre  * Common Development and Distribution License (the "License").
6*49bfb42bSAlexandre Chartre  * You may not use this file except in compliance with the License.
7*49bfb42bSAlexandre Chartre  *
8*49bfb42bSAlexandre Chartre  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*49bfb42bSAlexandre Chartre  * or http://www.opensolaris.org/os/licensing.
10*49bfb42bSAlexandre Chartre  * See the License for the specific language governing permissions
11*49bfb42bSAlexandre Chartre  * and limitations under the License.
12*49bfb42bSAlexandre Chartre  *
13*49bfb42bSAlexandre Chartre  * When distributing Covered Code, include this CDDL HEADER in each
14*49bfb42bSAlexandre Chartre  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*49bfb42bSAlexandre Chartre  * If applicable, add the following below this CDDL HEADER, with the
16*49bfb42bSAlexandre Chartre  * fields enclosed by brackets "[]" replaced with your own identifying
17*49bfb42bSAlexandre Chartre  * information: Portions Copyright [yyyy] [name of copyright owner]
18*49bfb42bSAlexandre Chartre  *
19*49bfb42bSAlexandre Chartre  * CDDL HEADER END
20*49bfb42bSAlexandre Chartre  */
21*49bfb42bSAlexandre Chartre 
22*49bfb42bSAlexandre Chartre /*
23*49bfb42bSAlexandre Chartre  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*49bfb42bSAlexandre Chartre  * Use is subject to license terms.
25*49bfb42bSAlexandre Chartre  */
26*49bfb42bSAlexandre Chartre 
27*49bfb42bSAlexandre Chartre /*
28*49bfb42bSAlexandre Chartre  * Logical Domains (LDoms) Agents Daemon
29*49bfb42bSAlexandre Chartre  *
30*49bfb42bSAlexandre Chartre  * The LDoms agents daemon (ldmad) runs on LDoms domains and provides
31*49bfb42bSAlexandre Chartre  * information to the control domain. It is composed of a set of agents
32*49bfb42bSAlexandre Chartre  * which can send and receive messages to and from the control domain.
33*49bfb42bSAlexandre Chartre  * Each agent is registered as a domain service using the libds library,
34*49bfb42bSAlexandre Chartre  * and is able to handle requests coming from the control domain.
35*49bfb42bSAlexandre Chartre  *
36*49bfb42bSAlexandre Chartre  * The control domain sends requests to an agent as messages on the
37*49bfb42bSAlexandre Chartre  * corresponding domain service (identified by the agent name). All requests
38*49bfb42bSAlexandre Chartre  * are received by the ldmad daemon which dispatches them to the appropriate
39*49bfb42bSAlexandre Chartre  * handler function of the agent depending on the type of the message.
40*49bfb42bSAlexandre Chartre  *
41*49bfb42bSAlexandre Chartre  * After the request has been processed by the handler, the ldmad daemon sent
42*49bfb42bSAlexandre Chartre  * a reply message back to the control domain. The reply is either a result
43*49bfb42bSAlexandre Chartre  * message if the request was successfully completed, or an error message
44*49bfb42bSAlexandre Chartre  * describing the failure.
45*49bfb42bSAlexandre Chartre  */
46*49bfb42bSAlexandre Chartre 
47*49bfb42bSAlexandre Chartre #include <dirent.h>
48*49bfb42bSAlexandre Chartre #include <dlfcn.h>
49*49bfb42bSAlexandre Chartre #include <errno.h>
50*49bfb42bSAlexandre Chartre #include <fcntl.h>
51*49bfb42bSAlexandre Chartre #include <link.h>
52*49bfb42bSAlexandre Chartre #include <libds.h>
53*49bfb42bSAlexandre Chartre #include <libgen.h>
54*49bfb42bSAlexandre Chartre #include <signal.h>
55*49bfb42bSAlexandre Chartre #include <stdio.h>
56*49bfb42bSAlexandre Chartre #include <stdlib.h>
57*49bfb42bSAlexandre Chartre #include <strings.h>
58*49bfb42bSAlexandre Chartre #include <syslog.h>
59*49bfb42bSAlexandre Chartre #include <unistd.h>
60*49bfb42bSAlexandre Chartre #include <sys/types.h>
61*49bfb42bSAlexandre Chartre #include <sys/stat.h>
62*49bfb42bSAlexandre Chartre #include <sys/wait.h>
63*49bfb42bSAlexandre Chartre 
64*49bfb42bSAlexandre Chartre #include "ldma.h"
65*49bfb42bSAlexandre Chartre 
66*49bfb42bSAlexandre Chartre #define	LDMA_MODULE	"ldm-agent-daemon"
67*49bfb42bSAlexandre Chartre 
68*49bfb42bSAlexandre Chartre #define	LDMA_CONTROL_DOMAIN_DHDL	0	/* id of the control domain */
69*49bfb42bSAlexandre Chartre #define	LDMA_DOMAIN_NAME_MAXLEN		MAXNAMELEN
70*49bfb42bSAlexandre Chartre 
71*49bfb42bSAlexandre Chartre typedef struct ldma_agent {
72*49bfb42bSAlexandre Chartre 	ldma_agent_info_t	*info;		/* agent information */
73*49bfb42bSAlexandre Chartre 	ds_hdl_t		conn_hdl;	/* connexion handler */
74*49bfb42bSAlexandre Chartre 	ds_ver_t		conn_ver;	/* connexion version */
75*49bfb42bSAlexandre Chartre } ldma_agent_t;
76*49bfb42bSAlexandre Chartre 
77*49bfb42bSAlexandre Chartre /* information about existing agents */
78*49bfb42bSAlexandre Chartre extern ldma_agent_info_t ldma_device_info;
79*49bfb42bSAlexandre Chartre extern ldma_agent_info_t ldma_system_info;
80*49bfb42bSAlexandre Chartre 
81*49bfb42bSAlexandre Chartre boolean_t ldma_debug = B_FALSE;
82*49bfb42bSAlexandre Chartre boolean_t ldma_daemon = B_FALSE;
83*49bfb42bSAlexandre Chartre 
84*49bfb42bSAlexandre Chartre static ldma_agent_info_t *ldma_agent_infos[] = {
85*49bfb42bSAlexandre Chartre 	&ldma_device_info,
86*49bfb42bSAlexandre Chartre 	&ldma_system_info,
87*49bfb42bSAlexandre Chartre 	NULL
88*49bfb42bSAlexandre Chartre };
89*49bfb42bSAlexandre Chartre 
90*49bfb42bSAlexandre Chartre static char *cmdname;
91*49bfb42bSAlexandre Chartre static pid_t daemon_pid;
92*49bfb42bSAlexandre Chartre 
93*49bfb42bSAlexandre Chartre /*
94*49bfb42bSAlexandre Chartre  * Allocate a new message with the specified message number (msg_num),
95*49bfb42bSAlexandre Chartre  * message type (msg_type) and message data length (msg_dlen). Return
96*49bfb42bSAlexandre Chartre  * NULL if the allocation has failed.
97*49bfb42bSAlexandre Chartre  */
98*49bfb42bSAlexandre Chartre static ldma_message_header_t *
99*49bfb42bSAlexandre Chartre ldma_alloc_msg(uint64_t msg_num, uint32_t msg_type, size_t msg_dlen)
100*49bfb42bSAlexandre Chartre {
101*49bfb42bSAlexandre Chartre 	ldma_message_header_t *msg;
102*49bfb42bSAlexandre Chartre 	size_t msg_len;
103*49bfb42bSAlexandre Chartre 
104*49bfb42bSAlexandre Chartre 	msg_len = LDMA_MESSAGE_SIZE(msg_dlen);
105*49bfb42bSAlexandre Chartre 	msg = malloc(msg_len);
106*49bfb42bSAlexandre Chartre 	if (msg == NULL)
107*49bfb42bSAlexandre Chartre 		return (NULL);
108*49bfb42bSAlexandre Chartre 
109*49bfb42bSAlexandre Chartre 	msg->msg_num = msg_num;
110*49bfb42bSAlexandre Chartre 	msg->msg_type = msg_type;
111*49bfb42bSAlexandre Chartre 	msg->msg_info = 0;
112*49bfb42bSAlexandre Chartre 
113*49bfb42bSAlexandre Chartre 	return (msg);
114*49bfb42bSAlexandre Chartre }
115*49bfb42bSAlexandre Chartre 
116*49bfb42bSAlexandre Chartre /*
117*49bfb42bSAlexandre Chartre  * Allocate a result message (LDMA_MSG_REQ_RESULT) with the specified message
118*49bfb42bSAlexandre Chartre  * data length (msg_dlen). If the request argument is not NULL then the message
119*49bfb42bSAlexandre Chartre  * is created with the same message number as the request, otherwise the message
120*49bfb42bSAlexandre Chartre  * number is set to 0. Return NULL if the allocation has failed.
121*49bfb42bSAlexandre Chartre  */
122*49bfb42bSAlexandre Chartre ldma_message_header_t *
123*49bfb42bSAlexandre Chartre ldma_alloc_result_msg(ldma_message_header_t *request, size_t msg_dlen)
124*49bfb42bSAlexandre Chartre {
125*49bfb42bSAlexandre Chartre 	uint64_t msg_num;
126*49bfb42bSAlexandre Chartre 
127*49bfb42bSAlexandre Chartre 	msg_num = (request == NULL)? 0 : request->msg_num;
128*49bfb42bSAlexandre Chartre 
129*49bfb42bSAlexandre Chartre 	return (ldma_alloc_msg(msg_num, LDMA_MSG_RESULT, msg_dlen));
130*49bfb42bSAlexandre Chartre }
131*49bfb42bSAlexandre Chartre 
132*49bfb42bSAlexandre Chartre /*
133*49bfb42bSAlexandre Chartre  * Agent register callback. This callback is invoked when a client is registered
134*49bfb42bSAlexandre Chartre  * for using the service provided by an agent. An agent will only have one
135*49bfb42bSAlexandre Chartre  * consumer which is coming from the control domain.
136*49bfb42bSAlexandre Chartre  */
137*49bfb42bSAlexandre Chartre static void
138*49bfb42bSAlexandre Chartre ldma_reg_cb(ds_hdl_t hdl, ds_cb_arg_t arg, ds_ver_t *ver,
139*49bfb42bSAlexandre Chartre     ds_domain_hdl_t dhdl)
140*49bfb42bSAlexandre Chartre {
141*49bfb42bSAlexandre Chartre 	ldma_agent_t *agent = (ldma_agent_t *)arg;
142*49bfb42bSAlexandre Chartre 	char dname[LDMA_DOMAIN_NAME_MAXLEN];
143*49bfb42bSAlexandre Chartre 
144*49bfb42bSAlexandre Chartre 	if (ds_dom_hdl_to_name(dhdl, dname, LDMA_DOMAIN_NAME_MAXLEN) != 0) {
145*49bfb42bSAlexandre Chartre 		(void) strcpy(dname, "<unknown>");
146*49bfb42bSAlexandre Chartre 	}
147*49bfb42bSAlexandre Chartre 
148*49bfb42bSAlexandre Chartre 	LDMA_DBG("%s: REGISTER hdl=%llx, dhdl=%llx (%s) ver=%hd.%hd",
149*49bfb42bSAlexandre Chartre 	    agent->info->name, hdl, dhdl, dname, ver->major, ver->minor);
150*49bfb42bSAlexandre Chartre 
151*49bfb42bSAlexandre Chartre 	/*
152*49bfb42bSAlexandre Chartre 	 * Record client information if the connexion is from the control
153*49bfb42bSAlexandre Chartre 	 * domain. The domain service framework only allows connexion of a
154*49bfb42bSAlexandre Chartre 	 * domain with the control domain. However, if the agent is running
155*49bfb42bSAlexandre Chartre 	 * on the control domain then it can see connexions coming from any
156*49bfb42bSAlexandre Chartre 	 * domains. That's why we explicitly have to check if the connexion
157*49bfb42bSAlexandre Chartre 	 * is effectively with the control domain.
158*49bfb42bSAlexandre Chartre 	 */
159*49bfb42bSAlexandre Chartre 	if (dhdl == LDMA_CONTROL_DOMAIN_DHDL) {
160*49bfb42bSAlexandre Chartre 		agent->conn_hdl = hdl;
161*49bfb42bSAlexandre Chartre 		agent->conn_ver.major = ver->major;
162*49bfb42bSAlexandre Chartre 		agent->conn_ver.minor = ver->minor;
163*49bfb42bSAlexandre Chartre 	} else {
164*49bfb42bSAlexandre Chartre 		LDMA_INFO("agent %s will ignore any request from distrusted "
165*49bfb42bSAlexandre Chartre 		    "domain %s", agent->info->name, dname);
166*49bfb42bSAlexandre Chartre 	}
167*49bfb42bSAlexandre Chartre }
168*49bfb42bSAlexandre Chartre 
169*49bfb42bSAlexandre Chartre /*
170*49bfb42bSAlexandre Chartre  * Agent unregister callback. This callback is invoked when a client is
171*49bfb42bSAlexandre Chartre  * unregistered and stops using the service provided by an agent.
172*49bfb42bSAlexandre Chartre  */
173*49bfb42bSAlexandre Chartre static void
174*49bfb42bSAlexandre Chartre ldma_unreg_cb(ds_hdl_t hdl, ds_cb_arg_t arg)
175*49bfb42bSAlexandre Chartre {
176*49bfb42bSAlexandre Chartre 	ldma_agent_t *agent = (ldma_agent_t *)arg;
177*49bfb42bSAlexandre Chartre 
178*49bfb42bSAlexandre Chartre 	LDMA_DBG("%s: UNREGISTER hdl=%llx", agent->info->name, hdl);
179*49bfb42bSAlexandre Chartre 
180*49bfb42bSAlexandre Chartre 	if (agent->conn_hdl == hdl) {
181*49bfb42bSAlexandre Chartre 		agent->conn_hdl = 0;
182*49bfb42bSAlexandre Chartre 		agent->conn_ver.major = 0;
183*49bfb42bSAlexandre Chartre 		agent->conn_ver.minor = 0;
184*49bfb42bSAlexandre Chartre 	} else {
185*49bfb42bSAlexandre Chartre 		LDMA_INFO("agent %s has unregistered consumer from "
186*49bfb42bSAlexandre Chartre 		    "distrusted domain", agent->info->name);
187*49bfb42bSAlexandre Chartre 	}
188*49bfb42bSAlexandre Chartre }
189*49bfb42bSAlexandre Chartre 
190*49bfb42bSAlexandre Chartre /*
191*49bfb42bSAlexandre Chartre  * Agent data callback. This callback is invoked when an agent receives a new
192*49bfb42bSAlexandre Chartre  * message from a client. Any request from a client which is not the control
193*49bfb42bSAlexandre Chartre  * domain is immediatly rejected. Otherwise the message is forwarded to the
194*49bfb42bSAlexandre Chartre  * appropriate handler function provided by the agent, depending on the message
195*49bfb42bSAlexandre Chartre  * type.
196*49bfb42bSAlexandre Chartre  */
197*49bfb42bSAlexandre Chartre static void
198*49bfb42bSAlexandre Chartre ldma_data_cb(ds_hdl_t hdl, ds_cb_arg_t arg, void *buf, size_t len)
199*49bfb42bSAlexandre Chartre {
200*49bfb42bSAlexandre Chartre 	ldma_agent_t *agent = (ldma_agent_t *)arg;
201*49bfb42bSAlexandre Chartre 	ldma_msg_handler_t *handler;
202*49bfb42bSAlexandre Chartre 	ldma_message_header_t *request = buf;
203*49bfb42bSAlexandre Chartre 	ldma_message_header_t *reply = NULL;
204*49bfb42bSAlexandre Chartre 	ldma_request_status_t status;
205*49bfb42bSAlexandre Chartre 	size_t request_dlen, reply_len, reply_dlen = 0;
206*49bfb42bSAlexandre Chartre 	int i;
207*49bfb42bSAlexandre Chartre 
208*49bfb42bSAlexandre Chartre 	/* check the message size */
209*49bfb42bSAlexandre Chartre 	if (len < LDMA_MESSAGE_HEADER_SIZE) {
210*49bfb42bSAlexandre Chartre 		LDMA_INFO("agent %s has ignored message with an invalid "
211*49bfb42bSAlexandre Chartre 		    "size of %d bytes", agent->info->name, len);
212*49bfb42bSAlexandre Chartre 		return;
213*49bfb42bSAlexandre Chartre 	}
214*49bfb42bSAlexandre Chartre 
215*49bfb42bSAlexandre Chartre 	request_dlen = LDMA_MESSAGE_DLEN(len);
216*49bfb42bSAlexandre Chartre 
217*49bfb42bSAlexandre Chartre 	LDMA_DBG("%s: DATA hdl=%llx, request num=%llu type=0x%x info=0x%x "
218*49bfb42bSAlexandre Chartre 	    "dlen=%d", agent->info->name, hdl, request->msg_num,
219*49bfb42bSAlexandre Chartre 	    request->msg_type, request->msg_info, request_dlen);
220*49bfb42bSAlexandre Chartre 
221*49bfb42bSAlexandre Chartre 	/* reject any request which is not from the control domain */
222*49bfb42bSAlexandre Chartre 	if (hdl != agent->conn_hdl) {
223*49bfb42bSAlexandre Chartre 		LDMA_DBG("%s: DATA hdl=%llx, rejecting request from a "
224*49bfb42bSAlexandre Chartre 		    "distrusted domain", agent->info->name, hdl);
225*49bfb42bSAlexandre Chartre 		status = LDMA_REQ_DENIED;
226*49bfb42bSAlexandre Chartre 		goto do_reply;
227*49bfb42bSAlexandre Chartre 	}
228*49bfb42bSAlexandre Chartre 
229*49bfb42bSAlexandre Chartre 	handler = NULL;
230*49bfb42bSAlexandre Chartre 
231*49bfb42bSAlexandre Chartre 	for (i = 0; i < agent->info->nhandlers; i++) {
232*49bfb42bSAlexandre Chartre 		if (agent->info->handlers[i].msg_type == request->msg_type) {
233*49bfb42bSAlexandre Chartre 			handler = &agent->info->handlers[i];
234*49bfb42bSAlexandre Chartre 			break;
235*49bfb42bSAlexandre Chartre 		}
236*49bfb42bSAlexandre Chartre 	}
237*49bfb42bSAlexandre Chartre 
238*49bfb42bSAlexandre Chartre 	if (handler == NULL) {
239*49bfb42bSAlexandre Chartre 		/* this type of message is not defined by the agent */
240*49bfb42bSAlexandre Chartre 		LDMA_DBG("%s: DATA hdl=%llx, unknown message type %x",
241*49bfb42bSAlexandre Chartre 		    agent->info->name, hdl, request->msg_type);
242*49bfb42bSAlexandre Chartre 		status = LDMA_REQ_NOTSUP;
243*49bfb42bSAlexandre Chartre 		goto do_reply;
244*49bfb42bSAlexandre Chartre 	}
245*49bfb42bSAlexandre Chartre 
246*49bfb42bSAlexandre Chartre 	if (handler->msg_handler == NULL) {
247*49bfb42bSAlexandre Chartre 		/*
248*49bfb42bSAlexandre Chartre 		 * This type of message is defined by the agent but it
249*49bfb42bSAlexandre Chartre 		 * has no handler. That means there is no processing to
250*49bfb42bSAlexandre Chartre 		 * do, the message is just ignored, but the request is
251*49bfb42bSAlexandre Chartre 		 * successfully completed.
252*49bfb42bSAlexandre Chartre 		 */
253*49bfb42bSAlexandre Chartre 		LDMA_DBG("%s: DATA hdl=%llx, no handler",
254*49bfb42bSAlexandre Chartre 		    agent->info->name, hdl);
255*49bfb42bSAlexandre Chartre 		status = LDMA_REQ_COMPLETED;
256*49bfb42bSAlexandre Chartre 		goto do_reply;
257*49bfb42bSAlexandre Chartre 	}
258*49bfb42bSAlexandre Chartre 
259*49bfb42bSAlexandre Chartre 	/* invoke the message handler of the agent */
260*49bfb42bSAlexandre Chartre 	status = (*handler->msg_handler)(&agent->conn_ver, request,
261*49bfb42bSAlexandre Chartre 	    request_dlen, &reply, &reply_dlen);
262*49bfb42bSAlexandre Chartre 
263*49bfb42bSAlexandre Chartre 	LDMA_DBG("%s: DATA hdl=%llx, handler stat=%d reply=%p rlen=%d",
264*49bfb42bSAlexandre Chartre 	    agent->info->name, hdl, status, (void *)reply, reply_dlen);
265*49bfb42bSAlexandre Chartre 
266*49bfb42bSAlexandre Chartre do_reply:
267*49bfb42bSAlexandre Chartre 	/*
268*49bfb42bSAlexandre Chartre 	 * If the handler has provided a reply message, we use it directly.
269*49bfb42bSAlexandre Chartre 	 * Otherwise, we build a reply depending on the status of the request.
270*49bfb42bSAlexandre Chartre 	 * In that case, we re-use the request buffer to build the reply
271*49bfb42bSAlexandre Chartre 	 * message.
272*49bfb42bSAlexandre Chartre 	 */
273*49bfb42bSAlexandre Chartre 	if (reply == NULL) {
274*49bfb42bSAlexandre Chartre 
275*49bfb42bSAlexandre Chartre 		reply = request;
276*49bfb42bSAlexandre Chartre 		reply_dlen = 0;
277*49bfb42bSAlexandre Chartre 
278*49bfb42bSAlexandre Chartre 		if (status == LDMA_REQ_COMPLETED) {
279*49bfb42bSAlexandre Chartre 			/*
280*49bfb42bSAlexandre Chartre 			 * The request was successful but no result message was
281*49bfb42bSAlexandre Chartre 			 * provided so we send an empty result message.
282*49bfb42bSAlexandre Chartre 			 */
283*49bfb42bSAlexandre Chartre 			reply->msg_type = LDMA_MSG_RESULT;
284*49bfb42bSAlexandre Chartre 			reply->msg_info = 0;
285*49bfb42bSAlexandre Chartre 
286*49bfb42bSAlexandre Chartre 		} else {
287*49bfb42bSAlexandre Chartre 			/*
288*49bfb42bSAlexandre Chartre 			 * The request has failed but no error message was
289*49bfb42bSAlexandre Chartre 			 * provided so we send an error message based on the
290*49bfb42bSAlexandre Chartre 			 * request status.
291*49bfb42bSAlexandre Chartre 			 */
292*49bfb42bSAlexandre Chartre 			reply->msg_type = LDMA_MSG_ERROR;
293*49bfb42bSAlexandre Chartre 			reply->msg_info =
294*49bfb42bSAlexandre Chartre 			    (status == LDMA_REQ_NOTSUP)? LDMA_MSGERR_NOTSUP :
295*49bfb42bSAlexandre Chartre 			    (status == LDMA_REQ_INVALID)? LDMA_MSGERR_INVALID :
296*49bfb42bSAlexandre Chartre 			    (status == LDMA_REQ_DENIED)? LDMA_MSGERR_DENY :
297*49bfb42bSAlexandre Chartre 			    LDMA_MSGERR_FAIL;
298*49bfb42bSAlexandre Chartre 		}
299*49bfb42bSAlexandre Chartre 	}
300*49bfb42bSAlexandre Chartre 
301*49bfb42bSAlexandre Chartre 	reply_len = LDMA_MESSAGE_SIZE(reply_dlen);
302*49bfb42bSAlexandre Chartre 
303*49bfb42bSAlexandre Chartre 	LDMA_DBG("%s: DATA hdl=%llx, reply num=%llu type=0x%x info=0x%x "
304*49bfb42bSAlexandre Chartre 	    "dlen=%d", agent->info->name, hdl, reply->msg_num,
305*49bfb42bSAlexandre Chartre 	    reply->msg_type, reply->msg_info, reply_dlen);
306*49bfb42bSAlexandre Chartre 
307*49bfb42bSAlexandre Chartre 	if (ds_send_msg(hdl, reply, reply_len) != 0) {
308*49bfb42bSAlexandre Chartre 		LDMA_ERR("agent %s has failed to send reply for request %llu",
309*49bfb42bSAlexandre Chartre 		    agent->info->name, request->msg_num);
310*49bfb42bSAlexandre Chartre 	}
311*49bfb42bSAlexandre Chartre 
312*49bfb42bSAlexandre Chartre 	if (reply != request)
313*49bfb42bSAlexandre Chartre 		free(reply);
314*49bfb42bSAlexandre Chartre }
315*49bfb42bSAlexandre Chartre 
316*49bfb42bSAlexandre Chartre /*
317*49bfb42bSAlexandre Chartre  * Register an agent. Return 0 if the agent was successfully registered.
318*49bfb42bSAlexandre Chartre  */
319*49bfb42bSAlexandre Chartre static int
320*49bfb42bSAlexandre Chartre ldma_register(ldma_agent_info_t *agent_info)
321*49bfb42bSAlexandre Chartre {
322*49bfb42bSAlexandre Chartre 	ldma_agent_t	*agent;
323*49bfb42bSAlexandre Chartre 	ds_capability_t	ds_cap;
324*49bfb42bSAlexandre Chartre 	ds_ops_t	ds_ops;
325*49bfb42bSAlexandre Chartre 
326*49bfb42bSAlexandre Chartre 	agent = malloc(sizeof (ldma_agent_t));
327*49bfb42bSAlexandre Chartre 	if (agent == NULL)
328*49bfb42bSAlexandre Chartre 		goto register_fail;
329*49bfb42bSAlexandre Chartre 
330*49bfb42bSAlexandre Chartre 	agent->info = agent_info;
331*49bfb42bSAlexandre Chartre 	agent->conn_hdl = 0;
332*49bfb42bSAlexandre Chartre 	agent->conn_ver.major = 0;
333*49bfb42bSAlexandre Chartre 	agent->conn_ver.minor = 0;
334*49bfb42bSAlexandre Chartre 
335*49bfb42bSAlexandre Chartre 	ds_cap.svc_id = agent_info->name;
336*49bfb42bSAlexandre Chartre 	ds_cap.vers = agent_info->vers;
337*49bfb42bSAlexandre Chartre 	ds_cap.nvers = agent_info->nvers;
338*49bfb42bSAlexandre Chartre 
339*49bfb42bSAlexandre Chartre 	ds_ops.ds_reg_cb = ldma_reg_cb;
340*49bfb42bSAlexandre Chartre 	ds_ops.ds_unreg_cb = ldma_unreg_cb;
341*49bfb42bSAlexandre Chartre 	ds_ops.ds_data_cb = ldma_data_cb;
342*49bfb42bSAlexandre Chartre 	ds_ops.cb_arg = agent;
343*49bfb42bSAlexandre Chartre 
344*49bfb42bSAlexandre Chartre 	if (ds_svc_reg(&ds_cap, &ds_ops) == 0) {
345*49bfb42bSAlexandre Chartre 		LDMA_INFO("agent %s registered", agent_info->name);
346*49bfb42bSAlexandre Chartre 		return (0);
347*49bfb42bSAlexandre Chartre 	}
348*49bfb42bSAlexandre Chartre 
349*49bfb42bSAlexandre Chartre register_fail:
350*49bfb42bSAlexandre Chartre 
351*49bfb42bSAlexandre Chartre 	LDMA_ERR("agent %s has failed to register", agent_info->name);
352*49bfb42bSAlexandre Chartre 	free(agent);
353*49bfb42bSAlexandre Chartre 	return (-1);
354*49bfb42bSAlexandre Chartre }
355*49bfb42bSAlexandre Chartre 
356*49bfb42bSAlexandre Chartre /*
357*49bfb42bSAlexandre Chartre  * Register all known agents. Return the number of agents successfully
358*49bfb42bSAlexandre Chartre  * registered.
359*49bfb42bSAlexandre Chartre  */
360*49bfb42bSAlexandre Chartre static int
361*49bfb42bSAlexandre Chartre ldma_register_agents()
362*49bfb42bSAlexandre Chartre {
363*49bfb42bSAlexandre Chartre 	int count = 0;
364*49bfb42bSAlexandre Chartre 	ldma_agent_info_t **agent_infop;
365*49bfb42bSAlexandre Chartre 
366*49bfb42bSAlexandre Chartre 	for (agent_infop = ldma_agent_infos;
367*49bfb42bSAlexandre Chartre 	    *agent_infop != NULL; agent_infop++) {
368*49bfb42bSAlexandre Chartre 
369*49bfb42bSAlexandre Chartre 		if (ldma_register(*agent_infop) == 0)
370*49bfb42bSAlexandre Chartre 			count++;
371*49bfb42bSAlexandre Chartre 	}
372*49bfb42bSAlexandre Chartre 
373*49bfb42bSAlexandre Chartre 	return (count);
374*49bfb42bSAlexandre Chartre }
375*49bfb42bSAlexandre Chartre 
376*49bfb42bSAlexandre Chartre /*ARGSUSED*/
377*49bfb42bSAlexandre Chartre static void
378*49bfb42bSAlexandre Chartre ldma_sigusr_handler(int sig, siginfo_t *sinfo, void *ucontext)
379*49bfb42bSAlexandre Chartre {
380*49bfb42bSAlexandre Chartre 	if (daemon_pid <= 0 || sig != SIGUSR1 || sinfo->si_code != SI_USER ||
381*49bfb42bSAlexandre Chartre 	    sinfo->si_pid != daemon_pid)
382*49bfb42bSAlexandre Chartre 		return;
383*49bfb42bSAlexandre Chartre 
384*49bfb42bSAlexandre Chartre 	/*
385*49bfb42bSAlexandre Chartre 	 * The parent process has received a USR1 signal from the child.
386*49bfb42bSAlexandre Chartre 	 * This means that the daemon has correctly started and the parent
387*49bfb42bSAlexandre Chartre 	 * can exit.
388*49bfb42bSAlexandre Chartre 	 */
389*49bfb42bSAlexandre Chartre 	exit(0);
390*49bfb42bSAlexandre Chartre }
391*49bfb42bSAlexandre Chartre 
392*49bfb42bSAlexandre Chartre static void
393*49bfb42bSAlexandre Chartre ldma_start(boolean_t standalone)
394*49bfb42bSAlexandre Chartre {
395*49bfb42bSAlexandre Chartre 	int stat, rv;
396*49bfb42bSAlexandre Chartre 	struct sigaction action;
397*49bfb42bSAlexandre Chartre 
398*49bfb42bSAlexandre Chartre 	if (!standalone) {
399*49bfb42bSAlexandre Chartre 		/*
400*49bfb42bSAlexandre Chartre 		 * Some configuration of the daemon has to be done in the
401*49bfb42bSAlexandre Chartre 		 * child, but we want the parent to report if the daemon
402*49bfb42bSAlexandre Chartre 		 * has successfully started or not. So we setup a signal
403*49bfb42bSAlexandre Chartre 		 * handler, and the child will notify the parent using the
404*49bfb42bSAlexandre Chartre 		 * USR1 signal if the setup was successful. Otherwise the
405*49bfb42bSAlexandre Chartre 		 * child will exit.
406*49bfb42bSAlexandre Chartre 		 */
407*49bfb42bSAlexandre Chartre 		action.sa_sigaction = ldma_sigusr_handler;
408*49bfb42bSAlexandre Chartre 		action.sa_flags = SA_SIGINFO;
409*49bfb42bSAlexandre Chartre 
410*49bfb42bSAlexandre Chartre 		if (sigemptyset(&action.sa_mask) == -1) {
411*49bfb42bSAlexandre Chartre 			LDMA_ERR("sigemptyset error (%d)", errno);
412*49bfb42bSAlexandre Chartre 			exit(1);
413*49bfb42bSAlexandre Chartre 		}
414*49bfb42bSAlexandre Chartre 
415*49bfb42bSAlexandre Chartre 		if (sigaction(SIGUSR1, &action, NULL) == -1) {
416*49bfb42bSAlexandre Chartre 			LDMA_ERR("sigaction() error (%d)", errno);
417*49bfb42bSAlexandre Chartre 			exit(1);
418*49bfb42bSAlexandre Chartre 		}
419*49bfb42bSAlexandre Chartre 
420*49bfb42bSAlexandre Chartre 		if (sigrelse(SIGUSR1) == -1) {
421*49bfb42bSAlexandre Chartre 			LDMA_ERR("sigrelse() error (%d)", errno);
422*49bfb42bSAlexandre Chartre 			exit(1);
423*49bfb42bSAlexandre Chartre 		}
424*49bfb42bSAlexandre Chartre 
425*49bfb42bSAlexandre Chartre 		if ((daemon_pid = fork()) == -1) {
426*49bfb42bSAlexandre Chartre 			LDMA_ERR("fork() error (%d)", errno);
427*49bfb42bSAlexandre Chartre 			exit(1);
428*49bfb42bSAlexandre Chartre 		}
429*49bfb42bSAlexandre Chartre 
430*49bfb42bSAlexandre Chartre 		if (daemon_pid != 0) {
431*49bfb42bSAlexandre Chartre 			/*
432*49bfb42bSAlexandre Chartre 			 * The parent process waits until the child exits (in
433*49bfb42bSAlexandre Chartre 			 * case of an error) or sends a USR1 signal (if the
434*49bfb42bSAlexandre Chartre 			 * daemon has correctly started).
435*49bfb42bSAlexandre Chartre 			 */
436*49bfb42bSAlexandre Chartre 			for (;;) {
437*49bfb42bSAlexandre Chartre 				rv = waitpid(daemon_pid, &stat, 0);
438*49bfb42bSAlexandre Chartre 				if ((rv == daemon_pid && WIFEXITED(stat)) ||
439*49bfb42bSAlexandre Chartre 				    (rv == -1 && errno != EINTR)) {
440*49bfb42bSAlexandre Chartre 					/* child has exited or error */
441*49bfb42bSAlexandre Chartre 					exit(1);
442*49bfb42bSAlexandre Chartre 				}
443*49bfb42bSAlexandre Chartre 			}
444*49bfb42bSAlexandre Chartre 		}
445*49bfb42bSAlexandre Chartre 
446*49bfb42bSAlexandre Chartre 		/*
447*49bfb42bSAlexandre Chartre 		 * Initialize child process
448*49bfb42bSAlexandre Chartre 		 */
449*49bfb42bSAlexandre Chartre 		if (sighold(SIGUSR1) == -1) {
450*49bfb42bSAlexandre Chartre 			LDMA_ERR("sighold error (%d)", errno);
451*49bfb42bSAlexandre Chartre 			exit(1);
452*49bfb42bSAlexandre Chartre 		}
453*49bfb42bSAlexandre Chartre 
454*49bfb42bSAlexandre Chartre 		if (sigignore(SIGUSR1) == -1) {
455*49bfb42bSAlexandre Chartre 			LDMA_ERR("sigignore error (%d)", errno);
456*49bfb42bSAlexandre Chartre 			exit(1);
457*49bfb42bSAlexandre Chartre 		}
458*49bfb42bSAlexandre Chartre 
459*49bfb42bSAlexandre Chartre 		if (setsid() == -1) {
460*49bfb42bSAlexandre Chartre 			LDMA_ERR("setsid error (%d)", errno);
461*49bfb42bSAlexandre Chartre 			exit(1);
462*49bfb42bSAlexandre Chartre 		}
463*49bfb42bSAlexandre Chartre 
464*49bfb42bSAlexandre Chartre 		if (chdir("/") == -1) {
465*49bfb42bSAlexandre Chartre 			LDMA_ERR("chdir error (%d)", errno);
466*49bfb42bSAlexandre Chartre 			exit(1);
467*49bfb42bSAlexandre Chartre 		}
468*49bfb42bSAlexandre Chartre 		(void) umask(0);
469*49bfb42bSAlexandre Chartre 
470*49bfb42bSAlexandre Chartre 		/*
471*49bfb42bSAlexandre Chartre 		 * Initialize file descriptors. Do not touch stderr
472*49bfb42bSAlexandre Chartre 		 * which is initialized by SMF to point to the daemon
473*49bfb42bSAlexandre Chartre 		 * specific log file.
474*49bfb42bSAlexandre Chartre 		 */
475*49bfb42bSAlexandre Chartre 		(void) close(STDIN_FILENO);
476*49bfb42bSAlexandre Chartre 		if (open("/dev/null", O_RDWR) == -1) {
477*49bfb42bSAlexandre Chartre 			LDMA_ERR("open /dev/null error (%d)", errno);
478*49bfb42bSAlexandre Chartre 			exit(1);
479*49bfb42bSAlexandre Chartre 		}
480*49bfb42bSAlexandre Chartre 		if (dup2(STDIN_FILENO, STDOUT_FILENO) == -1) {
481*49bfb42bSAlexandre Chartre 			LDMA_ERR("dup2 error (%d)", errno);
482*49bfb42bSAlexandre Chartre 			exit(1);
483*49bfb42bSAlexandre Chartre 		}
484*49bfb42bSAlexandre Chartre 		closefrom(STDERR_FILENO + 1);
485*49bfb42bSAlexandre Chartre 
486*49bfb42bSAlexandre Chartre 		/* initialize logging */
487*49bfb42bSAlexandre Chartre 		openlog(cmdname, LOG_CONS | LOG_NDELAY, LOG_DAEMON);
488*49bfb42bSAlexandre Chartre 
489*49bfb42bSAlexandre Chartre 		ldma_daemon = B_TRUE;
490*49bfb42bSAlexandre Chartre 	}
491*49bfb42bSAlexandre Chartre 
492*49bfb42bSAlexandre Chartre 	/*
493*49bfb42bSAlexandre Chartre 	 * Register the agents. It would be easier to do this before
494*49bfb42bSAlexandre Chartre 	 * daemonizing so that any start error is directly reported. But
495*49bfb42bSAlexandre Chartre 	 * this can not be done because agents are registered using libds
496*49bfb42bSAlexandre Chartre 	 * and this will subscribe the daemon to some sysevents which is
497*49bfb42bSAlexandre Chartre 	 * a process based subscription. Instead we notify the parent process
498*49bfb42bSAlexandre Chartre 	 * either by exiting, or by sending a SIGUSR1 signal.
499*49bfb42bSAlexandre Chartre 	 */
500*49bfb42bSAlexandre Chartre 	if (ldma_register_agents() == 0) {
501*49bfb42bSAlexandre Chartre 		/* no agent registered */
502*49bfb42bSAlexandre Chartre 		LDMA_ERR("Unable to register any agent", cmdname);
503*49bfb42bSAlexandre Chartre 		exit(1);
504*49bfb42bSAlexandre Chartre 	}
505*49bfb42bSAlexandre Chartre 
506*49bfb42bSAlexandre Chartre 	if (!standalone) {
507*49bfb42bSAlexandre Chartre 		/* signal parent that startup was successful */
508*49bfb42bSAlexandre Chartre 		if (kill(getppid(), SIGUSR1) == -1)
509*49bfb42bSAlexandre Chartre 			exit(1);
510*49bfb42bSAlexandre Chartre 	}
511*49bfb42bSAlexandre Chartre }
512*49bfb42bSAlexandre Chartre 
513*49bfb42bSAlexandre Chartre static void
514*49bfb42bSAlexandre Chartre ldma_usage()
515*49bfb42bSAlexandre Chartre {
516*49bfb42bSAlexandre Chartre 	(void) fprintf(stderr, "usage: %s\n", cmdname);
517*49bfb42bSAlexandre Chartre }
518*49bfb42bSAlexandre Chartre 
519*49bfb42bSAlexandre Chartre int
520*49bfb42bSAlexandre Chartre main(int argc, char *argv[])
521*49bfb42bSAlexandre Chartre {
522*49bfb42bSAlexandre Chartre 	int opt;
523*49bfb42bSAlexandre Chartre 	boolean_t standalone = B_FALSE;
524*49bfb42bSAlexandre Chartre 
525*49bfb42bSAlexandre Chartre 	cmdname = basename(argv[0]);
526*49bfb42bSAlexandre Chartre 
527*49bfb42bSAlexandre Chartre 	/* disable getopt error messages */
528*49bfb42bSAlexandre Chartre 	opterr = 0;
529*49bfb42bSAlexandre Chartre 
530*49bfb42bSAlexandre Chartre 	while ((opt = getopt(argc, argv, "ds")) != EOF) {
531*49bfb42bSAlexandre Chartre 
532*49bfb42bSAlexandre Chartre 		switch (opt) {
533*49bfb42bSAlexandre Chartre 		case 'd':
534*49bfb42bSAlexandre Chartre 			ldma_debug = B_TRUE;
535*49bfb42bSAlexandre Chartre 			break;
536*49bfb42bSAlexandre Chartre 		case 's':
537*49bfb42bSAlexandre Chartre 			standalone = B_TRUE;
538*49bfb42bSAlexandre Chartre 			break;
539*49bfb42bSAlexandre Chartre 		default:
540*49bfb42bSAlexandre Chartre 			ldma_usage();
541*49bfb42bSAlexandre Chartre 			exit(1);
542*49bfb42bSAlexandre Chartre 		}
543*49bfb42bSAlexandre Chartre 	}
544*49bfb42bSAlexandre Chartre 
545*49bfb42bSAlexandre Chartre 	ldma_start(standalone);
546*49bfb42bSAlexandre Chartre 
547*49bfb42bSAlexandre Chartre 	/*
548*49bfb42bSAlexandre Chartre 	 * Loop forever. Any incoming message will be received by libds and
549*49bfb42bSAlexandre Chartre 	 * forwarded to the agent data callback (ldma_data_cb()) where it
550*49bfb42bSAlexandre Chartre 	 * will be processed.
551*49bfb42bSAlexandre Chartre 	 */
552*49bfb42bSAlexandre Chartre 	for (;;) {
553*49bfb42bSAlexandre Chartre 		(void) pause();
554*49bfb42bSAlexandre Chartre 	}
555*49bfb42bSAlexandre Chartre 
556*49bfb42bSAlexandre Chartre 	/*NOTREACHED*/
557*49bfb42bSAlexandre Chartre 	return (0);
558*49bfb42bSAlexandre Chartre }
559