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