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 /* 23*fc256490SJason Beloro * Copyright 2010 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; 80*fc256490SJason Beloro extern ldma_agent_info_t ldma_dio_info; 8149bfb42bSAlexandre Chartre 8249bfb42bSAlexandre Chartre boolean_t ldma_debug = B_FALSE; 8349bfb42bSAlexandre Chartre boolean_t ldma_daemon = B_FALSE; 8449bfb42bSAlexandre Chartre 8549bfb42bSAlexandre Chartre static ldma_agent_info_t *ldma_agent_infos[] = { 8649bfb42bSAlexandre Chartre &ldma_device_info, 8749bfb42bSAlexandre Chartre &ldma_system_info, 88*fc256490SJason Beloro &ldma_dio_info, 8949bfb42bSAlexandre Chartre NULL 9049bfb42bSAlexandre Chartre }; 9149bfb42bSAlexandre Chartre 9249bfb42bSAlexandre Chartre static char *cmdname; 936b8303caSAlexandre Chartre static pid_t daemon_pid = 0; 9449bfb42bSAlexandre Chartre 9549bfb42bSAlexandre Chartre /* 9649bfb42bSAlexandre Chartre * Allocate a new message with the specified message number (msg_num), 9749bfb42bSAlexandre Chartre * message type (msg_type) and message data length (msg_dlen). Return 9849bfb42bSAlexandre Chartre * NULL if the allocation has failed. 9949bfb42bSAlexandre Chartre */ 10049bfb42bSAlexandre Chartre static ldma_message_header_t * 10149bfb42bSAlexandre Chartre ldma_alloc_msg(uint64_t msg_num, uint32_t msg_type, size_t msg_dlen) 10249bfb42bSAlexandre Chartre { 10349bfb42bSAlexandre Chartre ldma_message_header_t *msg; 10449bfb42bSAlexandre Chartre size_t msg_len; 10549bfb42bSAlexandre Chartre 10649bfb42bSAlexandre Chartre msg_len = LDMA_MESSAGE_SIZE(msg_dlen); 10749bfb42bSAlexandre Chartre msg = malloc(msg_len); 10849bfb42bSAlexandre Chartre if (msg == NULL) 10949bfb42bSAlexandre Chartre return (NULL); 11049bfb42bSAlexandre Chartre 11149bfb42bSAlexandre Chartre msg->msg_num = msg_num; 11249bfb42bSAlexandre Chartre msg->msg_type = msg_type; 11349bfb42bSAlexandre Chartre msg->msg_info = 0; 11449bfb42bSAlexandre Chartre 11549bfb42bSAlexandre Chartre return (msg); 11649bfb42bSAlexandre Chartre } 11749bfb42bSAlexandre Chartre 11849bfb42bSAlexandre Chartre /* 11949bfb42bSAlexandre Chartre * Allocate a result message (LDMA_MSG_REQ_RESULT) with the specified message 12049bfb42bSAlexandre Chartre * data length (msg_dlen). If the request argument is not NULL then the message 12149bfb42bSAlexandre Chartre * is created with the same message number as the request, otherwise the message 12249bfb42bSAlexandre Chartre * number is set to 0. Return NULL if the allocation has failed. 12349bfb42bSAlexandre Chartre */ 12449bfb42bSAlexandre Chartre ldma_message_header_t * 12549bfb42bSAlexandre Chartre ldma_alloc_result_msg(ldma_message_header_t *request, size_t msg_dlen) 12649bfb42bSAlexandre Chartre { 12749bfb42bSAlexandre Chartre uint64_t msg_num; 12849bfb42bSAlexandre Chartre 12949bfb42bSAlexandre Chartre msg_num = (request == NULL)? 0 : request->msg_num; 13049bfb42bSAlexandre Chartre 13149bfb42bSAlexandre Chartre return (ldma_alloc_msg(msg_num, LDMA_MSG_RESULT, msg_dlen)); 13249bfb42bSAlexandre Chartre } 13349bfb42bSAlexandre Chartre 13449bfb42bSAlexandre Chartre /* 13549bfb42bSAlexandre Chartre * Agent register callback. This callback is invoked when a client is registered 13649bfb42bSAlexandre Chartre * for using the service provided by an agent. An agent will only have one 13749bfb42bSAlexandre Chartre * consumer which is coming from the control domain. 13849bfb42bSAlexandre Chartre */ 13949bfb42bSAlexandre Chartre static void 14049bfb42bSAlexandre Chartre ldma_reg_cb(ds_hdl_t hdl, ds_cb_arg_t arg, ds_ver_t *ver, 14149bfb42bSAlexandre Chartre ds_domain_hdl_t dhdl) 14249bfb42bSAlexandre Chartre { 14349bfb42bSAlexandre Chartre ldma_agent_t *agent = (ldma_agent_t *)arg; 14449bfb42bSAlexandre Chartre char dname[LDMA_DOMAIN_NAME_MAXLEN]; 14549bfb42bSAlexandre Chartre 14649bfb42bSAlexandre Chartre if (ds_dom_hdl_to_name(dhdl, dname, LDMA_DOMAIN_NAME_MAXLEN) != 0) { 14749bfb42bSAlexandre Chartre (void) strcpy(dname, "<unknown>"); 14849bfb42bSAlexandre Chartre } 14949bfb42bSAlexandre Chartre 15049bfb42bSAlexandre Chartre LDMA_DBG("%s: REGISTER hdl=%llx, dhdl=%llx (%s) ver=%hd.%hd", 15149bfb42bSAlexandre Chartre agent->info->name, hdl, dhdl, dname, ver->major, ver->minor); 15249bfb42bSAlexandre Chartre 15349bfb42bSAlexandre Chartre /* 15449bfb42bSAlexandre Chartre * Record client information if the connexion is from the control 15549bfb42bSAlexandre Chartre * domain. The domain service framework only allows connexion of a 15649bfb42bSAlexandre Chartre * domain with the control domain. However, if the agent is running 15749bfb42bSAlexandre Chartre * on the control domain then it can see connexions coming from any 15849bfb42bSAlexandre Chartre * domains. That's why we explicitly have to check if the connexion 15949bfb42bSAlexandre Chartre * is effectively with the control domain. 16049bfb42bSAlexandre Chartre */ 16149bfb42bSAlexandre Chartre if (dhdl == LDMA_CONTROL_DOMAIN_DHDL) { 16249bfb42bSAlexandre Chartre agent->conn_hdl = hdl; 16349bfb42bSAlexandre Chartre agent->conn_ver.major = ver->major; 16449bfb42bSAlexandre Chartre agent->conn_ver.minor = ver->minor; 16549bfb42bSAlexandre Chartre } else { 16649bfb42bSAlexandre Chartre LDMA_INFO("agent %s will ignore any request from distrusted " 16749bfb42bSAlexandre Chartre "domain %s", agent->info->name, dname); 16849bfb42bSAlexandre Chartre } 16949bfb42bSAlexandre Chartre } 17049bfb42bSAlexandre Chartre 17149bfb42bSAlexandre Chartre /* 17249bfb42bSAlexandre Chartre * Agent unregister callback. This callback is invoked when a client is 17349bfb42bSAlexandre Chartre * unregistered and stops using the service provided by an agent. 17449bfb42bSAlexandre Chartre */ 17549bfb42bSAlexandre Chartre static void 17649bfb42bSAlexandre Chartre ldma_unreg_cb(ds_hdl_t hdl, ds_cb_arg_t arg) 17749bfb42bSAlexandre Chartre { 17849bfb42bSAlexandre Chartre ldma_agent_t *agent = (ldma_agent_t *)arg; 17949bfb42bSAlexandre Chartre 18049bfb42bSAlexandre Chartre LDMA_DBG("%s: UNREGISTER hdl=%llx", agent->info->name, hdl); 18149bfb42bSAlexandre Chartre 18249bfb42bSAlexandre Chartre if (agent->conn_hdl == hdl) { 18349bfb42bSAlexandre Chartre agent->conn_hdl = 0; 18449bfb42bSAlexandre Chartre agent->conn_ver.major = 0; 18549bfb42bSAlexandre Chartre agent->conn_ver.minor = 0; 18649bfb42bSAlexandre Chartre } else { 18749bfb42bSAlexandre Chartre LDMA_INFO("agent %s has unregistered consumer from " 18849bfb42bSAlexandre Chartre "distrusted domain", agent->info->name); 18949bfb42bSAlexandre Chartre } 19049bfb42bSAlexandre Chartre } 19149bfb42bSAlexandre Chartre 19249bfb42bSAlexandre Chartre /* 19349bfb42bSAlexandre Chartre * Agent data callback. This callback is invoked when an agent receives a new 19449bfb42bSAlexandre Chartre * message from a client. Any request from a client which is not the control 19549bfb42bSAlexandre Chartre * domain is immediatly rejected. Otherwise the message is forwarded to the 19649bfb42bSAlexandre Chartre * appropriate handler function provided by the agent, depending on the message 19749bfb42bSAlexandre Chartre * type. 19849bfb42bSAlexandre Chartre */ 19949bfb42bSAlexandre Chartre static void 20049bfb42bSAlexandre Chartre ldma_data_cb(ds_hdl_t hdl, ds_cb_arg_t arg, void *buf, size_t len) 20149bfb42bSAlexandre Chartre { 20249bfb42bSAlexandre Chartre ldma_agent_t *agent = (ldma_agent_t *)arg; 20349bfb42bSAlexandre Chartre ldma_msg_handler_t *handler; 20449bfb42bSAlexandre Chartre ldma_message_header_t *request = buf; 20549bfb42bSAlexandre Chartre ldma_message_header_t *reply = NULL; 20649bfb42bSAlexandre Chartre ldma_request_status_t status; 20749bfb42bSAlexandre Chartre size_t request_dlen, reply_len, reply_dlen = 0; 20849bfb42bSAlexandre Chartre int i; 20949bfb42bSAlexandre Chartre 21049bfb42bSAlexandre Chartre /* check the message size */ 21149bfb42bSAlexandre Chartre if (len < LDMA_MESSAGE_HEADER_SIZE) { 21249bfb42bSAlexandre Chartre LDMA_INFO("agent %s has ignored message with an invalid " 21349bfb42bSAlexandre Chartre "size of %d bytes", agent->info->name, len); 21449bfb42bSAlexandre Chartre return; 21549bfb42bSAlexandre Chartre } 21649bfb42bSAlexandre Chartre 21749bfb42bSAlexandre Chartre request_dlen = LDMA_MESSAGE_DLEN(len); 21849bfb42bSAlexandre Chartre 21949bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, request num=%llu type=0x%x info=0x%x " 22049bfb42bSAlexandre Chartre "dlen=%d", agent->info->name, hdl, request->msg_num, 22149bfb42bSAlexandre Chartre request->msg_type, request->msg_info, request_dlen); 22249bfb42bSAlexandre Chartre 22349bfb42bSAlexandre Chartre /* reject any request which is not from the control domain */ 22449bfb42bSAlexandre Chartre if (hdl != agent->conn_hdl) { 22549bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, rejecting request from a " 22649bfb42bSAlexandre Chartre "distrusted domain", agent->info->name, hdl); 22749bfb42bSAlexandre Chartre status = LDMA_REQ_DENIED; 22849bfb42bSAlexandre Chartre goto do_reply; 22949bfb42bSAlexandre Chartre } 23049bfb42bSAlexandre Chartre 23149bfb42bSAlexandre Chartre handler = NULL; 23249bfb42bSAlexandre Chartre 23349bfb42bSAlexandre Chartre for (i = 0; i < agent->info->nhandlers; i++) { 23449bfb42bSAlexandre Chartre if (agent->info->handlers[i].msg_type == request->msg_type) { 23549bfb42bSAlexandre Chartre handler = &agent->info->handlers[i]; 23649bfb42bSAlexandre Chartre break; 23749bfb42bSAlexandre Chartre } 23849bfb42bSAlexandre Chartre } 23949bfb42bSAlexandre Chartre 24049bfb42bSAlexandre Chartre if (handler == NULL) { 24149bfb42bSAlexandre Chartre /* this type of message is not defined by the agent */ 24249bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, unknown message type %x", 24349bfb42bSAlexandre Chartre agent->info->name, hdl, request->msg_type); 24449bfb42bSAlexandre Chartre status = LDMA_REQ_NOTSUP; 24549bfb42bSAlexandre Chartre goto do_reply; 24649bfb42bSAlexandre Chartre } 24749bfb42bSAlexandre Chartre 24849bfb42bSAlexandre Chartre if (handler->msg_handler == NULL) { 24949bfb42bSAlexandre Chartre /* 25049bfb42bSAlexandre Chartre * This type of message is defined by the agent but it 25149bfb42bSAlexandre Chartre * has no handler. That means there is no processing to 25249bfb42bSAlexandre Chartre * do, the message is just ignored, but the request is 25349bfb42bSAlexandre Chartre * successfully completed. 25449bfb42bSAlexandre Chartre */ 25549bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, no handler", 25649bfb42bSAlexandre Chartre agent->info->name, hdl); 25749bfb42bSAlexandre Chartre status = LDMA_REQ_COMPLETED; 25849bfb42bSAlexandre Chartre goto do_reply; 25949bfb42bSAlexandre Chartre } 26049bfb42bSAlexandre Chartre 26149bfb42bSAlexandre Chartre /* invoke the message handler of the agent */ 26249bfb42bSAlexandre Chartre status = (*handler->msg_handler)(&agent->conn_ver, request, 26349bfb42bSAlexandre Chartre request_dlen, &reply, &reply_dlen); 26449bfb42bSAlexandre Chartre 26549bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, handler stat=%d reply=%p rlen=%d", 26649bfb42bSAlexandre Chartre agent->info->name, hdl, status, (void *)reply, reply_dlen); 26749bfb42bSAlexandre Chartre 26849bfb42bSAlexandre Chartre do_reply: 26949bfb42bSAlexandre Chartre /* 27049bfb42bSAlexandre Chartre * If the handler has provided a reply message, we use it directly. 27149bfb42bSAlexandre Chartre * Otherwise, we build a reply depending on the status of the request. 27249bfb42bSAlexandre Chartre * In that case, we re-use the request buffer to build the reply 27349bfb42bSAlexandre Chartre * message. 27449bfb42bSAlexandre Chartre */ 27549bfb42bSAlexandre Chartre if (reply == NULL) { 27649bfb42bSAlexandre Chartre 27749bfb42bSAlexandre Chartre reply = request; 27849bfb42bSAlexandre Chartre reply_dlen = 0; 27949bfb42bSAlexandre Chartre 28049bfb42bSAlexandre Chartre if (status == LDMA_REQ_COMPLETED) { 28149bfb42bSAlexandre Chartre /* 28249bfb42bSAlexandre Chartre * The request was successful but no result message was 28349bfb42bSAlexandre Chartre * provided so we send an empty result message. 28449bfb42bSAlexandre Chartre */ 28549bfb42bSAlexandre Chartre reply->msg_type = LDMA_MSG_RESULT; 28649bfb42bSAlexandre Chartre reply->msg_info = 0; 28749bfb42bSAlexandre Chartre 28849bfb42bSAlexandre Chartre } else { 28949bfb42bSAlexandre Chartre /* 29049bfb42bSAlexandre Chartre * The request has failed but no error message was 29149bfb42bSAlexandre Chartre * provided so we send an error message based on the 29249bfb42bSAlexandre Chartre * request status. 29349bfb42bSAlexandre Chartre */ 29449bfb42bSAlexandre Chartre reply->msg_type = LDMA_MSG_ERROR; 29549bfb42bSAlexandre Chartre reply->msg_info = 29649bfb42bSAlexandre Chartre (status == LDMA_REQ_NOTSUP)? LDMA_MSGERR_NOTSUP : 29749bfb42bSAlexandre Chartre (status == LDMA_REQ_INVALID)? LDMA_MSGERR_INVALID : 29849bfb42bSAlexandre Chartre (status == LDMA_REQ_DENIED)? LDMA_MSGERR_DENY : 29949bfb42bSAlexandre Chartre LDMA_MSGERR_FAIL; 30049bfb42bSAlexandre Chartre } 30149bfb42bSAlexandre Chartre } 30249bfb42bSAlexandre Chartre 30349bfb42bSAlexandre Chartre reply_len = LDMA_MESSAGE_SIZE(reply_dlen); 30449bfb42bSAlexandre Chartre 30549bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, reply num=%llu type=0x%x info=0x%x " 30649bfb42bSAlexandre Chartre "dlen=%d", agent->info->name, hdl, reply->msg_num, 30749bfb42bSAlexandre Chartre reply->msg_type, reply->msg_info, reply_dlen); 30849bfb42bSAlexandre Chartre 30949bfb42bSAlexandre Chartre if (ds_send_msg(hdl, reply, reply_len) != 0) { 31049bfb42bSAlexandre Chartre LDMA_ERR("agent %s has failed to send reply for request %llu", 31149bfb42bSAlexandre Chartre agent->info->name, request->msg_num); 31249bfb42bSAlexandre Chartre } 31349bfb42bSAlexandre Chartre 31449bfb42bSAlexandre Chartre if (reply != request) 31549bfb42bSAlexandre Chartre free(reply); 31649bfb42bSAlexandre Chartre } 31749bfb42bSAlexandre Chartre 31849bfb42bSAlexandre Chartre /* 31949bfb42bSAlexandre Chartre * Register an agent. Return 0 if the agent was successfully registered. 32049bfb42bSAlexandre Chartre */ 32149bfb42bSAlexandre Chartre static int 32249bfb42bSAlexandre Chartre ldma_register(ldma_agent_info_t *agent_info) 32349bfb42bSAlexandre Chartre { 32449bfb42bSAlexandre Chartre ldma_agent_t *agent; 32549bfb42bSAlexandre Chartre ds_capability_t ds_cap; 32649bfb42bSAlexandre Chartre ds_ops_t ds_ops; 32749bfb42bSAlexandre Chartre 32849bfb42bSAlexandre Chartre agent = malloc(sizeof (ldma_agent_t)); 32949bfb42bSAlexandre Chartre if (agent == NULL) 33049bfb42bSAlexandre Chartre goto register_fail; 33149bfb42bSAlexandre Chartre 33249bfb42bSAlexandre Chartre agent->info = agent_info; 33349bfb42bSAlexandre Chartre agent->conn_hdl = 0; 33449bfb42bSAlexandre Chartre agent->conn_ver.major = 0; 33549bfb42bSAlexandre Chartre agent->conn_ver.minor = 0; 33649bfb42bSAlexandre Chartre 33749bfb42bSAlexandre Chartre ds_cap.svc_id = agent_info->name; 33849bfb42bSAlexandre Chartre ds_cap.vers = agent_info->vers; 33949bfb42bSAlexandre Chartre ds_cap.nvers = agent_info->nvers; 34049bfb42bSAlexandre Chartre 34149bfb42bSAlexandre Chartre ds_ops.ds_reg_cb = ldma_reg_cb; 34249bfb42bSAlexandre Chartre ds_ops.ds_unreg_cb = ldma_unreg_cb; 34349bfb42bSAlexandre Chartre ds_ops.ds_data_cb = ldma_data_cb; 34449bfb42bSAlexandre Chartre ds_ops.cb_arg = agent; 34549bfb42bSAlexandre Chartre 34649bfb42bSAlexandre Chartre if (ds_svc_reg(&ds_cap, &ds_ops) == 0) { 34749bfb42bSAlexandre Chartre LDMA_INFO("agent %s registered", agent_info->name); 34849bfb42bSAlexandre Chartre return (0); 34949bfb42bSAlexandre Chartre } 35049bfb42bSAlexandre Chartre 35149bfb42bSAlexandre Chartre register_fail: 35249bfb42bSAlexandre Chartre 35349bfb42bSAlexandre Chartre LDMA_ERR("agent %s has failed to register", agent_info->name); 35449bfb42bSAlexandre Chartre free(agent); 35549bfb42bSAlexandre Chartre return (-1); 35649bfb42bSAlexandre Chartre } 35749bfb42bSAlexandre Chartre 35849bfb42bSAlexandre Chartre /* 35949bfb42bSAlexandre Chartre * Register all known agents. Return the number of agents successfully 36049bfb42bSAlexandre Chartre * registered. 36149bfb42bSAlexandre Chartre */ 36249bfb42bSAlexandre Chartre static int 36349bfb42bSAlexandre Chartre ldma_register_agents() 36449bfb42bSAlexandre Chartre { 36549bfb42bSAlexandre Chartre int count = 0; 36649bfb42bSAlexandre Chartre ldma_agent_info_t **agent_infop; 36749bfb42bSAlexandre Chartre 36849bfb42bSAlexandre Chartre for (agent_infop = ldma_agent_infos; 36949bfb42bSAlexandre Chartre *agent_infop != NULL; agent_infop++) { 37049bfb42bSAlexandre Chartre 37149bfb42bSAlexandre Chartre if (ldma_register(*agent_infop) == 0) 37249bfb42bSAlexandre Chartre count++; 37349bfb42bSAlexandre Chartre } 37449bfb42bSAlexandre Chartre 37549bfb42bSAlexandre Chartre return (count); 37649bfb42bSAlexandre Chartre } 37749bfb42bSAlexandre Chartre 37849bfb42bSAlexandre Chartre /*ARGSUSED*/ 37949bfb42bSAlexandre Chartre static void 38049bfb42bSAlexandre Chartre ldma_sigusr_handler(int sig, siginfo_t *sinfo, void *ucontext) 38149bfb42bSAlexandre Chartre { 3826b8303caSAlexandre Chartre /* 3836b8303caSAlexandre Chartre * The child process can send the signal before the fork() 3846b8303caSAlexandre Chartre * call has returned in the parent process. So daemon_pid 3856b8303caSAlexandre Chartre * may not be set yet, and we don't check the pid in that 3866b8303caSAlexandre Chartre * case. 3876b8303caSAlexandre Chartre */ 3886b8303caSAlexandre Chartre if (sig != SIGUSR1 || sinfo->si_code != SI_USER || 3896b8303caSAlexandre Chartre (daemon_pid > 0 && sinfo->si_pid != daemon_pid)) 39049bfb42bSAlexandre Chartre return; 39149bfb42bSAlexandre Chartre 39249bfb42bSAlexandre Chartre /* 39349bfb42bSAlexandre Chartre * The parent process has received a USR1 signal from the child. 39449bfb42bSAlexandre Chartre * This means that the daemon has correctly started and the parent 39549bfb42bSAlexandre Chartre * can exit. 39649bfb42bSAlexandre Chartre */ 39749bfb42bSAlexandre Chartre exit(0); 39849bfb42bSAlexandre Chartre } 39949bfb42bSAlexandre Chartre 40049bfb42bSAlexandre Chartre static void 40149bfb42bSAlexandre Chartre ldma_start(boolean_t standalone) 40249bfb42bSAlexandre Chartre { 40349bfb42bSAlexandre Chartre int stat, rv; 40449bfb42bSAlexandre Chartre struct sigaction action; 40549bfb42bSAlexandre Chartre 40649bfb42bSAlexandre Chartre if (!standalone) { 40749bfb42bSAlexandre Chartre /* 40849bfb42bSAlexandre Chartre * Some configuration of the daemon has to be done in the 40949bfb42bSAlexandre Chartre * child, but we want the parent to report if the daemon 41049bfb42bSAlexandre Chartre * has successfully started or not. So we setup a signal 41149bfb42bSAlexandre Chartre * handler, and the child will notify the parent using the 41249bfb42bSAlexandre Chartre * USR1 signal if the setup was successful. Otherwise the 41349bfb42bSAlexandre Chartre * child will exit. 41449bfb42bSAlexandre Chartre */ 41549bfb42bSAlexandre Chartre action.sa_sigaction = ldma_sigusr_handler; 41649bfb42bSAlexandre Chartre action.sa_flags = SA_SIGINFO; 41749bfb42bSAlexandre Chartre 41849bfb42bSAlexandre Chartre if (sigemptyset(&action.sa_mask) == -1) { 41949bfb42bSAlexandre Chartre LDMA_ERR("sigemptyset error (%d)", errno); 42049bfb42bSAlexandre Chartre exit(1); 42149bfb42bSAlexandre Chartre } 42249bfb42bSAlexandre Chartre 42349bfb42bSAlexandre Chartre if (sigaction(SIGUSR1, &action, NULL) == -1) { 42449bfb42bSAlexandre Chartre LDMA_ERR("sigaction() error (%d)", errno); 42549bfb42bSAlexandre Chartre exit(1); 42649bfb42bSAlexandre Chartre } 42749bfb42bSAlexandre Chartre 42849bfb42bSAlexandre Chartre if (sigrelse(SIGUSR1) == -1) { 42949bfb42bSAlexandre Chartre LDMA_ERR("sigrelse() error (%d)", errno); 43049bfb42bSAlexandre Chartre exit(1); 43149bfb42bSAlexandre Chartre } 43249bfb42bSAlexandre Chartre 43349bfb42bSAlexandre Chartre if ((daemon_pid = fork()) == -1) { 43449bfb42bSAlexandre Chartre LDMA_ERR("fork() error (%d)", errno); 43549bfb42bSAlexandre Chartre exit(1); 43649bfb42bSAlexandre Chartre } 43749bfb42bSAlexandre Chartre 43849bfb42bSAlexandre Chartre if (daemon_pid != 0) { 43949bfb42bSAlexandre Chartre /* 44049bfb42bSAlexandre Chartre * The parent process waits until the child exits (in 44149bfb42bSAlexandre Chartre * case of an error) or sends a USR1 signal (if the 44249bfb42bSAlexandre Chartre * daemon has correctly started). 44349bfb42bSAlexandre Chartre */ 44449bfb42bSAlexandre Chartre for (;;) { 44549bfb42bSAlexandre Chartre rv = waitpid(daemon_pid, &stat, 0); 44649bfb42bSAlexandre Chartre if ((rv == daemon_pid && WIFEXITED(stat)) || 44749bfb42bSAlexandre Chartre (rv == -1 && errno != EINTR)) { 44849bfb42bSAlexandre Chartre /* child has exited or error */ 44949bfb42bSAlexandre Chartre exit(1); 45049bfb42bSAlexandre Chartre } 45149bfb42bSAlexandre Chartre } 45249bfb42bSAlexandre Chartre } 45349bfb42bSAlexandre Chartre 45449bfb42bSAlexandre Chartre /* 45549bfb42bSAlexandre Chartre * Initialize child process 45649bfb42bSAlexandre Chartre */ 45749bfb42bSAlexandre Chartre if (sighold(SIGUSR1) == -1) { 45849bfb42bSAlexandre Chartre LDMA_ERR("sighold error (%d)", errno); 45949bfb42bSAlexandre Chartre exit(1); 46049bfb42bSAlexandre Chartre } 46149bfb42bSAlexandre Chartre 46249bfb42bSAlexandre Chartre if (sigignore(SIGUSR1) == -1) { 46349bfb42bSAlexandre Chartre LDMA_ERR("sigignore error (%d)", errno); 46449bfb42bSAlexandre Chartre exit(1); 46549bfb42bSAlexandre Chartre } 46649bfb42bSAlexandre Chartre 46749bfb42bSAlexandre Chartre if (setsid() == -1) { 46849bfb42bSAlexandre Chartre LDMA_ERR("setsid error (%d)", errno); 46949bfb42bSAlexandre Chartre exit(1); 47049bfb42bSAlexandre Chartre } 47149bfb42bSAlexandre Chartre 47249bfb42bSAlexandre Chartre if (chdir("/") == -1) { 47349bfb42bSAlexandre Chartre LDMA_ERR("chdir error (%d)", errno); 47449bfb42bSAlexandre Chartre exit(1); 47549bfb42bSAlexandre Chartre } 47649bfb42bSAlexandre Chartre (void) umask(0); 47749bfb42bSAlexandre Chartre 47849bfb42bSAlexandre Chartre /* 47949bfb42bSAlexandre Chartre * Initialize file descriptors. Do not touch stderr 48049bfb42bSAlexandre Chartre * which is initialized by SMF to point to the daemon 48149bfb42bSAlexandre Chartre * specific log file. 48249bfb42bSAlexandre Chartre */ 48349bfb42bSAlexandre Chartre (void) close(STDIN_FILENO); 48449bfb42bSAlexandre Chartre if (open("/dev/null", O_RDWR) == -1) { 48549bfb42bSAlexandre Chartre LDMA_ERR("open /dev/null error (%d)", errno); 48649bfb42bSAlexandre Chartre exit(1); 48749bfb42bSAlexandre Chartre } 48849bfb42bSAlexandre Chartre if (dup2(STDIN_FILENO, STDOUT_FILENO) == -1) { 48949bfb42bSAlexandre Chartre LDMA_ERR("dup2 error (%d)", errno); 49049bfb42bSAlexandre Chartre exit(1); 49149bfb42bSAlexandre Chartre } 49249bfb42bSAlexandre Chartre closefrom(STDERR_FILENO + 1); 49349bfb42bSAlexandre Chartre 49449bfb42bSAlexandre Chartre /* initialize logging */ 49549bfb42bSAlexandre Chartre openlog(cmdname, LOG_CONS | LOG_NDELAY, LOG_DAEMON); 49649bfb42bSAlexandre Chartre 49749bfb42bSAlexandre Chartre ldma_daemon = B_TRUE; 49849bfb42bSAlexandre Chartre } 49949bfb42bSAlexandre Chartre 50049bfb42bSAlexandre Chartre /* 50149bfb42bSAlexandre Chartre * Register the agents. It would be easier to do this before 50249bfb42bSAlexandre Chartre * daemonizing so that any start error is directly reported. But 50349bfb42bSAlexandre Chartre * this can not be done because agents are registered using libds 50449bfb42bSAlexandre Chartre * and this will subscribe the daemon to some sysevents which is 50549bfb42bSAlexandre Chartre * a process based subscription. Instead we notify the parent process 50649bfb42bSAlexandre Chartre * either by exiting, or by sending a SIGUSR1 signal. 50749bfb42bSAlexandre Chartre */ 50849bfb42bSAlexandre Chartre if (ldma_register_agents() == 0) { 50949bfb42bSAlexandre Chartre /* no agent registered */ 5106b8303caSAlexandre Chartre LDMA_ERR("Unable to register any agent"); 51149bfb42bSAlexandre Chartre exit(1); 51249bfb42bSAlexandre Chartre } 51349bfb42bSAlexandre Chartre 51449bfb42bSAlexandre Chartre if (!standalone) { 51549bfb42bSAlexandre Chartre /* signal parent that startup was successful */ 51649bfb42bSAlexandre Chartre if (kill(getppid(), SIGUSR1) == -1) 51749bfb42bSAlexandre Chartre exit(1); 51849bfb42bSAlexandre Chartre } 51949bfb42bSAlexandre Chartre } 52049bfb42bSAlexandre Chartre 52149bfb42bSAlexandre Chartre static void 52249bfb42bSAlexandre Chartre ldma_usage() 52349bfb42bSAlexandre Chartre { 52449bfb42bSAlexandre Chartre (void) fprintf(stderr, "usage: %s\n", cmdname); 52549bfb42bSAlexandre Chartre } 52649bfb42bSAlexandre Chartre 52749bfb42bSAlexandre Chartre int 52849bfb42bSAlexandre Chartre main(int argc, char *argv[]) 52949bfb42bSAlexandre Chartre { 53049bfb42bSAlexandre Chartre int opt; 53149bfb42bSAlexandre Chartre boolean_t standalone = B_FALSE; 53249bfb42bSAlexandre Chartre 53349bfb42bSAlexandre Chartre cmdname = basename(argv[0]); 53449bfb42bSAlexandre Chartre 53549bfb42bSAlexandre Chartre /* disable getopt error messages */ 53649bfb42bSAlexandre Chartre opterr = 0; 53749bfb42bSAlexandre Chartre 53849bfb42bSAlexandre Chartre while ((opt = getopt(argc, argv, "ds")) != EOF) { 53949bfb42bSAlexandre Chartre 54049bfb42bSAlexandre Chartre switch (opt) { 54149bfb42bSAlexandre Chartre case 'd': 54249bfb42bSAlexandre Chartre ldma_debug = B_TRUE; 54349bfb42bSAlexandre Chartre break; 54449bfb42bSAlexandre Chartre case 's': 54549bfb42bSAlexandre Chartre standalone = B_TRUE; 54649bfb42bSAlexandre Chartre break; 54749bfb42bSAlexandre Chartre default: 54849bfb42bSAlexandre Chartre ldma_usage(); 54949bfb42bSAlexandre Chartre exit(1); 55049bfb42bSAlexandre Chartre } 55149bfb42bSAlexandre Chartre } 55249bfb42bSAlexandre Chartre 55349bfb42bSAlexandre Chartre ldma_start(standalone); 55449bfb42bSAlexandre Chartre 55549bfb42bSAlexandre Chartre /* 55649bfb42bSAlexandre Chartre * Loop forever. Any incoming message will be received by libds and 55749bfb42bSAlexandre Chartre * forwarded to the agent data callback (ldma_data_cb()) where it 55849bfb42bSAlexandre Chartre * will be processed. 55949bfb42bSAlexandre Chartre */ 56049bfb42bSAlexandre Chartre for (;;) { 56149bfb42bSAlexandre Chartre (void) pause(); 56249bfb42bSAlexandre Chartre } 56349bfb42bSAlexandre Chartre 56449bfb42bSAlexandre Chartre /*NOTREACHED*/ 56549bfb42bSAlexandre Chartre return (0); 56649bfb42bSAlexandre Chartre } 567