PageRenderTime 1097ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/amanda/trunk/device-src/device.c

#
C | 1621 lines | 1228 code | 277 blank | 116 comment | 189 complexity | 5b096ff743fd0c8d68c415626c95ccf0 MD5 | raw file
  1. /*
  2. * Copyright (c) 2007, 2008, 2009, 2010 Zmanda, Inc. All Rights Reserved.
  3. *
  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.
  7. *
  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
  11. * for more details.
  12. *
  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
  16. *
  17. * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
  18. * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
  19. */
  20. /* The Device API abstracts device workings, interaction, properties, and
  21. * capabilities from the rest of the Amanda code base. It supports
  22. * pluggable modules for different kinds of devices. */
  23. #include "amanda.h"
  24. #include "conffile.h"
  25. #include <regex.h>
  26. #include "device.h"
  27. #include "property.h"
  28. #include "timestamp.h"
  29. #include "util.h"
  30. /*
  31. * Prototypes for subclass registration functions
  32. */
  33. void null_device_register (void);
  34. void rait_device_register (void);
  35. #ifdef WANT_S3_DEVICE
  36. void s3_device_register (void);
  37. #endif
  38. #ifdef WANT_TAPE_DEVICE
  39. void tape_device_register (void);
  40. #endif
  41. void vfs_device_register (void);
  42. #ifdef WANT_DVDRW_DEVICE
  43. void dvdrw_device_register (void);
  44. #endif
  45. #ifdef WANT_NDMP_DEVICE
  46. void ndmp_device_register (void);
  47. #endif
  48. /*
  49. * Registration infrastructure
  50. */
  51. static GHashTable* driverList = NULL;
  52. void device_api_init(void) {
  53. glib_init();
  54. device_property_init();
  55. driverList = g_hash_table_new(g_str_hash, g_str_equal);
  56. /* register other types and devices. */
  57. null_device_register();
  58. vfs_device_register();
  59. #ifdef WANT_TAPE_DEVICE
  60. tape_device_register();
  61. #endif
  62. rait_device_register();
  63. #ifdef WANT_S3_DEVICE
  64. s3_device_register();
  65. #endif
  66. #ifdef WANT_DVDRW_DEVICE
  67. dvdrw_device_register();
  68. #endif
  69. #ifdef WANT_NDMP_DEVICE
  70. ndmp_device_register();
  71. #endif
  72. }
  73. void
  74. register_device(
  75. DeviceFactory factory,
  76. const char ** device_prefix_list)
  77. {
  78. char ** tmp;
  79. g_assert(driverList != NULL);
  80. g_assert(factory != NULL);
  81. g_return_if_fail(device_prefix_list != NULL);
  82. g_return_if_fail(*device_prefix_list != NULL);
  83. tmp = (char**)device_prefix_list;
  84. while (*tmp != NULL) {
  85. g_hash_table_insert(driverList, *tmp, (gpointer)factory);
  86. tmp ++;
  87. }
  88. }
  89. static DeviceFactory lookup_device_factory(const char *device_type) {
  90. gpointer key, value;
  91. g_assert(driverList != NULL);
  92. if (g_hash_table_lookup_extended(driverList, device_type, &key, &value)) {
  93. return (DeviceFactory)value;
  94. } else {
  95. return NULL;
  96. }
  97. }
  98. static const GFlagsValue device_status_flags_values[] = {
  99. { DEVICE_STATUS_SUCCESS,
  100. "DEVICE_STATUS_SUCCESS",
  101. "Success" },
  102. { DEVICE_STATUS_DEVICE_ERROR,
  103. "DEVICE_STATUS_DEVICE_ERROR",
  104. "Device error" },
  105. { DEVICE_STATUS_DEVICE_BUSY,
  106. "DEVICE_STATUS_DEVICE_BUSY",
  107. "Device busy" },
  108. { DEVICE_STATUS_VOLUME_MISSING,
  109. "DEVICE_STATUS_VOLUME_MISSING",
  110. "Volume not found" },
  111. { DEVICE_STATUS_VOLUME_UNLABELED,
  112. "DEVICE_STATUS_VOLUME_UNLABELED",
  113. "Volume not labeled" },
  114. { DEVICE_STATUS_VOLUME_ERROR,
  115. "DEVICE_STATUS_VOLUME_ERROR",
  116. "Volume error" },
  117. { 0, NULL, NULL }
  118. };
  119. GType device_status_flags_get_type(void) {
  120. static GType type = 0;
  121. if (G_UNLIKELY(type == 0)) {
  122. type = g_flags_register_static("DeviceStatusFlags",
  123. device_status_flags_values);
  124. }
  125. return type;
  126. }
  127. /* Device class definition starts here. */
  128. struct DevicePrivate_s {
  129. /* hash table mapping ID to SimpleProperty object */
  130. GHashTable * simple_properties;
  131. /* In writing mode, after a short block is written, no additional blocks
  132. * are allowed the file is finished and a new file started. This is only
  133. * used for assertions. */
  134. gboolean wrote_short_block;
  135. /* Holds an error message if the function returned an error. */
  136. char * errmsg;
  137. /* temporary holding place for device_status_error() */
  138. char * statusmsg;
  139. DeviceStatusFlags last_status;
  140. };
  141. /* This holds the default response to a particular property. */
  142. typedef struct {
  143. DeviceProperty *prop;
  144. GValue response;
  145. PropertySurety surety;
  146. PropertySource source;
  147. } SimpleProperty;
  148. #define selfp (self->private)
  149. /* here are local prototypes, so we can make function pointers. */
  150. static void device_init (Device * o);
  151. static void device_class_init (DeviceClass * c);
  152. static void device_base_init (DeviceClass * c);
  153. static void simple_property_free(SimpleProperty *o);
  154. static void default_device_open_device(Device * self, char * device_name,
  155. char * device_type, char * device_node);
  156. static gboolean default_device_configure(Device *self, gboolean use_global_config);
  157. static gboolean default_device_property_get_ex(Device * self, DevicePropertyId id,
  158. GValue * val,
  159. PropertySurety *surety,
  160. PropertySource *source);
  161. static gboolean default_device_property_set_ex(Device *self,
  162. DevicePropertyId id,
  163. GValue * val,
  164. PropertySurety surety,
  165. PropertySource source);
  166. static void set_properties_from_global_config(Device * device);
  167. static void set_properties_from_device_config(Device * device, device_config_t *dc);
  168. static gboolean property_get_block_size_fn(Device *self,
  169. DevicePropertyBase *base, GValue *val,
  170. PropertySurety *surety, PropertySource *source);
  171. static gboolean property_set_block_size_fn(Device *self,
  172. DevicePropertyBase *base, GValue *val,
  173. PropertySurety surety, PropertySource source);
  174. static gboolean property_get_min_block_size_fn(Device *self,
  175. DevicePropertyBase *base, GValue *val,
  176. PropertySurety *surety, PropertySource *source);
  177. static gboolean property_get_max_block_size_fn(Device *self,
  178. DevicePropertyBase *base, GValue *val,
  179. PropertySurety *surety, PropertySource *source);
  180. static gboolean property_get_canonical_name_fn(Device *self,
  181. DevicePropertyBase *base, GValue *val,
  182. PropertySurety *surety, PropertySource *source);
  183. /* pointer to the class of our parent */
  184. static GObjectClass *parent_class = NULL;
  185. GType
  186. device_get_type (void)
  187. {
  188. static GType type = 0;
  189. if G_UNLIKELY(type == 0) {
  190. static const GTypeInfo info = {
  191. sizeof (DeviceClass),
  192. (GBaseInitFunc) device_base_init,
  193. (GBaseFinalizeFunc) NULL,
  194. (GClassInitFunc) device_class_init,
  195. (GClassFinalizeFunc) NULL,
  196. NULL /* class_data */,
  197. sizeof (Device),
  198. 0 /* n_preallocs */,
  199. (GInstanceInitFunc) device_init,
  200. NULL
  201. };
  202. type = g_type_register_static (G_TYPE_OBJECT, "Device", &info,
  203. (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
  204. }
  205. return type;
  206. }
  207. static void device_finalize(GObject *obj_self) {
  208. Device *self G_GNUC_UNUSED = DEVICE (obj_self);
  209. if(G_OBJECT_CLASS(parent_class)->finalize)
  210. (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
  211. /* Here we call device_finish() if it hasn't been done
  212. yet. Subclasses may need to do this same check earlier. */
  213. if (self->access_mode != ACCESS_NULL) {
  214. device_finish(self);
  215. }
  216. amfree(self->device_name);
  217. amfree(self->volume_label);
  218. amfree(self->volume_time);
  219. amfree(self->volume_header);
  220. amfree(selfp->errmsg);
  221. amfree(selfp->statusmsg);
  222. g_hash_table_destroy(selfp->simple_properties);
  223. amfree(self->private);
  224. }
  225. static void
  226. device_init (Device * self)
  227. {
  228. self->private = malloc(sizeof(DevicePrivate));
  229. self->device_name = NULL;
  230. self->access_mode = ACCESS_NULL;
  231. self->is_eof = FALSE;
  232. self->is_eom = FALSE;
  233. self->file = -1;
  234. self->block = 0;
  235. self->in_file = FALSE;
  236. self->volume_label = NULL;
  237. self->volume_time = NULL;
  238. self->status = DEVICE_STATUS_SUCCESS;
  239. self->min_block_size = 1;
  240. self->max_block_size = SIZE_MAX; /* subclasses *really* should choose something smaller */
  241. self->block_size = DISK_BLOCK_BYTES;
  242. selfp->errmsg = NULL;
  243. selfp->statusmsg = NULL;
  244. selfp->last_status = 0;
  245. selfp->simple_properties =
  246. g_hash_table_new_full(g_direct_hash,
  247. g_direct_equal,
  248. NULL,
  249. (GDestroyNotify) simple_property_free);
  250. }
  251. static void
  252. device_class_init (DeviceClass * device_class)
  253. {
  254. GObjectClass *g_object_class = (GObjectClass*) device_class;
  255. parent_class = g_type_class_ref (G_TYPE_OBJECT);
  256. device_class->directtcp_supported = FALSE;
  257. device_class->open_device = default_device_open_device;
  258. device_class->configure = default_device_configure;
  259. device_class->property_get_ex = default_device_property_get_ex;
  260. device_class->property_set_ex = default_device_property_set_ex;
  261. g_object_class->finalize = device_finalize;
  262. }
  263. static void
  264. device_base_init (DeviceClass * device_class)
  265. {
  266. /* The base_init function is called once each time a child class is
  267. * created, before the class_init functions (even our own) are called. */
  268. device_class->class_properties = g_array_new(FALSE, TRUE, sizeof(DeviceProperty));
  269. device_class->class_properties_list = NULL;
  270. device_class_register_property(device_class, PROPERTY_BLOCK_SIZE,
  271. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  272. property_get_block_size_fn,
  273. property_set_block_size_fn);
  274. device_class_register_property(device_class, PROPERTY_MIN_BLOCK_SIZE,
  275. PROPERTY_ACCESS_GET_MASK,
  276. property_get_min_block_size_fn,
  277. NULL);
  278. device_class_register_property(device_class, PROPERTY_MAX_BLOCK_SIZE,
  279. PROPERTY_ACCESS_GET_MASK,
  280. property_get_max_block_size_fn,
  281. NULL);
  282. device_class_register_property(device_class, PROPERTY_CANONICAL_NAME,
  283. PROPERTY_ACCESS_GET_MASK,
  284. property_get_canonical_name_fn,
  285. NULL);
  286. device_class_register_property(device_class, PROPERTY_CONCURRENCY,
  287. PROPERTY_ACCESS_GET_MASK,
  288. device_simple_property_get_fn,
  289. device_simple_property_set_fn);
  290. device_class_register_property(device_class, PROPERTY_STREAMING,
  291. PROPERTY_ACCESS_GET_MASK,
  292. device_simple_property_get_fn,
  293. device_simple_property_set_fn);
  294. device_class_register_property(device_class, PROPERTY_APPENDABLE,
  295. PROPERTY_ACCESS_GET_MASK,
  296. device_simple_property_get_fn,
  297. device_simple_property_set_fn);
  298. device_class_register_property(device_class, PROPERTY_PARTIAL_DELETION,
  299. PROPERTY_ACCESS_GET_MASK,
  300. device_simple_property_get_fn,
  301. device_simple_property_set_fn);
  302. device_class_register_property(device_class, PROPERTY_FULL_DELETION,
  303. PROPERTY_ACCESS_GET_MASK,
  304. device_simple_property_get_fn,
  305. device_simple_property_set_fn);
  306. device_class_register_property(device_class, PROPERTY_MEDIUM_ACCESS_TYPE,
  307. PROPERTY_ACCESS_GET_MASK,
  308. device_simple_property_get_fn,
  309. device_simple_property_set_fn);
  310. device_class_register_property(device_class, PROPERTY_COMMENT,
  311. PROPERTY_ACCESS_GET_MASK|PROPERTY_ACCESS_SET_MASK,
  312. device_simple_property_get_fn,
  313. device_simple_property_set_fn);
  314. device_class_register_property(device_class, PROPERTY_LEOM,
  315. PROPERTY_ACCESS_GET_MASK,
  316. device_simple_property_get_fn,
  317. device_simple_property_set_fn);
  318. }
  319. static void simple_property_free(SimpleProperty * resp) {
  320. g_value_unset(&(resp->response));
  321. amfree(resp);
  322. }
  323. /*
  324. * A full device name (the user_name argument here) must match (case
  325. * insensitive) ^([a-z0-9]+):(.*), with the device driver being $1 and device
  326. * name being $2. However, for legacy reasons, ^[^:](.*) is also accepted, in
  327. * which case the device driver is "tape" and the device name is $1.
  328. *
  329. * As this is pretty much a split over a single colon, we use g_strsplit() to
  330. * split the string against ":", with a maximum of two tokens. This function
  331. * returns a dynamicaly allocated gchar **. Given r0 the first array member and
  332. * r1 the second, the results are as such, according to the input string:
  333. *
  334. * INPUT: "x:y"; OUTPUT: r0 -> "x", r1 -> "y"
  335. * INPUT: "x"; OUTPUT: r0 -> "x", r1 -> NULL
  336. * INPUT: "x:"; OUTPUT: r0 -> "x", r1 -> ""
  337. * INPUT: ":y"; OUTPUT: r0 -> "", r1 -> "y"
  338. * INPUT: ":"; OUTPUT: r0 -> "", r1 -> ""
  339. *
  340. * This leads to the following validation algorithm (note that r0 can never be
  341. * NULL):
  342. *
  343. * - if r0 is the empty string, device name is invalid;
  344. * - if r1 is NULL, the device name is invalid if we don't WANT_TAPE_DEVICE,
  345. * otherwise it is "tape" as the driver and r0 as the device;
  346. * - otherwise, r0 is the device type and r1 the device name.
  347. */
  348. static gboolean
  349. validate_device_name(const char *user_name, char **driver_name, char **device)
  350. {
  351. gboolean ret = FALSE;
  352. gchar **split_result = g_strsplit(user_name, ":", 2);
  353. gchar *split_driver_name = split_result[0], *split_device = split_result[1];
  354. if (!*split_driver_name)
  355. goto out;
  356. if (!split_device) {
  357. #ifdef WANT_TAPE_DEVICE
  358. *driver_name = g_strdup("tape");
  359. *device = g_strdup(split_driver_name);
  360. g_warning("\"%s\" uses deprecated device naming convention; \n"
  361. "using \"tape:%s\" instead.\n", user_name, user_name);
  362. ret = TRUE;
  363. #endif /* WANT_TAPE_DEVICE */
  364. goto out;
  365. }
  366. *driver_name = g_strdup(split_driver_name);
  367. *device = g_strdup(split_device);
  368. ret = TRUE;
  369. out:
  370. g_strfreev(split_result);
  371. return ret;
  372. }
  373. /* helper function for device_open */
  374. static Device *
  375. make_null_error(char *errmsg, DeviceStatusFlags status)
  376. {
  377. DeviceFactory factory;
  378. Device *device;
  379. factory = lookup_device_factory("null");
  380. g_assert(factory != NULL);
  381. device = factory("null:", "null", "");
  382. device_set_error(device, errmsg, status);
  383. return device;
  384. }
  385. char *
  386. device_unaliased_name(
  387. char *device_name)
  388. {
  389. device_config_t *dc;
  390. char *unaliased_name;
  391. /* look up the unaliased device name in the configuration */
  392. if ((dc = lookup_device_config(device_name))) {
  393. if (!(unaliased_name = device_config_get_tapedev(dc))
  394. || unaliased_name[0] == '\0') {
  395. return NULL;
  396. }
  397. } else {
  398. unaliased_name = device_name;
  399. }
  400. return unaliased_name;
  401. }
  402. Device*
  403. device_open (char * device_name)
  404. {
  405. char *device_type = NULL;
  406. char *device_node = NULL;
  407. char *unaliased_name = NULL;
  408. DeviceFactory factory;
  409. Device *device;
  410. g_assert(device_name != NULL);
  411. if (driverList == NULL) {
  412. g_critical("device_open() called without device_api_init()!");
  413. g_assert_not_reached();
  414. }
  415. if (device_name == NULL)
  416. return make_null_error(g_strdup("No device name specified"), DEVICE_STATUS_DEVICE_ERROR);
  417. unaliased_name = device_unaliased_name(device_name);
  418. if (!unaliased_name) {
  419. return make_null_error(
  420. g_strdup_printf("Device \"%s\" has no tapedev", device_name),
  421. DEVICE_STATUS_DEVICE_ERROR);
  422. }
  423. if (!validate_device_name(unaliased_name, &device_type, &device_node)) {
  424. amfree(device_type);
  425. amfree(device_node);
  426. return make_null_error(
  427. g_strdup_printf("\"%s\" is not a valid device name", unaliased_name),
  428. DEVICE_STATUS_DEVICE_ERROR);
  429. }
  430. factory = lookup_device_factory(device_type);
  431. if (factory == NULL) {
  432. Device *nulldev = make_null_error(
  433. g_strdup_printf("Device type \"%s\" is not known", device_type),
  434. DEVICE_STATUS_DEVICE_ERROR);
  435. amfree(device_type);
  436. amfree(device_node);
  437. return nulldev;
  438. }
  439. device = factory(device_name, device_type, device_node);
  440. g_assert(device != NULL); /* factories must always return a device */
  441. amfree(device_type);
  442. amfree(device_node);
  443. return device;
  444. }
  445. char *
  446. device_error(Device * self)
  447. {
  448. if (self == NULL) {
  449. return device_error_or_status(self);
  450. } else if (selfp->errmsg) {
  451. return selfp->errmsg;
  452. } else {
  453. return "Unknown Device error";
  454. }
  455. }
  456. char *
  457. device_status_error(Device * self)
  458. {
  459. char **status_strv;
  460. char *statusmsg;
  461. if (self == NULL) {
  462. return device_error_or_status(self);
  463. }
  464. /* reuse a previous statusmsg, if it was for the same status */
  465. if (selfp->statusmsg && selfp->last_status == self->status)
  466. return selfp->statusmsg;
  467. amfree(selfp->statusmsg);
  468. status_strv = g_flags_nick_to_strv(self->status, DEVICE_STATUS_FLAGS_TYPE);
  469. g_assert(g_strv_length(status_strv) > 0);
  470. if (g_strv_length(status_strv) == 1) {
  471. statusmsg = g_strdup(*status_strv);
  472. } else {
  473. char * status_list = g_english_strjoinv(status_strv, "or");
  474. statusmsg = g_strdup_printf("one of %s", status_list);
  475. amfree(status_list);
  476. }
  477. g_strfreev(status_strv);
  478. selfp->statusmsg = statusmsg;
  479. selfp->last_status = self->status;
  480. return statusmsg;
  481. }
  482. char *
  483. device_error_or_status(Device * self)
  484. {
  485. if (self == NULL) {
  486. return "Device is NULL";
  487. } else if (selfp->errmsg) {
  488. return selfp->errmsg;
  489. } else {
  490. return device_status_error(self);
  491. }
  492. }
  493. void
  494. device_set_error(Device *self, char *errmsg, DeviceStatusFlags new_flags)
  495. {
  496. char **flags_strv;
  497. char *flags_str;
  498. char *device_name;
  499. if (!self) {
  500. g_warning("device_set_error called with a NULL device: '%s'", errmsg? errmsg:"(NULL)");
  501. amfree(errmsg);
  502. return;
  503. }
  504. device_name = self->device_name? self->device_name : "(unknown device)";
  505. if (errmsg && (!selfp->errmsg || !g_str_equal(errmsg, selfp->errmsg)))
  506. g_debug("Device %s error = '%s'", device_name, errmsg);
  507. amfree(selfp->errmsg);
  508. selfp->errmsg = errmsg;
  509. if (new_flags != DEVICE_STATUS_SUCCESS) {
  510. flags_strv = g_flags_name_to_strv(new_flags, DEVICE_STATUS_FLAGS_TYPE);
  511. g_assert(g_strv_length(flags_strv) > 0);
  512. flags_str = g_english_strjoinv(flags_strv, "and");
  513. g_debug("Device %s setting status flag(s): %s", device_name, flags_str);
  514. amfree(flags_str);
  515. g_strfreev(flags_strv);
  516. }
  517. self->status = new_flags;
  518. }
  519. char * device_build_amanda_header(Device * self, const dumpfile_t * info,
  520. size_t *size) {
  521. return build_header(info, size, self->block_size);
  522. }
  523. dumpfile_t * make_tapestart_header(Device * self, char * label,
  524. char * timestamp) {
  525. dumpfile_t * rval;
  526. GValue val;
  527. bzero(&val, sizeof(val));
  528. g_assert(label != NULL);
  529. rval = malloc(sizeof(*rval));
  530. fh_init(rval);
  531. rval->type = F_TAPESTART;
  532. if (device_property_get(self, PROPERTY_BLOCK_SIZE, &val)) {
  533. rval->blocksize = g_value_get_int(&val);
  534. g_value_unset(&val);
  535. }
  536. amfree(self->volume_time);
  537. if (get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
  538. self->volume_time = get_proper_stamp_from_time(time(NULL));
  539. } else {
  540. self->volume_time = g_strdup(timestamp);
  541. }
  542. strncpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp));
  543. strncpy(rval->name, label, sizeof(rval->name));
  544. return rval;
  545. }
  546. dumpfile_t * make_tapeend_header(void) {
  547. dumpfile_t * rval;
  548. char * timestamp;
  549. rval = malloc(sizeof(*rval));
  550. rval->type = F_TAPEEND;
  551. timestamp = get_timestamp_from_time(time(NULL));
  552. strncpy(rval->datestamp, timestamp, sizeof(rval->datestamp));
  553. amfree(timestamp);
  554. return rval;
  555. }
  556. /* Try setting the blocksize on a device. Check results, fallback, and
  557. * set error status for problems. */
  558. static gboolean
  559. try_set_blocksize(Device * device, guint blocksize) {
  560. GValue val;
  561. gboolean success;
  562. bzero(&val, sizeof(val));
  563. g_value_init(&val, G_TYPE_INT);
  564. g_value_set_int(&val, blocksize);
  565. success = device_property_set(device, PROPERTY_BLOCK_SIZE, &val);
  566. g_value_unset(&val);
  567. if (!success) {
  568. device_set_error(device,
  569. g_strdup_printf(_("Setting BLOCK_SIZE to %u "
  570. "not supported for device %s.\n"),
  571. blocksize, device->device_name),
  572. DEVICE_STATUS_DEVICE_ERROR);
  573. }
  574. return success;
  575. }
  576. /* A GHFunc (callback for g_hash_table_foreach) */
  577. static void set_device_property(gpointer key_p, gpointer value_p,
  578. gpointer user_data_p) {
  579. char * property_s = key_p;
  580. property_t * property = value_p;
  581. Device * device = user_data_p;
  582. const DevicePropertyBase* property_base;
  583. GValue property_value;
  584. char * value;
  585. g_return_if_fail(IS_DEVICE(device));
  586. g_return_if_fail(property_s != NULL);
  587. g_return_if_fail(property != NULL);
  588. g_return_if_fail(property->values != NULL);
  589. /* don't continue beating on a device that's already erroring */
  590. if (device_in_error(device)) return;
  591. property_base = device_property_get_by_name(property_s);
  592. if (property_base == NULL) {
  593. /* Nonexistant property name. */
  594. device_set_error(device,
  595. g_strdup_printf(_("unknown device property name '%s'"), property_s),
  596. DEVICE_STATUS_DEVICE_ERROR);
  597. return;
  598. }
  599. if (g_slist_length(property->values) > 1) {
  600. device_set_error(device,
  601. g_strdup_printf(_("multiple values for device property '%s'"), property_s),
  602. DEVICE_STATUS_DEVICE_ERROR);
  603. return;
  604. }
  605. bzero(&property_value, sizeof(property_value));
  606. g_value_init(&property_value, property_base->type);
  607. value = property->values->data;
  608. if (!g_value_set_from_string(&property_value, value)) {
  609. /* Value type could not be interpreted. */
  610. device_set_error(device,
  611. g_strdup_printf(_("Could not parse property value '%s' for property '%s' (property type %s)"),
  612. value, property_base->name, g_type_name(property_base->type)),
  613. DEVICE_STATUS_DEVICE_ERROR);
  614. return;
  615. } else {
  616. g_assert (G_VALUE_HOLDS(&property_value, property_base->type));
  617. }
  618. if (!device_property_set(device, property_base->ID, &property_value)) {
  619. /* Device rejects property. */
  620. if (!device_in_error(device)) {
  621. device_set_error(device,
  622. g_strdup_printf(_("Could not set property '%s' to '%s' on %s"),
  623. property_base->name, value, device->device_name),
  624. DEVICE_STATUS_DEVICE_ERROR);
  625. }
  626. return;
  627. }
  628. }
  629. /* Set up properties based on various taper-related configuration parameters
  630. * and from the tapetype.
  631. */
  632. static void
  633. set_properties_from_global_config(Device * device) {
  634. char * tapetype_name = getconf_str(CNF_TAPETYPE);
  635. if (tapetype_name != NULL) {
  636. tapetype_t * tapetype = lookup_tapetype(tapetype_name);
  637. if (tapetype != NULL) {
  638. GValue val;
  639. guint64 length;
  640. guint blocksize_kb;
  641. gboolean success;
  642. bzero(&val, sizeof(GValue));
  643. if (tapetype_seen(tapetype, TAPETYPE_LENGTH)) {
  644. length = tapetype_get_length(tapetype);
  645. g_value_init(&val, G_TYPE_UINT64);
  646. g_value_set_uint64(&val, length * 1024);
  647. /* If this fails, it's not really an error. */
  648. device_property_set(device, PROPERTY_MAX_VOLUME_USAGE, &val);
  649. g_value_unset(&val);
  650. }
  651. if (tapetype_seen(tapetype, TAPETYPE_READBLOCKSIZE)) {
  652. blocksize_kb = tapetype_get_readblocksize(tapetype);
  653. g_value_init(&val, G_TYPE_UINT);
  654. g_value_set_uint(&val, blocksize_kb * 1024);
  655. success = device_property_set(device,
  656. PROPERTY_READ_BLOCK_SIZE,
  657. &val);
  658. g_value_unset(&val);
  659. if (!success) {
  660. /* a non-fatal error */
  661. g_warning("Setting READ_BLOCK_SIZE to %ju not supported for device %s.",
  662. 1024*(uintmax_t)blocksize_kb, device->device_name);
  663. }
  664. }
  665. if (tapetype_seen(tapetype, TAPETYPE_BLOCKSIZE)) {
  666. blocksize_kb = tapetype_get_blocksize(tapetype);
  667. /* TODO: handle errors */
  668. (void)try_set_blocksize(device, blocksize_kb * 1024);
  669. }
  670. }
  671. }
  672. g_hash_table_foreach(getconf_proplist(CNF_DEVICE_PROPERTY),
  673. set_device_property, device);
  674. }
  675. /* Set properties specified within a device definition */
  676. static void
  677. set_properties_from_device_config(Device * device, device_config_t *dc) {
  678. g_hash_table_foreach(device_config_get_property(dc),
  679. set_device_property, device);
  680. }
  681. static gboolean
  682. default_device_configure(Device *self, gboolean use_global_config)
  683. {
  684. device_config_t *dc;
  685. if (device_in_error(self))
  686. return FALSE;
  687. if (use_global_config)
  688. set_properties_from_global_config(self);
  689. if (device_in_error(self))
  690. return FALSE;
  691. if ((dc = lookup_device_config(self->device_name)))
  692. set_properties_from_device_config(self, dc);
  693. return !device_in_error(self);
  694. }
  695. void device_clear_volume_details(Device * device) {
  696. if (device == NULL || device->access_mode != ACCESS_NULL) {
  697. return;
  698. }
  699. amfree(device->volume_label);
  700. amfree(device->volume_time);
  701. }
  702. /* Here we put default implementations of virtual functions. Since
  703. this class is virtual, many of these functions offer at best
  704. incomplete functionality. But they do offer the useful commonality
  705. that all devices can expect to need. */
  706. static void default_device_open_device(Device * self, char * device_name,
  707. char * device_type G_GNUC_UNUSED, char * device_node G_GNUC_UNUSED) {
  708. /* Set the device_name property */
  709. self->device_name = g_strdup(device_name);
  710. }
  711. static gboolean
  712. property_get_block_size_fn(
  713. Device *self,
  714. DevicePropertyBase *base G_GNUC_UNUSED,
  715. GValue *val,
  716. PropertySurety *surety,
  717. PropertySource *source)
  718. {
  719. g_value_unset_init(val, G_TYPE_INT);
  720. g_assert(self->block_size < G_MAXINT); /* gsize -> gint */
  721. g_value_set_int(val, (gint)self->block_size);
  722. if (surety)
  723. *surety = self->block_size_surety;
  724. if (source)
  725. *source = self->block_size_source;
  726. return TRUE;
  727. }
  728. static gboolean
  729. property_set_block_size_fn(
  730. Device *self,
  731. DevicePropertyBase *base G_GNUC_UNUSED,
  732. GValue *val,
  733. PropertySurety surety,
  734. PropertySource source)
  735. {
  736. gint block_size = g_value_get_int(val);
  737. g_assert(block_size >= 0); /* int -> gsize (unsigned) */
  738. if ((gsize)block_size < self->min_block_size
  739. || (gsize)block_size > self->max_block_size) {
  740. device_set_error(self,
  741. 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),
  742. DEVICE_STATUS_DEVICE_ERROR);
  743. return FALSE;
  744. }
  745. self->block_size = block_size;
  746. self->block_size_surety = surety;
  747. self->block_size_source = source;
  748. return TRUE;
  749. }
  750. static gboolean
  751. property_get_min_block_size_fn(
  752. Device *self,
  753. DevicePropertyBase *base G_GNUC_UNUSED,
  754. GValue *val,
  755. PropertySurety *surety,
  756. PropertySource *source)
  757. {
  758. g_value_unset_init(val, G_TYPE_UINT);
  759. g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
  760. g_value_set_uint(val, (guint)self->min_block_size);
  761. if (surety)
  762. *surety = PROPERTY_SURETY_GOOD;
  763. if (source)
  764. *source = PROPERTY_SOURCE_DEFAULT;
  765. return TRUE;
  766. }
  767. static gboolean
  768. property_get_max_block_size_fn(
  769. Device *self,
  770. DevicePropertyBase *base G_GNUC_UNUSED,
  771. GValue *val,
  772. PropertySurety *surety,
  773. PropertySource *source)
  774. {
  775. g_value_unset_init(val, G_TYPE_UINT);
  776. g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
  777. g_value_set_uint(val, (guint)self->max_block_size);
  778. if (surety)
  779. *surety = PROPERTY_SURETY_GOOD;
  780. if (source)
  781. *source = PROPERTY_SOURCE_DEFAULT;
  782. return TRUE;
  783. }
  784. static gboolean
  785. property_get_canonical_name_fn(
  786. Device *self,
  787. DevicePropertyBase *base G_GNUC_UNUSED,
  788. GValue *val,
  789. PropertySurety *surety,
  790. PropertySource *source)
  791. {
  792. g_value_unset_init(val, G_TYPE_STRING);
  793. g_value_set_string(val, self->device_name);
  794. if (surety)
  795. *surety = PROPERTY_SURETY_GOOD;
  796. if (source)
  797. *source = PROPERTY_SOURCE_DEFAULT;
  798. return TRUE;
  799. }
  800. /* util function */
  801. static PropertyPhaseFlags
  802. state_to_phase(
  803. Device *self)
  804. {
  805. if (self->access_mode == ACCESS_NULL) {
  806. return PROPERTY_PHASE_BEFORE_START;
  807. } else if (IS_WRITABLE_ACCESS_MODE(self->access_mode)) {
  808. if (self->in_file) {
  809. return PROPERTY_PHASE_INSIDE_FILE_WRITE;
  810. } else {
  811. return PROPERTY_PHASE_BETWEEN_FILE_WRITE;
  812. }
  813. } else { /* read mode */
  814. if (self->in_file) {
  815. return PROPERTY_PHASE_INSIDE_FILE_READ;
  816. } else {
  817. return PROPERTY_PHASE_BETWEEN_FILE_READ;
  818. }
  819. }
  820. }
  821. /* This default implementation serves up static responses, and
  822. implements a few default responses based on values from the Device
  823. struct. */
  824. static gboolean
  825. default_device_property_get_ex(
  826. Device * self,
  827. DevicePropertyId id,
  828. GValue * val,
  829. PropertySurety *surety,
  830. PropertySource *source)
  831. {
  832. DeviceProperty *prop;
  833. GArray *class_properties;
  834. PropertyPhaseFlags cur_phase;
  835. /* Most of this function's job is to sanity-check everything, then
  836. * call the relevant getter. */
  837. class_properties = DEVICE_GET_CLASS(self)->class_properties;
  838. if (id >= class_properties->len)
  839. return FALSE;
  840. prop = &g_array_index(class_properties, DeviceProperty, id);
  841. if (prop->base == NULL)
  842. return FALSE;
  843. if (val || surety || source) {
  844. /* check the phase */
  845. cur_phase = state_to_phase(self);
  846. if (!(prop->access & cur_phase))
  847. return FALSE;
  848. if (prop->getter == NULL)
  849. return FALSE;
  850. if (!prop->getter(self, prop->base, val, surety, source))
  851. return FALSE;
  852. }
  853. return TRUE;
  854. }
  855. static gboolean
  856. default_device_property_set_ex(
  857. Device *self,
  858. DevicePropertyId id,
  859. GValue * val,
  860. PropertySurety surety,
  861. PropertySource source)
  862. {
  863. DeviceProperty *prop;
  864. GArray *class_properties;
  865. PropertyPhaseFlags cur_phase;
  866. /* Most of this function's job is to sanity-check everything, then
  867. * call the relevant setter. */
  868. if (device_in_error(self))
  869. return FALSE;
  870. class_properties = DEVICE_GET_CLASS(self)->class_properties;
  871. if (id >= class_properties->len)
  872. return FALSE;
  873. prop = &g_array_index(class_properties, DeviceProperty, id);
  874. if (prop->base == NULL)
  875. return FALSE;
  876. /* check that the type matches */
  877. if (!G_VALUE_HOLDS(val, prop->base->type))
  878. return FALSE;
  879. /* check the phase */
  880. cur_phase = state_to_phase(self) << PROPERTY_PHASE_SHIFT;
  881. if (!(prop->access & cur_phase))
  882. return FALSE;
  883. if (prop->setter == NULL)
  884. return FALSE;
  885. if (!prop->setter(self, prop->base, val, surety, source))
  886. return FALSE;
  887. return TRUE;
  888. }
  889. const GSList *
  890. device_property_get_list (Device * self)
  891. {
  892. g_assert(IS_DEVICE(self));
  893. return DEVICE_GET_CLASS(self)->class_properties_list;
  894. }
  895. /* XXX WARNING XXX
  896. * All the functions below this comment are stub functions that do nothing
  897. * but implement the virtual function table. Call these functions and they
  898. * will do what you expect vis-a-vis virtual functions. But don't put code
  899. * in them beyond error checking and VFT lookup. */
  900. void
  901. device_open_device (Device * self, char * device_name,
  902. char * device_type, char * device_node)
  903. {
  904. DeviceClass *klass;
  905. g_assert(IS_DEVICE(self));
  906. g_assert(device_name != NULL);
  907. klass = DEVICE_GET_CLASS(self);
  908. g_assert(klass->open_device);
  909. (klass->open_device)(self, device_name, device_type, device_node);
  910. }
  911. DeviceStatusFlags device_read_label(Device * self) {
  912. DeviceClass * klass;
  913. g_assert(self != NULL);
  914. g_assert(IS_DEVICE(self));
  915. g_assert(self->access_mode == ACCESS_NULL);
  916. klass = DEVICE_GET_CLASS(self);
  917. g_assert(klass->read_label);
  918. return (klass->read_label)(self);
  919. }
  920. gboolean
  921. device_finish (Device * self) {
  922. DeviceClass *klass;
  923. g_assert(IS_DEVICE (self));
  924. klass = DEVICE_GET_CLASS(self);
  925. g_assert(klass->finish);
  926. return (klass->finish)(self);
  927. }
  928. guint64
  929. device_get_bytes_read (Device * self) {
  930. DeviceClass *klass;
  931. g_assert(IS_DEVICE (self));
  932. if (self->in_file) {
  933. klass = DEVICE_GET_CLASS(self);
  934. if (klass->get_bytes_read) {
  935. return (klass->get_bytes_read)(self);
  936. } else {
  937. return self->bytes_read;
  938. }
  939. }
  940. return 0;
  941. }
  942. gboolean
  943. device_configure (Device * self, gboolean use_global_config)
  944. {
  945. DeviceClass *klass;
  946. g_assert(IS_DEVICE (self));
  947. g_assert(self->access_mode == ACCESS_NULL);
  948. klass = DEVICE_GET_CLASS(self);
  949. if(klass->configure) {
  950. return (klass->configure)(self, use_global_config);
  951. } else {
  952. device_set_error(self,
  953. g_strdup(_("Unimplemented method")),
  954. DEVICE_STATUS_DEVICE_ERROR);
  955. return FALSE;
  956. }
  957. }
  958. gboolean
  959. device_start (Device * self, DeviceAccessMode mode,
  960. char * label, char * timestamp)
  961. {
  962. DeviceClass *klass;
  963. char * local_timestamp = NULL;
  964. gboolean rv;
  965. g_assert(IS_DEVICE (self));
  966. g_assert(mode != ACCESS_NULL);
  967. g_assert(mode != ACCESS_WRITE || label != NULL);
  968. klass = DEVICE_GET_CLASS(self);
  969. g_assert(klass->start);
  970. /* For a good combination of synchronization and public simplicity,
  971. this stub function does not require a timestamp, but the actual
  972. implementation function does. We generate the timestamp here with
  973. time(). */
  974. if (mode == ACCESS_WRITE &&
  975. get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
  976. local_timestamp = timestamp =
  977. get_proper_stamp_from_time(time(NULL));
  978. }
  979. rv = (klass->start)(self, mode, label, timestamp);
  980. amfree(local_timestamp);
  981. return rv;
  982. }
  983. gboolean
  984. device_write_block (Device * self, guint size, gpointer block)
  985. {
  986. DeviceClass *klass;
  987. g_assert(IS_DEVICE (self));
  988. g_assert(size > 0);
  989. /* these are all things that the caller should take care to
  990. * guarantee, so we just assert them here */
  991. g_assert(size <= self->block_size);
  992. g_assert(self->in_file);
  993. g_assert(!selfp->wrote_short_block);
  994. g_assert(block != NULL);
  995. g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
  996. if (size < self->block_size)
  997. selfp->wrote_short_block = TRUE;
  998. klass = DEVICE_GET_CLASS(self);
  999. g_assert(klass->write_block);
  1000. return (*klass->write_block)(self,size, block);
  1001. }
  1002. gboolean
  1003. device_start_file (Device * self, dumpfile_t * jobInfo) {
  1004. DeviceClass * klass;
  1005. g_assert(IS_DEVICE (self));
  1006. g_assert(!(self->in_file));
  1007. g_assert(jobInfo != NULL);
  1008. selfp->wrote_short_block = FALSE;
  1009. klass = DEVICE_GET_CLASS(self);
  1010. g_assert(klass->start_file);
  1011. return (klass->start_file)(self, jobInfo );
  1012. }
  1013. gboolean
  1014. device_finish_file (Device * self)
  1015. {
  1016. DeviceClass *klass;
  1017. g_assert(IS_DEVICE (self));
  1018. g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
  1019. g_assert(self->in_file);
  1020. klass = DEVICE_GET_CLASS(self);
  1021. g_assert(klass->finish_file);
  1022. return (klass->finish_file)(self);
  1023. }
  1024. dumpfile_t*
  1025. device_seek_file (Device * self, guint file)
  1026. {
  1027. DeviceClass *klass;
  1028. g_assert(IS_DEVICE (self));
  1029. g_assert(self->access_mode == ACCESS_READ);
  1030. klass = DEVICE_GET_CLASS(self);
  1031. g_assert(klass->seek_file);
  1032. return (klass->seek_file)(self,file);
  1033. }
  1034. gboolean
  1035. device_seek_block (Device * self, guint64 block)
  1036. {
  1037. DeviceClass *klass;
  1038. g_assert(IS_DEVICE (self));
  1039. g_assert(self->access_mode == ACCESS_READ);
  1040. g_assert(self->in_file);
  1041. klass = DEVICE_GET_CLASS(self);
  1042. g_assert(klass->seek_block);
  1043. return (klass->seek_block)(self,block);
  1044. }
  1045. int
  1046. device_read_block (Device * self, gpointer buffer, int * size)
  1047. {
  1048. DeviceClass *klass;
  1049. g_assert(IS_DEVICE (self));
  1050. g_assert(size != NULL);
  1051. g_assert(self->access_mode == ACCESS_READ);
  1052. if (*size != 0) {
  1053. g_assert(buffer != NULL);
  1054. }
  1055. klass = DEVICE_GET_CLASS(self);
  1056. g_assert(klass->read_block);
  1057. return (klass->read_block)(self,buffer,size);
  1058. }
  1059. gboolean
  1060. device_property_get_ex(
  1061. Device * self,
  1062. DevicePropertyId id,
  1063. GValue * val,
  1064. PropertySurety *surety,
  1065. PropertySource *source)
  1066. {
  1067. DeviceClass *klass;
  1068. g_assert(IS_DEVICE (self));
  1069. g_assert(device_property_get_by_id(id) != NULL);
  1070. klass = DEVICE_GET_CLASS(self);
  1071. g_assert(klass->property_get_ex);
  1072. return (klass->property_get_ex)(self, id, val, surety, source);
  1073. }
  1074. gboolean
  1075. device_property_set_ex(
  1076. Device * self,
  1077. DevicePropertyId id,
  1078. GValue * val,
  1079. PropertySurety surety,
  1080. PropertySource source)
  1081. {
  1082. DeviceClass *klass;
  1083. g_assert(IS_DEVICE (self));
  1084. klass = DEVICE_GET_CLASS(self);
  1085. g_assert(klass->property_set_ex);
  1086. return (klass->property_set_ex)(self, id, val, surety, source);
  1087. }
  1088. gboolean
  1089. device_recycle_file (Device * self, guint filenum)
  1090. {
  1091. DeviceClass *klass;
  1092. g_assert(self != NULL);
  1093. g_assert(IS_DEVICE (self));
  1094. g_assert(self->access_mode == ACCESS_APPEND);
  1095. g_assert(!self->in_file);
  1096. klass = DEVICE_GET_CLASS(self);
  1097. g_assert(klass->recycle_file);
  1098. return (klass->recycle_file)(self,filenum);
  1099. }
  1100. gboolean
  1101. device_erase (Device * self)
  1102. {
  1103. DeviceClass *klass;
  1104. g_assert(IS_DEVICE (self));
  1105. g_assert(self->access_mode == ACCESS_NULL);
  1106. g_assert(!self->in_file);
  1107. klass = DEVICE_GET_CLASS(self);
  1108. if(klass->erase) {
  1109. return (klass->erase)(self);
  1110. } else {
  1111. device_set_error(self,
  1112. g_strdup(_("Unimplemented method")),
  1113. DEVICE_STATUS_DEVICE_ERROR);
  1114. return FALSE;
  1115. }
  1116. }
  1117. gboolean
  1118. device_eject (Device * self)
  1119. {
  1120. DeviceClass *klass;
  1121. g_assert(IS_DEVICE (self));
  1122. g_assert(self->access_mode == ACCESS_NULL);
  1123. g_assert(!self->in_file);
  1124. klass = DEVICE_GET_CLASS(self);
  1125. if (klass->eject) {
  1126. return (klass->eject)(self);
  1127. } else {
  1128. return TRUE;
  1129. }
  1130. }
  1131. gboolean
  1132. device_listen(
  1133. Device *self,
  1134. gboolean for_writing,
  1135. DirectTCPAddr **addrs)
  1136. {
  1137. DeviceClass *klass;
  1138. klass = DEVICE_GET_CLASS(self);
  1139. if(klass->listen) {
  1140. return (klass->listen)(self, for_writing, addrs);
  1141. } else {
  1142. device_set_error(self,
  1143. g_strdup(_("Unimplemented method")),
  1144. DEVICE_STATUS_DEVICE_ERROR);
  1145. return FALSE;
  1146. }
  1147. }
  1148. gboolean
  1149. device_accept(
  1150. Device *self,
  1151. DirectTCPConnection **conn,
  1152. ProlongProc prolong,
  1153. gpointer prolong_data)
  1154. {
  1155. DeviceClass *klass;
  1156. klass = DEVICE_GET_CLASS(self);
  1157. if(klass->accept) {
  1158. return (klass->accept)(self, conn, prolong, prolong_data);
  1159. } else {
  1160. device_set_error(self,
  1161. g_strdup(_("Unimplemented method")),
  1162. DEVICE_STATUS_DEVICE_ERROR);
  1163. return FALSE;
  1164. }
  1165. }
  1166. gboolean
  1167. device_connect(
  1168. Device *self,
  1169. gboolean for_writing,
  1170. DirectTCPAddr *addrs,
  1171. DirectTCPConnection **conn,
  1172. ProlongProc prolong,
  1173. gpointer prolong_data)
  1174. {
  1175. DeviceClass *klass;
  1176. klass = DEVICE_GET_CLASS(self);
  1177. if(klass->connect) {
  1178. return (klass->connect)(self, for_writing, addrs, conn, prolong, prolong_data);
  1179. } else {
  1180. device_set_error(self,
  1181. g_strdup(_("Unimplemented method")),
  1182. DEVICE_STATUS_DEVICE_ERROR);
  1183. return FALSE;
  1184. }
  1185. }
  1186. gboolean
  1187. device_write_from_connection(
  1188. Device *self,
  1189. guint64 size,
  1190. guint64 *actual_size)
  1191. {
  1192. DeviceClass *klass;
  1193. klass = DEVICE_GET_CLASS(self);
  1194. g_assert(self->in_file);
  1195. g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
  1196. if(klass->write_from_connection) {
  1197. return (klass->write_from_connection)(self, size, actual_size);
  1198. } else {
  1199. device_set_error(self,
  1200. g_strdup(_("Unimplemented method")),
  1201. DEVICE_STATUS_DEVICE_ERROR);
  1202. return FALSE;
  1203. }
  1204. }
  1205. gboolean
  1206. device_read_to_connection(
  1207. Device *self,
  1208. guint64 size,
  1209. guint64 *actual_size)
  1210. {
  1211. DeviceClass *klass;
  1212. g_assert(self->in_file);
  1213. g_assert(self->access_mode == ACCESS_READ);
  1214. klass = DEVICE_GET_CLASS(self);
  1215. if(klass->read_to_connection) {
  1216. return (klass->read_to_connection)(self, size, actual_size);
  1217. } else {
  1218. device_set_error(self,
  1219. g_strdup(_("Unimplemented method")),
  1220. DEVICE_STATUS_DEVICE_ERROR);
  1221. return FALSE;
  1222. }
  1223. }
  1224. gboolean
  1225. device_use_connection(
  1226. Device *self,
  1227. DirectTCPConnection *conn)
  1228. {
  1229. DeviceClass *klass;
  1230. g_assert(self->access_mode == ACCESS_NULL);
  1231. klass = DEVICE_GET_CLASS(self);
  1232. if(klass->use_connection) {
  1233. return (klass->use_connection)(self, conn);
  1234. } else {
  1235. device_set_error(self,
  1236. g_strdup(_("Unimplemented method")),
  1237. DEVICE_STATUS_DEVICE_ERROR);
  1238. return FALSE;
  1239. }
  1240. }
  1241. /* Property handling */
  1242. void
  1243. device_class_register_property(
  1244. DeviceClass *klass,
  1245. DevicePropertyId id,
  1246. PropertyAccessFlags access,
  1247. PropertyGetFn getter,
  1248. PropertySetFn setter)
  1249. {
  1250. DevicePropertyBase *base;
  1251. DeviceProperty *prop;
  1252. GSList *proplist;
  1253. guint i;
  1254. g_assert(klass != NULL);
  1255. base = device_property_get_by_id(id);
  1256. g_assert(base != NULL);
  1257. if (klass->class_properties->len <= id) {
  1258. g_array_set_size(klass->class_properties, id+1);
  1259. }
  1260. prop = &g_array_index(klass->class_properties, DeviceProperty, id);
  1261. prop->base = base;
  1262. prop->access = access;
  1263. prop->getter = getter;
  1264. prop->setter = setter;
  1265. /* completely rewrite the list of prop pointers, as they may have changed,
  1266. * or we may have replaced an existing property*/
  1267. if (klass->class_properties_list) {
  1268. g_slist_free(klass->class_properties_list);
  1269. }
  1270. proplist = NULL;
  1271. for (i = 0; i < klass->class_properties->len; i++) {
  1272. prop = &g_array_index(klass->class_properties, DeviceProperty, i);
  1273. if (!prop->base)
  1274. continue;
  1275. proplist = g_slist_prepend(proplist, prop);
  1276. }
  1277. klass->class_properties_list = proplist;
  1278. }
  1279. gboolean
  1280. device_set_simple_property(
  1281. Device *self,
  1282. DevicePropertyId id,
  1283. GValue *val,
  1284. PropertySurety surety,
  1285. PropertySource source)
  1286. {
  1287. SimpleProperty *simp;
  1288. DeviceProperty *prop;
  1289. prop = &g_array_index(DEVICE_GET_CLASS(self)->class_properties,
  1290. DeviceProperty, id);
  1291. /* these assertions should already be checked, but let's be sure */
  1292. g_assert(prop->base != NULL); /* prop must be registered with device */
  1293. g_assert(G_VALUE_HOLDS(val, prop->base->type));
  1294. simp = g_new0(SimpleProperty, 1);
  1295. simp->prop = prop;
  1296. g_value_unset_copy(val, &(simp->response));
  1297. simp->surety = surety;
  1298. simp->source = source;
  1299. g_hash_table_insert(selfp->simple_properties,
  1300. GINT_TO_POINTER(id),
  1301. simp);
  1302. return TRUE;
  1303. }
  1304. gboolean
  1305. device_simple_property_set_fn(
  1306. Device *self,
  1307. DevicePropertyBase *base,
  1308. GValue *val,
  1309. PropertySurety surety,
  1310. PropertySource source)
  1311. {
  1312. return device_set_simple_property(self, base->ID, val, surety, source);
  1313. }
  1314. gboolean
  1315. device_get_simple_property(
  1316. Device *self,
  1317. DevicePropertyId id,
  1318. GValue *val,
  1319. PropertySurety *surety,
  1320. PropertySource *source)
  1321. {
  1322. SimpleProperty *simp =
  1323. g_hash_table_lookup(selfp->simple_properties,
  1324. GINT_TO_POINTER(id));
  1325. if (!simp)
  1326. return FALSE;
  1327. if (val)
  1328. g_value_unset_copy(&(simp->response), val);
  1329. if (surety)
  1330. *surety = simp->surety;
  1331. if (source)
  1332. *source = simp->source;
  1333. return TRUE;
  1334. }
  1335. gboolean
  1336. device_simple_property_get_fn(
  1337. Device *self,
  1338. DevicePropertyBase *base,
  1339. GValue *val,
  1340. PropertySurety *surety,
  1341. PropertySource *source)
  1342. {
  1343. return device_get_simple_property(self, base->ID, val, surety, source);
  1344. }