PageRenderTime 77ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/amanda/tags/3_3_0beta1/device-src/device.c

#
C | 1604 lines | 1238 code | 275 blank | 91 comment | 195 complexity | 1e7f37249d49a1634f4ee7778059a1d7 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. static char *
  324. regex_message(int result, regex_t *regex) {
  325. char * rval;
  326. size_t size;
  327. size = regerror(result, regex, NULL, 0);
  328. rval = malloc(size);
  329. regerror(result, regex, rval, size);
  330. return rval;
  331. }
  332. static gboolean
  333. handle_device_regex(const char * user_name, char ** driver_name,
  334. char ** device, char **errmsg) {
  335. regex_t regex;
  336. int reg_result;
  337. regmatch_t pmatch[3];
  338. static const char * regex_string = "^([a-z0-9]+):(.*)$";
  339. bzero(&regex, sizeof(regex));
  340. reg_result = regcomp(&regex, regex_string, REG_EXTENDED | REG_ICASE);
  341. if (reg_result != 0) {
  342. char * message = regex_message(reg_result, &regex);
  343. *errmsg = newvstrallocf(*errmsg, "Error compiling regular expression \"%s\": %s\n",
  344. regex_string, message);
  345. amfree(message);
  346. return FALSE;
  347. }
  348. reg_result = regexec(&regex, user_name, 3, pmatch, 0);
  349. if (reg_result != 0 && reg_result != REG_NOMATCH) {
  350. char * message = regex_message(reg_result, &regex);
  351. *errmsg = newvstrallocf(*errmsg,
  352. "Error applying regular expression \"%s\" to string \"%s\": %s\n",
  353. user_name, regex_string, message);
  354. amfree(message);
  355. regfree(&regex);
  356. return FALSE;
  357. } else if (reg_result == REG_NOMATCH) {
  358. #ifdef WANT_TAPE_DEVICE
  359. g_warning(
  360. "\"%s\" uses deprecated device naming convention; \n"
  361. "using \"tape:%s\" instead.\n",
  362. user_name, user_name);
  363. *driver_name = stralloc("tape");
  364. *device = stralloc(user_name);
  365. #else /* !WANT_TAPE_DEVICE */
  366. *errmsg = newvstrallocf(*errmsg, "\"%s\" is not a valid device name.\n", user_name);
  367. regfree(&regex);
  368. return FALSE;
  369. #endif /* WANT_TAPE_DEVICE */
  370. } else {
  371. *driver_name = find_regex_substring(user_name, pmatch[1]);
  372. *device = find_regex_substring(user_name, pmatch[2]);
  373. }
  374. regfree(&regex);
  375. return TRUE;
  376. }
  377. /* helper function for device_open */
  378. static Device *
  379. make_null_error(char *errmsg, DeviceStatusFlags status)
  380. {
  381. DeviceFactory factory;
  382. Device *device;
  383. factory = lookup_device_factory("null");
  384. g_assert(factory != NULL);
  385. device = factory("null:", "null", "");
  386. device_set_error(device, errmsg, status);
  387. return device;
  388. }
  389. char *
  390. device_unaliased_name(
  391. char *device_name)
  392. {
  393. device_config_t *dc;
  394. char *unaliased_name;
  395. /* look up the unaliased device name in the configuration */
  396. if ((dc = lookup_device_config(device_name))) {
  397. if (!(unaliased_name = device_config_get_tapedev(dc))
  398. || unaliased_name[0] == '\0') {
  399. return NULL;
  400. }
  401. } else {
  402. unaliased_name = device_name;
  403. }
  404. return unaliased_name;
  405. }
  406. Device*
  407. device_open (char * device_name)
  408. {
  409. char *device_type = NULL;
  410. char *device_node = NULL;
  411. char *errmsg = NULL;
  412. char *unaliased_name = NULL;
  413. DeviceFactory factory;
  414. Device *device;
  415. g_assert(device_name != NULL);
  416. if (driverList == NULL) {
  417. g_critical("device_open() called without device_api_init()!");
  418. g_assert_not_reached();
  419. }
  420. if (device_name == NULL)
  421. return make_null_error(stralloc(_("No device name specified")), DEVICE_STATUS_DEVICE_ERROR);
  422. unaliased_name = device_unaliased_name(device_name);
  423. if (!unaliased_name) {
  424. return make_null_error(
  425. vstrallocf(_("Device '%s' has no tapedev"), device_name),
  426. DEVICE_STATUS_DEVICE_ERROR);
  427. }
  428. if (!handle_device_regex(unaliased_name, &device_type, &device_node,
  429. &errmsg)) {
  430. amfree(device_type);
  431. amfree(device_node);
  432. return make_null_error(errmsg, DEVICE_STATUS_DEVICE_ERROR);
  433. }
  434. factory = lookup_device_factory(device_type);
  435. if (factory == NULL) {
  436. Device *nulldev = make_null_error(vstrallocf(_("Device type %s is not known."),
  437. device_type), DEVICE_STATUS_DEVICE_ERROR);
  438. amfree(device_type);
  439. amfree(device_node);
  440. return nulldev;
  441. }
  442. device = factory(device_name, device_type, device_node);
  443. g_assert(device != NULL); /* factories must always return a device */
  444. amfree(device_type);
  445. amfree(device_node);
  446. return device;
  447. }
  448. char *
  449. device_error(Device * self)
  450. {
  451. if (self == NULL) {
  452. return device_error_or_status(self);
  453. } else if (selfp->errmsg) {
  454. return selfp->errmsg;
  455. } else {
  456. return "Unknown Device error";
  457. }
  458. }
  459. char *
  460. device_status_error(Device * self)
  461. {
  462. char **status_strv;
  463. char *statusmsg;
  464. if (self == NULL) {
  465. return device_error_or_status(self);
  466. }
  467. /* reuse a previous statusmsg, if it was for the same status */
  468. if (selfp->statusmsg && selfp->last_status == self->status)
  469. return selfp->statusmsg;
  470. amfree(selfp->statusmsg);
  471. status_strv = g_flags_nick_to_strv(self->status, DEVICE_STATUS_FLAGS_TYPE);
  472. g_assert(g_strv_length(status_strv) > 0);
  473. if (g_strv_length(status_strv) == 1) {
  474. statusmsg = stralloc(*status_strv);
  475. } else {
  476. char * status_list = g_english_strjoinv(status_strv, "or");
  477. statusmsg = g_strdup_printf("one of %s", status_list);
  478. amfree(status_list);
  479. }
  480. g_strfreev(status_strv);
  481. selfp->statusmsg = statusmsg;
  482. selfp->last_status = self->status;
  483. return statusmsg;
  484. }
  485. char *
  486. device_error_or_status(Device * self)
  487. {
  488. if (self == NULL) {
  489. return "Device is NULL";
  490. } else if (selfp->errmsg) {
  491. return selfp->errmsg;
  492. } else {
  493. return device_status_error(self);
  494. }
  495. }
  496. void
  497. device_set_error(Device *self, char *errmsg, DeviceStatusFlags new_flags)
  498. {
  499. char **flags_strv;
  500. char *flags_str;
  501. char *device_name;
  502. if (!self) {
  503. g_warning("device_set_error called with a NULL device: '%s'", errmsg? errmsg:"(NULL)");
  504. amfree(errmsg);
  505. return;
  506. }
  507. device_name = self->device_name? self->device_name : "(unknown device)";
  508. if (errmsg && (!selfp->errmsg || strcmp(errmsg, selfp->errmsg) != 0))
  509. g_debug("Device %s error = '%s'", device_name, errmsg);
  510. amfree(selfp->errmsg);
  511. selfp->errmsg = errmsg;
  512. if (new_flags != DEVICE_STATUS_SUCCESS) {
  513. flags_strv = g_flags_name_to_strv(new_flags, DEVICE_STATUS_FLAGS_TYPE);
  514. g_assert(g_strv_length(flags_strv) > 0);
  515. flags_str = g_english_strjoinv(flags_strv, "and");
  516. g_debug("Device %s setting status flag(s): %s", device_name, flags_str);
  517. amfree(flags_str);
  518. g_strfreev(flags_strv);
  519. }
  520. self->status = new_flags;
  521. }
  522. char * device_build_amanda_header(Device * self, const dumpfile_t * info,
  523. size_t *size) {
  524. return build_header(info, size, self->block_size);
  525. }
  526. dumpfile_t * make_tapestart_header(Device * self, char * label,
  527. char * timestamp) {
  528. dumpfile_t * rval;
  529. GValue val;
  530. bzero(&val, sizeof(val));
  531. g_assert(label != NULL);
  532. rval = malloc(sizeof(*rval));
  533. fh_init(rval);
  534. rval->type = F_TAPESTART;
  535. if (device_property_get(self, PROPERTY_BLOCK_SIZE, &val)) {
  536. rval->blocksize = g_value_get_int(&val);
  537. g_value_unset(&val);
  538. }
  539. amfree(self->volume_time);
  540. if (get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
  541. self->volume_time = get_proper_stamp_from_time(time(NULL));
  542. } else {
  543. self->volume_time = g_strdup(timestamp);
  544. }
  545. strncpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp));
  546. strncpy(rval->name, label, sizeof(rval->name));
  547. return rval;
  548. }
  549. dumpfile_t * make_tapeend_header(void) {
  550. dumpfile_t * rval;
  551. char * timestamp;
  552. rval = malloc(sizeof(*rval));
  553. rval->type = F_TAPEEND;
  554. timestamp = get_timestamp_from_time(time(NULL));
  555. strncpy(rval->datestamp, timestamp, sizeof(rval->datestamp));
  556. amfree(timestamp);
  557. return rval;
  558. }
  559. /* Try setting the blocksize on a device. Check results, fallback, and
  560. * set error status for problems. */
  561. static gboolean
  562. try_set_blocksize(Device * device, guint blocksize) {
  563. GValue val;
  564. gboolean success;
  565. bzero(&val, sizeof(val));
  566. g_value_init(&val, G_TYPE_INT);
  567. g_value_set_int(&val, blocksize);
  568. success = device_property_set(device, PROPERTY_BLOCK_SIZE, &val);
  569. g_value_unset(&val);
  570. if (!success) {
  571. device_set_error(device,
  572. vstrallocf(_("Setting BLOCK_SIZE to %u "
  573. "not supported for device %s.\n"),
  574. blocksize, device->device_name),
  575. DEVICE_STATUS_DEVICE_ERROR);
  576. }
  577. return success;
  578. }
  579. /* A GHFunc (callback for g_hash_table_foreach) */
  580. static void set_device_property(gpointer key_p, gpointer value_p,
  581. gpointer user_data_p) {
  582. char * property_s = key_p;
  583. property_t * property = value_p;
  584. Device * device = user_data_p;
  585. const DevicePropertyBase* property_base;
  586. GValue property_value;
  587. char * value;
  588. g_return_if_fail(IS_DEVICE(device));
  589. g_return_if_fail(property_s != NULL);
  590. g_return_if_fail(property != NULL);
  591. g_return_if_fail(property->values != NULL);
  592. /* don't continue beating on a device that's already erroring */
  593. if (device_in_error(device)) return;
  594. property_base = device_property_get_by_name(property_s);
  595. if (property_base == NULL) {
  596. /* Nonexistant property name. */
  597. device_set_error(device,
  598. vstrallocf(_("unknown device property name '%s'"), property_s),
  599. DEVICE_STATUS_DEVICE_ERROR);
  600. return;
  601. }
  602. if (g_slist_length(property->values) > 1) {
  603. device_set_error(device,
  604. vstrallocf(_("multiple values for device property '%s'"), property_s),
  605. DEVICE_STATUS_DEVICE_ERROR);
  606. return;
  607. }
  608. bzero(&property_value, sizeof(property_value));
  609. g_value_init(&property_value, property_base->type);
  610. value = property->values->data;
  611. if (!g_value_set_from_string(&property_value, value)) {
  612. /* Value type could not be interpreted. */
  613. device_set_error(device,
  614. vstrallocf(_("Could not parse property value '%s' for property '%s' (property type %s)"),
  615. value, property_base->name, g_type_name(property_base->type)),
  616. DEVICE_STATUS_DEVICE_ERROR);
  617. return;
  618. } else {
  619. g_assert (G_VALUE_HOLDS(&property_value, property_base->type));
  620. }
  621. if (!device_property_set(device, property_base->ID, &property_value)) {
  622. /* Device rejects property. */
  623. if (!device_in_error(device)) {
  624. device_set_error(device,
  625. vstrallocf(_("Could not set property '%s' to '%s' on %s"),
  626. property_base->name, value, device->device_name),
  627. DEVICE_STATUS_DEVICE_ERROR);
  628. }
  629. return;
  630. }
  631. }
  632. /* Set up properties based on various taper-related configuration parameters
  633. * and from the tapetype.
  634. */
  635. static void
  636. set_properties_from_global_config(Device * device) {
  637. char * tapetype_name = getconf_str(CNF_TAPETYPE);
  638. if (tapetype_name != NULL) {
  639. tapetype_t * tapetype = lookup_tapetype(tapetype_name);
  640. if (tapetype != NULL) {
  641. GValue val;
  642. guint64 length;
  643. guint blocksize_kb;
  644. gboolean success;
  645. bzero(&val, sizeof(GValue));
  646. if (tapetype_seen(tapetype, TAPETYPE_LENGTH)) {
  647. length = tapetype_get_length(tapetype);
  648. g_value_init(&val, G_TYPE_UINT64);
  649. g_value_set_uint64(&val, length * 1024);
  650. /* If this fails, it's not really an error. */
  651. device_property_set(device, PROPERTY_MAX_VOLUME_USAGE, &val);
  652. g_value_unset(&val);
  653. }
  654. if (tapetype_seen(tapetype, TAPETYPE_READBLOCKSIZE)) {
  655. blocksize_kb = tapetype_get_readblocksize(tapetype);
  656. g_value_init(&val, G_TYPE_UINT);
  657. g_value_set_uint(&val, blocksize_kb * 1024);
  658. success = device_property_set(device,
  659. PROPERTY_READ_BLOCK_SIZE,
  660. &val);
  661. g_value_unset(&val);
  662. if (!success) {
  663. /* a non-fatal error */
  664. g_warning("Setting READ_BLOCK_SIZE to %ju not supported for device %s.",
  665. 1024*(uintmax_t)blocksize_kb, device->device_name);
  666. }
  667. }
  668. if (tapetype_seen(tapetype, TAPETYPE_BLOCKSIZE)) {
  669. blocksize_kb = tapetype_get_blocksize(tapetype);
  670. /* TODO: handle errors */
  671. (void)try_set_blocksize(device, blocksize_kb * 1024);
  672. }
  673. }
  674. }
  675. g_hash_table_foreach(getconf_proplist(CNF_DEVICE_PROPERTY),
  676. set_device_property, device);
  677. }
  678. /* Set properties specified within a device definition */
  679. static void
  680. set_properties_from_device_config(Device * device, device_config_t *dc) {
  681. g_hash_table_foreach(device_config_get_property(dc),
  682. set_device_property, device);
  683. }
  684. static gboolean
  685. default_device_configure(Device *self, gboolean use_global_config)
  686. {
  687. device_config_t *dc;
  688. if (device_in_error(self))
  689. return FALSE;
  690. if (use_global_config)
  691. set_properties_from_global_config(self);
  692. if (device_in_error(self))
  693. return FALSE;
  694. if ((dc = lookup_device_config(self->device_name)))
  695. set_properties_from_device_config(self, dc);
  696. return !device_in_error(self);
  697. }
  698. void device_clear_volume_details(Device * device) {
  699. if (device == NULL || device->access_mode != ACCESS_NULL) {
  700. return;
  701. }
  702. amfree(device->volume_label);
  703. amfree(device->volume_time);
  704. }
  705. /* Here we put default implementations of virtual functions. Since
  706. this class is virtual, many of these functions offer at best
  707. incomplete functionality. But they do offer the useful commonality
  708. that all devices can expect to need. */
  709. static void default_device_open_device(Device * self, char * device_name,
  710. char * device_type G_GNUC_UNUSED, char * device_node G_GNUC_UNUSED) {
  711. /* Set the device_name property */
  712. self->device_name = stralloc(device_name);
  713. }
  714. static gboolean
  715. property_get_block_size_fn(
  716. Device *self,
  717. DevicePropertyBase *base G_GNUC_UNUSED,
  718. GValue *val,
  719. PropertySurety *surety,
  720. PropertySource *source)
  721. {
  722. g_value_unset_init(val, G_TYPE_INT);
  723. g_assert(self->block_size < G_MAXINT); /* gsize -> gint */
  724. g_value_set_int(val, (gint)self->block_size);
  725. if (surety)
  726. *surety = self->block_size_surety;
  727. if (source)
  728. *source = self->block_size_source;
  729. return TRUE;
  730. }
  731. static gboolean
  732. property_set_block_size_fn(
  733. Device *self,
  734. DevicePropertyBase *base G_GNUC_UNUSED,
  735. GValue *val,
  736. PropertySurety surety,
  737. PropertySource source)
  738. {
  739. gint block_size = g_value_get_int(val);
  740. g_assert(block_size >= 0); /* int -> gsize (unsigned) */
  741. if ((gsize)block_size < self->min_block_size
  742. || (gsize)block_size > self->max_block_size)
  743. return FALSE;
  744. self->block_size = block_size;
  745. self->block_size_surety = surety;
  746. self->block_size_source = source;
  747. return TRUE;
  748. }
  749. static gboolean
  750. property_get_min_block_size_fn(
  751. Device *self,
  752. DevicePropertyBase *base G_GNUC_UNUSED,
  753. GValue *val,
  754. PropertySurety *surety,
  755. PropertySource *source)
  756. {
  757. g_value_unset_init(val, G_TYPE_UINT);
  758. g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
  759. g_value_set_uint(val, (guint)self->min_block_size);
  760. if (surety)
  761. *surety = PROPERTY_SURETY_GOOD;
  762. if (source)
  763. *source = PROPERTY_SOURCE_DEFAULT;
  764. return TRUE;
  765. }
  766. static gboolean
  767. property_get_max_block_size_fn(
  768. Device *self,
  769. DevicePropertyBase *base G_GNUC_UNUSED,
  770. GValue *val,
  771. PropertySurety *surety,
  772. PropertySource *source)
  773. {
  774. g_value_unset_init(val, G_TYPE_UINT);
  775. g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
  776. g_value_set_uint(val, (guint)self->max_block_size);
  777. if (surety)
  778. *surety = PROPERTY_SURETY_GOOD;
  779. if (source)
  780. *source = PROPERTY_SOURCE_DEFAULT;
  781. return TRUE;
  782. }
  783. static gboolean
  784. property_get_canonical_name_fn(
  785. Device *self,
  786. DevicePropertyBase *base G_GNUC_UNUSED,
  787. GValue *val,
  788. PropertySurety *surety,
  789. PropertySource *source)
  790. {
  791. g_value_unset_init(val, G_TYPE_STRING);
  792. g_value_set_string(val, self->device_name);
  793. if (surety)
  794. *surety = PROPERTY_SURETY_GOOD;
  795. if (source)
  796. *source = PROPERTY_SOURCE_DEFAULT;
  797. return TRUE;
  798. }
  799. /* util function */
  800. static PropertyPhaseFlags
  801. state_to_phase(
  802. Device *self)
  803. {
  804. if (self->access_mode == ACCESS_NULL) {
  805. return PROPERTY_PHASE_BEFORE_START;
  806. } else if (IS_WRITABLE_ACCESS_MODE(self->access_mode)) {
  807. if (self->in_file) {
  808. return PROPERTY_PHASE_INSIDE_FILE_WRITE;
  809. } else {
  810. return PROPERTY_PHASE_BETWEEN_FILE_WRITE;
  811. }
  812. } else { /* read mode */
  813. if (self->in_file) {
  814. return PROPERTY_PHASE_INSIDE_FILE_READ;
  815. } else {
  816. return PROPERTY_PHASE_BETWEEN_FILE_READ;
  817. }
  818. }
  819. }
  820. /* This default implementation serves up static responses, and
  821. implements a few default responses based on values from the Device
  822. struct. */
  823. static gboolean
  824. default_device_property_get_ex(
  825. Device * self,
  826. DevicePropertyId id,
  827. GValue * val,
  828. PropertySurety *surety,
  829. PropertySource *source)
  830. {
  831. DeviceProperty *prop;
  832. GArray *class_properties;
  833. PropertyPhaseFlags cur_phase;
  834. /* Most of this function's job is to sanity-check everything, then
  835. * call the relevant getter. */
  836. class_properties = DEVICE_GET_CLASS(self)->class_properties;
  837. if (id >= class_properties->len)
  838. return FALSE;
  839. prop = &g_array_index(class_properties, DeviceProperty, id);
  840. if (prop->base == NULL)
  841. return FALSE;
  842. if (val || surety || source) {
  843. /* check the phase */
  844. cur_phase = state_to_phase(self);
  845. if (!(prop->access & cur_phase))
  846. return FALSE;
  847. if (prop->getter == NULL)
  848. return FALSE;
  849. if (!prop->getter(self, prop->base, val, surety, source))
  850. return FALSE;
  851. }
  852. return TRUE;
  853. }
  854. static gboolean
  855. default_device_property_set_ex(
  856. Device *self,
  857. DevicePropertyId id,
  858. GValue * val,
  859. PropertySurety surety,
  860. PropertySource source)
  861. {
  862. DeviceProperty *prop;
  863. GArray *class_properties;
  864. PropertyPhaseFlags cur_phase;
  865. /* Most of this function's job is to sanity-check everything, then
  866. * call the relevant setter. */
  867. if (device_in_error(self))
  868. return FALSE;
  869. class_properties = DEVICE_GET_CLASS(self)->class_properties;
  870. if (id >= class_properties->len)
  871. return FALSE;
  872. prop = &g_array_index(class_properties, DeviceProperty, id);
  873. if (prop->base == NULL)
  874. return FALSE;
  875. /* check that the type matches */
  876. if (!G_VALUE_HOLDS(val, prop->base->type))
  877. return FALSE;
  878. /* check the phase */
  879. cur_phase = state_to_phase(self) << PROPERTY_PHASE_SHIFT;
  880. if (!(prop->access & cur_phase))
  881. return FALSE;
  882. if (prop->setter == NULL)
  883. return FALSE;
  884. if (!prop->setter(self, prop->base, val, surety, source))
  885. return FALSE;
  886. return TRUE;
  887. }
  888. const GSList *
  889. device_property_get_list (Device * self)
  890. {
  891. g_assert(IS_DEVICE(self));
  892. return DEVICE_GET_CLASS(self)->class_properties_list;
  893. }
  894. /* XXX WARNING XXX
  895. * All the functions below this comment are stub functions that do nothing
  896. * but implement the virtual function table. Call these functions and they
  897. * will do what you expect vis-a-vis virtual functions. But don't put code
  898. * in them beyond error checking and VFT lookup. */
  899. void
  900. device_open_device (Device * self, char * device_name,
  901. char * device_type, char * device_node)
  902. {
  903. DeviceClass *klass;
  904. g_assert(IS_DEVICE(self));
  905. g_assert(device_name != NULL);
  906. klass = DEVICE_GET_CLASS(self);
  907. g_assert(klass->open_device);
  908. (klass->open_device)(self, device_name, device_type, device_node);
  909. }
  910. DeviceStatusFlags device_read_label(Device * self) {
  911. DeviceClass * klass;
  912. g_assert(self != NULL);
  913. g_assert(IS_DEVICE(self));
  914. g_assert(self->access_mode == ACCESS_NULL);
  915. klass = DEVICE_GET_CLASS(self);
  916. g_assert(klass->read_label);
  917. return (klass->read_label)(self);
  918. }
  919. gboolean
  920. device_finish (Device * self) {
  921. DeviceClass *klass;
  922. g_assert(IS_DEVICE (self));
  923. klass = DEVICE_GET_CLASS(self);
  924. g_assert(klass->finish);
  925. return (klass->finish)(self);
  926. }
  927. gboolean
  928. device_configure (Device * self, gboolean use_global_config)
  929. {
  930. DeviceClass *klass;
  931. g_assert(IS_DEVICE (self));
  932. g_assert(self->access_mode == ACCESS_NULL);
  933. klass = DEVICE_GET_CLASS(self);
  934. if(klass->configure) {
  935. return (klass->configure)(self, use_global_config);
  936. } else {
  937. device_set_error(self,
  938. stralloc(_("Unimplemented method")),
  939. DEVICE_STATUS_DEVICE_ERROR);
  940. return FALSE;
  941. }
  942. }
  943. gboolean
  944. device_start (Device * self, DeviceAccessMode mode,
  945. char * label, char * timestamp)
  946. {
  947. DeviceClass *klass;
  948. char * local_timestamp = NULL;
  949. gboolean rv;
  950. g_assert(IS_DEVICE (self));
  951. g_assert(mode != ACCESS_NULL);
  952. g_assert(mode != ACCESS_WRITE || label != NULL);
  953. klass = DEVICE_GET_CLASS(self);
  954. g_assert(klass->start);
  955. /* For a good combination of synchronization and public simplicity,
  956. this stub function does not require a timestamp, but the actual
  957. implementation function does. We generate the timestamp here with
  958. time(). */
  959. if (mode == ACCESS_WRITE &&
  960. get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
  961. local_timestamp = timestamp =
  962. get_proper_stamp_from_time(time(NULL));
  963. }
  964. rv = (klass->start)(self, mode, label, timestamp);
  965. amfree(local_timestamp);
  966. return rv;
  967. }
  968. gboolean
  969. device_write_block (Device * self, guint size, gpointer block)
  970. {
  971. DeviceClass *klass;
  972. g_assert(IS_DEVICE (self));
  973. g_assert(size > 0);
  974. /* these are all things that the caller should take care to
  975. * guarantee, so we just assert them here */
  976. g_assert(size <= self->block_size);
  977. g_assert(self->in_file);
  978. g_assert(!selfp->wrote_short_block);
  979. g_assert(block != NULL);
  980. g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
  981. if (size < self->block_size)
  982. selfp->wrote_short_block = TRUE;
  983. klass = DEVICE_GET_CLASS(self);
  984. g_assert(klass->write_block);
  985. return (*klass->write_block)(self,size, block);
  986. }
  987. gboolean
  988. device_start_file (Device * self, dumpfile_t * jobInfo) {
  989. DeviceClass * klass;
  990. g_assert(IS_DEVICE (self));
  991. g_assert(!(self->in_file));
  992. g_assert(jobInfo != NULL);
  993. selfp->wrote_short_block = FALSE;
  994. klass = DEVICE_GET_CLASS(self);
  995. g_assert(klass->start_file);
  996. return (klass->start_file)(self, jobInfo );
  997. }
  998. gboolean
  999. device_finish_file (Device * self)
  1000. {
  1001. DeviceClass *klass;
  1002. g_assert(IS_DEVICE (self));
  1003. g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
  1004. g_assert(self->in_file);
  1005. klass = DEVICE_GET_CLASS(self);
  1006. g_assert(klass->finish_file);
  1007. return (klass->finish_file)(self);
  1008. }
  1009. dumpfile_t*
  1010. device_seek_file (Device * self, guint file)
  1011. {
  1012. DeviceClass *klass;
  1013. g_assert(IS_DEVICE (self));
  1014. g_assert(self->access_mode == ACCESS_READ);
  1015. klass = DEVICE_GET_CLASS(self);
  1016. g_assert(klass->seek_file);
  1017. return (klass->seek_file)(self,file);
  1018. }
  1019. gboolean
  1020. device_seek_block (Device * self, guint64 block)
  1021. {
  1022. DeviceClass *klass;
  1023. g_assert(IS_DEVICE (self));
  1024. g_assert(self->access_mode == ACCESS_READ);
  1025. g_assert(self->in_file);
  1026. klass = DEVICE_GET_CLASS(self);
  1027. g_assert(klass->seek_block);
  1028. return (klass->seek_block)(self,block);
  1029. }
  1030. int
  1031. device_read_block (Device * self, gpointer buffer, int * size)
  1032. {
  1033. DeviceClass *klass;
  1034. g_assert(IS_DEVICE (self));
  1035. g_assert(size != NULL);
  1036. g_assert(self->access_mode == ACCESS_READ);
  1037. if (*size != 0) {
  1038. g_assert(buffer != NULL);
  1039. }
  1040. klass = DEVICE_GET_CLASS(self);
  1041. g_assert(klass->read_block);
  1042. return (klass->read_block)(self,buffer,size);
  1043. }
  1044. gboolean
  1045. device_property_get_ex(
  1046. Device * self,
  1047. DevicePropertyId id,
  1048. GValue * val,
  1049. PropertySurety *surety,
  1050. PropertySource *source)
  1051. {
  1052. DeviceClass *klass;
  1053. g_assert(IS_DEVICE (self));
  1054. g_assert(device_property_get_by_id(id) != NULL);
  1055. klass = DEVICE_GET_CLASS(self);
  1056. g_assert(klass->property_get_ex);
  1057. return (klass->property_get_ex)(self, id, val, surety, source);
  1058. }
  1059. gboolean
  1060. device_property_set_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. klass = DEVICE_GET_CLASS(self);
  1070. g_assert(klass->property_set_ex);
  1071. return (klass->property_set_ex)(self, id, val, surety, source);
  1072. }
  1073. gboolean
  1074. device_recycle_file (Device * self, guint filenum)
  1075. {
  1076. DeviceClass *klass;
  1077. g_assert(self != NULL);
  1078. g_assert(IS_DEVICE (self));
  1079. g_assert(self->access_mode == ACCESS_APPEND);
  1080. g_assert(!self->in_file);
  1081. klass = DEVICE_GET_CLASS(self);
  1082. g_assert(klass->recycle_file);
  1083. return (klass->recycle_file)(self,filenum);
  1084. }
  1085. gboolean
  1086. device_erase (Device * self)
  1087. {
  1088. DeviceClass *klass;
  1089. g_assert(IS_DEVICE (self));
  1090. g_assert(self->access_mode == ACCESS_NULL);
  1091. g_assert(!self->in_file);
  1092. klass = DEVICE_GET_CLASS(self);
  1093. if(klass->erase) {
  1094. return (klass->erase)(self);
  1095. } else {
  1096. device_set_error(self,
  1097. stralloc(_("Unimplemented method")),
  1098. DEVICE_STATUS_DEVICE_ERROR);
  1099. return FALSE;
  1100. }
  1101. }
  1102. gboolean
  1103. device_eject (Device * self)
  1104. {
  1105. DeviceClass *klass;
  1106. g_assert(IS_DEVICE (self));
  1107. g_assert(self->access_mode == ACCESS_NULL);
  1108. g_assert(!self->in_file);
  1109. klass = DEVICE_GET_CLASS(self);
  1110. if (klass->eject) {
  1111. return (klass->eject)(self);
  1112. } else {
  1113. return TRUE;
  1114. }
  1115. }
  1116. gboolean
  1117. device_listen(
  1118. Device *self,
  1119. gboolean for_writing,
  1120. DirectTCPAddr **addrs)
  1121. {
  1122. DeviceClass *klass;
  1123. klass = DEVICE_GET_CLASS(self);
  1124. if(klass->listen) {
  1125. return (klass->listen)(self, for_writing, addrs);
  1126. } else {
  1127. device_set_error(self,
  1128. stralloc(_("Unimplemented method")),
  1129. DEVICE_STATUS_DEVICE_ERROR);
  1130. return FALSE;
  1131. }
  1132. }
  1133. gboolean
  1134. device_accept(
  1135. Device *self,
  1136. DirectTCPConnection **conn,
  1137. ProlongProc prolong,
  1138. gpointer prolong_data)
  1139. {
  1140. DeviceClass *klass;
  1141. klass = DEVICE_GET_CLASS(self);
  1142. if(klass->accept) {
  1143. return (klass->accept)(self, conn, prolong, prolong_data);
  1144. } else {
  1145. device_set_error(self,
  1146. stralloc(_("Unimplemented method")),
  1147. DEVICE_STATUS_DEVICE_ERROR);
  1148. return FALSE;
  1149. }
  1150. }
  1151. gboolean
  1152. device_connect(
  1153. Device *self,
  1154. gboolean for_writing,
  1155. DirectTCPAddr *addrs,
  1156. DirectTCPConnection **conn,
  1157. ProlongProc prolong,
  1158. gpointer prolong_data)
  1159. {
  1160. DeviceClass *klass;
  1161. klass = DEVICE_GET_CLASS(self);
  1162. if(klass->connect) {
  1163. return (klass->connect)(self, for_writing, addrs, conn, prolong, prolong_data);
  1164. } else {
  1165. device_set_error(self,
  1166. stralloc(_("Unimplemented method")),
  1167. DEVICE_STATUS_DEVICE_ERROR);
  1168. return FALSE;
  1169. }
  1170. }
  1171. gboolean
  1172. device_write_from_connection(
  1173. Device *self,
  1174. guint64 size,
  1175. guint64 *actual_size)
  1176. {
  1177. DeviceClass *klass;
  1178. klass = DEVICE_GET_CLASS(self);
  1179. g_assert(self->in_file);
  1180. g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
  1181. if(klass->write_from_connection) {
  1182. return (klass->write_from_connection)(self, size, actual_size);
  1183. } else {
  1184. device_set_error(self,
  1185. stralloc(_("Unimplemented method")),
  1186. DEVICE_STATUS_DEVICE_ERROR);
  1187. return FALSE;
  1188. }
  1189. }
  1190. gboolean
  1191. device_read_to_connection(
  1192. Device *self,
  1193. guint64 size,
  1194. guint64 *actual_size)
  1195. {
  1196. DeviceClass *klass;
  1197. g_assert(self->in_file);
  1198. g_assert(self->access_mode == ACCESS_READ);
  1199. klass = DEVICE_GET_CLASS(self);
  1200. if(klass->read_to_connection) {
  1201. return (klass->read_to_connection)(self, size, actual_size);
  1202. } else {
  1203. device_set_error(self,
  1204. stralloc(_("Unimplemented method")),
  1205. DEVICE_STATUS_DEVICE_ERROR);
  1206. return FALSE;
  1207. }
  1208. }
  1209. gboolean
  1210. device_use_connection(
  1211. Device *self,
  1212. DirectTCPConnection *conn)
  1213. {
  1214. DeviceClass *klass;
  1215. g_assert(self->access_mode == ACCESS_NULL);
  1216. klass = DEVICE_GET_CLASS(self);
  1217. if(klass->use_connection) {
  1218. return (klass->use_connection)(self, conn);
  1219. } else {
  1220. device_set_error(self,
  1221. stralloc(_("Unimplemented method")),
  1222. DEVICE_STATUS_DEVICE_ERROR);
  1223. return FALSE;
  1224. }
  1225. }
  1226. /* Property handling */
  1227. void
  1228. device_class_register_property(
  1229. DeviceClass *klass,
  1230. DevicePropertyId id,
  1231. PropertyAccessFlags access,
  1232. PropertyGetFn getter,
  1233. PropertySetFn setter)
  1234. {
  1235. DevicePropertyBase *base;
  1236. DeviceProperty *prop;
  1237. GSList *proplist;
  1238. guint i;
  1239. g_assert(klass != NULL);
  1240. base = device_property_get_by_id(id);
  1241. g_assert(base != NULL);
  1242. if (klass->class_properties->len <= id) {
  1243. g_array_set_size(klass->class_properties, id+1);
  1244. }
  1245. prop = &g_array_index(klass->class_properties, DeviceProperty, id);
  1246. prop->base = base;
  1247. prop->access = access;
  1248. prop->getter = getter;
  1249. prop->setter = setter;
  1250. /* completely rewrite the list of prop pointers, as they may have changed,
  1251. * or we may have replaced an existing property*/
  1252. if (klass->class_properties_list) {
  1253. g_slist_free(klass->class_properties_list);
  1254. }
  1255. proplist = NULL;
  1256. for (i = 0; i < klass->class_properties->len; i++) {
  1257. prop = &g_array_index(klass->class_properties, DeviceProperty, i);
  1258. if (!prop->base)
  1259. continue;
  1260. proplist = g_slist_prepend(proplist, prop);
  1261. }
  1262. klass->class_properties_list = proplist;
  1263. }
  1264. gboolean
  1265. device_set_simple_property(
  1266. Device *self,
  1267. DevicePropertyId id,
  1268. GValue *val,
  1269. PropertySurety surety,
  1270. PropertySource source)
  1271. {
  1272. SimpleProperty *simp;
  1273. DeviceProperty *prop;
  1274. prop = &g_array_index(DEVICE_GET_CLASS(self)->class_properties,
  1275. DeviceProperty, id);
  1276. /* these assertions should already be checked, but let's be sure */
  1277. g_assert(prop->base != NULL); /* prop must be registered with device */
  1278. g_assert(G_VALUE_HOLDS(val, prop->base->type));
  1279. simp = g_new0(SimpleProperty, 1);
  1280. simp->prop = prop;
  1281. g_value_unset_copy(val, &(simp->response));
  1282. simp->surety = surety;
  1283. simp->source = source;
  1284. g_hash_table_insert(selfp->simple_properties,
  1285. GINT_TO_POINTER(id),
  1286. simp);
  1287. return TRUE;
  1288. }
  1289. gboolean
  1290. device_simple_property_set_fn(
  1291. Device *self,
  1292. DevicePropertyBase *base,
  1293. GValue *val,
  1294. PropertySurety surety,
  1295. PropertySource source)
  1296. {
  1297. return device_set_simple_property(self, base->ID, val, surety, source);
  1298. }
  1299. gboolean
  1300. device_get_simple_property(
  1301. Device *self,
  1302. DevicePropertyId id,
  1303. GValue *val,
  1304. PropertySurety *surety,
  1305. PropertySource *source)
  1306. {
  1307. SimpleProperty *simp =
  1308. g_hash_table_lookup(selfp->simple_properties,
  1309. GINT_TO_POINTER(id));
  1310. if (!simp)
  1311. return FALSE;
  1312. if (val)
  1313. g_value_unset_copy(&(simp->response), val);
  1314. if (surety)
  1315. *surety = simp->surety;
  1316. if (source)
  1317. *source = simp->source;
  1318. return TRUE;
  1319. }
  1320. gboolean
  1321. device_simple_property_get_fn(
  1322. Device *self,
  1323. DevicePropertyBase *base,
  1324. GValue *val,
  1325. PropertySurety *surety,
  1326. PropertySource *source)
  1327. {
  1328. return device_get_simple_property(self, base->ID, val, surety, source);
  1329. }