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)
887 self->block_size = block_size;
888 self->block_size_surety = surety;
889 self->block_size_source = source;
895 property_get_min_block_size_fn(
897 DevicePropertyBase *base G_GNUC_UNUSED,
899 PropertySurety *surety,
900 PropertySource *source)
902 g_value_unset_init(val, G_TYPE_UINT);
903 g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
904 g_value_set_uint(val, (guint)self->min_block_size);
907 *surety = PROPERTY_SURETY_GOOD;
910 *source = PROPERTY_SOURCE_DEFAULT;
916 property_get_max_block_size_fn(
918 DevicePropertyBase *base G_GNUC_UNUSED,
920 PropertySurety *surety,
921 PropertySource *source)
923 g_value_unset_init(val, G_TYPE_UINT);
924 g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
925 g_value_set_uint(val, (guint)self->max_block_size);
928 *surety = PROPERTY_SURETY_GOOD;
931 *source = PROPERTY_SOURCE_DEFAULT;
937 property_get_canonical_name_fn(
939 DevicePropertyBase *base G_GNUC_UNUSED,
941 PropertySurety *surety,
942 PropertySource *source)
944 g_value_unset_init(val, G_TYPE_STRING);
945 g_value_set_string(val, self->device_name);
948 *surety = PROPERTY_SURETY_GOOD;
951 *source = PROPERTY_SOURCE_DEFAULT;
957 static PropertyPhaseFlags
961 if (self->access_mode == ACCESS_NULL) {
962 return PROPERTY_PHASE_BEFORE_START;
963 } else if (IS_WRITABLE_ACCESS_MODE(self->access_mode)) {
965 return PROPERTY_PHASE_INSIDE_FILE_WRITE;
967 return PROPERTY_PHASE_BETWEEN_FILE_WRITE;
969 } else { /* read mode */
971 return PROPERTY_PHASE_INSIDE_FILE_READ;
973 return PROPERTY_PHASE_BETWEEN_FILE_READ;
978 /* This default implementation serves up static responses, and
979 implements a few default responses based on values from the Device
982 default_device_property_get_ex(
986 PropertySurety *surety,
987 PropertySource *source)
989 DeviceProperty *prop;
990 GArray *class_properties;
991 PropertyPhaseFlags cur_phase;
993 /* Most of this function's job is to sanity-check everything, then
994 * call the relevant getter. */
996 class_properties = DEVICE_GET_CLASS(self)->class_properties;
997 if (id >= class_properties->len)
1000 prop = &g_array_index(class_properties, DeviceProperty, id);
1001 if (prop->base == NULL)
1004 if (val || surety || source) {
1005 /* check the phase */
1006 cur_phase = state_to_phase(self);
1007 if (!(prop->access & cur_phase))
1010 if (prop->getter == NULL)
1013 if (!prop->getter(self, prop->base, val, surety, source))
1021 default_device_property_set_ex(
1023 DevicePropertyId id,
1025 PropertySurety surety,
1026 PropertySource source)
1028 DeviceProperty *prop;
1029 GArray *class_properties;
1030 PropertyPhaseFlags cur_phase;
1032 /* Most of this function's job is to sanity-check everything, then
1033 * call the relevant setter. */
1035 if (device_in_error(self))
1038 class_properties = DEVICE_GET_CLASS(self)->class_properties;
1039 if (id >= class_properties->len)
1042 prop = &g_array_index(class_properties, DeviceProperty, id);
1043 if (prop->base == NULL)
1046 /* check that the type matches */
1047 if (!G_VALUE_HOLDS(val, prop->base->type))
1050 /* check the phase */
1051 cur_phase = state_to_phase(self) << PROPERTY_PHASE_SHIFT;
1052 if (!(prop->access & cur_phase))
1055 if (prop->setter == NULL)
1058 if (!prop->setter(self, prop->base, val, surety, source))
1065 device_property_get_list (Device * self)
1067 g_assert(IS_DEVICE(self));
1069 return DEVICE_GET_CLASS(self)->class_properties_list;
1073 * All the functions below this comment are stub functions that do nothing
1074 * but implement the virtual function table. Call these functions and they
1075 * will do what you expect vis-a-vis virtual functions. But don't put code
1076 * in them beyond error checking and VFT lookup. */
1079 device_open_device (Device * self, char * device_name,
1080 char * device_type, char * device_node)
1084 g_assert(IS_DEVICE(self));
1085 g_assert(device_name != NULL);
1087 klass = DEVICE_GET_CLASS(self);
1088 g_assert(klass->open_device);
1089 (klass->open_device)(self, device_name, device_type, device_node);
1092 DeviceStatusFlags device_read_label(Device * self) {
1093 DeviceClass * klass;
1095 g_assert(self != NULL);
1096 g_assert(IS_DEVICE(self));
1097 g_assert(self->access_mode == ACCESS_NULL);
1099 klass = DEVICE_GET_CLASS(self);
1100 g_assert(klass->read_label);
1101 return (klass->read_label)(self);
1105 device_finish (Device * self) {
1108 g_assert(IS_DEVICE (self));
1110 klass = DEVICE_GET_CLASS(self);
1111 g_assert(klass->finish);
1112 return (klass->finish)(self);
1116 device_configure (Device * self, gboolean use_global_config)
1120 g_assert(IS_DEVICE (self));
1121 g_assert(self->access_mode == ACCESS_NULL);
1123 klass = DEVICE_GET_CLASS(self);
1124 if(klass->configure) {
1125 return (klass->configure)(self, use_global_config);
1127 device_set_error(self,
1128 stralloc(_("Unimplemented method")),
1129 DEVICE_STATUS_DEVICE_ERROR);
1135 device_start (Device * self, DeviceAccessMode mode,
1136 char * label, char * timestamp)
1139 char * local_timestamp = NULL;
1142 g_assert(IS_DEVICE (self));
1143 g_assert(mode != ACCESS_NULL);
1144 g_assert(mode != ACCESS_WRITE || label != NULL);
1146 klass = DEVICE_GET_CLASS(self);
1147 g_assert(klass->start);
1149 /* For a good combination of synchronization and public simplicity,
1150 this stub function does not require a timestamp, but the actual
1151 implementation function does. We generate the timestamp here with
1153 if (mode == ACCESS_WRITE &&
1154 get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
1155 local_timestamp = timestamp =
1156 get_proper_stamp_from_time(time(NULL));
1159 rv = (klass->start)(self, mode, label, timestamp);
1160 amfree(local_timestamp);
1165 device_write_block (Device * self, guint size, gpointer block)
1169 g_assert(IS_DEVICE (self));
1172 /* these are all things that the caller should take care to
1173 * guarantee, so we just assert them here */
1174 g_assert(size <= self->block_size);
1175 g_assert(self->in_file);
1176 g_assert(!selfp->wrote_short_block);
1177 g_assert(block != NULL);
1178 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1180 if (size < self->block_size)
1181 selfp->wrote_short_block = TRUE;
1183 klass = DEVICE_GET_CLASS(self);
1184 g_assert(klass->write_block);
1185 return (*klass->write_block)(self,size, block);
1189 device_start_file (Device * self, dumpfile_t * jobInfo) {
1190 DeviceClass * klass;
1192 g_assert(IS_DEVICE (self));
1193 g_assert(!(self->in_file));
1194 g_assert(jobInfo != NULL);
1196 selfp->wrote_short_block = FALSE;
1198 klass = DEVICE_GET_CLASS(self);
1199 g_assert(klass->start_file);
1200 return (klass->start_file)(self, jobInfo );
1204 device_finish_file (Device * self)
1208 g_assert(IS_DEVICE (self));
1209 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1210 g_assert(self->in_file);
1212 klass = DEVICE_GET_CLASS(self);
1213 g_assert(klass->finish_file);
1214 return (klass->finish_file)(self);
1218 device_seek_file (Device * self, guint file)
1222 g_assert(IS_DEVICE (self));
1223 g_assert(self->access_mode == ACCESS_READ);
1225 klass = DEVICE_GET_CLASS(self);
1226 g_assert(klass->seek_file);
1227 return (klass->seek_file)(self,file);
1231 device_seek_block (Device * self, guint64 block)
1235 g_assert(IS_DEVICE (self));
1236 g_assert(self->access_mode == ACCESS_READ);
1237 g_assert(self->in_file);
1239 klass = DEVICE_GET_CLASS(self);
1240 g_assert(klass->seek_block);
1241 return (klass->seek_block)(self,block);
1245 device_read_block (Device * self, gpointer buffer, int * size)
1249 g_assert(IS_DEVICE (self));
1250 g_assert(size != NULL);
1251 g_assert(self->access_mode == ACCESS_READ);
1254 g_assert(buffer != NULL);
1257 klass = DEVICE_GET_CLASS(self);
1258 g_assert(klass->read_block);
1259 return (klass->read_block)(self,buffer,size);
1263 device_property_get_ex(
1265 DevicePropertyId id,
1267 PropertySurety *surety,
1268 PropertySource *source)
1272 g_assert(IS_DEVICE (self));
1273 g_assert(device_property_get_by_id(id) != NULL);
1275 klass = DEVICE_GET_CLASS(self);
1277 g_assert(klass->property_get_ex);
1278 return (klass->property_get_ex)(self, id, val, surety, source);
1282 device_property_set_ex(
1284 DevicePropertyId id,
1286 PropertySurety surety,
1287 PropertySource source)
1291 g_assert(IS_DEVICE (self));
1293 klass = DEVICE_GET_CLASS(self);
1295 g_assert(klass->property_set_ex);
1296 return (klass->property_set_ex)(self, id, val, surety, source);
1300 device_recycle_file (Device * self, guint filenum)
1304 g_assert(self != NULL);
1305 g_assert(IS_DEVICE (self));
1306 g_assert(self->access_mode == ACCESS_APPEND);
1307 g_assert(!self->in_file);
1309 klass = DEVICE_GET_CLASS(self);
1311 g_assert(klass->recycle_file);
1312 return (klass->recycle_file)(self,filenum);
1316 device_erase (Device * self)
1320 g_assert(IS_DEVICE (self));
1321 g_assert(self->access_mode == ACCESS_NULL);
1322 g_assert(!self->in_file);
1324 klass = DEVICE_GET_CLASS(self);
1326 return (klass->erase)(self);
1328 device_set_error(self,
1329 stralloc(_("Unimplemented method")),
1330 DEVICE_STATUS_DEVICE_ERROR);
1336 device_eject (Device * self)
1340 g_assert(IS_DEVICE (self));
1341 g_assert(self->access_mode == ACCESS_NULL);
1342 g_assert(!self->in_file);
1344 klass = DEVICE_GET_CLASS(self);
1346 return (klass->eject)(self);
1355 gboolean for_writing,
1356 DirectTCPAddr **addrs)
1360 klass = DEVICE_GET_CLASS(self);
1362 return (klass->listen)(self, for_writing, addrs);
1364 device_set_error(self,
1365 stralloc(_("Unimplemented method")),
1366 DEVICE_STATUS_DEVICE_ERROR);
1374 DirectTCPConnection **conn,
1375 ProlongProc prolong,
1376 gpointer prolong_data)
1380 klass = DEVICE_GET_CLASS(self);
1382 return (klass->accept)(self, conn, prolong, prolong_data);
1384 device_set_error(self,
1385 stralloc(_("Unimplemented method")),
1386 DEVICE_STATUS_DEVICE_ERROR);
1394 gboolean for_writing,
1395 DirectTCPAddr *addrs,
1396 DirectTCPConnection **conn,
1397 ProlongProc prolong,
1398 gpointer prolong_data)
1402 klass = DEVICE_GET_CLASS(self);
1403 if(klass->connect) {
1404 return (klass->connect)(self, for_writing, addrs, conn, prolong, prolong_data);
1406 device_set_error(self,
1407 stralloc(_("Unimplemented method")),
1408 DEVICE_STATUS_DEVICE_ERROR);
1414 device_write_from_connection(
1417 guint64 *actual_size)
1421 klass = DEVICE_GET_CLASS(self);
1423 g_assert(self->in_file);
1424 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1426 if(klass->write_from_connection) {
1427 return (klass->write_from_connection)(self, size, actual_size);
1429 device_set_error(self,
1430 stralloc(_("Unimplemented method")),
1431 DEVICE_STATUS_DEVICE_ERROR);
1437 device_read_to_connection(
1440 guint64 *actual_size)
1444 g_assert(self->in_file);
1445 g_assert(self->access_mode == ACCESS_READ);
1447 klass = DEVICE_GET_CLASS(self);
1448 if(klass->read_to_connection) {
1449 return (klass->read_to_connection)(self, size, actual_size);
1451 device_set_error(self,
1452 stralloc(_("Unimplemented method")),
1453 DEVICE_STATUS_DEVICE_ERROR);
1459 device_use_connection(
1461 DirectTCPConnection *conn)
1465 g_assert(self->access_mode == ACCESS_NULL);
1467 klass = DEVICE_GET_CLASS(self);
1468 if(klass->use_connection) {
1469 return (klass->use_connection)(self, conn);
1471 device_set_error(self,
1472 stralloc(_("Unimplemented method")),
1473 DEVICE_STATUS_DEVICE_ERROR);
1478 /* Property handling */
1481 device_class_register_property(
1483 DevicePropertyId id,
1484 PropertyAccessFlags access,
1485 PropertyGetFn getter,
1486 PropertySetFn setter)
1488 DevicePropertyBase *base;
1489 DeviceProperty *prop;
1493 g_assert(klass != NULL);
1495 base = device_property_get_by_id(id);
1496 g_assert(base != NULL);
1498 if (klass->class_properties->len <= id) {
1499 g_array_set_size(klass->class_properties, id+1);
1502 prop = &g_array_index(klass->class_properties, DeviceProperty, id);
1504 prop->access = access;
1505 prop->getter = getter;
1506 prop->setter = setter;
1508 /* completely rewrite the list of prop pointers, as they may have changed,
1509 * or we may have replaced an existing property*/
1511 if (klass->class_properties_list) {
1512 g_slist_free(klass->class_properties_list);
1516 for (i = 0; i < klass->class_properties->len; i++) {
1517 prop = &g_array_index(klass->class_properties, DeviceProperty, i);
1520 proplist = g_slist_prepend(proplist, prop);
1523 klass->class_properties_list = proplist;
1527 device_set_simple_property(
1529 DevicePropertyId id,
1531 PropertySurety surety,
1532 PropertySource source)
1534 SimpleProperty *simp;
1535 DeviceProperty *prop;
1537 prop = &g_array_index(DEVICE_GET_CLASS(self)->class_properties,
1538 DeviceProperty, id);
1540 /* these assertions should already be checked, but let's be sure */
1541 g_assert(prop->base != NULL); /* prop must be registered with device */
1542 g_assert(G_VALUE_HOLDS(val, prop->base->type));
1544 simp = g_new0(SimpleProperty, 1);
1546 g_value_unset_copy(val, &(simp->response));
1547 simp->surety = surety;
1548 simp->source = source;
1550 g_hash_table_insert(selfp->simple_properties,
1551 GINT_TO_POINTER(id),
1558 device_simple_property_set_fn(
1560 DevicePropertyBase *base,
1562 PropertySurety surety,
1563 PropertySource source)
1565 return device_set_simple_property(self, base->ID, val, surety, source);
1569 device_get_simple_property(
1571 DevicePropertyId id,
1573 PropertySurety *surety,
1574 PropertySource *source)
1576 SimpleProperty *simp =
1577 g_hash_table_lookup(selfp->simple_properties,
1578 GINT_TO_POINTER(id));
1584 g_value_unset_copy(&(simp->response), val);
1587 *surety = simp->surety;
1590 *source = simp->source;
1596 device_simple_property_get_fn(
1598 DevicePropertyBase *base,
1600 PropertySurety *surety,
1601 PropertySource *source)
1603 return device_get_simple_property(self, base->ID, val, surety, source);