a2f4c57b98ca8e2e447678ae2456aad5215b9d0d
[debian/amanda] / device-src / property.c
1 /*
2  * Copyright (c) 2007,2008,2009 Zmanda, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 as published
6  * by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16  *
17  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
19  */
20
21 #include "amanda.h"
22
23 #include "property.h"
24 #include "glib-util.h"
25
26 /*****
27  * Property-specific Types, etc.
28  */
29
30 static const GEnumValue _concurrency_paradigm_values[] = {
31         { CONCURRENCY_PARADIGM_EXCLUSIVE,
32           "CONCURRENCY_PARADIGM_EXCLUSIVE",
33           "exclusive" },
34         { CONCURRENCY_PARADIGM_SHARED_READ,
35           "CONCURRENCY_PARADIGM_SHARED_READ",
36           "shared-read" },
37         { CONCURRENCY_PARADIGM_RANDOM_ACCESS,
38           "CONCURRENCY_PARADIGM_RANDOM_ACCESS",
39           "random-access" },
40         { 0, NULL, NULL }
41 };
42
43 GType concurrency_paradigm_get_type (void) {
44     static GType type = 0;
45     if (G_UNLIKELY(type == 0)) {
46         type = g_enum_register_static ("ConcurrencyParadigm",
47                                        _concurrency_paradigm_values);
48     }
49     return type;
50 }
51
52 static const GEnumValue _streaming_requirement_values[] = {
53         { STREAMING_REQUIREMENT_NONE,
54           "STREAMING_REQUIREMENT_NONE",
55           "none" },
56         { STREAMING_REQUIREMENT_DESIRED,
57           "STREAMING_REQUIREMENT_DESIRED",
58           "desired" },
59         { STREAMING_REQUIREMENT_REQUIRED,
60           "STREAMING_REQUIREMENT_REQUIRED",
61           "required" },
62         { 0, NULL, NULL }
63 };
64
65 GType streaming_requirement_get_type (void) {
66     static GType type = 0;
67     if (G_UNLIKELY(type == 0)) {
68         type = g_enum_register_static ("StreamingRequirement",
69                                        _streaming_requirement_values);
70     }
71     return type;
72 }
73
74 static const GEnumValue _media_access_mode_values[] = {
75         { MEDIA_ACCESS_MODE_READ_ONLY,
76           "MEDIA_ACCESS_MODE_READ_ONLY",
77           (char *)"read-only" },
78         { MEDIA_ACCESS_MODE_WORM,
79           "MEDIA_ACCESS_MODE_WORM",
80           (char *)"write-once-read-many" },
81         { MEDIA_ACCESS_MODE_READ_WRITE,
82           "MEDIA_ACCESS_MODE_READ_WRITE",
83           (char *)"read-write" },
84         { MEDIA_ACCESS_MODE_WRITE_ONLY,
85           "MEDIA_ACCESS_MODE_WRITE_ONLY",
86           (char *)"write-many-read-never" },
87         { 0, NULL, NULL }
88 };
89
90 GType media_access_mode_get_type (void) {
91     static GType type = 0;
92     if (G_UNLIKELY(type == 0)) {
93         type = g_enum_register_static ("MediaAccessMode",
94                                        _media_access_mode_values);
95     }
96     return type;
97 }
98
99 /* Copy function for GBoxed QualifiedSize. */
100 static gpointer qualified_size_copy(gpointer source) {
101     gpointer rval = g_new(QualifiedSize, 1);
102     memcpy(rval, source, sizeof(QualifiedSize));
103     return rval;
104 }
105
106 GType qualified_size_get_type (void) {
107     static GType type = 0;
108     if (G_UNLIKELY(type == 0)) {
109         type = g_boxed_type_register_static ("QualifiedSize",
110                                              qualified_size_copy,
111                                              free);
112     }
113     return type;
114 }
115
116 /******
117  * Property registration and lookup
118  */
119
120 static GPtrArray *device_property_bases = NULL;
121 static GHashTable *device_property_bases_by_name = NULL;
122
123 DevicePropertyBase* device_property_get_by_id(DevicePropertyId id) {
124     if (!device_property_bases || id >= device_property_bases->len)
125         return NULL;
126
127     return g_ptr_array_index(device_property_bases, id);
128 }
129
130 DevicePropertyBase* device_property_get_by_name(const char *name) {
131     gpointer rv;
132
133     if (!device_property_bases_by_name)
134         return NULL;
135
136     rv = g_hash_table_lookup(device_property_bases_by_name, name);
137     if (rv)
138         return (DevicePropertyBase *)rv;
139
140     return NULL;
141 }
142
143 #define toupper_and_underscore(c) (((c)=='-')? '_' : g_ascii_toupper((c)))
144 static guint
145 device_property_hash(
146         gconstpointer key)
147 {
148     /* modified version of glib's hash function, copyright
149      * GLib Team and others 1997-2000. */
150     const char *p = key;
151     guint h = toupper_and_underscore(*p);
152
153     if (h)
154         for (p += 1; *p != '\0'; p++)
155             h = (h << 5) - h + toupper_and_underscore(*p);
156
157     return h;
158 }
159
160 static gboolean
161 device_property_equal(
162         gconstpointer v1,
163         gconstpointer v2)
164 {
165     const char *s1 = v1, *s2 = v2;
166
167     while (*s1 && *s2) {
168         if (toupper_and_underscore(*s1) != toupper_and_underscore(*s2))
169             return FALSE;
170         s1++, s2++;
171     }
172     if (*s1 || *s2)
173         return FALSE;
174
175     return TRUE;
176 }
177
178 void
179 device_property_fill_and_register(DevicePropertyBase *base,
180                     GType type, const char * name, const char * desc) {
181
182     /* create the hash table and array if necessary */
183     if (!device_property_bases) {
184         device_property_bases = g_ptr_array_new();
185         device_property_bases_by_name = g_hash_table_new(device_property_hash, device_property_equal);
186     }
187
188     /* check for a duplicate */
189     if (device_property_get_by_name(name)) {
190         g_critical("A property named '%s' already exists!", name);
191     }
192
193     /* allocate space for this DPB and fill it in */
194     base->ID = device_property_bases->len;
195     base->type = type;
196     base->name = name; /* no strdup -- it's statically allocated */
197     base->description = desc; /* ditto */
198
199     /* add it to the array and hash table; note that its array index and its
200      * ID are the same. */
201     g_ptr_array_add(device_property_bases, base);
202     g_hash_table_insert(device_property_bases_by_name, (gpointer)name, (gpointer)base);
203 }
204
205 /******
206  * Initialization
207  */
208
209 void device_property_init(void) {
210     device_property_fill_and_register(&device_property_concurrency,
211                                       CONCURRENCY_PARADIGM_TYPE, "concurrency",
212       "Supported concurrency mode (none, multiple readers, multiple writers)");
213     device_property_fill_and_register(&device_property_streaming,
214                                       STREAMING_REQUIREMENT_TYPE, "streaming",
215       "Streaming desirability (unnecessary, desired, required)");
216     device_property_fill_and_register(&device_property_compression,
217                                       G_TYPE_BOOLEAN, "compression",
218       "Is device performing data compression?");
219     device_property_fill_and_register(&device_property_compression_rate,
220                                       G_TYPE_DOUBLE, "compression_rate",
221       "Compression rate, "
222           "averaged for some (currently undefined) period of time)");
223     device_property_fill_and_register(&device_property_block_size,
224                                       G_TYPE_INT, "block_size",
225                                       "Block size to use while writing.");
226     device_property_fill_and_register(&device_property_min_block_size,
227                                       G_TYPE_UINT, "min_block_size",
228       "Minimum supported blocking factor.");
229     device_property_fill_and_register(&device_property_max_block_size,
230                                       G_TYPE_UINT, "max_block_size",
231       "Maximum supported blocking factor.");
232     device_property_fill_and_register(&device_property_read_block_size,
233                                       G_TYPE_UINT, "read_block_size",
234       "Minimum size of a read for this device (maximum expected block size)");
235     device_property_fill_and_register(&device_property_appendable,
236                                       G_TYPE_BOOLEAN, "appendable",
237       "Does device support appending to previously-written media?");
238     device_property_fill_and_register(&device_property_canonical_name,
239                                       G_TYPE_STRING, "canonical_name",
240       "The most reliable device name to use to refer to this device.");
241     device_property_fill_and_register(&device_property_medium_access_type,
242                                       MEDIA_ACCESS_MODE_TYPE,
243                                       "medium_access_type",
244       "What kind of media (RO/WORM/RW/WORN) do we have here?");
245     device_property_fill_and_register(&device_property_partial_deletion,
246                                      G_TYPE_BOOLEAN, "partial_deletion",
247       "Does this device support recycling just part of a volume?" );
248     device_property_fill_and_register(&device_property_full_deletion,
249                                      G_TYPE_BOOLEAN, "full_deletion",
250       "Does this device support recycling the entire volume?" );
251     device_property_fill_and_register(&device_property_free_space,
252                                       QUALIFIED_SIZE_TYPE, "free_space",
253       "Remaining capacity of the device.");
254     device_property_fill_and_register(&device_property_max_volume_usage,
255                                       G_TYPE_UINT64, "max_volume_usage",
256       "Artificial limit to data written to volume.");
257     device_property_fill_and_register(&device_property_verbose,
258                                      G_TYPE_BOOLEAN, "verbose",
259        "Should the device produce verbose output?");
260     device_property_fill_and_register(&device_property_comment,
261                                      G_TYPE_STRING, "comment",
262        "User-specified comment for the device");
263 }
264
265 DevicePropertyBase device_property_concurrency;
266 DevicePropertyBase device_property_streaming;
267 DevicePropertyBase device_property_compression;
268 DevicePropertyBase device_property_compression_rate;
269 DevicePropertyBase device_property_block_size;
270 DevicePropertyBase device_property_min_block_size;
271 DevicePropertyBase device_property_max_block_size;
272 DevicePropertyBase device_property_read_block_size;
273 DevicePropertyBase device_property_appendable;
274 DevicePropertyBase device_property_canonical_name;
275 DevicePropertyBase device_property_medium_access_type;
276 DevicePropertyBase device_property_partial_deletion;
277 DevicePropertyBase device_property_full_deletion;
278 DevicePropertyBase device_property_free_space;
279 DevicePropertyBase device_property_max_volume_usage;
280 DevicePropertyBase device_property_verbose;
281 DevicePropertyBase device_property_comment;