2 * Copyright (c) 2005-2008 Zmanda Inc. All Rights Reserved.
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 2.1 as
6 * published by the Free Software Foundation.
8 * This library 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 Lesser General Public
11 * License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17 * Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300
18 * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
21 /* The Device API abstracts device workings, interaction, properties, and
22 * capabilities from the rest of the Amanda code base. It supports
23 * pluggable modules for different kinds of devices. */
32 #include "device-queueing.h"
35 #include "timestamp.h"
39 * Prototypes for subclass registration functions
42 void null_device_register (void);
43 void rait_device_register (void);
45 void s3_device_register (void);
47 #ifdef WANT_TAPE_DEVICE
48 void tape_device_register (void);
50 void vfs_device_register (void);
53 * Registration infrastructure
56 static GHashTable* driverList = NULL;
58 void device_api_init(void) {
60 device_property_init();
61 driverList = g_hash_table_new(g_str_hash, g_str_equal);
63 /* register other types and devices. */
64 null_device_register();
65 vfs_device_register();
66 #ifdef WANT_TAPE_DEVICE
67 tape_device_register();
69 rait_device_register();
77 DeviceFactory factory,
78 const char ** device_prefix_list)
82 g_assert(driverList != NULL);
83 g_assert(factory != NULL);
84 g_return_if_fail(device_prefix_list != NULL);
85 g_return_if_fail(*device_prefix_list != NULL);
87 tmp = (char**)device_prefix_list;
88 while (*tmp != NULL) {
89 g_hash_table_insert(driverList, *tmp, (gpointer)factory);
94 static DeviceFactory lookup_device_factory(const char *device_type) {
96 g_assert(driverList != NULL);
98 if (g_hash_table_lookup_extended(driverList, device_type, &key, &value)) {
99 return (DeviceFactory)value;
105 static const GFlagsValue device_status_flags_values[] = {
106 { DEVICE_STATUS_SUCCESS,
107 "DEVICE_STATUS_SUCCESS",
109 { DEVICE_STATUS_DEVICE_ERROR,
110 "DEVICE_STATUS_DEVICE_ERROR",
112 { DEVICE_STATUS_DEVICE_BUSY,
113 "DEVICE_STATUS_DEVICE_BUSY",
115 { DEVICE_STATUS_VOLUME_MISSING,
116 "DEVICE_STATUS_VOLUME_MISSING",
117 "Volume not found" },
118 { DEVICE_STATUS_VOLUME_UNLABELED,
119 "DEVICE_STATUS_VOLUME_UNLABELED",
120 "Volume not labeled" },
121 { DEVICE_STATUS_VOLUME_ERROR,
122 "DEVICE_STATUS_VOLUME_ERROR",
127 GType device_status_flags_get_type(void) {
128 static GType type = 0;
129 if (G_UNLIKELY(type == 0)) {
130 type = g_flags_register_static("DeviceStatusFlags",
131 device_status_flags_values);
136 /* Device class definition starts here. */
138 struct DevicePrivate_s {
139 /* hash table mapping ID to SimpleProperty object */
140 GHashTable * simple_properties;
142 /* In writing mode, after a short block is written, no additional blocks
143 * are allowed the file is finished and a new file started. This is only
144 * used for assertions. */
145 gboolean wrote_short_block;
147 /* Holds an error message if the function returned an error. */
150 /* temporary holding place for device_status_error() */
152 DeviceStatusFlags last_status;
155 /* This holds the default response to a particular property. */
157 DeviceProperty *prop;
159 PropertySurety surety;
160 PropertySource source;
163 #define selfp (self->private)
165 /* here are local prototypes, so we can make function pointers. */
166 static void device_init (Device * o);
167 static void device_class_init (DeviceClass * c);
168 static void device_base_init (DeviceClass * c);
170 static void simple_property_free(SimpleProperty *o);
172 static void default_device_open_device(Device * self, char * device_name,
173 char * device_type, char * device_node);
174 static gboolean default_device_configure(Device *self, gboolean use_global_config);
175 static gboolean default_device_write_from_fd(Device *self,
176 queue_fd_t *queue_fd);
177 static gboolean default_device_read_to_fd(Device *self, queue_fd_t *queue_fd);
178 static gboolean default_device_property_get_ex(Device * self, DevicePropertyId id,
180 PropertySurety *surety,
181 PropertySource *source);
182 static gboolean default_device_property_set_ex(Device *self,
185 PropertySurety surety,
186 PropertySource source);
187 static void set_properties_from_global_config(Device * device);
188 static void set_properties_from_device_config(Device * device, device_config_t *dc);
190 static gboolean property_get_block_size_fn(Device *self,
191 DevicePropertyBase *base, GValue *val,
192 PropertySurety *surety, PropertySource *source);
194 static gboolean property_set_block_size_fn(Device *self,
195 DevicePropertyBase *base, GValue *val,
196 PropertySurety surety, PropertySource source);
198 static gboolean property_get_min_block_size_fn(Device *self,
199 DevicePropertyBase *base, GValue *val,
200 PropertySurety *surety, PropertySource *source);
202 static gboolean property_get_max_block_size_fn(Device *self,
203 DevicePropertyBase *base, GValue *val,
204 PropertySurety *surety, PropertySource *source);
206 static gboolean property_get_canonical_name_fn(Device *self,
207 DevicePropertyBase *base, GValue *val,
208 PropertySurety *surety, PropertySource *source);
210 /* pointer to the class of our parent */
211 static GObjectClass *parent_class = NULL;
214 device_get_type (void)
216 static GType type = 0;
218 if G_UNLIKELY(type == 0) {
219 static const GTypeInfo info = {
220 sizeof (DeviceClass),
221 (GBaseInitFunc) device_base_init,
222 (GBaseFinalizeFunc) NULL,
223 (GClassInitFunc) device_class_init,
224 (GClassFinalizeFunc) NULL,
225 NULL /* class_data */,
228 (GInstanceInitFunc) device_init,
232 type = g_type_register_static (G_TYPE_OBJECT, "Device", &info,
233 (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
239 static void device_finalize(GObject *obj_self) {
240 Device *self G_GNUC_UNUSED = DEVICE (obj_self);
241 if(G_OBJECT_CLASS(parent_class)->finalize)
242 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
244 /* Here we call device_finish() if it hasn't been done
245 yet. Subclasses may need to do this same check earlier. */
246 if (self->access_mode != ACCESS_NULL) {
250 amfree(self->device_name);
251 amfree(self->volume_label);
252 amfree(self->volume_time);
253 amfree(self->volume_header);
254 amfree(selfp->errmsg);
255 amfree(selfp->statusmsg);
256 g_hash_table_destroy(selfp->simple_properties);
257 amfree(self->private);
261 device_init (Device * self)
263 self->private = malloc(sizeof(DevicePrivate));
264 self->device_name = NULL;
265 self->access_mode = ACCESS_NULL;
266 self->is_eof = FALSE;
269 self->in_file = FALSE;
270 self->volume_label = NULL;
271 self->volume_time = NULL;
272 self->status = DEVICE_STATUS_SUCCESS;
273 self->min_block_size = 1;
274 self->max_block_size = SIZE_MAX; /* subclasses *really* should choose something smaller */
275 self->block_size = DISK_BLOCK_BYTES;
276 selfp->errmsg = NULL;
277 selfp->statusmsg = NULL;
278 selfp->last_status = 0;
279 selfp->simple_properties =
280 g_hash_table_new_full(g_direct_hash,
283 (GDestroyNotify) simple_property_free);
287 device_class_init (DeviceClass * device_class)
289 GObjectClass *g_object_class = (GObjectClass*) device_class;
291 parent_class = g_type_class_ref (G_TYPE_OBJECT);
293 device_class->open_device = default_device_open_device;
294 device_class->configure = default_device_configure;
295 device_class->write_from_fd = default_device_write_from_fd;
296 device_class->read_to_fd = default_device_read_to_fd;
297 device_class->property_get_ex = default_device_property_get_ex;
298 device_class->property_set_ex = default_device_property_set_ex;
299 g_object_class->finalize = device_finalize;
303 device_base_init (DeviceClass * device_class)
305 /* The base_init function is called once each time a child class is
306 * created, before the class_init functions (even our own) are called. */
308 device_class->class_properties = g_array_new(FALSE, TRUE, sizeof(DeviceProperty));
309 device_class->class_properties_list = NULL;
311 device_class_register_property(device_class, PROPERTY_BLOCK_SIZE,
312 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
313 property_get_block_size_fn,
314 property_set_block_size_fn);
316 device_class_register_property(device_class, PROPERTY_MIN_BLOCK_SIZE,
317 PROPERTY_ACCESS_GET_MASK,
318 property_get_min_block_size_fn,
321 device_class_register_property(device_class, PROPERTY_MAX_BLOCK_SIZE,
322 PROPERTY_ACCESS_GET_MASK,
323 property_get_max_block_size_fn,
326 device_class_register_property(device_class, PROPERTY_CANONICAL_NAME,
327 PROPERTY_ACCESS_GET_MASK,
328 property_get_canonical_name_fn,
331 device_class_register_property(device_class, PROPERTY_CONCURRENCY,
332 PROPERTY_ACCESS_GET_MASK,
333 device_simple_property_get_fn,
334 device_simple_property_set_fn);
336 device_class_register_property(device_class, PROPERTY_STREAMING,
337 PROPERTY_ACCESS_GET_MASK,
338 device_simple_property_get_fn,
339 device_simple_property_set_fn);
341 device_class_register_property(device_class, PROPERTY_APPENDABLE,
342 PROPERTY_ACCESS_GET_MASK,
343 device_simple_property_get_fn,
344 device_simple_property_set_fn);
346 device_class_register_property(device_class, PROPERTY_PARTIAL_DELETION,
347 PROPERTY_ACCESS_GET_MASK,
348 device_simple_property_get_fn,
349 device_simple_property_set_fn);
351 device_class_register_property(device_class, PROPERTY_MEDIUM_ACCESS_TYPE,
352 PROPERTY_ACCESS_GET_MASK,
353 device_simple_property_get_fn,
354 device_simple_property_set_fn);
357 static void simple_property_free(SimpleProperty * resp) {
358 g_value_unset(&(resp->response));
363 regex_message(int result, regex_t *regex) {
367 size = regerror(result, regex, NULL, 0);
369 regerror(result, regex, rval, size);
375 handle_device_regex(const char * user_name, char ** driver_name,
376 char ** device, char **errmsg) {
379 regmatch_t pmatch[3];
380 static const char * regex_string = "^([a-z0-9]+):(.*)$";
382 bzero(®ex, sizeof(regex));
384 reg_result = regcomp(®ex, regex_string, REG_EXTENDED | REG_ICASE);
385 if (reg_result != 0) {
386 char * message = regex_message(reg_result, ®ex);
387 *errmsg = newvstrallocf(*errmsg, "Error compiling regular expression \"%s\": %s\n",
388 regex_string, message);
393 reg_result = regexec(®ex, user_name, 3, pmatch, 0);
394 if (reg_result != 0 && reg_result != REG_NOMATCH) {
395 char * message = regex_message(reg_result, ®ex);
396 *errmsg = newvstrallocf(*errmsg,
397 "Error applying regular expression \"%s\" to string \"%s\": %s\n",
398 user_name, regex_string, message);
402 } else if (reg_result == REG_NOMATCH) {
403 #ifdef WANT_TAPE_DEVICE
405 "\"%s\" uses deprecated device naming convention; \n"
406 "using \"tape:%s\" instead.\n",
407 user_name, user_name);
408 *driver_name = stralloc("tape");
409 *device = stralloc(user_name);
410 #else /* !WANT_TAPE_DEVICE */
411 errmsg = newvstrallocf(errmsg, "\"%s\" is not a valid device name.\n", user_name);
414 #endif /* WANT_TAPE_DEVICE */
416 *driver_name = find_regex_substring(user_name, pmatch[1]);
417 *device = find_regex_substring(user_name, pmatch[2]);
423 /* helper function for device_open */
425 make_null_error(char *errmsg, DeviceStatusFlags status)
427 DeviceFactory factory;
430 factory = lookup_device_factory("null");
431 g_assert(factory != NULL);
433 device = factory("null:", "null", "");
434 device_set_error(device, errmsg, status);
440 device_open (char * device_name)
442 char *device_type = NULL;
443 char *device_node = NULL;
445 char *unaliased_name = NULL;
446 DeviceFactory factory;
450 g_assert(device_name != NULL);
452 if (driverList == NULL) {
453 g_critical("device_open() called without device_api_init()!");
454 g_assert_not_reached();
457 if (device_name == NULL)
458 return make_null_error(stralloc(_("No device name specified")), DEVICE_STATUS_DEVICE_ERROR);
460 /* look up the unaliased device name in the configuration */
461 if ((dc = lookup_device_config(device_name))) {
462 if (!(unaliased_name = device_config_get_tapedev(dc))
463 || unaliased_name[0] == '\0') {
464 return make_null_error(
465 vstrallocf(_("Device '%s' has no tapedev"), device_name),
466 DEVICE_STATUS_DEVICE_ERROR);
469 unaliased_name = device_name;
472 if (!handle_device_regex(unaliased_name, &device_type, &device_node,
476 return make_null_error(errmsg, DEVICE_STATUS_DEVICE_ERROR);
479 factory = lookup_device_factory(device_type);
481 if (factory == NULL) {
482 Device *nulldev = make_null_error(vstrallocf(_("Device type %s is not known."),
483 device_type), DEVICE_STATUS_DEVICE_ERROR);
489 device = factory(device_name, device_type, device_node);
490 g_assert(device != NULL); /* factories must always return a device */
499 device_error(Device * self)
502 return device_error_or_status(self);
503 } else if (selfp->errmsg) {
504 return selfp->errmsg;
506 return "Unknown Device error";
511 device_status_error(Device * self)
517 return device_error_or_status(self);
520 /* reuse a previous statusmsg, if it was for the same status */
521 if (selfp->statusmsg && selfp->last_status == self->status)
522 return selfp->statusmsg;
524 amfree(selfp->statusmsg);
526 status_strv = g_flags_nick_to_strv(self->status, DEVICE_STATUS_FLAGS_TYPE);
527 g_assert(g_strv_length(status_strv) > 0);
528 if (g_strv_length(status_strv) == 1) {
529 statusmsg = stralloc(*status_strv);
531 char * status_list = g_english_strjoinv(status_strv, "or");
532 statusmsg = g_strdup_printf("one of %s", status_list);
535 g_strfreev(status_strv);
537 selfp->statusmsg = statusmsg;
538 selfp->last_status = self->status;
543 device_error_or_status(Device * self)
546 return "Device is NULL";
547 } else if (selfp->errmsg) {
548 return selfp->errmsg;
550 return device_status_error(self);
555 device_set_error(Device *self, char *errmsg, DeviceStatusFlags new_flags)
562 g_warning("device_set_error called with a NULL device: '%s'", errmsg? errmsg:"(NULL)");
567 device_name = self->device_name? self->device_name : "(unknown device)";
569 if (errmsg && (!selfp->errmsg || strcmp(errmsg, selfp->errmsg) != 0))
570 g_debug("Device %s error = '%s'", device_name, errmsg);
572 amfree(selfp->errmsg);
573 selfp->errmsg = errmsg;
575 if (new_flags != DEVICE_STATUS_SUCCESS) {
576 flags_strv = g_flags_name_to_strv(new_flags, DEVICE_STATUS_FLAGS_TYPE);
577 g_assert(g_strv_length(flags_strv) > 0);
578 flags_str = g_english_strjoinv(flags_strv, "and");
579 g_debug("Device %s setting status flag(s): %s", device_name, flags_str);
581 g_strfreev(flags_strv);
584 self->status = new_flags;
587 char * device_build_amanda_header(Device * self, const dumpfile_t * info,
588 int * size, gboolean * oneblock) {
590 size_t min_header_length;
591 size_t header_buffer_size;
593 min_header_length = self->block_size;
594 amanda_header = build_header(info, min_header_length);
595 header_buffer_size = MAX(min_header_length, strlen(amanda_header)+1);
597 *size = header_buffer_size;
598 if (oneblock != NULL)
599 *oneblock = (header_buffer_size <= self->block_size);
600 return amanda_header;
603 dumpfile_t * make_tapestart_header(Device * self, char * label,
607 bzero(&val, sizeof(val));
609 g_assert(label != NULL);
611 rval = malloc(sizeof(*rval));
613 rval->type = F_TAPESTART;
614 if (device_property_get(self, PROPERTY_BLOCK_SIZE, &val)) {
615 rval->blocksize = g_value_get_int(&val);
619 amfree(self->volume_time);
620 if (get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
621 self->volume_time = get_proper_stamp_from_time(time(NULL));
623 self->volume_time = g_strdup(timestamp);
625 strncpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp));
626 strncpy(rval->name, label, sizeof(rval->name));
631 dumpfile_t * make_tapeend_header(void) {
635 rval = malloc(sizeof(*rval));
636 rval->type = F_TAPEEND;
637 timestamp = get_timestamp_from_time(time(NULL));
638 strncpy(rval->datestamp, timestamp, sizeof(rval->datestamp));
643 /* Try setting the blocksize on a device. Check results, fallback, and
644 * set error status for problems. */
646 try_set_blocksize(Device * device, guint blocksize) {
649 bzero(&val, sizeof(val));
651 g_value_init(&val, G_TYPE_INT);
652 g_value_set_int(&val, blocksize);
653 success = device_property_set(device, PROPERTY_BLOCK_SIZE, &val);
657 device_set_error(device,
658 vstrallocf(_("Setting BLOCK_SIZE to %u "
659 "not supported for device %s.\n"),
660 blocksize, device->device_name),
661 DEVICE_STATUS_DEVICE_ERROR);
667 /* A GHFunc (callback for g_hash_table_foreach) */
668 static void set_device_property(gpointer key_p, gpointer value_p,
669 gpointer user_data_p) {
670 char * property_s = key_p;
671 property_t * property = value_p;
672 Device * device = user_data_p;
673 const DevicePropertyBase* property_base;
674 GValue property_value;
677 g_return_if_fail(IS_DEVICE(device));
678 g_return_if_fail(property_s != NULL);
679 g_return_if_fail(property != NULL);
680 g_return_if_fail(property->values != NULL);
682 /* don't continue beating on a device that's already erroring */
683 if (device_in_error(device)) return;
685 property_base = device_property_get_by_name(property_s);
686 if (property_base == NULL) {
687 /* Nonexistant property name. */
688 device_set_error(device,
689 vstrallocf(_("unknown device property name '%s'"), property_s),
690 DEVICE_STATUS_DEVICE_ERROR);
693 if (g_slist_length(property->values) > 1) {
694 device_set_error(device,
695 vstrallocf(_("multiple values for device property '%s'"), property_s),
696 DEVICE_STATUS_DEVICE_ERROR);
700 bzero(&property_value, sizeof(property_value));
701 g_value_init(&property_value, property_base->type);
702 value = property->values->data;
703 if (!g_value_set_from_string(&property_value, value)) {
704 /* Value type could not be interpreted. */
705 device_set_error(device,
706 vstrallocf(_("Could not parse property value '%s' for property '%s' (property type %s)"),
707 value, property_base->name, g_type_name(property_base->type)),
708 DEVICE_STATUS_DEVICE_ERROR);
711 g_assert (G_VALUE_HOLDS(&property_value, property_base->type));
714 if (!device_property_set(device, property_base->ID, &property_value)) {
715 /* Device rejects property. */
716 if (!device_in_error(device)) {
717 device_set_error(device,
718 vstrallocf(_("Could not set property '%s' to '%s' on %s"),
719 property_base->name, value, device->device_name),
720 DEVICE_STATUS_DEVICE_ERROR);
726 /* Set up properties based on various taper-related configuration parameters
727 * and from the tapetype.
730 set_properties_from_global_config(Device * device) {
731 char * tapetype_name = getconf_str(CNF_TAPETYPE);
732 if (tapetype_name != NULL) {
733 tapetype_t * tapetype = lookup_tapetype(tapetype_name);
734 if (tapetype != NULL) {
740 bzero(&val, sizeof(GValue));
742 if (tapetype_seen(tapetype, TAPETYPE_LENGTH)) {
743 length = tapetype_get_length(tapetype);
744 g_value_init(&val, G_TYPE_UINT64);
745 g_value_set_uint64(&val, length * 1024);
746 /* If this fails, it's not really an error. */
747 device_property_set(device, PROPERTY_MAX_VOLUME_USAGE, &val);
751 if (tapetype_seen(tapetype, TAPETYPE_READBLOCKSIZE)) {
752 blocksize_kb = tapetype_get_readblocksize(tapetype);
753 g_value_init(&val, G_TYPE_UINT);
754 g_value_set_uint(&val, blocksize_kb * 1024);
755 success = device_property_set(device,
756 PROPERTY_READ_BUFFER_SIZE,
760 /* a non-fatal error */
761 g_warning("Setting READ_BUFFER_SIZE to %ju not supported for device %s.",
762 1024*(uintmax_t)blocksize_kb, device->device_name);
766 if (tapetype_seen(tapetype, TAPETYPE_BLOCKSIZE)) {
767 blocksize_kb = tapetype_get_blocksize(tapetype);
768 /* TODO: handle errors */
769 (void)try_set_blocksize(device, blocksize_kb * 1024);
774 g_hash_table_foreach(getconf_proplist(CNF_DEVICE_PROPERTY),
775 set_device_property, device);
778 /* Set properties specified within a device definition */
780 set_properties_from_device_config(Device * device, device_config_t *dc) {
781 g_hash_table_foreach(device_config_get_property(dc),
782 set_device_property, device);
786 default_device_configure(Device *self, gboolean use_global_config)
790 if (device_in_error(self))
793 if (use_global_config)
794 set_properties_from_global_config(self);
796 if (device_in_error(self))
799 if ((dc = lookup_device_config(self->device_name)))
800 set_properties_from_device_config(self, dc);
802 return !device_in_error(self);
805 void device_clear_volume_details(Device * device) {
806 if (device == NULL || device->access_mode != ACCESS_NULL) {
810 amfree(device->volume_label);
811 amfree(device->volume_time);
814 /* Here we put default implementations of virtual functions. Since
815 this class is virtual, many of these functions offer at best
816 incomplete functionality. But they do offer the useful commonality
817 that all devices can expect to need. */
819 static void default_device_open_device(Device * self, char * device_name,
820 char * device_type G_GNUC_UNUSED, char * device_node G_GNUC_UNUSED) {
821 /* Set the device_name property */
822 self->device_name = stralloc(device_name);
826 property_get_block_size_fn(
828 DevicePropertyBase *base G_GNUC_UNUSED,
830 PropertySurety *surety,
831 PropertySource *source)
833 g_value_unset_init(val, G_TYPE_INT);
834 g_assert(self->block_size < G_MAXINT); /* gsize -> gint */
835 g_value_set_int(val, (gint)self->block_size);
838 *surety = self->block_size_surety;
841 *source = self->block_size_source;
847 property_set_block_size_fn(
849 DevicePropertyBase *base G_GNUC_UNUSED,
851 PropertySurety surety,
852 PropertySource source)
854 gint block_size = g_value_get_int(val);
856 g_assert(block_size >= 0); /* int -> gsize (unsigned) */
857 if ((gsize)block_size < self->min_block_size
858 || (gsize)block_size > self->max_block_size)
861 self->block_size = block_size;
862 self->block_size_surety = surety;
863 self->block_size_source = source;
869 property_get_min_block_size_fn(
871 DevicePropertyBase *base G_GNUC_UNUSED,
873 PropertySurety *surety,
874 PropertySource *source)
876 g_value_unset_init(val, G_TYPE_UINT);
877 g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
878 g_value_set_uint(val, (guint)self->min_block_size);
881 *surety = PROPERTY_SURETY_GOOD;
884 *source = PROPERTY_SOURCE_DEFAULT;
890 property_get_max_block_size_fn(
892 DevicePropertyBase *base G_GNUC_UNUSED,
894 PropertySurety *surety,
895 PropertySource *source)
897 g_value_unset_init(val, G_TYPE_UINT);
898 g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
899 g_value_set_uint(val, (guint)self->max_block_size);
902 *surety = PROPERTY_SURETY_GOOD;
905 *source = PROPERTY_SOURCE_DEFAULT;
911 property_get_canonical_name_fn(
913 DevicePropertyBase *base G_GNUC_UNUSED,
915 PropertySurety *surety,
916 PropertySource *source)
918 g_value_unset_init(val, G_TYPE_STRING);
919 g_value_set_string(val, self->device_name);
922 *surety = PROPERTY_SURETY_GOOD;
925 *source = PROPERTY_SOURCE_DEFAULT;
931 static PropertyPhaseFlags
935 if (self->access_mode == ACCESS_NULL) {
936 return PROPERTY_PHASE_BEFORE_START;
937 } else if (IS_WRITABLE_ACCESS_MODE(self->access_mode)) {
939 return PROPERTY_PHASE_INSIDE_FILE_WRITE;
941 return PROPERTY_PHASE_BETWEEN_FILE_WRITE;
943 } else { /* read mode */
945 return PROPERTY_PHASE_INSIDE_FILE_READ;
947 return PROPERTY_PHASE_BETWEEN_FILE_READ;
952 /* This default implementation serves up static responses, and
953 implements a few default responses based on values from the Device
956 default_device_property_get_ex(
960 PropertySurety *surety,
961 PropertySource *source)
963 DeviceProperty *prop;
964 GArray *class_properties;
965 PropertyPhaseFlags cur_phase;
967 /* Most of this function's job is to sanity-check everything, then
968 * call the relevant getter. */
970 if (device_in_error(self))
973 class_properties = DEVICE_GET_CLASS(self)->class_properties;
974 if (id >= class_properties->len)
977 prop = &g_array_index(class_properties, DeviceProperty, id);
978 if (prop->base == NULL)
981 if (val || surety || source) {
982 /* check the phase */
983 cur_phase = state_to_phase(self);
984 if (!(prop->access & cur_phase))
987 if (prop->getter == NULL)
990 if (!prop->getter(self, prop->base, val, surety, source))
998 default_device_property_set_ex(
1000 DevicePropertyId id,
1002 PropertySurety surety,
1003 PropertySource source)
1005 DeviceProperty *prop;
1006 GArray *class_properties;
1007 PropertyPhaseFlags cur_phase;
1009 /* Most of this function's job is to sanity-check everything, then
1010 * call the relevant setter. */
1012 if (device_in_error(self))
1015 class_properties = DEVICE_GET_CLASS(self)->class_properties;
1016 if (id >= class_properties->len)
1019 prop = &g_array_index(class_properties, DeviceProperty, id);
1020 if (prop->base == NULL)
1023 /* check that the type matches */
1024 if (!G_VALUE_HOLDS(val, prop->base->type))
1027 /* check the phase */
1028 cur_phase = state_to_phase(self) << PROPERTY_PHASE_SHIFT;
1029 if (!(prop->access & cur_phase))
1032 if (prop->setter == NULL)
1035 if (!prop->setter(self, prop->base, val, surety, source))
1042 device_property_get_list (Device * self)
1044 g_assert(IS_DEVICE(self));
1046 return DEVICE_GET_CLASS(self)->class_properties_list;
1050 default_device_read_to_fd(Device *self, queue_fd_t *queue_fd) {
1052 StreamingRequirement streaming_mode;
1054 if (device_in_error(self)) return FALSE;
1056 /* Get the device's parameters */
1057 bzero(&val, sizeof(val));
1058 if (!device_property_get(self, PROPERTY_STREAMING, &val)
1059 || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
1060 streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
1062 streaming_mode = g_value_get_enum(&val);
1065 return QUEUE_SUCCESS ==
1066 do_consumer_producer_queue_full(
1067 device_read_producer,
1072 DEFAULT_MAX_BUFFER_MEMORY,
1077 default_device_write_from_fd(Device *self, queue_fd_t *queue_fd) {
1079 StreamingRequirement streaming_mode;
1081 if (device_in_error(self)) return FALSE;
1083 /* Get the device's parameters */
1084 bzero(&val, sizeof(val));
1085 if (!device_property_get(self, PROPERTY_STREAMING, &val)
1086 || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
1087 streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
1089 streaming_mode = g_value_get_enum(&val);
1092 return QUEUE_SUCCESS ==
1093 do_consumer_producer_queue_full(
1096 device_write_consumer,
1099 DEFAULT_MAX_BUFFER_MEMORY,
1104 * All the functions below this comment are stub functions that do nothing
1105 * but implement the virtual function table. Call these functions and they
1106 * will do what you expect vis-a-vis virtual functions. But don't put code
1107 * in them beyond error checking and VFT lookup. */
1110 device_open_device (Device * self, char * device_name,
1111 char * device_type, char * device_node)
1115 g_assert(IS_DEVICE(self));
1116 g_assert(device_name != NULL);
1118 klass = DEVICE_GET_CLASS(self);
1119 g_assert(klass->open_device);
1120 (klass->open_device)(self, device_name, device_type, device_node);
1123 DeviceStatusFlags device_read_label(Device * self) {
1124 DeviceClass * klass;
1126 g_assert(self != NULL);
1127 g_assert(IS_DEVICE(self));
1128 g_assert(self->access_mode == ACCESS_NULL);
1130 klass = DEVICE_GET_CLASS(self);
1131 g_assert(klass->read_label);
1132 return (klass->read_label)(self);
1136 device_finish (Device * self) {
1139 g_assert(IS_DEVICE (self));
1141 klass = DEVICE_GET_CLASS(self);
1142 g_assert(klass->finish);
1143 return (klass->finish)(self);
1147 device_configure (Device * self, gboolean use_global_config)
1151 g_assert(IS_DEVICE (self));
1152 g_assert(self->access_mode == ACCESS_NULL);
1154 klass = DEVICE_GET_CLASS(self);
1155 if(klass->configure) {
1156 return (klass->configure)(self, use_global_config);
1158 device_set_error(self,
1159 stralloc(_("Unimplemented method")),
1160 DEVICE_STATUS_DEVICE_ERROR);
1166 device_start (Device * self, DeviceAccessMode mode,
1167 char * label, char * timestamp)
1170 char * local_timestamp = NULL;
1173 g_assert(IS_DEVICE (self));
1174 g_assert(mode != ACCESS_NULL);
1175 g_assert(mode != ACCESS_WRITE || label != NULL);
1177 klass = DEVICE_GET_CLASS(self);
1178 g_assert(klass->start);
1180 /* For a good combination of synchronization and public simplicity,
1181 this stub function does not require a timestamp, but the actual
1182 implementation function does. We generate the timestamp here with
1184 if (mode == ACCESS_WRITE &&
1185 get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
1186 local_timestamp = timestamp =
1187 get_proper_stamp_from_time(time(NULL));
1190 rv = (klass->start)(self, mode, label, timestamp);
1191 amfree(local_timestamp);
1196 device_write_block (Device * self, guint size, gpointer block)
1200 g_assert(IS_DEVICE (self));
1203 /* these are all things that the caller should take care to
1204 * guarantee, so we just assert them here */
1205 g_assert(size <= self->block_size);
1206 g_assert(self->in_file);
1207 g_assert(!selfp->wrote_short_block);
1208 g_assert(block != NULL);
1209 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1211 if (size < self->block_size)
1212 selfp->wrote_short_block = TRUE;
1214 klass = DEVICE_GET_CLASS(self);
1215 g_assert(klass->write_block);
1216 return (*klass->write_block)(self,size, block);
1220 device_write_from_fd (Device * self, queue_fd_t * queue_fd)
1224 g_assert(IS_DEVICE (self));
1225 g_assert(queue_fd->fd >= 0);
1226 g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
1228 klass = DEVICE_GET_CLASS(self);
1229 g_assert(klass->write_from_fd);
1230 return (klass->write_from_fd)(self,queue_fd);
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_read_to_fd (Device * self, queue_fd_t *queue_fd)
1312 g_assert(IS_DEVICE (self));
1313 g_assert(queue_fd->fd >= 0);
1314 g_assert(self->access_mode == ACCESS_READ);
1316 klass = DEVICE_GET_CLASS(self);
1317 g_assert(klass->read_to_fd);
1318 return (klass->read_to_fd)(self,queue_fd);
1323 device_property_get_ex(
1325 DevicePropertyId id,
1327 PropertySurety *surety,
1328 PropertySource *source)
1332 g_assert(IS_DEVICE (self));
1333 g_assert(device_property_get_by_id(id) != NULL);
1335 klass = DEVICE_GET_CLASS(self);
1337 g_assert(klass->property_get_ex);
1338 return (klass->property_get_ex)(self, id, val, surety, source);
1342 device_property_set_ex(
1344 DevicePropertyId id,
1346 PropertySurety surety,
1347 PropertySource source)
1351 g_assert(IS_DEVICE (self));
1353 klass = DEVICE_GET_CLASS(self);
1355 g_assert(klass->property_set_ex);
1356 return (klass->property_set_ex)(self, id, val, surety, source);
1360 device_recycle_file (Device * self, guint filenum)
1364 g_assert(self != NULL);
1365 g_assert(IS_DEVICE (self));
1366 g_assert(self->access_mode == ACCESS_APPEND);
1367 g_assert(!self->in_file);
1369 klass = DEVICE_GET_CLASS(self);
1371 g_assert(klass->recycle_file);
1372 return (klass->recycle_file)(self,filenum);
1375 /* Property handling */
1378 device_class_register_property(
1380 DevicePropertyId id,
1381 PropertyAccessFlags access,
1382 PropertyGetFn getter,
1383 PropertySetFn setter)
1385 DevicePropertyBase *base;
1386 DeviceProperty *prop;
1390 g_assert(klass != NULL);
1392 base = device_property_get_by_id(id);
1393 g_assert(base != NULL);
1395 if (klass->class_properties->len <= id) {
1396 g_array_set_size(klass->class_properties, id+1);
1399 prop = &g_array_index(klass->class_properties, DeviceProperty, id);
1401 prop->access = access;
1402 prop->getter = getter;
1403 prop->setter = setter;
1405 /* completely rewrite the list of prop pointers, as they may have changed,
1406 * or we may have replaced an existing property*/
1408 if (klass->class_properties_list) {
1409 g_slist_free(klass->class_properties_list);
1413 for (i = 0; i < klass->class_properties->len; i++) {
1414 prop = &g_array_index(klass->class_properties, DeviceProperty, i);
1417 proplist = g_slist_prepend(proplist, prop);
1420 klass->class_properties_list = proplist;
1424 device_set_simple_property(
1426 DevicePropertyId id,
1428 PropertySurety surety,
1429 PropertySource source)
1431 SimpleProperty *simp;
1432 DeviceProperty *prop;
1434 prop = &g_array_index(DEVICE_GET_CLASS(self)->class_properties,
1435 DeviceProperty, id);
1437 /* these assertions should already be checked, but let's be sure */
1438 g_assert(prop->base != NULL); /* prop must be registered with device */
1439 g_assert(G_VALUE_HOLDS(val, prop->base->type));
1441 simp = g_new0(SimpleProperty, 1);
1443 g_value_unset_copy(val, &(simp->response));
1444 simp->surety = surety;
1445 simp->source = source;
1447 g_hash_table_insert(selfp->simple_properties,
1448 GINT_TO_POINTER(id),
1455 device_simple_property_set_fn(
1457 DevicePropertyBase *base,
1459 PropertySurety surety,
1460 PropertySource source)
1462 return device_set_simple_property(self, base->ID, val, surety, source);
1466 device_get_simple_property(
1468 DevicePropertyId id,
1470 PropertySurety *surety,
1471 PropertySource *source)
1473 SimpleProperty *simp =
1474 g_hash_table_lookup(selfp->simple_properties,
1475 GINT_TO_POINTER(id));
1481 g_value_unset_copy(&(simp->response), val);
1484 *surety = simp->surety;
1487 *source = simp->source;
1493 device_simple_property_get_fn(
1495 DevicePropertyBase *base,
1497 PropertySurety *surety,
1498 PropertySource *source)
1500 return device_get_simple_property(self, base->ID, val, surety, source);