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. */
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 */
536 device_error(Device * self)
539 return device_error_or_status(self);
540 } else if (selfp->errmsg) {
541 return selfp->errmsg;
543 return "Unknown Device error";
548 device_status_error(Device * self)
554 return device_error_or_status(self);
557 /* reuse a previous statusmsg, if it was for the same status */
558 if (selfp->statusmsg && selfp->last_status == self->status)
559 return selfp->statusmsg;
561 amfree(selfp->statusmsg);
563 status_strv = g_flags_nick_to_strv(self->status, DEVICE_STATUS_FLAGS_TYPE);
564 g_assert(g_strv_length(status_strv) > 0);
565 if (g_strv_length(status_strv) == 1) {
566 statusmsg = stralloc(*status_strv);
568 char * status_list = g_english_strjoinv(status_strv, "or");
569 statusmsg = g_strdup_printf("one of %s", status_list);
572 g_strfreev(status_strv);
574 selfp->statusmsg = statusmsg;
575 selfp->last_status = self->status;
580 device_error_or_status(Device * self)
583 return "Device is NULL";
584 } else if (selfp->errmsg) {
585 return selfp->errmsg;
587 return device_status_error(self);
592 device_set_error(Device *self, char *errmsg, DeviceStatusFlags new_flags)
599 g_warning("device_set_error called with a NULL device: '%s'", errmsg? errmsg:"(NULL)");
604 device_name = self->device_name? self->device_name : "(unknown device)";
606 if (errmsg && (!selfp->errmsg || strcmp(errmsg, selfp->errmsg) != 0))
607 g_debug("Device %s error = '%s'", device_name, errmsg);
609 amfree(selfp->errmsg);
610 selfp->errmsg = errmsg;
612 if (new_flags != DEVICE_STATUS_SUCCESS) {
613 flags_strv = g_flags_name_to_strv(new_flags, DEVICE_STATUS_FLAGS_TYPE);
614 g_assert(g_strv_length(flags_strv) > 0);
615 flags_str = g_english_strjoinv(flags_strv, "and");
616 g_debug("Device %s setting status flag(s): %s", device_name, flags_str);
618 g_strfreev(flags_strv);
621 self->status = new_flags;
624 char * device_build_amanda_header(Device * self, const dumpfile_t * info,
626 return build_header(info, size, self->block_size);
629 dumpfile_t * make_tapestart_header(Device * self, char * label,
633 bzero(&val, sizeof(val));
635 g_assert(label != NULL);
637 rval = malloc(sizeof(*rval));
639 rval->type = F_TAPESTART;
640 if (device_property_get(self, PROPERTY_BLOCK_SIZE, &val)) {
641 rval->blocksize = g_value_get_int(&val);
645 amfree(self->volume_time);
646 if (get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
647 self->volume_time = get_proper_stamp_from_time(time(NULL));
649 self->volume_time = g_strdup(timestamp);
651 strncpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp));
652 strncpy(rval->name, label, sizeof(rval->name));
657 dumpfile_t * make_tapeend_header(void) {
661 rval = malloc(sizeof(*rval));
662 rval->type = F_TAPEEND;
663 timestamp = get_timestamp_from_time(time(NULL));
664 strncpy(rval->datestamp, timestamp, sizeof(rval->datestamp));
669 /* Try setting the blocksize on a device. Check results, fallback, and
670 * set error status for problems. */
672 try_set_blocksize(Device * device, guint blocksize) {
675 bzero(&val, sizeof(val));
677 g_value_init(&val, G_TYPE_INT);
678 g_value_set_int(&val, blocksize);
679 success = device_property_set(device, PROPERTY_BLOCK_SIZE, &val);
683 device_set_error(device,
684 vstrallocf(_("Setting BLOCK_SIZE to %u "
685 "not supported for device %s.\n"),
686 blocksize, device->device_name),
687 DEVICE_STATUS_DEVICE_ERROR);
693 /* A GHFunc (callback for g_hash_table_foreach) */
694 static void set_device_property(gpointer key_p, gpointer value_p,
695 gpointer user_data_p) {
696 char * property_s = key_p;
697 property_t * property = value_p;
698 Device * device = user_data_p;
699 const DevicePropertyBase* property_base;
700 GValue property_value;
703 g_return_if_fail(IS_DEVICE(device));
704 g_return_if_fail(property_s != NULL);
705 g_return_if_fail(property != NULL);
706 g_return_if_fail(property->values != NULL);
708 /* don't continue beating on a device that's already erroring */
709 if (device_in_error(device)) return;
711 property_base = device_property_get_by_name(property_s);
712 if (property_base == NULL) {
713 /* Nonexistant property name. */
714 device_set_error(device,
715 vstrallocf(_("unknown device property name '%s'"), property_s),
716 DEVICE_STATUS_DEVICE_ERROR);
719 if (g_slist_length(property->values) > 1) {
720 device_set_error(device,
721 vstrallocf(_("multiple values for device property '%s'"), property_s),
722 DEVICE_STATUS_DEVICE_ERROR);
726 bzero(&property_value, sizeof(property_value));
727 g_value_init(&property_value, property_base->type);
728 value = property->values->data;
729 if (!g_value_set_from_string(&property_value, value)) {
730 /* Value type could not be interpreted. */
731 device_set_error(device,
732 vstrallocf(_("Could not parse property value '%s' for property '%s' (property type %s)"),
733 value, property_base->name, g_type_name(property_base->type)),
734 DEVICE_STATUS_DEVICE_ERROR);
737 g_assert (G_VALUE_HOLDS(&property_value, property_base->type));
740 if (!device_property_set(device, property_base->ID, &property_value)) {
741 /* Device rejects property. */
742 if (!device_in_error(device)) {
743 device_set_error(device,
744 vstrallocf(_("Could not set property '%s' to '%s' on %s"),
745 property_base->name, value, device->device_name),
746 DEVICE_STATUS_DEVICE_ERROR);
752 /* Set up properties based on various taper-related configuration parameters
753 * and from the tapetype.
756 set_properties_from_global_config(Device * device) {
757 char * tapetype_name = getconf_str(CNF_TAPETYPE);
758 if (tapetype_name != NULL) {
759 tapetype_t * tapetype = lookup_tapetype(tapetype_name);
760 if (tapetype != NULL) {
766 bzero(&val, sizeof(GValue));
768 if (tapetype_seen(tapetype, TAPETYPE_LENGTH)) {
769 length = tapetype_get_length(tapetype);
770 g_value_init(&val, G_TYPE_UINT64);
771 g_value_set_uint64(&val, length * 1024);
772 /* If this fails, it's not really an error. */
773 device_property_set(device, PROPERTY_MAX_VOLUME_USAGE, &val);
777 if (tapetype_seen(tapetype, TAPETYPE_READBLOCKSIZE)) {
778 blocksize_kb = tapetype_get_readblocksize(tapetype);
779 g_value_init(&val, G_TYPE_UINT);
780 g_value_set_uint(&val, blocksize_kb * 1024);
781 success = device_property_set(device,
782 PROPERTY_READ_BLOCK_SIZE,
786 /* a non-fatal error */
787 g_warning("Setting READ_BLOCK_SIZE to %ju not supported for device %s.",
788 1024*(uintmax_t)blocksize_kb, device->device_name);
792 if (tapetype_seen(tapetype, TAPETYPE_BLOCKSIZE)) {
793 blocksize_kb = tapetype_get_blocksize(tapetype);
794 /* TODO: handle errors */
795 (void)try_set_blocksize(device, blocksize_kb * 1024);
800 g_hash_table_foreach(getconf_proplist(CNF_DEVICE_PROPERTY),
801 set_device_property, device);
804 /* Set properties specified within a device definition */
806 set_properties_from_device_config(Device * device, device_config_t *dc) {
807 g_hash_table_foreach(device_config_get_property(dc),
808 set_device_property, device);
812 default_device_configure(Device *self, gboolean use_global_config)
816 if (device_in_error(self))
819 if (use_global_config)
820 set_properties_from_global_config(self);
822 if (device_in_error(self))
825 if ((dc = lookup_device_config(self->device_name)))
826 set_properties_from_device_config(self, dc);
828 return !device_in_error(self);
831 void device_clear_volume_details(Device * device) {
832 if (device == NULL || device->access_mode != ACCESS_NULL) {
836 amfree(device->volume_label);
837 amfree(device->volume_time);
840 /* Here we put default implementations of virtual functions. Since
841 this class is virtual, many of these functions offer at best
842 incomplete functionality. But they do offer the useful commonality
843 that all devices can expect to need. */
845 static void default_device_open_device(Device * self, char * device_name,
846 char * device_type G_GNUC_UNUSED, char * device_node G_GNUC_UNUSED) {
847 /* Set the device_name property */
848 self->device_name = stralloc(device_name);
852 property_get_block_size_fn(
854 DevicePropertyBase *base G_GNUC_UNUSED,
856 PropertySurety *surety,
857 PropertySource *source)
859 g_value_unset_init(val, G_TYPE_INT);
860 g_assert(self->block_size < G_MAXINT); /* gsize -> gint */
861 g_value_set_int(val, (gint)self->block_size);
864 *surety = self->block_size_surety;
867 *source = self->block_size_source;
873 property_set_block_size_fn(
875 DevicePropertyBase *base G_GNUC_UNUSED,
877 PropertySurety surety,
878 PropertySource source)
880 gint block_size = g_value_get_int(val);
882 g_assert(block_size >= 0); /* int -> gsize (unsigned) */
883 if ((gsize)block_size < self->min_block_size
884 || (gsize)block_size > self->max_block_size) {
885 device_set_error(self,
886 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),
887 DEVICE_STATUS_DEVICE_ERROR);
891 self->block_size = block_size;
892 self->block_size_surety = surety;
893 self->block_size_source = source;
899 property_get_min_block_size_fn(
901 DevicePropertyBase *base G_GNUC_UNUSED,
903 PropertySurety *surety,
904 PropertySource *source)
906 g_value_unset_init(val, G_TYPE_UINT);
907 g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
908 g_value_set_uint(val, (guint)self->min_block_size);
911 *surety = PROPERTY_SURETY_GOOD;
914 *source = PROPERTY_SOURCE_DEFAULT;
920 property_get_max_block_size_fn(
922 DevicePropertyBase *base G_GNUC_UNUSED,
924 PropertySurety *surety,
925 PropertySource *source)
927 g_value_unset_init(val, G_TYPE_UINT);
928 g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
929 g_value_set_uint(val, (guint)self->max_block_size);
932 *surety = PROPERTY_SURETY_GOOD;
935 *source = PROPERTY_SOURCE_DEFAULT;
941 property_get_canonical_name_fn(
943 DevicePropertyBase *base G_GNUC_UNUSED,
945 PropertySurety *surety,
946 PropertySource *source)
948 g_value_unset_init(val, G_TYPE_STRING);
949 g_value_set_string(val, self->device_name);
952 *surety = PROPERTY_SURETY_GOOD;
955 *source = PROPERTY_SOURCE_DEFAULT;
961 static PropertyPhaseFlags
965 if (self->access_mode == ACCESS_NULL) {
966 return PROPERTY_PHASE_BEFORE_START;
967 } else if (IS_WRITABLE_ACCESS_MODE(self->access_mode)) {
969 return PROPERTY_PHASE_INSIDE_FILE_WRITE;
971 return PROPERTY_PHASE_BETWEEN_FILE_WRITE;
973 } else { /* read mode */
975 return PROPERTY_PHASE_INSIDE_FILE_READ;
977 return PROPERTY_PHASE_BETWEEN_FILE_READ;
982 /* This default implementation serves up static responses, and
983 implements a few default responses based on values from the Device
986 default_device_property_get_ex(
990 PropertySurety *surety,
991 PropertySource *source)
993 DeviceProperty *prop;
994 GArray *class_properties;
995 PropertyPhaseFlags cur_phase;
997 /* Most of this function's job is to sanity-check everything, then
998 * call the relevant getter. */
1000 class_properties = DEVICE_GET_CLASS(self)->class_properties;
1001 if (id >= class_properties->len)
1004 prop = &g_array_index(class_properties, DeviceProperty, id);
1005 if (prop->base == NULL)
1008 if (val || surety || source) {
1009 /* check the phase */
1010 cur_phase = state_to_phase(self);
1011 if (!(prop->access & cur_phase))
1014 if (prop->getter == NULL)
1017 if (!prop->getter(self, prop->base, val, surety, source))
1025 default_device_property_set_ex(
1027 DevicePropertyId id,
1029 PropertySurety surety,
1030 PropertySource source)
1032 DeviceProperty *prop;
1033 GArray *class_properties;
1034 PropertyPhaseFlags cur_phase;
1036 /* Most of this function's job is to sanity-check everything, then
1037 * call the relevant setter. */
1039 if (device_in_error(self))
1042 class_properties = DEVICE_GET_CLASS(self)->class_properties;
1043 if (id >= class_properties->len)
1046 prop = &g_array_index(class_properties, DeviceProperty, id);
1047 if (prop->base == NULL)
1050 /* check that the type matches */
1051 if (!G_VALUE_HOLDS(val, prop->base->type))
1054 /* check the phase */
1055 cur_phase = state_to_phase(self) << PROPERTY_PHASE_SHIFT;
1056 if (!(prop->access & cur_phase))
1059 if (prop->setter == NULL)
1062 if (!prop->setter(self, prop->base, val, surety, source))
1069 device_property_get_list (Device * self)
1071 g_assert(IS_DEVICE(self));
1073 return DEVICE_GET_CLASS(self)->class_properties_list;
1077 * All the functions below this comment are stub functions that do nothing
1078 * but implement the virtual function table. Call these functions and they
1079 * will do what you expect vis-a-vis virtual functions. But don't put code
1080 * in them beyond error checking and VFT lookup. */
1083 device_open_device (Device * self, char * device_name,
1084 char * device_type, char * device_node)
1088 g_assert(IS_DEVICE(self));
1089 g_assert(device_name != NULL);
1091 klass = DEVICE_GET_CLASS(self);
1092 g_assert(klass->open_device);
1093 (klass->open_device)(self, device_name, device_type, device_node);
1096 DeviceStatusFlags device_read_label(Device * self) {
1097 DeviceClass * klass;
1099 g_assert(self != NULL);
1100 g_assert(IS_DEVICE(self));
1101 g_assert(self->access_mode == ACCESS_NULL);
1103 klass = DEVICE_GET_CLASS(self);
1104 g_assert(klass->read_label);
1105 return (klass->read_label)(self);
1109 device_finish (Device * self) {
1112 g_assert(IS_DEVICE (self));
1114 klass = DEVICE_GET_CLASS(self);
1115 g_assert(klass->finish);
1116 return (klass->finish)(self);
1120 device_configure (Device * self, gboolean use_global_config)
1124 g_assert(IS_DEVICE (self));
1125 g_assert(self->access_mode == ACCESS_NULL);
1127 klass = DEVICE_GET_CLASS(self);
1128 if(klass->configure) {
1129 return (klass->configure)(self, use_global_config);
1131 device_set_error(self,
1132 stralloc(_("Unimplemented method")),
1133 DEVICE_STATUS_DEVICE_ERROR);
1139 device_start (Device * self, DeviceAccessMode mode,
1140 char * label, char * timestamp)
1143 char * local_timestamp = NULL;
1146 g_assert(IS_DEVICE (self));
1147 g_assert(mode != ACCESS_NULL);
1148 g_assert(mode != ACCESS_WRITE || label != NULL);
1150 klass = DEVICE_GET_CLASS(self);
1151 g_assert(klass->start);
1153 /* For a good combination of synchronization and public simplicity,
1154 this stub function does not require a timestamp, but the actual
1155 implementation function does. We generate the timestamp here with
1157 if (mode == ACCESS_WRITE &&
1158 get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
1159 local_timestamp = timestamp =
1160 get_proper_stamp_from_time(time(NULL));
1163 rv = (klass->start)(self, mode, label, timestamp);
1164 amfree(local_timestamp);
1169 device_write_block (Device * self, guint size, gpointer block)
1173 g_assert(IS_DEVICE (self));
1176 /* these are all things that the caller should take care to
1177 * guarantee, so we just assert them here */
1178 g_assert(size <= self->block_size);
1179 g_assert(self->in_file);
1180 g_assert(!selfp->wrote_short_block);
1181 g_assert(block != NULL);
1182 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1184 if (size < self->block_size)
1185 selfp->wrote_short_block = TRUE;
1187 klass = DEVICE_GET_CLASS(self);
1188 g_assert(klass->write_block);
1189 return (*klass->write_block)(self,size, block);
1193 device_start_file (Device * self, dumpfile_t * jobInfo) {
1194 DeviceClass * klass;
1196 g_assert(IS_DEVICE (self));
1197 g_assert(!(self->in_file));
1198 g_assert(jobInfo != NULL);
1200 selfp->wrote_short_block = FALSE;
1202 klass = DEVICE_GET_CLASS(self);
1203 g_assert(klass->start_file);
1204 return (klass->start_file)(self, jobInfo );
1208 device_finish_file (Device * self)
1212 g_assert(IS_DEVICE (self));
1213 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1214 g_assert(self->in_file);
1216 klass = DEVICE_GET_CLASS(self);
1217 g_assert(klass->finish_file);
1218 return (klass->finish_file)(self);
1222 device_seek_file (Device * self, guint file)
1226 g_assert(IS_DEVICE (self));
1227 g_assert(self->access_mode == ACCESS_READ);
1229 klass = DEVICE_GET_CLASS(self);
1230 g_assert(klass->seek_file);
1231 return (klass->seek_file)(self,file);
1235 device_seek_block (Device * self, guint64 block)
1239 g_assert(IS_DEVICE (self));
1240 g_assert(self->access_mode == ACCESS_READ);
1241 g_assert(self->in_file);
1243 klass = DEVICE_GET_CLASS(self);
1244 g_assert(klass->seek_block);
1245 return (klass->seek_block)(self,block);
1249 device_read_block (Device * self, gpointer buffer, int * size)
1253 g_assert(IS_DEVICE (self));
1254 g_assert(size != NULL);
1255 g_assert(self->access_mode == ACCESS_READ);
1258 g_assert(buffer != NULL);
1261 klass = DEVICE_GET_CLASS(self);
1262 g_assert(klass->read_block);
1263 return (klass->read_block)(self,buffer,size);
1267 device_property_get_ex(
1269 DevicePropertyId id,
1271 PropertySurety *surety,
1272 PropertySource *source)
1276 g_assert(IS_DEVICE (self));
1277 g_assert(device_property_get_by_id(id) != NULL);
1279 klass = DEVICE_GET_CLASS(self);
1281 g_assert(klass->property_get_ex);
1282 return (klass->property_get_ex)(self, id, val, surety, source);
1286 device_property_set_ex(
1288 DevicePropertyId id,
1290 PropertySurety surety,
1291 PropertySource source)
1295 g_assert(IS_DEVICE (self));
1297 klass = DEVICE_GET_CLASS(self);
1299 g_assert(klass->property_set_ex);
1300 return (klass->property_set_ex)(self, id, val, surety, source);
1304 device_recycle_file (Device * self, guint filenum)
1308 g_assert(self != NULL);
1309 g_assert(IS_DEVICE (self));
1310 g_assert(self->access_mode == ACCESS_APPEND);
1311 g_assert(!self->in_file);
1313 klass = DEVICE_GET_CLASS(self);
1315 g_assert(klass->recycle_file);
1316 return (klass->recycle_file)(self,filenum);
1320 device_erase (Device * self)
1324 g_assert(IS_DEVICE (self));
1325 g_assert(self->access_mode == ACCESS_NULL);
1326 g_assert(!self->in_file);
1328 klass = DEVICE_GET_CLASS(self);
1330 return (klass->erase)(self);
1332 device_set_error(self,
1333 stralloc(_("Unimplemented method")),
1334 DEVICE_STATUS_DEVICE_ERROR);
1340 device_eject (Device * self)
1344 g_assert(IS_DEVICE (self));
1345 g_assert(self->access_mode == ACCESS_NULL);
1346 g_assert(!self->in_file);
1348 klass = DEVICE_GET_CLASS(self);
1350 return (klass->eject)(self);
1359 gboolean for_writing,
1360 DirectTCPAddr **addrs)
1364 klass = DEVICE_GET_CLASS(self);
1366 return (klass->listen)(self, for_writing, addrs);
1368 device_set_error(self,
1369 stralloc(_("Unimplemented method")),
1370 DEVICE_STATUS_DEVICE_ERROR);
1378 DirectTCPConnection **conn,
1379 ProlongProc prolong,
1380 gpointer prolong_data)
1384 klass = DEVICE_GET_CLASS(self);
1386 return (klass->accept)(self, conn, prolong, prolong_data);
1388 device_set_error(self,
1389 stralloc(_("Unimplemented method")),
1390 DEVICE_STATUS_DEVICE_ERROR);
1398 gboolean for_writing,
1399 DirectTCPAddr *addrs,
1400 DirectTCPConnection **conn,
1401 ProlongProc prolong,
1402 gpointer prolong_data)
1406 klass = DEVICE_GET_CLASS(self);
1407 if(klass->connect) {
1408 return (klass->connect)(self, for_writing, addrs, conn, prolong, prolong_data);
1410 device_set_error(self,
1411 stralloc(_("Unimplemented method")),
1412 DEVICE_STATUS_DEVICE_ERROR);
1418 device_write_from_connection(
1421 guint64 *actual_size)
1425 klass = DEVICE_GET_CLASS(self);
1427 g_assert(self->in_file);
1428 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1430 if(klass->write_from_connection) {
1431 return (klass->write_from_connection)(self, size, actual_size);
1433 device_set_error(self,
1434 stralloc(_("Unimplemented method")),
1435 DEVICE_STATUS_DEVICE_ERROR);
1441 device_read_to_connection(
1444 guint64 *actual_size)
1448 g_assert(self->in_file);
1449 g_assert(self->access_mode == ACCESS_READ);
1451 klass = DEVICE_GET_CLASS(self);
1452 if(klass->read_to_connection) {
1453 return (klass->read_to_connection)(self, size, actual_size);
1455 device_set_error(self,
1456 stralloc(_("Unimplemented method")),
1457 DEVICE_STATUS_DEVICE_ERROR);
1463 device_use_connection(
1465 DirectTCPConnection *conn)
1469 g_assert(self->access_mode == ACCESS_NULL);
1471 klass = DEVICE_GET_CLASS(self);
1472 if(klass->use_connection) {
1473 return (klass->use_connection)(self, conn);
1475 device_set_error(self,
1476 stralloc(_("Unimplemented method")),
1477 DEVICE_STATUS_DEVICE_ERROR);
1482 /* Property handling */
1485 device_class_register_property(
1487 DevicePropertyId id,
1488 PropertyAccessFlags access,
1489 PropertyGetFn getter,
1490 PropertySetFn setter)
1492 DevicePropertyBase *base;
1493 DeviceProperty *prop;
1497 g_assert(klass != NULL);
1499 base = device_property_get_by_id(id);
1500 g_assert(base != NULL);
1502 if (klass->class_properties->len <= id) {
1503 g_array_set_size(klass->class_properties, id+1);
1506 prop = &g_array_index(klass->class_properties, DeviceProperty, id);
1508 prop->access = access;
1509 prop->getter = getter;
1510 prop->setter = setter;
1512 /* completely rewrite the list of prop pointers, as they may have changed,
1513 * or we may have replaced an existing property*/
1515 if (klass->class_properties_list) {
1516 g_slist_free(klass->class_properties_list);
1520 for (i = 0; i < klass->class_properties->len; i++) {
1521 prop = &g_array_index(klass->class_properties, DeviceProperty, i);
1524 proplist = g_slist_prepend(proplist, prop);
1527 klass->class_properties_list = proplist;
1531 device_set_simple_property(
1533 DevicePropertyId id,
1535 PropertySurety surety,
1536 PropertySource source)
1538 SimpleProperty *simp;
1539 DeviceProperty *prop;
1541 prop = &g_array_index(DEVICE_GET_CLASS(self)->class_properties,
1542 DeviceProperty, id);
1544 /* these assertions should already be checked, but let's be sure */
1545 g_assert(prop->base != NULL); /* prop must be registered with device */
1546 g_assert(G_VALUE_HOLDS(val, prop->base->type));
1548 simp = g_new0(SimpleProperty, 1);
1550 g_value_unset_copy(val, &(simp->response));
1551 simp->surety = surety;
1552 simp->source = source;
1554 g_hash_table_insert(selfp->simple_properties,
1555 GINT_TO_POINTER(id),
1562 device_simple_property_set_fn(
1564 DevicePropertyBase *base,
1566 PropertySurety surety,
1567 PropertySource source)
1569 return device_set_simple_property(self, base->ID, val, surety, source);
1573 device_get_simple_property(
1575 DevicePropertyId id,
1577 PropertySurety *surety,
1578 PropertySource *source)
1580 SimpleProperty *simp =
1581 g_hash_table_lookup(selfp->simple_properties,
1582 GINT_TO_POINTER(id));
1588 g_value_unset_copy(&(simp->response), val);
1591 *surety = simp->surety;
1594 *source = simp->source;
1600 device_simple_property_get_fn(
1602 DevicePropertyBase *base,
1604 PropertySurety *surety,
1605 PropertySource *source)
1607 return device_get_simple_property(self, base->ID, val, surety, source);