PageRenderTime 58ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/amanda/tags/amanda261p2/device-src/device.c

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