PageRenderTime 72ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

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

#
C | 1083 lines | 849 code | 161 blank | 73 comment | 154 complexity | f9c8bba4997afed988ab6c4a4ea39e80 MD5 | raw file
  1. /*
  2. * Copyright (c) 2005 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., 505 N Mathlida Ave, Suite 120
  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 "queueing.h"
  28. #include "property.h"
  29. #include "null-device.h"
  30. #include "timestamp.h"
  31. #include "vfs-device.h"
  32. #include "util.h"
  33. #ifdef WANT_TAPE_DEVICE
  34. #include "tape-device.h"
  35. #endif
  36. #include "rait-device.h"
  37. #ifdef WANT_S3_DEVICE
  38. #include "s3-device.h"
  39. #endif
  40. static GHashTable* driverList = NULL;
  41. void device_api_init(void) {
  42. g_type_init();
  43. amanda_thread_init();
  44. device_property_init();
  45. driverList = g_hash_table_new(g_str_hash, g_str_equal);
  46. /* register other types and devices. */
  47. null_device_register();
  48. vfs_device_register();
  49. #ifdef WANT_TAPE_DEVICE
  50. tape_device_register();
  51. #endif
  52. rait_device_register();
  53. #ifdef WANT_S3_DEVICE
  54. s3_device_register();
  55. #endif
  56. }
  57. void register_device(DeviceFactory factory,
  58. const char ** device_prefix_list) {
  59. char ** tmp;
  60. g_assert(driverList != NULL);
  61. g_assert(factory != NULL);
  62. g_return_if_fail(device_prefix_list != NULL);
  63. g_return_if_fail(*device_prefix_list != NULL);
  64. tmp = (char**)device_prefix_list;
  65. while (*tmp != NULL) {
  66. g_hash_table_insert(driverList, *tmp, (gpointer)factory);
  67. tmp ++;
  68. }
  69. }
  70. static DeviceFactory lookup_device_factory(const char *device_name) {
  71. gpointer key, value;
  72. g_assert(driverList != NULL);
  73. if (g_hash_table_lookup_extended(driverList, device_name, &key, &value)) {
  74. return (DeviceFactory)value;
  75. } else {
  76. return NULL;
  77. }
  78. }
  79. static const GFlagsValue read_label_status_flags_values[] = {
  80. { READ_LABEL_STATUS_SUCCESS,
  81. "READ_LABEL_STATUS_SUCCESS",
  82. "Success" },
  83. { READ_LABEL_STATUS_DEVICE_MISSING,
  84. "READ_LABEL_STATUS_DEVICE_MISSING",
  85. "Device not found" },
  86. { READ_LABEL_STATUS_DEVICE_ERROR,
  87. "READ_LABEL_STATUS_DEVICE_ERROR",
  88. "Device error" },
  89. { READ_LABEL_STATUS_VOLUME_MISSING,
  90. "READ_LABEL_STATUS_VOLUME_MISSING",
  91. "Volume not found" },
  92. { READ_LABEL_STATUS_VOLUME_UNLABELED,
  93. "READ_LABEL_STATUS_VOLUME_UNLABELED",
  94. "Volume not labeled" },
  95. { READ_LABEL_STATUS_VOLUME_ERROR,
  96. "READ_LABEL_STATUS_VOLUME_ERROR",
  97. "Volume error" },
  98. { 0, NULL, NULL }
  99. };
  100. GType read_label_status_flags_get_type(void) {
  101. static GType type = 0;
  102. if (G_UNLIKELY(type == 0)) {
  103. type = g_flags_register_static("ReadLabelStatusFlags",
  104. read_label_status_flags_values);
  105. }
  106. return type;
  107. }
  108. /* Device class definition starts here. */
  109. struct DevicePrivate_s {
  110. /* This is the return value of the device_get_property_list()
  111. method. */
  112. GArray *property_list;
  113. GHashTable * property_response;
  114. };
  115. /* This holds the default response to a particular property. */
  116. typedef struct {
  117. PropertyAccessFlags access;
  118. GValue response;
  119. } PropertyResponse;
  120. #define selfp (self->private)
  121. /* here are local prototypes, so we can make function pointers. */
  122. static void device_init (Device * o) G_GNUC_UNUSED;
  123. static void device_class_init (DeviceClass * c) G_GNUC_UNUSED;
  124. static void property_response_free(PropertyResponse *o);
  125. static gboolean default_device_open_device(Device * self, char * device_name);
  126. static gboolean default_device_finish(Device * self);
  127. static gboolean default_device_start(Device * self, DeviceAccessMode mode,
  128. char * label, char * timestamp);
  129. static gboolean default_device_start_file (Device * self,
  130. const dumpfile_t * jobinfo);
  131. static gboolean default_device_write_block (Device * self, guint size,
  132. gpointer data, gboolean last);
  133. static gboolean default_device_write_from_fd(Device *self, int fd);
  134. static gboolean default_device_finish_file (Device * self);
  135. static dumpfile_t* default_device_seek_file (Device * self, guint file);
  136. static gboolean default_device_seek_block (Device * self, guint64 block);
  137. static int default_device_read_block (Device * self, gpointer buffer,
  138. int * size);
  139. static gboolean default_device_read_to_fd(Device *self, int fd);
  140. static gboolean default_device_property_get(Device * self, DevicePropertyId ID,
  141. GValue * value);
  142. /* pointer to the class of our parent */
  143. static GObjectClass *parent_class = NULL;
  144. GType
  145. device_get_type (void)
  146. {
  147. static GType type = 0;
  148. if G_UNLIKELY(type == 0) {
  149. static const GTypeInfo info = {
  150. sizeof (DeviceClass),
  151. (GBaseInitFunc) NULL,
  152. (GBaseFinalizeFunc) NULL,
  153. (GClassInitFunc) device_class_init,
  154. (GClassFinalizeFunc) NULL,
  155. NULL /* class_data */,
  156. sizeof (Device),
  157. 0 /* n_preallocs */,
  158. (GInstanceInitFunc) device_init,
  159. NULL
  160. };
  161. type = g_type_register_static (G_TYPE_OBJECT, "Device", &info,
  162. (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
  163. }
  164. return type;
  165. }
  166. static void device_finalize(GObject *obj_self) {
  167. Device *self G_GNUC_UNUSED = DEVICE (obj_self);
  168. if(G_OBJECT_CLASS(parent_class)->finalize)
  169. (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
  170. /* Here we call device_finish() if it hasn't been done
  171. yet. Subclasses may need to do this same check earlier. */
  172. if (self->access_mode != ACCESS_NULL) {
  173. device_finish(self);
  174. }
  175. amfree(self->device_name);
  176. amfree(self->volume_label);
  177. amfree(self->volume_time);
  178. g_array_free(selfp->property_list, TRUE);
  179. g_hash_table_destroy(selfp->property_response);
  180. amfree(self->private);
  181. }
  182. static void
  183. device_init (Device * self G_GNUC_UNUSED)
  184. {
  185. self->private = malloc(sizeof(DevicePrivate));
  186. self->device_name = NULL;
  187. self->access_mode = ACCESS_NULL;
  188. self->is_eof = FALSE;
  189. self->file = -1;
  190. self->block = 0;
  191. self->in_file = FALSE;
  192. self->volume_label = NULL;
  193. self->volume_time = NULL;
  194. selfp->property_list = g_array_new(TRUE, FALSE, sizeof(DeviceProperty));
  195. selfp->property_response =
  196. g_hash_table_new_full(g_direct_hash,
  197. g_direct_equal,
  198. NULL,
  199. (GDestroyNotify) property_response_free);
  200. }
  201. static void
  202. device_class_init (DeviceClass * c G_GNUC_UNUSED)
  203. {
  204. GObjectClass *g_object_class G_GNUC_UNUSED = (GObjectClass*) c;
  205. parent_class = g_type_class_ref (G_TYPE_OBJECT);
  206. c->open_device = default_device_open_device;
  207. c->finish = default_device_finish;
  208. c->read_label = NULL;
  209. c->start = default_device_start;
  210. c->start_file = default_device_start_file;
  211. c->write_block = default_device_write_block;
  212. c->write_from_fd = default_device_write_from_fd;
  213. c->finish_file = default_device_finish_file;
  214. c->seek_file = default_device_seek_file;
  215. c->seek_block = default_device_seek_block;
  216. c->read_block = default_device_read_block;
  217. c->read_to_fd = default_device_read_to_fd;
  218. c->property_get = default_device_property_get;
  219. c->property_set = NULL;
  220. c->recycle_file = NULL;
  221. g_object_class->finalize = device_finalize;
  222. }
  223. static void property_response_free(PropertyResponse * resp) {
  224. g_value_unset(&(resp->response));
  225. amfree(resp);
  226. }
  227. static char *
  228. regex_message(int result, regex_t *regex) {
  229. char * rval;
  230. size_t size;
  231. size = regerror(result, regex, NULL, 0);
  232. rval = malloc(size);
  233. regerror(result, regex, rval, size);
  234. return rval;
  235. }
  236. static gboolean
  237. handle_device_regex(const char * user_name, char ** driver_name,
  238. char ** device) {
  239. regex_t regex;
  240. int reg_result;
  241. regmatch_t pmatch[3];
  242. static const char * regex_string = "^([a-z0-9]+):(.*)$";
  243. bzero(&regex, sizeof(regex));
  244. reg_result = regcomp(&regex, regex_string, REG_EXTENDED | REG_ICASE);
  245. if (reg_result != 0) {
  246. char * message = regex_message(reg_result, &regex);
  247. g_fprintf(stderr, "Error compiling regular expression \"%s\": %s\n",
  248. regex_string, message);
  249. amfree(message);
  250. return FALSE;
  251. }
  252. reg_result = regexec(&regex, user_name, 3, pmatch, 0);
  253. if (reg_result != 0 && reg_result != REG_NOMATCH) {
  254. char * message = regex_message(reg_result, &regex);
  255. g_fprintf(stderr, "Error applying regular expression \"%s\" to string \"%s\":\n"
  256. "%s\n", user_name, regex_string, message);
  257. regfree(&regex);
  258. return FALSE;
  259. } else if (reg_result == REG_NOMATCH) {
  260. #ifdef WANT_TAPE_DEVICE
  261. g_fprintf(stderr, "\"%s\" uses deprecated device naming convention; \n"
  262. "using \"tape:%s\" instead.\n",
  263. user_name, user_name);
  264. *driver_name = stralloc("tape");
  265. *device = stralloc(user_name);
  266. #else /* !WANT_TAPE_DEVICE */
  267. g_fprintf(stderr, "\"%s\" is not a valid device name.\n", user_name);
  268. regfree(&regex);
  269. return FALSE;
  270. #endif /* WANT_TAPE_DEVICE */
  271. } else {
  272. *driver_name = find_regex_substring(user_name, pmatch[1]);
  273. *device = find_regex_substring(user_name, pmatch[2]);
  274. }
  275. regfree(&regex);
  276. return TRUE;
  277. }
  278. Device*
  279. device_open (char * device_name)
  280. {
  281. char *device_driver_name = NULL;
  282. char *device_node_name = NULL;
  283. DeviceFactory factory;
  284. Device *device;
  285. g_return_val_if_fail (device_name != NULL, NULL);
  286. if (driverList == NULL) {
  287. g_log(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR,
  288. "device_open() called without device_api_init()!\n");
  289. g_assert_not_reached();
  290. }
  291. if (!handle_device_regex(device_name, &device_driver_name, &device_node_name)) {
  292. amfree(device_driver_name);
  293. amfree(device_node_name);
  294. return NULL;
  295. }
  296. factory = lookup_device_factory(device_driver_name);
  297. if (factory == NULL) {
  298. g_fprintf(stderr, "Device driver %s is not known.\n",
  299. device_driver_name);
  300. amfree(device_driver_name);
  301. amfree(device_node_name);
  302. return NULL;
  303. }
  304. device = factory(device_driver_name, device_node_name);
  305. amfree(device_driver_name);
  306. amfree(device_node_name);
  307. return device;
  308. }
  309. void
  310. device_add_property (Device * self, DeviceProperty * prop, GValue * response)
  311. {
  312. unsigned int i;
  313. g_return_if_fail (self != NULL);
  314. g_return_if_fail (IS_DEVICE (self));
  315. g_assert(selfp->property_list != NULL);
  316. g_assert(selfp->property_response != NULL);
  317. /* Delete it if it already exists. */
  318. for(i = 0; i < selfp->property_list->len; i ++) {
  319. if (g_array_index(selfp->property_list,
  320. DeviceProperty, i).base->ID == prop->base->ID) {
  321. g_array_remove_index_fast(selfp->property_list, i);
  322. break;
  323. }
  324. }
  325. g_array_append_val(selfp->property_list, *prop);
  326. if (response != NULL) {
  327. PropertyResponse * property_response;
  328. g_return_if_fail(G_IS_VALUE(response));
  329. property_response = malloc(sizeof(*property_response));
  330. property_response->access = prop->access;
  331. bzero(&(property_response->response),
  332. sizeof(property_response->response));
  333. g_value_init(&(property_response->response),
  334. G_VALUE_TYPE(response));
  335. g_value_copy(response, &(property_response->response));
  336. g_hash_table_insert(selfp->property_response,
  337. GINT_TO_POINTER(prop->base->ID),
  338. property_response);
  339. }
  340. }
  341. const DeviceProperty *
  342. device_property_get_list (Device * self)
  343. {
  344. g_return_val_if_fail (self != NULL, (const DeviceProperty * )0);
  345. g_return_val_if_fail (IS_DEVICE (self), (const DeviceProperty * )0);
  346. return (const DeviceProperty*) selfp->property_list->data;
  347. }
  348. guint device_write_min_size(Device * self) {
  349. GValue g_tmp;
  350. int block_size, min_block_size;
  351. bzero(&g_tmp, sizeof(g_tmp));
  352. device_property_get(self, PROPERTY_BLOCK_SIZE, &g_tmp);
  353. block_size = g_value_get_int(&g_tmp);
  354. g_value_unset(&g_tmp);
  355. if (block_size > 0) {
  356. return block_size;
  357. }
  358. /* variable block size */
  359. device_property_get(self, PROPERTY_MIN_BLOCK_SIZE, &g_tmp);
  360. min_block_size = g_value_get_uint(&g_tmp);
  361. g_value_unset(&g_tmp);
  362. return min_block_size;
  363. }
  364. guint device_write_max_size(Device * self) {
  365. GValue g_tmp;
  366. int block_size, max_block_size;
  367. bzero(&g_tmp, sizeof(g_tmp));
  368. device_property_get(self, PROPERTY_BLOCK_SIZE, &g_tmp);
  369. block_size = g_value_get_int(&g_tmp);
  370. g_value_unset(&g_tmp);
  371. if (block_size > 0) {
  372. return block_size;
  373. }
  374. /* variable block size */
  375. device_property_get(self, PROPERTY_MAX_BLOCK_SIZE, &g_tmp);
  376. max_block_size = g_value_get_uint(&g_tmp);
  377. g_value_unset(&g_tmp);
  378. return max_block_size;
  379. }
  380. guint device_read_max_size(Device * self) {
  381. GValue g_tmp;
  382. bzero(&g_tmp, sizeof(g_tmp));
  383. if (device_property_get(self, PROPERTY_READ_BUFFER_SIZE, &g_tmp)) {
  384. guint rval = g_value_get_uint(&g_tmp);
  385. g_value_unset(&g_tmp);
  386. return rval;
  387. } else {
  388. return device_write_max_size(self);
  389. }
  390. }
  391. char * device_build_amanda_header(Device * self, const dumpfile_t * info,
  392. int * size, gboolean * oneblock) {
  393. char *amanda_header;
  394. unsigned int min_header_length;
  395. unsigned int header_buffer_size;
  396. min_header_length = device_write_min_size(self);
  397. amanda_header = build_header(info, min_header_length);
  398. header_buffer_size = MAX(min_header_length, strlen(amanda_header)+1);
  399. if (size != NULL)
  400. *size = header_buffer_size;
  401. if (oneblock != NULL)
  402. *oneblock = (header_buffer_size <= device_write_max_size(self));
  403. return amanda_header;
  404. }
  405. dumpfile_t * make_tapestart_header(Device * self, char * label,
  406. char * timestamp) {
  407. dumpfile_t * rval;
  408. g_return_val_if_fail(label != NULL, NULL);
  409. rval = malloc(sizeof(*rval));
  410. fh_init(rval);
  411. rval->type = F_TAPESTART;
  412. amfree(self->volume_time);
  413. if (get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
  414. self->volume_time = get_proper_stamp_from_time(time(NULL));
  415. } else {
  416. self->volume_time = g_strdup(timestamp);
  417. }
  418. strncpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp));
  419. strncpy(rval->name, label, sizeof(rval->name));
  420. return rval;
  421. }
  422. dumpfile_t * make_tapeend_header(void) {
  423. dumpfile_t * rval;
  424. char * timestamp;
  425. rval = malloc(sizeof(*rval));
  426. rval->type = F_TAPEEND;
  427. timestamp = get_timestamp_from_time(time(NULL));
  428. strncpy(rval->datestamp, timestamp, sizeof(rval->datestamp));
  429. amfree(timestamp);
  430. return rval;
  431. }
  432. /* Try setting max/fixed blocksize on a device. Check results, fallback, and
  433. * print messages for problems. */
  434. static void try_set_blocksize(Device * device, guint blocksize,
  435. gboolean try_max_first) {
  436. GValue val;
  437. gboolean success;
  438. bzero(&val, sizeof(val));
  439. g_value_init(&val, G_TYPE_UINT);
  440. g_value_set_uint(&val, blocksize);
  441. if (try_max_first) {
  442. success = device_property_set(device,
  443. PROPERTY_MAX_BLOCK_SIZE,
  444. &val);
  445. if (!success) {
  446. g_fprintf(stderr, "Setting MAX_BLOCK_SIZE to %u "
  447. "not supported for device %s.\n"
  448. "trying BLOCK_SIZE instead.\n",
  449. blocksize, device->device_name);
  450. } else {
  451. g_value_unset(&val);
  452. return;
  453. }
  454. }
  455. g_value_unset(&val);
  456. g_value_init(&val, G_TYPE_INT);
  457. g_value_set_int(&val, blocksize);
  458. success = device_property_set(device,
  459. PROPERTY_BLOCK_SIZE,
  460. &val);
  461. if (!success) {
  462. g_fprintf(stderr, "Setting BLOCK_SIZE to %u "
  463. "not supported for device %s.\n",
  464. blocksize, device->device_name);
  465. }
  466. g_value_unset(&val);
  467. }
  468. /* A GHFunc (callback for g_hash_table_foreach) */
  469. static void set_device_property(gpointer key_p, gpointer value_p,
  470. gpointer user_data_p) {
  471. char * property_s = key_p;
  472. char * value_s = value_p;
  473. Device * device = user_data_p;
  474. const DevicePropertyBase* property_base;
  475. GValue property_value;
  476. g_return_if_fail(IS_DEVICE(device));
  477. g_return_if_fail(property_s != NULL);
  478. g_return_if_fail(value_s != NULL);
  479. property_base = device_property_get_by_name(property_s);
  480. if (property_base == NULL) {
  481. /* Nonexistant property name. */
  482. g_fprintf(stderr, _("Unknown device property name %s.\n"), property_s);
  483. return;
  484. }
  485. bzero(&property_value, sizeof(property_value));
  486. g_value_init(&property_value, property_base->type);
  487. if (!g_value_set_from_string(&property_value, value_s)) {
  488. /* Value type could not be interpreted. */
  489. g_fprintf(stderr,
  490. _("Could not parse property value %s for property type %s.\n"),
  491. value_s, g_type_name(property_base->type));
  492. return;
  493. } else {
  494. g_assert (G_VALUE_HOLDS(&property_value, property_base->type));
  495. }
  496. if (!device_property_set(device, property_base->ID, &property_value)) {
  497. /* Device rejects property. */
  498. g_fprintf(stderr, _("Could not set property %s to %s on device %s.\n"),
  499. property_base->name, value_s, device->device_name);
  500. return;
  501. }
  502. }
  503. /* Set up first-run properties, including DEVICE_MAX_VOLUME_USAGE property
  504. * based on the tapetype. */
  505. void device_set_startup_properties_from_config(Device * device) {
  506. char * tapetype_name = getconf_str(CNF_TAPETYPE);
  507. if (tapetype_name != NULL) {
  508. tapetype_t * tapetype = lookup_tapetype(tapetype_name);
  509. if (tapetype != NULL) {
  510. GValue val;
  511. guint64 length;
  512. guint blocksize_kb;
  513. gboolean success;
  514. bzero(&val, sizeof(GValue));
  515. if (tapetype_seen(tapetype, TAPETYPE_LENGTH)) {
  516. length = tapetype_get_length(tapetype);
  517. g_value_init(&val, G_TYPE_UINT64);
  518. g_value_set_uint64(&val, length * 1024);
  519. /* If this fails, it's not really an error. */
  520. device_property_set(device, PROPERTY_MAX_VOLUME_USAGE, &val);
  521. g_value_unset(&val);
  522. }
  523. if (tapetype_seen(tapetype, TAPETYPE_READBLOCKSIZE)) {
  524. blocksize_kb = tapetype_get_readblocksize(tapetype);
  525. g_value_init(&val, G_TYPE_UINT);
  526. g_value_set_uint(&val, blocksize_kb * 1024);
  527. success = device_property_set(device,
  528. PROPERTY_READ_BUFFER_SIZE,
  529. &val);
  530. g_value_unset(&val);
  531. if (!success) {
  532. g_fprintf(stderr, "Setting READ_BUFFER_SIZE to %llu "
  533. "not supported for device %s.\n",
  534. 1024*(long long unsigned int)blocksize_kb,
  535. device->device_name);
  536. }
  537. }
  538. if (tapetype_seen(tapetype, TAPETYPE_BLOCKSIZE)) {
  539. blocksize_kb = tapetype_get_blocksize(tapetype);
  540. try_set_blocksize(device, blocksize_kb * 1024,
  541. !tapetype_get_file_pad(tapetype));
  542. }
  543. }
  544. }
  545. g_hash_table_foreach(getconf_proplist(CNF_DEVICE_PROPERTY),
  546. set_device_property, device);
  547. }
  548. void device_clear_volume_details(Device * device) {
  549. if (device == NULL || device->access_mode != ACCESS_NULL) {
  550. return;
  551. }
  552. amfree(device->volume_label);
  553. amfree(device->volume_time);
  554. }
  555. /* Here we put default implementations of virtual functions. Since
  556. this class is virtual, many of these functions offer at best
  557. incomplete functionality. But they do offer the useful commonality
  558. that all devices can expect to need. */
  559. /* This function only updates access_mode, volume_label, and volume_time. */
  560. static gboolean
  561. default_device_start (Device * self, DeviceAccessMode mode, char * label,
  562. char * timestamp) {
  563. if (mode != ACCESS_WRITE && self->volume_label == NULL) {
  564. if (device_read_label(self) != READ_LABEL_STATUS_SUCCESS)
  565. return FALSE;
  566. } else if (mode == ACCESS_WRITE) {
  567. self->volume_label = newstralloc(self->volume_label, label);
  568. self->volume_time = newstralloc(self->volume_time, timestamp);
  569. }
  570. self->access_mode = mode;
  571. return TRUE;
  572. }
  573. static gboolean default_device_open_device(Device * self,
  574. char * device_name) {
  575. DeviceProperty prop;
  576. guint i;
  577. self->device_name = stralloc(device_name);
  578. prop.base = &device_property_canonical_name;
  579. prop.access = PROPERTY_ACCESS_GET_MASK;
  580. for(i = 0; i < selfp->property_list->len; i ++) {
  581. if (g_array_index(selfp->property_list,
  582. DeviceProperty, i).base->ID == prop.base->ID) {
  583. return TRUE;
  584. }
  585. }
  586. /* If we got here, the property was not registered. */
  587. device_add_property(self, &prop, NULL);
  588. return TRUE;
  589. }
  590. /* This default implementation does very little. */
  591. static gboolean
  592. default_device_finish (Device * self) {
  593. self->access_mode = ACCESS_NULL;
  594. return TRUE;
  595. }
  596. /* This function updates the file, in_file, and block attributes. */
  597. static gboolean
  598. default_device_start_file (Device * self,
  599. const dumpfile_t * jobInfo G_GNUC_UNUSED) {
  600. self->in_file = TRUE;
  601. if (self->file <= 0)
  602. self->file = 1;
  603. else
  604. self->file ++;
  605. self->block = 0;
  606. return TRUE;
  607. }
  608. /* This function lies: It updates the block number and maybe calls
  609. device_finish_file(), but returns FALSE. */
  610. static gboolean
  611. default_device_write_block(Device * self, guint size G_GNUC_UNUSED,
  612. gpointer data G_GNUC_UNUSED, gboolean last_block) {
  613. self->block ++;
  614. if (last_block)
  615. device_finish_file(self);
  616. return FALSE;
  617. }
  618. /* This function lies: It updates the block number, but returns
  619. -1. */
  620. static int
  621. default_device_read_block(Device * self, gpointer buf G_GNUC_UNUSED,
  622. int * size G_GNUC_UNUSED) {
  623. self->block ++;
  624. return -1;
  625. }
  626. /* This function just updates the in_file field. */
  627. static gboolean
  628. default_device_finish_file(Device * self) {
  629. self->in_file = FALSE;
  630. return TRUE;
  631. }
  632. /* This function just updates the file number. */
  633. static dumpfile_t *
  634. default_device_seek_file(Device * self, guint file) {
  635. self->in_file = TRUE;
  636. self->file = file;
  637. return NULL;
  638. }
  639. /* This function just updates the block number. */
  640. static gboolean
  641. default_device_seek_block(Device * self, guint64 block) {
  642. self->block = block;
  643. return TRUE;
  644. }
  645. /* This default implementation serves up static responses, and
  646. implements a default response to the "canonical name" property. */
  647. static gboolean
  648. default_device_property_get(Device * self, DevicePropertyId ID,
  649. GValue * value) {
  650. const PropertyResponse * resp;
  651. resp = (PropertyResponse*)g_hash_table_lookup(selfp->property_response,
  652. GINT_TO_POINTER(ID));
  653. if (resp == NULL) {
  654. if (ID == PROPERTY_CANONICAL_NAME) {
  655. g_value_unset_init(value, G_TYPE_STRING);
  656. g_value_set_string(value, self->device_name);
  657. return TRUE;
  658. } else {
  659. return FALSE;
  660. }
  661. }
  662. g_value_unset_copy(&resp->response, value);
  663. return TRUE;
  664. }
  665. static gboolean
  666. default_device_read_to_fd(Device *self, int fd) {
  667. return do_consumer_producer_queue(device_read_producer,
  668. self,
  669. fd_write_consumer,
  670. GINT_TO_POINTER(fd));
  671. }
  672. static gboolean
  673. default_device_write_from_fd(Device *self, int fd) {
  674. return do_consumer_producer_queue(fd_read_producer,
  675. GINT_TO_POINTER(fd),
  676. device_write_consumer,
  677. self);
  678. }
  679. /* XXX WARNING XXX
  680. * All the functions below this comment are stub functions that do nothing
  681. * but implement the virtual function table. Call these functions and they
  682. * will do what you expect vis-a-vis virtual functions. But don't put code
  683. * in them beyond error checking and VFT lookup. */
  684. gboolean
  685. device_open_device (Device * self, char * device_name)
  686. {
  687. DeviceClass *klass;
  688. g_return_val_if_fail (self != NULL, FALSE);
  689. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  690. g_return_val_if_fail (device_name != NULL, FALSE);
  691. klass = DEVICE_GET_CLASS(self);
  692. if(klass->open_device)
  693. return (*klass->open_device)(self,device_name);
  694. else
  695. return FALSE;
  696. }
  697. ReadLabelStatusFlags device_read_label(Device * self) {
  698. DeviceClass * klass;
  699. g_return_val_if_fail(self != NULL, FALSE);
  700. g_return_val_if_fail(IS_DEVICE(self), FALSE);
  701. g_return_val_if_fail(self->access_mode == ACCESS_NULL, FALSE);
  702. klass = DEVICE_GET_CLASS(self);
  703. if (klass->read_label) {
  704. return (klass->read_label)(self);
  705. } else {
  706. return ~ READ_LABEL_STATUS_SUCCESS;
  707. }
  708. }
  709. gboolean
  710. device_finish (Device * self) {
  711. DeviceClass *klass;
  712. g_return_val_if_fail (self != NULL, FALSE);
  713. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  714. if (self->access_mode == ACCESS_NULL)
  715. return TRUE;
  716. klass = DEVICE_GET_CLASS(self);
  717. if (klass->finish) {
  718. return (*klass->finish)(self);
  719. } else {
  720. return FALSE;
  721. }
  722. }
  723. /* For a good combination of synchronization and public simplicity,
  724. this stub function does not take a timestamp, but the actual
  725. implementation function does. We generate the timestamp here with
  726. time(). */
  727. gboolean
  728. device_start (Device * self, DeviceAccessMode mode,
  729. char * label, char * timestamp)
  730. {
  731. DeviceClass *klass;
  732. g_return_val_if_fail (self != NULL, FALSE);
  733. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  734. g_return_val_if_fail (mode != ACCESS_NULL, FALSE);
  735. g_return_val_if_fail (mode != ACCESS_WRITE || label != NULL,
  736. FALSE);
  737. klass = DEVICE_GET_CLASS(self);
  738. if(klass->start) {
  739. char * local_timestamp = NULL;
  740. gboolean rv;
  741. /* fill in a timestamp if none was given */
  742. if (mode == ACCESS_WRITE &&
  743. get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
  744. local_timestamp = timestamp =
  745. get_proper_stamp_from_time(time(NULL));
  746. }
  747. rv = (*klass->start)(self, mode, label, timestamp);
  748. amfree(local_timestamp);
  749. return rv;
  750. } else {
  751. return FALSE;
  752. }
  753. }
  754. gboolean
  755. device_write_block (Device * self, guint size, gpointer block,
  756. gboolean short_block)
  757. {
  758. DeviceClass *klass;
  759. g_return_val_if_fail (self != NULL, FALSE);
  760. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  761. g_return_val_if_fail (size > 0, FALSE);
  762. g_return_val_if_fail (short_block ||
  763. size >= device_write_min_size(self), FALSE);
  764. g_return_val_if_fail (size <= device_write_max_size(self), FALSE);
  765. g_return_val_if_fail (block != NULL, FALSE);
  766. g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
  767. FALSE);
  768. klass = DEVICE_GET_CLASS(self);
  769. if(klass->write_block)
  770. return (*klass->write_block)(self,size, block, short_block);
  771. else
  772. return FALSE;
  773. }
  774. gboolean
  775. device_write_from_fd (Device * self, int fd)
  776. {
  777. DeviceClass *klass;
  778. g_return_val_if_fail (self != NULL, FALSE);
  779. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  780. g_return_val_if_fail (fd >= 0, FALSE);
  781. g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
  782. FALSE);
  783. klass = DEVICE_GET_CLASS(self);
  784. if(klass->write_from_fd)
  785. return (*klass->write_from_fd)(self,fd);
  786. else
  787. return FALSE;
  788. }
  789. gboolean
  790. device_start_file (Device * self, const dumpfile_t * jobInfo) {
  791. DeviceClass * klass;
  792. g_return_val_if_fail (self != NULL, FALSE);
  793. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  794. g_return_val_if_fail (!(self->in_file), FALSE);
  795. g_return_val_if_fail (jobInfo != NULL, FALSE);
  796. klass = DEVICE_GET_CLASS(self);
  797. if(klass->start_file)
  798. return (*klass->start_file)(self, jobInfo );
  799. else
  800. return FALSE;
  801. }
  802. gboolean
  803. device_finish_file (Device * self)
  804. {
  805. DeviceClass *klass;
  806. g_return_val_if_fail (self != NULL, FALSE);
  807. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  808. g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
  809. FALSE);
  810. g_return_val_if_fail (self->in_file, FALSE);
  811. klass = DEVICE_GET_CLASS(self);
  812. if(klass->finish_file)
  813. return (*klass->finish_file)(self);
  814. else
  815. return FALSE;
  816. }
  817. dumpfile_t*
  818. device_seek_file (Device * self, guint file)
  819. {
  820. DeviceClass *klass;
  821. g_return_val_if_fail (self != NULL, NULL);
  822. g_return_val_if_fail (IS_DEVICE (self), NULL);
  823. g_return_val_if_fail (self->access_mode == ACCESS_READ,
  824. NULL);
  825. klass = DEVICE_GET_CLASS(self);
  826. if(klass->seek_file)
  827. return (*klass->seek_file)(self,file);
  828. else
  829. return FALSE;
  830. }
  831. gboolean
  832. device_seek_block (Device * self, guint64 block)
  833. {
  834. DeviceClass *klass;
  835. g_return_val_if_fail (self != NULL, FALSE);
  836. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  837. g_return_val_if_fail (self->access_mode == ACCESS_READ,
  838. FALSE);
  839. g_return_val_if_fail (self->in_file, FALSE);
  840. klass = DEVICE_GET_CLASS(self);
  841. if(klass->seek_block)
  842. return (*klass->seek_block)(self,block);
  843. else
  844. return FALSE;
  845. }
  846. int
  847. device_read_block (Device * self, gpointer buffer, int * size)
  848. {
  849. DeviceClass *klass;
  850. g_return_val_if_fail (self != NULL, -1);
  851. g_return_val_if_fail (IS_DEVICE (self), -1);
  852. g_return_val_if_fail (size != NULL, -1);
  853. g_return_val_if_fail (self->access_mode == ACCESS_READ, -1);
  854. if (*size != 0) {
  855. g_return_val_if_fail (buffer != NULL, -1);
  856. }
  857. /* Do a quick check here, so fixed-block subclasses don't have to. */
  858. if (*size == 0 &&
  859. device_write_min_size(self) == device_write_max_size(self)) {
  860. *size = device_write_min_size(self);
  861. return 0;
  862. }
  863. klass = DEVICE_GET_CLASS(self);
  864. if(klass->read_block)
  865. return (*klass->read_block)(self,buffer,size);
  866. else
  867. return -1;
  868. }
  869. gboolean
  870. device_read_to_fd (Device * self, int fd)
  871. {
  872. DeviceClass *klass;
  873. g_return_val_if_fail (self != NULL, FALSE);
  874. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  875. g_return_val_if_fail (fd >= 0, FALSE);
  876. g_return_val_if_fail (self->access_mode == ACCESS_READ, FALSE);
  877. klass = DEVICE_GET_CLASS(self);
  878. if(klass->read_to_fd)
  879. return (*klass->read_to_fd)(self,fd);
  880. else
  881. return FALSE;
  882. }
  883. gboolean
  884. device_property_get (Device * self, DevicePropertyId id, GValue * val)
  885. {
  886. DeviceClass *klass;
  887. g_return_val_if_fail (self != NULL, FALSE);
  888. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  889. g_return_val_if_fail (device_property_get_by_id(id) != NULL, FALSE);
  890. klass = DEVICE_GET_CLASS(self);
  891. /* FIXME: Check access flags? */
  892. if(klass->property_get)
  893. return (*klass->property_get)(self,id,val);
  894. else
  895. return FALSE;
  896. }
  897. gboolean
  898. device_property_set (Device * self, DevicePropertyId id, GValue * val)
  899. {
  900. DeviceClass *klass;
  901. g_return_val_if_fail (self != NULL, FALSE);
  902. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  903. klass = DEVICE_GET_CLASS(self);
  904. /* FIXME: Check access flags? */
  905. if(klass->property_set)
  906. return (*klass->property_set)(self,id,val);
  907. else
  908. return FALSE;
  909. }
  910. gboolean
  911. device_recycle_file (Device * self, guint filenum)
  912. {
  913. DeviceClass *klass;
  914. g_return_val_if_fail (self != NULL, FALSE);
  915. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  916. g_return_val_if_fail (self->access_mode == ACCESS_APPEND, FALSE);
  917. klass = DEVICE_GET_CLASS(self);
  918. if(klass->recycle_file)
  919. return (*klass->recycle_file)(self,filenum);
  920. else
  921. return FALSE;
  922. }