2 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
22 /* The Device API abstracts device workings, interaction, properties, and
23 * capabilities from the rest of the Amanda code base. It supports
24 * pluggable modules for different kinds of devices. */
34 #include "timestamp.h"
38 * Prototypes for subclass registration functions
41 void null_device_register (void);
42 void rait_device_register (void);
44 void s3_device_register (void);
46 #ifdef WANT_TAPE_DEVICE
47 void tape_device_register (void);
49 void vfs_device_register (void);
50 #ifdef WANT_DVDRW_DEVICE
51 void dvdrw_device_register (void);
53 #ifdef WANT_NDMP_DEVICE
54 void ndmp_device_register (void);
58 * Registration infrastructure
61 static GHashTable* driverList = NULL;
63 void device_api_init(void) {
65 device_property_init();
66 driverList = g_hash_table_new(g_str_hash, g_str_equal);
68 /* register other types and devices. */
69 null_device_register();
70 vfs_device_register();
71 #ifdef WANT_TAPE_DEVICE
72 tape_device_register();
74 rait_device_register();
78 #ifdef WANT_DVDRW_DEVICE
79 dvdrw_device_register();
81 #ifdef WANT_NDMP_DEVICE
82 ndmp_device_register();
88 DeviceFactory factory,
89 const char ** device_prefix_list)
93 g_assert(driverList != NULL);
94 g_assert(factory != NULL);
95 g_return_if_fail(device_prefix_list != NULL);
96 g_return_if_fail(*device_prefix_list != NULL);
98 tmp = (char**)device_prefix_list;
99 while (*tmp != NULL) {
100 g_hash_table_insert(driverList, *tmp, (gpointer)factory);
105 static DeviceFactory lookup_device_factory(const char *device_type) {
107 g_assert(driverList != NULL);
109 if (g_hash_table_lookup_extended(driverList, device_type, &key, &value)) {
110 return (DeviceFactory)value;
116 static const GFlagsValue device_status_flags_values[] = {
117 { DEVICE_STATUS_SUCCESS,
118 "DEVICE_STATUS_SUCCESS",
120 { DEVICE_STATUS_DEVICE_ERROR,
121 "DEVICE_STATUS_DEVICE_ERROR",
123 { DEVICE_STATUS_DEVICE_BUSY,
124 "DEVICE_STATUS_DEVICE_BUSY",
126 { DEVICE_STATUS_VOLUME_MISSING,
127 "DEVICE_STATUS_VOLUME_MISSING",
128 "Volume not found" },
129 { DEVICE_STATUS_VOLUME_UNLABELED,
130 "DEVICE_STATUS_VOLUME_UNLABELED",
131 "Volume not labeled" },
132 { DEVICE_STATUS_VOLUME_ERROR,
133 "DEVICE_STATUS_VOLUME_ERROR",
138 GType device_status_flags_get_type(void) {
139 static GType type = 0;
140 if (G_UNLIKELY(type == 0)) {
141 type = g_flags_register_static("DeviceStatusFlags",
142 device_status_flags_values);
147 /* Device class definition starts here. */
149 struct DevicePrivate_s {
150 /* hash table mapping ID to SimpleProperty object */
151 GHashTable * simple_properties;
153 /* In writing mode, after a short block is written, no additional blocks
154 * are allowed the file is finished and a new file started. This is only
155 * used for assertions. */
156 gboolean wrote_short_block;
158 /* Holds an error message if the function returned an error. */
161 /* temporary holding place for device_status_error() */
163 DeviceStatusFlags last_status;
166 /* This holds the default response to a particular property. */
168 DeviceProperty *prop;
170 PropertySurety surety;
171 PropertySource source;
174 #define selfp (self->private)
176 /* here are local prototypes, so we can make function pointers. */
177 static void device_init (Device * o);
178 static void device_class_init (DeviceClass * c);
179 static void device_base_init (DeviceClass * c);
181 static void simple_property_free(SimpleProperty *o);
183 static void default_device_open_device(Device * self, char * device_name,
184 char * device_type, char * device_node);
185 static gboolean default_device_configure(Device *self, gboolean use_global_config);
186 static gboolean default_device_property_get_ex(Device * self, DevicePropertyId id,
188 PropertySurety *surety,
189 PropertySource *source);
190 static gboolean default_device_property_set_ex(Device *self,
193 PropertySurety surety,
194 PropertySource source);
195 static void set_properties_from_global_config(Device * device);
196 static void set_properties_from_device_config(Device * device, device_config_t *dc);
198 static gboolean property_get_block_size_fn(Device *self,
199 DevicePropertyBase *base, GValue *val,
200 PropertySurety *surety, PropertySource *source);
202 static gboolean property_set_block_size_fn(Device *self,
203 DevicePropertyBase *base, GValue *val,
204 PropertySurety surety, PropertySource source);
206 static gboolean property_get_min_block_size_fn(Device *self,
207 DevicePropertyBase *base, GValue *val,
208 PropertySurety *surety, PropertySource *source);
210 static gboolean property_get_max_block_size_fn(Device *self,
211 DevicePropertyBase *base, GValue *val,
212 PropertySurety *surety, PropertySource *source);
214 static gboolean property_get_canonical_name_fn(Device *self,
215 DevicePropertyBase *base, GValue *val,
216 PropertySurety *surety, PropertySource *source);
218 /* pointer to the class of our parent */
219 static GObjectClass *parent_class = NULL;
222 device_get_type (void)
224 static GType type = 0;
226 if G_UNLIKELY(type == 0) {
227 static const GTypeInfo info = {
228 sizeof (DeviceClass),
229 (GBaseInitFunc) device_base_init,
230 (GBaseFinalizeFunc) NULL,
231 (GClassInitFunc) device_class_init,
232 (GClassFinalizeFunc) NULL,
233 NULL /* class_data */,
236 (GInstanceInitFunc) device_init,
240 type = g_type_register_static (G_TYPE_OBJECT, "Device", &info,
241 (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
247 static void device_finalize(GObject *obj_self) {
248 Device *self G_GNUC_UNUSED = DEVICE (obj_self);
249 if(G_OBJECT_CLASS(parent_class)->finalize)
250 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
252 /* Here we call device_finish() if it hasn't been done
253 yet. Subclasses may need to do this same check earlier. */
254 if (self->access_mode != ACCESS_NULL) {
258 amfree(self->device_name);
259 amfree(self->volume_label);
260 amfree(self->volume_time);
261 amfree(self->volume_header);
262 amfree(selfp->errmsg);
263 amfree(selfp->statusmsg);
264 g_hash_table_destroy(selfp->simple_properties);
265 amfree(self->private);
269 device_init (Device * self)
271 self->private = malloc(sizeof(DevicePrivate));
272 self->device_name = NULL;
273 self->access_mode = ACCESS_NULL;
274 self->is_eof = FALSE;
275 self->is_eom = FALSE;
278 self->in_file = FALSE;
279 self->volume_label = NULL;
280 self->volume_time = NULL;
281 self->status = DEVICE_STATUS_SUCCESS;
282 self->min_block_size = 1;
283 self->max_block_size = SIZE_MAX; /* subclasses *really* should choose something smaller */
284 self->block_size = DISK_BLOCK_BYTES;
285 selfp->errmsg = NULL;
286 selfp->statusmsg = NULL;
287 selfp->last_status = 0;
288 selfp->simple_properties =
289 g_hash_table_new_full(g_direct_hash,
292 (GDestroyNotify) simple_property_free);
296 device_class_init (DeviceClass * device_class)
298 GObjectClass *g_object_class = (GObjectClass*) device_class;
300 parent_class = g_type_class_ref (G_TYPE_OBJECT);
302 device_class->directtcp_supported = FALSE;
304 device_class->open_device = default_device_open_device;
305 device_class->configure = default_device_configure;
306 device_class->property_get_ex = default_device_property_get_ex;
307 device_class->property_set_ex = default_device_property_set_ex;
308 g_object_class->finalize = device_finalize;
312 device_base_init (DeviceClass * device_class)
314 /* The base_init function is called once each time a child class is
315 * created, before the class_init functions (even our own) are called. */
317 device_class->class_properties = g_array_new(FALSE, TRUE, sizeof(DeviceProperty));
318 device_class->class_properties_list = NULL;
320 device_class_register_property(device_class, PROPERTY_BLOCK_SIZE,
321 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
322 property_get_block_size_fn,
323 property_set_block_size_fn);
325 device_class_register_property(device_class, PROPERTY_MIN_BLOCK_SIZE,
326 PROPERTY_ACCESS_GET_MASK,
327 property_get_min_block_size_fn,
330 device_class_register_property(device_class, PROPERTY_MAX_BLOCK_SIZE,
331 PROPERTY_ACCESS_GET_MASK,
332 property_get_max_block_size_fn,
335 device_class_register_property(device_class, PROPERTY_CANONICAL_NAME,
336 PROPERTY_ACCESS_GET_MASK,
337 property_get_canonical_name_fn,
340 device_class_register_property(device_class, PROPERTY_CONCURRENCY,
341 PROPERTY_ACCESS_GET_MASK,
342 device_simple_property_get_fn,
343 device_simple_property_set_fn);
345 device_class_register_property(device_class, PROPERTY_STREAMING,
346 PROPERTY_ACCESS_GET_MASK,
347 device_simple_property_get_fn,
348 device_simple_property_set_fn);
350 device_class_register_property(device_class, PROPERTY_APPENDABLE,
351 PROPERTY_ACCESS_GET_MASK,
352 device_simple_property_get_fn,
353 device_simple_property_set_fn);
355 device_class_register_property(device_class, PROPERTY_PARTIAL_DELETION,
356 PROPERTY_ACCESS_GET_MASK,
357 device_simple_property_get_fn,
358 device_simple_property_set_fn);
360 device_class_register_property(device_class, PROPERTY_FULL_DELETION,
361 PROPERTY_ACCESS_GET_MASK,
362 device_simple_property_get_fn,
363 device_simple_property_set_fn);
365 device_class_register_property(device_class, PROPERTY_MEDIUM_ACCESS_TYPE,
366 PROPERTY_ACCESS_GET_MASK,
367 device_simple_property_get_fn,
368 device_simple_property_set_fn);
370 device_class_register_property(device_class, PROPERTY_COMMENT,
371 PROPERTY_ACCESS_GET_MASK|PROPERTY_ACCESS_SET_MASK,
372 device_simple_property_get_fn,
373 device_simple_property_set_fn);
375 device_class_register_property(device_class, PROPERTY_LEOM,
376 PROPERTY_ACCESS_GET_MASK,
377 device_simple_property_get_fn,
378 device_simple_property_set_fn);
381 static void simple_property_free(SimpleProperty * resp) {
382 g_value_unset(&(resp->response));
387 regex_message(int result, regex_t *regex) {
391 size = regerror(result, regex, NULL, 0);
393 regerror(result, regex, rval, size);
399 handle_device_regex(const char * user_name, char ** driver_name,
400 char ** device, char **errmsg) {
403 regmatch_t pmatch[3];
404 static const char * regex_string = "^([a-z0-9]+):(.*)$";
406 bzero(®ex, sizeof(regex));
408 reg_result = regcomp(®ex, regex_string, REG_EXTENDED | REG_ICASE);
409 if (reg_result != 0) {
410 char * message = regex_message(reg_result, ®ex);
411 *errmsg = newvstrallocf(*errmsg, "Error compiling regular expression \"%s\": %s\n",
412 regex_string, message);
417 reg_result = regexec(®ex, user_name, 3, pmatch, 0);
418 if (reg_result != 0 && reg_result != REG_NOMATCH) {
419 char * message = regex_message(reg_result, ®ex);
420 *errmsg = newvstrallocf(*errmsg,
421 "Error applying regular expression \"%s\" to string \"%s\": %s\n",
422 user_name, regex_string, message);
426 } else if (reg_result == REG_NOMATCH) {
427 #ifdef WANT_TAPE_DEVICE
429 "\"%s\" uses deprecated device naming convention; \n"
430 "using \"tape:%s\" instead.\n",
431 user_name, user_name);
432 *driver_name = stralloc("tape");
433 *device = stralloc(user_name);
434 #else /* !WANT_TAPE_DEVICE */
435 *errmsg = newvstrallocf(*errmsg, "\"%s\" is not a valid device name.\n", user_name);
438 #endif /* WANT_TAPE_DEVICE */
440 *driver_name = find_regex_substring(user_name, pmatch[1]);
441 *device = find_regex_substring(user_name, pmatch[2]);
447 /* helper function for device_open */
449 make_null_error(char *errmsg, DeviceStatusFlags status)
451 DeviceFactory factory;
454 factory = lookup_device_factory("null");
455 g_assert(factory != NULL);
457 device = factory("null:", "null", "");
458 device_set_error(device, errmsg, status);
464 device_unaliased_name(
468 char *unaliased_name;
470 /* look up the unaliased device name in the configuration */
471 if ((dc = lookup_device_config(device_name))) {
472 if (!(unaliased_name = device_config_get_tapedev(dc))
473 || unaliased_name[0] == '\0') {
477 unaliased_name = device_name;
480 return unaliased_name;
484 device_open (char * device_name)
486 char *device_type = NULL;
487 char *device_node = NULL;
489 char *unaliased_name = NULL;
490 DeviceFactory factory;
493 g_assert(device_name != NULL);
495 if (driverList == NULL) {
496 g_critical("device_open() called without device_api_init()!");
497 g_assert_not_reached();
500 if (device_name == NULL)
501 return make_null_error(stralloc(_("No device name specified")), DEVICE_STATUS_DEVICE_ERROR);
503 unaliased_name = device_unaliased_name(device_name);
504 if (!unaliased_name) {
505 return make_null_error(
506 vstrallocf(_("Device '%s' has no tapedev"), device_name),
507 DEVICE_STATUS_DEVICE_ERROR);
510 if (!handle_device_regex(unaliased_name, &device_type, &device_node,
514 return make_null_error(errmsg, DEVICE_STATUS_DEVICE_ERROR);
517 factory = lookup_device_factory(device_type);
519 if (factory == NULL) {
520 Device *nulldev = make_null_error(vstrallocf(_("Device type %s is not known."),
521 device_type), DEVICE_STATUS_DEVICE_ERROR);
527 device = factory(device_name, device_type, device_node);
528 g_assert(device != NULL); /* factories must always return a device */
530 device->device_mutex = g_mutex_new();
538 device_error(Device * self)
541 return device_error_or_status(self);
542 } else if (selfp->errmsg) {
543 return selfp->errmsg;
545 return "Unknown Device error";
550 device_status_error(Device * self)
556 return device_error_or_status(self);
559 /* reuse a previous statusmsg, if it was for the same status */
560 if (selfp->statusmsg && selfp->last_status == self->status)
561 return selfp->statusmsg;
563 amfree(selfp->statusmsg);
565 status_strv = g_flags_nick_to_strv(self->status, DEVICE_STATUS_FLAGS_TYPE);
566 g_assert(g_strv_length(status_strv) > 0);
567 if (g_strv_length(status_strv) == 1) {
568 statusmsg = stralloc(*status_strv);
570 char * status_list = g_english_strjoinv(status_strv, "or");
571 statusmsg = g_strdup_printf("one of %s", status_list);
574 g_strfreev(status_strv);
576 selfp->statusmsg = statusmsg;
577 selfp->last_status = self->status;
582 device_error_or_status(Device * self)
585 return "Device is NULL";
586 } else if (selfp->errmsg) {
587 return selfp->errmsg;
589 return device_status_error(self);
594 device_set_error(Device *self, char *errmsg, DeviceStatusFlags new_flags)
601 g_warning("device_set_error called with a NULL device: '%s'", errmsg? errmsg:"(NULL)");
606 device_name = self->device_name? self->device_name : "(unknown device)";
608 if (errmsg && (!selfp->errmsg || strcmp(errmsg, selfp->errmsg) != 0))
609 g_debug("Device %s error = '%s'", device_name, errmsg);
611 amfree(selfp->errmsg);
612 selfp->errmsg = errmsg;
614 if (new_flags != DEVICE_STATUS_SUCCESS) {
615 flags_strv = g_flags_name_to_strv(new_flags, DEVICE_STATUS_FLAGS_TYPE);
616 g_assert(g_strv_length(flags_strv) > 0);
617 flags_str = g_english_strjoinv(flags_strv, "and");
618 g_debug("Device %s setting status flag(s): %s", device_name, flags_str);
620 g_strfreev(flags_strv);
623 self->status = new_flags;
626 char * device_build_amanda_header(Device * self, const dumpfile_t * info,
628 return build_header(info, size, self->block_size);
631 dumpfile_t * make_tapestart_header(Device * self, char * label,
635 bzero(&val, sizeof(val));
637 g_assert(label != NULL);
639 rval = malloc(sizeof(*rval));
641 rval->type = F_TAPESTART;
642 if (device_property_get(self, PROPERTY_BLOCK_SIZE, &val)) {
643 rval->blocksize = g_value_get_int(&val);
647 amfree(self->volume_time);
648 if (get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
649 self->volume_time = get_proper_stamp_from_time(time(NULL));
651 self->volume_time = g_strdup(timestamp);
653 g_strlcpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp));
654 g_strlcpy(rval->name, label, sizeof(rval->name));
659 dumpfile_t * make_tapeend_header(void) {
663 rval = malloc(sizeof(*rval));
664 rval->type = F_TAPEEND;
665 timestamp = get_timestamp_from_time(time(NULL));
666 g_strlcpy(rval->datestamp, timestamp, sizeof(rval->datestamp));
671 /* Try setting the blocksize on a device. Check results, fallback, and
672 * set error status for problems. */
674 try_set_blocksize(Device * device, guint blocksize) {
677 bzero(&val, sizeof(val));
679 g_value_init(&val, G_TYPE_INT);
680 g_value_set_int(&val, blocksize);
681 success = device_property_set(device, PROPERTY_BLOCK_SIZE, &val);
685 device_set_error(device,
686 vstrallocf(_("Setting BLOCK_SIZE to %u "
687 "not supported for device %s.\n"),
688 blocksize, device->device_name),
689 DEVICE_STATUS_DEVICE_ERROR);
695 /* A GHFunc (callback for g_hash_table_foreach) */
696 static void set_device_property(gpointer key_p, gpointer value_p,
697 gpointer user_data_p) {
698 char * property_s = key_p;
699 property_t * property = value_p;
700 Device * device = user_data_p;
701 const DevicePropertyBase* property_base;
702 GValue property_value;
705 g_return_if_fail(IS_DEVICE(device));
706 g_return_if_fail(property_s != NULL);
707 g_return_if_fail(property != NULL);
708 g_return_if_fail(property->values != NULL);
710 /* don't continue beating on a device that's already erroring */
711 if (device_in_error(device)) return;
713 property_base = device_property_get_by_name(property_s);
714 if (property_base == NULL) {
715 /* Nonexistant property name. */
716 device_set_error(device,
717 vstrallocf(_("unknown device property name '%s'"), property_s),
718 DEVICE_STATUS_DEVICE_ERROR);
721 if (g_slist_length(property->values) > 1) {
722 device_set_error(device,
723 vstrallocf(_("multiple values for device property '%s'"), property_s),
724 DEVICE_STATUS_DEVICE_ERROR);
728 bzero(&property_value, sizeof(property_value));
729 g_value_init(&property_value, property_base->type);
730 value = property->values->data;
731 if (!g_value_set_from_string(&property_value, value)) {
732 /* Value type could not be interpreted. */
733 device_set_error(device,
734 vstrallocf(_("Could not parse property value '%s' for property '%s' (property type %s)"),
735 value, property_base->name, g_type_name(property_base->type)),
736 DEVICE_STATUS_DEVICE_ERROR);
739 g_assert (G_VALUE_HOLDS(&property_value, property_base->type));
742 if (!device_property_set(device, property_base->ID, &property_value)) {
743 /* Device rejects property. */
744 if (!device_in_error(device)) {
745 device_set_error(device,
746 vstrallocf(_("Could not set property '%s' to '%s' on %s"),
747 property_base->name, value, device->device_name),
748 DEVICE_STATUS_DEVICE_ERROR);
754 /* Set up properties based on various taper-related configuration parameters
755 * and from the tapetype.
758 set_properties_from_global_config(Device * device) {
759 char * tapetype_name = getconf_str(CNF_TAPETYPE);
760 if (tapetype_name != NULL) {
761 tapetype_t * tapetype = lookup_tapetype(tapetype_name);
762 if (tapetype != NULL) {
768 bzero(&val, sizeof(GValue));
770 if (tapetype_seen(tapetype, TAPETYPE_LENGTH)) {
771 length = tapetype_get_length(tapetype);
772 g_value_init(&val, G_TYPE_UINT64);
773 g_value_set_uint64(&val, length * 1024);
774 /* If this fails, it's not really an error. */
775 device_property_set(device, PROPERTY_MAX_VOLUME_USAGE, &val);
779 if (tapetype_seen(tapetype, TAPETYPE_READBLOCKSIZE)) {
780 blocksize_kb = tapetype_get_readblocksize(tapetype);
781 g_value_init(&val, G_TYPE_UINT);
782 g_value_set_uint(&val, blocksize_kb * 1024);
783 success = device_property_set(device,
784 PROPERTY_READ_BLOCK_SIZE,
788 /* a non-fatal error */
789 g_warning("Setting READ_BLOCK_SIZE to %ju not supported for device %s.",
790 1024*(uintmax_t)blocksize_kb, device->device_name);
794 if (tapetype_seen(tapetype, TAPETYPE_BLOCKSIZE)) {
795 blocksize_kb = tapetype_get_blocksize(tapetype);
796 /* TODO: handle errors */
797 (void)try_set_blocksize(device, blocksize_kb * 1024);
802 g_hash_table_foreach(getconf_proplist(CNF_DEVICE_PROPERTY),
803 set_device_property, device);
806 /* Set properties specified within a device definition */
808 set_properties_from_device_config(Device * device, device_config_t *dc) {
809 g_hash_table_foreach(device_config_get_property(dc),
810 set_device_property, device);
814 default_device_configure(Device *self, gboolean use_global_config)
818 if (device_in_error(self))
821 if (use_global_config)
822 set_properties_from_global_config(self);
824 if (device_in_error(self))
827 if ((dc = lookup_device_config(self->device_name)))
828 set_properties_from_device_config(self, dc);
830 return !device_in_error(self);
833 void device_clear_volume_details(Device * device) {
834 if (device == NULL || device->access_mode != ACCESS_NULL) {
838 amfree(device->volume_label);
839 amfree(device->volume_time);
842 /* Here we put default implementations of virtual functions. Since
843 this class is virtual, many of these functions offer at best
844 incomplete functionality. But they do offer the useful commonality
845 that all devices can expect to need. */
847 static void default_device_open_device(Device * self, char * device_name,
848 char * device_type G_GNUC_UNUSED, char * device_node G_GNUC_UNUSED) {
849 /* Set the device_name property */
850 self->device_name = stralloc(device_name);
854 property_get_block_size_fn(
856 DevicePropertyBase *base G_GNUC_UNUSED,
858 PropertySurety *surety,
859 PropertySource *source)
861 g_value_unset_init(val, G_TYPE_INT);
862 g_assert(self->block_size < G_MAXINT); /* gsize -> gint */
863 g_value_set_int(val, (gint)self->block_size);
866 *surety = self->block_size_surety;
869 *source = self->block_size_source;
875 property_set_block_size_fn(
877 DevicePropertyBase *base G_GNUC_UNUSED,
879 PropertySurety surety,
880 PropertySource source)
882 gint block_size = g_value_get_int(val);
884 g_assert(block_size >= 0); /* int -> gsize (unsigned) */
885 if ((gsize)block_size < self->min_block_size
886 || (gsize)block_size > self->max_block_size) {
887 device_set_error(self,
888 g_strdup_printf("Error setting BLOCK-SIZE property to '%zu', it must be between %zu and %zu", (gsize)block_size, self->min_block_size, self->max_block_size),
889 DEVICE_STATUS_DEVICE_ERROR);
893 self->block_size = block_size;
894 self->block_size_surety = surety;
895 self->block_size_source = source;
901 property_get_min_block_size_fn(
903 DevicePropertyBase *base G_GNUC_UNUSED,
905 PropertySurety *surety,
906 PropertySource *source)
908 g_value_unset_init(val, G_TYPE_UINT);
909 g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
910 g_value_set_uint(val, (guint)self->min_block_size);
913 *surety = PROPERTY_SURETY_GOOD;
916 *source = PROPERTY_SOURCE_DEFAULT;
922 property_get_max_block_size_fn(
924 DevicePropertyBase *base G_GNUC_UNUSED,
926 PropertySurety *surety,
927 PropertySource *source)
929 g_value_unset_init(val, G_TYPE_UINT);
930 g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
931 g_value_set_uint(val, (guint)self->max_block_size);
934 *surety = PROPERTY_SURETY_GOOD;
937 *source = PROPERTY_SOURCE_DEFAULT;
943 property_get_canonical_name_fn(
945 DevicePropertyBase *base G_GNUC_UNUSED,
947 PropertySurety *surety,
948 PropertySource *source)
950 g_value_unset_init(val, G_TYPE_STRING);
951 g_value_set_string(val, self->device_name);
954 *surety = PROPERTY_SURETY_GOOD;
957 *source = PROPERTY_SOURCE_DEFAULT;
963 static PropertyPhaseFlags
967 if (self->access_mode == ACCESS_NULL) {
968 return PROPERTY_PHASE_BEFORE_START;
969 } else if (IS_WRITABLE_ACCESS_MODE(self->access_mode)) {
971 return PROPERTY_PHASE_INSIDE_FILE_WRITE;
973 return PROPERTY_PHASE_BETWEEN_FILE_WRITE;
975 } else { /* read mode */
977 return PROPERTY_PHASE_INSIDE_FILE_READ;
979 return PROPERTY_PHASE_BETWEEN_FILE_READ;
984 /* This default implementation serves up static responses, and
985 implements a few default responses based on values from the Device
988 default_device_property_get_ex(
992 PropertySurety *surety,
993 PropertySource *source)
995 DeviceProperty *prop;
996 GArray *class_properties;
997 PropertyPhaseFlags cur_phase;
999 /* Most of this function's job is to sanity-check everything, then
1000 * call the relevant getter. */
1002 class_properties = DEVICE_GET_CLASS(self)->class_properties;
1003 if (id >= class_properties->len)
1006 prop = &g_array_index(class_properties, DeviceProperty, id);
1007 if (prop->base == NULL)
1010 if (val || surety || source) {
1011 /* check the phase */
1012 cur_phase = state_to_phase(self);
1013 if (!(prop->access & cur_phase))
1016 if (prop->getter == NULL)
1019 if (!prop->getter(self, prop->base, val, surety, source))
1027 default_device_property_set_ex(
1029 DevicePropertyId id,
1031 PropertySurety surety,
1032 PropertySource source)
1034 DeviceProperty *prop;
1035 GArray *class_properties;
1036 PropertyPhaseFlags cur_phase;
1038 /* Most of this function's job is to sanity-check everything, then
1039 * call the relevant setter. */
1041 if (device_in_error(self))
1044 class_properties = DEVICE_GET_CLASS(self)->class_properties;
1045 if (id >= class_properties->len)
1048 prop = &g_array_index(class_properties, DeviceProperty, id);
1049 if (prop->base == NULL)
1052 /* check that the type matches */
1053 if (!G_VALUE_HOLDS(val, prop->base->type))
1056 /* check the phase */
1057 cur_phase = state_to_phase(self) << PROPERTY_PHASE_SHIFT;
1058 if (!(prop->access & cur_phase))
1061 if (prop->setter == NULL)
1064 if (!prop->setter(self, prop->base, val, surety, source))
1071 device_property_get_list (Device * self)
1073 g_assert(IS_DEVICE(self));
1075 return DEVICE_GET_CLASS(self)->class_properties_list;
1079 * All the functions below this comment are stub functions that do nothing
1080 * but implement the virtual function table. Call these functions and they
1081 * will do what you expect vis-a-vis virtual functions. But don't put code
1082 * in them beyond error checking and VFT lookup. */
1085 device_open_device (Device * self, char * device_name,
1086 char * device_type, char * device_node)
1090 g_assert(IS_DEVICE(self));
1091 g_assert(device_name != NULL);
1093 klass = DEVICE_GET_CLASS(self);
1094 g_assert(klass->open_device);
1095 (klass->open_device)(self, device_name, device_type, device_node);
1098 DeviceStatusFlags device_read_label(Device * self) {
1099 DeviceClass * klass;
1101 g_assert(self != NULL);
1102 g_assert(IS_DEVICE(self));
1103 g_assert(self->access_mode == ACCESS_NULL);
1105 klass = DEVICE_GET_CLASS(self);
1106 g_assert(klass->read_label);
1107 return (klass->read_label)(self);
1111 device_finish (Device * self) {
1114 g_assert(IS_DEVICE (self));
1116 klass = DEVICE_GET_CLASS(self);
1117 g_assert(klass->finish);
1118 return (klass->finish)(self);
1122 device_get_bytes_read (Device * self) {
1126 g_assert(IS_DEVICE (self));
1128 g_mutex_lock(self->device_mutex);
1129 if (self->in_file) {
1130 klass = DEVICE_GET_CLASS(self);
1131 if (klass->get_bytes_read) {
1132 bytes = (klass->get_bytes_read)(self);
1134 bytes = self->bytes_read;
1137 g_mutex_unlock(self->device_mutex);
1142 device_get_bytes_written (Device * self) {
1146 g_assert(IS_DEVICE (self));
1148 g_mutex_lock(self->device_mutex);
1149 if (self->in_file) {
1150 klass = DEVICE_GET_CLASS(self);
1151 if (klass->get_bytes_written) {
1152 bytes = (klass->get_bytes_written)(self);
1154 bytes = self->bytes_written;
1157 g_mutex_unlock(self->device_mutex);
1162 device_configure (Device * self, gboolean use_global_config)
1166 g_assert(IS_DEVICE (self));
1167 g_assert(self->access_mode == ACCESS_NULL);
1169 klass = DEVICE_GET_CLASS(self);
1170 if(klass->configure) {
1171 return (klass->configure)(self, use_global_config);
1173 device_set_error(self,
1174 stralloc(_("Unimplemented method")),
1175 DEVICE_STATUS_DEVICE_ERROR);
1181 device_start (Device * self, DeviceAccessMode mode,
1182 char * label, char * timestamp)
1185 char * local_timestamp = NULL;
1188 g_assert(IS_DEVICE (self));
1189 g_assert(mode != ACCESS_NULL);
1190 g_assert(mode != ACCESS_WRITE || label != NULL);
1192 klass = DEVICE_GET_CLASS(self);
1193 g_assert(klass->start);
1195 /* For a good combination of synchronization and public simplicity,
1196 this stub function does not require a timestamp, but the actual
1197 implementation function does. We generate the timestamp here with
1199 if (mode == ACCESS_WRITE &&
1200 get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
1201 local_timestamp = timestamp =
1202 get_proper_stamp_from_time(time(NULL));
1205 rv = (klass->start)(self, mode, label, timestamp);
1206 amfree(local_timestamp);
1211 device_write_block (Device * self, guint size, gpointer block)
1215 g_assert(IS_DEVICE (self));
1218 /* these are all things that the caller should take care to
1219 * guarantee, so we just assert them here */
1220 g_assert(size <= self->block_size);
1221 g_assert(self->in_file);
1222 g_assert(!selfp->wrote_short_block);
1223 g_assert(block != NULL);
1224 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1226 if (size < self->block_size)
1227 selfp->wrote_short_block = TRUE;
1229 klass = DEVICE_GET_CLASS(self);
1230 g_assert(klass->write_block);
1231 return (*klass->write_block)(self,size, block);
1235 device_start_file (Device * self, dumpfile_t * jobInfo) {
1236 DeviceClass * klass;
1238 g_assert(IS_DEVICE (self));
1239 g_assert(!(self->in_file));
1240 g_assert(jobInfo != NULL);
1242 selfp->wrote_short_block = FALSE;
1244 klass = DEVICE_GET_CLASS(self);
1245 g_assert(klass->start_file);
1246 return (klass->start_file)(self, jobInfo );
1250 device_finish_file (Device * self)
1254 g_assert(IS_DEVICE (self));
1255 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1256 g_assert(self->in_file);
1258 klass = DEVICE_GET_CLASS(self);
1259 g_assert(klass->finish_file);
1260 return (klass->finish_file)(self);
1264 device_seek_file (Device * self, guint file)
1268 g_assert(IS_DEVICE (self));
1269 g_assert(self->access_mode == ACCESS_READ);
1271 klass = DEVICE_GET_CLASS(self);
1272 g_assert(klass->seek_file);
1273 return (klass->seek_file)(self,file);
1277 device_seek_block (Device * self, guint64 block)
1281 g_assert(IS_DEVICE (self));
1282 g_assert(self->access_mode == ACCESS_READ);
1283 g_assert(self->in_file);
1285 klass = DEVICE_GET_CLASS(self);
1286 g_assert(klass->seek_block);
1287 return (klass->seek_block)(self,block);
1291 device_read_block (Device * self, gpointer buffer, int * size)
1295 g_assert(IS_DEVICE (self));
1296 g_assert(size != NULL);
1297 g_assert(self->access_mode == ACCESS_READ);
1300 g_assert(buffer != NULL);
1303 klass = DEVICE_GET_CLASS(self);
1304 g_assert(klass->read_block);
1305 return (klass->read_block)(self,buffer,size);
1309 device_property_get_ex(
1311 DevicePropertyId id,
1313 PropertySurety *surety,
1314 PropertySource *source)
1318 g_assert(IS_DEVICE (self));
1319 g_assert(device_property_get_by_id(id) != NULL);
1321 klass = DEVICE_GET_CLASS(self);
1323 g_assert(klass->property_get_ex);
1324 return (klass->property_get_ex)(self, id, val, surety, source);
1328 device_property_set_ex(
1330 DevicePropertyId id,
1332 PropertySurety surety,
1333 PropertySource source)
1337 g_assert(IS_DEVICE (self));
1339 klass = DEVICE_GET_CLASS(self);
1341 g_assert(klass->property_set_ex);
1342 return (klass->property_set_ex)(self, id, val, surety, source);
1346 device_recycle_file (Device * self, guint filenum)
1350 g_assert(self != NULL);
1351 g_assert(IS_DEVICE (self));
1352 g_assert(self->access_mode == ACCESS_APPEND);
1353 g_assert(!self->in_file);
1355 klass = DEVICE_GET_CLASS(self);
1357 g_assert(klass->recycle_file);
1358 return (klass->recycle_file)(self,filenum);
1362 device_erase (Device * self)
1366 g_assert(IS_DEVICE (self));
1367 g_assert(self->access_mode == ACCESS_NULL);
1368 g_assert(!self->in_file);
1370 klass = DEVICE_GET_CLASS(self);
1372 return (klass->erase)(self);
1374 device_set_error(self,
1375 stralloc(_("Unimplemented method")),
1376 DEVICE_STATUS_DEVICE_ERROR);
1382 device_eject (Device * self)
1386 g_assert(IS_DEVICE (self));
1387 g_assert(self->access_mode == ACCESS_NULL);
1388 g_assert(!self->in_file);
1390 klass = DEVICE_GET_CLASS(self);
1392 return (klass->eject)(self);
1401 gboolean for_writing,
1402 DirectTCPAddr **addrs)
1406 klass = DEVICE_GET_CLASS(self);
1408 return (klass->listen)(self, for_writing, addrs);
1410 device_set_error(self,
1411 stralloc(_("Unimplemented method")),
1412 DEVICE_STATUS_DEVICE_ERROR);
1420 DirectTCPConnection **conn,
1422 GMutex *abort_mutex,
1427 klass = DEVICE_GET_CLASS(self);
1429 return (klass->accept)(self, conn, cancelled, abort_mutex, abort_cond);
1431 device_set_error(self,
1432 g_strdup(_("Unimplemented method")),
1433 DEVICE_STATUS_DEVICE_ERROR);
1442 gboolean for_writing,
1443 DirectTCPAddr *addrs,
1444 DirectTCPConnection **conn,
1446 GMutex *abort_mutex,
1451 klass = DEVICE_GET_CLASS(self);
1452 if(klass->connect) {
1453 return (klass->connect)(self, for_writing, addrs, conn, cancelled,
1454 abort_mutex, abort_cond);
1456 device_set_error(self,
1457 g_strdup(_("Unimplemented method")),
1458 DEVICE_STATUS_DEVICE_ERROR);
1464 device_write_from_connection(
1467 guint64 *actual_size,
1469 GMutex *abort_mutex,
1474 klass = DEVICE_GET_CLASS(self);
1476 g_assert(self->in_file);
1477 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1479 if(klass->write_from_connection) {
1480 return (klass->write_from_connection)(self, size, actual_size,
1482 abort_mutex, abort_cond);
1484 device_set_error(self,
1485 stralloc(_("Unimplemented method")),
1486 DEVICE_STATUS_DEVICE_ERROR);
1492 device_read_to_connection(
1495 guint64 *actual_size,
1497 GMutex *abort_mutex,
1502 g_assert(self->in_file);
1503 g_assert(self->access_mode == ACCESS_READ);
1505 klass = DEVICE_GET_CLASS(self);
1506 if(klass->read_to_connection) {
1507 return (klass->read_to_connection)(self, size, actual_size,
1508 cancelled, abort_mutex, abort_cond);
1510 device_set_error(self,
1511 stralloc(_("Unimplemented method")),
1512 DEVICE_STATUS_DEVICE_ERROR);
1518 device_use_connection(
1520 DirectTCPConnection *conn)
1524 g_assert(self->access_mode == ACCESS_NULL);
1526 klass = DEVICE_GET_CLASS(self);
1527 if(klass->use_connection) {
1528 return (klass->use_connection)(self, conn);
1530 device_set_error(self,
1531 stralloc(_("Unimplemented method")),
1532 DEVICE_STATUS_DEVICE_ERROR);
1537 /* Property handling */
1540 device_class_register_property(
1542 DevicePropertyId id,
1543 PropertyAccessFlags access,
1544 PropertyGetFn getter,
1545 PropertySetFn setter)
1547 DevicePropertyBase *base;
1548 DeviceProperty *prop;
1552 g_assert(klass != NULL);
1554 base = device_property_get_by_id(id);
1555 g_assert(base != NULL);
1557 if (klass->class_properties->len <= id) {
1558 g_array_set_size(klass->class_properties, id+1);
1561 prop = &g_array_index(klass->class_properties, DeviceProperty, id);
1563 prop->access = access;
1564 prop->getter = getter;
1565 prop->setter = setter;
1567 /* completely rewrite the list of prop pointers, as they may have changed,
1568 * or we may have replaced an existing property*/
1570 if (klass->class_properties_list) {
1571 g_slist_free(klass->class_properties_list);
1575 for (i = 0; i < klass->class_properties->len; i++) {
1576 prop = &g_array_index(klass->class_properties, DeviceProperty, i);
1579 proplist = g_slist_prepend(proplist, prop);
1582 klass->class_properties_list = proplist;
1586 device_set_simple_property(
1588 DevicePropertyId id,
1590 PropertySurety surety,
1591 PropertySource source)
1593 SimpleProperty *simp;
1594 DeviceProperty *prop;
1596 prop = &g_array_index(DEVICE_GET_CLASS(self)->class_properties,
1597 DeviceProperty, id);
1599 /* these assertions should already be checked, but let's be sure */
1600 g_assert(prop->base != NULL); /* prop must be registered with device */
1601 g_assert(G_VALUE_HOLDS(val, prop->base->type));
1603 simp = g_new0(SimpleProperty, 1);
1605 g_value_unset_copy(val, &(simp->response));
1606 simp->surety = surety;
1607 simp->source = source;
1609 g_hash_table_insert(selfp->simple_properties,
1610 GINT_TO_POINTER(id),
1617 device_simple_property_set_fn(
1619 DevicePropertyBase *base,
1621 PropertySurety surety,
1622 PropertySource source)
1624 return device_set_simple_property(self, base->ID, val, surety, source);
1628 device_get_simple_property(
1630 DevicePropertyId id,
1632 PropertySurety *surety,
1633 PropertySource *source)
1635 SimpleProperty *simp =
1636 g_hash_table_lookup(selfp->simple_properties,
1637 GINT_TO_POINTER(id));
1643 g_value_unset_copy(&(simp->response), val);
1646 *surety = simp->surety;
1649 *source = simp->source;
1655 device_simple_property_get_fn(
1657 DevicePropertyBase *base,
1659 PropertySurety *surety,
1660 PropertySource *source)
1662 return device_get_simple_property(self, base->ID, val, surety, source);