149bfb42bSAlexandre Chartre /* 249bfb42bSAlexandre Chartre * CDDL HEADER START 349bfb42bSAlexandre Chartre * 449bfb42bSAlexandre Chartre * The contents of this file are subject to the terms of the 549bfb42bSAlexandre Chartre * Common Development and Distribution License (the "License"). 649bfb42bSAlexandre Chartre * You may not use this file except in compliance with the License. 749bfb42bSAlexandre Chartre * 849bfb42bSAlexandre Chartre * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 949bfb42bSAlexandre Chartre * or http://www.opensolaris.org/os/licensing. 1049bfb42bSAlexandre Chartre * See the License for the specific language governing permissions 1149bfb42bSAlexandre Chartre * and limitations under the License. 1249bfb42bSAlexandre Chartre * 1349bfb42bSAlexandre Chartre * When distributing Covered Code, include this CDDL HEADER in each 1449bfb42bSAlexandre Chartre * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1549bfb42bSAlexandre Chartre * If applicable, add the following below this CDDL HEADER, with the 1649bfb42bSAlexandre Chartre * fields enclosed by brackets "[]" replaced with your own identifying 1749bfb42bSAlexandre Chartre * information: Portions Copyright [yyyy] [name of copyright owner] 1849bfb42bSAlexandre Chartre * 1949bfb42bSAlexandre Chartre * CDDL HEADER END 2049bfb42bSAlexandre Chartre */ 2149bfb42bSAlexandre Chartre 2249bfb42bSAlexandre Chartre /* 2349bfb42bSAlexandre Chartre * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2449bfb42bSAlexandre Chartre * Use is subject to license terms. 2549bfb42bSAlexandre Chartre */ 2649bfb42bSAlexandre Chartre 2749bfb42bSAlexandre Chartre /* 2849bfb42bSAlexandre Chartre * Logical Domains (LDoms) Agents Daemon 2949bfb42bSAlexandre Chartre * 3049bfb42bSAlexandre Chartre * The LDoms agents daemon (ldmad) runs on LDoms domains and provides 3149bfb42bSAlexandre Chartre * information to the control domain. It is composed of a set of agents 3249bfb42bSAlexandre Chartre * which can send and receive messages to and from the control domain. 3349bfb42bSAlexandre Chartre * Each agent is registered as a domain service using the libds library, 3449bfb42bSAlexandre Chartre * and is able to handle requests coming from the control domain. 3549bfb42bSAlexandre Chartre * 3649bfb42bSAlexandre Chartre * The control domain sends requests to an agent as messages on the 3749bfb42bSAlexandre Chartre * corresponding domain service (identified by the agent name). All requests 3849bfb42bSAlexandre Chartre * are received by the ldmad daemon which dispatches them to the appropriate 3949bfb42bSAlexandre Chartre * handler function of the agent depending on the type of the message. 4049bfb42bSAlexandre Chartre * 4149bfb42bSAlexandre Chartre * After the request has been processed by the handler, the ldmad daemon sent 4249bfb42bSAlexandre Chartre * a reply message back to the control domain. The reply is either a result 4349bfb42bSAlexandre Chartre * message if the request was successfully completed, or an error message 4449bfb42bSAlexandre Chartre * describing the failure. 4549bfb42bSAlexandre Chartre */ 4649bfb42bSAlexandre Chartre 4749bfb42bSAlexandre Chartre #include <dirent.h> 4849bfb42bSAlexandre Chartre #include <dlfcn.h> 4949bfb42bSAlexandre Chartre #include <errno.h> 5049bfb42bSAlexandre Chartre #include <fcntl.h> 5149bfb42bSAlexandre Chartre #include <link.h> 5249bfb42bSAlexandre Chartre #include <libds.h> 5349bfb42bSAlexandre Chartre #include <libgen.h> 5449bfb42bSAlexandre Chartre #include <signal.h> 5549bfb42bSAlexandre Chartre #include <stdio.h> 5649bfb42bSAlexandre Chartre #include <stdlib.h> 5749bfb42bSAlexandre Chartre #include <strings.h> 5849bfb42bSAlexandre Chartre #include <syslog.h> 5949bfb42bSAlexandre Chartre #include <unistd.h> 6049bfb42bSAlexandre Chartre #include <sys/types.h> 6149bfb42bSAlexandre Chartre #include <sys/stat.h> 6249bfb42bSAlexandre Chartre #include <sys/wait.h> 6349bfb42bSAlexandre Chartre 6449bfb42bSAlexandre Chartre #include "ldma.h" 6549bfb42bSAlexandre Chartre 6649bfb42bSAlexandre Chartre #define LDMA_MODULE "ldm-agent-daemon" 6749bfb42bSAlexandre Chartre 6849bfb42bSAlexandre Chartre #define LDMA_CONTROL_DOMAIN_DHDL 0 /* id of the control domain */ 6949bfb42bSAlexandre Chartre #define LDMA_DOMAIN_NAME_MAXLEN MAXNAMELEN 7049bfb42bSAlexandre Chartre 7149bfb42bSAlexandre Chartre typedef struct ldma_agent { 7249bfb42bSAlexandre Chartre ldma_agent_info_t *info; /* agent information */ 7349bfb42bSAlexandre Chartre ds_hdl_t conn_hdl; /* connexion handler */ 7449bfb42bSAlexandre Chartre ds_ver_t conn_ver; /* connexion version */ 7549bfb42bSAlexandre Chartre } ldma_agent_t; 7649bfb42bSAlexandre Chartre 7749bfb42bSAlexandre Chartre /* information about existing agents */ 7849bfb42bSAlexandre Chartre extern ldma_agent_info_t ldma_device_info; 7949bfb42bSAlexandre Chartre extern ldma_agent_info_t ldma_system_info; 8049bfb42bSAlexandre Chartre 8149bfb42bSAlexandre Chartre boolean_t ldma_debug = B_FALSE; 8249bfb42bSAlexandre Chartre boolean_t ldma_daemon = B_FALSE; 8349bfb42bSAlexandre Chartre 8449bfb42bSAlexandre Chartre static ldma_agent_info_t *ldma_agent_infos[] = { 8549bfb42bSAlexandre Chartre &ldma_device_info, 8649bfb42bSAlexandre Chartre &ldma_system_info, 8749bfb42bSAlexandre Chartre NULL 8849bfb42bSAlexandre Chartre }; 8949bfb42bSAlexandre Chartre 9049bfb42bSAlexandre Chartre static char *cmdname; 91*6b8303caSAlexandre Chartre static pid_t daemon_pid = 0; 9249bfb42bSAlexandre Chartre 9349bfb42bSAlexandre Chartre /* 9449bfb42bSAlexandre Chartre * Allocate a new message with the specified message number (msg_num), 9549bfb42bSAlexandre Chartre * message type (msg_type) and message data length (msg_dlen). Return 9649bfb42bSAlexandre Chartre * NULL if the allocation has failed. 9749bfb42bSAlexandre Chartre */ 9849bfb42bSAlexandre Chartre static ldma_message_header_t * 9949bfb42bSAlexandre Chartre ldma_alloc_msg(uint64_t msg_num, uint32_t msg_type, size_t msg_dlen) 10049bfb42bSAlexandre Chartre { 10149bfb42bSAlexandre Chartre ldma_message_header_t *msg; 10249bfb42bSAlexandre Chartre size_t msg_len; 10349bfb42bSAlexandre Chartre 10449bfb42bSAlexandre Chartre msg_len = LDMA_MESSAGE_SIZE(msg_dlen); 10549bfb42bSAlexandre Chartre msg = malloc(msg_len); 10649bfb42bSAlexandre Chartre if (msg == NULL) 10749bfb42bSAlexandre Chartre return (NULL); 10849bfb42bSAlexandre Chartre 10949bfb42bSAlexandre Chartre msg->msg_num = msg_num; 11049bfb42bSAlexandre Chartre msg->msg_type = msg_type; 11149bfb42bSAlexandre Chartre msg->msg_info = 0; 11249bfb42bSAlexandre Chartre 11349bfb42bSAlexandre Chartre return (msg); 11449bfb42bSAlexandre Chartre } 11549bfb42bSAlexandre Chartre 11649bfb42bSAlexandre Chartre /* 11749bfb42bSAlexandre Chartre * Allocate a result message (LDMA_MSG_REQ_RESULT) with the specified message 11849bfb42bSAlexandre Chartre * data length (msg_dlen). If the request argument is not NULL then the message 11949bfb42bSAlexandre Chartre * is created with the same message number as the request, otherwise the message 12049bfb42bSAlexandre Chartre * number is set to 0. Return NULL if the allocation has failed. 12149bfb42bSAlexandre Chartre */ 12249bfb42bSAlexandre Chartre ldma_message_header_t * 12349bfb42bSAlexandre Chartre ldma_alloc_result_msg(ldma_message_header_t *request, size_t msg_dlen) 12449bfb42bSAlexandre Chartre { 12549bfb42bSAlexandre Chartre uint64_t msg_num; 12649bfb42bSAlexandre Chartre 12749bfb42bSAlexandre Chartre msg_num = (request == NULL)? 0 : request->msg_num; 12849bfb42bSAlexandre Chartre 12949bfb42bSAlexandre Chartre return (ldma_alloc_msg(msg_num, LDMA_MSG_RESULT, msg_dlen)); 13049bfb42bSAlexandre Chartre } 13149bfb42bSAlexandre Chartre 13249bfb42bSAlexandre Chartre /* 13349bfb42bSAlexandre Chartre * Agent register callback. This callback is invoked when a client is registered 13449bfb42bSAlexandre Chartre * for using the service provided by an agent. An agent will only have one 13549bfb42bSAlexandre Chartre * consumer which is coming from the control domain. 13649bfb42bSAlexandre Chartre */ 13749bfb42bSAlexandre Chartre static void 13849bfb42bSAlexandre Chartre ldma_reg_cb(ds_hdl_t hdl, ds_cb_arg_t arg, ds_ver_t *ver, 13949bfb42bSAlexandre Chartre ds_domain_hdl_t dhdl) 14049bfb42bSAlexandre Chartre { 14149bfb42bSAlexandre Chartre ldma_agent_t *agent = (ldma_agent_t *)arg; 14249bfb42bSAlexandre Chartre char dname[LDMA_DOMAIN_NAME_MAXLEN]; 14349bfb42bSAlexandre Chartre 14449bfb42bSAlexandre Chartre if (ds_dom_hdl_to_name(dhdl, dname, LDMA_DOMAIN_NAME_MAXLEN) != 0) { 14549bfb42bSAlexandre Chartre (void) strcpy(dname, "<unknown>"); 14649bfb42bSAlexandre Chartre } 14749bfb42bSAlexandre Chartre 14849bfb42bSAlexandre Chartre LDMA_DBG("%s: REGISTER hdl=%llx, dhdl=%llx (%s) ver=%hd.%hd", 14949bfb42bSAlexandre Chartre agent->info->name, hdl, dhdl, dname, ver->major, ver->minor); 15049bfb42bSAlexandre Chartre 15149bfb42bSAlexandre Chartre /* 15249bfb42bSAlexandre Chartre * Record client information if the connexion is from the control 15349bfb42bSAlexandre Chartre * domain. The domain service framework only allows connexion of a 15449bfb42bSAlexandre Chartre * domain with the control domain. However, if the agent is running 15549bfb42bSAlexandre Chartre * on the control domain then it can see connexions coming from any 15649bfb42bSAlexandre Chartre * domains. That's why we explicitly have to check if the connexion 15749bfb42bSAlexandre Chartre * is effectively with the control domain. 15849bfb42bSAlexandre Chartre */ 15949bfb42bSAlexandre Chartre if (dhdl == LDMA_CONTROL_DOMAIN_DHDL) { 16049bfb42bSAlexandre Chartre agent->conn_hdl = hdl; 16149bfb42bSAlexandre Chartre agent->conn_ver.major = ver->major; 16249bfb42bSAlexandre Chartre agent->conn_ver.minor = ver->minor; 16349bfb42bSAlexandre Chartre } else { 16449bfb42bSAlexandre Chartre LDMA_INFO("agent %s will ignore any request from distrusted " 16549bfb42bSAlexandre Chartre "domain %s", agent->info->name, dname); 16649bfb42bSAlexandre Chartre } 16749bfb42bSAlexandre Chartre } 16849bfb42bSAlexandre Chartre 16949bfb42bSAlexandre Chartre /* 17049bfb42bSAlexandre Chartre * Agent unregister callback. This callback is invoked when a client is 17149bfb42bSAlexandre Chartre * unregistered and stops using the service provided by an agent. 17249bfb42bSAlexandre Chartre */ 17349bfb42bSAlexandre Chartre static void 17449bfb42bSAlexandre Chartre ldma_unreg_cb(ds_hdl_t hdl, ds_cb_arg_t arg) 17549bfb42bSAlexandre Chartre { 17649bfb42bSAlexandre Chartre ldma_agent_t *agent = (ldma_agent_t *)arg; 17749bfb42bSAlexandre Chartre 17849bfb42bSAlexandre Chartre LDMA_DBG("%s: UNREGISTER hdl=%llx", agent->info->name, hdl); 17949bfb42bSAlexandre Chartre 18049bfb42bSAlexandre Chartre if (agent->conn_hdl == hdl) { 18149bfb42bSAlexandre Chartre agent->conn_hdl = 0; 18249bfb42bSAlexandre Chartre agent->conn_ver.major = 0; 18349bfb42bSAlexandre Chartre agent->conn_ver.minor = 0; 18449bfb42bSAlexandre Chartre } else { 18549bfb42bSAlexandre Chartre LDMA_INFO("agent %s has unregistered consumer from " 18649bfb42bSAlexandre Chartre "distrusted domain", agent->info->name); 18749bfb42bSAlexandre Chartre } 18849bfb42bSAlexandre Chartre } 18949bfb42bSAlexandre Chartre 19049bfb42bSAlexandre Chartre /* 19149bfb42bSAlexandre Chartre * Agent data callback. This callback is invoked when an agent receives a new 19249bfb42bSAlexandre Chartre * message from a client. Any request from a client which is not the control 19349bfb42bSAlexandre Chartre * domain is immediatly rejected. Otherwise the message is forwarded to the 19449bfb42bSAlexandre Chartre * appropriate handler function provided by the agent, depending on the message 19549bfb42bSAlexandre Chartre * type. 19649bfb42bSAlexandre Chartre */ 19749bfb42bSAlexandre Chartre static void 19849bfb42bSAlexandre Chartre ldma_data_cb(ds_hdl_t hdl, ds_cb_arg_t arg, void *buf, size_t len) 19949bfb42bSAlexandre Chartre { 20049bfb42bSAlexandre Chartre ldma_agent_t *agent = (ldma_agent_t *)arg; 20149bfb42bSAlexandre Chartre ldma_msg_handler_t *handler; 20249bfb42bSAlexandre Chartre ldma_message_header_t *request = buf; 20349bfb42bSAlexandre Chartre ldma_message_header_t *reply = NULL; 20449bfb42bSAlexandre Chartre ldma_request_status_t status; 20549bfb42bSAlexandre Chartre size_t request_dlen, reply_len, reply_dlen = 0; 20649bfb42bSAlexandre Chartre int i; 20749bfb42bSAlexandre Chartre 20849bfb42bSAlexandre Chartre /* check the message size */ 20949bfb42bSAlexandre Chartre if (len < LDMA_MESSAGE_HEADER_SIZE) { 21049bfb42bSAlexandre Chartre LDMA_INFO("agent %s has ignored message with an invalid " 21149bfb42bSAlexandre Chartre "size of %d bytes", agent->info->name, len); 21249bfb42bSAlexandre Chartre return; 21349bfb42bSAlexandre Chartre } 21449bfb42bSAlexandre Chartre 21549bfb42bSAlexandre Chartre request_dlen = LDMA_MESSAGE_DLEN(len); 21649bfb42bSAlexandre Chartre 21749bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, request num=%llu type=0x%x info=0x%x " 21849bfb42bSAlexandre Chartre "dlen=%d", agent->info->name, hdl, request->msg_num, 21949bfb42bSAlexandre Chartre request->msg_type, request->msg_info, request_dlen); 22049bfb42bSAlexandre Chartre 22149bfb42bSAlexandre Chartre /* reject any request which is not from the control domain */ 22249bfb42bSAlexandre Chartre if (hdl != agent->conn_hdl) { 22349bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, rejecting request from a " 22449bfb42bSAlexandre Chartre "distrusted domain", agent->info->name, hdl); 22549bfb42bSAlexandre Chartre status = LDMA_REQ_DENIED; 22649bfb42bSAlexandre Chartre goto do_reply; 22749bfb42bSAlexandre Chartre } 22849bfb42bSAlexandre Chartre 22949bfb42bSAlexandre Chartre handler = NULL; 23049bfb42bSAlexandre Chartre 23149bfb42bSAlexandre Chartre for (i = 0; i < agent->info->nhandlers; i++) { 23249bfb42bSAlexandre Chartre if (agent->info->handlers[i].msg_type == request->msg_type) { 23349bfb42bSAlexandre Chartre handler = &agent->info->handlers[i]; 23449bfb42bSAlexandre Chartre break; 23549bfb42bSAlexandre Chartre } 23649bfb42bSAlexandre Chartre } 23749bfb42bSAlexandre Chartre 23849bfb42bSAlexandre Chartre if (handler == NULL) { 23949bfb42bSAlexandre Chartre /* this type of message is not defined by the agent */ 24049bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, unknown message type %x", 24149bfb42bSAlexandre Chartre agent->info->name, hdl, request->msg_type); 24249bfb42bSAlexandre Chartre status = LDMA_REQ_NOTSUP; 24349bfb42bSAlexandre Chartre goto do_reply; 24449bfb42bSAlexandre Chartre } 24549bfb42bSAlexandre Chartre 24649bfb42bSAlexandre Chartre if (handler->msg_handler == NULL) { 24749bfb42bSAlexandre Chartre /* 24849bfb42bSAlexandre Chartre * This type of message is defined by the agent but it 24949bfb42bSAlexandre Chartre * has no handler. That means there is no processing to 25049bfb42bSAlexandre Chartre * do, the message is just ignored, but the request is 25149bfb42bSAlexandre Chartre * successfully completed. 25249bfb42bSAlexandre Chartre */ 25349bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, no handler", 25449bfb42bSAlexandre Chartre agent->info->name, hdl); 25549bfb42bSAlexandre Chartre status = LDMA_REQ_COMPLETED; 25649bfb42bSAlexandre Chartre goto do_reply; 25749bfb42bSAlexandre Chartre } 25849bfb42bSAlexandre Chartre 25949bfb42bSAlexandre Chartre /* invoke the message handler of the agent */ 26049bfb42bSAlexandre Chartre status = (*handler->msg_handler)(&agent->conn_ver, request, 26149bfb42bSAlexandre Chartre request_dlen, &reply, &reply_dlen); 26249bfb42bSAlexandre Chartre 26349bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, handler stat=%d reply=%p rlen=%d", 26449bfb42bSAlexandre Chartre agent->info->name, hdl, status, (void *)reply, reply_dlen); 26549bfb42bSAlexandre Chartre 26649bfb42bSAlexandre Chartre do_reply: 26749bfb42bSAlexandre Chartre /* 26849bfb42bSAlexandre Chartre * If the handler has provided a reply message, we use it directly. 26949bfb42bSAlexandre Chartre * Otherwise, we build a reply depending on the status of the request. 27049bfb42bSAlexandre Chartre * In that case, we re-use the request buffer to build the reply 27149bfb42bSAlexandre Chartre * message. 27249bfb42bSAlexandre Chartre */ 27349bfb42bSAlexandre Chartre if (reply == NULL) { 27449bfb42bSAlexandre Chartre 27549bfb42bSAlexandre Chartre reply = request; 27649bfb42bSAlexandre Chartre reply_dlen = 0; 27749bfb42bSAlexandre Chartre 27849bfb42bSAlexandre Chartre if (status == LDMA_REQ_COMPLETED) { 27949bfb42bSAlexandre Chartre /* 28049bfb42bSAlexandre Chartre * The request was successful but no result message was 28149bfb42bSAlexandre Chartre * provided so we send an empty result message. 28249bfb42bSAlexandre Chartre */ 28349bfb42bSAlexandre Chartre reply->msg_type = LDMA_MSG_RESULT; 28449bfb42bSAlexandre Chartre reply->msg_info = 0; 28549bfb42bSAlexandre Chartre 28649bfb42bSAlexandre Chartre } else { 28749bfb42bSAlexandre Chartre /* 28849bfb42bSAlexandre Chartre * The request has failed but no error message was 28949bfb42bSAlexandre Chartre * provided so we send an error message based on the 29049bfb42bSAlexandre Chartre * request status. 29149bfb42bSAlexandre Chartre */ 29249bfb42bSAlexandre Chartre reply->msg_type = LDMA_MSG_ERROR; 29349bfb42bSAlexandre Chartre reply->msg_info = 29449bfb42bSAlexandre Chartre (status == LDMA_REQ_NOTSUP)? LDMA_MSGERR_NOTSUP : 29549bfb42bSAlexandre Chartre (status == LDMA_REQ_INVALID)? LDMA_MSGERR_INVALID : 29649bfb42bSAlexandre Chartre (status == LDMA_REQ_DENIED)? LDMA_MSGERR_DENY : 29749bfb42bSAlexandre Chartre LDMA_MSGERR_FAIL; 29849bfb42bSAlexandre Chartre } 29949bfb42bSAlexandre Chartre } 30049bfb42bSAlexandre Chartre 30149bfb42bSAlexandre Chartre reply_len = LDMA_MESSAGE_SIZE(reply_dlen); 30249bfb42bSAlexandre Chartre 30349bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, reply num=%llu type=0x%x info=0x%x " 30449bfb42bSAlexandre Chartre "dlen=%d", agent->info->name, hdl, reply->msg_num, 30549bfb42bSAlexandre Chartre reply->msg_type, reply->msg_info, reply_dlen); 30649bfb42bSAlexandre Chartre 30749bfb42bSAlexandre Chartre if (ds_send_msg(hdl, reply, reply_len) != 0) { 30849bfb42bSAlexandre Chartre LDMA_ERR("agent %s has failed to send reply for request %llu", 30949bfb42bSAlexandre Chartre agent->info->name, request->msg_num); 31049bfb42bSAlexandre Chartre } 31149bfb42bSAlexandre Chartre 31249bfb42bSAlexandre Chartre if (reply != request) 31349bfb42bSAlexandre Chartre free(reply); 31449bfb42bSAlexandre Chartre } 31549bfb42bSAlexandre Chartre 31649bfb42bSAlexandre Chartre /* 31749bfb42bSAlexandre Chartre * Register an agent. Return 0 if the agent was successfully registered. 31849bfb42bSAlexandre Chartre */ 31949bfb42bSAlexandre Chartre static int 32049bfb42bSAlexandre Chartre ldma_register(ldma_agent_info_t *agent_info) 32149bfb42bSAlexandre Chartre { 32249bfb42bSAlexandre Chartre ldma_agent_t *agent; 32349bfb42bSAlexandre Chartre ds_capability_t ds_cap; 32449bfb42bSAlexandre Chartre ds_ops_t ds_ops; 32549bfb42bSAlexandre Chartre 32649bfb42bSAlexandre Chartre agent = malloc(sizeof (ldma_agent_t)); 32749bfb42bSAlexandre Chartre if (agent == NULL) 32849bfb42bSAlexandre Chartre goto register_fail; 32949bfb42bSAlexandre Chartre 33049bfb42bSAlexandre Chartre agent->info = agent_info; 33149bfb42bSAlexandre Chartre agent->conn_hdl = 0; 33249bfb42bSAlexandre Chartre agent->conn_ver.major = 0; 33349bfb42bSAlexandre Chartre agent->conn_ver.minor = 0; 33449bfb42bSAlexandre Chartre 33549bfb42bSAlexandre Chartre ds_cap.svc_id = agent_info->name; 33649bfb42bSAlexandre Chartre ds_cap.vers = agent_info->vers; 33749bfb42bSAlexandre Chartre ds_cap.nvers = agent_info->nvers; 33849bfb42bSAlexandre Chartre 33949bfb42bSAlexandre Chartre ds_ops.ds_reg_cb = ldma_reg_cb; 34049bfb42bSAlexandre Chartre ds_ops.ds_unreg_cb = ldma_unreg_cb; 34149bfb42bSAlexandre Chartre ds_ops.ds_data_cb = ldma_data_cb; 34249bfb42bSAlexandre Chartre ds_ops.cb_arg = agent; 34349bfb42bSAlexandre Chartre 34449bfb42bSAlexandre Chartre if (ds_svc_reg(&ds_cap, &ds_ops) == 0) { 34549bfb42bSAlexandre Chartre LDMA_INFO("agent %s registered", agent_info->name); 34649bfb42bSAlexandre Chartre return (0); 34749bfb42bSAlexandre Chartre } 34849bfb42bSAlexandre Chartre 34949bfb42bSAlexandre Chartre register_fail: 35049bfb42bSAlexandre Chartre 35149bfb42bSAlexandre Chartre LDMA_ERR("agent %s has failed to register", agent_info->name); 35249bfb42bSAlexandre Chartre free(agent); 35349bfb42bSAlexandre Chartre return (-1); 35449bfb42bSAlexandre Chartre } 35549bfb42bSAlexandre Chartre 35649bfb42bSAlexandre Chartre /* 35749bfb42bSAlexandre Chartre * Register all known agents. Return the number of agents successfully 35849bfb42bSAlexandre Chartre * registered. 35949bfb42bSAlexandre Chartre */ 36049bfb42bSAlexandre Chartre static int 36149bfb42bSAlexandre Chartre ldma_register_agents() 36249bfb42bSAlexandre Chartre { 36349bfb42bSAlexandre Chartre int count = 0; 36449bfb42bSAlexandre Chartre ldma_agent_info_t **agent_infop; 36549bfb42bSAlexandre Chartre 36649bfb42bSAlexandre Chartre for (agent_infop = ldma_agent_infos; 36749bfb42bSAlexandre Chartre *agent_infop != NULL; agent_infop++) { 36849bfb42bSAlexandre Chartre 36949bfb42bSAlexandre Chartre if (ldma_register(*agent_infop) == 0) 37049bfb42bSAlexandre Chartre count++; 37149bfb42bSAlexandre Chartre } 37249bfb42bSAlexandre Chartre 37349bfb42bSAlexandre Chartre return (count); 37449bfb42bSAlexandre Chartre } 37549bfb42bSAlexandre Chartre 37649bfb42bSAlexandre Chartre /*ARGSUSED*/ 37749bfb42bSAlexandre Chartre static void 37849bfb42bSAlexandre Chartre ldma_sigusr_handler(int sig, siginfo_t *sinfo, void *ucontext) 37949bfb42bSAlexandre Chartre { 380*6b8303caSAlexandre Chartre /* 381*6b8303caSAlexandre Chartre * The child process can send the signal before the fork() 382*6b8303caSAlexandre Chartre * call has returned in the parent process. So daemon_pid 383*6b8303caSAlexandre Chartre * may not be set yet, and we don't check the pid in that 384*6b8303caSAlexandre Chartre * case. 385*6b8303caSAlexandre Chartre */ 386*6b8303caSAlexandre Chartre if (sig != SIGUSR1 || sinfo->si_code != SI_USER || 387*6b8303caSAlexandre Chartre (daemon_pid > 0 && sinfo->si_pid != daemon_pid)) 38849bfb42bSAlexandre Chartre return; 38949bfb42bSAlexandre Chartre 39049bfb42bSAlexandre Chartre /* 39149bfb42bSAlexandre Chartre * The parent process has received a USR1 signal from the child. 39249bfb42bSAlexandre Chartre * This means that the daemon has correctly started and the parent 39349bfb42bSAlexandre Chartre * can exit. 39449bfb42bSAlexandre Chartre */ 39549bfb42bSAlexandre Chartre exit(0); 39649bfb42bSAlexandre Chartre } 39749bfb42bSAlexandre Chartre 39849bfb42bSAlexandre Chartre static void 39949bfb42bSAlexandre Chartre ldma_start(boolean_t standalone) 40049bfb42bSAlexandre Chartre { 40149bfb42bSAlexandre Chartre int stat, rv; 40249bfb42bSAlexandre Chartre struct sigaction action; 40349bfb42bSAlexandre Chartre 40449bfb42bSAlexandre Chartre if (!standalone) { 40549bfb42bSAlexandre Chartre /* 40649bfb42bSAlexandre Chartre * Some configuration of the daemon has to be done in the 40749bfb42bSAlexandre Chartre * child, but we want the parent to report if the daemon 40849bfb42bSAlexandre Chartre * has successfully started or not. So we setup a signal 40949bfb42bSAlexandre Chartre * handler, and the child will notify the parent using the 41049bfb42bSAlexandre Chartre * USR1 signal if the setup was successful. Otherwise the 41149bfb42bSAlexandre Chartre * child will exit. 41249bfb42bSAlexandre Chartre */ 41349bfb42bSAlexandre Chartre action.sa_sigaction = ldma_sigusr_handler; 41449bfb42bSAlexandre Chartre action.sa_flags = SA_SIGINFO; 41549bfb42bSAlexandre Chartre 41649bfb42bSAlexandre Chartre if (sigemptyset(&action.sa_mask) == -1) { 41749bfb42bSAlexandre Chartre LDMA_ERR("sigemptyset error (%d)", errno); 41849bfb42bSAlexandre Chartre exit(1); 41949bfb42bSAlexandre Chartre } 42049bfb42bSAlexandre Chartre 42149bfb42bSAlexandre Chartre if (sigaction(SIGUSR1, &action, NULL) == -1) { 42249bfb42bSAlexandre Chartre LDMA_ERR("sigaction() error (%d)", errno); 42349bfb42bSAlexandre Chartre exit(1); 42449bfb42bSAlexandre Chartre } 42549bfb42bSAlexandre Chartre 42649bfb42bSAlexandre Chartre if (sigrelse(SIGUSR1) == -1) { 42749bfb42bSAlexandre Chartre LDMA_ERR("sigrelse() error (%d)", errno); 42849bfb42bSAlexandre Chartre exit(1); 42949bfb42bSAlexandre Chartre } 43049bfb42bSAlexandre Chartre 43149bfb42bSAlexandre Chartre if ((daemon_pid = fork()) == -1) { 43249bfb42bSAlexandre Chartre LDMA_ERR("fork() error (%d)", errno); 43349bfb42bSAlexandre Chartre exit(1); 43449bfb42bSAlexandre Chartre } 43549bfb42bSAlexandre Chartre 43649bfb42bSAlexandre Chartre if (daemon_pid != 0) { 43749bfb42bSAlexandre Chartre /* 43849bfb42bSAlexandre Chartre * The parent process waits until the child exits (in 43949bfb42bSAlexandre Chartre * case of an error) or sends a USR1 signal (if the 44049bfb42bSAlexandre Chartre * daemon has correctly started). 44149bfb42bSAlexandre Chartre */ 44249bfb42bSAlexandre Chartre for (;;) { 44349bfb42bSAlexandre Chartre rv = waitpid(daemon_pid, &stat, 0); 44449bfb42bSAlexandre Chartre if ((rv == daemon_pid && WIFEXITED(stat)) || 44549bfb42bSAlexandre Chartre (rv == -1 && errno != EINTR)) { 44649bfb42bSAlexandre Chartre /* child has exited or error */ 44749bfb42bSAlexandre Chartre exit(1); 44849bfb42bSAlexandre Chartre } 44949bfb42bSAlexandre Chartre } 45049bfb42bSAlexandre Chartre } 45149bfb42bSAlexandre Chartre 45249bfb42bSAlexandre Chartre /* 45349bfb42bSAlexandre Chartre * Initialize child process 45449bfb42bSAlexandre Chartre */ 45549bfb42bSAlexandre Chartre if (sighold(SIGUSR1) == -1) { 45649bfb42bSAlexandre Chartre LDMA_ERR("sighold error (%d)", errno); 45749bfb42bSAlexandre Chartre exit(1); 45849bfb42bSAlexandre Chartre } 45949bfb42bSAlexandre Chartre 46049bfb42bSAlexandre Chartre if (sigignore(SIGUSR1) == -1) { 46149bfb42bSAlexandre Chartre LDMA_ERR("sigignore error (%d)", errno); 46249bfb42bSAlexandre Chartre exit(1); 46349bfb42bSAlexandre Chartre } 46449bfb42bSAlexandre Chartre 46549bfb42bSAlexandre Chartre if (setsid() == -1) { 46649bfb42bSAlexandre Chartre LDMA_ERR("setsid error (%d)", errno); 46749bfb42bSAlexandre Chartre exit(1); 46849bfb42bSAlexandre Chartre } 46949bfb42bSAlexandre Chartre 47049bfb42bSAlexandre Chartre if (chdir("/") == -1) { 47149bfb42bSAlexandre Chartre LDMA_ERR("chdir error (%d)", errno); 47249bfb42bSAlexandre Chartre exit(1); 47349bfb42bSAlexandre Chartre } 47449bfb42bSAlexandre Chartre (void) umask(0); 47549bfb42bSAlexandre Chartre 47649bfb42bSAlexandre Chartre /* 47749bfb42bSAlexandre Chartre * Initialize file descriptors. Do not touch stderr 47849bfb42bSAlexandre Chartre * which is initialized by SMF to point to the daemon 47949bfb42bSAlexandre Chartre * specific log file. 48049bfb42bSAlexandre Chartre */ 48149bfb42bSAlexandre Chartre (void) close(STDIN_FILENO); 48249bfb42bSAlexandre Chartre if (open("/dev/null", O_RDWR) == -1) { 48349bfb42bSAlexandre Chartre LDMA_ERR("open /dev/null error (%d)", errno); 48449bfb42bSAlexandre Chartre exit(1); 48549bfb42bSAlexandre Chartre } 48649bfb42bSAlexandre Chartre if (dup2(STDIN_FILENO, STDOUT_FILENO) == -1) { 48749bfb42bSAlexandre Chartre LDMA_ERR("dup2 error (%d)", errno); 48849bfb42bSAlexandre Chartre exit(1); 48949bfb42bSAlexandre Chartre } 49049bfb42bSAlexandre Chartre closefrom(STDERR_FILENO + 1); 49149bfb42bSAlexandre Chartre 49249bfb42bSAlexandre Chartre /* initialize logging */ 49349bfb42bSAlexandre Chartre openlog(cmdname, LOG_CONS | LOG_NDELAY, LOG_DAEMON); 49449bfb42bSAlexandre Chartre 49549bfb42bSAlexandre Chartre ldma_daemon = B_TRUE; 49649bfb42bSAlexandre Chartre } 49749bfb42bSAlexandre Chartre 49849bfb42bSAlexandre Chartre /* 49949bfb42bSAlexandre Chartre * Register the agents. It would be easier to do this before 50049bfb42bSAlexandre Chartre * daemonizing so that any start error is directly reported. But 50149bfb42bSAlexandre Chartre * this can not be done because agents are registered using libds 50249bfb42bSAlexandre Chartre * and this will subscribe the daemon to some sysevents which is 50349bfb42bSAlexandre Chartre * a process based subscription. Instead we notify the parent process 50449bfb42bSAlexandre Chartre * either by exiting, or by sending a SIGUSR1 signal. 50549bfb42bSAlexandre Chartre */ 50649bfb42bSAlexandre Chartre if (ldma_register_agents() == 0) { 50749bfb42bSAlexandre Chartre /* no agent registered */ 508*6b8303caSAlexandre Chartre LDMA_ERR("Unable to register any agent"); 50949bfb42bSAlexandre Chartre exit(1); 51049bfb42bSAlexandre Chartre } 51149bfb42bSAlexandre Chartre 51249bfb42bSAlexandre Chartre if (!standalone) { 51349bfb42bSAlexandre Chartre /* signal parent that startup was successful */ 51449bfb42bSAlexandre Chartre if (kill(getppid(), SIGUSR1) == -1) 51549bfb42bSAlexandre Chartre exit(1); 51649bfb42bSAlexandre Chartre } 51749bfb42bSAlexandre Chartre } 51849bfb42bSAlexandre Chartre 51949bfb42bSAlexandre Chartre static void 52049bfb42bSAlexandre Chartre ldma_usage() 52149bfb42bSAlexandre Chartre { 52249bfb42bSAlexandre Chartre (void) fprintf(stderr, "usage: %s\n", cmdname); 52349bfb42bSAlexandre Chartre } 52449bfb42bSAlexandre Chartre 52549bfb42bSAlexandre Chartre int 52649bfb42bSAlexandre Chartre main(int argc, char *argv[]) 52749bfb42bSAlexandre Chartre { 52849bfb42bSAlexandre Chartre int opt; 52949bfb42bSAlexandre Chartre boolean_t standalone = B_FALSE; 53049bfb42bSAlexandre Chartre 53149bfb42bSAlexandre Chartre cmdname = basename(argv[0]); 53249bfb42bSAlexandre Chartre 53349bfb42bSAlexandre Chartre /* disable getopt error messages */ 53449bfb42bSAlexandre Chartre opterr = 0; 53549bfb42bSAlexandre Chartre 53649bfb42bSAlexandre Chartre while ((opt = getopt(argc, argv, "ds")) != EOF) { 53749bfb42bSAlexandre Chartre 53849bfb42bSAlexandre Chartre switch (opt) { 53949bfb42bSAlexandre Chartre case 'd': 54049bfb42bSAlexandre Chartre ldma_debug = B_TRUE; 54149bfb42bSAlexandre Chartre break; 54249bfb42bSAlexandre Chartre case 's': 54349bfb42bSAlexandre Chartre standalone = B_TRUE; 54449bfb42bSAlexandre Chartre break; 54549bfb42bSAlexandre Chartre default: 54649bfb42bSAlexandre Chartre ldma_usage(); 54749bfb42bSAlexandre Chartre exit(1); 54849bfb42bSAlexandre Chartre } 54949bfb42bSAlexandre Chartre } 55049bfb42bSAlexandre Chartre 55149bfb42bSAlexandre Chartre ldma_start(standalone); 55249bfb42bSAlexandre Chartre 55349bfb42bSAlexandre Chartre /* 55449bfb42bSAlexandre Chartre * Loop forever. Any incoming message will be received by libds and 55549bfb42bSAlexandre Chartre * forwarded to the agent data callback (ldma_data_cb()) where it 55649bfb42bSAlexandre Chartre * will be processed. 55749bfb42bSAlexandre Chartre */ 55849bfb42bSAlexandre Chartre for (;;) { 55949bfb42bSAlexandre Chartre (void) pause(); 56049bfb42bSAlexandre Chartre } 56149bfb42bSAlexandre Chartre 56249bfb42bSAlexandre Chartre /*NOTREACHED*/ 56349bfb42bSAlexandre Chartre return (0); 56449bfb42bSAlexandre Chartre } 565