mm.c revision d1d2228c6cf3ec632d28262810ab7902932a5d33
/*
* 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
*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <pthread.h>
#include <pwd.h>
#include <unistd.h>
#include <mms_list.h>
#include <mms_parser.h>
#include <libgen.h>
#include <mms_trace.h>
#include <mms_strapp.h>
#include <netdb.h>
#include <mms_cores.h>
#include <time.h>
#include <libscf.h>
#include "mm_db.h"
#include "mm.h"
#include "mm_util.h"
#include "mm_commands.h"
#include "mm_sql.h"
#include "mm_sql_impl.h"
#include "mm_task.h"
#include "mm_path.h"
#include "mm_db_version.h"
#include "mms_sock.h"
#include "mms_cfg.h"
/*
* MM data
*/
int mm_exiting = 0;
int mm_refresh = 0;
/*
* mm_signal_handler
*
* Parameters:
* -int signo
*
* This is the routine used to handle various signals
*
* Return Values:
* None
*
*/
static void
mm_signal_handler(int signo)
{
switch (signo) {
case SIGINT:
mm_exiting = 1;
break;
case SIGTERM:
mm_exiting = 1;
break;
case SIGHUP:
mm_refresh = 1;
break;
case SIGPIPE:
break;
}
}
/*
* mm_init_mm
*
* Parameters:
* - mm_data : Pointer to mm_data_t structure
*
* This function initialzes the various elements of mm_data
*
* Return Values:
* None
*
*/
void
{
/* list mutex */
/* worker */
/* Task Manager */
/* Notify */
}
/*
* mm_init_attribute_info
*
* Parameters:
* - mm_data: Pointer to mm_data_t structure
*
* This function intializes the attr_info struct
*
* Return Values:
* 0 for success
*
*/
int
/* Restricted Status OBJECTS */
/* modifiable by 'system' */
/* MM_NUM_STATUS_OBJS */
/* Restricted Status Attributes */
/* modifiable by 'system' */
/* MM_NUM_STATUS_ATTS */
strdup("DRIVE.DriveNumberMountsSinceCleaning");
strdup("CARTRIDGE.CartridgeTimeMountedLast");
strdup("CARTRIDGE.CartridgeTimeMountedTotal");
strdup("PARTITION.PartitionTimeMountedTotal");
strdup("PARTITION.PartitionTimeMountedLast");
strdup("CARTRIDGE.CartridgeWriteProtected");
/* Restricted Control Attributes */
/* modifiable by 'administrator' */
/* MM_NUM_CONTROL_ATTS */
strdup("DRIVEGROUPAPPLICATION.DriveGroupApplicationUnloadTime");
strdup("CARTRIDGEGROUP.CartridgeGroupPriority");
strdup("CARTRIDGEGROUPAPPLICATION.CartridgeGroupApplicationPriority");
return (0);
}
/*
* mm_signal
*
* Parameters:
* - sig : signal
* - handler : function to handle sig
*
* Sets up a handler function for a given signal
*
* Return Values:
* None:
*
*/
static void
{
/*
* Setup to catch signals
*/
/*
* Allow alarm signal to interrupt
*/
}
}
}
/*
* mm_initialize
*
* Parameters:
* - mm_data : pointer to mm_data_t
*
* Initialzes structures, creates threads and starts db connections
*
* Return Values:
* None
*
*/
static void
{
char ebuf[MMS_EBUF_LEN];
int i;
int fd_limit;
char *corename;
/*
* Initialize
*/
/*
* Start tracing
*/
/*
* Decome a daemon
*/
if (daemon_mode) {
/*
* Parent process
*/
} else {
/* Successfully forked, parent exits */
exit(0);
}
}
}
/*
*/
setsid();
chdir("/");
umask(0);
}
/* Check to see how many core files exist */
"%s:%d core management %s", MMS_HERE,
}
/*
* Close unused file descriptors
*/
for (i = 0; i < OPEN_MAX; i++) {
close(i);
}
/* Initialize mm */
mm_data->mm_work_todo = 0;
/*
* Start tracing
*/
}
(void) mms_trace_filter(mm_read_trace_level());
/* Use devp as default if debug build */
#ifdef MMSDEBUG
(void) mms_trace_filter(MMS_SEV_DEVP);
#endif
/*
* Read config
*/
}
/*
* Load mms data model object pathing
*/
if (mm_init_paths(MM_PATHS_FN)) {
}
if (mm_init_attribute_info(mm_data)) {
}
/*
* Start and initialize database server
*/
}
/*
* Database
*/
}
/* get system settings from database */
}
"\"SystemName\" = '%s',\"SystemInstance\" = '%s';",
}
/* cleanup database */
"VACUUM VERBOSE ANALYZE;") != MM_DB_OK) {
}
"REINDEX DATABASE %s;",
}
}
/*
* Set MMS password
*/
"update \"MMPASSWORD\" set \"Password\" = '%s' "
"where \"ApplicationName\" = '%s';",
}
/*
* Setup open file descriptor limit
*/
if (mm_set_fd_limit(fd_limit)) {
}
}
#ifdef MMS_OPENSSL
}
#endif /* MMS_OPENSSL */
/*
* Ready for mm clients to connect
*/
}
/*
* mm_char_list_destroy
*
* Parameters:
* - list: pointer to mm_list_t
*
* Free's memory for an entire mm_list_t
* caller must do a list_destroy
*
* Return Values:
* None
*
*/
void
char_list = next_char_list) {
}
}
/*
* mm_free_cmi_drive
*
* Parameters:
* - drive: pointer to a cmd_dirve_list_t list
*
* free memory for an entire cmi_drive_list_t
* caller must do a list_destroy
*
* Return Values:
* None
*
*/
void
/* Drive */
if (drive->cmi_drive_name)
if (drive->cmi_dm_name)
if (drive->cmi_loaded_pcl)
}
/*
* mm_free_cmi_cart
*
* Parameters:
* - cart :
*
* Free memory for a single cmi_cart_list_t
*
* Return Values:
* None
*
*/
void
/* Cartridge */
if (cart->cmi_library)
if (cart->cmi_side_name)
if (cart->cmi_cart_pcl)
if (cart->cmi_cart_type)
if (cart->cmi_bit_format)
drive = next_drive) {
drive);
drive);
}
}
/*
* mm_free_cmi_cart_list
*
* Parameters:
* - cart_list : mms_list_t of cmi_cart_list_t
*
* Free memory for an entire list of cmi_cart_list_t
* caller must do a list_destroy
*
* Return Values:
* None
*
*/
void
/* This function frees the cart list, */
/* but does not destroy it */
cart);
cart);
}
}
/*
* mm_remove_from_depend
*
* Parameters:
* - cmd : cmd to remove from other commands depend list
*
* This function will remove cmd from the dependent command lists
* of all other commands. This should be called for every command
* when the command is being destroyed
*
* if not removed from all other commands, then next list
* access of the depend list containning this cmd will hit list_head
* assert since the memory has already been free'd
*
* Return Values:
* None
*
*/
void
/* this is the command to remove */
continue;
}
depend_list != NULL;
if (depend_list == cmd) {
}
}
}
}
/*
* mm_destroy_cmd
*
* Parameters:
* - cmd : pointer to a command
*
* Does all cleanup necessary for the command
* and free's all memory associated with this command
* This includes reseting any data base states used
* by the command
*
* Return Values:
* 0 for success
*
*/
int
{
/* begin end command list */
}
"mm_destroy_cmd, %s (%p)",
cmd);
"delete from \"TASK\" where " \
"\"TaskID\" = '%s';",
}
"delete from \"REQUEST\" where "
"\"RequestingTaskID\" = '%s' and "
"\"RequestState\" != 'responded';",
}
(void) mm_add_clear_drive(cmd->
}
}
"delete from \"TASK\" where " \
"\"TaskID\" = '%s';",
}
"delete from \"REQUEST\" where "
"\"RequestingTaskID\" = '%s' and "
"\"RequestState\" != 'responded';",
}
(void) mm_add_clear_drive(cmd->
}
}
}
/* Free a begin end list */
next_cmd =
cur_cmd);
(void) mm_destroy_cmd(cur_cmd);
}
}
/* clean depend_list */
"remove this cmd from all other cmd depend lists");
next_cmd =
cur_cmd);
cur_cmd);
}
cart);
cart);
}
for (mode =
mode);
mode);
}
}
if (cmd->cmd_response) {
}
if (cmd->cmd_textcmd)
if (cmd->cmd_report)
/* Free mount_info */
if (mount_info->cmi_dm)
if (mount_info->cmi_drive)
if (mount_info->cmi_library)
if (mount_info->cmi_cartridge)
if (mount_info->cmi_pcl)
if (mount_info->cmi_side_name)
if (mount_info->cmi_where)
if (mount_info->cmi_filename)
if (mount_info->cmi_blocksize)
if (mount_info->cmi_filesequence)
if (mount_info->cmi_volumeid)
if (mount_info->cmi_capability)
if (mount_info->cmi_retention)
if (mount_info->cmi_handle)
if (mount_info->cmi_user)
/* Un mount */
if (mount_info->cui_signature_type)
if (mount_info->cui_signature)
if (mount_info->cmi_first_lib)
if (mount_info->cmi_first_drive)
if (mount_info->cmi_second_lib)
if (mount_info->cmi_second_drive)
if (cmd->cmd_eclass)
/* Eject cartridge */
eject_cart != NULL;
}
}
/* Path Matching */
if (cmd->cmd_has_list) {
}
/* Message */
}
return (0);
}
/*
* mm_destroy_wka
*
* Parameters:
* - wka : pointer to a mm_wka_t
*
* Free's all memory associated with this client workarea
*
* Return Values:
* None
*
*/
void
if (wka->mm_wka_conn)
}
/*
* mm_return_unload
*
* Parameters:
* - library : ptr to string of library name
* - drive : ptr to string of drive name
* - mm_data : pointer to mm_data_t
*
* For a given library and drive, search the command
* queue and return a pointer to the delay unload
* command for his library and drive
*
* Return Values:
* mm_command_t* : if the function finds a
* delay unload for this library
* and drive, it will return
* a ptr to that command
* NULL: If no unload is found
* the function will return NULL
*
*/
break;
}
}
}
return (unload_cmd);
}
/*
* mm_set_depend_response
*
* Parameters:
* - cmd : ptr to mm_command_t
*
* Copy the response to for this command to each command
* dependent on this command (in this cmd's depend list)
*
* Return Values:
* 1 : if responses were copied
* 0 : if no responses were copied
*
*/
int
int set_one = 0;
if (mm_has_depend(cmd) == 0) {
return (0);
}
/* Generate text cmd from cmd response */
"error getting response text");
return (0);
}
set_one = 1;
"%s has parent, %s",
cmd_name);
if (cur_depend->
cmd_response != NULL)
/* Rebuild parnode */
switch (cmd->cmd_language) {
case MM_LANG_MMP:
break;
case MM_LANG_DMP:
break;
case MM_LANG_LMP:
break;
}
}
return (set_one);
}
/*
* mm_set_depend_error
*
* Parameters:
* - cmd : ptr to mm_command_t
*
* Copy the error response to for this command to each command
* dependent on this command (in this cmd's depend list)
* Set error flags for each dependent command
*
* Return Values:
* 1 : if responses were copied
* 0 : if no responses were copied
*
*/
int
int set_one = 0;
/* this cmd had an error, */
/* set error buf for every command */
/* depending on this one */
/*
* Command has a parent
* Set error flags,
* and dispatch
* parent command func can
* handle the error
* Save the child's error
* response for the parent
*/
if (mm_has_depend(cmd) == 0) {
return (0);
}
/* Generate text cmd from cmd response */
"error getting response text");
return (0);
}
set_one = 1;
"%s has parent, %s",
cmd_name);
if (cur_depend->
cmd_response != NULL)
/* Rebuild parnode */
switch (cmd->cmd_language) {
case MM_LANG_MMP:
break;
case MM_LANG_DMP:
break;
case MM_LANG_LMP:
break;
}
cur_depend->cmd_flags |=
cur_depend->cmd_flags |=
}
return (set_one);
}
/*
* mm_dispatch_all_depend
*
* Parameters:
* - cmd : ptr to mm_command_t
*
* Set every command dependent on this command
* ready for dispatch
*
* Return Values:
* None
*
*/
void
/* set every depend for this cmd for dispatch */
cur_depend->cmd_flags |=
}
}
/*
* mm_remove_this_depend
*
* Parameters:
* - cmd : ptr to mm_command_t
* - remove : ptr to mm_command_t
*
* Removes the command 'remove' from the depend list in 'cmd'
*
* Return Values:
* none
*
*/
void
/* remove remove from cmd's depend list */
depend_list != NULL;
if (depend_list == remove) {
}
}
}
/*
* mm_remove_all_depend
*
* Parameters:
* - cmd : ptr to mm_command_t
*
* Removes all depedent commands from cmd's depend list
*
* Return Values:
* None
*
*/
void
/* remove and free all */
depend_list != NULL;
}
}
/*
* mm_is_parent
*
* Parameters:
* - parent : ptr to mm_command_t
* - child : ptr to mm_command_t
*
* Determines if parent is in the depend list of child
*
* Return Values:
* 1 : if parent is in the depend list
* of child
* 0 : if parent is not in the depend list
* of child
*
*/
int
/* is parent, the parent of child? */
if (cur_depend == parent) {
return (1);
}
}
return (0);
}
/*
* mm_first_parent
*
* Parameters:
* - child : ptr to mm_command_t
*
* Returns the first command dependent on child
*
* Return Values:
* mm_command_t* : returns a pointer to the
* first parent of child
* NULL : returns NULL if there are
* no parents of child
*
*/
return (cur_depend);
}
/*
* mm_top_parent
*
* Parameters:
* - child : ptr to mm_command_t
*
* Finds the 1st command to set child as a dependent
*
* Return Values:
* mm_command_t* : ptr to the 1st parent of child
* NULL : return NULL if child had no
* commands in its depend list
*/
/* return parent of this child */
if (mm_has_depend(child) == 0) {
/* No parent */
return (NULL);
}
if (cur_depend == NULL) {
return (NULL);
}
if (mm_has_depend(cur_depend) == 0) {
return (cur_depend);
}
return (mm_top_parent(cur_depend));
}
/*
* mm_has_depend
*
* Parameters:
* - cmd : ptr to mm_command_t
*
* Determine if cmd has any commands in its depend list
*
* Return Values:
* 0 : for no commands in its depend list
* 1 : for any command in its depend list
*
*/
int
/* does this command have a depend in the list */
return (1);
}
return (0);
}
/*
* mm_add_depend
*
* Parameters:
* - child : ptr to mm_command_t
* - parent : ptr to mm_command_t
*
* Adds command pointed to by parent to the depend list
* of command pointed to by child
*
* Return Values:
* None
*
*/
void
/* this function adds parent to the child */
/* allows multiple parents per child */
"mm_add_depend");
"passed a NULL parent");
return;
}
"%p is already a parent of %p",
return;
}
"added %p as parent of %p",
child);
return;
}
/*
* mm_set_unload_dispatch
*
* Parameters:
* - unmnt_cmd : ptr to mm_command_t
* - parent : ptr to mm_command_t
*
* set the command pointed to by unmnt_cmd ready for dispatch
* if parent is pointing to a command, add that command to
* unmnt_cmd's depend list
*
* Return Values:
* None
*
*/
void
/* This sets the unmnt_cmd for dispatch */
/* if parent != NULL */
/* it will be added to this commands parents */
/* this delay unload is */
/* already running */
"this delay unmout is "
"already running");
} else {
}
/* Need to set cmd */
/* as part of cur_cmd */
/* depend list */
}
/*
* mm_dispatch_unload
*
* Parameters:
* - library : ptr to library name string
* - drive : ptr to drive name string
* - cmd : ptr to mm_command_t
* - mm_data : ptr to mm_data_t
*
* Find's the unload command the give library and drive
* and sets that ready for dispatch
* then add cmd to that unload command's depend list
*
* Return Values:
* mm_command_t : if an unload is found for library
* and drive, a ptr to that command
* is returned
* NULL : if an unload for library and drive
* cannot be found, NULL is returned
*
*/
/* searches the cmd_queue for a delay unmount cmd function */
/* if the library and drive match, the cmd is set for dispatch */
/* if cmd != NULL, then cmd will be set */
/* as parent of the delay unmount */
"dispatch delay unmount, %s %s",
drive);
}
}
}
return (unmnt_cmd);
/* We did not find a delay unload */
/* Search the list for a clear drive function */
/* This cmd may be following an error recovery situation */
/* where the delay was not correctly added */
/* search for a clear drive instead */
/* do not dispatch the clear drive */
continue;
}
"found clear drive for, %s %s",
drive);
}
}
}
return (unmnt_cmd);
}
/*
* mm_remove_unload
*
* Parameters:
* - library : ptr to library name string
* - drive : ptr to drive name string
* - mm_data : ptr to mm_data_t
*
* Find the unload command for the given library and drive,
* then set that unload command for removal
*
* Return Values:
* 1 : return 1 if a command was set for removal
* 0 : return 0 if a command was not set for removal
*
*/
int
/* searches the cmd_queue for a delay unmount cmd function */
/* if the library and drive match, the cmd is set for removal */
int removed_one = 0;
"remove delay unmount, %s %s",
drive);
removed_one = 1;
}
}
}
return (removed_one);
}
/*
* mm_remove_commands
*
* Parameters:
* - mm_data : ptr to mm_data_t
* - db_main : ptr to valid db connection, mm_db_t
* - mm_wka : ptr to cli work area, mm_wka_t
*
* For the client workarea mm_wka points to, remove
* and clean up all commands associated with it.
* this may require updating states in the db
*
* Return Values:
* 0 : for success
* 1 : for errors
*
*/
int
/* Set outstanding commands for remove */
/*
* If this command is a mount command,
* set flag for clearing the drive
*/
}
/* This is not a command from this wka */
continue;
}
/* This IS a command from this client's wka */
"set for remove, %s",
"client has an outstanding "
"mount command");
"Mark a mount_cmd for "
"clear and reset states");
/* Call mm_rm_mount */
/* to clear resources */
/* and reset manager states */
cmi_reset_states = 1;
(void) mm_rm_mount(cur_cmd);
cmi_need_clear = 1;
/* Could optimize this clear */
/* ie dont physical clear unless necessary */
(void) mm_add_clear_drive(cur_cmd->
}
/* TODO fix manager states, */
/* clear resources */
"client has an outstanding "
"unmount command");
(void) mm_rm_unmount(cur_cmd);
cmi_need_clear = 1;
cmi_reset_states = 1;
if (cur_cmd->
(void) mm_add_clear_drive(cur_cmd->
}
}
/*
* If this command is a depend,
* mark its parent
*/
if (mm_has_depend(cur_cmd)) {
"this command has depend's in list "
"mark each with MMS_ERROR and do not dispatch");
cur_depend) {
}
/* Clear depend list so that the parents may be */
/* used by other commands */
}
/*
* If this command is a parent,
* Mark its children
*/
child) {
/* not a parent of this child */
continue;
}
strdup("**UNKNOWN CMD**");
}
" %s is child "
"of %s, set cmd "
"for remove",
/* TODO */
/*
* What to do with outstanding
* commands?
*
* Cancel child commands in a mount
* Ensure that states are correct
* and drives are clear
*
* TEMP
* Remove all dependent commands
* If lmp munt is a child
* Allow it to complete, then
* clear the drive
*/
"lmp mount") == 0) {
"mount for clear_drive");
/* Need clear for lmp mount */
cmi_need_clear = 1;
"delay unmount") == 0) {
"do not remove "
"this delay unmount");
} else {
}
}
}
return (0);
}
/*
* mm_remove_mmp_client
*
* Parameters:
* - mm_wka : ptr to cli work area, mm_wka_t
* - db_main : ptr to valid db connection, mm_db_t
*
* Does clean up for an MMP client, reset any states that need
* to be reset. If the client has a tape mounted, add commands
* to free that resource
*
* Return Values:
* 0 : for successful cleanup
* 1 : for errors
*
*/
int
char *drive_name = NULL;
char *cartridge_pcl = NULL;
char *library_name = NULL;
int physical = 0;
int i = 0;
int num_mounts = 0;
/* Do any MMP specific tasks here */
/* If this is a MMP client, check the MOUNTPHYSICAL */
/* schedule a clear drive */
"select distinct "
"\"MOUNTPHYSICAL\".\"DriveName\","
"\"MOUNTPHYSICAL\".\"CartridgePCL\", "
"\"MOUNTPHYSICAL\".\"LibraryName\" "
"from \"MOUNTPHYSICAL\""
"where"
"("
"\"MOUNTPHYSICAL\".\"SessionID\" = '%s');",
!= MM_DB_DATA) {
return (1);
}
"client has %d tapes mounted",
for (i = 0; i < num_mounts; i++) {
i, 0);
i, 1);
i, 2);
"%s %s has tape mounted, %s %s %s, clear drive",
/* Reset resources */
/* Set States For a Clear Drive */
"update \"DRIVE\" set "
"\"DriveStateSoft\" = 'ready' "
"where \"DriveName\" = '%s';",
"update \"CARTRIDGE\" set "
"\"CartridgeStatus\" = 'available' "
"where \"CartridgePCL\" = "
"'%s' and \"LibraryName\" = '%s';",
/* If this client does not have an outstanding */
/* physical unmount, add a non-physical clear */
/* wka is the same, cmd is unmount */
/* unmount is physical, and drive are the same */
drive_name) == 0)) {
physical = 1;
}
}
if (physical) {
"adding a physical force unmount");
(void) mm_add_clear_drive(drive_name,
NULL,
cartridge_pcl, 1, 0);
} else {
"adding a non-physical unmount ");
(void) mm_add_clear_drive(drive_name,
NULL,
cartridge_pcl, 0, 1);
}
}
return (0);
}
/*
* mm_remove_dmp_client
*
* Parameters:
* - mm_wka : ptr to cli work area, mm_wka_t
* - db_main : ptr to valid db connection, mm_db_t
*
* Does clean up for an DMP client, reset any states that need
* to be reset. Copy any existing handle information for this DM
* from MOUNTLOGICAL to STALEHANDLE
*
* If this DM recieved an unwelcome response, return without altering
* any state information
*
* Return Values:
* None
*
*/
void
int rows;
int rc;
/* try to add dmdown event */
/* copy mountlogical to stalehandle */
/* delete the config for this dm */
if (mm_wka->wka_unwelcome) {
"mm_remove_dmp_client: "
"DM was unwelcome, skip clean up");
return;
}
(void) mm_notify_add_dmdown_dc(mm_wka,
db_main);
/* Move MOUNTLOGICAL to STALEHANDLE */
"select \"ApplicationName\", " \
"\"VolumeName\", \"PartitionName\", "\
"\"SideName\", \"CartridgeID\", "\
"\"DriveName\", \"DMName\", "\
"\"MountLogicalHandle\" "\
"from\"MOUNTLOGICAL\" " \
"where \"DMName\" = '%s';",
if (rc != MM_DB_DATA) {
/* error */
"MOUNTLOGICAL handles");
(void) mm_db_txn_rollback(db_main);
return;
}
for (int i = 0; i < rows; i ++) {
/* Move 1 MOUNTLOGICAL to STALEHANDLE */
"insert into \"STALEHANDLE\" "\
"(\"ApplicationName\", "\
"\"VolumeName\", " \
"\"PartitionName\", "\
"\"SideName\", "\
"\"CartridgeID\", " \
"\"DriveName\", \"DMName\", "\
"\"MountLogicalHandle\") "\
"values " \
"('%s', '%s', '%s', '%s', "\
"'%s', '%s', '%s', '%s');",
PQgetvalue(mount_logical, i, 0),
i, 7)) != MM_DB_OK) {
"MOUNTLOGICAL to STALEHANDLE");
}
}
"delete from \"MOUNTLOGICAL\" where "\
"\"DMName\" = '%s';",
MM_DB_OK) {
"MOUNTLOGICAL");
}
"update \"DM\" set "\
"\"DMStateSoft\" = " \
"'absent' where \"DMName\" = '%s';",
MM_DB_OK) {
"Error updating "\
"DMStateSoft");
}
}
/*
* mm_remove_dmp_client
*
* Parameters:
* - mm_wka : ptr to cli work area, mm_wka_t
* - db_main : ptr to valid db connection, mm_db_t
*
* Does clean up for an LMP client, reset any states that need
* to be reset.
*
* If this LM recieved an unwelcome response, return without altering
* any state information
*
* Return Values:
* None
*
*/
void
/* Try to add an lmdown event */
/* Set LMStateSoft == 'absent' */
if (mm_wka->wka_unwelcome) {
"mm_remove_lmp_client: "
"LM was unwelcome, skip clean up");
return;
}
(void) mm_notify_add_lmdown_dc(mm_wka,
db_main);
"\"LMStateSoft\" = 'absent' WHERE \"LibraryName\" = '%s' "
"Error removing LIBRARY LM");
}
}
/*
* mm_remove_connection
*
* Parameters:
* - mm_wka : ptr to cli work area, mm_wka_t
* - db_main : ptr to valid db connection, mm_db_t
*
* Do general clean up for all connections (MMP, DMP, LMP)
* Cancel any notficitaions for the client, reset connection
* object states
*
* Return Values:
* None
*
*/
void
(void) mm_db_txn_begin(db_main);
}
!= MM_DB_OK) {
}
/* Get all NotifyId's and drop the rules */
"select \"NotifyID\",\"NotifyObject\""
" from \"NOTIFYRULES\" where "
"\"ConnectionID\" = '%s';",
PQgetvalue(results, i, 0));
"mm_remove_connection: "
"db error setting savepoint");
}
"drop rule \"%s\" on \"%s\";",
PQgetvalue(results, i, 0),
MM_DB_OK) {
"mm_remove_connection: "
"db error rollingback savepoint");
}
}
"mm_remove_connection: "
"db error releasing savepoint");
}
}
} else {
"error reading notify id from table");
}
!= MM_DB_OK) {
}
!= MM_DB_OK) {
}
!= MM_DB_OK) {
}
(void) mm_db_txn_commit(db_main);
}
/*
* mm_remove_clients
*
* Parameters:
* - mm_data : ptr to mm_data_t
* - db : ptr to valid db connection, mm_db_t
*
* Check all client work areas in the work area list for
* connections that need removal. For each client that needs
* to be removed, call the approperate clean up functions
*
* This function should cause the reset of the
* approperate db states and free memory assocated with
* the disconnected clients
*
* Return Values:
* 0 : return 0 for success
* 1 : return 1 for errors
*
*/
static int
{
int go = 1;
int remove;
"mm_remove_clients");
/*
* Find bad file descriptors
*
* Also need to remove all commands from
* queue that are asscociated with
* the bad FD
*/
/* mms_trace(MMS_INFO, "Inside remove clients"); */
/* Service Not Valid */
return (1);
}
while (go) {
remove = 0;
/* mms_trace(MMS_INFO," Checking a wka"); */
if (mm_wka->wka_remove) {
remove = 1;
break;
}
/* Not Valid */
"bad FD -> %d",
remove = 1;
break;
}
}
if (remove) {
/* Destroy the wka */
/* Remove commands associated with this wka */
}
/* Clean up for MMP client */
}
/* Clean up for DMP client */
}
/* Clean up for LMP client */
}
/* Clean up connections */
/* free(mm_wka); */
} else {
go = 0;
}
}
return (0);
}
/*
* mm_add_wka
*
* Parameters:
* - mm_data : ptr to mm_data_t
* - conn : ptr to MMS connection struct, mms_t
*
* Allocate and intialize a new client work area (mm_wka_t)
* using the connection information in conn
*
* Return Values:
* 0 : for success
* 1 : for errors
*
*/
int
{
"Unable to malloc mm_wka_t fd %d: %s",
return (1);
}
/*
* Allocate empty connection strings for
* access before a client says hello.
*/
return (1);
}
mm_wka->wka_remove = 0;
mm_wka->wka_need_accept = 0;
mm_wka->wka_goodbye = 0;
mm_wka->wka_unwelcome = 0;
return (0);
}
/*
* mm_response_cmd_func
*
* Parameters:
* - mm_wka : ptr to cli work area, mm_wka_t
* - rsp_cmd : ptr to mm_command_t
*
* command function for all responses, this function will
* find the command matching this response and set the response
* values for that command. it will also set the approperate
* flags for the command based on the type of response
* (error, accept, success)
*
* Return Values:
* One of the Dispatcher return codes, see mm.h
* (MM_CMD_DONE, MM_NO_DISPATCH etc...)
*
*/
int
{
/*
* A response has been recieved,
* Find the the matching command in the queue,
*
* check:
* mm_wka->cci_uuid matches rsp_uuid (same connection)
* command's task is the same
*
* Set the command's flag to dispatchable
* Save parsed response in cmd_response
* return MM_CMD_DONE
*/
char *rsp_task;
char *task;
int skip = 0;
} else {
"No task clause in response");
return (MM_CMD_ERROR);
}
"set for a cmd, continue");
continue;
}
skip = 0;
"response") == 0) {
skip = 1;
}
}
/* From the same connection */
}
/* Same Task */
if (!skip)
break;
}
}
}
}
if (cur_cmd) {
(void) mm_message_command(rsp_cmd);
"accepted",
MMS_PN_KEYWORD, NULL)) {
}
return (MM_DISPATCH_AGAIN);
} else {
return (MM_NO_DISPATCH);
}
}
cur_cmd);
} else {
"set NULL root for dispatch, %p",
cur_cmd);
}
return (MM_DISPATCH_AGAIN);
}
}
return (MM_CMD_ERROR);
}
/*
* mm_handle_parser_error
*
* Parameters:
* - err_list : error list for this error, ptf to mms_list_t
*
* Attempt to parse the partial parse tree and determine what the cmd is
* If it can be determined that the command is a hello return unwelcome,
* if the command is a response or unknown, don't send a response
*
* Return Values:
* MM_PAR_ERROR : if cmd is unknown
* MM_PAR_SEND_UNWEL : if cmd is hello command
* MM_PAR_IS_RESP : if command is a response
* MM_PAR_NO_MEM : parser is out of memory
* MM_PAR_SEND_UNACC : if cmd requres an unaccep response
*
*/
int
int syntax = 0; /* Number of syntax errors in cmd */
/* Need unaccept list */
int num_unaccept = 34;
char *unaccept[34];
int ret_val;
case MMS_PE_NOMEM:
"Parser error detected no memory "
"available");
goto end;
case MMS_PE_SYNTAX:
syntax++;
break;
case MMS_PE_MAX_LEVEL:
"Parser error detected max level "
"reached");
goto end;
default:
"Invalid parser err encountered - %d",
/* XXX DO MMS_ERROR RECOVERY IN THIS. SNO */
/* SINCE ONLY 3 MMS_ERROR CONDITIONS EXIST */
goto end;
}
"mm_handle_parser_error: error mms_mmp_parse, \n"
" line %d, col %d, near token \"%s\", "
"err code %d, %s",
}
if (!syntax) {
"mm_handle_parser_error: Parse error was not "
"a valid error condition for MM, Unable to process "
"error");
goto end;
}
"mm_handle_parser_error: Parse error was syntax error. "
"Num of errors - %d", syntax);
"complete mess, no cmd found");
/* NEED TO HANDLE MMS_ERROR CASE, UNABLE DETERMINE IF MESSAGE */
/* WAS A CMD, CMD RESPONSE, CMD ACCEPT, NOT ABLE TO DETERMINE */
/* WHAT TYPE OF RESPONSE SHOULD BE SENT IF ONE SHOULD BE XXX */
goto end;
}
/* The command has a syntax error, but root != NULL */
/* Check root, send unaccept for valid commands, */
/* send unwelcome for hello, skip resoponses and */
/* unrecognized commands */
for (int i = 0; i < num_unaccept; i ++) {
unaccept[i]) == 0) {
" send unaccept", unaccept[i]);
goto end;
}
}
" send unwelcome");
/* send an unwelcome for hello */
goto end;
"response") == 0) {
/* Don't send an unacceptable for response */
"Don't send unacceptable");
goto end;
}
/* shouldn't ever get here */
end:
for (int i = 0; i < num_unaccept; i ++) {
if (unaccept[i])
}
return (ret_val);
}
/*
* mm_setup_cmd
*
* Parameters:
* - cmd : ptr to mm_command_t
* - buf : pointer to char string of cmd text
*
* Parses the string in buf and sets up the mm_command_t struct
* Sets the cmd_function pointer for the command
* if there is problem parsing the command, send the approperate
* response to the client (unwelcome or unacceptable)
*
* Return Values:
* 0 : for errors
* 1 : for success
* 2 : for success and cmd was a part of a begin-end group
*
*/
int
{
int rc;
int send_acc = 1;
int parse_error = 0;
/* Parse error */
int send_unwelcome = 0;
int send_unacceptable = 0;
int is_response = 0;
int p_err_rc;
/* Begin-end */
switch (cmd->cmd_language) {
case MM_LANG_MMP:
if (rc) {
if (p_err_rc == MM_PAR_SEND_UNACC) {
send_unacceptable = 1;
}
if (p_err_rc == MM_PAR_SEND_UNWEL) {
send_unwelcome = 1;
}
if (p_err_rc == MM_PAR_IS_RESP) {
is_response = 1;
}
parse_error = 1;
break;
}
send_acc = 0;
"response") == 0) {
send_acc = 0;
"mount") == 0) {
"create") == 0) {
"goodbye") == 0) {
"delete") == 0) {
"show") == 0) {
"attribute") == 0) {
"locale") == 0) {
"privilege") == 0) {
"begin") == 0) {
"unmount") == 0) {
"end") == 0) {
"allocate") == 0) {
"deallocate") == 0) {
"rename") == 0) {
"shutdown") == 0) {
"cpscan") == 0) {
"cpreset") == 0) {
"cpexit") == 0) {
"cpstart") == 0) {
"move") == 0) {
"eject") == 0) {
"inject") == 0) {
"notify") == 0) {
"library") == 0) {
"drive") == 0) {
"request") == 0) {
"accept") == 0) {
"respond") == 0) {
"release") == 0) {
"cancel") == 0) {
"identity") == 0) {
"message") == 0) {
"direct") == 0) {
"setpassword") == 0) {
} else {
}
break;
case MM_LANG_DMP:
if (rc) {
if (p_err_rc == MM_PAR_SEND_UNACC) {
send_unacceptable = 1;
}
if (p_err_rc == MM_PAR_SEND_UNWEL) {
send_unwelcome = 1;
}
if (p_err_rc == MM_PAR_IS_RESP) {
is_response = 1;
}
parse_error = 1;
break;
}
send_acc = 0;
"response") == 0) {
send_acc = 0;
"create") == 0) {
"notify") == 0) {
} else {
}
break;
case MM_LANG_LMP:
if (rc) {
if (p_err_rc == MM_PAR_SEND_UNACC) {
send_unacceptable = 1;
}
if (p_err_rc == MM_PAR_SEND_UNWEL) {
send_unwelcome = 1;
}
if (p_err_rc == MM_PAR_IS_RESP) {
is_response = 1;
}
parse_error = 1;
break;
}
send_acc = 0;
"response") == 0) {
send_acc = 0;
"notify") == 0) {
} else {
}
break;
}
if (parse_error == 0) {
char *buf_ptr;
} else {
}
"command %s %s fd -> %d"
"\n\n%s\n",
buf_ptr);
}
if (parse_error) {
if (send_unwelcome) {
/* Syntax error in a hello command */
/* send unwelcome */
return (0);
} else if (send_unacceptable) {
/* Syntax error in valid MM command */
/* send unacceptable */
"Parse error- response unacceptable");
return (0);
} else if (is_response) {
/* There was a syntax error in the response, */
/* attempt to process anyways */
"attempting anyways");
send_acc = 0;
cmd->cmd_remove = 0;
return (1);
} else {
/* Unrecoverable error, syntax, no mem */
/* What to do?? Print message and ignore for now */
/* Close the connection so the client does not hang */
return (0);
}
}
rc = 1;
if (mm_wka->wka_goodbye) {
"this client has already "
"sent a goodbye, send unaccept");
return (0);
}
/* If this wka is involved in a begin-end command group, */
/* send unaccept for all commands execpt, end, mount, unmount */
/* Client is in beg-end group */
"client in begin end group"
" may only send mount,unmount, or end");
return (0);
/* if this is mount or unmount and to begin cmd list */
/* Return 2 for special rc code */
rc = 2;
}
}
/* Send an accept for all command that are not hello or response */
if (send_acc) {
/* If this command is a begin command */
/* set begin end mode before sending the accept */
"begin-end mode active");
}
/* If this command is a end command */
/* set begin end mode off before sending the accept */
"begin-end mode disabled");
/* Match this end with a begin */
(cur_cmd->cmd_begin_has_end == 0)) {
/* found the begin for this end */
"mm_setup_cmd: "
"matched this end (%s, %p) "
"with begin (%s, %p)",
cur_cmd);
break;
}
}
}
}
/* Set this commands name */
return (rc);
return (0);
}
/*
* mm_add_beginend_cmd
*
* Parameters:
* - mm_wka : ptr to cli work area, mm_wka_t
* - mm_cmd : ptr to mm_command_t
* - mm_data : ptr to mm_data_t
*
* For the workarea pointed to by mm_wka, add the command
* mm_cmd to the currently active list of commands for the
* begin-end group
*
* Return Values:
* 0 : if the command was succesfully added to a
* begin-end group
* 1 : if the command was not added to a begin-end group
*
*/
int
continue;
(cur_cmd->cmd_begin_has_end == 0)) {
/* This clients begin cmd */
mm_cmd);
return (0);
}
}
return (1);
}
/*
* mm_add_cmd
*
* Parameters:
* - mm_wka : ptr to cli work area, mm_wka_t
* - buf : ptr to char string of cmd text
* - mm_data : ptr to mm_data_t
*
* Adds command to mm's command queue
* Update CONNECTION information
* setup command and add the command to the approperate
* list based on the return from mm_setup_cmd
*
* Return Values:
* None
*
*/
void
{
int rc = 0;
"update \"CONNECTION\" "
"set \"ConnectionTimeLastActive\" = now() "
"where \"ConnectionID\" = '%s';",
"Unable to malloc mm_command_t: %s",
return;
}
if (rc == 0) {
} else if (rc == 1) {
} else if (rc == 2) {
/* Add this command to begin-end block commands */
"couldn't find a begin command in cmd queue");
} else {
"begin-end block");
}
} else {
}
}
/*
* mm_cmd_dispatch
*
* Parameters:
* - cmd : ptr to mm_command_t
*
* Determines if the command is ready for dipatch,
* if the command is ready, call the function in cmd's
* command function pointer.
*
* This function will put a postgres txn block around the
* command function so if the command function returns
* error, parial changes to the db are not committed
*
* Return Values:
* One of the Dispatcher return codes, see mm.h
* (MM_CMD_DONE, MM_NO_DISPATCH etc...)
*
*/
int
{
int rc;
int txn;
/* Dispatch the Command */
/* Skip db txn for the following funtions */
txn = 1;
/* Check for a valid wka before running cmd */
"this commands wka is NULL");
rc = MM_CMD_ERROR;
"this commands wka is set for remove");
} else {
if (txn) {
}
/* Lock this wka's local lock */
"dispatching %s %s (%p) fd -> %d",
cmd,
/* Unlock this wka's local lock */
if (rc == MM_CMD_ERROR ||
rc == MM_DEPEND_ERROR) {
if (txn) {
(void) mm_db_txn_rollback(&cmd->
wka_ptr->
}
} else {
if (txn) {
(void) mm_db_txn_commit(&cmd->
wka_ptr->
}
}
if (rc == MM_CMD_DONE) {
(void) mm_message_command(cmd);
}
}
} else {
return (MM_NO_DISPATCH);
}
return (rc);
} else {
return (MM_NO_DISPATCH);
}
}
/*
* mm_rm_unmount
*
* Parameters:
* - cmd : ptr to mm_command_t
*
* Do additional steps to clean up when the command
* being removed is an unmount command
* check what subcommands are active,
* reset drive and cartridge states and add commands
* to clear the drive
*
* Return Values:
* 0 : for success
* 1 : for error
*
*/
int
return (0);
}
/* Check this cmd's sub cmd's */
/* Allow detach release unload /unmount to complete */
/* if they have already been accepted */
}
}
}
(void) mm_set_drive_statesoft(cmd->
"ready", db);
}
(void) mm_set_cartridge_status(cmd->
"available", db);
}
"select \"DriveStateHard\" from \"DRIVE\" where"
"\"DRIVE\".\"DriveName\" = '%s';",
"error checking DRIVE state");
return (0);
}
if (PQntuples(drive_results) == 0) {
"DRIVE results returned 0");
return (0);
}
"drive is loaded, set DriveStateHard == unloading");
"update \"DRIVE\" set "
"\"DriveStateHard\" = 'unloading' "
"where \"DriveName\" = '%s';",
}
}
return (0);
}
/*
* mm_rm_mount
*
* Parameters:
* - cmd : ptr to mm_command_t
*
* Do additional steps to clean up when the command
* being removed is a mount command
* check what subcommands are active,
* reset drive and cartridge states and add commands
* to clear the drive
*
* Return Values:
* 0 : for success
* 1 : for error
*
*/
int
{
/* This function is called when a client has disconnected */
/* with an outstanding mount command */
/* need to deallocate the resources and reset device manager states */
return (0);
}
/* command is not a MMP mount */
"this command is not a MMP mount command");
return (0);
}
/* Do clean up for MMP mount command */
/* Cartridge is not in the drive */
/* Reset CARTRIDGE and DRIVE */
"update \"CARTRIDGE\" set "
"\"CartridgeStatus\" = 'available' "
"where \"CartridgeID\" = '%s';",
} else {
"cmi_cartridge is NULL "
"cannot update state");
}
"update \"DRIVE\" set "
"\"DriveStateSoft\" = 'ready' "
"where \"DriveName\" = '%s';",
"select \"DriveStateHard\" from \"DRIVE\" where"
"\"DRIVE\".\"DriveName\" = '%s';",
"error checking DRIVE state");
return (0);
}
if (PQntuples(drive_results) == 0) {
"DRIVE results returned 0");
return (0);
}
"loaded") == 0) ||
"loadeding") == 0)) {
"DriveStateHard == unloading");
"update \"DRIVE\" set "
"\"DriveStateHard\" = 'unloading' "
"where \"DriveName\" = '%s';",
}
} else {
"cmi_drive is NULL "
"cannot update state");
}
return (0);
}
/*
* mm_print_cmd_queue
*
* Parameters:
* - mm_data : ptr to mm_data_t
*
* Traces the names of all commands in
* the current command queue
*
* Return Values:
* None
*
*/
void
int print_one = 0;
print_one = 1;
if (print_buf)
switch (cur_cmd->cmd_language) {
case MM_LANG_MMP:
"MMP ");
break;
case MM_LANG_DMP:
"DMP ");
break;
case MM_LANG_LMP:
"LMP ");
break;
}
}
"%s",
} else {
"NULL command name");
}
" (%p)",
cur_cmd);
cur_depend = NULL;
if (cur_cmd->cmd_has_list) {
cur_depend) {
/* Is a child command */
" child of");
/* depend name has been set */
" %s",
cmd_name);
} else {
"NULL command name");
}
" (%p)",
}
} else {
" (no depend list)");
}
/* Has a valid wka */
", %s",
}
" %s",
} else {
}
}
if (!print_one) {
" none");
}
if (print_buf) {
}
}
/*
* mm_dispatch_delay_unmount
*
* Parameters:
* - mm_data : ptr to mm_data_t
*
* Check each delay unmount in the command queue
* and test its timer to see if it is ready for dispatch
* dispach any command whose timer has expired
*
* Return Values:
* None
*
*/
void
"a delay unmount is ready for dispatch");
/* Delay is over */
/* command is in the 1st or 2nd state */
}
}
}
}
/*
* mm_order_cmd_queue
*
* Parameters:
* - mm_data : ptr to mm_data_t
*
* Reorders the command queue to make processing more
* efficient. This will put all response first while maintaining
* the original order. This allows MM to do more work each
* pass through the command queue
*
* Return Values:
* None
*
*/
void
/*
* Re order the queue:
* 1) Responses
* 3) Privilenged Commands
* 4) Remaning
*/
int print_message = 0;
int bump = 0;
int response = 0;
int lmp_dmp = 0;
char *bump_list[3];
int num_bump_list = 3;
/* Test - print all the commands in the queue */
if (print_message)
bump = 0;
response = 0;
lmp_dmp = 0;
/*
* Find responses and privileged commands
*/
lmp_dmp = 1;
}
cmd_root), "response") == 0) {
response = 1;
}
for (int i = 0; i < num_bump_list; i ++) {
bump_list[i]) == 0) {
bump = 1;
}
}
}
/*
* Add responses to response list,
* priviled to front list
*/
if (response) {
if (print_message)
cur_cmd);
} else if (lmp_dmp) {
if (print_message)
cur_cmd);
} else if (bump) {
if (print_message)
"Bump this command to front");
cur_cmd);
} else {
if (print_message)
}
}
/* Put commands back into the queue */
cur_cmd);
}
cur_cmd);
}
cur_cmd);
}
/* Test - print all the commands in the queue */
/*
* if (print_message)
*/
/* Clean up */
for (int i = 0; i < num_bump_list; i ++) {
}
}
/*
* mm_notify
*
* Parameters:
* - arg : pointer to mm_data
*
* Main function for the notification thread
*
* This function will brodcast events to clients
* It checks the event list and event tables and
* sends the events to the approperate clients
* When all events have been sent, the thread will wait
* untill more events are generated
*
* Return Values:
* None
*
*/
void *
int done_one = 0;
while (!mm_exiting) {
/* Wait for Work */
mms_trace_flush(); /* flush mms_trace buffer */
while (mm_data->mm_notify_work_todo == 0) {
}
mm_data->mm_notify_work_todo = 0;
if (mm_exiting)
break;
/* Do the notify work */
"Notify Thread Processing Events...");
done_one = 0;
event = next_event) {
done_one = 1;
/*
* This event is not
* associated with a command
* Set the event ready for dispatch
* This may already have been set
*/
}
/* unlock to process event */
/* This allows the worker to add events */
/* while this thread proccess an event */
/* brodcast the event */
(void) notify_send(event);
/* clean up */
/* re lock */
} else {
"event not dispatchable, %s",
}
}
/* Send events in the event table */
if (mm_notify_event_table(mm_data)) {
"error sending status table events");
}
if (mm_notify_event_rules(mm_data)) {
"error sending status table events");
}
if (!done_one) {
" No Events Found");
}
}
return (NULL);
}
/*
* mm_worker
*
* Parameters:
* - arg : ptr to mm_data
*
* Main function for the worker thread
*
* This function will loop through the command queue
* and attempt to dispatch commands. If no commands are dispatchable
* it will wait to be signaled by the main thread.
*
* For dispatchable commands, it will call a function to execute
* that commands specifc command function. mm_worker will use the return code
* of that command function to take the approperate action
* (see mm.h for return codes used by this function)
*
* After doing some work, this therad will wake the taskmanager thread
* and notification thread
*
* Return Values:
* None
*
*/
void *
int rc;
int command_count = 0;
int get_next_cmd;
while (!mm_exiting) {
/* Wake the task manager thread */
/* Wake the notify thread */
/* Wait for Work */
mms_trace_flush(); /* flush mms_trace buffer */
while (mm_data->mm_work_todo == 0) {
}
/* Remove disconnected clients */
"clean up clients");
/* Service fd is bad */
"setting mm_exiting");
mm_exiting = 1;
}
mm_data->mm_work_todo = 0;
if (mm_exiting)
break;
/* Lock and Dispatch */
/*
* Re order the queue:
* 1) Responses
* 2) Privilenged Commands
* 3) Remaning
*/
command_count = 0;
command_count ++;
get_next_cmd = 0;
if (command_count > 10) {
break;
}
rc = -1;
} else if (cur_cmd->cmd_remove) {
rc = MM_NO_DISPATCH;
} else {
}
switch (rc) {
case MM_NO_DISPATCH:
"A command "\
"was not dispatchable - %s",
} else {
"A command " \
"was not dispatchable");
}
/* Command not dispatchable-return to queue */
if (cur_cmd->cmd_remove) {
strdup("UNKNOWN COMMAND");
}
"Removing cmd, %s %p",
/* free(cur_cmd); */
(void) mm_destroy_cmd(cur_cmd);
} else {
get_next_cmd = 1;
}
/*
* non-dispatchable commands
* don't count in the command count
*/
command_count --;
break;
case MM_DISPATCH_DEPEND:
/*
* Parent Command has added
* a new command to the
* queue that is ready for dispatch,
* set todo = true;
*/
get_next_cmd = 1;
break;
case MM_DEPEND_ERROR:
/*
* There was an error on a dependent command
* Recovery command has been added
*/
get_next_cmd = 1;
break;
case MM_DEPEND_DONE:
/*
* Command With Parent is done,
* dispatch the parent and remove
* the completed command
*/
/* free(cur_cmd); */
(void) mm_destroy_cmd(cur_cmd);
break;
case MM_CMD_DONE:
/* The command has sucessfully completed */
if (mm_has_depend(cur_cmd)) {
}
/* free(cur_cmd); */
(void) mm_destroy_cmd(cur_cmd);
/*
* mms_trace(MMS_INFO, "command destroyed...");
*/
break;
case MM_CMD_ERROR:
"Command Error - removing");
if (mm_set_depend_error(cur_cmd)) {
}
/* If this is a failed mount */
/* check if states need to be reset */
(void) mm_set_cartridge_status(cur_cmd->
(void) mm_set_drive_statesoft(cur_cmd->
}
/* free(cur_cmd); */
(void) mm_destroy_cmd(cur_cmd);
break;
case MM_DISPATCH_AGAIN:
/*
* This RC means that the current
* command has finished,
* but has added another command to run
* Remove the first command and set todo = 1
*/
/* If this command has depends, dispatch them */
if (mm_has_depend(cur_cmd)) {
}
/* free(cur_cmd); */
(void) mm_destroy_cmd(cur_cmd);
break;
case MM_ACCEPT_NEEDED:
/*
* A command has returned and needs an accept
* from an LM or DM, MM_CMD_NEED_ACCEPT
* flag should
* be set and command is NOT dispatchable
* Leave the cmd in the queue,
* when accept is recieved, the cmd will
* be dispatched
*/
get_next_cmd = 1;
break;
case MM_WORK_TODO:
/* A mount command state = 0 has finished */
get_next_cmd = 1;
break;
case (-1):
/* No commands left */
get_next_cmd = 1;
break;
}
/* Lock queue for the for loop */
if (get_next_cmd) {
}
}
/* Check for responses */
/* If all responses are not finished */
/* set todo */
"response") == 0) {
}
}
}
}
return (NULL);
}
/*
* mm_task_man
*
* Parameters:
* - arg : ptr to mm_data_T
*
* Main function for the task manager thread
*
* This function will attempt to dispatch any outstanding tasks
* by calling mm_get_tm_cmd
* After all tasks have been evaluated, the thread will wait
* untill signaled by the worker thread with new work.
*
* Return Values:
* None
*
*/
void *
mm_task_man(void * arg)
{
while (!mm_exiting) {
/* Wait for Work */
mms_trace_flush(); /* flush mms_trace buffer */
while (mm_data->mm_tm_work_todo == 0) {
}
mm_data->mm_tm_work_todo = 0;
if (mm_exiting)
break;
/* Run TM algorithm */
(void) mm_get_tm_cmd(mm_data);
}
return (NULL);
}
/*
* mm_check_drive_records
*
* Parameters:
* - mm_data : ptr to mm_data_t
* - db : ptr to valid db connection, mm_db_t
*
* Checks and cleans drive records
*
* Return Values:
* 0 : for success
*
*/
int
}
return (0);
}
/*
* mm_clean_drive_records
*
* Parameters:
* - mm_data : ptr to mm_data_t
* - db : ptr to valid db connection, mm_db_t
*
* Cleans drive records, records older than
* DriveRecordRetention will be removed from the db
*
* Return Values:
* 0 : for success
* 1 : for error
*
*/
int
char *wait;
"select \"DriveRecordRetention\" "
"from \"SYSTEM\"") != MM_DB_DATA) {
"error reading system object");
return (1);
}
"row number mismatch"
" reading system object");
return (1);
}
/* wait is in days, so days * 24 * 60 * 60 == wait in seconds */
"delete from \"DRIVECARTRIDGEACCESS\" where "
"((extract(epoch from (\"DriveCartridgeAccessTimeUnmount\" - "
"\"DriveCartridgeAccessTimeMount\"))) + (%s * 24 * 60 * 60)) > 0",
"error removing drive records");
return (1);
}
/* Schedule the next clean of drive records 24 hours from now */
return (0);
}
/*
* mm_start_states
*
* Parameters:
* - mm_data : ptr to mm_data_t
*
* Set the starting states for the db
* this is called once when MM first starts
*
* Return Values:
* 0 : for success
*
*/
int
{
int rows;
int rc;
/* TEMPORARY set HardState = ready */
"\"DMStateSoft\" = 'absent',"\
"\"DMStateHard\" = 'ready';");
"\"LMStateSoft\" = 'absent', "\
"\"LMStateHard\" = 'ready';");
"update \"CARTRIDGE\" set "
"\"CartridgeStatus\" = 'unavailable';");
/* Move MOUNTLOGICAL to STALEHANDLE */
"\"VolumeName\", \"PartitionName\", "\
"\"SideName\", \"CartridgeID\", "\
"\"DriveName\", \"DMName\", "\
"\"MountLogicalHandle\" from\"MOUNTLOGICAL\";");
if (rc != MM_DB_DATA) {
/* error */
return (0);
}
for (int i = 0; i < rows; i ++) {
/* Move 1 MOUNTLOGICAL to STALEHANDLE */
"insert into \"STALEHANDLE\" "\
"(\"ApplicationName\", \"VolumeName\", "\
"\"PartitionName\", "\
"\"SideName\", \"CartridgeID\", "\
"\"DriveName\", \"DMName\", "\
"\"MountLogicalHandle\") values "\
"('%s', '%s', '%s', '%s', "\
"'%s', '%s', '%s', '%s');",
PQgetvalue(mount_logical, i, 0),
"DB error copying MOUNTLOGICAL to STALEHANDLE");
}
/* Delete the old mount logical */
"delete from \"MOUNTLOGICAL\" "
"where \"CartridgeID\" = '%s';",
"DB error deleting MOUNTLOGICAL");
}
}
"\"DriveStateSoft\" = 'unavailable', "
"\"DriveLibraryOccupied\" = 'f', "
"\"DriveStateHard\" = 'unloaded', "
"\"BayName\" = DEFAULT, "
"\"DriveShapeName\" = DEFAULT, "
"\"DMName\" = DEFAULT;") != MM_DB_OK) {
MM_ABORT("drive set at init");
}
"\"RequestState\" != 'responded';");
/* Get any rules and drop them */
"select \"NotifyID\",\"NotifyObject\""
" from \"NOTIFYRULES\";") == MM_DB_DATA) {
for (int i = 0; i < PQntuples(notifyid_results); i ++) {
"drop rule \"%s\" on \"%s\";",
PQgetvalue(notifyid_results, i, 0),
}
} else {
"error getting notifyid's");
}
"\"LibraryStateSoft\" = 'ready';");
/* Delete all DM Configs */
/* Clean the Event table */
/* Clean the drive records */
return (0);
}
/*
* mm_calculate_timeout
*
* Parameters:
* - mm_data : ptr to mm_data_t
*
* Determines the correct timeout for MM's main thread pselect
*
* When there is a delay unload command present, MM will
* need to break out of pselect inorder to do the unload
* at the correct time.
*
* The timeout will be the time for the current delay
* unload's drivegroup minus the time since the delay was
* scheduled.
*
* There will only be a timeout if there is delay unload
* command on the queue. If the delay unload is not
* present the function returns 0
*
* Return Values:
* timeout : return the timeout in seconds
* 0 : return 0 for no timeout
*
*/
int
int wait = 0;
int wait_set = 0;
int any_command = 0;
/* Returns 0 for no timout */
any_command = 1;
/* is a delay unload command */
if ((wait_set == 0) &&
/* The 1st delay unload */
wait_set = 1;
/* A delay shorter than the 1st */
}
}
}
if (!any_command) {
return (wait);
}
if (!wait_set) {
"select \"DriveGroupUnloadTime\" from "
"\"DRIVEGROUP\" order by "
"\"DriveGroupUnloadTime\" asc limit 1;")
!= MM_DB_DATA) {
return (0);
}
return (0);
}
/* Timeout is in min, so mult by 60 for seconds */
}
return (wait);
}
/*
* mm_reconfig
*
* Parameters:
* - mm_data : ptr to mm_data_t
*
*
* Referesh the MM's config information
*
* Return Values:
* 0 : for success
*
*/
static int
{
#ifdef MMS_OPENSSL
char ebuf[MMS_EBUF_LEN];
#endif
/*
* Re-load configuration
*/
mm_refresh = 0;
if (mm_cfg_read(&mm_cfg)) {
}
#ifdef MMS_OPENSSL
if (data->mm_ssl_data) {
/*
* Get updated CRL
*/
return (1);
}
/*
* Check for revoked clients
*/
mm_wka->mm_wka_conn)) {
"client revoked %s %s - %s",
ebuf);
}
}
}
}
#endif /* MMS_OPENSSL */
(void) smf_refresh_instance(MMS_CFG_WCR_INST);
return (0);
}
/*
* main
*
* Parameters:
* No args
*
* This is the main function for MM
*
* This function first initializes the MM's tracing,
* db connections, core files, signal handleing, and
* creates the worker, task manager, and notification threads.
*
* Once MM has been intialized, this thread acts as the reader thread
* it will accept and proccess incomming command and clients.
* It will signal the other threads when there is work to be done.
* When commands/clients have completed/disconnected this thread will
* do the clean up and free any associated memory
*
* Return Values:
* N/A
*
*/
int
{
int mfd;
int rc;
char ebuf[MMS_EBUF_LEN];
char c;
void *status;
/* Time out */
int err;
int daemon_mode = 1;
/*
* Get debug DM config option
*/
switch (c) {
case 'v':
return (0);
case 'n':
daemon_mode = 0;
break;
default:
break;
}
}
/*
* Setup MM data and services
*/
/*
* Setup to block signals MM cares about.
* This is inherited by the threads so they will not
* be interrupted by signals.
*/
/*
* Get seperate database connections for worker and main threads
*/
}
/* initialze the db cmd lists */
(void) mm_start_states(data);
/* create worker and task manager threads */
if (mm_notify_init(&mm_data)) {
}
/*
* Setup signal handlers
*/
/*
* Accept new clients, read client input
*/
while (!mm_exiting) {
/*
* Setup for pselect
*/
"mms_fd == -1 for client,"
"set wka_remove");
continue;
}
}
}
mms_trace_flush(); /* flush mms_trace buffer */
/* Calculate the time out */
} else {
}
if (mm_exiting) {
break;
}
if (mm_refresh) {
if (mm_reconfig(&mm_data)) {
mm_exiting = 1;
break;
}
}
/* Check for interupt and bad file descriptor */
if (rc == -1) {
/* Take action */
continue;
/* Take action */
}
"mm service not valid FD -> %d",
/* Service Not Valid */
break;
}
/* Get valid FD SET */
continue;
}
/* A wka FD is ready to be read... */
if (mm_wka->wka_remove ||
"wka should be removed"
", dont read");
} else if (!mm_exiting &&
}
if (rc > 0) {
"read %s %s fd -> %d",
if (mm_wka->mm_wka_mm_lang ==
MM_LANG_DMP) {
"DM Disconnected "
"%s %s fd -> %d",
mm_wka->
mm_wka->
} else if (mm_wka->mm_wka_mm_lang ==
MM_LANG_LMP) {
"LM Disconnected "
"%s %s fd -> %d",
mm_wka->
mm_wka->
mm_wka->
} else if (mm_wka->mm_wka_mm_lang ==
MM_LANG_MMP) {
"MM Client Disconnected "
"%s %s fd -> %d",
mm_wka->
mm_wka->
mm_wka->
} else {
"bad read - "
"client disconnect "
"%s %s fd -> %d",
mm_wka->
mm_wka->
mm_wka->
}
}
}
}
/* A new client has been found */
if (mm_exiting) {
break;
}
break;
}
cli_conn)) {
"Error accepting new client connection");
ebuf, MMS_EBUF_LEN);
/* continue processing */
} else {
if (mm_exiting) {
break;
}
}
}
}
/* Service Not Valid */
break;
}
/* wakeup worker thread to do work */
}
/*
* Cleanup and exit
*/
mm_exiting = 1;
#ifdef MMS_OPENSSL
#endif
closelog();
return (SMF_EXIT_OK);
}