2 * Copyright (c) 2007-2012 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. */
33 #include "timestamp.h"
37 * Prototypes for subclass registration functions
40 void null_device_register (void);
41 void rait_device_register (void);
43 void s3_device_register (void);
45 #ifdef WANT_TAPE_DEVICE
46 void tape_device_register (void);
48 void vfs_device_register (void);
49 #ifdef WANT_DVDRW_DEVICE
50 void dvdrw_device_register (void);
52 #ifdef WANT_NDMP_DEVICE
53 void ndmp_device_register (void);
57 * Registration infrastructure
60 static GHashTable* driverList = NULL;
62 void device_api_init(void) {
64 device_property_init();
65 driverList = g_hash_table_new(g_str_hash, g_str_equal);
67 /* register other types and devices. */
68 null_device_register();
69 vfs_device_register();
70 #ifdef WANT_TAPE_DEVICE
71 tape_device_register();
73 rait_device_register();
77 #ifdef WANT_DVDRW_DEVICE
78 dvdrw_device_register();
80 #ifdef WANT_NDMP_DEVICE
81 ndmp_device_register();
87 DeviceFactory factory,
88 const char ** device_prefix_list)
92 g_assert(driverList != NULL);
93 g_assert(factory != NULL);
94 g_return_if_fail(device_prefix_list != NULL);
95 g_return_if_fail(*device_prefix_list != NULL);
97 tmp = (char**)device_prefix_list;
98 while (*tmp != NULL) {
99 g_hash_table_insert(driverList, *tmp, (gpointer)factory);
104 static DeviceFactory lookup_device_factory(const char *device_type) {
106 g_assert(driverList != NULL);
108 if (g_hash_table_lookup_extended(driverList, device_type, &key, &value)) {
109 return (DeviceFactory)value;
115 static const GFlagsValue device_status_flags_values[] = {
116 { DEVICE_STATUS_SUCCESS,
117 "DEVICE_STATUS_SUCCESS",
119 { DEVICE_STATUS_DEVICE_ERROR,
120 "DEVICE_STATUS_DEVICE_ERROR",
122 { DEVICE_STATUS_DEVICE_BUSY,
123 "DEVICE_STATUS_DEVICE_BUSY",
125 { DEVICE_STATUS_VOLUME_MISSING,
126 "DEVICE_STATUS_VOLUME_MISSING",
127 "Volume not found" },
128 { DEVICE_STATUS_VOLUME_UNLABELED,
129 "DEVICE_STATUS_VOLUME_UNLABELED",
130 "Volume not labeled" },
131 { DEVICE_STATUS_VOLUME_ERROR,
132 "DEVICE_STATUS_VOLUME_ERROR",
137 GType device_status_flags_get_type(void) {
138 static GType type = 0;
139 if (G_UNLIKELY(type == 0)) {
140 type = g_flags_register_static("DeviceStatusFlags",
141 device_status_flags_values);
146 /* Device class definition starts here. */
148 struct DevicePrivate_s {
149 /* hash table mapping ID to SimpleProperty object */
150 GHashTable * simple_properties;
152 /* In writing mode, after a short block is written, no additional blocks
153 * are allowed the file is finished and a new file started. This is only
154 * used for assertions. */
155 gboolean wrote_short_block;
157 /* Holds an error message if the function returned an error. */
160 /* temporary holding place for device_status_error() */
162 DeviceStatusFlags last_status;
165 /* This holds the default response to a particular property. */
167 DeviceProperty *prop;
169 PropertySurety surety;
170 PropertySource source;
173 #define selfp (self->private)
175 /* here are local prototypes, so we can make function pointers. */
176 static void device_init (Device * o);
177 static void device_class_init (DeviceClass * c);
178 static void device_base_init (DeviceClass * c);
180 static void simple_property_free(SimpleProperty *o);
182 static void default_device_open_device(Device * self, char * device_name,
183 char * device_type, char * device_node);
184 static gboolean default_device_configure(Device *self, gboolean use_global_config);
185 static gboolean default_device_property_get_ex(Device * self, DevicePropertyId id,
187 PropertySurety *surety,
188 PropertySource *source);
189 static gboolean default_device_property_set_ex(Device *self,
192 PropertySurety surety,
193 PropertySource source);
194 static void set_properties_from_global_config(Device * device);
195 static void set_properties_from_device_config(Device * device, device_config_t *dc);
197 static gboolean property_get_block_size_fn(Device *self,
198 DevicePropertyBase *base, GValue *val,
199 PropertySurety *surety, PropertySource *source);
201 static gboolean property_set_block_size_fn(Device *self,
202 DevicePropertyBase *base, GValue *val,
203 PropertySurety surety, PropertySource source);
205 static gboolean property_get_min_block_size_fn(Device *self,
206 DevicePropertyBase *base, GValue *val,
207 PropertySurety *surety, PropertySource *source);
209 static gboolean property_get_max_block_size_fn(Device *self,
210 DevicePropertyBase *base, GValue *val,
211 PropertySurety *surety, PropertySource *source);
213 static gboolean property_get_canonical_name_fn(Device *self,
214 DevicePropertyBase *base, GValue *val,
215 PropertySurety *surety, PropertySource *source);
217 /* pointer to the class of our parent */
218 static GObjectClass *parent_class = NULL;
221 device_get_type (void)
223 static GType type = 0;
225 if G_UNLIKELY(type == 0) {
226 static const GTypeInfo info = {
227 sizeof (DeviceClass),
228 (GBaseInitFunc) device_base_init,
229 (GBaseFinalizeFunc) NULL,
230 (GClassInitFunc) device_class_init,
231 (GClassFinalizeFunc) NULL,
232 NULL /* class_data */,
235 (GInstanceInitFunc) device_init,
239 type = g_type_register_static (G_TYPE_OBJECT, "Device", &info,
240 (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
246 static void device_finalize(GObject *obj_self) {
247 Device *self G_GNUC_UNUSED = DEVICE (obj_self);
248 if(G_OBJECT_CLASS(parent_class)->finalize)
249 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
251 /* Here we call device_finish() if it hasn't been done
252 yet. Subclasses may need to do this same check earlier. */
253 if (self->access_mode != ACCESS_NULL) {
257 amfree(self->device_name);
258 amfree(self->volume_label);
259 amfree(self->volume_time);
260 amfree(self->volume_header);
261 amfree(selfp->errmsg);
262 amfree(selfp->statusmsg);
263 g_hash_table_destroy(selfp->simple_properties);
264 amfree(self->private);
268 device_init (Device * self)
270 self->private = malloc(sizeof(DevicePrivate));
271 self->device_name = NULL;
272 self->access_mode = ACCESS_NULL;
273 self->is_eof = FALSE;
274 self->is_eom = FALSE;
277 self->in_file = FALSE;
278 self->volume_label = NULL;
279 self->volume_time = NULL;
280 self->status = DEVICE_STATUS_SUCCESS;
281 self->min_block_size = 1;
282 self->max_block_size = SIZE_MAX; /* subclasses *really* should choose something smaller */
283 self->block_size = DISK_BLOCK_BYTES;
284 selfp->errmsg = NULL;
285 selfp->statusmsg = NULL;
286 selfp->last_status = 0;
287 selfp->simple_properties =
288 g_hash_table_new_full(g_direct_hash,
291 (GDestroyNotify) simple_property_free);
295 device_class_init (DeviceClass * device_class)
297 GObjectClass *g_object_class = (GObjectClass*) device_class;
299 parent_class = g_type_class_ref (G_TYPE_OBJECT);
301 device_class->directtcp_supported = FALSE;
303 device_class->open_device = default_device_open_device;
304 device_class->configure = default_device_configure;
305 device_class->property_get_ex = default_device_property_get_ex;
306 device_class->property_set_ex = default_device_property_set_ex;
307 g_object_class->finalize = device_finalize;
311 device_base_init (DeviceClass * device_class)
313 /* The base_init function is called once each time a child class is
314 * created, before the class_init functions (even our own) are called. */
316 device_class->class_properties = g_array_new(FALSE, TRUE, sizeof(DeviceProperty));
317 device_class->class_properties_list = NULL;
319 device_class_register_property(device_class, PROPERTY_BLOCK_SIZE,
320 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
321 property_get_block_size_fn,
322 property_set_block_size_fn);
324 device_class_register_property(device_class, PROPERTY_MIN_BLOCK_SIZE,
325 PROPERTY_ACCESS_GET_MASK,
326 property_get_min_block_size_fn,
329 device_class_register_property(device_class, PROPERTY_MAX_BLOCK_SIZE,
330 PROPERTY_ACCESS_GET_MASK,
331 property_get_max_block_size_fn,
334 device_class_register_property(device_class, PROPERTY_CANONICAL_NAME,
335 PROPERTY_ACCESS_GET_MASK,
336 property_get_canonical_name_fn,
339 device_class_register_property(device_class, PROPERTY_CONCURRENCY,
340 PROPERTY_ACCESS_GET_MASK,
341 device_simple_property_get_fn,
342 device_simple_property_set_fn);
344 device_class_register_property(device_class, PROPERTY_STREAMING,
345 PROPERTY_ACCESS_GET_MASK,
346 device_simple_property_get_fn,
347 device_simple_property_set_fn);
349 device_class_register_property(device_class, PROPERTY_APPENDABLE,
350 PROPERTY_ACCESS_GET_MASK,
351 device_simple_property_get_fn,
352 device_simple_property_set_fn);
354 device_class_register_property(device_class, PROPERTY_PARTIAL_DELETION,
355 PROPERTY_ACCESS_GET_MASK,
356 device_simple_property_get_fn,
357 device_simple_property_set_fn);
359 device_class_register_property(device_class, PROPERTY_FULL_DELETION,
360 PROPERTY_ACCESS_GET_MASK,
361 device_simple_property_get_fn,
362 device_simple_property_set_fn);
364 device_class_register_property(device_class, PROPERTY_MEDIUM_ACCESS_TYPE,
365 PROPERTY_ACCESS_GET_MASK,
366 device_simple_property_get_fn,
367 device_simple_property_set_fn);
369 device_class_register_property(device_class, PROPERTY_COMMENT,
370 PROPERTY_ACCESS_GET_MASK|PROPERTY_ACCESS_SET_MASK,
371 device_simple_property_get_fn,
372 device_simple_property_set_fn);
374 device_class_register_property(device_class, PROPERTY_LEOM,
375 PROPERTY_ACCESS_GET_MASK,
376 device_simple_property_get_fn,
377 device_simple_property_set_fn);
380 static void simple_property_free(SimpleProperty * resp) {
381 g_value_unset(&(resp->response));
386 regex_message(int result, regex_t *regex) {
390 size = regerror(result, regex, NULL, 0);
392 regerror(result, regex, rval, size);
398 handle_device_regex(const char * user_name, char ** driver_name,
399 char ** device, char **errmsg) {
402 regmatch_t pmatch[3];
403 static const char * regex_string = "^([a-z0-9]+):(.*)$";
405 bzero(®ex, sizeof(regex));
407 reg_result = regcomp(®ex, regex_string, REG_EXTENDED | REG_ICASE);
408 if (reg_result != 0) {
409 char * message = regex_message(reg_result, ®ex);
410 *errmsg = newvstrallocf(*errmsg, "Error compiling regular expression \"%s\": %s\n",
411 regex_string, message);
416 reg_result = regexec(®ex, user_name, 3, pmatch, 0);
417 if (reg_result != 0 && reg_result != REG_NOMATCH) {
418 char * message = regex_message(reg_result, ®ex);
419 *errmsg = newvstrallocf(*errmsg,
420 "Error applying regular expression \"%s\" to string \"%s\": %s\n",
421 user_name, regex_string, message);
425 } else if (reg_result == REG_NOMATCH) {
426 #ifdef WANT_TAPE_DEVICE
428 "\"%s\" uses deprecated device naming convention; \n"
429 "using \"tape:%s\" instead.\n",
430 user_name, user_name);
431 *driver_name = stralloc("tape");
432 *device = stralloc(user_name);
433 #else /* !WANT_TAPE_DEVICE */
434 *errmsg = newvstrallocf(*errmsg, "\"%s\" is not a valid device name.\n", user_name);
437 #endif /* WANT_TAPE_DEVICE */
439 *driver_name = find_regex_substring(user_name, pmatch[1]);
440 *device = find_regex_substring(user_name, pmatch[2]);
446 /* helper function for device_open */
448 make_null_error(char *errmsg, DeviceStatusFlags status)
450 DeviceFactory factory;
453 factory = lookup_device_factory("null");
454 g_assert(factory != NULL);
456 device = factory("null:", "null", "");
457 device_set_error(device, errmsg, status);
463 device_unaliased_name(
467 char *unaliased_name;
469 /* look up the unaliased device name in the configuration */
470 if ((dc = lookup_device_config(device_name))) {
471 if (!(unaliased_name = device_config_get_tapedev(dc))
472 || unaliased_name[0] == '\0') {
476 unaliased_name = device_name;
479 return unaliased_name;
483 device_open (char * device_name)
485 char *device_type = NULL;
486 char *device_node = NULL;
488 char *unaliased_name = NULL;
489 DeviceFactory factory;
492 g_assert(device_name != NULL);
494 if (driverList == NULL) {
495 g_critical("device_open() called without device_api_init()!");
496 g_assert_not_reached();
499 if (device_name == NULL)
500 return make_null_error(stralloc(_("No device name specified")), DEVICE_STATUS_DEVICE_ERROR);
502 unaliased_name = device_unaliased_name(device_name);
503 if (!unaliased_name) {
504 return make_null_error(
505 vstrallocf(_("Device '%s' has no tapedev"), device_name),
506 DEVICE_STATUS_DEVICE_ERROR);
509 if (!handle_device_regex(unaliased_name, &device_type, &device_node,
513 return make_null_error(errmsg, DEVICE_STATUS_DEVICE_ERROR);
516 factory = lookup_device_factory(device_type);
518 if (factory == NULL) {
519 Device *nulldev = make_null_error(vstrallocf(_("Device type %s is not known."),
520 device_type), DEVICE_STATUS_DEVICE_ERROR);
526 device = factory(device_name, device_type, device_node);
527 g_assert(device != NULL); /* factories must always return a device */
529 device->device_mutex = g_mutex_new();
537 device_error(Device * self)
540 return device_error_or_status(self);
541 } else if (selfp->errmsg) {
542 return selfp->errmsg;
544 return "Unknown Device error";
549 device_status_error(Device * self)
555 return device_error_or_status(self);
558 /* reuse a previous statusmsg, if it was for the same status */
559 if (selfp->statusmsg && selfp->last_status == self->status)
560 return selfp->statusmsg;
562 amfree(selfp->statusmsg);
564 status_strv = g_flags_nick_to_strv(self->status, DEVICE_STATUS_FLAGS_TYPE);
565 g_assert(g_strv_length(status_strv) > 0);
566 if (g_strv_length(status_strv) == 1) {
567 statusmsg = stralloc(*status_strv);
569 char * status_list = g_english_strjoinv(status_strv, "or");
570 statusmsg = g_strdup_printf("one of %s", status_list);
573 g_strfreev(status_strv);
575 selfp->statusmsg = statusmsg;
576 selfp->last_status = self->status;
581 device_error_or_status(Device * self)
584 return "Device is NULL";
585 } else if (selfp->errmsg) {
586 return selfp->errmsg;
588 return device_status_error(self);
593 device_set_error(Device *self, char *errmsg, DeviceStatusFlags new_flags)
600 g_warning("device_set_error called with a NULL device: '%s'", errmsg? errmsg:"(NULL)");
605 device_name = self->device_name? self->device_name : "(unknown device)";
607 if (errmsg && (!selfp->errmsg || strcmp(errmsg, selfp->errmsg) != 0))
608 g_debug("Device %s error = '%s'", device_name, errmsg);
610 amfree(selfp->errmsg);
611 selfp->errmsg = errmsg;
613 if (new_flags != DEVICE_STATUS_SUCCESS) {
614 flags_strv = g_flags_name_to_strv(new_flags, DEVICE_STATUS_FLAGS_TYPE);
615 g_assert(g_strv_length(flags_strv) > 0);
616 flags_str = g_english_strjoinv(flags_strv, "and");
617 g_debug("Device %s setting status flag(s): %s", device_name, flags_str);
619 g_strfreev(flags_strv);
622 self->status = new_flags;
625 char * device_build_amanda_header(Device * self, const dumpfile_t * info,
627 return build_header(info, size, self->block_size);
630 dumpfile_t * make_tapestart_header(Device * self, char * label,
634 bzero(&val, sizeof(val));
636 g_assert(label != NULL);
638 rval = malloc(sizeof(*rval));
640 rval->type = F_TAPESTART;
641 if (device_property_get(self, PROPERTY_BLOCK_SIZE, &val)) {
642 rval->blocksize = g_value_get_int(&val);
646 amfree(self->volume_time);
647 if (get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
648 self->volume_time = get_proper_stamp_from_time(time(NULL));
650 self->volume_time = g_strdup(timestamp);
652 strncpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp));
653 strncpy(rval->name, label, sizeof(rval->name));
658 dumpfile_t * make_tapeend_header(void) {
662 rval = malloc(sizeof(*rval));
663 rval->type = F_TAPEEND;
664 timestamp = get_timestamp_from_time(time(NULL));
665 strncpy(rval->datestamp, timestamp, sizeof(rval->datestamp));
670 /* Try setting the blocksize on a device. Check results, fallback, and
671 * set error status for problems. */
673 try_set_blocksize(Device * device, guint blocksize) {
676 bzero(&val, sizeof(val));
678 g_value_init(&val, G_TYPE_INT);
679 g_value_set_int(&val, blocksize);
680 success = device_property_set(device, PROPERTY_BLOCK_SIZE, &val);
684 device_set_error(device,
685 vstrallocf(_("Setting BLOCK_SIZE to %u "
686 "not supported for device %s.\n"),
687 blocksize, device->device_name),
688 DEVICE_STATUS_DEVICE_ERROR);
694 /* A GHFunc (callback for g_hash_table_foreach) */
695 static void set_device_property(gpointer key_p, gpointer value_p,
696 gpointer user_data_p) {
697 char * property_s = key_p;
698 property_t * property = value_p;
699 Device * device = user_data_p;
700 const DevicePropertyBase* property_base;
701 GValue property_value;
704 g_return_if_fail(IS_DEVICE(device));
705 g_return_if_fail(property_s != NULL);
706 g_return_if_fail(property != NULL);
707 g_return_if_fail(property->values != NULL);
709 /* don't continue beating on a device that's already erroring */
710 if (device_in_error(device)) return;
712 property_base = device_property_get_by_name(property_s);
713 if (property_base == NULL) {
714 /* Nonexistant property name. */
715 device_set_error(device,
716 vstrallocf(_("unknown device property name '%s'"), property_s),
717 DEVICE_STATUS_DEVICE_ERROR);
720 if (g_slist_length(property->values) > 1) {
721 device_set_error(device,
722 vstrallocf(_("multiple values for device property '%s'"), property_s),
723 DEVICE_STATUS_DEVICE_ERROR);
727 bzero(&property_value, sizeof(property_value));
728 g_value_init(&property_value, property_base->type);
729 value = property->values->data;
730 if (!g_value_set_from_string(&property_value, value)) {
731 /* Value type could not be interpreted. */
732 device_set_error(device,
733 vstrallocf(_("Could not parse property value '%s' for property '%s' (property type %s)"),
734 value, property_base->name, g_type_name(property_base->type)),
735 DEVICE_STATUS_DEVICE_ERROR);
738 g_assert (G_VALUE_HOLDS(&property_value, property_base->type));
741 if (!device_property_set(device, property_base->ID, &property_value)) {
742 /* Device rejects property. */
743 if (!device_in_error(device)) {
744 device_set_error(device,
745 vstrallocf(_("Could not set property '%s' to '%s' on %s"),
746 property_base->name, value, device->device_name),
747 DEVICE_STATUS_DEVICE_ERROR);
753 /* Set up properties based on various taper-related configuration parameters
754 * and from the tapetype.
757 set_properties_from_global_config(Device * device) {
758 char * tapetype_name = getconf_str(CNF_TAPETYPE);
759 if (tapetype_name != NULL) {
760 tapetype_t * tapetype = lookup_tapetype(tapetype_name);
761 if (tapetype != NULL) {
767 bzero(&val, sizeof(GValue));
769 if (tapetype_seen(tapetype, TAPETYPE_LENGTH)) {
770 length = tapetype_get_length(tapetype);
771 g_value_init(&val, G_TYPE_UINT64);
772 g_value_set_uint64(&val, length * 1024);
773 /* If this fails, it's not really an error. */
774 device_property_set(device, PROPERTY_MAX_VOLUME_USAGE, &val);
778 if (tapetype_seen(tapetype, TAPETYPE_READBLOCKSIZE)) {
779 blocksize_kb = tapetype_get_readblocksize(tapetype);
780 g_value_init(&val, G_TYPE_UINT);
781 g_value_set_uint(&val, blocksize_kb * 1024);
782 success = device_property_set(device,
783 PROPERTY_READ_BLOCK_SIZE,
787 /* a non-fatal error */
788 g_warning("Setting READ_BLOCK_SIZE to %ju not supported for device %s.",
789 1024*(uintmax_t)blocksize_kb, device->device_name);
793 if (tapetype_seen(tapetype, TAPETYPE_BLOCKSIZE)) {
794 blocksize_kb = tapetype_get_blocksize(tapetype);
795 /* TODO: handle errors */
796 (void)try_set_blocksize(device, blocksize_kb * 1024);
801 g_hash_table_foreach(getconf_proplist(CNF_DEVICE_PROPERTY),
802 set_device_property, device);
805 /* Set properties specified within a device definition */
807 set_properties_from_device_config(Device * device, device_config_t *dc) {
808 g_hash_table_foreach(device_config_get_property(dc),
809 set_device_property, device);
813 default_device_configure(Device *self, gboolean use_global_config)
817 if (device_in_error(self))
820 if (use_global_config)
821 set_properties_from_global_config(self);
823 if (device_in_error(self))
826 if ((dc = lookup_device_config(self->device_name)))
827 set_properties_from_device_config(self, dc);
829 return !device_in_error(self);
832 void device_clear_volume_details(Device * device) {
833 if (device == NULL || device->access_mode != ACCESS_NULL) {
837 amfree(device->volume_label);
838 amfree(device->volume_time);
841 /* Here we put default implementations of virtual functions. Since
842 this class is virtual, many of these functions offer at best
843 incomplete functionality. But they do offer the useful commonality
844 that all devices can expect to need. */
846 static void default_device_open_device(Device * self, char * device_name,
847 char * device_type G_GNUC_UNUSED, char * device_node G_GNUC_UNUSED) {
848 /* Set the device_name property */
849 self->device_name = stralloc(device_name);
853 property_get_block_size_fn(
855 DevicePropertyBase *base G_GNUC_UNUSED,
857 PropertySurety *surety,
858 PropertySource *source)
860 g_value_unset_init(val, G_TYPE_INT);
861 g_assert(self->block_size < G_MAXINT); /* gsize -> gint */
862 g_value_set_int(val, (gint)self->block_size);
865 *surety = self->block_size_surety;
868 *source = self->block_size_source;
874 property_set_block_size_fn(
876 DevicePropertyBase *base G_GNUC_UNUSED,
878 PropertySurety surety,
879 PropertySource source)
881 gint block_size = g_value_get_int(val);
883 g_assert(block_size >= 0); /* int -> gsize (unsigned) */
884 if ((gsize)block_size < self->min_block_size
885 || (gsize)block_size > self->max_block_size) {
886 device_set_error(self,
887 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),
888 DEVICE_STATUS_DEVICE_ERROR);
892 self->block_size = block_size;
893 self->block_size_surety = surety;
894 self->block_size_source = source;
900 property_get_min_block_size_fn(
902 DevicePropertyBase *base G_GNUC_UNUSED,
904 PropertySurety *surety,
905 PropertySource *source)
907 g_value_unset_init(val, G_TYPE_UINT);
908 g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
909 g_value_set_uint(val, (guint)self->min_block_size);
912 *surety = PROPERTY_SURETY_GOOD;
915 *source = PROPERTY_SOURCE_DEFAULT;
921 property_get_max_block_size_fn(
923 DevicePropertyBase *base G_GNUC_UNUSED,
925 PropertySurety *surety,
926 PropertySource *source)
928 g_value_unset_init(val, G_TYPE_UINT);
929 g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
930 g_value_set_uint(val, (guint)self->max_block_size);
933 *surety = PROPERTY_SURETY_GOOD;
936 *source = PROPERTY_SOURCE_DEFAULT;
942 property_get_canonical_name_fn(
944 DevicePropertyBase *base G_GNUC_UNUSED,
946 PropertySurety *surety,
947 PropertySource *source)
949 g_value_unset_init(val, G_TYPE_STRING);
950 g_value_set_string(val, self->device_name);
953 *surety = PROPERTY_SURETY_GOOD;
956 *source = PROPERTY_SOURCE_DEFAULT;
962 static PropertyPhaseFlags
966 if (self->access_mode == ACCESS_NULL) {
967 return PROPERTY_PHASE_BEFORE_START;
968 } else if (IS_WRITABLE_ACCESS_MODE(self->access_mode)) {
970 return PROPERTY_PHASE_INSIDE_FILE_WRITE;
972 return PROPERTY_PHASE_BETWEEN_FILE_WRITE;
974 } else { /* read mode */
976 return PROPERTY_PHASE_INSIDE_FILE_READ;
978 return PROPERTY_PHASE_BETWEEN_FILE_READ;
983 /* This default implementation serves up static responses, and
984 implements a few default responses based on values from the Device
987 default_device_property_get_ex(
991 PropertySurety *surety,
992 PropertySource *source)
994 DeviceProperty *prop;
995 GArray *class_properties;
996 PropertyPhaseFlags cur_phase;
998 /* Most of this function's job is to sanity-check everything, then
999 * call the relevant getter. */
1001 class_properties = DEVICE_GET_CLASS(self)->class_properties;
1002 if (id >= class_properties->len)
1005 prop = &g_array_index(class_properties, DeviceProperty, id);
1006 if (prop->base == NULL)
1009 if (val || surety || source) {
1010 /* check the phase */
1011 cur_phase = state_to_phase(self);
1012 if (!(prop->access & cur_phase))
1015 if (prop->getter == NULL)
1018 if (!prop->getter(self, prop->base, val, surety, source))
1026 default_device_property_set_ex(
1028 DevicePropertyId id,
1030 PropertySurety surety,
1031 PropertySource source)
1033 DeviceProperty *prop;
1034 GArray *class_properties;
1035 PropertyPhaseFlags cur_phase;
1037 /* Most of this function's job is to sanity-check everything, then
1038 * call the relevant setter. */
1040 if (device_in_error(self))
1043 class_properties = DEVICE_GET_CLASS(self)->class_properties;
1044 if (id >= class_properties->len)
1047 prop = &g_array_index(class_properties, DeviceProperty, id);
1048 if (prop->base == NULL)
1051 /* check that the type matches */
1052 if (!G_VALUE_HOLDS(val, prop->base->type))
1055 /* check the phase */
1056 cur_phase = state_to_phase(self) << PROPERTY_PHASE_SHIFT;
1057 if (!(prop->access & cur_phase))
1060 if (prop->setter == NULL)
1063 if (!prop->setter(self, prop->base, val, surety, source))
1070 device_property_get_list (Device * self)
1072 g_assert(IS_DEVICE(self));
1074 return DEVICE_GET_CLASS(self)->class_properties_list;
1078 * All the functions below this comment are stub functions that do nothing
1079 * but implement the virtual function table. Call these functions and they
1080 * will do what you expect vis-a-vis virtual functions. But don't put code
1081 * in them beyond error checking and VFT lookup. */
1084 device_open_device (Device * self, char * device_name,
1085 char * device_type, char * device_node)
1089 g_assert(IS_DEVICE(self));
1090 g_assert(device_name != NULL);
1092 klass = DEVICE_GET_CLASS(self);
1093 g_assert(klass->open_device);
1094 (klass->open_device)(self, device_name, device_type, device_node);
1097 DeviceStatusFlags device_read_label(Device * self) {
1098 DeviceClass * klass;
1100 g_assert(self != NULL);
1101 g_assert(IS_DEVICE(self));
1102 g_assert(self->access_mode == ACCESS_NULL);
1104 klass = DEVICE_GET_CLASS(self);
1105 g_assert(klass->read_label);
1106 return (klass->read_label)(self);
1110 device_finish (Device * self) {
1113 g_assert(IS_DEVICE (self));
1115 klass = DEVICE_GET_CLASS(self);
1116 g_assert(klass->finish);
1117 return (klass->finish)(self);
1121 device_get_bytes_read (Device * self) {
1125 g_assert(IS_DEVICE (self));
1127 g_mutex_lock(self->device_mutex);
1128 if (self->in_file) {
1129 klass = DEVICE_GET_CLASS(self);
1130 if (klass->get_bytes_read) {
1131 bytes = (klass->get_bytes_read)(self);
1133 bytes = self->bytes_read;
1136 g_mutex_unlock(self->device_mutex);
1141 device_get_bytes_written (Device * self) {
1145 g_assert(IS_DEVICE (self));
1147 g_mutex_lock(self->device_mutex);
1148 if (self->in_file) {
1149 klass = DEVICE_GET_CLASS(self);
1150 if (klass->get_bytes_written) {
1151 bytes = (klass->get_bytes_written)(self);
1153 bytes = self->bytes_written;
1156 g_mutex_unlock(self->device_mutex);
1161 device_configure (Device * self, gboolean use_global_config)
1165 g_assert(IS_DEVICE (self));
1166 g_assert(self->access_mode == ACCESS_NULL);
1168 klass = DEVICE_GET_CLASS(self);
1169 if(klass->configure) {
1170 return (klass->configure)(self, use_global_config);
1172 device_set_error(self,
1173 stralloc(_("Unimplemented method")),
1174 DEVICE_STATUS_DEVICE_ERROR);
1180 device_start (Device * self, DeviceAccessMode mode,
1181 char * label, char * timestamp)
1184 char * local_timestamp = NULL;
1187 g_assert(IS_DEVICE (self));
1188 g_assert(mode != ACCESS_NULL);
1189 g_assert(mode != ACCESS_WRITE || label != NULL);
1191 klass = DEVICE_GET_CLASS(self);
1192 g_assert(klass->start);
1194 /* For a good combination of synchronization and public simplicity,
1195 this stub function does not require a timestamp, but the actual
1196 implementation function does. We generate the timestamp here with
1198 if (mode == ACCESS_WRITE &&
1199 get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
1200 local_timestamp = timestamp =
1201 get_proper_stamp_from_time(time(NULL));
1204 rv = (klass->start)(self, mode, label, timestamp);
1205 amfree(local_timestamp);
1210 device_write_block (Device * self, guint size, gpointer block)
1214 g_assert(IS_DEVICE (self));
1217 /* these are all things that the caller should take care to
1218 * guarantee, so we just assert them here */
1219 g_assert(size <= self->block_size);
1220 g_assert(self->in_file);
1221 g_assert(!selfp->wrote_short_block);
1222 g_assert(block != NULL);
1223 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1225 if (size < self->block_size)
1226 selfp->wrote_short_block = TRUE;
1228 klass = DEVICE_GET_CLASS(self);
1229 g_assert(klass->write_block);
1230 return (*klass->write_block)(self,size, block);
1234 device_start_file (Device * self, dumpfile_t * jobInfo) {
1235 DeviceClass * klass;
1237 g_assert(IS_DEVICE (self));
1238 g_assert(!(self->in_file));
1239 g_assert(jobInfo != NULL);
1241 selfp->wrote_short_block = FALSE;
1243 klass = DEVICE_GET_CLASS(self);
1244 g_assert(klass->start_file);
1245 return (klass->start_file)(self, jobInfo );
1249 device_finish_file (Device * self)
1253 g_assert(IS_DEVICE (self));
1254 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1255 g_assert(self->in_file);
1257 klass = DEVICE_GET_CLASS(self);
1258 g_assert(klass->finish_file);
1259 return (klass->finish_file)(self);
1263 device_seek_file (Device * self, guint file)
1267 g_assert(IS_DEVICE (self));
1268 g_assert(self->access_mode == ACCESS_READ);
1270 klass = DEVICE_GET_CLASS(self);
1271 g_assert(klass->seek_file);
1272 return (klass->seek_file)(self,file);
1276 device_seek_block (Device * self, guint64 block)
1280 g_assert(IS_DEVICE (self));
1281 g_assert(self->access_mode == ACCESS_READ);
1282 g_assert(self->in_file);
1284 klass = DEVICE_GET_CLASS(self);
1285 g_assert(klass->seek_block);
1286 return (klass->seek_block)(self,block);
1290 device_read_block (Device * self, gpointer buffer, int * size)
1294 g_assert(IS_DEVICE (self));
1295 g_assert(size != NULL);
1296 g_assert(self->access_mode == ACCESS_READ);
1299 g_assert(buffer != NULL);
1302 klass = DEVICE_GET_CLASS(self);
1303 g_assert(klass->read_block);
1304 return (klass->read_block)(self,buffer,size);
1308 device_property_get_ex(
1310 DevicePropertyId id,
1312 PropertySurety *surety,
1313 PropertySource *source)
1317 g_assert(IS_DEVICE (self));
1318 g_assert(device_property_get_by_id(id) != NULL);
1320 klass = DEVICE_GET_CLASS(self);
1322 g_assert(klass->property_get_ex);
1323 return (klass->property_get_ex)(self, id, val, surety, source);
1327 device_property_set_ex(
1329 DevicePropertyId id,
1331 PropertySurety surety,
1332 PropertySource source)
1336 g_assert(IS_DEVICE (self));
1338 klass = DEVICE_GET_CLASS(self);
1340 g_assert(klass->property_set_ex);
1341 return (klass->property_set_ex)(self, id, val, surety, source);
1345 device_recycle_file (Device * self, guint filenum)
1349 g_assert(self != NULL);
1350 g_assert(IS_DEVICE (self));
1351 g_assert(self->access_mode == ACCESS_APPEND);
1352 g_assert(!self->in_file);
1354 klass = DEVICE_GET_CLASS(self);
1356 g_assert(klass->recycle_file);
1357 return (klass->recycle_file)(self,filenum);
1361 device_erase (Device * self)
1365 g_assert(IS_DEVICE (self));
1366 g_assert(self->access_mode == ACCESS_NULL);
1367 g_assert(!self->in_file);
1369 klass = DEVICE_GET_CLASS(self);
1371 return (klass->erase)(self);
1373 device_set_error(self,
1374 stralloc(_("Unimplemented method")),
1375 DEVICE_STATUS_DEVICE_ERROR);
1381 device_eject (Device * self)
1385 g_assert(IS_DEVICE (self));
1386 g_assert(self->access_mode == ACCESS_NULL);
1387 g_assert(!self->in_file);
1389 klass = DEVICE_GET_CLASS(self);
1391 return (klass->eject)(self);
1400 gboolean for_writing,
1401 DirectTCPAddr **addrs)
1405 klass = DEVICE_GET_CLASS(self);
1407 return (klass->listen)(self, for_writing, addrs);
1409 device_set_error(self,
1410 stralloc(_("Unimplemented method")),
1411 DEVICE_STATUS_DEVICE_ERROR);
1419 DirectTCPConnection **conn,
1420 ProlongProc prolong,
1421 gpointer prolong_data)
1425 klass = DEVICE_GET_CLASS(self);
1427 return (klass->accept)(self, conn, prolong, prolong_data);
1429 device_set_error(self,
1430 stralloc(_("Unimplemented method")),
1431 DEVICE_STATUS_DEVICE_ERROR);
1437 device_accept_with_cond(
1439 DirectTCPConnection **conn,
1440 GMutex *abort_mutex,
1445 klass = DEVICE_GET_CLASS(self);
1446 if(klass->accept_with_cond) {
1447 return (klass->accept_with_cond)(self, conn, abort_mutex, abort_cond);
1449 device_set_error(self,
1450 g_strdup(_("Unimplemented method")),
1451 DEVICE_STATUS_DEVICE_ERROR);
1459 gboolean for_writing,
1460 DirectTCPAddr *addrs,
1461 DirectTCPConnection **conn,
1462 ProlongProc prolong,
1463 gpointer prolong_data)
1467 klass = DEVICE_GET_CLASS(self);
1468 if(klass->connect) {
1469 return (klass->connect)(self, for_writing, addrs, conn, prolong, prolong_data);
1471 device_set_error(self,
1472 stralloc(_("Unimplemented method")),
1473 DEVICE_STATUS_DEVICE_ERROR);
1479 device_connect_with_cond(
1481 gboolean for_writing,
1482 DirectTCPAddr *addrs,
1483 DirectTCPConnection **conn,
1484 GMutex *abort_mutex,
1489 klass = DEVICE_GET_CLASS(self);
1490 if(klass->connect) {
1491 return (klass->connect_with_cond)(self, for_writing, addrs, conn, abort_mutex, abort_cond);
1493 device_set_error(self,
1494 g_strdup(_("Unimplemented method")),
1495 DEVICE_STATUS_DEVICE_ERROR);
1501 device_write_from_connection(
1504 guint64 *actual_size)
1508 klass = DEVICE_GET_CLASS(self);
1510 g_assert(self->in_file);
1511 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1513 if(klass->write_from_connection) {
1514 return (klass->write_from_connection)(self, size, actual_size);
1516 device_set_error(self,
1517 stralloc(_("Unimplemented method")),
1518 DEVICE_STATUS_DEVICE_ERROR);
1524 device_read_to_connection(
1527 guint64 *actual_size)
1531 g_assert(self->in_file);
1532 g_assert(self->access_mode == ACCESS_READ);
1534 klass = DEVICE_GET_CLASS(self);
1535 if(klass->read_to_connection) {
1536 return (klass->read_to_connection)(self, size, actual_size);
1538 device_set_error(self,
1539 stralloc(_("Unimplemented method")),
1540 DEVICE_STATUS_DEVICE_ERROR);
1546 device_use_connection(
1548 DirectTCPConnection *conn)
1552 g_assert(self->access_mode == ACCESS_NULL);
1554 klass = DEVICE_GET_CLASS(self);
1555 if(klass->use_connection) {
1556 return (klass->use_connection)(self, conn);
1558 device_set_error(self,
1559 stralloc(_("Unimplemented method")),
1560 DEVICE_STATUS_DEVICE_ERROR);
1565 /* Property handling */
1568 device_class_register_property(
1570 DevicePropertyId id,
1571 PropertyAccessFlags access,
1572 PropertyGetFn getter,
1573 PropertySetFn setter)
1575 DevicePropertyBase *base;
1576 DeviceProperty *prop;
1580 g_assert(klass != NULL);
1582 base = device_property_get_by_id(id);
1583 g_assert(base != NULL);
1585 if (klass->class_properties->len <= id) {
1586 g_array_set_size(klass->class_properties, id+1);
1589 prop = &g_array_index(klass->class_properties, DeviceProperty, id);
1591 prop->access = access;
1592 prop->getter = getter;
1593 prop->setter = setter;
1595 /* completely rewrite the list of prop pointers, as they may have changed,
1596 * or we may have replaced an existing property*/
1598 if (klass->class_properties_list) {
1599 g_slist_free(klass->class_properties_list);
1603 for (i = 0; i < klass->class_properties->len; i++) {
1604 prop = &g_array_index(klass->class_properties, DeviceProperty, i);
1607 proplist = g_slist_prepend(proplist, prop);
1610 klass->class_properties_list = proplist;
1614 device_set_simple_property(
1616 DevicePropertyId id,
1618 PropertySurety surety,
1619 PropertySource source)
1621 SimpleProperty *simp;
1622 DeviceProperty *prop;
1624 prop = &g_array_index(DEVICE_GET_CLASS(self)->class_properties,
1625 DeviceProperty, id);
1627 /* these assertions should already be checked, but let's be sure */
1628 g_assert(prop->base != NULL); /* prop must be registered with device */
1629 g_assert(G_VALUE_HOLDS(val, prop->base->type));
1631 simp = g_new0(SimpleProperty, 1);
1633 g_value_unset_copy(val, &(simp->response));
1634 simp->surety = surety;
1635 simp->source = source;
1637 g_hash_table_insert(selfp->simple_properties,
1638 GINT_TO_POINTER(id),
1645 device_simple_property_set_fn(
1647 DevicePropertyBase *base,
1649 PropertySurety surety,
1650 PropertySource source)
1652 return device_set_simple_property(self, base->ID, val, surety, source);
1656 device_get_simple_property(
1658 DevicePropertyId id,
1660 PropertySurety *surety,
1661 PropertySource *source)
1663 SimpleProperty *simp =
1664 g_hash_table_lookup(selfp->simple_properties,
1665 GINT_TO_POINTER(id));
1671 g_value_unset_copy(&(simp->response), val);
1674 *surety = simp->surety;
1677 *source = simp->source;
1683 device_simple_property_get_fn(
1685 DevicePropertyBase *base,
1687 PropertySurety *surety,
1688 PropertySource *source)
1690 return device_get_simple_property(self, base->ID, val, surety, source);