cdesktopenv/cde/lib/tt/bin/ttdbserverd/db_server_functions.C

2786 lines
76 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
//%% (c) Copyright 1993, 1994 Hewlett-Packard Company
//%% (c) Copyright 1993, 1994 International Business Machines Corp.
//%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
//%% (c) Copyright 1993, 1994 Novell, Inc.
//%% $TOG: db_server_functions.C /main/6 1999/10/14 18:38:12 mgreess $
/*
* @(#)db_server_functions.C 1.35 95/06/07
*
* Copyright (c) 1992 by Sun Microsystems, Inc.
*
* This file contains the functions that connect the DB server RPC
* interface to the DB server classes.
*
* As a function is implemented, it should commented
* out of the db_server_stubs.cc file.
*/
#include <dirent.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <errno.h>
#include <stdint.h>
#include <unistd.h>
#include <nl_types.h>
#include "api/c/tt_c.h"
#include "util/tt_file_system.h"
#include "util/tt_file_system_entry.h"
#include "util/tt_path.h"
#include "util/tt_port.h"
#include "util/tt_xdr_utils.h"
#include "util/tt_gettext.h"
#include "db/db_server.h"
#include "db/tt_db_access.h"
#include "db/tt_db_property.h"
#include "db/tt_db_access_utils.h"
#include "db/tt_db_property_utils.h"
#include "db/tt_db_rpc_routines.h"
#include "db_server_globals.h"
#include "tt_db_message_info_utils.h"
#include "tt_db_partition_global_map_ref.h"
#include "tt_db_server_consts.h"
#include "tt_db_server_db_utils.h"
#include "dm_access_cache.h"
#include "dm/dm_recfmts.h"
#if !defined(OPT_GARBAGE_THREADS)
#include <db/tt_db_client.h>
#include <db/tt_db_client_utils.h>
char **global_argv;
char **global_envp;
#endif
//
// This is the PID or TID of the procedure that is
// performing the garbage collection.
//
#if defined(USL) || defined(__uxp__)
int _tt_garbage_id = 0; // TID or PID.
#else
int _tt_garbage_id = -1; // TID or PID.
#endif
int _tt_run_garbage_collect(int in_parallel);
static const char * sesProp = _TT_FILEJOIN_PROPNAME;
static const char * modDate = _MP_NODE_MOD_PROP;
static const char * propTable = "property_table";
extern _Tt_db_info _tt_db_table[_TT_MAX_ISFD];
static bool_t _tt_is_file_a_directory (const _Tt_string&);
static _Tt_string _tt_make_equivalent_object_id(const _Tt_string &objid,
const _Tt_string &partition);
static _Tt_db_results _tt_get_partition_db (const _Tt_string&,
_Tt_db_server_db_ptr&);
static _Tt_db_access_ptr
_tt_get_real_rpc_access (const _tt_access &rpc_access);
static _Tt_db_access_ptr _tt_get_file_access (const _Tt_string &file,
const _tt_access &rpc_access);
static _Tt_db_access_ptr _tt_get_unix_file_access (const _Tt_string &file);
static _Tt_string _tt_get_file_partition (const _Tt_string &file);
static _Tt_db_results
_tt_increment_file_properties_cache_level (const _Tt_db_server_db_ptr&,
const _Tt_string&,
const _Tt_db_access_ptr&,
int&);
static _Tt_db_results
_tt_get_file_properties_cache_level (const _Tt_db_server_db_ptr&,
const _Tt_string&,
const _Tt_db_access_ptr&,
int&);
static _Tt_string _tt_get_object_partition (const _Tt_string &objid);
static _Tt_db_results
_tt_increment_object_properties_cache_level (const _Tt_db_server_db_ptr&,
const _Tt_string&,
const _Tt_db_access_ptr&,
int&);
static _Tt_db_results
_tt_get_object_properties_cache_level (const _Tt_db_server_db_ptr&,
const _Tt_string&,
const _Tt_db_access_ptr&,
int&);
static void _tt_screen_object_properties (_Tt_db_property_list_ptr&);
static _Tt_string _tt_get_local_path (const _Tt_string &network_path,
_Tt_string &hostname,
_Tt_string &partition);
_tt_auth_level_results *_tt_get_min_auth_level_1 (void * /* dummy_arg */,
SVCXPRT * /* transp */)
{
static _tt_auth_level_results results;
results.auth_level = _tt_auth_level;
results.results = TT_DB_OK;
return &results;
}
_tt_file_partition_results *_tt_get_file_partition_1 (char **file,
SVCXPRT * /* transp */)
{
static _tt_file_partition_results results;
_Tt_string hostname = _tt_gethostname();
_Tt_string file_hostname;
_Tt_string network_path = *file;
_Tt_string partition;
_Tt_string local_path = _tt_get_local_path (network_path,
file_hostname,
partition);
results.partition = strdup((char *)partition);
if (file_hostname == hostname) {
network_path = file_hostname.cat(":").cat(local_path);
}
results.network_path = strdup((char *)network_path);
results.results = TT_DB_OK;
return &results;
}
_tt_db_cache_results *_tt_create_file_1 (_tt_create_file_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_cache_results results;
results.cache_level = -1;
_Tt_string real_file = args->file;
_Tt_string partition = _tt_get_file_partition(args->file);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr access = _tt_get_file_access(real_file, args->access);
if (results.results == TT_DB_OK) {
// See if the file already exists by trying to get its access info
_Tt_db_access_ptr temp_access;
_Tt_db_results temp_results = db->getFileAccess(real_file,
access,
temp_access);
// If the file exists...
if ((temp_results == TT_DB_OK) ||
(temp_results == TT_DB_ERR_ACCESS_DENIED)) {
results.results = TT_DB_ERR_FILE_EXISTS;
}
// Else, if the file does not exist...
else if (temp_results == TT_DB_ERR_NO_SUCH_FILE) {
results.results = TT_DB_OK;
}
else {
results.results = temp_results;
}
}
if (results.results == TT_DB_OK) {
results.results = db->createFile(real_file, access);
if (results.results == TT_DB_OK) {
_Tt_db_property_list_ptr properties;
_tt_get_rpc_properties(args->properties, properties);
if (!properties.is_null()) {
results.results = db->setFileProperties(real_file,
properties,
access);
}
if (results.results == TT_DB_OK) {
results.results =
_tt_increment_file_properties_cache_level(db,
real_file,
access,
results.cache_level);
}
}
}
return &results;
}
_tt_db_cache_results *_tt_create_obj_1 (_tt_create_obj_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_cache_results results;
results.cache_level = -1;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_string real_file = args->file;
_Tt_db_access_ptr object_access = _tt_get_real_rpc_access(args->access);
if (results.results == TT_DB_OK) {
// See if the object already exists by trying to get the forward
// pointer property
_Tt_db_property_ptr temp_property;
_Tt_db_results temp_results =
db->getObjectProperty(args->objid,
TT_DB_FORWARD_POINTER_PROPERTY,
object_access,
temp_property);
// If the property exists, remove the object
if (temp_results == TT_DB_OK) {
(void)db->removeObject(args->objid, object_access);
}
// Else if the object exists without a forward pointer...
else if (temp_results == TT_DB_ERR_NO_SUCH_PROPERTY) {
results.results = TT_DB_ERR_OBJECT_EXISTS;
}
// Else if the object does not exist...
else if (temp_results == TT_DB_ERR_NO_SUCH_OBJECT) {
results.results = TT_DB_OK;
}
else {
results.results = temp_results;
}
}
if (results.results == TT_DB_OK) {
_Tt_db_access_ptr file_access = _tt_get_file_access(real_file,
args->access);
results.results = db->createObject(real_file,
args->objid,
object_access,
file_access);
if (results.results == TT_DB_OK) {
_Tt_db_property_list_ptr properties;
_tt_get_rpc_properties(args->properties, properties);
if (!properties.is_null()) {
_tt_screen_object_properties (properties);
}
if (!properties.is_null()) {
results.results = db->setObjectProperties(args->objid,
properties,
object_access);
}
// Set the otype of the object
if (results.results == TT_DB_OK) {
_Tt_db_property_ptr property = new _Tt_db_property;
property->name = TT_DB_OBJECT_TYPE_PROPERTY;
property->values->append(_Tt_string(args->otype));
results.results = db->setObjectProperty(args->objid,
property,
object_access);
}
if (results.results == TT_DB_OK) {
results.results =
_tt_increment_object_properties_cache_level(db,
args->objid,
object_access,
results.cache_level);
}
}
}
return &results;
}
_tt_db_results *_tt_remove_file_1 (_tt_remove_file_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_results results;
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_string real_file = args->file;
_Tt_string partition = _tt_get_file_partition(args->file);
_Tt_db_server_db_ptr db;
results = _tt_get_partition_db(partition, db);
if (results == TT_DB_OK) {
// Get the list of children under the file to remove along with
// the file. The list includes the file itself.
_Tt_string_list_ptr children;
results = db->getFileChildren(real_file, children);
if (children->is_empty()) {
results = TT_DB_ERR_NO_SUCH_FILE;
}
else {
_Tt_string_list_cursor children_cursor(children);
while ((results == TT_DB_OK) && children_cursor.next()) {
results = db->removeFile(*children_cursor, accessPtr);
}
}
}
return &results;
}
_tt_db_results *_tt_remove_obj_1 (_tt_remove_obj_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_results results;
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results = _tt_get_partition_db(partition, db);
if (results == TT_DB_OK) {
results = db->removeObject(args->objid, accessPtr);
if (results == TT_DB_OK) {
if (args->forward_pointer && strlen(args->forward_pointer)) {
// Allow everyone to read and delete the forward pointer
_Tt_db_access_ptr new_access = new _Tt_db_access;
new_access->user = (uid_t)-1;
new_access->group = (gid_t)-1;
new_access->mode = (mode_t)-1;
// Create a special forward pointer object with no file...
results = db->createObject((char *)NULL,
args->objid,
new_access,
new_access);
if (results == TT_DB_OK) {
_Tt_db_property_ptr property = new _Tt_db_property;
property->name = TT_DB_FORWARD_POINTER_PROPERTY;
property->values->append(_Tt_string(args->forward_pointer));
results = db->setObjectProperty(args->objid, property, accessPtr);
}
}
}
}
return &results;
}
_tt_db_results *_tt_move_file_1 (_tt_move_file_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_results results;
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_string real_file = args->file;
_Tt_string real_new_file = args->new_file;
// Make sure we really need to do a move
if (real_file != real_new_file) {
_Tt_file_system fs;
_Tt_file_system_entry_ptr entry = fs.bestMatchToPath(real_file);
_Tt_file_system_entry_ptr new_entry = fs.bestMatchToPath(real_new_file);
_Tt_string partition = entry->getMountPoint();
_Tt_string new_partition = new_entry->getMountPoint();
if (partition == new_partition) {
// Get a connection to the partition DB
_Tt_db_server_db_ptr db;
results = _tt_get_partition_db(partition, db);
_Tt_string_list_ptr children;
if (results == TT_DB_OK) {
// Get a list of the files to move
results = db->getFileChildren(real_file, children);
}
if (results == TT_DB_OK) {
if (children->is_empty ()) {
results = TT_DB_ERR_NO_SUCH_FILE;
}
else {
_Tt_string_list_cursor children_cursor(children);
while ((results == TT_DB_OK) && children_cursor.next()) {
// Construct the new file name by replacing the part
// that equals the "real_file" with the "real_new_file".
int length = (*children_cursor).len() - real_file.len();
_Tt_string new_child = real_new_file.cat("/");
new_child = new_child.cat((*children_cursor).right(length));
// Change the file name in the database
db->setFileFile(*children_cursor, new_child, accessPtr);
}
}
}
}
// Else, different partitions, therefore we can only move one
// non-directory file
else if (!_tt_is_file_a_directory(real_file)) {
// Get a connections to both partition DBs
_Tt_db_server_db_ptr db;
results = _tt_get_partition_db(partition, db);
_Tt_db_server_db_ptr new_db;
if (results == TT_DB_OK) {
results = _tt_get_partition_db(new_partition, new_db);
}
if (results == TT_DB_OK) {
_Tt_db_property_list_ptr properties;
_Tt_db_access_ptr current_access;
_Tt_string_list_ptr objids;
// Get all of the file's possesions
results = db->getFileProperties(real_file, accessPtr, properties);
if (results == TT_DB_OK) {
results = db->getFileAccess(real_file, accessPtr, current_access);
}
if (results == TT_DB_OK) {
results = db->getFileObjects(real_file, accessPtr, objids);
}
// Create the new file
if (results == TT_DB_OK) {
results = new_db->createFile(real_new_file, current_access);
}
// Copy the old file's properties to the new file
if (results == TT_DB_OK) {
results = new_db->setFileProperties(real_new_file,
properties,
accessPtr);
}
// Create the new objects with equivalent objids on the new partition
_Tt_string_list_ptr new_objids;
if (results == TT_DB_OK && (!objids->is_empty())) {
new_objids = new _Tt_string_list;
// Loop through the file's objects
_Tt_string_list_cursor objids_cursor(objids);
while ((results == TT_DB_OK) && objids_cursor.next()) {
_Tt_string new_objid =
_tt_make_equivalent_object_id(*objids_cursor, new_partition);
new_objids->append(new_objid);
_Tt_db_property_list_ptr properties;
_Tt_db_access_ptr current_access;
// Get all of the object's possesions
results = db->getObjectProperties(*objids_cursor,
accessPtr,
properties);
if (results == TT_DB_OK) {
results = db->getObjectAccess(*objids_cursor,
accessPtr,
current_access);
}
// Create the new object
if (results == TT_DB_OK) {
results = new_db->createObject(real_new_file,
new_objid,
current_access,
current_access);
}
// Copy the old object's properties to the new object
if (results == TT_DB_OK) {
results = new_db->setObjectProperties(new_objid,
properties,
accessPtr);
}
}
}
// Remove the old file and all of its objects
if (results == TT_DB_OK) {
results = db->removeFile(real_file, accessPtr);
}
// Create the forwarding pointers for all of the objects on
// the old file
if ((results == TT_DB_OK) && (!objids->is_empty())) {
_Tt_string_list_cursor objids_cursor(objids);
_Tt_string_list_cursor new_objids_cursor(new_objids);
while ((results == TT_DB_OK) &&
objids_cursor.next() &&
new_objids_cursor.next()) {
// Allow everyone to read and delete the forward pointer
_Tt_db_access_ptr new_access = new _Tt_db_access;
new_access->user = (uid_t)-1;
new_access->group = (gid_t)-1;
new_access->mode = (mode_t)-1;
// Create a special forward pointer object with no file...
results = db->createObject((char *)NULL,
*objids_cursor,
new_access,
new_access);
if (results == TT_DB_OK) {
_Tt_db_property_ptr property = new _Tt_db_property;
property->name = TT_DB_FORWARD_POINTER_PROPERTY;
property->values->append(*new_objids_cursor);
results = db->setObjectProperty(*objids_cursor,
property,
accessPtr);
}
}
}
}
}
else {
results = TT_DB_ERR_ILLEGAL_FILE;
}
}
else {
results = TT_DB_ERR_SAME_FILE;
}
return &results;
}
_tt_db_cache_results *_tt_set_file_props_1 (_tt_set_file_props_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_cache_results results;
results.cache_level = -1;
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_string real_file = args->file;
_Tt_string partition = _tt_get_file_partition(args->file);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
if (results.results == TT_DB_OK) {
_Tt_db_property_list_ptr properties;
_tt_get_rpc_properties(args->properties, properties);
if (!properties.is_null()) {
results.results = db->setFileProperties(real_file,
properties,
accessPtr);
}
else {
results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
}
if (results.results == TT_DB_OK) {
results.results =
_tt_increment_file_properties_cache_level(db,
real_file,
accessPtr,
results.cache_level);
}
}
return &results;
}
_tt_db_cache_results *_tt_set_file_prop_1 (_tt_set_file_prop_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_cache_results results;
results.cache_level = -1;
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_string real_file = args->file;
_Tt_string partition = _tt_get_file_partition(args->file);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
if (results.results == TT_DB_OK) {
_Tt_db_property_ptr property;
_tt_get_rpc_property(args->property, property);
if (!property.is_null()) {
results.results = db->setFileProperty(real_file,
property,
accessPtr);
}
else {
results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
}
if (results.results == TT_DB_OK) {
results.results =
_tt_increment_file_properties_cache_level(db,
real_file,
accessPtr,
results.cache_level);
}
}
return &results;
}
_tt_db_cache_results *_tt_add_file_prop_1 (_tt_add_file_prop_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_cache_results results;
results.cache_level = -1;
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_string real_file = args->file;
_Tt_string partition = _tt_get_file_partition(args->file);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
if (results.results == TT_DB_OK) {
_Tt_db_property_ptr property;
_tt_get_rpc_property(args->property, property);
if (!property.is_null()) {
results.results = db->addFileProperty(real_file,
property,
args->unique,
accessPtr);
}
else {
results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
}
if (results.results == TT_DB_OK) {
results.results =
_tt_increment_file_properties_cache_level(db,
real_file,
accessPtr,
results.cache_level);
}
}
return &results;
}
_tt_db_cache_results *_tt_delete_file_prop_1 (_tt_del_file_prop_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_cache_results results;
results.cache_level = -1;
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_string real_file = args->file;
_Tt_string partition = _tt_get_file_partition(args->file);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
if (results.results == TT_DB_OK) {
_Tt_db_property_ptr property;
_tt_get_rpc_property(args->property, property);
if (!property.is_null()) {
results.results = db->deleteFileProperty(real_file,
property,
accessPtr);
}
else {
results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
}
if (results.results == TT_DB_OK) {
results.results =
_tt_increment_file_properties_cache_level(db,
real_file,
accessPtr,
results.cache_level);
}
}
return &results;
}
_tt_file_prop_results *_tt_get_file_prop_1 (_tt_get_file_prop_args *args,
SVCXPRT * /* transp */)
{
static _tt_file_prop_results results;
results.cache_level = -1;
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_string real_file = args->file;
_Tt_string partition = _tt_get_file_partition(args->file);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
if (results.results == TT_DB_OK) {
results.results = _tt_get_file_properties_cache_level(db,
real_file,
accessPtr,
results.cache_level);
}
_Tt_db_property_ptr property;
if ((results.cache_level > args->cache_level) &&
(results.results == TT_DB_OK)) {
results.results = db->getFileProperty(real_file,
args->name,
accessPtr,
property);
}
_tt_set_rpc_property(property, results.property);
return &results;
}
_tt_file_props_results *
_tt_get_file_props_1 (_tt_get_file_props_args *args,
SVCXPRT * /* transp */)
{
static _tt_file_props_results results;
results.cache_level = -1;
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_string real_file = args->file;
_Tt_string partition = _tt_get_file_partition(args->file);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
if (results.results == TT_DB_OK) {
results.results = _tt_get_file_properties_cache_level(db,
real_file,
accessPtr,
results.cache_level);
}
_Tt_db_property_list_ptr properties;
if ((results.cache_level > args->cache_level) &&
(results.results == TT_DB_OK)) {
results.results = db->getFileProperties(real_file,
accessPtr,
properties);
}
_tt_set_rpc_properties(properties, results.properties);
return &results;
}
_tt_file_objs_results *_tt_get_file_objs_1 (_tt_get_file_objs_args *args,
SVCXPRT * /* transp */)
{
static _tt_file_objs_results results;
// Make sure the returned cache level is higher then the callers
// cache level, so that the caller will use the returned data
results.cache_level = args->cache_level + 1;
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_string real_file = args->file;
_Tt_string partition = _tt_get_file_partition(args->file);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_string_list_ptr objids;
if ((results.cache_level > args->cache_level) &&
(results.results == TT_DB_OK)) {
results.results = db->getFileObjects(real_file,
accessPtr,
objids);
}
_tt_set_rpc_strings(objids, results.objids);
return &results;
}
_tt_db_results *_tt_set_file_access_1 (_tt_set_file_access_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_results results;
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_string real_file = args->file;
_Tt_string partition = _tt_get_file_partition(args->file);
_Tt_db_server_db_ptr db;
results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr new_access;
if (results == TT_DB_OK) {
_tt_get_rpc_access(args->new_access, new_access);
if ((new_access->user == (uid_t)-1) ||
(new_access->group == (gid_t)-1) ||
(new_access->mode == (mode_t)-1)) {
_Tt_db_access_ptr current_access;
results = db->getFileAccess(real_file,
accessPtr,
current_access);
if (results == TT_DB_OK) {
if (new_access->user == (uid_t)-1) {
new_access->user = current_access->user;
}
if (new_access->group == (gid_t)-1) {
new_access->group = current_access->group;
}
if (new_access->mode == (mode_t)-1) {
new_access->mode = current_access->mode;
}
}
}
if (results == TT_DB_OK) {
results = db->setFileAccess(real_file, new_access, accessPtr);
}
}
return &results;
}
_tt_file_access_results *_tt_get_file_access_1 (_tt_get_file_access_args *args,
SVCXPRT * /* transp */)
{
static _tt_file_access_results results;
_Tt_string real_file = args->file;
_Tt_string partition = _tt_get_file_partition(args->file);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_db_access_ptr current_access;
if (results.results == TT_DB_OK) {
results.results = db->getFileAccess(real_file,
accessPtr,
current_access);
}
_tt_set_rpc_access(current_access, results.access);
return &results;
}
_tt_obj_props_results *_tt_set_obj_props_1 (_tt_set_obj_props_args *args,
SVCXPRT * /* transp */)
{
static _tt_obj_props_results results;
results.cache_level = -1;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
if (results.results == TT_DB_OK) {
results.results =
_tt_get_object_properties_cache_level(db,
args->objid,
accessPtr,
results.cache_level);
}
_Tt_db_property_list_ptr properties;
// If the cache level in the DB is higher then the passed in
// cache level, then someone else must have updated before
// the callers last read from the DB --> update conflict...
if ((results.results == TT_DB_OK) &&
(results.cache_level > args->cache_level)) {
results.results = TT_DB_ERR_UPDATE_CONFLICT;
_Tt_db_results temp_results = db->getObjectProperties(args->objid,
accessPtr,
properties);
if (results.results != TT_DB_OK) {
properties = (_Tt_db_property_list *)NULL;
results.results = temp_results;
}
}
_tt_set_rpc_properties(properties, results.properties);
// No update conflicts or any other weirdness...
if (results.results == TT_DB_OK) {
_tt_get_rpc_properties(args->properties, properties);
if (!properties.is_null()) {
_tt_screen_object_properties (properties);
}
if (!properties.is_null()) {
results.results = db->setObjectProperties(args->objid,
properties,
accessPtr);
}
else {
results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
}
if (results.results == TT_DB_OK) {
results.results =
_tt_increment_object_properties_cache_level(db,
args->objid,
accessPtr,
results.cache_level);
}
}
return &results;
}
_tt_obj_props_results *_tt_set_obj_prop_1 (_tt_set_obj_prop_args *args,
SVCXPRT * /* transp */)
{
static _tt_obj_props_results results;
results.cache_level = -1;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
if (results.results == TT_DB_OK) {
results.results =
_tt_get_object_properties_cache_level(db,
args->objid,
accessPtr,
results.cache_level);
}
_Tt_db_property_list_ptr properties;
// If the cache level in the DB is higher then the passed in
// cache level, then someone else must have updated before
// the callers last read from the DB --> update conflict...
if ((results.results == TT_DB_OK) &&
(results.cache_level > args->cache_level)) {
results.results = TT_DB_ERR_UPDATE_CONFLICT;
_Tt_db_results temp_results = db->getObjectProperties(args->objid,
accessPtr,
properties);
if (results.results != TT_DB_OK) {
properties = (_Tt_db_property_list *)NULL;
results.results = temp_results;
}
}
_tt_set_rpc_properties(properties, results.properties);
// No update conflicts or any other weirdness...
if (results.results == TT_DB_OK) {
_Tt_db_property_ptr property;
_tt_get_rpc_property(args->property, property);
if (!property.is_null()) {
results.results = db->setObjectProperty(args->objid,
property,
accessPtr);
}
else {
results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
}
if (results.results == TT_DB_OK) {
results.results =
_tt_increment_object_properties_cache_level(db,
args->objid,
accessPtr,
results.cache_level);
}
}
return &results;
}
_tt_obj_props_results *_tt_add_obj_prop_1 (_tt_add_obj_prop_args *args,
SVCXPRT * /* transp */)
{
static _tt_obj_props_results results;
results.cache_level = -1;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
if (results.results == TT_DB_OK) {
results.results =
_tt_get_object_properties_cache_level(db,
args->objid,
accessPtr,
results.cache_level);
}
_Tt_db_property_list_ptr properties;
// If the cache level in the DB is higher then the passed in
// cache level, then someone else must have updated before
// the callers last read from the DB --> update conflict...
if ((results.results == TT_DB_OK) &&
(results.cache_level > args->cache_level)) {
results.results = TT_DB_ERR_UPDATE_CONFLICT;
_Tt_db_results temp_results = db->getObjectProperties(args->objid,
accessPtr,
properties);
if (results.results != TT_DB_OK) {
properties = (_Tt_db_property_list *)NULL;
results.results = temp_results;
}
}
_tt_set_rpc_properties(properties, results.properties);
// No update conflicts or any other weirdness...
if (results.results == TT_DB_OK) {
_Tt_db_property_ptr property;
_tt_get_rpc_property(args->property, property);
if (!property.is_null()) {
results.results = db->addObjectProperty(args->objid,
property,
args->unique,
accessPtr);
}
else {
results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
}
if (results.results == TT_DB_OK) {
results.results =
_tt_increment_object_properties_cache_level(db,
args->objid,
accessPtr,
results.cache_level);
}
}
return &results;
}
_tt_obj_props_results *_tt_delete_obj_prop_1 (_tt_del_obj_prop_args *args,
SVCXPRT * /* transp */)
{
static _tt_obj_props_results results;
results.cache_level = -1;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
if (results.results == TT_DB_OK) {
results.results =
_tt_get_object_properties_cache_level(db,
args->objid,
accessPtr,
results.cache_level);
}
// If the cache level in the DB is higher then the passed in
// cache level, then someone else must have updated before
// the callers last read from the DB --> update conflict...
if ((results.results == TT_DB_OK) &&
(results.cache_level > args->cache_level)) {
results.results = TT_DB_ERR_UPDATE_CONFLICT;
}
// No update conflicts or any other weirdness...
if (results.results == TT_DB_OK) {
_Tt_db_property_ptr property;
_tt_get_rpc_property(args->property, property);
if (!property.is_null()) {
results.results = db->deleteObjectProperty(args->objid,
property,
accessPtr);
}
else {
results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
}
if (results.results == TT_DB_OK) {
results.results =
_tt_increment_object_properties_cache_level(db,
args->objid,
accessPtr,
results.cache_level);
}
}
// The delete object prop function is the only object function that always
// returns that latest object properties. The cache level passed in
// is only used for update conflict detection.
_Tt_db_property_list_ptr properties;
if ((results.results == TT_DB_OK) ||
(results.results == TT_DB_ERR_UPDATE_CONFLICT)) {
_Tt_db_results temp_results = db->getObjectProperties(args->objid,
accessPtr,
properties);
if (results.results != TT_DB_OK) {
properties = (_Tt_db_property_list *)NULL;
results.results = temp_results;
}
}
_tt_set_rpc_properties(properties, results.properties);
return &results;
}
_tt_obj_prop_results *_tt_get_obj_prop_1 (_tt_get_obj_prop_args *args,
SVCXPRT * /* transp */)
{
static _tt_obj_prop_results results;
results.cache_level = -1;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
if (results.results == TT_DB_OK) {
results.results =
_tt_get_object_properties_cache_level(db,
args->objid,
accessPtr,
results.cache_level);
}
_Tt_db_property_ptr property;
// Only return values if the DB cache level is higher then the
// callers cache level
if ((results.results == TT_DB_OK) &&
(results.cache_level > args->cache_level)) {
results.results = db->getObjectProperty(args->objid,
args->name,
accessPtr,
property);
}
_tt_set_rpc_property(property, results.property);
return &results;
}
_tt_obj_props_results *_tt_get_obj_props_1 (_tt_get_obj_props_args *args,
SVCXPRT * /* transp */)
{
static _tt_obj_props_results results;
results.cache_level = -1;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
if (results.results == TT_DB_OK) {
results.results =
_tt_get_object_properties_cache_level(db,
args->objid,
accessPtr,
results.cache_level);
}
_Tt_db_property_list_ptr properties;
// Only return values if the DB cache level is higher then the
// callers cache level
if ((results.results == TT_DB_OK) &&
(results.cache_level > args->cache_level)) {
results.results = db->getObjectProperties(args->objid,
accessPtr,
properties);
}
_tt_set_rpc_properties(properties, results.properties);
return &results;
}
_tt_db_results *_tt_set_obj_type_1 (_tt_set_obj_type_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_results results;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
if (results == TT_DB_OK) {
_Tt_db_property_ptr property = new _Tt_db_property;
property->name = TT_DB_OBJECT_TYPE_PROPERTY;
property->values->append(_Tt_string(args->otype));
results = db->setObjectProperty(args->objid, property, accessPtr);
}
return &results;
}
_tt_obj_type_results *_tt_get_obj_type_1 (_tt_get_obj_type_args *args,
SVCXPRT * /* transp */)
{
static _tt_obj_type_results results;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
if (results.results == TT_DB_OK) {
_Tt_db_property_ptr property;
results.results = db->getObjectProperty(args->objid,
TT_DB_OBJECT_TYPE_PROPERTY,
accessPtr,
property);
results.otype = (char *)NULL;
if (results.results == TT_DB_OK) {
if (!property.is_null() && !property->is_empty()) {
_Tt_string otype = (*property->values) [0];
int length = otype.len();
results.otype = (char *)malloc(length+1);
memcpy(results.otype, (char *)otype, length);
results.otype [length] = '\0';
}
}
else if (results.results == TT_DB_ERR_NO_SUCH_PROPERTY) {
results.results = TT_DB_ERR_NO_OTYPE;
}
}
return &results;
}
_tt_db_results *_tt_set_obj_file_1 (_tt_set_obj_file_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_results results;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
if (results == TT_DB_OK) {
results = db->setObjectFile(args->objid, args->file, accessPtr);
}
return &results;
}
_tt_obj_file_results *_tt_get_obj_file_1 (_tt_get_obj_file_args *args,
SVCXPRT * /* transp */)
{
static _tt_obj_file_results results;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
if (results.results == TT_DB_OK) {
_Tt_string file;
results.results = db->getObjectFile(args->objid,
accessPtr,
file);
results.file = (char *)NULL;
if (results.results == TT_DB_OK) {
if (file.len()) {
results.file = strdup((char *)file);
}
}
}
return &results;
}
_tt_db_results *_tt_set_obj_access_1 (_tt_set_obj_access_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_results results;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_db_access_ptr new_access;
if (results == TT_DB_OK) {
_tt_get_rpc_access(args->new_access, new_access);
if ((new_access->user == (uid_t)-1) ||
(new_access->group == (gid_t)-1) ||
(new_access->mode == (mode_t)-1)) {
_Tt_db_access_ptr current_access;
results = db->getObjectAccess(args->objid,
accessPtr,
current_access);
if (results == TT_DB_OK) {
if (new_access->user == (uid_t)-1) {
new_access->user = current_access->user;
}
if (new_access->group == (gid_t)-1) {
new_access->group = current_access->group;
}
if (new_access->mode == (mode_t)-1) {
new_access->mode = current_access->mode;
}
}
}
if (results == TT_DB_OK) {
results = db->setObjectAccess(args->objid, new_access, accessPtr);
}
}
return &results;
}
_tt_obj_access_results *_tt_get_obj_access_1 (_tt_get_obj_access_args *args,
SVCXPRT * /* transp */)
{
static _tt_obj_access_results results;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_db_access_ptr current_access;
if (results.results == TT_DB_OK) {
results.results = db->getObjectAccess(args->objid,
accessPtr,
current_access);
}
_tt_set_rpc_access(current_access, results.access);
return &results;
}
_tt_is_file_in_db_results *_tt_is_file_in_db_1 (_tt_is_file_in_db_args *args,
SVCXPRT * /* transp */)
{
static _tt_is_file_in_db_results results;
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
_Tt_string real_file = args->file;
_Tt_string partition = _tt_get_file_partition(args->file);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
if (results.results == TT_DB_OK) {
// See if the file already exists by trying to get its access info
_Tt_db_access_ptr temp_access;
_Tt_db_results temp_results = db->getFileAccess(real_file,
accessPtr,
temp_access);
// If the file exists...
if ((temp_results == TT_DB_OK) ||
(temp_results == TT_DB_ERR_ACCESS_DENIED)) {
results.results = TT_DB_OK;
}
else {
results.results = temp_results;
}
// See if the file is a directory
results.directory_flag = _tt_is_file_a_directory(real_file);
}
return &results;
}
_tt_is_obj_in_db_results *_tt_is_obj_in_db_1 (_tt_is_obj_in_db_args *args,
SVCXPRT * /* transp */)
{
static _tt_is_obj_in_db_results results;
results.forward_pointer = (char *)NULL;
_Tt_string partition = _tt_get_object_partition(args->objid);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
_Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
if (results.results == TT_DB_OK) {
_Tt_string file;
// See if the object has an entry in the file-object map
results.results = db->getObjectFile(args->objid,
accessPtr,
file);
// If no entry in the file-object map...
if (results.results != TT_DB_OK) {
_Tt_db_property_ptr property;
// See if there is a forward pointer
_Tt_db_results temp_results =
db->getObjectProperty(args->objid,
TT_DB_FORWARD_POINTER_PROPERTY,
accessPtr,
property);
// If there is a forward pointer...
if (temp_results == TT_DB_OK) {
_Tt_string forward_pointer = (*property->values) [0];
int length = forward_pointer.len();
results.forward_pointer = (char *)malloc(length+1);
memcpy(results.forward_pointer, (char *)forward_pointer, length);
results.forward_pointer [length] = '\0';
results.results = TT_DB_WRN_FORWARD_POINTER;
}
}
}
return &results;
}
_tt_db_results *_tt_queue_message_1 (_tt_queue_msg_args *args,
SVCXPRT * /* transp */)
{
static _tt_db_results results;
bool_t property_written = FALSE;
_Tt_db_server_db_ptr db;
_Tt_string real_file = args->file;
if (!args->message.body.body_len) {
results = TT_DB_ERR_ILLEGAL_MESSAGE;
}
else {
_Tt_string partition = _tt_get_file_partition(args->file);
results = _tt_get_partition_db(partition, db);
}
if (results == TT_DB_OK) {
_Tt_db_access_ptr accessPtr = _tt_get_unix_file_access(real_file);
// Set the DB file access to be the same as the actual file. This
// allows an easy method of controlled message security
if (!accessPtr.is_null()) {
results = db->setFileAccess(real_file, accessPtr, accessPtr);
}
}
_Tt_db_access_ptr accessPtr = new _Tt_db_access;
accessPtr->user = _tt_uid;
accessPtr->group = _tt_gid;
// Create a new message info structure for the new message
_Tt_db_message_info_ptr message_info = new _Tt_db_message_info;
if (results == TT_DB_OK) {
XDR xdrs;
// Get the current information on queued messages
_Tt_db_property_ptr property;
_Tt_string name = TT_DB_MESSAGE_INFO_PROPERTY;
results = db->getFileProperty(real_file, name, accessPtr, property);
// Default new message ID if there are none in the queue
int message_id = 1;
if (results == TT_DB_OK) {
// Calculate the index for the last message info structure in
// the property
int index = property->values->count() - 1;
if (index > -1) {
// Un-XDR the message info into the "last_message_info" object
// and set the new message ID to the message ID in in
// "last_message_info" + 1.
_Tt_string message_info_bytes = (*property->values) [index];
xdrmem_create(&xdrs,
(char *)message_info_bytes,
(u_int)message_info_bytes.len(),
XDR_DECODE);
_Tt_db_message_info_ptr last_message_info = new _Tt_db_message_info;
(void)last_message_info->xdr(&xdrs);
message_id = last_message_info->messageID + 1;
}
}
// It doesn't matter if there were no queued messages, as long as
// there were no fatal errors
if ((results == TT_DB_OK) ||
(results == TT_DB_ERR_NO_SUCH_PROPERTY)) {
results = TT_DB_OK;
// Put the new message info into the message info structure
message_info->messageID = message_id;
message_info->numParts = (args->message.body.body_len / ISMAXRECLEN) + 1;
message_info->messageSize = args->message.body.body_len;
_tt_get_rpc_strings(args->ptypes, message_info->ptypes);
// Get the XDR size of the new message info structure
u_int length;
_Tt_xdr_size_stream xdrsz;
if (!message_info->xdr((XDR *)xdrsz)) {
results = TT_DB_ERR_ILLEGAL_MESSAGE;
} else {
length = (unsigned int) xdrsz.getsize();
}
// XDR the message info structure into "temp_string"
_Tt_string temp_string((int)length);
if (results != TT_DB_ERR_ILLEGAL_MESSAGE) {
xdrmem_create(&xdrs, (char *)temp_string, length, XDR_ENCODE);
if (!message_info->xdr(&xdrs)) {
results = TT_DB_ERR_ILLEGAL_MESSAGE;
}
}
if (results != TT_DB_ERR_ILLEGAL_MESSAGE) {
// Add the XDR'd message info to the message info property
_Tt_db_property_ptr property = new _Tt_db_property;
property->name = TT_DB_MESSAGE_INFO_PROPERTY;
property->values->append(temp_string);
results = db->addFileProperty(real_file, property, FALSE, accessPtr);
property_written = TRUE;
}
}
}
if (results == TT_DB_OK) {
int length = ISMAXRECLEN;
// Break up the message into ISMAXRECLEN sized parts and store
// as separate properties
for (int i=0;
(results == TT_DB_OK) && (i < message_info->numParts);
i++) {
// If this is the last part, it is probably shorter then
// ISMAXRECLEN, so calculate the exact length
if (i == message_info->numParts-1) {
length = message_info->messageSize - (i * ISMAXRECLEN);
}
// Copy the message part into a buffer
_Tt_string message_part(length);
memcpy((char *)message_part,
args->message.body.body_val+i*ISMAXRECLEN,
length);
// Construct a property name of the form:
//
// _TT_MSG_<ID#>_<PART#>
//
char name [64];
sprintf(name, TT_DB_MESSAGE_PROPERTY, message_info->messageID, i);
// Store the property
_Tt_db_property_ptr property = new _Tt_db_property;
property->name = name;
property->values->append(message_part);
results = db->setFileProperty(real_file, property, accessPtr);
property_written = TRUE;
}
}
if (property_written && (results == TT_DB_OK)) {
int cache_level;
results = _tt_increment_file_properties_cache_level(db,
real_file,
accessPtr,
cache_level);
}
return &results;
}
_tt_dequeue_msgs_results *
_tt_dequeue_messages_1 (_tt_dequeue_msgs_args *args,
SVCXPRT * /* transp */)
{
static _tt_dequeue_msgs_results results;
results.messages.messages_val = (_tt_message *)NULL;
results.messages.messages_len = 0;
bool_t property_written = FALSE;
_Tt_string real_file = args->file;
_Tt_string partition = _tt_get_file_partition(args->file);
_Tt_db_server_db_ptr db;
results.results = _tt_get_partition_db(partition, db);
if (results.results == TT_DB_OK) {
_Tt_db_access_ptr accessPtr = _tt_get_unix_file_access(real_file);
// Set the DB file access to be the same as the actual file. This
// allows an easy method of control for queued message security
if (!accessPtr.is_null()) {
results.results = db->setFileAccess(real_file,
accessPtr,
accessPtr);
}
}
_Tt_db_access_ptr accessPtr = new _Tt_db_access;
accessPtr->user = _tt_uid;
accessPtr->group = _tt_gid;
// Get the message info property
_Tt_db_property_ptr property;
if (results.results == TT_DB_OK) {
_Tt_string name = TT_DB_MESSAGE_INFO_PROPERTY;
results.results = db->getFileProperty(real_file,
name,
accessPtr,
property);
}
_Tt_db_message_info_ptr message_info = new _Tt_db_message_info;
_Tt_string_list_ptr messages;
if (results.results == TT_DB_ERR_NO_SUCH_PROPERTY) {
results.results = TT_DB_OK;
}
else if (results.results == TT_DB_OK) {
_Tt_string_list_ptr dequeue_ptypes;
_tt_get_rpc_strings(args->ptypes, dequeue_ptypes);
_Tt_string_list_cursor dequeue_ptypes_cursor(dequeue_ptypes);
// Loop through the message info property (effectively looping
// through the message info entries)
_Tt_string_list_cursor values_cursor(property->values);
while (values_cursor.next()) {
XDR xdrs;
// Un-XDR a message info structure
xdrmem_create(&xdrs,
(char *)*values_cursor,
(*values_cursor).len(),
XDR_DECODE);
(void)message_info->xdr(&xdrs);
// Eliminate all of the ptypes from the message info list
// that match the callers ptype list.
bool_t ptype_matched = FALSE;
_Tt_string_list_cursor ptypes_cursor(message_info->ptypes);
while (ptypes_cursor.next()) {
while (dequeue_ptypes_cursor.next()) {
if (*dequeue_ptypes_cursor == *ptypes_cursor) {
ptypes_cursor.remove();
ptype_matched = TRUE;
break;
}
}
}
// A ptype matched, this message is to be returned...
if (ptype_matched) {
if (messages.is_null()) {
messages = new _Tt_string_list;
}
// Reconstruct the message from the _TT_MSG_<ID#>_<PART#> properties
_Tt_string message(message_info->messageSize);
for (int i=0; (results.results == TT_DB_OK) &&
(i < message_info->numParts); i++) {
// Construct the property name
char name [64];
sprintf(name, TT_DB_MESSAGE_PROPERTY, message_info->messageID, i);
// Get the property value
_Tt_db_property_ptr property;
results.results = db->getFileProperty(real_file,
name,
accessPtr,
property);
if (results.results == TT_DB_OK) {
_Tt_string message_bytes = (*property->values) [0];
// Copy each succesive part into a large buffer
memcpy((char *)message+i*ISMAXRECLEN,
(char *)message_bytes,
message_bytes.len());
}
}
// Append the re-assembled message to the return list
if (results.results == TT_DB_OK) {
messages->append(message);
}
}
// No more ptypes left for this message, dequeue it...
if (message_info->ptypes->is_empty()) {
values_cursor.remove();
}
// Otherwise, update the property value with an updated version
// of the message_info structure
else {
u_int length;
XDR xdrs;
_Tt_xdr_size_stream xdrsz;
// Get the XDR size of the updated message info structure
(void)message_info->xdr((XDR *)xdrsz);
length = (unsigned int) xdrsz.getsize();
// XDR the message info structure into "temp_string"
_Tt_string temp_string((int)length);
xdrmem_create(&xdrs, (char *)temp_string, length, XDR_ENCODE);
if (!message_info->xdr(&xdrs)) {
// Update the property value
*values_cursor = temp_string;
}
}
}
// Put the message info property back into the DB. If all of
// the message info structures have been deleted from the
// property, then this should effectively delete the property.
results.results = db->setFileProperty(real_file,
property,
accessPtr);
property_written = TRUE;
if (!messages.is_null()) {
if ((results.results == TT_DB_OK) && !messages->is_empty()) {
// Allocate enough space to transport the messages back to the
// caller
results.messages.messages_val = (_tt_message *)
malloc(sizeof(_tt_message)*
messages->count());
results.messages.messages_len = messages->count();
// Put the messages into the results structure
int i = 0;
_Tt_string_list_cursor messages_cursor(messages);
while (messages_cursor.next()) {
results.messages.messages_val [i].body.body_val =
(char *)malloc((*messages_cursor).len());
results.messages.messages_val [i].body.body_len =
(*messages_cursor).len();
memcpy(results.messages.messages_val [i].body.body_val,
(char *)*messages_cursor,
(*messages_cursor).len());
i++;
}
}
}
}
if (property_written && (results.results == TT_DB_OK)) {
int cache_level;
results.results = _tt_increment_file_properties_cache_level(db,
real_file,
accessPtr,
cache_level);
}
return &results;
}
// Since we're calling the wrapped API calls, bringing in tt_c.h
// doesn't get us the declarations we need, so we have to bring
// these two in manually like this.
//
extern char * _tt_file_netfile(const char *);
extern char * _tt_netfile_file(const char *);
extern Tt_status _tt_pointer_error(void *p);
extern char * _tt_status_message(Tt_status s);
// Call the API routine _tt_file_netfile() and return the
// results.
_tt_file_netfile_results *
_tt_file_netfile_1 (_tt_file_netfile_args *args, SVCXPRT * /* transp */)
{
#ifdef notdef
printf("DEBUG: SERVER: _tt_file_netfile_1: calling _tt_file_netfile(%s)\n",
(char *) args->file_or_netfile);
#endif
static _tt_file_netfile_results results;
static char * canonical_path;
// we have a netfilename, get the local file version...
canonical_path = _tt_file_netfile(args->file_or_netfile);
#ifdef notdef
printf("DEBUG: SERVER: _tt_file_netfile_1: _tt_file_netfile(%s) returned %s\n",
args->file_or_netfile, canonical_path);
#endif
if (_tt_pointer_error(canonical_path) != TT_OK) {
results.results = TT_DB_ERR_ILLEGAL_FILE;
results.result_string = '\0';
} else {
results.results = TT_DB_OK;
results.result_string = canonical_path;
}
results.tt_status = (int) _tt_pointer_error(canonical_path);
#ifdef notdef
printf("\t results.tt_status == %s\n",
_tt_status_message(_tt_pointer_error(canonical_path)));
#endif
return &results;
}
// Call the API routine _tt_netfile_file() and return the
// results.
_tt_file_netfile_results *
_tt_netfile_file_1 (_tt_file_netfile_args *args, SVCXPRT * /* transp */)
{
#ifdef notdef
printf("DEBUG: SERVER: _tt_netfile_file_1: calling _tt_netfile_file(%s)\n",
(char *) args->file_or_netfile);
#endif
static _tt_file_netfile_results results;
static char * canonical_path;
// we have a netfilename, get the local file version...
canonical_path = _tt_netfile_file(args->file_or_netfile);
#ifdef notdef
printf("DEBUG: SERVER: _tt_netfile_file_1: _tt_netfile_file(%s) returned %s\n",
args->file_or_netfile, canonical_path);
#endif
if (_tt_pointer_error(canonical_path) != TT_OK) {
results.results = TT_DB_ERR_ILLEGAL_FILE;
results.result_string = '\0';
} else {
results.results = TT_DB_OK;
results.result_string = canonical_path;
}
results.tt_status = (int) _tt_pointer_error(canonical_path);
#ifdef notdef
printf("\t results.tt_status == %s\n",
_tt_status_message(_tt_pointer_error(canonical_path)));
#endif
return &results;
}
//
// Delete the named session from the properties table.
//
_tt_delete_session_results *
_tt_delete_session_1(_tt_delete_session_args *args,
SVCXPRT * /*NOTUSED*/)
{
static _tt_delete_session_results results;
Table_oid_prop record;
u_int fileOffset;
int propLen = strlen(propTable);
int isfd;
char *lastSlash;
char *pathName;
results.tt_status = TT_DB_OK;
//
// For each property_table that we manage,
// Compare the sessionID with the session that
// we just found to be dead, and delete it.
//
for (fileOffset = 0; fileOffset < _TT_MAX_ISFD; fileOffset++) {
pathName = _tt_db_table[fileOffset].db_path;
if (pathName && strlen(pathName) > 0) {
if (_tt_db_table[fileOffset].client_has_open
|| _tt_db_table[fileOffset].server_has_open) {
//
// Is the file name ".../property_table*" ?
//
lastSlash = strrchr(pathName, '/');
if (lastSlash) {
lastSlash++;
if (strncmp(propTable,lastSlash,propLen)==0) {
// Get the FD and process the file.
isfd=cached_isopen(pathName, ISINOUT);
//
// Get the 1st record.
//
LOCK_RPC();
isread(isfd, (char *)&record, ISFIRST);
((char *)(&record))[isreclen] = '\0';
// Delte the named session.
if (strcmp(sesProp, record.propname) == 0) {
if (strcmp(args->session.value, record.propval) == 0) {
isdelcurr(isfd);
isfsync(isfd);
}
}
// Unconditionally delete ALL _MODIFICATION_DATE's
if (strcmp(modDate, record.propname) == 0) {
isdelcurr(isfd);
isfsync(isfd);
}
UNLOCK_RPC();
do {
LOCK_RPC();
if (isread(isfd, (char *)&record,ISNEXT) != 0) {
UNLOCK_RPC();
break;
}
((char *)(&record))[isreclen] = '\0';
if (strcmp(sesProp, record.propname) == 0) {
if(strcmp(args->session.value,
record.propval) == 0) {
isdelcurr(isfd);
isfsync(isfd);
}
}
// Unconditionally delete ALL
// _MODIFICATION_DATE's
if (strcmp(modDate, record.propname) == 0) {
isdelcurr(isfd);
isfsync(isfd);
}
UNLOCK_RPC();
} while(TRUE);
cached_isclose(isfd);
}
}
}
}
}
return(&results);
}
//
// *All* is an over statment.
// It returns up to OPT_MAX_GET_SESSIONS sessions and the oidkey to use
// to resume.
//
_tt_get_all_sessions_results *
_tt_get_all_sessions_1(_tt_get_all_sessions_args * args,
SVCXPRT * /*NOTUSED*/)
{
static _tt_get_all_sessions_results results;
static _Tt_string_list *list;
list = new _Tt_string_list;
int offset;
int isfd;
int recordCount = 0;
int propLen = strlen(propTable);
char * lastSlash;
char * pathName;
_Tt_string propValue;
Table_oid_prop record;
//
// Empty out any existing session or key results.
//
list->flush();
if (results.oidkey.oidkey_val != NULL) {
free((char *)results.oidkey.oidkey_val);
}
for (offset = 0 ; offset < list->count() ; offset++) {
if (results.session_list.values_val[offset].value != NULL) {
free(results.session_list.values_val[offset].value);
}
}
if (results.session_list.values_val != NULL) {
free((char *)results.session_list.values_val);
results.session_list.values_val = NULL;
}
memset(&results.oidkey, '\0', sizeof(results.oidkey));
//
// For each property_table that we manage,
// pull out all of the session-ids and pass them back (up
// to OPT_MAX_GET_SESSIONS passed back in each call)
//
for (offset = 0 ; offset < _TT_MAX_ISFD; offset++) {
pathName = _tt_db_table[offset].db_path;
if (pathName && strlen(pathName) > 0) {
if (_tt_db_table[offset].client_has_open
|| _tt_db_table[offset].server_has_open) {
//
// Is the file name ".../property_table*" ?
//
lastSlash = strrchr(pathName, '/');
if (lastSlash) {
lastSlash++;
if (strncmp(propTable, lastSlash, propLen) == 0) {
// Get the FD and process the file.
isfd = cached_isopen(pathName, ISINOUT);
//
// If the user passed in a starting key,
// then use it.
//
if (args->oidkey.oidkey_len > 0
&& args->oidkey.oidkey_val != NULL) {
issetcurpos(isfd,
(char *)args->oidkey.oidkey_val);
}
//
// Get the 1st record.
//
isread(isfd, (char *)&record, ISFIRST);
((char *)(&record))[isreclen] = '\0';
if (strcmp(sesProp, record.propname) == 0) {
propValue = record.propval;
// Append it to the list to send back.
recordCount++;
list->append(propValue);
memset(&record, '\0', sizeof(record));
}
while(isread(isfd, (char *)&record,ISNEXT) != -1) {
((char *)(&record))[isreclen] = '\0';
if (strcmp(sesProp, record.propname) == 0) {
propValue = record.propval;
list->append(propValue);
if (++recordCount > OPT_MAX_GET_SESSIONS-1) {
results.oidkey.oidkey_val = NULL;
isgetcurpos(isfd,
(int *)&results.oidkey.oidkey_len,
(char **)&results.oidkey.oidkey_val);
break;
}
}
memset(&record, '\0', sizeof(record));
}
cached_isclose(isfd);
if (recordCount > OPT_MAX_GET_SESSIONS-1) {
break;
}
}
}
}
}
}
results.session_list.values_len = list->count();
if (results.session_list.values_len > 0) {
results.session_list.values_val = (_tt_string *)malloc(sizeof(_tt_string *) * list->count());
} else {
results.session_list.values_val = (_tt_string *)NULL;
}
for (offset = 0 ; offset < results.session_list.values_len ; offset++) {
propValue = list->top();
results.session_list.values_val[offset].value = strdup(propValue);
list->pop();
}
return(&results);
}
_tt_garbage_collect_results *
_tt_garbage_collect_1(void * /*NOTUSED*/,
SVCXPRT * /*NOTUSED*/)
{
static _tt_garbage_collect_results results;
memset(&results, '\0', sizeof(_tt_garbage_collect_results));
#if defined(OPT_GARBAGE_THREADS)
int id;
//
// Collect the garbage and delete old sessions in
// a seperate thread. As soon as the thread is started
// this function returns and the dbserver is again
// processing user requests.
id = _tt_run_garbage_collect(OPT_GARBAGE_IN_PARALLEL);
results.tt_status = (id >= 0) ? TT_OK : TT_ERR_INTERNAL;
#else
//
// Without threads, just compress (isgarbage) the
// db files. The user program will check for and
// delete old sessions.
//
isgarbage_collect();
results.tt_status = TT_OK;
#endif
return(&results);
}
//
// ******* Static helper functions start here *******
//
bool_t _tt_is_file_a_directory (const _Tt_string &file)
{
// This is sometimes called with a network path and a non-network path.
// Make sure we always give stat a non-network path.
char *slash = strchr((char *)file, '/');
char *path = strchr((char *)file, ':');
if (path != slash-1) {
path = (char *)NULL;
}
DIR *dd = opendir(path ? path+1 : (char *)file);
if (dd) {
(void)closedir(dd);
}
return (dd ? TRUE : FALSE);
}
// Replace the old partition with the new partition in the object ID
static _Tt_string _tt_make_equivalent_object_id (const _Tt_string &objid,
const _Tt_string &partition)
{
_Tt_string temp_string = (char *)objid;
_Tt_string new_objid;
temp_string = temp_string.rsplit (':', new_objid);
new_objid = new_objid.cat(partition);
return new_objid;
}
static _Tt_db_results _tt_get_partition_db (const _Tt_string &partition,
_Tt_db_server_db_ptr &db)
{
_Tt_db_partition_global_map_ref db_map;
_Tt_db_results results = TT_DB_OK;
db = db_map.getDB(partition);
if (db.is_null()) {
results = TT_DB_ERR_DB_OPEN_FAILED;
}
return results;
}
static _Tt_db_access_ptr _tt_get_real_rpc_access (const _tt_access &rpc_access)
{
_Tt_db_access_ptr accessPtr;
_tt_get_rpc_access(rpc_access, accessPtr);
accessPtr->user = _tt_uid;
accessPtr->group = (gid_t)-1;
// Make sure the group ID is valid before using it
for (int i=0; i < _tt_gidlen; i++) {
if (_tt_gidlist [i] == _tt_gid) {
accessPtr->group = _tt_gid;
}
}
return accessPtr;
}
static _Tt_db_access_ptr _tt_get_file_access (const _Tt_string &file,
const _tt_access &rpc_access)
{
_Tt_db_access_ptr accessPtr = _tt_get_unix_file_access(file);
if (accessPtr.is_null()) {
accessPtr = _tt_get_real_rpc_access(rpc_access);
}
else {
accessPtr->mode = (mode_t)-1;
}
return accessPtr;
}
static _Tt_db_access_ptr _tt_get_unix_file_access (const _Tt_string &file)
{
_Tt_db_access_ptr accessPtr;
struct stat stat_buf;
// Make sure we always give stat a non-network path.
_Tt_string local_path = file;
if (_tt_is_network_path(file)) {
_Tt_string temp_string;
local_path = local_path.split(':', temp_string);
}
if (!stat((char *)local_path, &stat_buf)) {
accessPtr = new _Tt_db_access;
accessPtr->user = stat_buf.st_uid;
accessPtr->group = stat_buf.st_gid;
accessPtr->mode = stat_buf.st_mode;
}
return accessPtr;
}
static _Tt_string _tt_get_file_partition (const _Tt_string &file)
{
_Tt_string temp_string;
_Tt_string local_path = file;
local_path = local_path.split(':', temp_string);
_Tt_file_system fs;
_Tt_file_system_entry_ptr entry = fs.bestMatchToPath(local_path);
return entry->getMountPoint();
}
static _Tt_db_results
_tt_increment_file_properties_cache_level
(const _Tt_db_server_db_ptr &db,
const _Tt_string &file,
const _Tt_db_access_ptr &accessPtr,
int &cache_level)
{
cache_level = -1;
_Tt_db_property_ptr property;
_Tt_db_results results =
db->getFileProperty(file,
TT_DB_PROPS_CACHE_LEVEL_PROPERTY,
accessPtr,
property);
if (results == TT_DB_OK) {
_Tt_string cache_level_bytes = (*property->values) [0];
memcpy ((char *)&cache_level, (char *)cache_level_bytes, sizeof(int));
cache_level++;
memcpy ((char *)cache_level_bytes, (char *)&cache_level, sizeof(int));
(*property->values) [0] = cache_level_bytes;
results = db->setFileProperty(file,
property,
accessPtr);
if (results != TT_DB_OK) {
cache_level = -1;
results = TT_DB_ERR_PROPS_CACHE_ERROR;
}
}
else if (results == TT_DB_ERR_NO_SUCH_PROPERTY) {
cache_level = 0;
_Tt_string value(sizeof(int));
memcpy((char *)value, (char *)&cache_level, sizeof(int));
_Tt_db_property_ptr property = new _Tt_db_property;
property->name = TT_DB_PROPS_CACHE_LEVEL_PROPERTY;
property->values->append(value);
results = db->setFileProperty(file,
property,
accessPtr);
if (results != TT_DB_OK) {
cache_level = -1;
results = TT_DB_ERR_PROPS_CACHE_ERROR;
}
}
else {
results = TT_DB_ERR_PROPS_CACHE_ERROR;
}
return results;
}
static _Tt_db_results
_tt_get_file_properties_cache_level (const _Tt_db_server_db_ptr &db,
const _Tt_string &file,
const _Tt_db_access_ptr &accessPtr,
int &cache_level)
{
cache_level = -1;
_Tt_db_property_ptr property;
_Tt_db_results results =
db->getFileProperty(file,
TT_DB_PROPS_CACHE_LEVEL_PROPERTY,
accessPtr,
property);
if (results == TT_DB_OK) {
_Tt_string cache_level_bytes = (*property->values) [0];
memcpy ((char *)&cache_level, (char *)cache_level_bytes, sizeof(int));
}
// The file was probably created for an object. The cache level
// was never stored as a property...
else if (results == TT_DB_ERR_NO_SUCH_PROPERTY) {
results = _tt_increment_file_properties_cache_level(db,
file,
accessPtr,
cache_level);
}
else {
results = TT_DB_ERR_PROPS_CACHE_ERROR;
}
return results;
}
static _Tt_string _tt_get_object_partition (const _Tt_string &objid)
{
_Tt_string partition = (char *)objid;
_Tt_string temp_string;
// Get rid of file system type and hostname - the partition
// is the only thing left
partition = partition.split(':', temp_string);
partition = partition.split(':', temp_string);
partition = partition.split(':', temp_string);
return partition;
}
static _Tt_db_results
_tt_increment_object_properties_cache_level
(const _Tt_db_server_db_ptr &db,
const _Tt_string &objid,
const _Tt_db_access_ptr &accessPtr,
int &cache_level)
{
cache_level = -1;
_Tt_db_property_ptr property;
_Tt_db_results results =
db->getObjectProperty(objid,
TT_DB_PROPS_CACHE_LEVEL_PROPERTY,
accessPtr,
property);
if (results == TT_DB_OK) {
_Tt_string cache_level_bytes = (*property->values) [0];
memcpy ((char *)&cache_level, (char *)cache_level_bytes, sizeof(int));
cache_level++;
memcpy ((char *)cache_level_bytes, (char *)&cache_level, sizeof(int));
(*property->values) [0] = cache_level_bytes;
results = db->setObjectProperty(objid,
property,
accessPtr);
if (results != TT_DB_OK) {
cache_level = -1;
results = TT_DB_ERR_PROPS_CACHE_ERROR;
}
}
else if (results == TT_DB_ERR_NO_SUCH_PROPERTY) {
cache_level = 0;
_Tt_string value(sizeof(int));
memcpy((char *)value, (char *)&cache_level, sizeof(int));
_Tt_db_property_ptr property = new _Tt_db_property;
property->name = TT_DB_PROPS_CACHE_LEVEL_PROPERTY;
property->values->append(value);
results = db->setObjectProperty(objid,
property,
accessPtr);
if (results != TT_DB_OK) {
cache_level = -1;
results = TT_DB_ERR_PROPS_CACHE_ERROR;
}
}
else {
results = TT_DB_ERR_PROPS_CACHE_ERROR;
}
return results;
}
static _Tt_db_results
_tt_get_object_properties_cache_level (const _Tt_db_server_db_ptr &db,
const _Tt_string &objid,
const _Tt_db_access_ptr &accessPtr,
int &cache_level)
{
cache_level = -1;
_Tt_db_property_ptr property;
_Tt_db_results results =
db->getObjectProperty(objid,
TT_DB_PROPS_CACHE_LEVEL_PROPERTY,
accessPtr,
property);
if (results == TT_DB_OK) {
_Tt_string cache_level_bytes = (*property->values) [0];
memcpy ((char *)&cache_level, (char *)cache_level_bytes, sizeof(int));
}
else {
results = TT_DB_ERR_PROPS_CACHE_ERROR;
}
return results;
}
static void
_tt_screen_object_properties (_Tt_db_property_list_ptr &properties)
{
_Tt_db_property_list_cursor properties_cursor (properties);
while (properties_cursor.next ()) {
if (properties_cursor->name == TT_DB_PROPS_CACHE_LEVEL_PROPERTY) {
properties_cursor.remove ();
}
else if (properties_cursor->name == TT_DB_OBJECT_TYPE_PROPERTY) {
properties_cursor.remove ();
}
}
if (properties->count () == 0) {
properties = (_Tt_db_property_list *)NULL;
}
}
static _Tt_string _tt_get_local_path (const _Tt_string &network_path,
_Tt_string &hostname,
_Tt_string &partition)
{
_Tt_string temp_string = network_path;
_Tt_string local_path = _tt_realpath (temp_string.split(':', hostname));
_Tt_file_system file_system;
_Tt_file_system_entry_ptr entry = file_system.bestMatchToPath(local_path);
partition = entry->getMountPoint();
_Tt_string loop_back_mount_point = entry->getLoopBackMountPoint();
if (loop_back_mount_point.len()) {
// Get the path info after the loop back mount point path
local_path = local_path.right(local_path.len()-loop_back_mount_point.len());
// Replace the loop back mount point path with the partition path
local_path = partition.cat(local_path);
}
return local_path;
}
//
// This is the thread that performs the garbage collection.
// It is defined as a (void *) function for thr_create() compatibility.
//
static void *
_tt_garbage_collect(void * /*NOTUSED*/)
{
// thr_create() func returns (void *).
void * results = NULL;
_tt_get_all_sessions_args args;
_Tt_string sessionId;
_Tt_string_list *sessions;
memset(&args, '\0', sizeof(args));
#if defined(OPT_GARBAGE_THREADS)
sigset_t new_thr_sigset;
//
// Tell ourself (this thread only) to ignore all SIGs, or quit.
//
if (sigfillset(&new_thr_sigset) != 0) {
return(results);
}
if (thr_sigsetmask(SIG_BLOCK, &new_thr_sigset, NULL) < 0) {
return(results);
}
LOCK_RPC();
isgarbage_collect(); // 1st compress the DB files.
UNLOCK_RPC();
#else
_Tt_db_client_ptr dbClient;
if (!dbClient.is_null()
&& dbClient->getConnectionResults() == TT_DB_OK) {
// Tell server to compress the files.
dbClient->garbage_collect_in_server();
#endif
// Get a list of all sessions.
do {
LOCK_RPC();
#if defined(OPT_GARBAGE_THREADS)
_tt_get_all_sessions_results *sessionList;
sessionList = _tt_get_all_sessions_1(&args, NULL);
int offset;
_Tt_string oneSession;
sessions = new _Tt_string_list;
for (offset = 0
; offset < sessionList->session_list.values_len
; offset++) {
oneSession = sessionList->session_list.values_val[offset].value;
sessions->append(oneSession);
}
#else
sessions = dbClient->get_all_sessions();
#endif
if (sessions== NULL || sessions->count() == 0) {
UNLOCK_RPC();
break;
}
UNLOCK_RPC();
// Delete the list of sessions that are dead.
do {
Tt_status ttstatus;
#if defined(OPT_GARBAGE_THREADS)
_tt_delete_session_args delsession;
#endif
sessionId = sessions->top();
if ((ttstatus=tt_default_session_set(sessionId)) != TT_OK) {
#if defined(OPT_GARBAGE_THREADS)
delsession.session.value = sessionId;
_tt_delete_session_1(&delsession,NULL);
#else
dbClient->delete_session(sessionId);
#endif
}
sessions->pop();
} while(sessions->count() > 0);
#if defined(OPT_GARBAGE_THREADS)
//
// Copy over the re-start key.
// (for more than OPT_MAX_GET_SESSIONS).
memcpy(&args.oidkey,
&sessionList->oidkey,
sizeof(args.oidkey));
#endif
} while (args.oidkey.oidkey_len != 0);
#if defined(OPT_GARBAGE_THREADS)
mutex_unlock(&garbage_run_in_process);
#else
}
#endif
return(results);
}
//
// Return the PID or TID of the running garbage collection function.
//
int
_tt_run_garbage_collect(int in_parallel)
{
extern FILE *errstr;
/* Make sure in_parallel is used to quiet warnings */
if (in_parallel) {}
#if defined(OPT_GARBAGE_THREADS)
static int mutex_inited = 0;
// Error back from mutex_*() and thr_() funcs.
int err;
// Times to try thr_create() if it return with EAGAIN.
int create_tries = OPT_SOLARIS_THREADED_TRIES;
if (!mutex_inited) {
mutex_inited = 1;
// Init the RPC syncronazation mutex lock.
mutex_init(&rpc_client_busy, USYNC_THREAD, 0);
mutex_init(&garbage_run_in_process, USYNC_PROCESS, 0);
// Raise the priority of ourselfs to be higher
// than our new thread.
thr_setprio(thr_self(), 10);
}
//
// See if anyone else is running, if so, then do not run
// gabage collection again.
//
if (mutex_trylock(&garbage_run_in_process) != 0) {
return (_tt_garbage_id);
}
//
//
// Start the thread and keep trying OPT_SOLARIS_THREADED_TRIES,
// or until it works.
//
while ((err = thr_create((void *)0, // stack_base - use default.
(size_t)0, // stack_size - use default.
_tt_garbage_collect,
(void *)_TT_GARBAGE_COLLECTION_FREQUENCY,// Arg to func.
THR_SUSPENDED|THR_BOUND,
(thread_t *)&_tt_garbage_id)) < 0) {
if (errno == EAGAIN && (--create_tries > 0)) {
thr_yield();
continue;
}
_tt_garbage_id = -2;
//
// Get here only on thr_create() error.
// Unable to create thread.
//
_tt_syslog(errstr, LOG_ERR, "%s",
catgets(_ttcatd, 5, 8,
"Unable to start garbage collection thread. thr_create()\n"));
}
//
// If we are to garbage collect in parallel, then
// let the garbage thread continue at a low priority.
//
// If we are not to garbage collect in parallel,
// then let the thread run, then the main thread exits.
//
if (in_parallel == TRUE) {
if (_tt_garbage_id > 0) {
// Lower the priority of garbage collection to lowest.
thr_setprio(_tt_garbage_id, 0);
// And start it.
thr_continue((thread_t)_tt_garbage_id);
}
} else {
if (_tt_garbage_id > 0) {
thr_continue((thread_t)_tt_garbage_id);
thr_yield();
thr_exit(0);
} else {
thr_exit(0);
}
}
#else //defined(OPT_GARBAGE_THREADS)
#if defined(OPT_AUTO_GARBAG_COLLECT)
//
// Do not start another, if one is running.
//
if (in_parallel == TRUE) {
if (_tt_garbage_id == -1) {
//
// FORK and EXEC ourself '-G'.
//
#if defined(OPT_BUG_AIX) || defined(OPT_BUG_USL) || defined(OPT_BUG_UXP)
#define vfork fork
#endif
switch (_tt_garbage_id = (int)vfork()) {
case 0: // child
{
const char *newargv[3];
newargv[0] = global_argv[0];
newargv[1] = "-G";
newargv[2] = NULL;
execve((const char *)newargv[0],
(char *const *)newargv,
(char *const *)global_envp);
_tt_syslog(errstr, LOG_ERR, "%s",
catgets(_ttcatd, 5, 9,
"Unable to fork() for garbage collection.\n"));
_tt_garbage_id = -3;
_exit(1); // ERROR, so exit new child.
}
break;
case -1: // Error.
_tt_syslog(errstr, LOG_ERR, "%s",
catgets(_ttcatd, 5, 9,
"Unable to fork() for garbage collection.\n"));
_tt_garbage_id = -4;
break;
default: // Parent.
break;
}
}
} else {
#endif /* OPT_AUTO_GARBAGE_COLLECT*/
exit((intptr_t)_tt_garbage_collect(NULL));
#if defined(OPT_AUTO_GARBAG_COLLECT)
}
#endif /* OPT_AUTO_GARBAGE_COLLECT*/
#endif // ! OPT_GARBAGE_THREADS
return (_tt_garbage_id);
}