/*
* Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
* Copyright (c) 2013-2016 Carbonite, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information: Carbonite Inc., 756 N Pastoria Ave
* Sunnyvale, CA 94085, or: http://www.zmanda.com
*/
#include "amanda.h"
#include "property.h"
#include "glib-util.h"
/*****
* Property-specific Types, etc.
*/
static const GEnumValue _concurrency_paradigm_values[] = {
{ CONCURRENCY_PARADIGM_EXCLUSIVE,
"CONCURRENCY_PARADIGM_EXCLUSIVE",
"exclusive" },
{ CONCURRENCY_PARADIGM_SHARED_READ,
"CONCURRENCY_PARADIGM_SHARED_READ",
"shared-read" },
{ CONCURRENCY_PARADIGM_RANDOM_ACCESS,
"CONCURRENCY_PARADIGM_RANDOM_ACCESS",
"random-access" },
{ 0, NULL, NULL }
};
GType concurrency_paradigm_get_type (void) {
static GType type = 0;
if (G_UNLIKELY(type == 0)) {
type = g_enum_register_static ("ConcurrencyParadigm",
_concurrency_paradigm_values);
}
return type;
}
static const GEnumValue _streaming_requirement_values[] = {
{ STREAMING_REQUIREMENT_NONE,
"STREAMING_REQUIREMENT_NONE",
"none" },
{ STREAMING_REQUIREMENT_DESIRED,
"STREAMING_REQUIREMENT_DESIRED",
"desired" },
{ STREAMING_REQUIREMENT_REQUIRED,
"STREAMING_REQUIREMENT_REQUIRED",
"required" },
{ 0, NULL, NULL }
};
GType streaming_requirement_get_type (void) {
static GType type = 0;
if (G_UNLIKELY(type == 0)) {
type = g_enum_register_static ("StreamingRequirement",
_streaming_requirement_values);
}
return type;
}
static const GEnumValue _media_access_mode_values[] = {
{ MEDIA_ACCESS_MODE_READ_ONLY,
"MEDIA_ACCESS_MODE_READ_ONLY",
(char *)"read-only" },
{ MEDIA_ACCESS_MODE_WORM,
"MEDIA_ACCESS_MODE_WORM",
(char *)"write-once-read-many" },
{ MEDIA_ACCESS_MODE_READ_WRITE,
"MEDIA_ACCESS_MODE_READ_WRITE",
(char *)"read-write" },
{ MEDIA_ACCESS_MODE_WRITE_ONLY,
"MEDIA_ACCESS_MODE_WRITE_ONLY",
(char *)"write-many-read-never" },
{ 0, NULL, NULL }
};
GType media_access_mode_get_type (void) {
static GType type = 0;
if (G_UNLIKELY(type == 0)) {
type = g_enum_register_static ("MediaAccessMode",
_media_access_mode_values);
}
return type;
}
/******
* Property registration and lookup
*/
static GPtrArray *device_property_bases = NULL;
static GHashTable *device_property_bases_by_name = NULL;
DevicePropertyBase* device_property_get_by_id(DevicePropertyId id) {
if (!device_property_bases || id >= device_property_bases->len)
return NULL;
return g_ptr_array_index(device_property_bases, id);
}
DevicePropertyBase* device_property_get_by_name(const char *name) {
gpointer rv;
if (!device_property_bases_by_name)
return NULL;
rv = g_hash_table_lookup(device_property_bases_by_name, name);
if (rv)
return (DevicePropertyBase *)rv;
return NULL;
}
#define toupper_and_underscore(c) (((c)=='-')? '_' : g_ascii_toupper((c)))
static guint
device_property_hash(
gconstpointer key)
{
/* modified version of glib's hash function, copyright
* GLib Team and others 1997-2000. */
const char *p = key;
guint h = toupper_and_underscore(*p);
if (h)
for (p += 1; *p != '\0'; p++)
h = (h << 5) - h + toupper_and_underscore(*p);
return h;
}
static gboolean
device_property_equal(
gconstpointer v1,
gconstpointer v2)
{
const char *s1 = v1, *s2 = v2;
while (*s1 && *s2) {
if (toupper_and_underscore(*s1) != toupper_and_underscore(*s2))
return FALSE;
s1++, s2++;
}
if (*s1 || *s2)
return FALSE;
return TRUE;
}
void
device_property_fill_and_register(DevicePropertyBase *base,
GType type, const char * name, const char * desc) {
/* create the hash table and array if necessary */
if (!device_property_bases) {
device_property_bases = g_ptr_array_new();
device_property_bases_by_name = g_hash_table_new(device_property_hash, device_property_equal);
}
/* check for a duplicate */
if (device_property_get_by_name(name)) {
g_critical("A property named '%s' already exists!", name);
}
/* allocate space for this DPB and fill it in */
base->ID = device_property_bases->len;
base->type = type;
base->name = name; /* no strdup -- it's statically allocated */
base->description = desc; /* ditto */
/* add it to the array and hash table; note that its array index and its
* ID are the same. */
g_ptr_array_add(device_property_bases, base);
g_hash_table_insert(device_property_bases_by_name, (gpointer)name, (gpointer)base);
}
/******
* Initialization
*/
void device_property_init(void) {
device_property_fill_and_register(&device_property_concurrency,
CONCURRENCY_PARADIGM_TYPE, "concurrency",
"Supported concurrency mode (none, multiple readers, multiple writers)");
device_property_fill_and_register(&device_property_streaming,
STREAMING_REQUIREMENT_TYPE, "streaming",
"Streaming desirability (unnecessary, desired, required)");
device_property_fill_and_register(&device_property_compression,
G_TYPE_BOOLEAN, "compression",
"Is device performing data compression?");
device_property_fill_and_register(&device_property_compression_rate,
G_TYPE_DOUBLE, "compression_rate",
"Compression rate, "
"averaged for some (currently undefined) period of time)");
device_property_fill_and_register(&device_property_block_size,
G_TYPE_INT, "block_size",
"Block size to use while writing.");
device_property_fill_and_register(&device_property_min_block_size,
G_TYPE_UINT, "min_block_size",
"Minimum supported blocking factor.");
device_property_fill_and_register(&device_property_max_block_size,
G_TYPE_UINT, "max_block_size",
"Maximum supported blocking factor.");
device_property_fill_and_register(&device_property_read_block_size,
G_TYPE_UINT, "read_block_size",
"Minimum size of a read for this device (maximum expected block size)");
device_property_fill_and_register(&device_property_appendable,
G_TYPE_BOOLEAN, "appendable",
"Does device support appending to previously-written media?");
device_property_fill_and_register(&device_property_canonical_name,
G_TYPE_STRING, "canonical_name",
"The most reliable device name to use to refer to this device.");
device_property_fill_and_register(&device_property_medium_access_type,
MEDIA_ACCESS_MODE_TYPE,
"medium_access_type",
"What kind of media (RO/WORM/RW/WORN) do we have here?");
device_property_fill_and_register(&device_property_partial_deletion,
G_TYPE_BOOLEAN, "partial_deletion",
"Does this device support recycling just part of a volume?" );
device_property_fill_and_register(&device_property_full_deletion,
G_TYPE_BOOLEAN, "full_deletion",
"Does this device support recycling the entire volume?" );
device_property_fill_and_register(&device_property_max_volume_usage,
G_TYPE_UINT64, "max_volume_usage",
"Artificial limit to data written to volume.");
device_property_fill_and_register(&device_property_enforce_max_volume_usage,
G_TYPE_BOOLEAN, "enforce_max_volume_usage",
"Does max_volume_usage enabled?");
device_property_fill_and_register(&device_property_verbose,
G_TYPE_BOOLEAN, "verbose",
"Should the device produce verbose output?");
device_property_fill_and_register(&device_property_comment,
G_TYPE_STRING, "comment",
"User-specified comment for the device");
device_property_fill_and_register(&device_property_leom,
G_TYPE_BOOLEAN, "leom",
"Does this device support LEOM?");
device_property_fill_and_register(&device_property_reuse_connection,
G_TYPE_BOOLEAN, "reuse_connection",
"Whether to reuse connection");
device_property_fill_and_register(&device_property_max_send_speed,
G_TYPE_UINT64, "max_send_speed",
"Maximum average upload speed (bytes/sec)");
device_property_fill_and_register(&device_property_max_recv_speed,
G_TYPE_UINT64, "max_recv_speed",
"Maximum average download speed (bytes/sec)");
device_property_fill_and_register(&device_property_nb_threads_backup,
G_TYPE_UINT64, "nb_threads_backup",
"Number of writer thread");
device_property_fill_and_register(&device_property_nb_threads_recovery,
G_TYPE_UINT64, "nb_threads_recovery",
"Number of reader thread");
device_property_fill_and_register(&device_property_multi_part_upload,
G_TYPE_BOOLEAN, "multi_part_upload",
"Whether to use multi part upload");
device_property_fill_and_register(&device_property_ssl_ca_info,
G_TYPE_STRING, "ssl_ca_info",
"Path to certificate authority certificate");
device_property_fill_and_register(&device_property_proxy,
G_TYPE_STRING, "proxy",
"The proxy");
}
DevicePropertyBase device_property_concurrency;
DevicePropertyBase device_property_streaming;
DevicePropertyBase device_property_compression;
DevicePropertyBase device_property_compression_rate;
DevicePropertyBase device_property_block_size;
DevicePropertyBase device_property_min_block_size;
DevicePropertyBase device_property_max_block_size;
DevicePropertyBase device_property_read_block_size;
DevicePropertyBase device_property_appendable;
DevicePropertyBase device_property_canonical_name;
DevicePropertyBase device_property_medium_access_type;
DevicePropertyBase device_property_partial_deletion;
DevicePropertyBase device_property_full_deletion;
DevicePropertyBase device_property_max_volume_usage;
DevicePropertyBase device_property_enforce_max_volume_usage;
DevicePropertyBase device_property_comment;
DevicePropertyBase device_property_leom;
DevicePropertyBase device_property_verbose;
DevicePropertyBase device_property_reuse_connection;
DevicePropertyBase device_property_max_send_speed;
DevicePropertyBase device_property_max_recv_speed;
DevicePropertyBase device_property_nb_threads_backup;
DevicePropertyBase device_property_nb_threads_recovery;
DevicePropertyBase device_property_multi_part_upload;
DevicePropertyBase device_property_ssl_ca_info;
DevicePropertyBase device_property_proxy;