2 * Copyright (c) 2007, 2008, 2009, 2010 Zmanda, Inc. All Rights Reserved.
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.
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
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
17 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
21 /* The Device API abstracts device workings, interaction, properties, and
22 * capabilities from the rest of the Amanda code base. It supports
23 * pluggable modules for different kinds of devices. */
32 #include "device-queueing.h"
35 #include "timestamp.h"
39 * Prototypes for subclass registration functions
42 void null_device_register (void);
43 void rait_device_register (void);
45 void s3_device_register (void);
47 #ifdef WANT_TAPE_DEVICE
48 void tape_device_register (void);
50 void vfs_device_register (void);
51 #ifdef WANT_DVDRW_DEVICE
52 void dvdrw_device_register (void);
54 #ifdef WANT_NDMP_DEVICE
55 void ndmp_device_register (void);
59 * Registration infrastructure
62 static GHashTable* driverList = NULL;
64 void device_api_init(void) {
66 device_property_init();
67 driverList = g_hash_table_new(g_str_hash, g_str_equal);
69 /* register other types and devices. */
70 null_device_register();
71 vfs_device_register();
72 #ifdef WANT_TAPE_DEVICE
73 tape_device_register();
75 rait_device_register();
79 #ifdef WANT_DVDRW_DEVICE
80 dvdrw_device_register();
82 #ifdef WANT_NDMP_DEVICE
83 ndmp_device_register();
89 DeviceFactory factory,
90 const char ** device_prefix_list)
94 g_assert(driverList != NULL);
95 g_assert(factory != NULL);
96 g_return_if_fail(device_prefix_list != NULL);
97 g_return_if_fail(*device_prefix_list != NULL);
99 tmp = (char**)device_prefix_list;
100 while (*tmp != NULL) {
101 g_hash_table_insert(driverList, *tmp, (gpointer)factory);
106 static DeviceFactory lookup_device_factory(const char *device_type) {
108 g_assert(driverList != NULL);
110 if (g_hash_table_lookup_extended(driverList, device_type, &key, &value)) {
111 return (DeviceFactory)value;
117 static const GFlagsValue device_status_flags_values[] = {
118 { DEVICE_STATUS_SUCCESS,
119 "DEVICE_STATUS_SUCCESS",
121 { DEVICE_STATUS_DEVICE_ERROR,
122 "DEVICE_STATUS_DEVICE_ERROR",
124 { DEVICE_STATUS_DEVICE_BUSY,
125 "DEVICE_STATUS_DEVICE_BUSY",
127 { DEVICE_STATUS_VOLUME_MISSING,
128 "DEVICE_STATUS_VOLUME_MISSING",
129 "Volume not found" },
130 { DEVICE_STATUS_VOLUME_UNLABELED,
131 "DEVICE_STATUS_VOLUME_UNLABELED",
132 "Volume not labeled" },
133 { DEVICE_STATUS_VOLUME_ERROR,
134 "DEVICE_STATUS_VOLUME_ERROR",
139 GType device_status_flags_get_type(void) {
140 static GType type = 0;
141 if (G_UNLIKELY(type == 0)) {
142 type = g_flags_register_static("DeviceStatusFlags",
143 device_status_flags_values);
148 /* Device class definition starts here. */
150 struct DevicePrivate_s {
151 /* hash table mapping ID to SimpleProperty object */
152 GHashTable * simple_properties;
154 /* In writing mode, after a short block is written, no additional blocks
155 * are allowed the file is finished and a new file started. This is only
156 * used for assertions. */
157 gboolean wrote_short_block;
159 /* Holds an error message if the function returned an error. */
162 /* temporary holding place for device_status_error() */
164 DeviceStatusFlags last_status;
167 /* This holds the default response to a particular property. */
169 DeviceProperty *prop;
171 PropertySurety surety;
172 PropertySource source;
175 #define selfp (self->private)
177 /* here are local prototypes, so we can make function pointers. */
178 static void device_init (Device * o);
179 static void device_class_init (DeviceClass * c);
180 static void device_base_init (DeviceClass * c);
182 static void simple_property_free(SimpleProperty *o);
184 static void default_device_open_device(Device * self, char * device_name,
185 char * device_type, char * device_node);
186 static gboolean default_device_configure(Device *self, gboolean use_global_config);
187 static gboolean default_device_write_from_fd(Device *self,
188 queue_fd_t *queue_fd);
189 static gboolean default_device_read_to_fd(Device *self, queue_fd_t *queue_fd);
190 static gboolean default_device_property_get_ex(Device * self, DevicePropertyId id,
192 PropertySurety *surety,
193 PropertySource *source);
194 static gboolean default_device_property_set_ex(Device *self,
197 PropertySurety surety,
198 PropertySource source);
199 static void set_properties_from_global_config(Device * device);
200 static void set_properties_from_device_config(Device * device, device_config_t *dc);
202 static gboolean property_get_block_size_fn(Device *self,
203 DevicePropertyBase *base, GValue *val,
204 PropertySurety *surety, PropertySource *source);
206 static gboolean property_set_block_size_fn(Device *self,
207 DevicePropertyBase *base, GValue *val,
208 PropertySurety surety, PropertySource source);
210 static gboolean property_get_min_block_size_fn(Device *self,
211 DevicePropertyBase *base, GValue *val,
212 PropertySurety *surety, PropertySource *source);
214 static gboolean property_get_max_block_size_fn(Device *self,
215 DevicePropertyBase *base, GValue *val,
216 PropertySurety *surety, PropertySource *source);
218 static gboolean property_get_canonical_name_fn(Device *self,
219 DevicePropertyBase *base, GValue *val,
220 PropertySurety *surety, PropertySource *source);
222 /* pointer to the class of our parent */
223 static GObjectClass *parent_class = NULL;
226 device_get_type (void)
228 static GType type = 0;
230 if G_UNLIKELY(type == 0) {
231 static const GTypeInfo info = {
232 sizeof (DeviceClass),
233 (GBaseInitFunc) device_base_init,
234 (GBaseFinalizeFunc) NULL,
235 (GClassInitFunc) device_class_init,
236 (GClassFinalizeFunc) NULL,
237 NULL /* class_data */,
240 (GInstanceInitFunc) device_init,
244 type = g_type_register_static (G_TYPE_OBJECT, "Device", &info,
245 (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
251 static void device_finalize(GObject *obj_self) {
252 Device *self G_GNUC_UNUSED = DEVICE (obj_self);
253 if(G_OBJECT_CLASS(parent_class)->finalize)
254 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
256 /* Here we call device_finish() if it hasn't been done
257 yet. Subclasses may need to do this same check earlier. */
258 if (self->access_mode != ACCESS_NULL) {
262 amfree(self->device_name);
263 amfree(self->volume_label);
264 amfree(self->volume_time);
265 amfree(self->volume_header);
266 amfree(selfp->errmsg);
267 amfree(selfp->statusmsg);
268 g_hash_table_destroy(selfp->simple_properties);
269 amfree(self->private);
273 device_init (Device * self)
275 self->private = malloc(sizeof(DevicePrivate));
276 self->device_name = NULL;
277 self->access_mode = ACCESS_NULL;
278 self->is_eof = FALSE;
279 self->is_eom = FALSE;
282 self->in_file = FALSE;
283 self->volume_label = NULL;
284 self->volume_time = NULL;
285 self->status = DEVICE_STATUS_SUCCESS;
286 self->min_block_size = 1;
287 self->max_block_size = SIZE_MAX; /* subclasses *really* should choose something smaller */
288 self->block_size = DISK_BLOCK_BYTES;
289 selfp->errmsg = NULL;
290 selfp->statusmsg = NULL;
291 selfp->last_status = 0;
292 selfp->simple_properties =
293 g_hash_table_new_full(g_direct_hash,
296 (GDestroyNotify) simple_property_free);
300 device_class_init (DeviceClass * device_class)
302 GObjectClass *g_object_class = (GObjectClass*) device_class;
304 parent_class = g_type_class_ref (G_TYPE_OBJECT);
306 device_class->directtcp_supported = FALSE;
308 device_class->open_device = default_device_open_device;
309 device_class->configure = default_device_configure;
310 device_class->write_from_fd = default_device_write_from_fd;
311 device_class->read_to_fd = default_device_read_to_fd;
312 device_class->property_get_ex = default_device_property_get_ex;
313 device_class->property_set_ex = default_device_property_set_ex;
314 g_object_class->finalize = device_finalize;
318 device_base_init (DeviceClass * device_class)
320 /* The base_init function is called once each time a child class is
321 * created, before the class_init functions (even our own) are called. */
323 device_class->class_properties = g_array_new(FALSE, TRUE, sizeof(DeviceProperty));
324 device_class->class_properties_list = NULL;
326 device_class_register_property(device_class, PROPERTY_BLOCK_SIZE,
327 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
328 property_get_block_size_fn,
329 property_set_block_size_fn);
331 device_class_register_property(device_class, PROPERTY_MIN_BLOCK_SIZE,
332 PROPERTY_ACCESS_GET_MASK,
333 property_get_min_block_size_fn,
336 device_class_register_property(device_class, PROPERTY_MAX_BLOCK_SIZE,
337 PROPERTY_ACCESS_GET_MASK,
338 property_get_max_block_size_fn,
341 device_class_register_property(device_class, PROPERTY_CANONICAL_NAME,
342 PROPERTY_ACCESS_GET_MASK,
343 property_get_canonical_name_fn,
346 device_class_register_property(device_class, PROPERTY_CONCURRENCY,
347 PROPERTY_ACCESS_GET_MASK,
348 device_simple_property_get_fn,
349 device_simple_property_set_fn);
351 device_class_register_property(device_class, PROPERTY_STREAMING,
352 PROPERTY_ACCESS_GET_MASK,
353 device_simple_property_get_fn,
354 device_simple_property_set_fn);
356 device_class_register_property(device_class, PROPERTY_APPENDABLE,
357 PROPERTY_ACCESS_GET_MASK,
358 device_simple_property_get_fn,
359 device_simple_property_set_fn);
361 device_class_register_property(device_class, PROPERTY_PARTIAL_DELETION,
362 PROPERTY_ACCESS_GET_MASK,
363 device_simple_property_get_fn,
364 device_simple_property_set_fn);
366 device_class_register_property(device_class, PROPERTY_FULL_DELETION,
367 PROPERTY_ACCESS_GET_MASK,
368 device_simple_property_get_fn,
369 device_simple_property_set_fn);
371 device_class_register_property(device_class, PROPERTY_MEDIUM_ACCESS_TYPE,
372 PROPERTY_ACCESS_GET_MASK,
373 device_simple_property_get_fn,
374 device_simple_property_set_fn);
376 device_class_register_property(device_class, PROPERTY_COMMENT,
377 PROPERTY_ACCESS_GET_MASK|PROPERTY_ACCESS_SET_MASK,
378 device_simple_property_get_fn,
379 device_simple_property_set_fn);
382 static void simple_property_free(SimpleProperty * resp) {
383 g_value_unset(&(resp->response));
388 regex_message(int result, regex_t *regex) {
392 size = regerror(result, regex, NULL, 0);
394 regerror(result, regex, rval, size);
400 handle_device_regex(const char * user_name, char ** driver_name,
401 char ** device, char **errmsg) {
404 regmatch_t pmatch[3];
405 static const char * regex_string = "^([a-z0-9]+):(.*)$";
407 bzero(®ex, sizeof(regex));
409 reg_result = regcomp(®ex, regex_string, REG_EXTENDED | REG_ICASE);
410 if (reg_result != 0) {
411 char * message = regex_message(reg_result, ®ex);
412 *errmsg = newvstrallocf(*errmsg, "Error compiling regular expression \"%s\": %s\n",
413 regex_string, message);
418 reg_result = regexec(®ex, user_name, 3, pmatch, 0);
419 if (reg_result != 0 && reg_result != REG_NOMATCH) {
420 char * message = regex_message(reg_result, ®ex);
421 *errmsg = newvstrallocf(*errmsg,
422 "Error applying regular expression \"%s\" to string \"%s\": %s\n",
423 user_name, regex_string, message);
427 } else if (reg_result == REG_NOMATCH) {
428 #ifdef WANT_TAPE_DEVICE
430 "\"%s\" uses deprecated device naming convention; \n"
431 "using \"tape:%s\" instead.\n",
432 user_name, user_name);
433 *driver_name = stralloc("tape");
434 *device = stralloc(user_name);
435 #else /* !WANT_TAPE_DEVICE */
436 errmsg = newvstrallocf(errmsg, "\"%s\" is not a valid device name.\n", user_name);
439 #endif /* WANT_TAPE_DEVICE */
441 *driver_name = find_regex_substring(user_name, pmatch[1]);
442 *device = find_regex_substring(user_name, pmatch[2]);
448 /* helper function for device_open */
450 make_null_error(char *errmsg, DeviceStatusFlags status)
452 DeviceFactory factory;
455 factory = lookup_device_factory("null");
456 g_assert(factory != NULL);
458 device = factory("null:", "null", "");
459 device_set_error(device, errmsg, status);
465 device_unaliased_name(
469 char *unaliased_name;
471 /* look up the unaliased device name in the configuration */
472 if ((dc = lookup_device_config(device_name))) {
473 if (!(unaliased_name = device_config_get_tapedev(dc))
474 || unaliased_name[0] == '\0') {
478 unaliased_name = device_name;
481 return unaliased_name;
485 device_open (char * device_name)
487 char *device_type = NULL;
488 char *device_node = NULL;
490 char *unaliased_name = NULL;
491 DeviceFactory factory;
494 g_assert(device_name != NULL);
496 if (driverList == NULL) {
497 g_critical("device_open() called without device_api_init()!");
498 g_assert_not_reached();
501 if (device_name == NULL)
502 return make_null_error(stralloc(_("No device name specified")), DEVICE_STATUS_DEVICE_ERROR);
504 unaliased_name = device_unaliased_name(device_name);
505 if (!unaliased_name) {
506 return make_null_error(
507 vstrallocf(_("Device '%s' has no tapedev"), device_name),
508 DEVICE_STATUS_DEVICE_ERROR);
511 if (!handle_device_regex(unaliased_name, &device_type, &device_node,
515 return make_null_error(errmsg, DEVICE_STATUS_DEVICE_ERROR);
518 factory = lookup_device_factory(device_type);
520 if (factory == NULL) {
521 Device *nulldev = make_null_error(vstrallocf(_("Device type %s is not known."),
522 device_type), DEVICE_STATUS_DEVICE_ERROR);
528 device = factory(device_name, device_type, device_node);
529 g_assert(device != NULL); /* factories must always return a device */
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 strncpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp));
654 strncpy(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 strncpy(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)
889 self->block_size = block_size;
890 self->block_size_surety = surety;
891 self->block_size_source = source;
897 property_get_min_block_size_fn(
899 DevicePropertyBase *base G_GNUC_UNUSED,
901 PropertySurety *surety,
902 PropertySource *source)
904 g_value_unset_init(val, G_TYPE_UINT);
905 g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
906 g_value_set_uint(val, (guint)self->min_block_size);
909 *surety = PROPERTY_SURETY_GOOD;
912 *source = PROPERTY_SOURCE_DEFAULT;
918 property_get_max_block_size_fn(
920 DevicePropertyBase *base G_GNUC_UNUSED,
922 PropertySurety *surety,
923 PropertySource *source)
925 g_value_unset_init(val, G_TYPE_UINT);
926 g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
927 g_value_set_uint(val, (guint)self->max_block_size);
930 *surety = PROPERTY_SURETY_GOOD;
933 *source = PROPERTY_SOURCE_DEFAULT;
939 property_get_canonical_name_fn(
941 DevicePropertyBase *base G_GNUC_UNUSED,
943 PropertySurety *surety,
944 PropertySource *source)
946 g_value_unset_init(val, G_TYPE_STRING);
947 g_value_set_string(val, self->device_name);
950 *surety = PROPERTY_SURETY_GOOD;
953 *source = PROPERTY_SOURCE_DEFAULT;
959 static PropertyPhaseFlags
963 if (self->access_mode == ACCESS_NULL) {
964 return PROPERTY_PHASE_BEFORE_START;
965 } else if (IS_WRITABLE_ACCESS_MODE(self->access_mode)) {
967 return PROPERTY_PHASE_INSIDE_FILE_WRITE;
969 return PROPERTY_PHASE_BETWEEN_FILE_WRITE;
971 } else { /* read mode */
973 return PROPERTY_PHASE_INSIDE_FILE_READ;
975 return PROPERTY_PHASE_BETWEEN_FILE_READ;
980 /* This default implementation serves up static responses, and
981 implements a few default responses based on values from the Device
984 default_device_property_get_ex(
988 PropertySurety *surety,
989 PropertySource *source)
991 DeviceProperty *prop;
992 GArray *class_properties;
993 PropertyPhaseFlags cur_phase;
995 /* Most of this function's job is to sanity-check everything, then
996 * call the relevant getter. */
998 class_properties = DEVICE_GET_CLASS(self)->class_properties;
999 if (id >= class_properties->len)
1002 prop = &g_array_index(class_properties, DeviceProperty, id);
1003 if (prop->base == NULL)
1006 if (val || surety || source) {
1007 /* check the phase */
1008 cur_phase = state_to_phase(self);
1009 if (!(prop->access & cur_phase))
1012 if (prop->getter == NULL)
1015 if (!prop->getter(self, prop->base, val, surety, source))
1023 default_device_property_set_ex(
1025 DevicePropertyId id,
1027 PropertySurety surety,
1028 PropertySource source)
1030 DeviceProperty *prop;
1031 GArray *class_properties;
1032 PropertyPhaseFlags cur_phase;
1034 /* Most of this function's job is to sanity-check everything, then
1035 * call the relevant setter. */
1037 if (device_in_error(self))
1040 class_properties = DEVICE_GET_CLASS(self)->class_properties;
1041 if (id >= class_properties->len)
1044 prop = &g_array_index(class_properties, DeviceProperty, id);
1045 if (prop->base == NULL)
1048 /* check that the type matches */
1049 if (!G_VALUE_HOLDS(val, prop->base->type))
1052 /* check the phase */
1053 cur_phase = state_to_phase(self) << PROPERTY_PHASE_SHIFT;
1054 if (!(prop->access & cur_phase))
1057 if (prop->setter == NULL)
1060 if (!prop->setter(self, prop->base, val, surety, source))
1067 device_property_get_list (Device * self)
1069 g_assert(IS_DEVICE(self));
1071 return DEVICE_GET_CLASS(self)->class_properties_list;
1075 default_device_read_to_fd(Device *self, queue_fd_t *queue_fd) {
1077 StreamingRequirement streaming_mode;
1079 if (device_in_error(self)) return FALSE;
1081 /* Get the device's parameters */
1082 bzero(&val, sizeof(val));
1083 if (!device_property_get(self, PROPERTY_STREAMING, &val)
1084 || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
1085 streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
1087 streaming_mode = g_value_get_enum(&val);
1090 return QUEUE_SUCCESS ==
1091 do_consumer_producer_queue_full(
1092 device_read_producer,
1097 DEFAULT_MAX_BUFFER_MEMORY,
1102 default_device_write_from_fd(Device *self, queue_fd_t *queue_fd) {
1104 StreamingRequirement streaming_mode;
1106 if (device_in_error(self)) return FALSE;
1108 /* Get the device's parameters */
1109 bzero(&val, sizeof(val));
1110 if (!device_property_get(self, PROPERTY_STREAMING, &val)
1111 || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
1112 streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
1114 streaming_mode = g_value_get_enum(&val);
1117 return QUEUE_SUCCESS ==
1118 do_consumer_producer_queue_full(
1121 device_write_consumer,
1124 DEFAULT_MAX_BUFFER_MEMORY,
1129 * All the functions below this comment are stub functions that do nothing
1130 * but implement the virtual function table. Call these functions and they
1131 * will do what you expect vis-a-vis virtual functions. But don't put code
1132 * in them beyond error checking and VFT lookup. */
1135 device_open_device (Device * self, char * device_name,
1136 char * device_type, char * device_node)
1140 g_assert(IS_DEVICE(self));
1141 g_assert(device_name != NULL);
1143 klass = DEVICE_GET_CLASS(self);
1144 g_assert(klass->open_device);
1145 (klass->open_device)(self, device_name, device_type, device_node);
1148 DeviceStatusFlags device_read_label(Device * self) {
1149 DeviceClass * klass;
1151 g_assert(self != NULL);
1152 g_assert(IS_DEVICE(self));
1153 g_assert(self->access_mode == ACCESS_NULL);
1155 klass = DEVICE_GET_CLASS(self);
1156 g_assert(klass->read_label);
1157 return (klass->read_label)(self);
1161 device_finish (Device * self) {
1164 g_assert(IS_DEVICE (self));
1166 klass = DEVICE_GET_CLASS(self);
1167 g_assert(klass->finish);
1168 return (klass->finish)(self);
1172 device_configure (Device * self, gboolean use_global_config)
1176 g_assert(IS_DEVICE (self));
1177 g_assert(self->access_mode == ACCESS_NULL);
1179 klass = DEVICE_GET_CLASS(self);
1180 if(klass->configure) {
1181 return (klass->configure)(self, use_global_config);
1183 device_set_error(self,
1184 stralloc(_("Unimplemented method")),
1185 DEVICE_STATUS_DEVICE_ERROR);
1191 device_start (Device * self, DeviceAccessMode mode,
1192 char * label, char * timestamp)
1195 char * local_timestamp = NULL;
1198 g_assert(IS_DEVICE (self));
1199 g_assert(mode != ACCESS_NULL);
1200 g_assert(mode != ACCESS_WRITE || label != NULL);
1202 klass = DEVICE_GET_CLASS(self);
1203 g_assert(klass->start);
1205 /* For a good combination of synchronization and public simplicity,
1206 this stub function does not require a timestamp, but the actual
1207 implementation function does. We generate the timestamp here with
1209 if (mode == ACCESS_WRITE &&
1210 get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
1211 local_timestamp = timestamp =
1212 get_proper_stamp_from_time(time(NULL));
1215 rv = (klass->start)(self, mode, label, timestamp);
1216 amfree(local_timestamp);
1221 device_write_block (Device * self, guint size, gpointer block)
1225 g_assert(IS_DEVICE (self));
1228 /* these are all things that the caller should take care to
1229 * guarantee, so we just assert them here */
1230 g_assert(size <= self->block_size);
1231 g_assert(self->in_file);
1232 g_assert(!selfp->wrote_short_block);
1233 g_assert(block != NULL);
1234 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1236 if (size < self->block_size)
1237 selfp->wrote_short_block = TRUE;
1239 klass = DEVICE_GET_CLASS(self);
1240 g_assert(klass->write_block);
1241 return (*klass->write_block)(self,size, block);
1245 device_write_from_fd (Device * self, queue_fd_t * queue_fd)
1249 g_assert(IS_DEVICE (self));
1250 g_assert(queue_fd->fd >= 0);
1251 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1253 klass = DEVICE_GET_CLASS(self);
1254 g_assert(klass->write_from_fd);
1255 return (klass->write_from_fd)(self,queue_fd);
1259 device_start_file (Device * self, dumpfile_t * jobInfo) {
1260 DeviceClass * klass;
1262 g_assert(IS_DEVICE (self));
1263 g_assert(!(self->in_file));
1264 g_assert(jobInfo != NULL);
1266 selfp->wrote_short_block = FALSE;
1268 klass = DEVICE_GET_CLASS(self);
1269 g_assert(klass->start_file);
1270 return (klass->start_file)(self, jobInfo );
1274 device_finish_file (Device * self)
1278 g_assert(IS_DEVICE (self));
1279 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1280 g_assert(self->in_file);
1282 klass = DEVICE_GET_CLASS(self);
1283 g_assert(klass->finish_file);
1284 return (klass->finish_file)(self);
1288 device_seek_file (Device * self, guint file)
1292 g_assert(IS_DEVICE (self));
1293 g_assert(self->access_mode == ACCESS_READ);
1295 klass = DEVICE_GET_CLASS(self);
1296 g_assert(klass->seek_file);
1297 return (klass->seek_file)(self,file);
1301 device_seek_block (Device * self, guint64 block)
1305 g_assert(IS_DEVICE (self));
1306 g_assert(self->access_mode == ACCESS_READ);
1307 g_assert(self->in_file);
1309 klass = DEVICE_GET_CLASS(self);
1310 g_assert(klass->seek_block);
1311 return (klass->seek_block)(self,block);
1315 device_read_block (Device * self, gpointer buffer, int * size)
1319 g_assert(IS_DEVICE (self));
1320 g_assert(size != NULL);
1321 g_assert(self->access_mode == ACCESS_READ);
1324 g_assert(buffer != NULL);
1327 klass = DEVICE_GET_CLASS(self);
1328 g_assert(klass->read_block);
1329 return (klass->read_block)(self,buffer,size);
1333 device_read_to_fd (Device * self, queue_fd_t *queue_fd)
1337 g_assert(IS_DEVICE (self));
1338 g_assert(queue_fd->fd >= 0);
1339 g_assert(self->access_mode == ACCESS_READ);
1341 klass = DEVICE_GET_CLASS(self);
1342 g_assert(klass->read_to_fd);
1343 return (klass->read_to_fd)(self,queue_fd);
1348 device_property_get_ex(
1350 DevicePropertyId id,
1352 PropertySurety *surety,
1353 PropertySource *source)
1357 g_assert(IS_DEVICE (self));
1358 g_assert(device_property_get_by_id(id) != NULL);
1360 klass = DEVICE_GET_CLASS(self);
1362 g_assert(klass->property_get_ex);
1363 return (klass->property_get_ex)(self, id, val, surety, source);
1367 device_property_set_ex(
1369 DevicePropertyId id,
1371 PropertySurety surety,
1372 PropertySource source)
1376 g_assert(IS_DEVICE (self));
1378 klass = DEVICE_GET_CLASS(self);
1380 g_assert(klass->property_set_ex);
1381 return (klass->property_set_ex)(self, id, val, surety, source);
1385 device_recycle_file (Device * self, guint filenum)
1389 g_assert(self != NULL);
1390 g_assert(IS_DEVICE (self));
1391 g_assert(self->access_mode == ACCESS_APPEND);
1392 g_assert(!self->in_file);
1394 klass = DEVICE_GET_CLASS(self);
1396 g_assert(klass->recycle_file);
1397 return (klass->recycle_file)(self,filenum);
1401 device_erase (Device * self)
1405 g_assert(IS_DEVICE (self));
1406 g_assert(self->access_mode == ACCESS_NULL);
1407 g_assert(!self->in_file);
1409 klass = DEVICE_GET_CLASS(self);
1411 return (klass->erase)(self);
1413 device_set_error(self,
1414 stralloc(_("Unimplemented method")),
1415 DEVICE_STATUS_DEVICE_ERROR);
1421 device_eject (Device * self)
1425 g_assert(IS_DEVICE (self));
1426 g_assert(self->access_mode == ACCESS_NULL);
1427 g_assert(!self->in_file);
1429 klass = DEVICE_GET_CLASS(self);
1431 return (klass->eject)(self);
1440 gboolean for_writing,
1441 DirectTCPAddr **addrs)
1445 klass = DEVICE_GET_CLASS(self);
1447 return (klass->listen)(self, for_writing, addrs);
1449 device_set_error(self,
1450 stralloc(_("Unimplemented method")),
1451 DEVICE_STATUS_DEVICE_ERROR);
1459 DirectTCPConnection **conn,
1460 ProlongProc prolong,
1461 gpointer prolong_data)
1465 klass = DEVICE_GET_CLASS(self);
1467 return (klass->accept)(self, conn, prolong, prolong_data);
1469 device_set_error(self,
1470 stralloc(_("Unimplemented method")),
1471 DEVICE_STATUS_DEVICE_ERROR);
1477 device_write_from_connection(
1480 guint64 *actual_size)
1484 klass = DEVICE_GET_CLASS(self);
1486 g_assert(self->in_file);
1487 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1489 if(klass->write_from_connection) {
1490 return (klass->write_from_connection)(self, size, actual_size);
1492 device_set_error(self,
1493 stralloc(_("Unimplemented method")),
1494 DEVICE_STATUS_DEVICE_ERROR);
1500 device_read_to_connection(
1503 guint64 *actual_size)
1507 g_assert(self->in_file);
1508 g_assert(self->access_mode == ACCESS_READ);
1510 klass = DEVICE_GET_CLASS(self);
1511 if(klass->read_to_connection) {
1512 return (klass->read_to_connection)(self, size, actual_size);
1514 device_set_error(self,
1515 stralloc(_("Unimplemented method")),
1516 DEVICE_STATUS_DEVICE_ERROR);
1522 device_use_connection(
1524 DirectTCPConnection *conn)
1528 g_assert(self->access_mode == ACCESS_NULL);
1530 klass = DEVICE_GET_CLASS(self);
1531 if(klass->use_connection) {
1532 return (klass->use_connection)(self, conn);
1534 device_set_error(self,
1535 stralloc(_("Unimplemented method")),
1536 DEVICE_STATUS_DEVICE_ERROR);
1541 /* Property handling */
1544 device_class_register_property(
1546 DevicePropertyId id,
1547 PropertyAccessFlags access,
1548 PropertyGetFn getter,
1549 PropertySetFn setter)
1551 DevicePropertyBase *base;
1552 DeviceProperty *prop;
1556 g_assert(klass != NULL);
1558 base = device_property_get_by_id(id);
1559 g_assert(base != NULL);
1561 if (klass->class_properties->len <= id) {
1562 g_array_set_size(klass->class_properties, id+1);
1565 prop = &g_array_index(klass->class_properties, DeviceProperty, id);
1567 prop->access = access;
1568 prop->getter = getter;
1569 prop->setter = setter;
1571 /* completely rewrite the list of prop pointers, as they may have changed,
1572 * or we may have replaced an existing property*/
1574 if (klass->class_properties_list) {
1575 g_slist_free(klass->class_properties_list);
1579 for (i = 0; i < klass->class_properties->len; i++) {
1580 prop = &g_array_index(klass->class_properties, DeviceProperty, i);
1583 proplist = g_slist_prepend(proplist, prop);
1586 klass->class_properties_list = proplist;
1590 device_set_simple_property(
1592 DevicePropertyId id,
1594 PropertySurety surety,
1595 PropertySource source)
1597 SimpleProperty *simp;
1598 DeviceProperty *prop;
1600 prop = &g_array_index(DEVICE_GET_CLASS(self)->class_properties,
1601 DeviceProperty, id);
1603 /* these assertions should already be checked, but let's be sure */
1604 g_assert(prop->base != NULL); /* prop must be registered with device */
1605 g_assert(G_VALUE_HOLDS(val, prop->base->type));
1607 simp = g_new0(SimpleProperty, 1);
1609 g_value_unset_copy(val, &(simp->response));
1610 simp->surety = surety;
1611 simp->source = source;
1613 g_hash_table_insert(selfp->simple_properties,
1614 GINT_TO_POINTER(id),
1621 device_simple_property_set_fn(
1623 DevicePropertyBase *base,
1625 PropertySurety surety,
1626 PropertySource source)
1628 return device_set_simple_property(self, base->ID, val, surety, source);
1632 device_get_simple_property(
1634 DevicePropertyId id,
1636 PropertySurety *surety,
1637 PropertySource *source)
1639 SimpleProperty *simp =
1640 g_hash_table_lookup(selfp->simple_properties,
1641 GINT_TO_POINTER(id));
1647 g_value_unset_copy(&(simp->response), val);
1650 *surety = simp->surety;
1653 *source = simp->source;
1659 device_simple_property_get_fn(
1661 DevicePropertyBase *base,
1663 PropertySurety *surety,
1664 PropertySource *source)
1666 return device_get_simple_property(self, base->ID, val, surety, source);