/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <sys/systeminfo.h>
#include <smbios.h>
#include <limits.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <door.h>
#include <fmd_conf.h>
#include <fmd_dispq.h>
#include <fmd_timerq.h>
#include <fmd_subr.h>
#include <fmd_error.h>
#include <fmd_module.h>
#include <fmd_thread.h>
#include <fmd_alloc.h>
#include <fmd_string.h>
#include <fmd_builtin.h>
#include <fmd_ustat.h>
#include <fmd_protocol.h>
#include <fmd_scheme.h>
#include <fmd_asru.h>
#include <fmd_case.h>
#include <fmd_log.h>
#include <fmd_idspace.h>
#include <fmd_rpc.h>
#include <fmd_dr.h>
#include <fmd_topo.h>
#include <fmd_xprt.h>
#include <fmd_ctl.h>
#include <sys/openpromio.h>
#include <libdevinfo.h>
#include <fmd.h>
/*
* Note: the configuration file path is ordered from most common to most host-
* module paths are in the opposite order, from most specific to most common,
* because once a module is loaded fmd will not try to load over the same name.
*/
static const char _fmd_conf_path[] =
static const char _fmd_agent_path[] =
static const char _fmd_plugin_path[] =
static const char _fmd_scheme_path[] =
};
};
};
static int
{
}
static int
{
}
static int
{
if (err == 0)
return (err);
}
static int
{
else
return (fmd_set_errno(EFMD_CONF_INVAL));
return (0);
}
static void
{
}
static int
{
else
return (fmd_set_errno(EFMD_CONF_INVAL));
return (0);
}
static void
{
}
};
};
};
};
};
#ifdef DEBUG
#else
#endif
};
/*
* Statistics maintained by fmd itself on behalf of various global subsystems.
* NOTE: FMD_TYPE_STRING statistics should not be used here. If they are
* required in the future, the FMD_ADM_MODGSTAT service routine must change.
*/
};
/*
* SMBIOS serial numbers can contain characters (particularly ':' and ' ')
* that are invalid for the authority and can break FMRI parsing. We translate
* any invalid characters to a safe '-', as well as trimming any leading or
* trailing whitespace. Similarly, '/' can be found in some product names
* so we translate that to '-'.
*/
void
{
char c;
int i;
begin++;
end--;
return;
for (i = 0; i < MAXNAMELEN - 1; i++) {
break;
c = *cp;
!isprint(c))
buf[i] = '-';
else
buf[i] = c;
cp++;
}
buf[i] = 0;
}
void
{
int i;
char *bufp;
(unsigned char **)&bufp) != -1) {
}
}
if (promh != DI_PROM_HANDLE_NIL)
if (rooth != DI_NODE_NIL)
/*
* A small number of properties must be set manually before we open
* the root configuration file. These include any settings for our
* memory allocator and path expansion token values, because these
* values are needed by the routines in fmd_conf.c itself. After
* the root configuration file is processed, we reset these properties
* based upon the latest values from the configuration file.
*/
"failed to load required configuration properties\n");
}
/*
* Manually specified rootdirs override config files, so only update
* d_rootdir based on the config files we parsed if no 'root' was set.
*/
else
/*
* Once the base conf file properties are loaded, lookup the values
* of $conf_path and $conf_file and merge in any other conf files.
*/
}
/*
* Update the value of fmd.d_fg based on "fg". We cache this property
* because it must be accessed deep within fmd at fmd_verror() time.
* Update any other properties that must be cached for performance.
*/
/*
* Initialize our custom libnvpair allocator and create an nvlist for
* authority elements corresponding to this instance of the daemon.
*/
/*
* The fmd_module_t for the root module must be created manually. Most
* of it remains unused and zero, except for the few things we fill in.
*/
/*
* In addition to inserting the _fmd_stats collection of program-wide
* statistics, we also insert a statistic named after each of our
* errors and update these counts in fmd_verror() (see fmd_subr.c).
*/
}
}
void
{
int core;
fmd_rpc_fini();
/*
* Unload the self-diagnosis module first. This ensures that it does
* not get confused as we start unloading other modules, etc. We must
* hold the dispq lock as a writer while doing so since it uses d_self.
*/
}
/*
* Unload modules in reverse order *except* for the root module, which
* is first in the list. This allows it to keep its thread and trace.
*/
}
}
/*
* Close both log files now that modules are no longer active. We must
* set these pointers to NULL in case any subsequent errors occur.
*/
}
}
/*
* Now destroy the resource cache: each ASRU contains a case reference,
* which may in turn contain a pointer to a referenced owning module.
*/
}
/*
* Now that all data structures that refer to modules are torn down,
* no modules should be remaining on the module list except for d_rmod.
* If we trip one of these assertions, we're missing a rele somewhere.
*/
/*
* Now destroy the root module. We clear its thread key first so any
* calls to fmd_trace() inside of the module code will be ignored.
*/
/*
* Now destroy the remaining global data structures. If 'core' was
* set to true, force a core dump so we can check for memory leaks.
*/
}
if (core)
fmd_panic("forcing core dump at user request\n");
}
/*ARGSUSED*/
static void
{
if (id != 0) {
}
}
/*ARGSUSED*/
static void
{
}
/*
* Events are committed to the errlog after cases are checkpointed. If fmd
* crashes before an event is ever associated with a module, this function will
* be called to replay it to all subscribers. If fmd crashes in between the
* subscriber checkpointing and committing the event in the error log, the
* module will have seen the event and we don't want to replay it. So we look
* for the event in all modules and transition it to the proper state. If
* it is found, we commit it to the error log and do not replay it. The in-
* memory case search used by fmd_module_contains() et al isn't particularly
* efficient, but it is faster than doing read i/o's on every case event to
* check their status or write i/o's on every event to replay to update states.
* We can improve the efficiency of this lookup algorithm later if necessary.
*/
/*ARGSUSED*/
static void
{
break;
}
}
} else {
}
}
void
{
}
/*
* Custom door server create callback. Any fmd services that use doors will
* require those threads to have their fmd-specific TSD initialized, etc.
* Modules should use door_xcreate and derivatives such as
* sysevent_evc_xsubscribe in order to use private doors that
* avoid this global door server function (see fmd_api_module comments).
*/
static void
{
}
/*
* This signal handler is installed for the client.thrsig signal to be used to
* force an auxiliary thread to wake up from a system call and return EINTR in
* response to a module's use of fmd_thr_signal(). We also trace the event.
*/
static void
{
}
void
{
const char *name;
fmd_event_t *e;
int dbout;
/*
* Cache all the current debug property settings in d_fmd_debug,
* d_fmd_dbout, d_hdl_debug, and d_hdl_dbout. If a given debug mask
* is non-zero and the corresponding dbout mask is zero, set dbout
* to a sensible default value based on whether we have daemonized.
*/
else
else
/*
* Initialize remaining major program data structures such as the
* clock, dispatch queues, log files, module hash collections, etc.
* This work is done here rather than in fmd_create() to permit the -o
* command-line option to modify properties after fmd_create() is done.
*/
/*
* The clock must be initialized before fmd_topo_init() because
* fmd_topo_update() calls fmd_time_gethrtime().
*/
(void) door_server_create(fmd_door);
/*
* The root module's mod_queue is created with limit zero, making it
*/
/*
* Once our subsystems that use signals have been set up, install the
* signal handler for the fmd_thr_signal() API. Verify that the signal
* being used for this purpose doesn't conflict with something else.
*/
}
}
/*
* Before loading modules, create an empty control event which will act
* as a global barrier for module event processing. Each module we
* load successfully will insert it at their head of their event queue,
* and then pause inside of fmd_ctl_rele() after dequeuing the event.
* This module barrier is required for two reasons:
*
* (a) During module loading, the restoration of case checkpoints may
* result in a list.* event being recreated for which the intended
* subscriber has not yet loaded depending on the load order. Such
* events could then result in spurious "no subscriber" errors.
*
* (b) During errlog replay, a sequence of errors from a long time ago
* may be replayed, and the module may attempt to install relative
* timers associated with one or more of these events. If errlog
* replay were "racing" with active module threads, an event E1
* that resulted in a relative timer T at time E1 + N nsec could
* fire prior to an event E2 being enqueued, even if the relative
* time ordering was E1 < E2 < E1 + N, causing mis-diagnosis.
*/
fmd_event_hold(e);
/*
* Once all data structures are initialized, we load all of our modules
* in order according to class in order to load up any subscriptions.
* Once built-in modules are loaded, we detach from our waiting parent.
*/
sizeof (code_str)) == 0)
code_str);
sizeof (code_str)) == 0)
code_str);
sizeof (code_str)) == 0)
code_str);
sizeof (code_str)) == 0)
code_str);
}
fmd_rpc_init();
/*
* Now that we're running, if a pipe fd was specified, write an exit
* status to it to indicate that our parent process can safely detach.
* Then proceed to loading the remaining non-built-in modules.
*/
if (pfd >= 0)
/*
* Before loading all modules, repopulate the ASRU cache from its
* persistent repository on disk. Then during module loading, the
* restoration of checkpoint files will reparent any active cases.
*/
/*
* With all modules loaded, replay fault events from the ASRU cache for
* any ASRUs that must be retired, replay error events from the errlog
* that did not finish processing the last time ran, and then release
* the global module barrier by executing a final rele on d_mod_event.
*/
fmd_event_rele(e);
/*
* Now replay list.updated and list.repaired events
*/
/*
* Finally, awaken any threads associated with receiving events from
* open transports and tell them to proceed with fmd_xprt_recv().
*/
fmd_clear_aged_rsrcs(dp, 0, 0);
}
void
{
}